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