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