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
ipmi_entity_add_assoc(ipmi_handle_t * ihp,ipmi_entity_impl_t * eip,uint8_t id,uint8_t instance)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
ipmi_entity_sdr_parse(ipmi_sdr_t * sdrp,uint8_t * id,uint8_t * instance,boolean_t * logical)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
ipmi_entity_visit(ipmi_handle_t * ihp,const char * name,ipmi_sdr_t * sdrp,void * unused)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
ipmi_entity_present_sdr(ipmi_handle_t * ihp,ipmi_sdr_t * sdrp,boolean_t * valp)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
ipmi_entity_present(ipmi_handle_t * ihp,ipmi_entity_t * ep,boolean_t * valp)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
ipmi_entity_refresh(ipmi_handle_t * ihp)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
ipmi_entity_iter(ipmi_handle_t * ihp,int (* func)(ipmi_handle_t *,ipmi_entity_t *,void *),void * data)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
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)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
ipmi_entity_iter_children(ipmi_handle_t * ihp,ipmi_entity_t * ep,int (* func)(ipmi_handle_t *,ipmi_entity_t *,void *),void * data)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 *
ipmi_entity_parent(ipmi_handle_t * ihp,ipmi_entity_t * ep)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 *
ipmi_entity_lookup(ipmi_handle_t * ihp,uint8_t type,uint8_t instance)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 *
ipmi_entity_lookup_sdr(ipmi_handle_t * ihp,const char * name)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 *
ipmi_entity_hash_convert(const void * p)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
ipmi_entity_hash_compute(const void * p)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
ipmi_entity_hash_compare(const void * a,const void * b)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
ipmi_entity_init(ipmi_handle_t * ihp)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
ipmi_entity_clear(ipmi_handle_t * ihp)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
ipmi_entity_fini(ipmi_handle_t * ihp)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