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