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 #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_SLOW; 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_SLOW || 537 ledmode == IPMI_SUNOEM_LED_MODE_FAST) 538 ledmode = TOPO_LED_STATE_ON; 539 else 540 ledmode = TOPO_LED_STATE_OFF; 541 542 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 543 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 544 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 545 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { 546 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 547 nvlist_free(nvl); 548 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 549 } 550 *out = nvl; 551 552 return (0); 553 } 554 555 556 /* 557 * This is a method for the "mode" property that is specific for the drive bay 558 * LED's on thumper platforms. On thumper, the drive bay LED's are manipulated 559 * by asserting the right state bits in the hdd#.state compact SDR. 560 */ 561 static int 562 thumper_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 563 nvlist_t *in, nvlist_t **out) 564 { 565 char *entity_ref; 566 ipmi_sdr_compact_sensor_t *cs = NULL; 567 ipmi_handle_t *hdl; 568 int err, ret; 569 uint32_t mask, type, ledmode; 570 nvlist_t *pargs, *nvl; 571 572 if (vers > TOPO_METH_THUMPER_MODE_VERSION) 573 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 574 575 /* 576 * Figure out which sensor state mask to use based on the indicator 577 * node's type prop val 578 */ 579 if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE, 580 &type, &err) != 0) { 581 topo_mod_dprintf(mod, "Failed to lookup %s property " 582 "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err)); 583 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 584 } 585 switch (type) { 586 case (TOPO_LED_TYPE_SERVICE): 587 mask = THUMPER_SERVICE_LED_MASK; 588 break; 589 case (TOPO_LED_TYPE_PRESENT): 590 mask = THUMPER_PRESENT_LED_MASK; 591 break; 592 case (TOPO_LED_TYPE_OK2RM): 593 mask = THUMPER_OK2RM_LED_MASK; 594 break; 595 default: 596 topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type); 597 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 598 } 599 600 /* 601 * Get an IPMI handle and then lookup the compact sensor data record 602 * referenced by the entity_ref prop val 603 */ 604 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 605 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 606 return (-1); 607 } 608 609 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 610 &entity_ref, &err) != 0) { 611 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 612 "(%s)", topo_strerror(err)); 613 topo_mod_ipmi_rele(mod); 614 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 615 } 616 617 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) 618 == NULL) { 619 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 620 entity_ref, ipmi_errmsg(hdl)); 621 topo_mod_strfree(mod, entity_ref); 622 topo_mod_ipmi_rele(mod); 623 return (-1); 624 } 625 626 /* 627 * Now lookup the propmethod argument list and figure out whether we're 628 * doing a get or a set operation, and then do it. 629 */ 630 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && 631 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { 632 /* 633 * Set the LED mode 634 */ 635 ipmi_set_sensor_reading_t sr_out = { 0 }; 636 637 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, 638 &ledmode)) != 0) { 639 topo_mod_dprintf(mod, "Failed to lookup %s nvpair " 640 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret)); 641 topo_mod_strfree(mod, entity_ref); 642 topo_mod_ipmi_rele(mod); 643 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 644 } 645 646 if (ledmode == TOPO_LED_STATE_OFF) { 647 sr_out.iss_deassert_state = mask; 648 sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET; 649 } else if (ledmode == TOPO_LED_STATE_ON) { 650 sr_out.iss_assert_state = mask; 651 sr_out.iss_assert_op = IPMI_SENSOR_OP_SET; 652 } else { 653 topo_mod_dprintf(mod, "Invalid LED mode: %d 0x%x\n", 654 ledmode); 655 topo_mod_strfree(mod, entity_ref); 656 topo_mod_ipmi_rele(mod); 657 return (-1); 658 } 659 sr_out.iss_id = cs->is_cs_number; 660 topo_mod_dprintf(mod, "Setting LED mode (mask = 0x%x)\n", mask); 661 if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) { 662 topo_mod_dprintf(mod, "Failed to set sensor reading " 663 "for sensor %s (%s)\n", entity_ref, 664 ipmi_errmsg(hdl)); 665 topo_mod_strfree(mod, entity_ref); 666 topo_mod_ipmi_rele(mod); 667 return (-1); 668 } 669 } else { 670 /* 671 * Get the LED mode 672 */ 673 ipmi_sensor_reading_t *sr_in; 674 675 topo_mod_dprintf(mod, "Getting LED mode\n"); 676 if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number)) 677 == NULL) { 678 topo_mod_dprintf(mod, "Failed to get sensor reading " 679 "for sensor %s (sensor num: %d) (error: %s)\n", 680 entity_ref, cs->is_cs_number, ipmi_errmsg(hdl)); 681 topo_mod_strfree(mod, entity_ref); 682 topo_mod_ipmi_rele(mod); 683 return (-1); 684 } 685 if (sr_in->isr_state & (uint16_t)mask) 686 ledmode = TOPO_LED_STATE_ON; 687 else 688 ledmode = TOPO_LED_STATE_OFF; 689 } 690 topo_mod_strfree(mod, entity_ref); 691 topo_mod_ipmi_rele(mod); 692 693 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 694 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 695 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 696 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { 697 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 698 nvlist_free(nvl); 699 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 700 } 701 *out = nvl; 702 return (0); 703 } 704 705 static int 706 make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd) 707 { 708 int err, ret, i; 709 tnode_t *fnode; 710 char *ftype = "sensor", facname[MAX_ID_LEN]; 711 topo_pgroup_info_t pgi; 712 nvlist_t *arg_nvl = NULL; 713 714 /* 715 * Some platforms have '/' characters in the IPMI entity name, but '/' 716 * has a special meaning for FMRI's so we change them to '.' before 717 * binding the node into the topology. 718 */ 719 (void) strcpy(facname, sd->sd_entity_ref); 720 for (i = 0; facname[i]; i++) 721 if (facname[i] == '/') 722 facname[i] = '.'; 723 724 if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) { 725 topo_mod_dprintf(mod, "Failed to bind facility node: %s\n", 726 facname); 727 /* topo errno set */ 728 return (-1); 729 } 730 731 pgi.tpi_name = TOPO_PGROUP_FACILITY; 732 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 733 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 734 pgi.tpi_version = 1; 735 if (topo_pgroup_create(fnode, &pgi, &err) != 0) { 736 if (err != ETOPO_PROP_DEFD) { 737 topo_mod_dprintf(mod, "pgroups create failure: %s\n", 738 topo_strerror(err)); 739 topo_node_unbind(fnode); 740 return (-1); 741 } 742 } 743 if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) { 744 topo_mod_dprintf(mod, "make_fac_node: " 745 "failed to register facility methods"); 746 topo_node_unbind(fnode); 747 return (-1); 748 } 749 /* 750 * For both threshold and discrete sensors we set up a propmethod for 751 * getting the sensor state and properties to hold the entity ref, 752 * sensor class and sensor type. 753 * 754 * Additionally, for analog sensors we set up a property method for 755 * getting the converted sensor reading and property for the base 756 * unit type 757 */ 758 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, "entity_ref", 759 TOPO_PROP_IMMUTABLE, sd->sd_entity_ref, &err) != 0) { 760 topo_mod_dprintf(mod, "Failed to set entity_ref property on " 761 "node: %s=%d (%s)\n", topo_node_name(fnode), 762 topo_node_instance(fnode), topo_strerror(err)); 763 return (-1); 764 } 765 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS, 766 TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) { 767 topo_mod_dprintf(mod, "Failed to set %s property on node: " 768 "%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode), 769 topo_node_instance(fnode), topo_strerror(err)); 770 return (-1); 771 } 772 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 773 TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) { 774 topo_mod_dprintf(mod, "Failed to set %s property on node: " 775 "%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode), 776 topo_node_instance(fnode), topo_strerror(err)); 777 return (-1); 778 } 779 if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) { 780 topo_node_unbind(fnode); 781 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 782 } 783 784 if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref)) 785 != 0) { 786 topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n", 787 strerror(ret)); 788 nvlist_free(arg_nvl); 789 return (-1); 790 } 791 792 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 793 TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl, 794 &err) != 0) { 795 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac " 796 "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode), 797 topo_strerror(err)); 798 nvlist_free(arg_nvl); 799 return (-1); 800 } 801 802 if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) { 803 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 804 TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, 805 "ipmi_sensor_reading", arg_nvl, &err) != 0) { 806 topo_mod_dprintf(mod, "Failed to register %s propmeth " 807 "on fac node %s (%s)\n", TOPO_SENSOR_READING, 808 topo_node_name(fnode), topo_strerror(err)); 809 nvlist_free(arg_nvl); 810 return (-1); 811 } 812 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 813 TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) 814 != 0) { 815 topo_mod_dprintf(mod, "Failed to set units property on " 816 "node: %s (%s)\n", topo_node_name(fnode), 817 topo_strerror(err)); 818 nvlist_free(arg_nvl); 819 return (-1); 820 } 821 } 822 nvlist_free(arg_nvl); 823 return (0); 824 } 825 826 /* ARGSUSED */ 827 static int 828 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data) 829 { 830 uint8_t sensor_entity, sensor_inst; 831 int sensor_idlen; 832 ipmi_sdr_full_sensor_t *f_sensor = NULL; 833 ipmi_sdr_compact_sensor_t *c_sensor = NULL; 834 struct sensor_data sd; 835 struct entity_info *ei = (struct entity_info *)data; 836 837 switch (sdr->is_type) { 838 case IPMI_SDR_TYPE_FULL_SENSOR: 839 f_sensor = 840 (ipmi_sdr_full_sensor_t *)sdr->is_record; 841 sensor_entity = f_sensor->is_fs_entity_id; 842 sensor_inst = f_sensor->is_fs_entity_instance; 843 sensor_idlen = f_sensor->is_fs_idlen; 844 (void) strncpy(sd.sd_entity_ref, 845 f_sensor->is_fs_idstring, 846 f_sensor->is_fs_idlen); 847 sd.sd_entity_ref[sensor_idlen] = '\0'; 848 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD; 849 sd.sd_units = f_sensor->is_fs_unit2; 850 sd.sd_stype = f_sensor->is_fs_type; 851 sd.sd_rtype = f_sensor->is_fs_reading_type; 852 break; 853 case IPMI_SDR_TYPE_COMPACT_SENSOR: 854 c_sensor = 855 (ipmi_sdr_compact_sensor_t *)sdr->is_record; 856 sensor_entity = c_sensor->is_cs_entity_id; 857 sensor_inst = c_sensor->is_cs_entity_instance; 858 sensor_idlen = c_sensor->is_cs_idlen; 859 (void) strncpy(sd.sd_entity_ref, 860 c_sensor->is_cs_idstring, 861 sensor_idlen); 862 sd.sd_entity_ref[sensor_idlen] = '\0'; 863 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE; 864 sd.sd_units = c_sensor->is_cs_unit2; 865 sd.sd_stype = c_sensor->is_cs_type; 866 sd.sd_rtype = c_sensor->is_cs_reading_type; 867 break; 868 default: 869 return (0); 870 } 871 /* 872 * We offset the threshold and generic sensor reading types by 0x100 873 */ 874 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc) 875 sd.sd_stype = sd.sd_rtype + 0x100; 876 877 if ((sensor_entity == ei->ei_id) && (sensor_inst == ei->ei_inst)) 878 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) { 879 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor " 880 "node for %s\n", sd.sd_entity_ref); 881 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP) 882 return (-1); 883 } 884 return (0); 885 } 886 887 /* ARGSUSED */ 888 static int 889 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 890 nvlist_t *in, nvlist_t **out) 891 { 892 char *entity_ref; 893 int err; 894 struct entity_info ei; 895 ipmi_sdr_t *ref_sdr; 896 ipmi_handle_t *hdl; 897 ipmi_sdr_full_sensor_t *fsensor; 898 ipmi_sdr_compact_sensor_t *csensor; 899 ipmi_sdr_fru_locator_t *floc; 900 ipmi_sdr_generic_locator_t *gloc; 901 902 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 903 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 904 return (-1); 905 } 906 907 /* 908 * Use the entity ref to lookup the SDR, which will have the entity ID 909 * and instance. 910 */ 911 if (topo_prop_get_string(node, TOPO_PGROUP_IPMI, 912 "entity_ref", &entity_ref, &err) != 0) { 913 topo_mod_dprintf(mod, "Failed to lookup entity_ref " 914 "property (%s)\n", topo_strerror(err)); 915 topo_mod_ipmi_rele(mod); 916 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 917 } 918 919 topo_mod_dprintf(mod, "Looking up SDR for %s ...\n", 920 entity_ref); 921 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_ref)) == NULL) { 922 topo_mod_dprintf(mod, "Failed to lookup SDR (%s)\n", 923 ipmi_errmsg(hdl)); 924 topo_mod_strfree(mod, entity_ref); 925 topo_mod_ipmi_rele(mod); 926 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 927 } 928 topo_mod_strfree(mod, entity_ref); 929 930 switch (ref_sdr->is_type) { 931 case IPMI_SDR_TYPE_FULL_SENSOR: 932 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record; 933 ei.ei_id = fsensor->is_fs_entity_id; 934 ei.ei_inst = fsensor->is_fs_entity_instance; 935 break; 936 case IPMI_SDR_TYPE_COMPACT_SENSOR: 937 csensor 938 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record; 939 ei.ei_id = csensor->is_cs_entity_id; 940 ei.ei_inst = csensor->is_cs_entity_instance; 941 break; 942 case IPMI_SDR_TYPE_FRU_LOCATOR: 943 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record; 944 ei.ei_id = floc->is_fl_entity; 945 ei.ei_inst = floc->is_fl_instance; 946 break; 947 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 948 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record; 949 ei.ei_id = gloc->is_gl_entity; 950 ei.ei_inst = gloc->is_gl_instance; 951 break; 952 default: 953 topo_mod_dprintf(mod, "Failed to determine entity id " 954 "and instance\n", ipmi_errmsg(hdl)); 955 topo_mod_ipmi_rele(mod); 956 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 957 } 958 topo_mod_dprintf(mod, "Entity ID = 0x%x, Entity Instance = 0x%x\n", 959 ei.ei_id, ei.ei_inst); 960 961 ei.ei_node = node; 962 ei.ei_mod = mod; 963 964 /* 965 * Now iterate through all of the full and compact sensor data records 966 * and create a sensor facility node for each record that matches our 967 * entity ID and instance 968 */ 969 if (ipmi_sdr_iter(hdl, sdr_callback, &ei) != 0) { 970 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n"); 971 topo_mod_ipmi_rele(mod); 972 return (-1); 973 } 974 975 topo_mod_ipmi_rele(mod); 976 977 return (0); 978 } 979 980 static int 981 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 982 nvlist_t *in, nvlist_t **out) 983 { 984 char *fmtstr, buf[BUFSZ]; 985 tnode_t *refnode; 986 int ret, inst1, inst2; 987 uint32_t offset, nparams; 988 nvlist_t *args, *nvl; 989 990 if (vers > TOPO_METH_IPMI_ENTITY_VERSION) 991 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 992 993 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 994 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 995 strerror(ret)); 996 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 997 } 998 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 999 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1000 strerror(ret)); 1001 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1002 } 1003 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) { 1004 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n", 1005 strerror(ret)); 1006 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1007 } 1008 1009 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1010 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1011 /* topo errno already set */ 1012 return (-1); 1013 } 1014 1015 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1016 refnode = topo_node_parent(node); 1017 else 1018 refnode = node; 1019 1020 switch (nparams) { 1021 case 1: 1022 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1023 (void) snprintf(buf, BUFSZ, fmtstr, 1024 (topo_node_instance(refnode) + offset)); 1025 break; 1026 case 2: 1027 inst1 = topo_node_instance(topo_node_parent(refnode)) + offset; 1028 inst2 = topo_node_instance(refnode) + offset; 1029 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1030 (void) snprintf(buf, BUFSZ, fmtstr, inst1, inst2); 1031 break; 1032 default: 1033 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n", 1034 nparams); 1035 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1036 } 1037 1038 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1039 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1040 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1041 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1042 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1043 nvlist_free(nvl); 1044 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1045 } 1046 *out = nvl; 1047 1048 return (0); 1049 } 1050 1051 /* ARGSUSED */ 1052 static int 1053 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1054 nvlist_t *in, nvlist_t **out) 1055 { 1056 char *fmtstr, buf[BUFSZ]; 1057 tnode_t *chip, *dimm; 1058 int ret; 1059 uint32_t offset; 1060 nvlist_t *args, *nvl; 1061 1062 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1063 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1064 strerror(ret)); 1065 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1066 } 1067 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 1068 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1069 strerror(ret)); 1070 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1071 } 1072 1073 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1074 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1075 /* topo errno already set */ 1076 return (-1); 1077 } 1078 1079 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1080 dimm = topo_node_parent(node); 1081 else 1082 dimm = node; 1083 1084 chip = topo_node_parent(topo_node_parent(dimm)); 1085 1086 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1087 (void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip), 1088 (topo_node_instance(dimm) + offset)); 1089 1090 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1091 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1092 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1093 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1094 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1095 nvlist_free(nvl); 1096 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1097 } 1098 *out = nvl; 1099 1100 return (0); 1101 } 1102 1103 /*ARGSUSED*/ 1104 static int 1105 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 1106 topo_instance_t min, topo_instance_t max, void *arg, void *unused) 1107 { 1108 topo_pgroup_info_t pgi; 1109 int err; 1110 1111 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) { 1112 pgi.tpi_name = TOPO_PGROUP_IPMI; 1113 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1114 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1115 pgi.tpi_version = 1; 1116 if (topo_pgroup_create(rnode, &pgi, &err) != 0) { 1117 if (err != ETOPO_PROP_DEFD) { 1118 topo_mod_dprintf(mod, 1119 "pgroups create failure: %s\n", 1120 topo_strerror(err)); 1121 return (-1); 1122 } 1123 } 1124 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) { 1125 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1126 "topo_method_register() failed: %s", 1127 topo_mod_errmsg(mod)); 1128 return (-1); 1129 } 1130 } else { 1131 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) { 1132 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1133 "topo_method_register() failed: %s", 1134 topo_mod_errmsg(mod)); 1135 return (-1); 1136 } 1137 } 1138 return (0); 1139 } 1140