xref: /onnv-gate/usr/src/lib/libipmi/common/ipmi_entity.c (revision 6070:1e70ddca5488)
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