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