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