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