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 2008 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 #define TOPO_PGROUP_IPMI "ipmi" 44 45 #define THUMPER_PRESENT_LED_MASK 0x01 46 #define THUMPER_SERVICE_LED_MASK 0x02 47 #define THUMPER_OK2RM_LED_MASK 0x08 48 49 /* 50 * The largest possible SDR ID length is 2^5+1 51 */ 52 #define MAX_ID_LEN 33 53 54 #define TOPO_METH_IPMI_READING_VERSION 0 55 #define TOPO_METH_IPMI_STATE_VERSION 0 56 #define TOPO_METH_IPMI_MODE_VERSION 0 57 #define TOPO_METH_THUMPER_LOCATE_VERSION 0 58 #define TOPO_METH_THUMPER_MODE_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 ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t, 75 nvlist_t *, nvlist_t **); 76 static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t, 77 nvlist_t *, nvlist_t **); 78 static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t, 79 nvlist_t *, nvlist_t **); 80 static int thumper_locate_mode(topo_mod_t *, tnode_t *, topo_version_t, 81 nvlist_t *, nvlist_t **); 82 static int thumper_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t, 83 nvlist_t *, nvlist_t **); 84 85 const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL }; 86 87 const topo_modinfo_t ipmi_info = 88 { "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION, 89 &ipmi_ops }; 90 91 static const topo_method_t ipmi_node_methods[] = { 92 { TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0, 93 TOPO_STABILITY_INTERNAL, ipmi_sensor_enum }, 94 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC, 95 TOPO_METH_IPMI_ENTITY_VERSION, 96 TOPO_STABILITY_INTERNAL, ipmi_entity }, 97 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC, 98 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 99 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity }, 100 { NULL } 101 }; 102 103 static const topo_method_t ipmi_fac_methods[] = { 104 { "ipmi_sensor_reading", TOPO_PROP_METH_DESC, 105 TOPO_METH_IPMI_READING_VERSION, 106 TOPO_STABILITY_INTERNAL, ipmi_sensor_reading }, 107 { "ipmi_sensor_state", TOPO_PROP_METH_DESC, 108 TOPO_METH_IPMI_STATE_VERSION, 109 TOPO_STABILITY_INTERNAL, ipmi_sensor_state }, 110 { "ipmi_indicator_mode", TOPO_PROP_METH_DESC, 111 TOPO_METH_IPMI_MODE_VERSION, 112 TOPO_STABILITY_INTERNAL, ipmi_indicator_mode }, 113 { "thumper_locate_mode", TOPO_PROP_METH_DESC, 114 TOPO_METH_THUMPER_LOCATE_VERSION, 115 TOPO_STABILITY_INTERNAL, thumper_locate_mode }, 116 { "thumper_indicator_mode", TOPO_PROP_METH_DESC, 117 TOPO_METH_THUMPER_MODE_VERSION, 118 TOPO_STABILITY_INTERNAL, thumper_indicator_mode }, 119 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC, 120 TOPO_METH_IPMI_ENTITY_VERSION, 121 TOPO_STABILITY_INTERNAL, ipmi_entity }, 122 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC, 123 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 124 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity }, 125 { NULL } 126 }; 127 128 struct entity_info { 129 uint32_t ei_id; 130 uint32_t ei_inst; 131 topo_mod_t *ei_mod; 132 tnode_t *ei_node; 133 }; 134 135 struct sensor_data { 136 char sd_entity_ref[MAX_ID_LEN]; 137 uint8_t sd_units; 138 uint32_t sd_stype; 139 uint32_t sd_rtype; 140 char *sd_class; 141 }; 142 143 /*ARGSUSED*/ 144 int 145 _topo_init(topo_mod_t *mod, topo_version_t version) 146 { 147 if (getenv("TOPOFACIPMIDEBUG") != NULL) 148 topo_mod_setdebug(mod); 149 150 return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION)); 151 } 152 153 void 154 _topo_fini(topo_mod_t *mod) 155 { 156 topo_mod_unregister(mod); 157 } 158 159 static char * 160 get_fmtstr(topo_mod_t *mod, nvlist_t *in) 161 { 162 char *fmtstr; 163 nvlist_t *args; 164 165 if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) { 166 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 167 strerror(errno)); 168 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 169 return (NULL); 170 } 171 if (nvlist_lookup_string(args, "format", &fmtstr) != 0) { 172 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n", 173 strerror(errno)); 174 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 175 return (NULL); 176 } 177 return (fmtstr); 178 } 179 180 /*ARGSUSED*/ 181 static int 182 ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 183 nvlist_t *in, nvlist_t **out) 184 { 185 char *entity_ref; 186 ipmi_sdr_t *sdr = NULL; 187 ipmi_sensor_reading_t *reading; 188 ipmi_handle_t *hdl; 189 int err; 190 uint8_t sensor_num; 191 ipmi_sdr_full_sensor_t *fsensor; 192 ipmi_sdr_compact_sensor_t *csensor; 193 nvlist_t *nvl; 194 195 if (vers > TOPO_METH_IPMI_STATE_VERSION) 196 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 197 198 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 199 &entity_ref, &err) != 0) { 200 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 201 "(%s)", topo_strerror(err)); 202 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 203 } 204 205 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 206 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 207 topo_mod_strfree(mod, entity_ref); 208 return (-1); 209 } 210 211 if ((sdr = ipmi_sdr_lookup(hdl, entity_ref)) == NULL) { 212 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 213 entity_ref, ipmi_errmsg(hdl)); 214 topo_mod_strfree(mod, entity_ref); 215 topo_mod_ipmi_rele(mod); 216 return (-1); 217 } 218 219 switch (sdr->is_type) { 220 case IPMI_SDR_TYPE_FULL_SENSOR: 221 fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record; 222 sensor_num = fsensor->is_fs_number; 223 break; 224 case IPMI_SDR_TYPE_COMPACT_SENSOR: 225 csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record; 226 sensor_num = csensor->is_cs_number; 227 break; 228 default: 229 topo_mod_dprintf(mod, "%s does not refer to a full or " 230 "compact SDR\n", entity_ref); 231 topo_mod_strfree(mod, entity_ref); 232 topo_mod_ipmi_rele(mod); 233 return (-1); 234 } 235 if ((reading = ipmi_get_sensor_reading(hdl, sensor_num)) 236 == NULL) { 237 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor " 238 "%s, sensor_num=%d (%s)\n", entity_ref, sensor_num, 239 ipmi_errmsg(hdl)); 240 topo_mod_strfree(mod, entity_ref); 241 topo_mod_ipmi_rele(mod); 242 return (-1); 243 } 244 topo_mod_strfree(mod, entity_ref); 245 topo_mod_ipmi_rele(mod); 246 247 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 248 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, 249 TOPO_SENSOR_STATE) != 0 || 250 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 251 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, reading->isr_state) 252 != 0) { 253 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 254 nvlist_free(nvl); 255 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 256 } 257 *out = nvl; 258 259 return (0); 260 } 261 262 /*ARGSUSED*/ 263 static int 264 ipmi_sensor_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 265 nvlist_t *in, nvlist_t **out) 266 { 267 char *entity_ref, reading_str[BUFSZ]; 268 int err = 0; 269 ipmi_sdr_full_sensor_t *sensor; 270 ipmi_sensor_reading_t *reading; 271 double conv_reading; 272 ipmi_handle_t *hdl; 273 nvlist_t *nvl; 274 275 if (vers > TOPO_METH_IPMI_READING_VERSION) 276 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 277 278 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 279 &entity_ref, &err) != 0) { 280 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 281 "(%s)", topo_strerror(err)); 282 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 283 } 284 285 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 286 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 287 topo_mod_strfree(mod, entity_ref); 288 return (-1); 289 } 290 291 if ((sensor = ipmi_sdr_lookup_full_sensor(hdl, entity_ref)) 292 == NULL) { 293 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 294 entity_ref, ipmi_errmsg(hdl)); 295 topo_mod_strfree(mod, entity_ref); 296 topo_mod_ipmi_rele(mod); 297 return (-1); 298 } 299 300 if ((reading = ipmi_get_sensor_reading(hdl, sensor->is_fs_number)) 301 == NULL) { 302 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor " 303 "%s, sensor_num=%d (%s)\n", entity_ref, 304 sensor->is_fs_number, ipmi_errmsg(hdl)); 305 topo_mod_strfree(mod, entity_ref); 306 topo_mod_ipmi_rele(mod); 307 return (-1); 308 } 309 topo_mod_ipmi_rele(mod); 310 311 if (ipmi_sdr_conv_reading(sensor, reading->isr_reading, &conv_reading) 312 != 0) { 313 topo_mod_dprintf(mod, "Failed to convert sensor reading for " 314 "sensor %s (%s)\n", entity_ref, ipmi_errmsg(hdl)); 315 topo_mod_strfree(mod, entity_ref); 316 return (-1); 317 } 318 topo_mod_strfree(mod, entity_ref); 319 320 (void) snprintf(reading_str, BUFSZ, "%f", conv_reading); 321 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 322 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, 323 TOPO_SENSOR_READING) != 0 || 324 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 || 325 nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, conv_reading) != 0) { 326 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 327 nvlist_free(nvl); 328 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 329 } 330 *out = nvl; 331 332 return (0); 333 } 334 335 static int 336 ipmi_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 337 nvlist_t *in, nvlist_t **out) 338 { 339 char *entity_ref; 340 ipmi_sdr_generic_locator_t *gdl = NULL; 341 ipmi_handle_t *hdl; 342 int err, ret; 343 uint8_t ledmode; 344 uint32_t mode_in; 345 nvlist_t *pargs, *nvl; 346 347 if (vers > TOPO_METH_IPMI_MODE_VERSION) 348 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 349 350 /* 351 * Get an IPMI handle and then lookup the generic device locator sensor 352 * data record referenced by the entity_ref prop val 353 */ 354 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 355 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 356 return (-1); 357 } 358 359 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 360 &entity_ref, &err) != 0) { 361 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 362 "(%s)", topo_strerror(err)); 363 topo_mod_ipmi_rele(mod); 364 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 365 } 366 367 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_ref)) 368 == NULL) { 369 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 370 entity_ref, ipmi_errmsg(hdl)); 371 topo_mod_strfree(mod, entity_ref); 372 topo_mod_ipmi_rele(mod); 373 return (-1); 374 } 375 376 /* 377 * Now look for a private argument list to figure out whether we're 378 * doing a get or a set operation, and then do it. 379 */ 380 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && 381 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { 382 /* 383 * Set the LED mode 384 */ 385 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, 386 &mode_in)) != 0) { 387 topo_mod_dprintf(mod, "Failed to lookup %s nvpair " 388 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret)); 389 topo_mod_strfree(mod, entity_ref); 390 topo_mod_ipmi_rele(mod); 391 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 392 } 393 if (mode_in != TOPO_LED_STATE_OFF && 394 mode_in != TOPO_LED_STATE_ON) { 395 topo_mod_dprintf(mod, "Invalid property value: %d\n", 396 mode_in); 397 topo_mod_strfree(mod, entity_ref); 398 topo_mod_ipmi_rele(mod); 399 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 400 } 401 ledmode = (uint8_t)mode_in; 402 topo_mod_dprintf(mod, "Setting LED mode to %s\n", 403 ledmode ? "ON" : "OFF"); 404 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) { 405 topo_mod_dprintf(mod, "Failed to set LED mode for %s " 406 "(%s)\n", entity_ref, ipmi_errmsg(hdl)); 407 topo_mod_strfree(mod, entity_ref); 408 topo_mod_ipmi_rele(mod); 409 return (-1); 410 } 411 } else { 412 /* 413 * Get the LED mode 414 */ 415 topo_mod_dprintf(mod, "Getting LED mode\n"); 416 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) { 417 topo_mod_dprintf(mod, "Failed to get LED mode for %s " 418 "(%s)\n", entity_ref, ipmi_errmsg(hdl)); 419 topo_mod_strfree(mod, entity_ref); 420 topo_mod_ipmi_rele(mod); 421 return (-1); 422 } 423 } 424 topo_mod_strfree(mod, entity_ref); 425 topo_mod_ipmi_rele(mod); 426 427 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 428 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 429 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 430 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { 431 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 432 nvlist_free(nvl); 433 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 434 } 435 *out = nvl; 436 437 return (0); 438 } 439 440 /* 441 * On thumper platforms these is no seperate locate LED for the drive bays. 442 * Therefore we simulate a locate LED by blinking the ok2rm LED. 443 */ 444 static int 445 thumper_locate_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 446 nvlist_t *in, nvlist_t **out) 447 { 448 char *entity_ref; 449 ipmi_sdr_generic_locator_t *gdl = NULL; 450 ipmi_handle_t *hdl; 451 int err, ret; 452 uint8_t ledmode; 453 uint32_t mode_in; 454 nvlist_t *pargs, *nvl; 455 456 if (vers > TOPO_METH_THUMPER_LOCATE_VERSION) 457 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 458 459 /* 460 * Get an IPMI handle and then lookup the generic device locator sensor 461 * data record referenced by the entity_ref prop val 462 */ 463 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 464 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 465 return (-1); 466 } 467 468 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 469 &entity_ref, &err) != 0) { 470 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 471 "(%s)", topo_strerror(err)); 472 topo_mod_ipmi_rele(mod); 473 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 474 } 475 476 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_ref)) 477 == NULL) { 478 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 479 entity_ref, ipmi_errmsg(hdl)); 480 topo_mod_strfree(mod, entity_ref); 481 topo_mod_ipmi_rele(mod); 482 return (-1); 483 } 484 485 /* 486 * Now look for a private argument list to figure out whether we're 487 * doing a get or a set operation, and then do it. 488 */ 489 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && 490 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { 491 /* 492 * Set the LED mode 493 */ 494 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, 495 &mode_in)) != 0) { 496 topo_mod_dprintf(mod, "Failed to lookup %s nvpair " 497 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret)); 498 topo_mod_strfree(mod, entity_ref); 499 topo_mod_ipmi_rele(mod); 500 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 501 } 502 if (mode_in != TOPO_LED_STATE_OFF && 503 mode_in != TOPO_LED_STATE_ON) { 504 topo_mod_dprintf(mod, "Invalid property value: %d\n", 505 mode_in); 506 topo_mod_strfree(mod, entity_ref); 507 topo_mod_ipmi_rele(mod); 508 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 509 } 510 if (mode_in == TOPO_LED_STATE_ON) 511 ledmode = IPMI_SUNOEM_LED_MODE_FAST; 512 else 513 ledmode = (uint8_t)mode_in; 514 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) { 515 topo_mod_dprintf(mod, "Failed to set LED mode for %s " 516 "(%s)\n", entity_ref, ipmi_errmsg(hdl)); 517 topo_mod_strfree(mod, entity_ref); 518 topo_mod_ipmi_rele(mod); 519 return (-1); 520 } 521 } else { 522 /* 523 * Get the LED mode 524 */ 525 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) { 526 topo_mod_dprintf(mod, "Failed to get LED mode for %s " 527 "(%s)\n", entity_ref, ipmi_errmsg(hdl)); 528 topo_mod_strfree(mod, entity_ref); 529 topo_mod_ipmi_rele(mod); 530 return (-1); 531 } 532 } 533 topo_mod_strfree(mod, entity_ref); 534 topo_mod_ipmi_rele(mod); 535 536 if (ledmode == IPMI_SUNOEM_LED_MODE_FAST) 537 ledmode = TOPO_LED_STATE_ON; 538 else 539 ledmode = TOPO_LED_STATE_OFF; 540 541 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 542 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 543 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 544 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { 545 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 546 nvlist_free(nvl); 547 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 548 } 549 *out = nvl; 550 551 return (0); 552 } 553 554 555 /* 556 * This is a method for the "mode" property that is specific for the drive bay 557 * LED's on thumper platforms. On thumper, the drive bay LED's are manipulated 558 * by asserting the right state bits in the hdd#.state compact SDR. 559 */ 560 static int 561 thumper_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 562 nvlist_t *in, nvlist_t **out) 563 { 564 char *entity_ref; 565 ipmi_sdr_compact_sensor_t *cs = NULL; 566 ipmi_handle_t *hdl; 567 int err, ret; 568 uint32_t mask, type, ledmode; 569 nvlist_t *pargs, *nvl; 570 571 if (vers > TOPO_METH_THUMPER_MODE_VERSION) 572 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 573 574 /* 575 * Figure out which sensor state mask to use based on the indicator 576 * node's type prop val 577 */ 578 if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE, 579 &type, &err) != 0) { 580 topo_mod_dprintf(mod, "Failed to lookup %s property " 581 "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err)); 582 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 583 } 584 switch (type) { 585 case (TOPO_LED_TYPE_SERVICE): 586 mask = THUMPER_SERVICE_LED_MASK; 587 break; 588 case (TOPO_LED_TYPE_PRESENT): 589 mask = THUMPER_PRESENT_LED_MASK; 590 break; 591 case (TOPO_LED_TYPE_OK2RM): 592 mask = THUMPER_OK2RM_LED_MASK; 593 break; 594 default: 595 topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type); 596 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 597 } 598 599 /* 600 * Get an IPMI handle and then lookup the compact sensor data record 601 * referenced by the entity_ref prop val 602 */ 603 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 604 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 605 return (-1); 606 } 607 608 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 609 &entity_ref, &err) != 0) { 610 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 611 "(%s)", topo_strerror(err)); 612 topo_mod_ipmi_rele(mod); 613 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 614 } 615 616 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) 617 == NULL) { 618 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 619 entity_ref, ipmi_errmsg(hdl)); 620 topo_mod_strfree(mod, entity_ref); 621 topo_mod_ipmi_rele(mod); 622 return (-1); 623 } 624 625 /* 626 * Now lookup the propmethod argument list and figure out whether we're 627 * doing a get or a set operation, and then do it. 628 */ 629 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && 630 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { 631 /* 632 * Set the LED mode 633 */ 634 ipmi_set_sensor_reading_t sr_out = { 0 }; 635 636 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, 637 &ledmode)) != 0) { 638 topo_mod_dprintf(mod, "Failed to lookup %s nvpair " 639 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret)); 640 topo_mod_strfree(mod, entity_ref); 641 topo_mod_ipmi_rele(mod); 642 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 643 } 644 645 if (ledmode == TOPO_LED_STATE_OFF) { 646 sr_out.iss_deassert_state = mask; 647 sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET; 648 } else if (ledmode == TOPO_LED_STATE_ON) { 649 sr_out.iss_assert_state = mask; 650 sr_out.iss_assert_op = IPMI_SENSOR_OP_SET; 651 } else { 652 topo_mod_dprintf(mod, "Invalid LED mode: %d 0x%x\n", 653 ledmode); 654 topo_mod_strfree(mod, entity_ref); 655 topo_mod_ipmi_rele(mod); 656 return (-1); 657 } 658 sr_out.iss_id = cs->is_cs_number; 659 topo_mod_dprintf(mod, "Setting LED mode (mask = 0x%x)\n", mask); 660 if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) { 661 topo_mod_dprintf(mod, "Failed to set sensor reading " 662 "for sensor %s (%s)\n", entity_ref, 663 ipmi_errmsg(hdl)); 664 topo_mod_strfree(mod, entity_ref); 665 topo_mod_ipmi_rele(mod); 666 return (-1); 667 } 668 } else { 669 /* 670 * Get the LED mode 671 */ 672 ipmi_sensor_reading_t *sr_in; 673 674 topo_mod_dprintf(mod, "Getting LED mode\n"); 675 if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number)) 676 == NULL) { 677 topo_mod_dprintf(mod, "Failed to get sensor reading " 678 "for sensor %s (sensor num: %d) (error: %s)\n", 679 entity_ref, cs->is_cs_number, ipmi_errmsg(hdl)); 680 topo_mod_strfree(mod, entity_ref); 681 topo_mod_ipmi_rele(mod); 682 return (-1); 683 } 684 if (sr_in->isr_state & (uint16_t)mask) 685 ledmode = TOPO_LED_STATE_ON; 686 else 687 ledmode = TOPO_LED_STATE_OFF; 688 } 689 topo_mod_strfree(mod, entity_ref); 690 topo_mod_ipmi_rele(mod); 691 692 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 693 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 694 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 695 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { 696 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 697 nvlist_free(nvl); 698 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 699 } 700 *out = nvl; 701 return (0); 702 } 703 704 static int 705 make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd) 706 { 707 int err, ret; 708 tnode_t *fnode; 709 char *ftype = "sensor"; 710 topo_pgroup_info_t pgi; 711 nvlist_t *arg_nvl = NULL; 712 713 if ((fnode = topo_node_facbind(mod, pnode, sd->sd_entity_ref, 714 ftype)) == NULL) { 715 topo_mod_dprintf(mod, "Failed to bind facility node: %s\n", 716 sd->sd_entity_ref); 717 /* topo errno set */ 718 return (-1); 719 } 720 721 pgi.tpi_name = TOPO_PGROUP_FACILITY; 722 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 723 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 724 pgi.tpi_version = 1; 725 if (topo_pgroup_create(fnode, &pgi, &err) != 0) { 726 if (err != ETOPO_PROP_DEFD) { 727 topo_mod_dprintf(mod, "pgroups create failure: %s\n", 728 topo_strerror(err)); 729 topo_node_unbind(fnode); 730 return (-1); 731 } 732 } 733 if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) { 734 topo_mod_dprintf(mod, "make_fac_node: " 735 "failed to register facility methods"); 736 topo_node_unbind(fnode); 737 return (-1); 738 } 739 /* 740 * For both threshold and discrete sensors we set up a propmethod for 741 * getting the sensor state and properties to hold the entity ref, 742 * sensor class and sensor type. 743 * 744 * Additionally, for analog sensors we set up a property method for 745 * getting the converted sensor reading and property for the base 746 * unit type 747 */ 748 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, "entity_ref", 749 TOPO_PROP_IMMUTABLE, sd->sd_entity_ref, &err) != 0) { 750 topo_mod_dprintf(mod, "Failed to set entity_ref property on " 751 "node: %s=%d (%s)\n", topo_node_name(fnode), 752 topo_node_instance(fnode), topo_strerror(err)); 753 return (-1); 754 } 755 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS, 756 TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) { 757 topo_mod_dprintf(mod, "Failed to set %s property on node: " 758 "%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode), 759 topo_node_instance(fnode), topo_strerror(err)); 760 return (-1); 761 } 762 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 763 TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) { 764 topo_mod_dprintf(mod, "Failed to set %s property on node: " 765 "%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode), 766 topo_node_instance(fnode), topo_strerror(err)); 767 return (-1); 768 } 769 if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) { 770 topo_node_unbind(fnode); 771 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 772 } 773 774 if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref)) 775 != 0) { 776 topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n", 777 strerror(ret)); 778 nvlist_free(arg_nvl); 779 return (-1); 780 } 781 782 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 783 TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl, 784 &err) != 0) { 785 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac " 786 "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode), 787 topo_strerror(err)); 788 nvlist_free(arg_nvl); 789 return (-1); 790 } 791 792 if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) { 793 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 794 TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, 795 "ipmi_sensor_reading", arg_nvl, &err) != 0) { 796 topo_mod_dprintf(mod, "Failed to register %s propmeth " 797 "on fac node %s (%s)\n", TOPO_SENSOR_READING, 798 topo_node_name(fnode), topo_strerror(err)); 799 nvlist_free(arg_nvl); 800 return (-1); 801 } 802 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 803 TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) 804 != 0) { 805 topo_mod_dprintf(mod, "Failed to set units property on " 806 "node: %s (%s)\n", topo_node_name(fnode), 807 topo_strerror(err)); 808 nvlist_free(arg_nvl); 809 return (-1); 810 } 811 } 812 nvlist_free(arg_nvl); 813 return (0); 814 } 815 816 /* ARGSUSED */ 817 static int 818 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data) 819 { 820 uint8_t sensor_entity, sensor_inst; 821 int sensor_idlen; 822 ipmi_sdr_full_sensor_t *f_sensor = NULL; 823 ipmi_sdr_compact_sensor_t *c_sensor = NULL; 824 struct sensor_data sd; 825 struct entity_info *ei = (struct entity_info *)data; 826 827 switch (sdr->is_type) { 828 case IPMI_SDR_TYPE_FULL_SENSOR: 829 f_sensor = 830 (ipmi_sdr_full_sensor_t *)sdr->is_record; 831 sensor_entity = f_sensor->is_fs_entity_id; 832 sensor_inst = f_sensor->is_fs_entity_instance; 833 sensor_idlen = f_sensor->is_fs_idlen; 834 (void) strncpy(sd.sd_entity_ref, 835 f_sensor->is_fs_idstring, 836 f_sensor->is_fs_idlen); 837 sd.sd_entity_ref[sensor_idlen] = '\0'; 838 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD; 839 sd.sd_units = f_sensor->is_fs_unit2; 840 sd.sd_stype = f_sensor->is_fs_type; 841 sd.sd_rtype = f_sensor->is_fs_reading_type; 842 break; 843 case IPMI_SDR_TYPE_COMPACT_SENSOR: 844 c_sensor = 845 (ipmi_sdr_compact_sensor_t *)sdr->is_record; 846 sensor_entity = c_sensor->is_cs_entity_id; 847 sensor_inst = c_sensor->is_cs_entity_instance; 848 sensor_idlen = c_sensor->is_cs_idlen; 849 (void) strncpy(sd.sd_entity_ref, 850 c_sensor->is_cs_idstring, 851 sensor_idlen); 852 sd.sd_entity_ref[sensor_idlen] = '\0'; 853 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE; 854 sd.sd_units = c_sensor->is_cs_unit2; 855 sd.sd_stype = c_sensor->is_cs_type; 856 sd.sd_rtype = c_sensor->is_cs_reading_type; 857 break; 858 default: 859 return (0); 860 } 861 /* 862 * We offset the threshold and generic sensor reading types by 0x100 863 */ 864 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc) 865 sd.sd_stype = sd.sd_rtype + 0x100; 866 867 if ((sensor_entity == ei->ei_id) && (sensor_inst == ei->ei_inst)) 868 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) { 869 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor " 870 "node for %s\n", sd.sd_entity_ref); 871 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP) 872 return (-1); 873 } 874 return (0); 875 } 876 877 /* ARGSUSED */ 878 static int 879 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 880 nvlist_t *in, nvlist_t **out) 881 { 882 char *entity_ref; 883 int err; 884 struct entity_info ei; 885 ipmi_sdr_t *ref_sdr; 886 ipmi_handle_t *hdl; 887 ipmi_sdr_full_sensor_t *fsensor; 888 ipmi_sdr_compact_sensor_t *csensor; 889 ipmi_sdr_fru_locator_t *floc; 890 ipmi_sdr_generic_locator_t *gloc; 891 892 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 893 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 894 return (-1); 895 } 896 897 /* 898 * Use the entity ref to lookup the SDR, which will have the entity ID 899 * and instance. 900 */ 901 if (topo_prop_get_string(node, TOPO_PGROUP_IPMI, 902 "entity_ref", &entity_ref, &err) != 0) { 903 topo_mod_dprintf(mod, "Failed to lookup entity_ref " 904 "property (%s)\n", topo_strerror(err)); 905 topo_mod_ipmi_rele(mod); 906 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 907 } 908 909 topo_mod_dprintf(mod, "Looking up SDR for %s ...\n", 910 entity_ref); 911 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_ref)) == NULL) { 912 topo_mod_dprintf(mod, "Failed to lookup SDR (%s)\n", 913 ipmi_errmsg(hdl)); 914 topo_mod_strfree(mod, entity_ref); 915 topo_mod_ipmi_rele(mod); 916 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 917 } 918 topo_mod_strfree(mod, entity_ref); 919 920 switch (ref_sdr->is_type) { 921 case IPMI_SDR_TYPE_FULL_SENSOR: 922 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record; 923 ei.ei_id = fsensor->is_fs_entity_id; 924 ei.ei_inst = fsensor->is_fs_entity_instance; 925 break; 926 case IPMI_SDR_TYPE_COMPACT_SENSOR: 927 csensor 928 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record; 929 ei.ei_id = csensor->is_cs_entity_id; 930 ei.ei_inst = csensor->is_cs_entity_instance; 931 break; 932 case IPMI_SDR_TYPE_FRU_LOCATOR: 933 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record; 934 ei.ei_id = floc->is_fl_entity; 935 ei.ei_inst = floc->is_fl_instance; 936 break; 937 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 938 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record; 939 ei.ei_id = gloc->is_gl_entity; 940 ei.ei_inst = gloc->is_gl_instance; 941 break; 942 default: 943 topo_mod_dprintf(mod, "Failed to determine entity id " 944 "and instance\n", ipmi_errmsg(hdl)); 945 topo_mod_ipmi_rele(mod); 946 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 947 } 948 topo_mod_dprintf(mod, "Entity ID = 0x%x, Entity Instance = 0x%x\n", 949 ei.ei_id, ei.ei_inst); 950 951 ei.ei_node = node; 952 ei.ei_mod = mod; 953 954 /* 955 * Now iterate through all of the full and compact sensor data records 956 * and create a sensor facility node for each record that matches our 957 * entity ID and instance 958 */ 959 if (ipmi_sdr_iter(hdl, sdr_callback, &ei) != 0) { 960 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n"); 961 topo_mod_ipmi_rele(mod); 962 return (-1); 963 } 964 965 topo_mod_ipmi_rele(mod); 966 967 return (0); 968 } 969 970 static int 971 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 972 nvlist_t *in, nvlist_t **out) 973 { 974 char *fmtstr, buf[BUFSZ]; 975 tnode_t *refnode; 976 int ret, inst1, inst2; 977 uint32_t offset, nparams; 978 nvlist_t *args, *nvl; 979 980 if (vers > TOPO_METH_IPMI_ENTITY_VERSION) 981 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 982 983 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 984 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 985 strerror(ret)); 986 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 987 } 988 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 989 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 990 strerror(ret)); 991 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 992 } 993 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) { 994 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n", 995 strerror(ret)); 996 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 997 } 998 999 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1000 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1001 /* topo errno already set */ 1002 return (-1); 1003 } 1004 1005 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1006 refnode = topo_node_parent(node); 1007 else 1008 refnode = node; 1009 1010 switch (nparams) { 1011 case 1: 1012 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1013 (void) snprintf(buf, BUFSZ, fmtstr, 1014 (topo_node_instance(refnode) + offset)); 1015 break; 1016 case 2: 1017 inst1 = topo_node_instance(topo_node_parent(refnode)) + offset; 1018 inst2 = topo_node_instance(refnode) + offset; 1019 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1020 (void) snprintf(buf, BUFSZ, fmtstr, inst1, inst2); 1021 break; 1022 default: 1023 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n", 1024 nparams); 1025 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1026 } 1027 1028 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1029 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1030 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1031 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1032 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1033 nvlist_free(nvl); 1034 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1035 } 1036 *out = nvl; 1037 1038 return (0); 1039 } 1040 1041 /* ARGSUSED */ 1042 static int 1043 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1044 nvlist_t *in, nvlist_t **out) 1045 { 1046 char *fmtstr, buf[BUFSZ]; 1047 tnode_t *chip, *dimm; 1048 int ret; 1049 uint32_t offset; 1050 nvlist_t *args, *nvl; 1051 1052 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1053 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1054 strerror(ret)); 1055 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1056 } 1057 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 1058 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1059 strerror(ret)); 1060 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1061 } 1062 1063 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1064 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1065 /* topo errno already set */ 1066 return (-1); 1067 } 1068 1069 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1070 dimm = topo_node_parent(node); 1071 else 1072 dimm = node; 1073 1074 chip = topo_node_parent(topo_node_parent(dimm)); 1075 1076 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1077 (void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip), 1078 (topo_node_instance(dimm) + offset)); 1079 1080 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1081 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1082 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1083 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1084 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1085 nvlist_free(nvl); 1086 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1087 } 1088 *out = nvl; 1089 1090 return (0); 1091 } 1092 1093 /*ARGSUSED*/ 1094 static int 1095 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 1096 topo_instance_t min, topo_instance_t max, void *arg, void *unused) 1097 { 1098 topo_pgroup_info_t pgi; 1099 int err; 1100 1101 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) { 1102 pgi.tpi_name = TOPO_PGROUP_IPMI; 1103 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1104 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1105 pgi.tpi_version = 1; 1106 if (topo_pgroup_create(rnode, &pgi, &err) != 0) { 1107 if (err != ETOPO_PROP_DEFD) { 1108 topo_mod_dprintf(mod, 1109 "pgroups create failure: %s\n", 1110 topo_strerror(err)); 1111 return (-1); 1112 } 1113 } 1114 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) { 1115 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1116 "topo_method_register() failed: %s", 1117 topo_mod_errmsg(mod)); 1118 return (-1); 1119 } 1120 } else { 1121 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) { 1122 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1123 "topo_method_register() failed: %s", 1124 topo_mod_errmsg(mod)); 1125 return (-1); 1126 } 1127 } 1128 return (0); 1129 } 1130