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