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