8967 libipmi: add support for GET_CHASSIS_STATUS command
[unleashed.git] / usr / src / lib / fm / topo / modules / common / fac_prov_ipmi / fac_prov_ipmi.c
blob5592f25cdd379d767f30e65ca3152a4fe1717400
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2017, Joyent, Inc.
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <limits.h>
34 #include <alloca.h>
35 #include <errno.h>
36 #include <libnvpair.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/fm/protocol.h>
40 #include <fm/libtopo.h>
41 #include <fm/topo_mod.h>
42 #include <libipmi.h>
44 #define BUFSZ 128
46 #define BAY_PRESENT_LED_MASK 0x01
49 * The largest possible SDR ID length is 2^5+1
51 #define MAX_ID_LEN 33
53 #define TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION 0
54 #define TOPO_METH_IPMI_READING_VERSION 0
55 #define TOPO_METH_IPMI_STATE_VERSION 0
56 #define TOPO_METH_IPMI_MODE_VERSION 0
57 #define TOPO_METH_X4500_MODE_VERSION 0
58 #define TOPO_METH_BAY_LOCATE_VERSION 0
59 #define TOPO_METH_BAY_MODE_VERSION 0
60 #define TOPO_METH_CHASSIS_SERVICE_VERSION 0
61 #define TOPO_METH_IPMI_ENTITY_VERSION 0
62 #define TOPO_METH_DIMM_IPMI_ENTITY_VERSION 0
63 #define TOPO_METH_CHASSIS_IDENT_VERSION 0
65 static int fac_prov_ipmi_enum(topo_mod_t *, tnode_t *, const char *,
66 topo_instance_t, topo_instance_t, void *, void *);
69 * IPMI facility provider methods
71 static int ipmi_sensor_enum(topo_mod_t *, tnode_t *, topo_version_t,
72 nvlist_t *, nvlist_t **);
73 static int ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
74 nvlist_t **);
75 static int dimm_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
76 nvlist_t **);
77 static int cs_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
78 nvlist_t **);
79 static int ipmi_platform_message(topo_mod_t *, tnode_t *, topo_version_t,
80 nvlist_t *, nvlist_t **);
81 static int ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t,
82 nvlist_t *, nvlist_t **);
83 static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t,
84 nvlist_t *, nvlist_t **);
85 static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
86 nvlist_t *, nvlist_t **);
87 static int bay_locate_mode(topo_mod_t *, tnode_t *, topo_version_t,
88 nvlist_t *, nvlist_t **);
89 static int x4500_present_mode(topo_mod_t *, tnode_t *, topo_version_t,
90 nvlist_t *, nvlist_t **);
91 static int bay_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
92 nvlist_t *, nvlist_t **);
93 static int chassis_service_mode(topo_mod_t *, tnode_t *, topo_version_t,
94 nvlist_t *, nvlist_t **);
95 static int chassis_ident_mode(topo_mod_t *, tnode_t *, topo_version_t,
96 nvlist_t *, nvlist_t **);
98 const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL };
100 const topo_modinfo_t ipmi_info =
101 { "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
102 &ipmi_ops };
104 static const topo_method_t ipmi_node_methods[] = {
105 { TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
106 TOPO_STABILITY_INTERNAL, ipmi_sensor_enum },
107 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
108 TOPO_METH_IPMI_ENTITY_VERSION,
109 TOPO_STABILITY_INTERNAL, ipmi_entity },
110 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
111 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
112 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
113 { "cs_ipmi_entity", TOPO_PROP_METH_DESC,
114 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
115 TOPO_STABILITY_INTERNAL, cs_ipmi_entity },
116 { NULL }
119 static const topo_method_t ipmi_fac_methods[] = {
120 { "ipmi_platform_message", TOPO_PROP_METH_DESC,
121 TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION,
122 TOPO_STABILITY_INTERNAL, ipmi_platform_message },
123 { "ipmi_sensor_reading", TOPO_PROP_METH_DESC,
124 TOPO_METH_IPMI_READING_VERSION,
125 TOPO_STABILITY_INTERNAL, ipmi_sensor_reading },
126 { "ipmi_sensor_state", TOPO_PROP_METH_DESC,
127 TOPO_METH_IPMI_STATE_VERSION,
128 TOPO_STABILITY_INTERNAL, ipmi_sensor_state },
129 { "ipmi_indicator_mode", TOPO_PROP_METH_DESC,
130 TOPO_METH_IPMI_MODE_VERSION,
131 TOPO_STABILITY_INTERNAL, ipmi_indicator_mode },
132 { "bay_locate_mode", TOPO_PROP_METH_DESC,
133 TOPO_METH_BAY_LOCATE_VERSION,
134 TOPO_STABILITY_INTERNAL, bay_locate_mode },
135 { "bay_indicator_mode", TOPO_PROP_METH_DESC,
136 TOPO_METH_BAY_MODE_VERSION,
137 TOPO_STABILITY_INTERNAL, bay_indicator_mode },
138 { "chassis_service_mode", TOPO_PROP_METH_DESC,
139 TOPO_METH_CHASSIS_SERVICE_VERSION,
140 TOPO_STABILITY_INTERNAL, chassis_service_mode },
141 { "chassis_ident_mode", TOPO_PROP_METH_DESC,
142 TOPO_METH_CHASSIS_SERVICE_VERSION,
143 TOPO_STABILITY_INTERNAL, chassis_ident_mode },
144 { "x4500_present_mode", TOPO_PROP_METH_DESC,
145 TOPO_METH_CHASSIS_SERVICE_VERSION,
146 TOPO_STABILITY_INTERNAL, x4500_present_mode },
147 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
148 TOPO_METH_IPMI_ENTITY_VERSION,
149 TOPO_STABILITY_INTERNAL, ipmi_entity },
150 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
151 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
152 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
153 { "cs_ipmi_entity", TOPO_PROP_METH_DESC,
154 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
155 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
156 { NULL }
159 struct entity_info {
160 uint32_t ei_id;
161 uint32_t ei_inst;
162 topo_mod_t *ei_mod;
163 tnode_t *ei_node;
164 char **ei_list;
165 uint_t ei_listsz;
168 struct sensor_data {
169 char sd_entity_ref[MAX_ID_LEN];
170 uint8_t sd_units;
171 uint32_t sd_stype;
172 uint32_t sd_rtype;
173 char *sd_class;
176 /*ARGSUSED*/
178 _topo_init(topo_mod_t *mod, topo_version_t version)
180 if (getenv("TOPOFACIPMIDEBUG") != NULL)
181 topo_mod_setdebug(mod);
183 return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION));
186 void
187 _topo_fini(topo_mod_t *mod)
189 topo_mod_unregister(mod);
192 static void
193 strarr_free(topo_mod_t *mod, char **arr, uint_t nelems)
195 for (int i = 0; i < nelems; i++)
196 topo_mod_strfree(mod, arr[i]);
197 topo_mod_free(mod, arr, (nelems * sizeof (char *)));
201 * Some platforms (most notably G1/2N) use the 'platform event message' command
202 * to manipulate disk fault LEDs over IPMI, but uses the standard sensor
203 * reading to read the value. This method implements this alternative
204 * interface for these platforms.
206 /*ARGSUSED*/
207 static int
208 ipmi_platform_message(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
209 nvlist_t *in, nvlist_t **out)
211 char *entity_ref;
212 ipmi_sdr_compact_sensor_t *csp;
213 ipmi_handle_t *hdl;
214 int err, ret;
215 uint32_t mode;
216 nvlist_t *pargs, *nvl;
217 ipmi_platform_event_message_t pem;
218 ipmi_sensor_reading_t *reading;
220 if (vers > TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION)
221 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
224 * Get an IPMI handle and then lookup the generic device locator sensor
225 * data record referenced by the entity_ref prop val
227 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
228 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
229 return (-1);
232 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref",
233 &entity_ref, &err) != 0) {
234 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
235 "(%s)", topo_strerror(err));
236 topo_mod_ipmi_rele(mod);
237 return (-1);
240 if ((csp = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) == NULL) {
241 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n",
242 entity_ref, ipmi_errmsg(hdl));
243 topo_mod_strfree(mod, entity_ref);
244 topo_mod_ipmi_rele(mod);
245 return (-1);
249 * Now look for a private argument list to figure out whether we're
250 * doing a get or a set operation, and then do it.
252 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
253 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
255 * Set the LED mode
257 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
258 &mode)) != 0) {
259 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
260 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
261 topo_mod_strfree(mod, entity_ref);
262 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
263 topo_mod_ipmi_rele(mod);
264 return (-1);
267 if (mode != TOPO_LED_STATE_OFF &&
268 mode != TOPO_LED_STATE_ON) {
269 topo_mod_dprintf(mod, "Invalid property value: %d\n",
270 mode);
271 topo_mod_strfree(mod, entity_ref);
272 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
273 topo_mod_ipmi_rele(mod);
274 return (-1);
277 pem.ipem_sensor_type = csp->is_cs_type;
278 pem.ipem_sensor_num = csp->is_cs_number;
279 pem.ipem_event_type = csp->is_cs_reading_type;
282 * The spec states that any values between 0x20 and 0x29 are
283 * legitimate for "system software". However, some versions of
284 * Sun's ILOM rejects messages over /dev/ipmi0 with a generator
285 * of 0x20, so we use 0x21 instead.
287 pem.ipem_generator = 0x21;
288 pem.ipem_event_dir = 0;
289 pem.ipem_rev = 0x04;
290 if (mode == TOPO_LED_STATE_ON)
291 pem.ipem_event_data[0] = 1;
292 else
293 pem.ipem_event_data[0] = 0;
294 pem.ipem_event_data[1] = 0xff;
295 pem.ipem_event_data[2] = 0xff;
297 if (ipmi_event_platform_message(hdl, &pem) < 0) {
298 topo_mod_dprintf(mod, "Failed to set LED mode for %s "
299 "(%s)\n", entity_ref, ipmi_errmsg(hdl));
300 topo_mod_strfree(mod, entity_ref);
301 topo_mod_ipmi_rele(mod);
302 return (-1);
304 } else {
306 * Get the LED mode
308 if ((reading = ipmi_get_sensor_reading(hdl, csp->is_cs_number))
309 == NULL) {
310 topo_mod_dprintf(mod, "Failed to get sensor reading "
311 "for sensor %s: %s\n", entity_ref,
312 ipmi_errmsg(hdl));
313 topo_mod_strfree(mod, entity_ref);
314 topo_mod_ipmi_rele(mod);
315 return (-1);
318 if (reading->isr_state &
319 TOPO_SENSOR_STATE_GENERIC_STATE_ASSERTED)
320 mode = TOPO_LED_STATE_ON;
321 else
322 mode = TOPO_LED_STATE_OFF;
324 topo_mod_strfree(mod, entity_ref);
326 topo_mod_ipmi_rele(mod);
328 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
329 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
330 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
331 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, mode) != 0) {
332 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
333 nvlist_free(nvl);
334 return (topo_mod_seterrno(mod, EMOD_NOMEM));
336 *out = nvl;
338 return (0);
341 /*ARGSUSED*/
342 static int
343 ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
344 nvlist_t *in, nvlist_t **out)
346 char **entity_refs;
347 uint_t nelems;
348 ipmi_sdr_t *sdr = NULL;
349 ipmi_sensor_reading_t *reading;
350 ipmi_handle_t *hdl;
351 int err, i;
352 uint8_t sensor_num;
353 ipmi_sdr_full_sensor_t *fsensor;
354 ipmi_sdr_compact_sensor_t *csensor;
355 nvlist_t *nvl;
356 boolean_t found_sdr = B_FALSE;
358 if (vers > TOPO_METH_IPMI_STATE_VERSION)
359 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
361 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
362 &entity_refs, &nelems, &err) != 0) {
363 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
364 "property (%s)", __func__, topo_strerror(err));
365 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
368 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
369 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
370 strarr_free(mod, entity_refs, nelems);
371 return (-1);
374 for (i = 0; i < nelems; i++) {
375 if ((sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
376 found_sdr = B_TRUE;
377 break;
378 } else
379 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
380 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
383 if (! found_sdr) {
384 strarr_free(mod, entity_refs, nelems);
385 topo_mod_ipmi_rele(mod);
386 return (-1);
389 switch (sdr->is_type) {
390 case IPMI_SDR_TYPE_FULL_SENSOR:
391 fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
392 sensor_num = fsensor->is_fs_number;
393 break;
394 case IPMI_SDR_TYPE_COMPACT_SENSOR:
395 csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record;
396 sensor_num = csensor->is_cs_number;
397 break;
398 default:
399 topo_mod_dprintf(mod, "%s does not refer to a full or "
400 "compact SDR\n", entity_refs[i]);
401 topo_mod_ipmi_rele(mod);
402 strarr_free(mod, entity_refs, nelems);
403 return (-1);
405 if ((reading = ipmi_get_sensor_reading(hdl, sensor_num))
406 == NULL) {
407 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
408 "%s, sensor_num=%d (%s)\n", entity_refs[i], sensor_num,
409 ipmi_errmsg(hdl));
410 strarr_free(mod, entity_refs, nelems);
411 topo_mod_ipmi_rele(mod);
412 return (-1);
414 strarr_free(mod, entity_refs, nelems);
415 topo_mod_ipmi_rele(mod);
417 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
418 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
419 TOPO_SENSOR_STATE) != 0 ||
420 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
421 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, reading->isr_state)
422 != 0) {
423 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
424 nvlist_free(nvl);
425 return (topo_mod_seterrno(mod, EMOD_NOMEM));
427 *out = nvl;
429 return (0);
432 /*ARGSUSED*/
433 static int
434 ipmi_sensor_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
435 nvlist_t *in, nvlist_t **out)
437 char **entity_refs, reading_str[BUFSZ];
438 uint_t nelems;
439 int err = 0, i;
440 ipmi_sdr_full_sensor_t *sensor;
441 ipmi_sensor_reading_t *reading;
442 double conv_reading;
443 ipmi_handle_t *hdl;
444 nvlist_t *nvl;
445 boolean_t found_sdr = B_FALSE;
447 if (vers > TOPO_METH_IPMI_READING_VERSION)
448 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
450 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
451 &entity_refs, &nelems, &err) != 0) {
452 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
453 "(%s)", topo_strerror(err));
454 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
457 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
458 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
459 strarr_free(mod, entity_refs, nelems);
460 return (-1);
463 for (i = 0; i < nelems; i++) {
464 if ((sensor = ipmi_sdr_lookup_full_sensor(hdl, entity_refs[i]))
465 != NULL) {
466 found_sdr = B_TRUE;
467 break;
468 } else
469 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
470 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
473 if (! found_sdr) {
474 strarr_free(mod, entity_refs, nelems);
475 topo_mod_ipmi_rele(mod);
476 return (-1);
479 if ((reading = ipmi_get_sensor_reading(hdl, sensor->is_fs_number))
480 == NULL) {
481 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
482 "%s, sensor_num=%d (%s)\n", entity_refs[i],
483 sensor->is_fs_number, ipmi_errmsg(hdl));
484 strarr_free(mod, entity_refs, nelems);
485 topo_mod_ipmi_rele(mod);
486 return (-1);
488 topo_mod_ipmi_rele(mod);
490 if (ipmi_sdr_conv_reading(sensor, reading->isr_reading, &conv_reading)
491 != 0) {
492 topo_mod_dprintf(mod, "Failed to convert sensor reading for "
493 "sensor %s (%s)\n", entity_refs[i], ipmi_errmsg(hdl));
494 strarr_free(mod, entity_refs, nelems);
495 return (-1);
497 strarr_free(mod, entity_refs, nelems);
499 (void) snprintf(reading_str, BUFSZ, "%f", conv_reading);
500 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
501 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
502 TOPO_SENSOR_READING) != 0 ||
503 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 ||
504 nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, conv_reading) != 0) {
505 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
506 nvlist_free(nvl);
507 return (topo_mod_seterrno(mod, EMOD_NOMEM));
509 *out = nvl;
511 return (0);
514 static int
515 ipmi_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
516 nvlist_t *in, nvlist_t **out)
518 char **entity_refs;
519 uint_t nelems;
520 ipmi_sdr_generic_locator_t *gdl = NULL;
521 ipmi_handle_t *hdl;
522 int err, ret, i;
523 uint8_t ledmode;
524 uint32_t mode_in;
525 nvlist_t *pargs, *nvl;
526 boolean_t found_sdr = B_FALSE;
528 if (vers > TOPO_METH_IPMI_MODE_VERSION)
529 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
532 * Get an IPMI handle and then lookup the generic device locator sensor
533 * data record referenced by the entity_ref prop val
535 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
536 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
537 return (-1);
540 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
541 &entity_refs, &nelems, &err) != 0) {
542 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
543 "(%s)", topo_strerror(err));
544 topo_mod_ipmi_rele(mod);
545 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
548 for (i = 0; i < nelems; i++) {
549 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
550 != NULL) {
551 found_sdr = B_TRUE;
552 break;
553 } else
554 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
555 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
558 if (! found_sdr) {
559 strarr_free(mod, entity_refs, nelems);
560 topo_mod_ipmi_rele(mod);
561 return (-1);
565 * Now look for a private argument list to figure out whether we're
566 * doing a get or a set operation, and then do it.
568 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
569 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
571 * Set the LED mode
573 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
574 &mode_in)) != 0) {
575 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
576 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
577 strarr_free(mod, entity_refs, nelems);
578 topo_mod_ipmi_rele(mod);
579 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
581 if (mode_in != TOPO_LED_STATE_OFF &&
582 mode_in != TOPO_LED_STATE_ON) {
583 topo_mod_dprintf(mod, "Invalid property value: %d\n",
584 mode_in);
585 strarr_free(mod, entity_refs, nelems);
586 topo_mod_ipmi_rele(mod);
587 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
589 ledmode = (uint8_t)mode_in;
590 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
591 topo_mod_dprintf(mod, "%s: Failed to set LED mode for "
592 "%s (%s) to %s\n", __func__, entity_refs[i],
593 ipmi_errmsg(hdl), ledmode ? "ON" : "OFF");
594 strarr_free(mod, entity_refs, nelems);
595 topo_mod_ipmi_rele(mod);
596 return (-1);
598 } else {
600 * Get the LED mode
602 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
603 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
604 "%s (%s)\n", __func__, entity_refs[i],
605 ipmi_errmsg(hdl));
606 strarr_free(mod, entity_refs, nelems);
607 topo_mod_ipmi_rele(mod);
608 return (-1);
611 strarr_free(mod, entity_refs, nelems);
612 topo_mod_ipmi_rele(mod);
614 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
615 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
616 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
617 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
618 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
619 nvlist_free(nvl);
620 return (topo_mod_seterrno(mod, EMOD_NOMEM));
622 *out = nvl;
624 return (0);
628 * On most Sun platforms there is no seperate locate LED for the drive bays.
629 * This propmethod simulates a locate LED by blinking the ok2rm LED.
631 * LED control is through a the Sun OEM led/get commands. This propmethod can
632 * work on X4500/X4540 with ILOM 2.x and on
633 * X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms with ILOM 3.x.
635 static int
636 bay_locate_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
637 nvlist_t *in, nvlist_t **out)
639 char **entity_refs;
640 uint_t nelems;
641 ipmi_sdr_generic_locator_t *gdl = NULL;
642 ipmi_handle_t *hdl;
643 int err, ret, i;
644 uint8_t ledmode;
645 uint32_t mode_in;
646 nvlist_t *pargs, *nvl;
647 boolean_t found_sdr = B_FALSE;
649 if (vers > TOPO_METH_BAY_LOCATE_VERSION)
650 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
653 * Get an IPMI handle and then lookup the generic device locator sensor
654 * data record referenced by the entity_ref prop val
656 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
657 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
658 return (-1);
661 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
662 &entity_refs, &nelems, &err) != 0) {
663 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
664 "(%s)", topo_strerror(err));
665 topo_mod_ipmi_rele(mod);
666 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
669 for (i = 0; i < nelems; i++) {
670 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
671 != NULL) {
672 found_sdr = B_TRUE;
673 break;
674 } else
675 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
676 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
679 if (! found_sdr) {
680 strarr_free(mod, entity_refs, nelems);
681 topo_mod_ipmi_rele(mod);
682 return (-1);
686 * Now look for a private argument list to figure out whether we're
687 * doing a get or a set operation, and then do it.
689 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
690 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
692 * Set the LED mode
694 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
695 &mode_in)) != 0) {
696 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
697 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
698 strarr_free(mod, entity_refs, nelems);
699 topo_mod_ipmi_rele(mod);
700 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
702 if (mode_in != TOPO_LED_STATE_OFF &&
703 mode_in != TOPO_LED_STATE_ON) {
704 topo_mod_dprintf(mod, "Invalid property value: %d\n",
705 mode_in);
706 strarr_free(mod, entity_refs, nelems);
707 topo_mod_ipmi_rele(mod);
708 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
710 if (mode_in == TOPO_LED_STATE_ON)
711 ledmode = IPMI_SUNOEM_LED_MODE_FAST;
712 else
713 ledmode = IPMI_SUNOEM_LED_MODE_OFF;
714 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
715 topo_mod_dprintf(mod, "Failed to set LED mode for %s "
716 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
717 strarr_free(mod, entity_refs, nelems);
718 topo_mod_ipmi_rele(mod);
719 return (-1);
721 } else {
723 * Get the LED mode
725 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
726 topo_mod_dprintf(mod, "Failed to get LED mode for %s "
727 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
728 strarr_free(mod, entity_refs, nelems);
729 topo_mod_ipmi_rele(mod);
730 return (-1);
733 strarr_free(mod, entity_refs, nelems);
734 topo_mod_ipmi_rele(mod);
736 if (ledmode == IPMI_SUNOEM_LED_MODE_SLOW ||
737 ledmode == IPMI_SUNOEM_LED_MODE_FAST)
738 ledmode = TOPO_LED_STATE_ON;
739 else
740 ledmode = TOPO_LED_STATE_OFF;
742 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
743 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
744 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
745 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
746 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
747 nvlist_free(nvl);
748 return (topo_mod_seterrno(mod, EMOD_NOMEM));
750 *out = nvl;
752 return (0);
756 * This is a method for the "mode" property that is specific for the ok2rm and
757 * service drive bay LED's on the X4500/X4540 platforms running ILOM 2.x and
758 * for X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms running
759 * ILOM 3.x.
761 * For ILOM 2.x, the LED's are controlled by a Sun OEM led set command
763 * For ILOM 3.x platforms the LED's are controlled by sending a platform event
764 * message for the appropriate DBP/HDD##/STATE compact SDR.
766 * For both ILOM 2 and ILOM 3, the current LED mode can be obtained by a
767 * Sun OEM led get command.
769 static int
770 bay_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
771 nvlist_t *in, nvlist_t **out)
773 char **entity_refs;
774 uint_t nelems;
775 ipmi_sdr_compact_sensor_t *cs = NULL;
776 ipmi_sdr_generic_locator_t *gdl = NULL;
777 ipmi_deviceid_t *sp_devid;
778 ipmi_platform_event_message_t pem;
779 ipmi_handle_t *hdl;
780 int err, ret, i;
781 uint32_t type, ledmode;
782 uint8_t mode_in, ev_off;
783 nvlist_t *pargs, *nvl;
784 boolean_t found_sdr = B_FALSE;
786 if (vers > TOPO_METH_BAY_MODE_VERSION)
787 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
789 if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
790 &type, &err) != 0) {
791 topo_mod_dprintf(mod, "Failed to lookup %s property "
792 "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err));
793 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
795 switch (type) {
796 case (TOPO_LED_TYPE_SERVICE):
797 ev_off = 0x01;
798 break;
799 case (TOPO_LED_TYPE_OK2RM):
800 ev_off = 0x03;
801 break;
802 default:
803 topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type);
804 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
807 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
808 &entity_refs, &nelems, &err) != 0) {
809 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
810 "(%s)", topo_strerror(err));
811 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
815 * Figure out whether the SP is running ILOM 2.x or ILOM 3.x
817 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
818 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
819 strarr_free(mod, entity_refs, nelems);
820 return (-1);
823 if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
824 topo_mod_dprintf(mod, "%s: GET DEVICEID command failed (%s)\n",
825 __func__, ipmi_errmsg(hdl));
826 strarr_free(mod, entity_refs, nelems);
827 topo_mod_ipmi_rele(mod);
828 return (-1);
832 * Now lookup the propmethod argument list and figure out whether we're
833 * doing a get or a set operation, and then do it.
835 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
836 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
838 * Set the LED mode
840 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
841 &ledmode)) != 0) {
842 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
843 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
844 strarr_free(mod, entity_refs, nelems);
845 topo_mod_ipmi_rele(mod);
846 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
849 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
850 ledmode ? "ON" : "OFF");
852 if (sp_devid->id_firm_major == 2) {
853 for (i = 0; i < nelems; i++) {
854 if ((gdl = ipmi_sdr_lookup_generic(hdl,
855 entity_refs[i])) != NULL) {
856 found_sdr = B_TRUE;
857 break;
858 } else
859 topo_mod_dprintf(mod,
860 "Failed to lookup SDR for %s(%s)\n",
861 entity_refs[i], ipmi_errmsg(hdl));
864 if (! found_sdr) {
865 strarr_free(mod, entity_refs, nelems);
866 topo_mod_ipmi_rele(mod);
867 return (-1);
870 if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)ledmode)
871 < 0) {
872 topo_mod_dprintf(mod,
873 "Failed to set LED mode for %s (%s)\n",
874 entity_refs[i], ipmi_errmsg(hdl));
875 strarr_free(mod, entity_refs, nelems);
876 topo_mod_ipmi_rele(mod);
877 return (-1);
879 } else {
880 for (i = 0; i < nelems; i++) {
881 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl,
882 entity_refs[i])) != NULL) {
883 found_sdr = B_TRUE;
884 break;
885 } else
886 topo_mod_dprintf(mod,
887 "Failed to lookup SDR for %s(%s)\n",
888 entity_refs[i], ipmi_errmsg(hdl));
891 if (! found_sdr) {
892 strarr_free(mod, entity_refs, nelems);
893 topo_mod_ipmi_rele(mod);
894 return (-1);
897 pem.ipem_generator = IPMI_SEL_SYSTEM;
898 pem.ipem_rev = IPMI_EV_REV15;
899 pem.ipem_sensor_type = IPMI_ST_BAY;
900 pem.ipem_sensor_num = cs->is_cs_number;
901 pem.ipem_event_type = IPMI_RT_SPECIFIC;
902 if (ledmode == TOPO_LED_STATE_ON)
903 pem.ipem_event_dir = 0;
904 else
905 pem.ipem_event_dir = 1;
907 pem.ipem_event_data[0] = ev_off;
908 pem.ipem_event_data[1] = 0xff;
909 pem.ipem_event_data[2] = 0xff;
911 if (ipmi_event_platform_message(hdl, &pem) != 0) {
912 topo_mod_dprintf(mod, "%s: Failed to send "
913 "platform event mesg for %s (%s)\n",
914 __func__, entity_refs[i], ipmi_errmsg(hdl));
915 strarr_free(mod, entity_refs, nelems);
916 topo_mod_ipmi_rele(mod);
917 return (-1);
920 } else {
922 * Get the LED mode
924 for (i = 0; i < nelems; i++) {
925 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
926 != NULL) {
927 found_sdr = B_TRUE;
928 break;
929 } else
930 topo_mod_dprintf(mod, "%s: Failed to lookup "
931 "SDR for %s (%s)\n", __func__,
932 entity_refs[i], ipmi_errmsg(hdl));
935 if (! found_sdr) {
936 strarr_free(mod, entity_refs, nelems);
937 topo_mod_ipmi_rele(mod);
938 return (-1);
940 if (ipmi_sunoem_led_get(hdl, gdl, &mode_in) < 0) {
941 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
942 "%s (%s)\n", __func__, entity_refs[i],
943 ipmi_errmsg(hdl));
944 strarr_free(mod, entity_refs, nelems);
945 topo_mod_ipmi_rele(mod);
946 return (-1);
948 ledmode = mode_in;
950 strarr_free(mod, entity_refs, nelems);
951 topo_mod_ipmi_rele(mod);
953 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
954 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
955 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
956 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
957 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
958 nvlist_free(nvl);
959 return (topo_mod_seterrno(mod, EMOD_NOMEM));
961 *out = nvl;
962 return (0);
966 * This propmethod is for controlling the present LED on the drive bays for
967 * the X4500 platform.
969 static int
970 x4500_present_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
971 nvlist_t *in, nvlist_t **out)
973 char **entity_refs;
974 uint_t nelems;
975 ipmi_sdr_compact_sensor_t *cs = NULL;
976 ipmi_set_sensor_reading_t sr_out = { 0 };
977 ipmi_handle_t *hdl;
978 int err, ret, i;
979 uint32_t ledmode;
980 nvlist_t *pargs, *nvl;
981 boolean_t found_sdr = B_FALSE;
983 if (vers > TOPO_METH_X4500_MODE_VERSION)
984 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
986 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
987 &entity_refs, &nelems, &err) != 0) {
988 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
989 "(%s)", topo_strerror(err));
990 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
993 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
994 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
995 strarr_free(mod, entity_refs, nelems);
996 return (-1);
998 for (i = 0; i < nelems; i++) {
999 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_refs[i]))
1000 != NULL) {
1001 found_sdr = B_TRUE;
1002 break;
1003 } else
1004 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
1005 "(%s)\n", entity_refs[i],
1006 ipmi_errmsg(hdl));
1009 if (! found_sdr) {
1010 strarr_free(mod, entity_refs, nelems);
1011 topo_mod_ipmi_rele(mod);
1012 return (-1);
1016 * Now lookup the propmethod argument list and figure out whether we're
1017 * doing a get or a set operation, and then do it.
1019 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1020 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1022 * Set the LED mode
1024 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1025 &ledmode)) != 0) {
1026 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1027 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1028 strarr_free(mod, entity_refs, nelems);
1029 topo_mod_ipmi_rele(mod);
1030 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1033 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1034 ledmode ? "ON" : "OFF");
1036 if (ledmode == TOPO_LED_STATE_OFF) {
1037 sr_out.iss_deassert_state = BAY_PRESENT_LED_MASK;
1038 sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET;
1039 } else if (ledmode == TOPO_LED_STATE_ON) {
1040 sr_out.iss_assert_state = BAY_PRESENT_LED_MASK;
1041 sr_out.iss_assert_op = IPMI_SENSOR_OP_SET;
1042 } else {
1043 topo_mod_dprintf(mod, "%s: Invalid LED mode: "
1044 "%d\n", __func__, ledmode);
1045 strarr_free(mod, entity_refs, nelems);
1046 topo_mod_ipmi_rele(mod);
1047 return (-1);
1049 sr_out.iss_id = cs->is_cs_number;
1050 topo_mod_dprintf(mod, "Setting LED mode (mask=0x%x)\n",
1051 BAY_PRESENT_LED_MASK);
1052 if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) {
1053 topo_mod_dprintf(mod, "%s: Failed to set "
1054 "sensor reading for %s (%s)\n", __func__,
1055 entity_refs[i], ipmi_errmsg(hdl));
1056 strarr_free(mod, entity_refs, nelems);
1057 topo_mod_ipmi_rele(mod);
1058 return (-1);
1060 } else {
1062 * Get the LED mode
1064 ipmi_sensor_reading_t *sr_in;
1066 topo_mod_dprintf(mod, "Getting LED mode\n");
1067 if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number))
1068 == NULL) {
1069 topo_mod_dprintf(mod, "Failed to get sensor reading "
1070 "for sensor %s (sensor num: %d) (error: %s)\n",
1071 entity_refs[i], cs->is_cs_number, ipmi_errmsg(hdl));
1072 strarr_free(mod, entity_refs, nelems);
1073 topo_mod_ipmi_rele(mod);
1074 return (-1);
1076 if (sr_in->isr_state & (uint16_t)BAY_PRESENT_LED_MASK)
1077 ledmode = TOPO_LED_STATE_ON;
1078 else
1079 ledmode = TOPO_LED_STATE_OFF;
1081 strarr_free(mod, entity_refs, nelems);
1082 topo_mod_ipmi_rele(mod);
1084 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1085 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1086 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1087 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1088 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1089 nvlist_free(nvl);
1090 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1092 *out = nvl;
1093 return (0);
1097 * This is a property method for controlling the chassis service LED on
1098 * ILOM 3.x based platforms.
1100 static int
1101 chassis_service_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1102 nvlist_t *in, nvlist_t **out)
1104 char **entity_refs;
1105 uint_t nelems;
1106 ipmi_sdr_generic_locator_t *gdl = NULL;
1107 ipmi_deviceid_t *sp_devid;
1108 ipmi_platform_event_message_t pem;
1109 ipmi_handle_t *hdl;
1110 int err, ret, i;
1111 uint8_t ledmode;
1112 uint32_t mode_in;
1113 nvlist_t *pargs, *nvl;
1114 boolean_t found_sdr = B_FALSE;
1116 if (vers > TOPO_METH_CHASSIS_SERVICE_VERSION)
1117 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1120 * Get an IPMI handle and then lookup the generic device locator record
1121 * referenced by the entity_ref prop val
1123 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1124 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1125 return (-1);
1128 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
1129 &entity_refs, &nelems, &err) != 0) {
1130 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
1131 "(%s)", topo_strerror(err));
1132 topo_mod_ipmi_rele(mod);
1133 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1136 for (i = 0; i < nelems; i++) {
1137 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
1138 != NULL) {
1139 found_sdr = B_TRUE;
1140 break;
1141 } else
1142 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
1143 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
1146 if (! found_sdr) {
1147 strarr_free(mod, entity_refs, nelems);
1148 topo_mod_ipmi_rele(mod);
1149 return (-1);
1153 * Now lookup the propmethod argument list and figure out whether we're
1154 * doing a get or a set operation, and then do it.
1156 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1157 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1159 * Set the LED mode
1161 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1162 &mode_in)) != 0) {
1163 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1164 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1165 strarr_free(mod, entity_refs, nelems);
1166 topo_mod_ipmi_rele(mod);
1167 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1171 * Determine which IPMI mechanism to use to set the LED mode
1172 * based on whether the SP is running ILOM 2 or later.
1174 if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
1175 topo_mod_dprintf(mod, "%s: GET DEVICEID command failed "
1176 "(%s)\n", __func__, ipmi_errmsg(hdl));
1177 strarr_free(mod, entity_refs, nelems);
1178 topo_mod_ipmi_rele(mod);
1179 return (-1);
1182 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1183 mode_in ? "ON" : "OFF");
1185 if (sp_devid->id_firm_major == 2) {
1186 if (mode_in != TOPO_LED_STATE_OFF &&
1187 mode_in != TOPO_LED_STATE_ON) {
1188 topo_mod_dprintf(mod, "Invalid property value: "
1189 "%d\n", mode_in);
1190 strarr_free(mod, entity_refs, nelems);
1191 topo_mod_ipmi_rele(mod);
1192 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1194 if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)mode_in)
1195 < 0) {
1196 topo_mod_dprintf(mod, "Failed to set LED mode "
1197 "for %s (%s)\n", entity_refs[i],
1198 ipmi_errmsg(hdl));
1199 strarr_free(mod, entity_refs, nelems);
1200 topo_mod_ipmi_rele(mod);
1201 return (-1);
1203 } else {
1204 pem.ipem_generator = IPMI_SEL_SYSTEM;
1205 pem.ipem_rev = IPMI_EV_REV15;
1206 pem.ipem_sensor_type = IPMI_ST_SYSTEM;
1207 pem.ipem_sensor_num = 0x00;
1208 pem.ipem_event_type = IPMI_RT_SPECIFIC;
1209 if (mode_in == TOPO_LED_STATE_ON)
1210 pem.ipem_event_dir = 0;
1211 else
1212 pem.ipem_event_dir = 1;
1214 pem.ipem_event_data[0] = 0x02;
1215 pem.ipem_event_data[1] = 0xff;
1216 pem.ipem_event_data[2] = 0xff;
1218 topo_mod_dprintf(mod, "Sending platform event\n");
1219 if (ipmi_event_platform_message(hdl, &pem) != 0) {
1220 topo_mod_dprintf(mod, "%s: Failed to send "
1221 "platform event mesg for sensor 0 (%s)\n",
1222 __func__, ipmi_errmsg(hdl));
1223 strarr_free(mod, entity_refs, nelems);
1224 topo_mod_ipmi_rele(mod);
1225 return (-1);
1228 } else {
1230 * Get the LED mode
1232 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
1233 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
1234 "%s (%s)\n", __func__, entity_refs[i],
1235 ipmi_errmsg(hdl));
1236 strarr_free(mod, entity_refs, nelems);
1237 topo_mod_ipmi_rele(mod);
1238 return (-1);
1241 strarr_free(mod, entity_refs, nelems);
1242 topo_mod_ipmi_rele(mod);
1244 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1245 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1246 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1247 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1248 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1249 nvlist_free(nvl);
1250 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1252 *out = nvl;
1253 return (0);
1257 * This is a property method for controlling the chassis identify LED using
1258 * generic IPMI mechanisms.
1260 /*ARGSUSED*/
1261 static int
1262 chassis_ident_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1263 nvlist_t *in, nvlist_t **out)
1265 ipmi_handle_t *hdl;
1266 int ret;
1267 uint32_t modeval;
1268 boolean_t assert_ident;
1269 nvlist_t *pargs, *nvl;
1270 ipmi_chassis_status_t *chs;
1272 if (vers > TOPO_METH_CHASSIS_IDENT_VERSION)
1273 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1275 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1276 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1277 return (-1);
1281 * Now lookup the propmethod argument list and figure out whether we're
1282 * doing a get or a set operation, and then do it.
1284 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1285 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1287 * Set the LED mode
1289 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1290 &modeval)) != 0) {
1291 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1292 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1293 topo_mod_ipmi_rele(mod);
1294 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1297 assert_ident = modeval ? B_TRUE : B_FALSE;
1298 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1299 assert_ident ? "ON" : "OFF");
1300 if (ipmi_chassis_identify(hdl, assert_ident) != 0) {
1301 topo_mod_ipmi_rele(mod);
1302 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1305 } else {
1307 * Get the LED mode
1309 if ((chs = ipmi_chassis_status(hdl)) == NULL ||
1310 !chs->ichs_identify_supported) {
1311 free(chs);
1312 topo_mod_ipmi_rele(mod);
1313 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1316 * ichs_identify_state is a 2-bit value with the following
1317 * semantics:
1318 * 0 - ident is off
1319 * 1 - ident is temporarily on
1320 * 2 - ident is indefinitely on
1321 * 3 - reserved
1323 switch (chs->ichs_identify_state) {
1324 case 0:
1325 modeval = TOPO_LED_STATE_OFF;
1326 break;
1327 case 1:
1328 case 2:
1329 modeval = TOPO_LED_STATE_ON;
1330 break;
1331 default:
1332 free(chs);
1333 topo_mod_ipmi_rele(mod);
1334 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1336 free(chs);
1338 topo_mod_ipmi_rele(mod);
1340 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1341 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1342 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1343 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, modeval) != 0) {
1344 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1345 nvlist_free(nvl);
1346 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1348 *out = nvl;
1349 return (0);
1352 static int
1353 make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
1355 int err, ret, i;
1356 tnode_t *fnode;
1357 char *ftype = "sensor", facname[MAX_ID_LEN], **entity_refs;
1358 topo_pgroup_info_t pgi;
1359 nvlist_t *arg_nvl = NULL;
1362 * Some platforms have '/' characters in the IPMI entity name, but '/'
1363 * has a special meaning for FMRI's so we change them to '.' before
1364 * binding the node into the topology.
1366 (void) strcpy(facname, sd->sd_entity_ref);
1367 for (i = 0; facname[i]; i++)
1368 if (facname[i] == '/')
1369 facname[i] = '.';
1371 if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) {
1372 topo_mod_dprintf(mod, "Failed to bind facility node: %s\n",
1373 facname);
1374 /* topo errno set */
1375 return (-1);
1378 pgi.tpi_name = TOPO_PGROUP_FACILITY;
1379 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1380 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1381 pgi.tpi_version = 1;
1382 if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
1383 if (err != ETOPO_PROP_DEFD) {
1384 topo_mod_dprintf(mod, "pgroups create failure: %s\n",
1385 topo_strerror(err));
1386 topo_node_unbind(fnode);
1387 return (-1);
1390 if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) {
1391 topo_mod_dprintf(mod, "make_fac_node: "
1392 "failed to register facility methods");
1393 topo_node_unbind(fnode);
1394 return (-1);
1397 * For both threshold and discrete sensors we set up a propmethod for
1398 * getting the sensor state and properties to hold the entity ref,
1399 * sensor class and sensor type.
1401 * Additionally, for analog sensors we set up a property method for
1402 * getting the converted sensor reading and property for the base
1403 * unit type
1405 if ((entity_refs = topo_mod_alloc(mod, sizeof (char *))) == NULL)
1406 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1408 entity_refs[0] = topo_mod_strdup(mod, sd->sd_entity_ref);
1410 if (topo_prop_set_string_array(fnode, TOPO_PGROUP_FACILITY,
1411 "entity_ref", TOPO_PROP_IMMUTABLE, (const char **)entity_refs, 1,
1412 &err) != 0) {
1413 topo_mod_dprintf(mod, "%s: Failed to set entity_ref property "
1414 "on node: %s=%d (%s)\n", __func__, topo_node_name(fnode),
1415 topo_node_instance(fnode), topo_strerror(err));
1416 strarr_free(mod, entity_refs, 1);
1417 return (-1);
1419 strarr_free(mod, entity_refs, 1);
1421 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
1422 TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) {
1423 topo_mod_dprintf(mod, "Failed to set %s property on node: "
1424 "%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode),
1425 topo_node_instance(fnode), topo_strerror(err));
1426 return (-1);
1428 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1429 TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) {
1430 topo_mod_dprintf(mod, "Failed to set %s property on node: "
1431 "%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode),
1432 topo_node_instance(fnode), topo_strerror(err));
1433 return (-1);
1435 if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) {
1436 topo_node_unbind(fnode);
1437 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1440 if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref))
1441 != 0) {
1442 topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n",
1443 strerror(ret));
1444 nvlist_free(arg_nvl);
1445 return (-1);
1448 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1449 TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl,
1450 &err) != 0) {
1451 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1452 "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode),
1453 topo_strerror(err));
1454 nvlist_free(arg_nvl);
1455 return (-1);
1458 if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) {
1459 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1460 TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE,
1461 "ipmi_sensor_reading", arg_nvl, &err) != 0) {
1462 topo_mod_dprintf(mod, "Failed to register %s propmeth "
1463 "on fac node %s (%s)\n", TOPO_SENSOR_READING,
1464 topo_node_name(fnode), topo_strerror(err));
1465 nvlist_free(arg_nvl);
1466 return (-1);
1468 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1469 TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err)
1470 != 0) {
1471 topo_mod_dprintf(mod, "Failed to set units property on "
1472 "node: %s (%s)\n", topo_node_name(fnode),
1473 topo_strerror(err));
1474 nvlist_free(arg_nvl);
1475 return (-1);
1478 nvlist_free(arg_nvl);
1479 return (0);
1482 static boolean_t
1483 seq_search(char *key, char **list, uint_t nelem)
1485 for (int i = 0; i < nelem; i++)
1486 if (strcmp(key, list[i]) == 0)
1487 return (B_TRUE);
1488 return (B_FALSE);
1491 /* ARGSUSED */
1492 static int
1493 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
1495 uint8_t sensor_entity, sensor_inst;
1496 int sensor_idlen;
1497 ipmi_sdr_full_sensor_t *f_sensor = NULL;
1498 ipmi_sdr_compact_sensor_t *c_sensor = NULL;
1499 struct sensor_data sd;
1500 struct entity_info *ei = (struct entity_info *)data;
1502 switch (sdr->is_type) {
1503 case IPMI_SDR_TYPE_FULL_SENSOR:
1504 f_sensor =
1505 (ipmi_sdr_full_sensor_t *)sdr->is_record;
1506 sensor_entity = f_sensor->is_fs_entity_id;
1507 sensor_inst = f_sensor->is_fs_entity_instance;
1508 sensor_idlen = f_sensor->is_fs_idlen;
1509 (void) strncpy(sd.sd_entity_ref,
1510 f_sensor->is_fs_idstring,
1511 f_sensor->is_fs_idlen);
1512 sd.sd_entity_ref[sensor_idlen] = '\0';
1513 sd.sd_units = f_sensor->is_fs_unit2;
1514 sd.sd_stype = f_sensor->is_fs_type;
1515 sd.sd_rtype = f_sensor->is_fs_reading_type;
1516 break;
1517 case IPMI_SDR_TYPE_COMPACT_SENSOR:
1518 c_sensor =
1519 (ipmi_sdr_compact_sensor_t *)sdr->is_record;
1520 sensor_entity = c_sensor->is_cs_entity_id;
1521 sensor_inst = c_sensor->is_cs_entity_instance;
1522 sensor_idlen = c_sensor->is_cs_idlen;
1523 (void) strncpy(sd.sd_entity_ref,
1524 c_sensor->is_cs_idstring,
1525 sensor_idlen);
1526 sd.sd_entity_ref[sensor_idlen] = '\0';
1527 sd.sd_units = c_sensor->is_cs_unit2;
1528 sd.sd_stype = c_sensor->is_cs_type;
1529 sd.sd_rtype = c_sensor->is_cs_reading_type;
1530 break;
1531 default:
1532 return (0);
1534 if (sd.sd_rtype == IPMI_RT_THRESHOLD)
1535 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD;
1536 else
1537 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE;
1540 * We offset the threshold and generic sensor reading types by 0x100
1542 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc)
1543 sd.sd_stype = sd.sd_rtype + 0x100;
1545 if ((ei->ei_list != NULL && seq_search(sd.sd_entity_ref,
1546 ei->ei_list, ei->ei_listsz) == B_TRUE) ||
1547 (sensor_entity == ei->ei_id && sensor_inst == ei->ei_inst)) {
1549 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) {
1550 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor "
1551 "node for %s\n", sd.sd_entity_ref);
1552 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP)
1553 return (-1);
1556 return (0);
1559 static int
1560 get_entity_info(topo_mod_t *mod, tnode_t *node, ipmi_handle_t *hdl,
1561 struct entity_info *ei)
1563 char **entity_refs;
1564 int err;
1565 uint_t nelems;
1566 ipmi_sdr_t *ref_sdr;
1567 ipmi_sdr_full_sensor_t *fsensor;
1568 ipmi_sdr_compact_sensor_t *csensor;
1569 ipmi_sdr_fru_locator_t *floc;
1570 ipmi_sdr_generic_locator_t *gloc;
1571 boolean_t found_sdr = B_FALSE;
1574 * Use the entity ref to lookup the SDR, which will have the entity ID
1575 * and instance.
1577 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
1578 "entity_ref", &entity_refs, &nelems, &err) != 0) {
1579 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
1580 "property on %s=%d (%s)\n", __func__, topo_node_name(node),
1581 topo_node_instance(node), topo_strerror(err));
1582 topo_mod_ipmi_rele(mod);
1583 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1586 for (int i = 0; i < nelems; i++) {
1587 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
1588 found_sdr = B_TRUE;
1589 break;
1590 } else
1591 topo_mod_dprintf(mod, "%s: Failed to lookup SDR for %s "
1592 "(%s)\n", __func__, entity_refs[i],
1593 ipmi_errmsg(hdl));
1595 strarr_free(mod, entity_refs, nelems);
1596 if (! found_sdr) {
1597 topo_mod_ipmi_rele(mod);
1598 return (-1);
1601 switch (ref_sdr->is_type) {
1602 case IPMI_SDR_TYPE_FULL_SENSOR:
1603 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record;
1604 ei->ei_id = fsensor->is_fs_entity_id;
1605 ei->ei_inst = fsensor->is_fs_entity_instance;
1606 break;
1607 case IPMI_SDR_TYPE_COMPACT_SENSOR:
1608 csensor
1609 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record;
1610 ei->ei_id = csensor->is_cs_entity_id;
1611 ei->ei_inst = csensor->is_cs_entity_instance;
1612 break;
1613 case IPMI_SDR_TYPE_FRU_LOCATOR:
1614 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record;
1615 ei->ei_id = floc->is_fl_entity;
1616 ei->ei_inst = floc->is_fl_instance;
1617 break;
1618 case IPMI_SDR_TYPE_GENERIC_LOCATOR:
1619 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record;
1620 ei->ei_id = gloc->is_gl_entity;
1621 ei->ei_inst = gloc->is_gl_instance;
1622 break;
1623 default:
1624 topo_mod_dprintf(mod, "Failed to determine entity id "
1625 "and instance\n", ipmi_errmsg(hdl));
1626 topo_mod_ipmi_rele(mod);
1627 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1629 return (0);
1632 /* ARGSUSED */
1633 static int
1634 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1635 nvlist_t *in, nvlist_t **out)
1637 int err, ret = -1;
1638 struct entity_info ei = {0};
1639 ipmi_handle_t *hdl;
1641 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1642 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1643 return (-1);
1647 * For cases where the records in the SDR are hopelessly broken, then
1648 * we'll resort to hardcoding a list of sensor entities that should be
1649 * bound to this particular node. Otherwise, we'll first check if the
1650 * properties for the associated IPMI entity id and instance exist. If
1651 * not, we check for a property referencing an IPMI entity name on which
1652 * we can lookup the entity ID and instance. If none of the above pans
1653 * out, then we bail out.
1655 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
1656 TOPO_PROP_IPMI_ENTITY_LIST, &ei.ei_list, &ei.ei_listsz, &err)
1657 != 0 && (topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
1658 TOPO_PROP_IPMI_ENTITY_ID, &ei.ei_id, &err) != 0 ||
1659 topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
1660 TOPO_PROP_IPMI_ENTITY_INST, &ei.ei_inst, &err) != 0)) {
1661 if (get_entity_info(mod, node, hdl, &ei) != 0)
1662 goto out;
1664 ei.ei_node = node;
1665 ei.ei_mod = mod;
1668 * Now iterate through all of the full and compact sensor data records
1669 * and create a sensor facility node for each record that matches our
1670 * entity ID and instance
1672 if ((ret = ipmi_sdr_iter(hdl, sdr_callback, &ei)) != 0) {
1673 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n");
1675 out:
1676 topo_mod_ipmi_rele(mod);
1677 if (ei.ei_list != NULL)
1678 strarr_free(mod, ei.ei_list, ei.ei_listsz);
1680 return (ret);
1683 static int
1684 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1685 nvlist_t *in, nvlist_t **out)
1687 char **fmtarr, **entity_refs, buf[BUFSZ];
1688 tnode_t *refnode;
1689 uint_t nelems;
1690 int ret, inst1, inst2;
1691 uint32_t offset, nparams;
1692 nvlist_t *args, *nvl;
1694 if (vers > TOPO_METH_IPMI_ENTITY_VERSION)
1695 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1697 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1698 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1699 strerror(ret));
1700 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1702 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1703 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1704 strerror(ret));
1705 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1707 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) {
1708 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n",
1709 strerror(ret));
1710 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1712 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1713 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1714 strerror(errno));
1715 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1718 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1719 == NULL)
1720 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1722 if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1723 refnode = topo_node_parent(node);
1724 else
1725 refnode = node;
1727 for (int i = 0; i < nelems; i++) {
1728 switch (nparams) {
1729 case 1:
1730 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1731 (void) snprintf(buf, BUFSZ, fmtarr[i],
1732 (topo_node_instance(refnode) + offset));
1733 break;
1734 case 2:
1735 inst1 = topo_node_instance(topo_node_parent(refnode))
1736 + offset;
1737 inst2 = topo_node_instance(refnode) + offset;
1738 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1739 (void) snprintf(buf, BUFSZ, fmtarr[i], inst1, inst2);
1740 break;
1741 default:
1742 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n",
1743 nparams);
1744 strarr_free(mod, entity_refs, nelems);
1745 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1747 entity_refs[i] = topo_mod_strdup(mod, buf);
1749 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1750 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1751 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1752 TOPO_TYPE_STRING_ARRAY) != 0 ||
1753 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs,
1754 nelems) != 0) {
1756 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1757 strarr_free(mod, entity_refs, nelems);
1758 nvlist_free(nvl);
1759 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1761 strarr_free(mod, entity_refs, nelems);
1762 *out = nvl;
1764 return (0);
1767 /* ARGSUSED */
1768 static int
1769 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1770 nvlist_t *in, nvlist_t **out)
1772 char **fmtarr, **entity_refs, buf[BUFSZ];
1773 tnode_t *chip, *dimm;
1774 int ret;
1775 uint_t nelems;
1776 uint32_t offset;
1777 nvlist_t *args, *nvl;
1779 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1780 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1781 strerror(ret));
1782 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1784 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1785 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1786 strerror(ret));
1787 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1789 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1790 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1791 strerror(errno));
1792 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1795 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1796 == NULL)
1797 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1799 if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1800 dimm = topo_node_parent(node);
1801 else
1802 dimm = node;
1804 chip = topo_node_parent(topo_node_parent(dimm));
1806 for (int i = 0; i < nelems; i++) {
1807 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1808 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
1809 (topo_node_instance(dimm) + offset));
1810 entity_refs[i] = topo_mod_strdup(mod, buf);
1813 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1814 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1815 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1816 TOPO_TYPE_STRING_ARRAY) != 0 ||
1817 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
1818 != 0) {
1819 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1820 strarr_free(mod, entity_refs, nelems);
1821 nvlist_free(nvl);
1822 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1824 strarr_free(mod, entity_refs, nelems);
1825 *out = nvl;
1827 return (0);
1830 /* ARGSUSED */
1831 static int
1832 cs_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1833 nvlist_t *in, nvlist_t **out)
1835 char **fmtarr, **entity_refs, buf[BUFSZ];
1836 tnode_t *chip, *chan, *cs;
1837 int ret, dimm_num;
1838 uint_t nelems;
1839 uint32_t offset;
1840 nvlist_t *args, *nvl;
1842 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1843 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1844 strerror(ret));
1845 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1847 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1848 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1849 strerror(ret));
1850 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1852 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1853 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1854 strerror(errno));
1855 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1858 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1859 == NULL)
1860 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1862 if (topo_node_flags(node) & TOPO_NODE_FACILITY) {
1863 cs = topo_node_parent(node);
1864 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
1865 chan = topo_node_parent(cs);
1867 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
1868 + topo_node_instance(cs) + offset;
1869 } else {
1870 cs = node;
1871 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
1872 chan = topo_node_parent(cs);
1874 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
1875 + topo_node_instance(chan) + offset;
1878 for (int i = 0; i < nelems; i++) {
1879 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1880 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
1881 dimm_num);
1882 entity_refs[i] = topo_mod_strdup(mod, buf);
1885 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1886 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1887 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1888 TOPO_TYPE_STRING_ARRAY) != 0 ||
1889 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
1890 != 0) {
1891 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1892 strarr_free(mod, entity_refs, nelems);
1893 nvlist_free(nvl);
1894 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1896 strarr_free(mod, entity_refs, nelems);
1897 *out = nvl;
1899 return (0);
1902 /*ARGSUSED*/
1903 static int
1904 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
1905 topo_instance_t min, topo_instance_t max, void *arg, void *unused)
1907 topo_pgroup_info_t pgi;
1908 int err;
1910 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) {
1911 pgi.tpi_name = TOPO_PGROUP_IPMI;
1912 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1913 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1914 pgi.tpi_version = 1;
1915 if (topo_pgroup_create(rnode, &pgi, &err) != 0) {
1916 if (err != ETOPO_PROP_DEFD) {
1917 topo_mod_dprintf(mod,
1918 "pgroups create failure: %s\n",
1919 topo_strerror(err));
1920 return (-1);
1923 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) {
1924 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
1925 "topo_method_register() failed: %s",
1926 topo_mod_errmsg(mod));
1927 return (-1);
1929 } else {
1930 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) {
1931 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
1932 "topo_method_register() failed: %s",
1933 topo_mod_errmsg(mod));
1934 return (-1);
1937 return (0);