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