1*6070Srobj /* 2*6070Srobj * CDDL HEADER START 3*6070Srobj * 4*6070Srobj * The contents of this file are subject to the terms of the 5*6070Srobj * Common Development and Distribution License (the "License"). 6*6070Srobj * You may not use this file except in compliance with the License. 7*6070Srobj * 8*6070Srobj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6070Srobj * or http://www.opensolaris.org/os/licensing. 10*6070Srobj * See the License for the specific language governing permissions 11*6070Srobj * and limitations under the License. 12*6070Srobj * 13*6070Srobj * When distributing Covered Code, include this CDDL HEADER in each 14*6070Srobj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6070Srobj * If applicable, add the following below this CDDL HEADER, with the 16*6070Srobj * fields enclosed by brackets "[]" replaced with your own identifying 17*6070Srobj * information: Portions Copyright [yyyy] [name of copyright owner] 18*6070Srobj * 19*6070Srobj * CDDL HEADER END 20*6070Srobj */ 21*6070Srobj /* 22*6070Srobj * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*6070Srobj * Use is subject to license terms. 24*6070Srobj */ 25*6070Srobj 26*6070Srobj #pragma ident "%Z%%M% %I% %E% SMI" 27*6070Srobj 28*6070Srobj /* 29*6070Srobj * IPMI entities are a strange beast. A reasonable assumption for those 30*6070Srobj * unfamiliar with the spec would be that there was a command to iterate over 31*6070Srobj * all entities, and a command to iterate over sensors associated with each 32*6070Srobj * entity. Instead, the entire IPMI world is derived from the SDR repository. 33*6070Srobj * Entities only exist in the sense that they are referenced by a SDR record. 34*6070Srobj * 35*6070Srobj * In addition, entities can be associated into groups, and determining entity 36*6070Srobj * presence is quite complicated. The IPMI spec dedicates an entire chapter 37*6070Srobj * (40) to the process of handling sensor associations. 38*6070Srobj * 39*6070Srobj * The above logic is implemented via the ipmi_entity_present() function. We 40*6070Srobj * make a first pass over the SDR repository to discover entities, creating 41*6070Srobj * entity groups and associating SDR records with the each. 42*6070Srobj * 43*6070Srobj * We don't currently support device-relative entities. 44*6070Srobj */ 45*6070Srobj 46*6070Srobj #include <libipmi.h> 47*6070Srobj #include <ipmi_impl.h> 48*6070Srobj #include <stddef.h> 49*6070Srobj 50*6070Srobj typedef struct ipmi_entity_sdr { 51*6070Srobj ipmi_list_t ies_list; 52*6070Srobj const char *ies_name; 53*6070Srobj ipmi_sdr_t *ies_sdr; 54*6070Srobj } ipmi_entity_sdr_t; 55*6070Srobj 56*6070Srobj typedef struct ipmi_entity_impl { 57*6070Srobj ipmi_list_t ie_list; 58*6070Srobj ipmi_entity_t ie_entity; 59*6070Srobj struct ipmi_entity_impl *ie_parent; 60*6070Srobj ipmi_hash_link_t ie_link; 61*6070Srobj ipmi_list_t ie_child_list; 62*6070Srobj ipmi_list_t ie_sdr_list; 63*6070Srobj } ipmi_entity_impl_t; 64*6070Srobj 65*6070Srobj #define ENTITY_TO_IMPL(ep) \ 66*6070Srobj ((ipmi_entity_impl_t *)((char *)(ep) - \ 67*6070Srobj offsetof(ipmi_entity_impl_t, ie_entity))) 68*6070Srobj 69*6070Srobj static int 70*6070Srobj ipmi_entity_add_assoc(ipmi_handle_t *ihp, ipmi_entity_impl_t *eip, 71*6070Srobj uint8_t id, uint8_t instance) 72*6070Srobj { 73*6070Srobj ipmi_entity_impl_t *cp; 74*6070Srobj ipmi_entity_t search; 75*6070Srobj 76*6070Srobj search.ie_type = id; 77*6070Srobj search.ie_instance = instance; 78*6070Srobj 79*6070Srobj if ((cp = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { 80*6070Srobj if ((cp = ipmi_zalloc(ihp, 81*6070Srobj sizeof (ipmi_entity_impl_t))) == NULL) 82*6070Srobj return (-1); 83*6070Srobj 84*6070Srobj cp->ie_entity.ie_type = id; 85*6070Srobj cp->ie_entity.ie_instance = instance; 86*6070Srobj 87*6070Srobj ipmi_hash_insert(ihp->ih_entities, cp); 88*6070Srobj } 89*6070Srobj 90*6070Srobj if (cp->ie_parent != NULL) { 91*6070Srobj /* 92*6070Srobj * This should never happen. However, we want to be tolerant of 93*6070Srobj * pathologically broken IPMI implementations, so we ignore this 94*6070Srobj * error, and the first parent wins. 95*6070Srobj */ 96*6070Srobj return (0); 97*6070Srobj } 98*6070Srobj 99*6070Srobj cp->ie_parent = eip; 100*6070Srobj ipmi_list_append(&eip->ie_child_list, cp); 101*6070Srobj eip->ie_entity.ie_children++; 102*6070Srobj 103*6070Srobj return (0); 104*6070Srobj } 105*6070Srobj 106*6070Srobj static int 107*6070Srobj ipmi_entity_sdr_parse(ipmi_sdr_t *sdrp, uint8_t *id, uint8_t *instance, 108*6070Srobj boolean_t *logical) 109*6070Srobj { 110*6070Srobj switch (sdrp->is_type) { 111*6070Srobj case IPMI_SDR_TYPE_FULL_SENSOR: 112*6070Srobj { 113*6070Srobj ipmi_sdr_full_sensor_t *fsp = 114*6070Srobj (ipmi_sdr_full_sensor_t *)sdrp->is_record; 115*6070Srobj *id = fsp->is_fs_entity_id; 116*6070Srobj *instance = fsp->is_fs_entity_instance; 117*6070Srobj *logical = fsp->is_fs_entity_logical; 118*6070Srobj break; 119*6070Srobj } 120*6070Srobj 121*6070Srobj case IPMI_SDR_TYPE_COMPACT_SENSOR: 122*6070Srobj { 123*6070Srobj ipmi_sdr_compact_sensor_t *csp = 124*6070Srobj (ipmi_sdr_compact_sensor_t *)sdrp->is_record; 125*6070Srobj *id = csp->is_cs_entity_id; 126*6070Srobj *instance = csp->is_cs_entity_instance; 127*6070Srobj *logical = csp->is_cs_entity_logical; 128*6070Srobj break; 129*6070Srobj } 130*6070Srobj 131*6070Srobj case IPMI_SDR_TYPE_EVENT_ONLY: 132*6070Srobj { 133*6070Srobj ipmi_sdr_event_only_t *eop = 134*6070Srobj (ipmi_sdr_event_only_t *)sdrp->is_record; 135*6070Srobj *id = eop->is_eo_entity_id; 136*6070Srobj *instance = eop->is_eo_entity_instance; 137*6070Srobj *logical = eop->is_eo_entity_logical; 138*6070Srobj break; 139*6070Srobj } 140*6070Srobj 141*6070Srobj case IPMI_SDR_TYPE_ENTITY_ASSOCIATION: 142*6070Srobj { 143*6070Srobj ipmi_sdr_entity_association_t *eap = 144*6070Srobj (ipmi_sdr_entity_association_t *)sdrp->is_record; 145*6070Srobj *id = eap->is_ea_entity_id; 146*6070Srobj *instance = eap->is_ea_entity_instance; 147*6070Srobj *logical = B_TRUE; 148*6070Srobj break; 149*6070Srobj } 150*6070Srobj 151*6070Srobj case IPMI_SDR_TYPE_GENERIC_LOCATOR: 152*6070Srobj { 153*6070Srobj ipmi_sdr_generic_locator_t *glp = 154*6070Srobj (ipmi_sdr_generic_locator_t *)sdrp->is_record; 155*6070Srobj *id = glp->is_gl_entity; 156*6070Srobj *instance = glp->is_gl_instance; 157*6070Srobj *logical = B_FALSE; 158*6070Srobj break; 159*6070Srobj } 160*6070Srobj 161*6070Srobj case IPMI_SDR_TYPE_FRU_LOCATOR: 162*6070Srobj { 163*6070Srobj ipmi_sdr_fru_locator_t *flp = 164*6070Srobj (ipmi_sdr_fru_locator_t *)sdrp->is_record; 165*6070Srobj *id = flp->is_fl_entity; 166*6070Srobj *instance = flp->is_fl_instance; 167*6070Srobj *logical = B_FALSE; 168*6070Srobj break; 169*6070Srobj } 170*6070Srobj 171*6070Srobj case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR: 172*6070Srobj { 173*6070Srobj ipmi_sdr_management_locator_t *mlp = 174*6070Srobj (ipmi_sdr_management_locator_t *)sdrp->is_record; 175*6070Srobj *id = mlp->is_ml_entity_id; 176*6070Srobj *instance = mlp->is_ml_entity_instance; 177*6070Srobj *logical = B_FALSE; 178*6070Srobj break; 179*6070Srobj } 180*6070Srobj 181*6070Srobj default: 182*6070Srobj return (-1); 183*6070Srobj } 184*6070Srobj 185*6070Srobj return (0); 186*6070Srobj } 187*6070Srobj 188*6070Srobj /* 189*6070Srobj * This function is responsible for gathering all entities, inserting them into 190*6070Srobj * the global hash, and establishing any associations. 191*6070Srobj */ 192*6070Srobj /*ARGSUSED*/ 193*6070Srobj static int 194*6070Srobj ipmi_entity_visit(ipmi_handle_t *ihp, const char *name, ipmi_sdr_t *sdrp, 195*6070Srobj void *unused) 196*6070Srobj { 197*6070Srobj uint8_t id, instance; 198*6070Srobj boolean_t logical; 199*6070Srobj ipmi_entity_t search; 200*6070Srobj ipmi_entity_impl_t *eip; 201*6070Srobj ipmi_entity_sdr_t *esp; 202*6070Srobj 203*6070Srobj if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0) 204*6070Srobj return (0); 205*6070Srobj 206*6070Srobj search.ie_type = id; 207*6070Srobj search.ie_instance = instance; 208*6070Srobj 209*6070Srobj if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { 210*6070Srobj if ((eip = ipmi_zalloc(ihp, 211*6070Srobj sizeof (ipmi_entity_impl_t))) == NULL) 212*6070Srobj return (-1); 213*6070Srobj 214*6070Srobj eip->ie_entity.ie_type = id; 215*6070Srobj eip->ie_entity.ie_instance = instance; 216*6070Srobj 217*6070Srobj ipmi_hash_insert(ihp->ih_entities, eip); 218*6070Srobj } 219*6070Srobj 220*6070Srobj eip->ie_entity.ie_logical |= logical; 221*6070Srobj 222*6070Srobj if (sdrp->is_type == IPMI_SDR_TYPE_ENTITY_ASSOCIATION) { 223*6070Srobj uint8_t start, end; 224*6070Srobj uint8_t i, type; 225*6070Srobj 226*6070Srobj ipmi_sdr_entity_association_t *eap = 227*6070Srobj (ipmi_sdr_entity_association_t *)sdrp->is_record; 228*6070Srobj 229*6070Srobj if (eap->is_ea_range) { 230*6070Srobj 231*6070Srobj type = eap->is_ea_sub[0].is_ea_sub_id; 232*6070Srobj start = eap->is_ea_sub[0].is_ea_sub_instance; 233*6070Srobj end = eap->is_ea_sub[1].is_ea_sub_instance; 234*6070Srobj 235*6070Srobj if (type != 0) { 236*6070Srobj for (i = start; i <= end; i++) { 237*6070Srobj if (ipmi_entity_add_assoc(ihp, eip, 238*6070Srobj type, i) != 0) 239*6070Srobj return (-1); 240*6070Srobj } 241*6070Srobj } 242*6070Srobj 243*6070Srobj type = eap->is_ea_sub[2].is_ea_sub_id; 244*6070Srobj start = eap->is_ea_sub[2].is_ea_sub_instance; 245*6070Srobj end = eap->is_ea_sub[3].is_ea_sub_instance; 246*6070Srobj 247*6070Srobj if (type != 0) { 248*6070Srobj for (i = start; i <= end; i++) { 249*6070Srobj if (ipmi_entity_add_assoc(ihp, eip, 250*6070Srobj type, i) != 0) 251*6070Srobj return (-1); 252*6070Srobj } 253*6070Srobj } 254*6070Srobj } else { 255*6070Srobj for (i = 0; i < 4; i++) { 256*6070Srobj type = eap->is_ea_sub[i].is_ea_sub_id; 257*6070Srobj instance = eap->is_ea_sub[i].is_ea_sub_instance; 258*6070Srobj 259*6070Srobj if (type == 0) 260*6070Srobj continue; 261*6070Srobj 262*6070Srobj if (ipmi_entity_add_assoc(ihp, eip, type, 263*6070Srobj instance) != 0) 264*6070Srobj return (-1); 265*6070Srobj } 266*6070Srobj } 267*6070Srobj } else { 268*6070Srobj if ((esp = ipmi_zalloc(ihp, 269*6070Srobj sizeof (ipmi_entity_sdr_t))) == NULL) 270*6070Srobj return (-1); 271*6070Srobj 272*6070Srobj esp->ies_sdr = sdrp; 273*6070Srobj esp->ies_name = name; 274*6070Srobj ipmi_list_append(&eip->ie_sdr_list, esp); 275*6070Srobj } 276*6070Srobj 277*6070Srobj return (0); 278*6070Srobj } 279*6070Srobj 280*6070Srobj /* 281*6070Srobj * Given a SDR record, return boolean values indicating whether the sensor 282*6070Srobj * indicates explicit presence. 283*6070Srobj * 284*6070Srobj * XXX this should really share code with entity_present() 285*6070Srobj */ 286*6070Srobj int 287*6070Srobj ipmi_entity_present_sdr(ipmi_handle_t *ihp, ipmi_sdr_t *sdrp, 288*6070Srobj boolean_t *valp) 289*6070Srobj { 290*6070Srobj uint16_t mask; 291*6070Srobj uint8_t number, sensor_type, reading_type; 292*6070Srobj ipmi_sdr_compact_sensor_t *csp; 293*6070Srobj ipmi_sdr_full_sensor_t *fsp; 294*6070Srobj ipmi_sensor_reading_t *srp; 295*6070Srobj 296*6070Srobj switch (sdrp->is_type) { 297*6070Srobj case IPMI_SDR_TYPE_COMPACT_SENSOR: 298*6070Srobj csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; 299*6070Srobj number = csp->is_cs_number; 300*6070Srobj sensor_type = csp->is_cs_type; 301*6070Srobj reading_type = csp->is_cs_reading_type; 302*6070Srobj break; 303*6070Srobj 304*6070Srobj case IPMI_SDR_TYPE_FULL_SENSOR: 305*6070Srobj fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; 306*6070Srobj number = fsp->is_fs_number; 307*6070Srobj sensor_type = fsp->is_fs_type; 308*6070Srobj reading_type = fsp->is_fs_reading_type; 309*6070Srobj break; 310*6070Srobj 311*6070Srobj default: 312*6070Srobj *valp = B_FALSE; 313*6070Srobj return (0); 314*6070Srobj } 315*6070Srobj 316*6070Srobj switch (reading_type) { 317*6070Srobj case IPMI_RT_PRESENT: 318*6070Srobj mask = IPMI_SR_PRESENT_ASSERT; 319*6070Srobj break; 320*6070Srobj 321*6070Srobj case IPMI_RT_SPECIFIC: 322*6070Srobj switch (sensor_type) { 323*6070Srobj case IPMI_ST_PROCESSOR: 324*6070Srobj mask = IPMI_EV_PROCESSOR_PRESENT; 325*6070Srobj break; 326*6070Srobj 327*6070Srobj case IPMI_ST_POWER_SUPPLY: 328*6070Srobj mask = IPMI_EV_POWER_SUPPLY_PRESENT; 329*6070Srobj break; 330*6070Srobj 331*6070Srobj case IPMI_ST_MEMORY: 332*6070Srobj mask = IPMI_EV_MEMORY_PRESENT; 333*6070Srobj break; 334*6070Srobj 335*6070Srobj case IPMI_ST_BAY: 336*6070Srobj mask = IPMI_EV_BAY_PRESENT; 337*6070Srobj break; 338*6070Srobj 339*6070Srobj default: 340*6070Srobj *valp = B_FALSE; 341*6070Srobj return (0); 342*6070Srobj } 343*6070Srobj break; 344*6070Srobj 345*6070Srobj default: 346*6070Srobj *valp = B_FALSE; 347*6070Srobj return (0); 348*6070Srobj } 349*6070Srobj 350*6070Srobj /* 351*6070Srobj * If we've reached here, then we have a dedicated sensor that 352*6070Srobj * indicates presence. 353*6070Srobj */ 354*6070Srobj if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { 355*6070Srobj if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) { 356*6070Srobj *valp = B_FALSE; 357*6070Srobj return (0); 358*6070Srobj } 359*6070Srobj 360*6070Srobj return (-1); 361*6070Srobj } 362*6070Srobj 363*6070Srobj *valp = (srp->isr_state & mask) != 0; 364*6070Srobj return (0); 365*6070Srobj } 366*6070Srobj 367*6070Srobj /* 368*6070Srobj * This function follows the procedure documented in section 40 of the spec. 369*6070Srobj * To quote the conclusion from section 40.2: 370*6070Srobj * 371*6070Srobj * Thus, the steps to detecting an Entity are: 372*6070Srobj * 373*6070Srobj * a) Scan the SDRs for sensors associated with the entity. 374*6070Srobj * 375*6070Srobj * b) If there is an active sensor that includes a presence bit, or the 376*6070Srobj * entity has an active Entity Presence sensor, use the sensor to 377*6070Srobj * determine the presence of the entity. 378*6070Srobj * 379*6070Srobj * c) Otherwise, check to see that there is at least one active sensor 380*6070Srobj * associated with the entity. Do this by doing 'Get Sensor Readings' 381*6070Srobj * to the sensors associated with the entity until a scanning sensor is 382*6070Srobj * found. 383*6070Srobj * 384*6070Srobj * d) If there are no active sensors directly associated with the entity, 385*6070Srobj * check the SDRs to see if the entity is a container entity in an 386*6070Srobj * entity-association. If so, check to see if any of the contained 387*6070Srobj * entities are present, if so, assume the container entity exists. 388*6070Srobj * Note that this may need to be iterative, since it's possible to have 389*6070Srobj * multi-level entity associations. 390*6070Srobj * 391*6070Srobj * e) If there are no active sensors for the entity, and the entity is not 392*6070Srobj * the container entity in an active entity-assocation, then the entity 393*6070Srobj * is present if (sic) there there is a FRU device for the entity, and 394*6070Srobj * the FRU device is present. 395*6070Srobj * 396*6070Srobj * It should not be considered an error if a FRU device locator record is 397*6070Srobj * present for a FRU device, but the FRU device is not there. 398*6070Srobj * 399*6070Srobj */ 400*6070Srobj int 401*6070Srobj ipmi_entity_present(ipmi_handle_t *ihp, ipmi_entity_t *ep, boolean_t *valp) 402*6070Srobj { 403*6070Srobj /* LINTED - alignment */ 404*6070Srobj ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); 405*6070Srobj ipmi_entity_impl_t *cp; 406*6070Srobj ipmi_entity_sdr_t *esp; 407*6070Srobj ipmi_sdr_t *sdrp; 408*6070Srobj uint16_t mask; 409*6070Srobj uint8_t number, sensor_type, reading_type; 410*6070Srobj ipmi_sensor_reading_t *srp; 411*6070Srobj ipmi_sdr_compact_sensor_t *csp; 412*6070Srobj ipmi_sdr_full_sensor_t *fsp; 413*6070Srobj ipmi_sdr_fru_locator_t *frup; 414*6070Srobj char *frudata; 415*6070Srobj 416*6070Srobj /* 417*6070Srobj * Search the sensors for a present sensor or a discrete sensor that 418*6070Srobj * indicates presence. 419*6070Srobj */ 420*6070Srobj for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; 421*6070Srobj esp = ipmi_list_next(esp)) { 422*6070Srobj sdrp = esp->ies_sdr; 423*6070Srobj switch (sdrp->is_type) { 424*6070Srobj case IPMI_SDR_TYPE_COMPACT_SENSOR: 425*6070Srobj csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; 426*6070Srobj number = csp->is_cs_number; 427*6070Srobj sensor_type = csp->is_cs_type; 428*6070Srobj reading_type = csp->is_cs_reading_type; 429*6070Srobj break; 430*6070Srobj 431*6070Srobj case IPMI_SDR_TYPE_FULL_SENSOR: 432*6070Srobj fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; 433*6070Srobj number = fsp->is_fs_number; 434*6070Srobj sensor_type = fsp->is_fs_type; 435*6070Srobj reading_type = fsp->is_fs_reading_type; 436*6070Srobj break; 437*6070Srobj 438*6070Srobj default: 439*6070Srobj continue; 440*6070Srobj } 441*6070Srobj 442*6070Srobj switch (reading_type) { 443*6070Srobj case IPMI_RT_PRESENT: 444*6070Srobj mask = IPMI_SR_PRESENT_ASSERT; 445*6070Srobj break; 446*6070Srobj 447*6070Srobj case IPMI_RT_SPECIFIC: 448*6070Srobj switch (sensor_type) { 449*6070Srobj case IPMI_ST_PROCESSOR: 450*6070Srobj mask = IPMI_EV_PROCESSOR_PRESENT; 451*6070Srobj break; 452*6070Srobj 453*6070Srobj case IPMI_ST_POWER_SUPPLY: 454*6070Srobj mask = IPMI_EV_POWER_SUPPLY_PRESENT; 455*6070Srobj break; 456*6070Srobj 457*6070Srobj case IPMI_ST_MEMORY: 458*6070Srobj mask = IPMI_EV_MEMORY_PRESENT; 459*6070Srobj break; 460*6070Srobj 461*6070Srobj case IPMI_ST_BAY: 462*6070Srobj mask = IPMI_EV_BAY_PRESENT; 463*6070Srobj break; 464*6070Srobj 465*6070Srobj default: 466*6070Srobj continue; 467*6070Srobj } 468*6070Srobj break; 469*6070Srobj 470*6070Srobj default: 471*6070Srobj continue; 472*6070Srobj } 473*6070Srobj 474*6070Srobj /* 475*6070Srobj * If we've reached here, then we have a dedicated sensor that 476*6070Srobj * indicates presence. 477*6070Srobj */ 478*6070Srobj if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { 479*6070Srobj if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) { 480*6070Srobj *valp = B_FALSE; 481*6070Srobj return (0); 482*6070Srobj } 483*6070Srobj 484*6070Srobj return (-1); 485*6070Srobj } 486*6070Srobj 487*6070Srobj *valp = (srp->isr_state & mask) != 0; 488*6070Srobj return (0); 489*6070Srobj } 490*6070Srobj 491*6070Srobj /* 492*6070Srobj * No explicit presence sensor was found. See if there is at least one 493*6070Srobj * active sensor associated with the entity. 494*6070Srobj */ 495*6070Srobj for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; 496*6070Srobj esp = ipmi_list_next(esp)) { 497*6070Srobj sdrp = esp->ies_sdr; 498*6070Srobj switch (sdrp->is_type) { 499*6070Srobj case IPMI_SDR_TYPE_COMPACT_SENSOR: 500*6070Srobj csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; 501*6070Srobj number = csp->is_cs_number; 502*6070Srobj break; 503*6070Srobj 504*6070Srobj case IPMI_SDR_TYPE_FULL_SENSOR: 505*6070Srobj fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; 506*6070Srobj number = fsp->is_fs_number; 507*6070Srobj break; 508*6070Srobj 509*6070Srobj default: 510*6070Srobj continue; 511*6070Srobj } 512*6070Srobj 513*6070Srobj if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { 514*6070Srobj if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) 515*6070Srobj continue; 516*6070Srobj 517*6070Srobj return (-1); 518*6070Srobj } 519*6070Srobj 520*6070Srobj if (srp->isr_scanning_enabled) { 521*6070Srobj *valp = B_TRUE; 522*6070Srobj return (0); 523*6070Srobj } 524*6070Srobj } 525*6070Srobj 526*6070Srobj /* 527*6070Srobj * If this entity has children, then it is present if any of its 528*6070Srobj * children are present. 529*6070Srobj */ 530*6070Srobj for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL; 531*6070Srobj cp = ipmi_list_next(cp)) { 532*6070Srobj if (ipmi_entity_present(ihp, &cp->ie_entity, valp) != 0) 533*6070Srobj return (-1); 534*6070Srobj 535*6070Srobj if (*valp) 536*6070Srobj return (0); 537*6070Srobj } 538*6070Srobj 539*6070Srobj /* 540*6070Srobj * If the FRU device is present, then the entity is present. 541*6070Srobj */ 542*6070Srobj for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; 543*6070Srobj esp = ipmi_list_next(esp)) { 544*6070Srobj sdrp = esp->ies_sdr; 545*6070Srobj if (sdrp->is_type != IPMI_SDR_TYPE_FRU_LOCATOR) 546*6070Srobj continue; 547*6070Srobj 548*6070Srobj frup = (ipmi_sdr_fru_locator_t *)sdrp->is_record; 549*6070Srobj if (ipmi_fru_read(ihp, frup, &frudata) >= 0) { 550*6070Srobj ipmi_free(ihp, frudata); 551*6070Srobj *valp = B_TRUE; 552*6070Srobj return (0); 553*6070Srobj } 554*6070Srobj 555*6070Srobj if (ipmi_errno(ihp) != EIPMI_NOT_PRESENT) 556*6070Srobj return (-1); 557*6070Srobj } 558*6070Srobj 559*6070Srobj *valp = B_FALSE; 560*6070Srobj return (0); 561*6070Srobj } 562*6070Srobj 563*6070Srobj static int 564*6070Srobj ipmi_entity_refresh(ipmi_handle_t *ihp) 565*6070Srobj { 566*6070Srobj if (ipmi_hash_first(ihp->ih_entities) != NULL && 567*6070Srobj !ipmi_sdr_changed(ihp)) 568*6070Srobj return (0); 569*6070Srobj 570*6070Srobj if (ipmi_sdr_iter(ihp, ipmi_entity_visit, NULL) != 0) 571*6070Srobj return (-1); 572*6070Srobj 573*6070Srobj return (0); 574*6070Srobj } 575*6070Srobj 576*6070Srobj int 577*6070Srobj ipmi_entity_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *, 578*6070Srobj ipmi_entity_t *, void *), void *data) 579*6070Srobj { 580*6070Srobj ipmi_entity_impl_t *eip; 581*6070Srobj int ret; 582*6070Srobj 583*6070Srobj if (ipmi_entity_refresh(ihp) != 0) 584*6070Srobj return (-1); 585*6070Srobj 586*6070Srobj for (eip = ipmi_hash_first(ihp->ih_entities); eip != NULL; 587*6070Srobj eip = ipmi_hash_next(ihp->ih_entities, eip)) { 588*6070Srobj if (eip->ie_parent != NULL) 589*6070Srobj continue; 590*6070Srobj 591*6070Srobj if ((ret = func(ihp, &eip->ie_entity, data)) != 0) 592*6070Srobj return (ret); 593*6070Srobj } 594*6070Srobj 595*6070Srobj return (0); 596*6070Srobj } 597*6070Srobj 598*6070Srobj int 599*6070Srobj ipmi_entity_iter_sdr(ipmi_handle_t *ihp, ipmi_entity_t *ep, 600*6070Srobj int (*func)(ipmi_handle_t *, ipmi_entity_t *, const char *, ipmi_sdr_t *, 601*6070Srobj void *), void *data) 602*6070Srobj { 603*6070Srobj /* LINTED - alignment */ 604*6070Srobj ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); 605*6070Srobj ipmi_entity_sdr_t *isp; 606*6070Srobj int ret; 607*6070Srobj 608*6070Srobj for (isp = ipmi_list_next(&eip->ie_sdr_list); isp != NULL; 609*6070Srobj isp = ipmi_list_next(isp)) { 610*6070Srobj if ((ret = func(ihp, ep, isp->ies_name, 611*6070Srobj isp->ies_sdr, data)) != 0) 612*6070Srobj return (ret); 613*6070Srobj } 614*6070Srobj 615*6070Srobj return (0); 616*6070Srobj } 617*6070Srobj 618*6070Srobj int 619*6070Srobj ipmi_entity_iter_children(ipmi_handle_t *ihp, ipmi_entity_t *ep, 620*6070Srobj int (*func)(ipmi_handle_t *, ipmi_entity_t *, void *), void *data) 621*6070Srobj { 622*6070Srobj /* LINTED - alignment */ 623*6070Srobj ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); 624*6070Srobj ipmi_entity_impl_t *cp; 625*6070Srobj int ret; 626*6070Srobj 627*6070Srobj for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL; 628*6070Srobj cp = ipmi_list_next(cp)) { 629*6070Srobj if ((ret = func(ihp, &cp->ie_entity, data)) != 0) 630*6070Srobj return (ret); 631*6070Srobj } 632*6070Srobj 633*6070Srobj return (0); 634*6070Srobj } 635*6070Srobj 636*6070Srobj ipmi_entity_t * 637*6070Srobj ipmi_entity_parent(ipmi_handle_t *ihp, ipmi_entity_t *ep) 638*6070Srobj { 639*6070Srobj /* LINTED - alignment */ 640*6070Srobj ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); 641*6070Srobj 642*6070Srobj if (eip->ie_parent == NULL) { 643*6070Srobj (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 644*6070Srobj return (NULL); 645*6070Srobj } 646*6070Srobj 647*6070Srobj return (&eip->ie_parent->ie_entity); 648*6070Srobj } 649*6070Srobj 650*6070Srobj ipmi_entity_t * 651*6070Srobj ipmi_entity_lookup(ipmi_handle_t *ihp, uint8_t type, uint8_t instance) 652*6070Srobj { 653*6070Srobj ipmi_entity_t search; 654*6070Srobj ipmi_entity_impl_t *eip; 655*6070Srobj 656*6070Srobj if (ipmi_entity_refresh(ihp) != 0) 657*6070Srobj return (NULL); 658*6070Srobj 659*6070Srobj search.ie_type = type; 660*6070Srobj search.ie_instance = instance; 661*6070Srobj 662*6070Srobj if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { 663*6070Srobj (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 664*6070Srobj return (NULL); 665*6070Srobj } 666*6070Srobj 667*6070Srobj return (&eip->ie_entity); 668*6070Srobj } 669*6070Srobj 670*6070Srobj ipmi_entity_t * 671*6070Srobj ipmi_entity_lookup_sdr(ipmi_handle_t *ihp, const char *name) 672*6070Srobj { 673*6070Srobj ipmi_sdr_t *sdrp; 674*6070Srobj uint8_t id, instance; 675*6070Srobj boolean_t logical; 676*6070Srobj 677*6070Srobj if ((sdrp = ipmi_sdr_lookup(ihp, name)) == NULL) 678*6070Srobj return (NULL); 679*6070Srobj 680*6070Srobj if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0) { 681*6070Srobj (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 682*6070Srobj "SDR record %s has no associated entity", name); 683*6070Srobj return (NULL); 684*6070Srobj } 685*6070Srobj 686*6070Srobj return (ipmi_entity_lookup(ihp, id, instance)); 687*6070Srobj } 688*6070Srobj 689*6070Srobj static const void * 690*6070Srobj ipmi_entity_hash_convert(const void *p) 691*6070Srobj { 692*6070Srobj const ipmi_entity_impl_t *eip = p; 693*6070Srobj 694*6070Srobj return (&eip->ie_entity); 695*6070Srobj } 696*6070Srobj 697*6070Srobj static ulong_t 698*6070Srobj ipmi_entity_hash_compute(const void *p) 699*6070Srobj { 700*6070Srobj const ipmi_entity_t *ep = p; 701*6070Srobj 702*6070Srobj return ((ep->ie_type << 8) | ep->ie_instance); 703*6070Srobj } 704*6070Srobj 705*6070Srobj static int 706*6070Srobj ipmi_entity_hash_compare(const void *a, const void *b) 707*6070Srobj { 708*6070Srobj const ipmi_entity_t *ea = a; 709*6070Srobj const ipmi_entity_t *eb = b; 710*6070Srobj 711*6070Srobj if (ea->ie_type == eb->ie_type && 712*6070Srobj ea->ie_instance == eb->ie_instance) 713*6070Srobj return (0); 714*6070Srobj else 715*6070Srobj return (-1); 716*6070Srobj } 717*6070Srobj 718*6070Srobj int 719*6070Srobj ipmi_entity_init(ipmi_handle_t *ihp) 720*6070Srobj { 721*6070Srobj if ((ihp->ih_entities = ipmi_hash_create(ihp, 722*6070Srobj offsetof(ipmi_entity_impl_t, ie_link), 723*6070Srobj ipmi_entity_hash_convert, 724*6070Srobj ipmi_entity_hash_compute, 725*6070Srobj ipmi_entity_hash_compare)) == NULL) 726*6070Srobj return (-1); 727*6070Srobj 728*6070Srobj return (0); 729*6070Srobj } 730*6070Srobj 731*6070Srobj void 732*6070Srobj ipmi_entity_clear(ipmi_handle_t *ihp) 733*6070Srobj { 734*6070Srobj ipmi_entity_impl_t *eip; 735*6070Srobj ipmi_entity_sdr_t *esp; 736*6070Srobj 737*6070Srobj while ((eip = ipmi_hash_first(ihp->ih_entities)) != NULL) { 738*6070Srobj while ((esp = ipmi_list_next(&eip->ie_sdr_list)) != NULL) { 739*6070Srobj ipmi_list_delete(&eip->ie_sdr_list, esp); 740*6070Srobj ipmi_free(ihp, esp); 741*6070Srobj } 742*6070Srobj ipmi_hash_remove(ihp->ih_entities, eip); 743*6070Srobj ipmi_free(ihp, eip); 744*6070Srobj } 745*6070Srobj } 746*6070Srobj 747*6070Srobj void 748*6070Srobj ipmi_entity_fini(ipmi_handle_t *ihp) 749*6070Srobj { 750*6070Srobj if (ihp->ih_entities != NULL) { 751*6070Srobj ipmi_entity_clear(ihp); 752*6070Srobj ipmi_hash_destroy(ihp->ih_entities); 753*6070Srobj } 754*6070Srobj } 755