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 (c) 2019, Joyent, Inc. 27 */ 28 #include <unistd.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <limits.h> 34 #include <alloca.h> 35 #include <errno.h> 36 #include <libnvpair.h> 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/fm/protocol.h> 40 #include <fm/libtopo.h> 41 #include <fm/topo_mod.h> 42 #include <libipmi.h> 43 44 #define BUFSZ 128 45 46 #define BAY_PRESENT_LED_MASK 0x01 47 48 /* 49 * The largest possible SDR ID length is 2^5+1 50 */ 51 #define MAX_ID_LEN 33 52 53 #define TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION 0 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_X4500_MODE_VERSION 0 58 #define TOPO_METH_BAY_LOCATE_VERSION 0 59 #define TOPO_METH_BAY_MODE_VERSION 0 60 #define TOPO_METH_CHASSIS_SERVICE_VERSION 0 61 #define TOPO_METH_IPMI_ENTITY_VERSION 0 62 #define TOPO_METH_DIMM_IPMI_ENTITY_VERSION 0 63 #define TOPO_METH_CHASSIS_IDENT_VERSION 0 64 65 static int fac_prov_ipmi_enum(topo_mod_t *, tnode_t *, const char *, 66 topo_instance_t, topo_instance_t, void *, void *); 67 68 /* 69 * IPMI facility provider methods 70 */ 71 static int ipmi_sensor_enum(topo_mod_t *, tnode_t *, topo_version_t, 72 nvlist_t *, nvlist_t **); 73 static int ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 74 nvlist_t **); 75 static int dimm_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 76 nvlist_t **); 77 static int cs_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 78 nvlist_t **); 79 static int ipmi_platform_message(topo_mod_t *, tnode_t *, topo_version_t, 80 nvlist_t *, nvlist_t **); 81 static int ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t, 82 nvlist_t *, nvlist_t **); 83 static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t, 84 nvlist_t *, nvlist_t **); 85 static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t, 86 nvlist_t *, nvlist_t **); 87 static int bay_locate_mode(topo_mod_t *, tnode_t *, topo_version_t, 88 nvlist_t *, nvlist_t **); 89 static int x4500_present_mode(topo_mod_t *, tnode_t *, topo_version_t, 90 nvlist_t *, nvlist_t **); 91 static int bay_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t, 92 nvlist_t *, nvlist_t **); 93 static int chassis_service_mode(topo_mod_t *, tnode_t *, topo_version_t, 94 nvlist_t *, nvlist_t **); 95 static int chassis_ident_mode(topo_mod_t *, tnode_t *, topo_version_t, 96 nvlist_t *, nvlist_t **); 97 98 const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL }; 99 100 const topo_modinfo_t ipmi_info = 101 { "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION, 102 &ipmi_ops }; 103 104 static const topo_method_t ipmi_node_methods[] = { 105 { TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0, 106 TOPO_STABILITY_INTERNAL, ipmi_sensor_enum }, 107 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC, 108 TOPO_METH_IPMI_ENTITY_VERSION, 109 TOPO_STABILITY_INTERNAL, ipmi_entity }, 110 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC, 111 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 112 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity }, 113 { "cs_ipmi_entity", TOPO_PROP_METH_DESC, 114 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 115 TOPO_STABILITY_INTERNAL, cs_ipmi_entity }, 116 { TOPO_METH_SENSOR_FAILURE, TOPO_METH_SENSOR_FAILURE_DESC, 117 TOPO_METH_SENSOR_FAILURE_VERSION, TOPO_STABILITY_INTERNAL, 118 topo_method_sensor_failure }, 119 { NULL } 120 }; 121 122 static const topo_method_t ipmi_fac_methods[] = { 123 { "ipmi_platform_message", TOPO_PROP_METH_DESC, 124 TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION, 125 TOPO_STABILITY_INTERNAL, ipmi_platform_message }, 126 { "ipmi_sensor_reading", TOPO_PROP_METH_DESC, 127 TOPO_METH_IPMI_READING_VERSION, 128 TOPO_STABILITY_INTERNAL, ipmi_sensor_reading }, 129 { "ipmi_sensor_state", TOPO_PROP_METH_DESC, 130 TOPO_METH_IPMI_STATE_VERSION, 131 TOPO_STABILITY_INTERNAL, ipmi_sensor_state }, 132 { "ipmi_indicator_mode", TOPO_PROP_METH_DESC, 133 TOPO_METH_IPMI_MODE_VERSION, 134 TOPO_STABILITY_INTERNAL, ipmi_indicator_mode }, 135 { "bay_locate_mode", TOPO_PROP_METH_DESC, 136 TOPO_METH_BAY_LOCATE_VERSION, 137 TOPO_STABILITY_INTERNAL, bay_locate_mode }, 138 { "bay_indicator_mode", TOPO_PROP_METH_DESC, 139 TOPO_METH_BAY_MODE_VERSION, 140 TOPO_STABILITY_INTERNAL, bay_indicator_mode }, 141 { "chassis_service_mode", TOPO_PROP_METH_DESC, 142 TOPO_METH_CHASSIS_SERVICE_VERSION, 143 TOPO_STABILITY_INTERNAL, chassis_service_mode }, 144 { "chassis_ident_mode", TOPO_PROP_METH_DESC, 145 TOPO_METH_CHASSIS_SERVICE_VERSION, 146 TOPO_STABILITY_INTERNAL, chassis_ident_mode }, 147 { "x4500_present_mode", TOPO_PROP_METH_DESC, 148 TOPO_METH_CHASSIS_SERVICE_VERSION, 149 TOPO_STABILITY_INTERNAL, x4500_present_mode }, 150 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC, 151 TOPO_METH_IPMI_ENTITY_VERSION, 152 TOPO_STABILITY_INTERNAL, ipmi_entity }, 153 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC, 154 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 155 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity }, 156 { "cs_ipmi_entity", TOPO_PROP_METH_DESC, 157 TOPO_METH_DIMM_IPMI_ENTITY_VERSION, 158 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity }, 159 { NULL } 160 }; 161 162 struct entity_info { 163 uint32_t ei_id; 164 uint32_t ei_inst; 165 topo_mod_t *ei_mod; 166 tnode_t *ei_node; 167 char **ei_list; 168 uint_t ei_listsz; 169 }; 170 171 struct sensor_data { 172 char sd_entity_ref[MAX_ID_LEN]; 173 uint8_t sd_units; 174 uint32_t sd_stype; 175 uint32_t sd_rtype; 176 char *sd_class; 177 ipmi_sdr_full_sensor_t *sd_fs_sdr; 178 }; 179 180 /*ARGSUSED*/ 181 int 182 _topo_init(topo_mod_t *mod, topo_version_t version) 183 { 184 if (getenv("TOPOFACIPMIDEBUG") != NULL) 185 topo_mod_setdebug(mod); 186 187 return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION)); 188 } 189 190 void 191 _topo_fini(topo_mod_t *mod) 192 { 193 topo_mod_unregister(mod); 194 } 195 196 static void 197 strarr_free(topo_mod_t *mod, char **arr, uint_t nelems) 198 { 199 for (int i = 0; i < nelems; i++) 200 topo_mod_strfree(mod, arr[i]); 201 topo_mod_free(mod, arr, (nelems * sizeof (char *))); 202 } 203 204 /* 205 * Some platforms (most notably G1/2N) use the 'platform event message' command 206 * to manipulate disk fault LEDs over IPMI, but uses the standard sensor 207 * reading to read the value. This method implements this alternative 208 * interface for these platforms. 209 */ 210 /*ARGSUSED*/ 211 static int 212 ipmi_platform_message(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 213 nvlist_t *in, nvlist_t **out) 214 { 215 char *entity_ref; 216 ipmi_sdr_compact_sensor_t *csp; 217 ipmi_handle_t *hdl; 218 int err, ret; 219 uint32_t mode; 220 nvlist_t *pargs, *nvl; 221 ipmi_platform_event_message_t pem; 222 ipmi_sensor_reading_t *reading; 223 224 if (vers > TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION) 225 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 226 227 /* 228 * Get an IPMI handle and then lookup the generic device locator sensor 229 * data record referenced by the entity_ref prop val 230 */ 231 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 232 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 233 return (-1); 234 } 235 236 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref", 237 &entity_ref, &err) != 0) { 238 topo_mod_dprintf(mod, "Failed to lookup entity_ref property " 239 "(%s)", topo_strerror(err)); 240 topo_mod_ipmi_rele(mod); 241 return (-1); 242 } 243 244 if ((csp = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) == NULL) { 245 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n", 246 entity_ref, ipmi_errmsg(hdl)); 247 topo_mod_strfree(mod, entity_ref); 248 topo_mod_ipmi_rele(mod); 249 return (-1); 250 } 251 252 /* 253 * Now look for a private argument list to figure out whether we're 254 * doing a get or a set operation, and then do it. 255 */ 256 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && 257 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { 258 /* 259 * Set the LED mode 260 */ 261 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, 262 &mode)) != 0) { 263 topo_mod_dprintf(mod, "Failed to lookup %s nvpair " 264 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret)); 265 topo_mod_strfree(mod, entity_ref); 266 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 267 topo_mod_ipmi_rele(mod); 268 return (-1); 269 } 270 271 if (mode != TOPO_LED_STATE_OFF && 272 mode != TOPO_LED_STATE_ON) { 273 topo_mod_dprintf(mod, "Invalid property value: %d\n", 274 mode); 275 topo_mod_strfree(mod, entity_ref); 276 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 277 topo_mod_ipmi_rele(mod); 278 return (-1); 279 } 280 281 pem.ipem_sensor_type = csp->is_cs_type; 282 pem.ipem_sensor_num = csp->is_cs_number; 283 pem.ipem_event_type = csp->is_cs_reading_type; 284 285 /* 286 * The spec states that any values between 0x20 and 0x29 are 287 * legitimate for "system software". However, some versions of 288 * Sun's ILOM rejects messages over /dev/ipmi0 with a generator 289 * of 0x20, so we use 0x21 instead. 290 */ 291 pem.ipem_generator = 0x21; 292 pem.ipem_event_dir = 0; 293 pem.ipem_rev = 0x04; 294 if (mode == TOPO_LED_STATE_ON) 295 pem.ipem_event_data[0] = 1; 296 else 297 pem.ipem_event_data[0] = 0; 298 pem.ipem_event_data[1] = 0xff; 299 pem.ipem_event_data[2] = 0xff; 300 301 if (ipmi_event_platform_message(hdl, &pem) < 0) { 302 topo_mod_dprintf(mod, "Failed to set LED mode for %s " 303 "(%s)\n", entity_ref, ipmi_errmsg(hdl)); 304 topo_mod_strfree(mod, entity_ref); 305 topo_mod_ipmi_rele(mod); 306 return (-1); 307 } 308 } else { 309 /* 310 * Get the LED mode 311 */ 312 if ((reading = ipmi_get_sensor_reading(hdl, csp->is_cs_number)) 313 == NULL) { 314 topo_mod_dprintf(mod, "Failed to get sensor reading " 315 "for sensor %s: %s\n", entity_ref, 316 ipmi_errmsg(hdl)); 317 topo_mod_strfree(mod, entity_ref); 318 topo_mod_ipmi_rele(mod); 319 return (-1); 320 } 321 322 if (reading->isr_state & 323 TOPO_SENSOR_STATE_GENERIC_STATE_ASSERTED) 324 mode = TOPO_LED_STATE_ON; 325 else 326 mode = TOPO_LED_STATE_OFF; 327 } 328 topo_mod_strfree(mod, entity_ref); 329 330 topo_mod_ipmi_rele(mod); 331 332 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 333 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || 334 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || 335 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, mode) != 0) { 336 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 337 nvlist_free(nvl); 338 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 339 } 340 *out = nvl; 341 342 return (0); 343 } 344 345 /*ARGSUSED*/ 346 static int 347 ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 348 nvlist_t *in, nvlist_t **out) 349 { 350 char **entity_refs, *sensor_class; 351 uint_t nelems; 352 ipmi_sdr_t *sdr = NULL; 353 ipmi_sensor_reading_t *reading; 354 ipmi_handle_t *hdl; 355 int err, i; 356 uint8_t sensor_num; 357 uint32_t e_id, e_inst, state; 358 ipmi_sdr_full_sensor_t *fsensor; 359 ipmi_sdr_compact_sensor_t *csensor; 360 nvlist_t *nvl; 361 boolean_t found_sdr = B_FALSE; 362 tnode_t *pnode; 363 364 if (vers > TOPO_METH_IPMI_STATE_VERSION) 365 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 366 367 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref", 368 &entity_refs, &nelems, &err) != 0) { 369 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref " 370 "property (%s)", __func__, topo_strerror(err)); 371 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 372 } 373 374 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 375 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 376 strarr_free(mod, entity_refs, nelems); 377 return (-1); 378 } 379 380 pnode = topo_node_parent(node); 381 if (topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI, 382 TOPO_PROP_IPMI_ENTITY_ID, &e_id, &err) != 0 || 383 topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI, 384 TOPO_PROP_IPMI_ENTITY_INST, &e_inst, &err) != 0) { 385 e_id = IPMI_ET_UNSPECIFIED; 386 e_inst = 0; 387 } 388 389 for (i = 0; i < nelems; i++) { 390 if ((sdr = ipmi_sdr_lookup_precise(hdl, entity_refs[i], 391 (uint8_t)e_id, (uint8_t)e_inst)) != NULL) { 392 found_sdr = B_TRUE; 393 break; 394 } else 395 topo_mod_dprintf(mod, "Failed to lookup SDR for %s " 396 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl)); 397 } 398 399 if (! found_sdr) { 400 strarr_free(mod, entity_refs, nelems); 401 topo_mod_ipmi_rele(mod); 402 return (-1); 403 } 404 405 switch (sdr->is_type) { 406 case IPMI_SDR_TYPE_FULL_SENSOR: 407 fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record; 408 sensor_num = fsensor->is_fs_number; 409 break; 410 case IPMI_SDR_TYPE_COMPACT_SENSOR: 411 csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record; 412 sensor_num = csensor->is_cs_number; 413 break; 414 default: 415 topo_mod_dprintf(mod, "%s does not refer to a full or " 416 "compact SDR\n", entity_refs[i]); 417 topo_mod_ipmi_rele(mod); 418 strarr_free(mod, entity_refs, nelems); 419 return (-1); 420 } 421 if ((reading = ipmi_get_sensor_reading(hdl, sensor_num)) 422 == NULL) { 423 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor " 424 "%s, sensor_num=%d (%s)\n", entity_refs[i], sensor_num, 425 ipmi_errmsg(hdl)); 426 strarr_free(mod, entity_refs, nelems); 427 topo_mod_ipmi_rele(mod); 428 return (-1); 429 } 430 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(mod, entity_refs, nelems); 554 return (-1); 555 } 556 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(mod, entity_refs, nelems); 666 topo_mod_ipmi_rele(mod); 667 return (-1); 668 } 669 } 670 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(mod, entity_refs, nelems); 788 topo_mod_ipmi_rele(mod); 789 return (-1); 790 } 791 } 792 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(mod, entity_refs, nelems); 1004 topo_mod_ipmi_rele(mod); 1005 return (-1); 1006 } 1007 ledmode = mode_in; 1008 } 1009 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(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 strarr_free(mod, entity_refs, nelems); 1296 topo_mod_ipmi_rele(mod); 1297 return (-1); 1298 } 1299 } 1300 strarr_free(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 strarr_free(mod, entity_refs, 1); 1525 return (topo_mod_seterrno(mod, err)); 1526 } 1527 strarr_free(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 topo_mod_dprintf(mod, "Failed to get sensor thresholds for " 1610 "node %s (%s)\n", topo_node_name(fnode), ipmi_errmsg(hdl)); 1611 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 1612 } 1613 1614 /* 1615 * The IPMI Get Sensor Thresholds command returns a bitmask describing 1616 * which of the 3 upper and lower thresholds are readable. Iterate 1617 * through those and create a topo property for each threshold that is 1618 * readable. 1619 */ 1620 mask = thresh.ithr_readable_mask; 1621 for (i = 0; i < num_thresholds; i++) { 1622 if (!ISBITSET(mask, threshset[i].sthr_threshbit)) 1623 continue; 1624 1625 if (set_thresh_prop(mod, fnode, sd->sd_fs_sdr, 1626 *(uint8_t *)((char *)&thresh + 1627 threshset[i].sthr_threshoff), &threshset[i]) != 0) { 1628 /* errno set */ 1629 return (-1); 1630 } 1631 } 1632 return (0); 1633 } 1634 1635 static boolean_t 1636 seq_search(char *key, char **list, uint_t nelem) 1637 { 1638 for (int i = 0; i < nelem; i++) 1639 if (strcmp(key, list[i]) == 0) 1640 return (B_TRUE); 1641 return (B_FALSE); 1642 } 1643 1644 /* ARGSUSED */ 1645 static int 1646 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data) 1647 { 1648 uint8_t sensor_entity, sensor_inst; 1649 int sensor_idlen; 1650 ipmi_sdr_full_sensor_t *f_sensor = NULL; 1651 ipmi_sdr_compact_sensor_t *c_sensor = NULL; 1652 struct sensor_data sd; 1653 struct entity_info *ei = (struct entity_info *)data; 1654 1655 switch (sdr->is_type) { 1656 case IPMI_SDR_TYPE_FULL_SENSOR: 1657 f_sensor = 1658 (ipmi_sdr_full_sensor_t *)sdr->is_record; 1659 sensor_entity = f_sensor->is_fs_entity_id; 1660 sensor_inst = f_sensor->is_fs_entity_instance; 1661 sensor_idlen = f_sensor->is_fs_idlen; 1662 (void) strncpy(sd.sd_entity_ref, 1663 f_sensor->is_fs_idstring, 1664 f_sensor->is_fs_idlen); 1665 sd.sd_entity_ref[sensor_idlen] = '\0'; 1666 sd.sd_units = f_sensor->is_fs_unit2; 1667 sd.sd_stype = f_sensor->is_fs_type; 1668 sd.sd_rtype = f_sensor->is_fs_reading_type; 1669 sd.sd_fs_sdr = f_sensor; 1670 break; 1671 case IPMI_SDR_TYPE_COMPACT_SENSOR: 1672 c_sensor = 1673 (ipmi_sdr_compact_sensor_t *)sdr->is_record; 1674 sensor_entity = c_sensor->is_cs_entity_id; 1675 sensor_inst = c_sensor->is_cs_entity_instance; 1676 sensor_idlen = c_sensor->is_cs_idlen; 1677 (void) strncpy(sd.sd_entity_ref, 1678 c_sensor->is_cs_idstring, 1679 sensor_idlen); 1680 sd.sd_entity_ref[sensor_idlen] = '\0'; 1681 sd.sd_units = c_sensor->is_cs_unit2; 1682 sd.sd_stype = c_sensor->is_cs_type; 1683 sd.sd_rtype = c_sensor->is_cs_reading_type; 1684 sd.sd_fs_sdr = NULL; 1685 break; 1686 default: 1687 return (0); 1688 } 1689 if (sd.sd_rtype == IPMI_RT_THRESHOLD) 1690 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD; 1691 else 1692 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE; 1693 1694 /* 1695 * We offset the threshold and generic sensor reading types by 0x100 1696 */ 1697 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc) 1698 sd.sd_stype = sd.sd_rtype + 0x100; 1699 1700 if ((ei->ei_list != NULL && seq_search(sd.sd_entity_ref, 1701 ei->ei_list, ei->ei_listsz) == B_TRUE) || 1702 (sensor_entity == ei->ei_id && sensor_inst == ei->ei_inst)) { 1703 1704 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd, hdl) != 0) { 1705 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor " 1706 "node for %s\n", sd.sd_entity_ref); 1707 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP) 1708 return (-1); 1709 } 1710 } 1711 return (0); 1712 } 1713 1714 static int 1715 get_entity_info(topo_mod_t *mod, tnode_t *node, ipmi_handle_t *hdl, 1716 struct entity_info *ei) 1717 { 1718 char **entity_refs; 1719 int err; 1720 uint_t nelems; 1721 ipmi_sdr_t *ref_sdr; 1722 ipmi_sdr_full_sensor_t *fsensor; 1723 ipmi_sdr_compact_sensor_t *csensor; 1724 ipmi_sdr_fru_locator_t *floc; 1725 ipmi_sdr_generic_locator_t *gloc; 1726 boolean_t found_sdr = B_FALSE; 1727 1728 /* 1729 * Use the entity ref to lookup the SDR, which will have the entity ID 1730 * and instance. 1731 */ 1732 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI, 1733 "entity_ref", &entity_refs, &nelems, &err) != 0) { 1734 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref " 1735 "property on %s=%d (%s)\n", __func__, topo_node_name(node), 1736 topo_node_instance(node), topo_strerror(err)); 1737 topo_mod_ipmi_rele(mod); 1738 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1739 } 1740 1741 for (int i = 0; i < nelems; i++) { 1742 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) { 1743 found_sdr = B_TRUE; 1744 break; 1745 } else 1746 topo_mod_dprintf(mod, "%s: Failed to lookup SDR for %s " 1747 "(%s)\n", __func__, entity_refs[i], 1748 ipmi_errmsg(hdl)); 1749 } 1750 strarr_free(mod, entity_refs, nelems); 1751 if (! found_sdr) { 1752 topo_mod_ipmi_rele(mod); 1753 return (-1); 1754 } 1755 1756 switch (ref_sdr->is_type) { 1757 case IPMI_SDR_TYPE_FULL_SENSOR: 1758 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record; 1759 ei->ei_id = fsensor->is_fs_entity_id; 1760 ei->ei_inst = fsensor->is_fs_entity_instance; 1761 break; 1762 case IPMI_SDR_TYPE_COMPACT_SENSOR: 1763 csensor 1764 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record; 1765 ei->ei_id = csensor->is_cs_entity_id; 1766 ei->ei_inst = csensor->is_cs_entity_instance; 1767 break; 1768 case IPMI_SDR_TYPE_FRU_LOCATOR: 1769 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record; 1770 ei->ei_id = floc->is_fl_entity; 1771 ei->ei_inst = floc->is_fl_instance; 1772 break; 1773 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 1774 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record; 1775 ei->ei_id = gloc->is_gl_entity; 1776 ei->ei_inst = gloc->is_gl_instance; 1777 break; 1778 default: 1779 topo_mod_dprintf(mod, "Failed to determine entity id " 1780 "and instance\n", ipmi_errmsg(hdl)); 1781 topo_mod_ipmi_rele(mod); 1782 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1783 } 1784 return (0); 1785 } 1786 1787 /* ARGSUSED */ 1788 static int 1789 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1790 nvlist_t *in, nvlist_t **out) 1791 { 1792 int err, ret = -1; 1793 struct entity_info ei = {0}; 1794 ipmi_handle_t *hdl; 1795 1796 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) { 1797 topo_mod_dprintf(mod, "Failed to get IPMI handle\n"); 1798 return (-1); 1799 } 1800 1801 /* 1802 * For cases where the records in the SDR are hopelessly broken, then 1803 * we'll resort to hardcoding a list of sensor entities that should be 1804 * bound to this particular node. Otherwise, we'll first check if the 1805 * properties for the associated IPMI entity id and instance exist. If 1806 * not, we check for a property referencing an IPMI entity name on which 1807 * we can lookup the entity ID and instance. If none of the above pans 1808 * out, then we bail out. 1809 */ 1810 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI, 1811 TOPO_PROP_IPMI_ENTITY_LIST, &ei.ei_list, &ei.ei_listsz, &err) 1812 != 0 && (topo_prop_get_uint32(node, TOPO_PGROUP_IPMI, 1813 TOPO_PROP_IPMI_ENTITY_ID, &ei.ei_id, &err) != 0 || 1814 topo_prop_get_uint32(node, TOPO_PGROUP_IPMI, 1815 TOPO_PROP_IPMI_ENTITY_INST, &ei.ei_inst, &err) != 0)) { 1816 if (get_entity_info(mod, node, hdl, &ei) != 0) 1817 goto out; 1818 } 1819 ei.ei_node = node; 1820 ei.ei_mod = mod; 1821 1822 /* 1823 * Now iterate through all of the full and compact sensor data records 1824 * and create a sensor facility node for each record that matches our 1825 * entity ID and instance 1826 */ 1827 if ((ret = ipmi_sdr_iter(hdl, sdr_callback, &ei)) != 0) { 1828 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n"); 1829 } 1830 out: 1831 topo_mod_ipmi_rele(mod); 1832 if (ei.ei_list != NULL) 1833 strarr_free(mod, ei.ei_list, ei.ei_listsz); 1834 1835 return (ret); 1836 } 1837 1838 static int 1839 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1840 nvlist_t *in, nvlist_t **out) 1841 { 1842 char **fmtarr, **entity_refs, buf[BUFSZ]; 1843 tnode_t *refnode; 1844 uint_t nelems; 1845 int ret, inst1, inst2; 1846 uint32_t offset, nparams; 1847 nvlist_t *args, *nvl; 1848 1849 if (vers > TOPO_METH_IPMI_ENTITY_VERSION) 1850 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1851 1852 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1853 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1854 strerror(ret)); 1855 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1856 } 1857 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 1858 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1859 strerror(ret)); 1860 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1861 } 1862 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) { 1863 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n", 1864 strerror(ret)); 1865 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1866 } 1867 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) { 1868 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n", 1869 strerror(errno)); 1870 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1871 } 1872 1873 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *)))) 1874 == NULL) 1875 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1876 1877 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1878 refnode = topo_node_parent(node); 1879 else 1880 refnode = node; 1881 1882 for (int i = 0; i < nelems; i++) { 1883 switch (nparams) { 1884 case 1: 1885 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1886 (void) snprintf(buf, BUFSZ, fmtarr[i], 1887 (topo_node_instance(refnode) + offset)); 1888 break; 1889 case 2: 1890 inst1 = topo_node_instance(topo_node_parent(refnode)) 1891 + offset; 1892 inst2 = topo_node_instance(refnode) + offset; 1893 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1894 (void) snprintf(buf, BUFSZ, fmtarr[i], inst1, inst2); 1895 break; 1896 default: 1897 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n", 1898 nparams); 1899 strarr_free(mod, entity_refs, nelems); 1900 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1901 } 1902 entity_refs[i] = topo_mod_strdup(mod, buf); 1903 } 1904 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1905 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1906 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, 1907 TOPO_TYPE_STRING_ARRAY) != 0 || 1908 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, 1909 nelems) != 0) { 1910 1911 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1912 strarr_free(mod, entity_refs, nelems); 1913 nvlist_free(nvl); 1914 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1915 } 1916 strarr_free(mod, entity_refs, nelems); 1917 *out = nvl; 1918 1919 return (0); 1920 } 1921 1922 /* ARGSUSED */ 1923 static int 1924 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1925 nvlist_t *in, nvlist_t **out) 1926 { 1927 char **fmtarr, **entity_refs, buf[BUFSZ]; 1928 tnode_t *chip, *dimm; 1929 int ret; 1930 uint_t nelems; 1931 uint32_t offset; 1932 nvlist_t *args, *nvl; 1933 1934 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1935 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1936 strerror(ret)); 1937 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1938 } 1939 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 1940 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 1941 strerror(ret)); 1942 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1943 } 1944 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) { 1945 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n", 1946 strerror(errno)); 1947 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 1948 } 1949 1950 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *)))) 1951 == NULL) 1952 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1953 1954 if (topo_node_flags(node) & TOPO_NODE_FACILITY) 1955 dimm = topo_node_parent(node); 1956 else 1957 dimm = node; 1958 1959 chip = topo_node_parent(topo_node_parent(dimm)); 1960 1961 for (int i = 0; i < nelems; i++) { 1962 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 1963 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip), 1964 (topo_node_instance(dimm) + offset)); 1965 entity_refs[i] = topo_mod_strdup(mod, buf); 1966 } 1967 1968 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 1969 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 1970 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, 1971 TOPO_TYPE_STRING_ARRAY) != 0 || 1972 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems) 1973 != 0) { 1974 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 1975 strarr_free(mod, entity_refs, nelems); 1976 nvlist_free(nvl); 1977 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1978 } 1979 strarr_free(mod, entity_refs, nelems); 1980 *out = nvl; 1981 1982 return (0); 1983 } 1984 1985 /* ARGSUSED */ 1986 static int 1987 cs_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers, 1988 nvlist_t *in, nvlist_t **out) 1989 { 1990 char **fmtarr, **entity_refs, buf[BUFSZ]; 1991 tnode_t *chip, *chan, *cs; 1992 int ret, dimm_num; 1993 uint_t nelems; 1994 uint32_t offset; 1995 nvlist_t *args, *nvl; 1996 1997 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) { 1998 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n", 1999 strerror(ret)); 2000 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 2001 } 2002 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) { 2003 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n", 2004 strerror(ret)); 2005 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 2006 } 2007 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) { 2008 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n", 2009 strerror(errno)); 2010 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 2011 } 2012 2013 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *)))) 2014 == NULL) 2015 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 2016 2017 if (topo_node_flags(node) & TOPO_NODE_FACILITY) { 2018 cs = topo_node_parent(node); 2019 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs))); 2020 chan = topo_node_parent(cs); 2021 2022 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2) 2023 + topo_node_instance(cs) + offset; 2024 } else { 2025 cs = node; 2026 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs))); 2027 chan = topo_node_parent(cs); 2028 2029 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2) 2030 + topo_node_instance(chan) + offset; 2031 } 2032 2033 for (int i = 0; i < nelems; i++) { 2034 /* LINTED: E_SEC_PRINTF_VAR_FMT */ 2035 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip), 2036 dimm_num); 2037 entity_refs[i] = topo_mod_strdup(mod, buf); 2038 } 2039 2040 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 2041 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 || 2042 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, 2043 TOPO_TYPE_STRING_ARRAY) != 0 || 2044 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems) 2045 != 0) { 2046 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 2047 strarr_free(mod, entity_refs, nelems); 2048 nvlist_free(nvl); 2049 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 2050 } 2051 strarr_free(mod, entity_refs, nelems); 2052 *out = nvl; 2053 2054 return (0); 2055 } 2056 2057 /*ARGSUSED*/ 2058 static int 2059 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 2060 topo_instance_t min, topo_instance_t max, void *arg, void *unused) 2061 { 2062 topo_pgroup_info_t pgi; 2063 int err; 2064 2065 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) { 2066 pgi.tpi_name = TOPO_PGROUP_IPMI; 2067 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 2068 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 2069 pgi.tpi_version = 1; 2070 if (topo_pgroup_create(rnode, &pgi, &err) != 0) { 2071 if (err != ETOPO_PROP_DEFD) { 2072 topo_mod_dprintf(mod, 2073 "pgroups create failure: %s\n", 2074 topo_strerror(err)); 2075 return (-1); 2076 } 2077 } 2078 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) { 2079 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 2080 "topo_method_register() failed: %s", 2081 topo_mod_errmsg(mod)); 2082 return (-1); 2083 } 2084 } else { 2085 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) { 2086 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: " 2087 "topo_method_register() failed: %s", 2088 topo_mod_errmsg(mod)); 2089 return (-1); 2090 } 2091 } 2092 return (0); 2093 } 2094