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; 709 tnode_t *fnode; 710 char *ftype = "sensor"; 711 topo_pgroup_info_t pgi; 712 nvlist_t *arg_nvl = NULL; 713 714 if ((fnode = topo_node_facbind(mod, pnode, sd->sd_entity_ref, 715 ftype)) == NULL) { 716 topo_mod_dprintf(mod, "Failed to bind facility node: %s\n", 717 sd->sd_entity_ref); 718 /* topo errno set */ 719 return (-1); 720 } 721 722 pgi.tpi_name = TOPO_PGROUP_FACILITY; 723 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 724 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 725 pgi.tpi_version = 1; 726 if (topo_pgroup_create(fnode, &pgi, &err) != 0) { 727 if (err != ETOPO_PROP_DEFD) { 728 topo_mod_dprintf(mod, "pgroups create failure: %s\n", 729 topo_strerror(err)); 730 topo_node_unbind(fnode); 731 return (-1); 732 } 733 } 734 if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) { 735 topo_mod_dprintf(mod, "make_fac_node: " 736 "failed to register facility methods"); 737 topo_node_unbind(fnode); 738 return (-1); 739 } 740 /* 741 * For both threshold and discrete sensors we set up a propmethod for 742 * getting the sensor state and properties to hold the entity ref, 743 * sensor class and sensor type. 744 * 745 * Additionally, for analog sensors we set up a property method for 746 * getting the converted sensor reading and property for the base 747 * unit type 748 */ 749 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, "entity_ref", 750 TOPO_PROP_IMMUTABLE, sd->sd_entity_ref, &err) != 0) { 751 topo_mod_dprintf(mod, "Failed to set entity_ref property on " 752 "node: %s=%d (%s)\n", topo_node_name(fnode), 753 topo_node_instance(fnode), topo_strerror(err)); 754 return (-1); 755 } 756 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS, 757 TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) { 758 topo_mod_dprintf(mod, "Failed to set %s property on node: " 759 "%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode), 760 topo_node_instance(fnode), topo_strerror(err)); 761 return (-1); 762 } 763 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 764 TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) { 765 topo_mod_dprintf(mod, "Failed to set %s property on node: " 766 "%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode), 767 topo_node_instance(fnode), topo_strerror(err)); 768 return (-1); 769 } 770 if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) { 771 topo_node_unbind(fnode); 772 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 773 } 774 775 if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref)) 776 != 0) { 777 topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n", 778 strerror(ret)); 779 nvlist_free(arg_nvl); 780 return (-1); 781 } 782 783 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 784 TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl, 785 &err) != 0) { 786 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac " 787 "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode), 788 topo_strerror(err)); 789 nvlist_free(arg_nvl); 790 return (-1); 791 } 792 793 if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) { 794 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY, 795 TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, 796 "ipmi_sensor_reading", arg_nvl, &err) != 0) { 797 topo_mod_dprintf(mod, "Failed to register %s propmeth " 798 "on fac node %s (%s)\n", TOPO_SENSOR_READING, 799 topo_node_name(fnode), topo_strerror(err)); 800 nvlist_free(arg_nvl); 801 return (-1); 802 } 803 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY, 804 TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) 805 != 0) { 806 topo_mod_dprintf(mod, "Failed to set units property on " 807 "node: %s (%s)\n", topo_node_name(fnode), 808 topo_strerror(err)); 809 nvlist_free(arg_nvl); 810 return (-1); 811 } 812 } 813 nvlist_free(arg_nvl); 814 return (0); 815 } 816 817 /* ARGSUSED */ 818 static int 819 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data) 820 { 821 uint8_t sensor_entity, sensor_inst; 822 int sensor_idlen; 823 ipmi_sdr_full_sensor_t *f_sensor = NULL; 824 ipmi_sdr_compact_sensor_t *c_sensor = NULL; 825 struct sensor_data sd; 826 struct entity_info *ei = (struct entity_info *)data; 827 828 switch (sdr->is_type) { 829 case IPMI_SDR_TYPE_FULL_SENSOR: 830 f_sensor = 831 (ipmi_sdr_full_sensor_t *)sdr->is_record; 832 sensor_entity = f_sensor->is_fs_entity_id; 833 sensor_inst = f_sensor->is_fs_entity_instance; 834 sensor_idlen = f_sensor->is_fs_idlen; 835 (void) strncpy(sd.sd_entity_ref, 836 f_sensor->is_fs_idstring, 837 f_sensor->is_fs_idlen); 838 sd.sd_entity_ref[sensor_idlen] = '\0'; 839 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD; 840 sd.sd_units = f_sensor->is_fs_unit2; 841 sd.sd_stype = f_sensor->is_fs_type; 842 sd.sd_rtype = f_sensor->is_fs_reading_type; 843 break; 844 case IPMI_SDR_TYPE_COMPACT_SENSOR: 845 c_sensor = 846 (ipmi_sdr_compact_sensor_t *)sdr->is_record; 847 sensor_entity = c_sensor->is_cs_entity_id; 848 sensor_inst = c_sensor->is_cs_entity_instance; 849 sensor_idlen = c_sensor->is_cs_idlen; 850 (void) strncpy(sd.sd_entity_ref, 851 c_sensor->is_cs_idstring, 852 sensor_idlen); 853 sd.sd_entity_ref[sensor_idlen] = '\0'; 854 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE; 855 sd.sd_units = c_sensor->is_cs_unit2; 856 sd.sd_stype = c_sensor->is_cs_type; 857 sd.sd_rtype = c_sensor->is_cs_reading_type; 858 break; 859 default: 860 return (0); 861 } 862 /* 863 * We offset the threshold and generic sensor reading types by 0x100 864 */ 865 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc) 866 sd.sd_stype = sd.sd_rtype + 0x100; 867 868 if ((sensor_entity == ei->ei_id) && (sensor_inst == ei->ei_inst)) 869 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) { 870 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor " 871 "node for %s\n", sd.sd_entity_ref); 872 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP) 873 return (-1); 874 } 875 return (0); 876 } 877 878 /* ARGSUSED */ 879 static int 880 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 881 nvlist_t *in, nvlist_t **out) 882 { 883 char *entity_ref; 884 int err; 885 struct entity_info ei; 886 ipmi_sdr_t *ref_sdr; 887 ipmi_handle_t *hdl; 888 ipmi_sdr_full_sensor_t *fsensor; 889 ipmi_sdr_compact_sensor_t *csensor; 890 ipmi_sdr_fru_locator_t *floc; 891 ipmi_sdr_generic_locator_t *gloc; 892 893 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 894 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 895 return (-1); 896 } 897 898 /* 899 * Use the entity ref to lookup the SDR, which will have the entity ID 900 * and instance. 901 */ 902 if (topo_prop_get_string(node, TOPO_PGROUP_IPMI, 903 "entity_ref", &entity_ref, &err) != 0) { 904 topo_mod_dprintf(mod, "Failed to lookup entity_ref " 905 "property (%s)\n", topo_strerror(err)); 906 topo_mod_ipmi_rele(mod); 907 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 908 } 909 910 topo_mod_dprintf(mod, "Looking up SDR for %s ...\n", 911 entity_ref); 912 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_ref)) == NULL) { 913 topo_mod_dprintf(mod, "Failed to lookup SDR (%s)\n", 914 ipmi_errmsg(hdl)); 915 topo_mod_strfree(mod, entity_ref); 916 topo_mod_ipmi_rele(mod); 917 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 918 } 919 topo_mod_strfree(mod, entity_ref); 920 921 switch (ref_sdr->is_type) { 922 case IPMI_SDR_TYPE_FULL_SENSOR: 923 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record; 924 ei.ei_id = fsensor->is_fs_entity_id; 925 ei.ei_inst = fsensor->is_fs_entity_instance; 926 break; 927 case IPMI_SDR_TYPE_COMPACT_SENSOR: 928 csensor 929 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record; 930 ei.ei_id = csensor->is_cs_entity_id; 931 ei.ei_inst = csensor->is_cs_entity_instance; 932 break; 933 case IPMI_SDR_TYPE_FRU_LOCATOR: 934 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record; 935 ei.ei_id = floc->is_fl_entity; 936 ei.ei_inst = floc->is_fl_instance; 937 break; 938 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 939 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record; 940 ei.ei_id = gloc->is_gl_entity; 941 ei.ei_inst = gloc->is_gl_instance; 942 break; 943 default: 944 topo_mod_dprintf(mod, "Failed to determine entity id " 945 "and instance\n", ipmi_errmsg(hdl)); 946 topo_mod_ipmi_rele(mod); 947 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 948 } 949 topo_mod_dprintf(mod, "Entity ID = 0x%x, Entity Instance = 0x%x\n", 950 ei.ei_id, ei.ei_inst); 951 952 ei.ei_node = node; 953 ei.ei_mod = mod; 954 955 /* 956 * Now iterate through all of the full and compact sensor data records 957 * and create a sensor facility node for each record that matches our 958 * entity ID and instance 959 */ 960 if (ipmi_sdr_iter(hdl, sdr_callback, &ei) != 0) { 961 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n"); 962 topo_mod_ipmi_rele(mod); 963 return (-1); 964 } 965 966 topo_mod_ipmi_rele(mod); 967 968 return (0); 969 } 970 971 static int 972 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 973 nvlist_t *in, nvlist_t **out) 974 { 975 char *fmtstr, buf[BUFSZ]; 976 tnode_t *refnode; 977 int ret, inst1, inst2; 978 uint32_t offset, nparams; 979 nvlist_t *args, *nvl; 980 981 if (vers > TOPO_METH_IPMI_ENTITY_VERSION) 982 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 983 984 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 985 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 986 strerror(ret)); 987 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 988 } 989 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 990 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 991 strerror(ret)); 992 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 993 } 994 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) { 995 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n", 996 strerror(ret)); 997 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 998 } 999 1000 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1001 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1002 /* topo errno already set */ 1003 return (-1); 1004 } 1005 1006 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1007 refnode = topo_node_parent(node); 1008 else 1009 refnode = node; 1010 1011 switch (nparams) { 1012 case 1: 1013 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1014 (void) snprintf(buf, BUFSZ, fmtstr, 1015 (topo_node_instance(refnode) + offset)); 1016 break; 1017 case 2: 1018 inst1 = topo_node_instance(topo_node_parent(refnode)) + offset; 1019 inst2 = topo_node_instance(refnode) + offset; 1020 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1021 (void) snprintf(buf, BUFSZ, fmtstr, inst1, inst2); 1022 break; 1023 default: 1024 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n", 1025 nparams); 1026 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1027 } 1028 1029 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1030 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1031 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1032 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1033 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1034 nvlist_free(nvl); 1035 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1036 } 1037 *out = nvl; 1038 1039 return (0); 1040 } 1041 1042 /* ARGSUSED */ 1043 static int 1044 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1045 nvlist_t *in, nvlist_t **out) 1046 { 1047 char *fmtstr, buf[BUFSZ]; 1048 tnode_t *chip, *dimm; 1049 int ret; 1050 uint32_t offset; 1051 nvlist_t *args, *nvl; 1052 1053 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1054 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1055 strerror(ret)); 1056 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1057 } 1058 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 1059 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1060 strerror(ret)); 1061 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1062 } 1063 1064 if ((fmtstr = get_fmtstr(mod, in)) == NULL) { 1065 topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n"); 1066 /* topo errno already set */ 1067 return (-1); 1068 } 1069 1070 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1071 dimm = topo_node_parent(node); 1072 else 1073 dimm = node; 1074 1075 chip = topo_node_parent(topo_node_parent(dimm)); 1076 1077 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1078 (void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip), 1079 (topo_node_instance(dimm) + offset)); 1080 1081 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1082 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1083 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING) != 0 || 1084 nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, buf) != 0) { 1085 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1086 nvlist_free(nvl); 1087 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1088 } 1089 *out = nvl; 1090 1091 return (0); 1092 } 1093 1094 /*ARGSUSED*/ 1095 static int 1096 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 1097 topo_instance_t min, topo_instance_t max, void *arg, void *unused) 1098 { 1099 topo_pgroup_info_t pgi; 1100 int err; 1101 1102 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) { 1103 pgi.tpi_name = TOPO_PGROUP_IPMI; 1104 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1105 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1106 pgi.tpi_version = 1; 1107 if (topo_pgroup_create(rnode, &pgi, &err) != 0) { 1108 if (err != ETOPO_PROP_DEFD) { 1109 topo_mod_dprintf(mod, 1110 "pgroups create failure: %s\n", 1111 topo_strerror(err)); 1112 return (-1); 1113 } 1114 } 1115 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) { 1116 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1117 "topo_method_register() failed: %s", 1118 topo_mod_errmsg(mod)); 1119 return (-1); 1120 } 1121 } else { 1122 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) { 1123 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 1124 "topo_method_register() failed: %s", 1125 topo_mod_errmsg(mod)); 1126 return (-1); 1127 } 1128 } 1129 return (0); 1130 } 1131