xref: /titanic_50/usr/src/lib/libipmi/common/ipmi_entity.c (revision 2eeaed14a5e2ed9bd811643ad5bffc3510ca0310)
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
ipmi_entity_add_assoc(ipmi_handle_t * ihp,ipmi_entity_impl_t * eip,uint8_t id,uint8_t instance)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
ipmi_entity_sdr_parse(ipmi_sdr_t * sdrp,uint8_t * id,uint8_t * instance,boolean_t * logical)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
ipmi_entity_visit(ipmi_handle_t * ihp,const char * name,ipmi_sdr_t * sdrp,void * unused)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
ipmi_entity_present_sdr(ipmi_handle_t * ihp,ipmi_sdr_t * sdrp,boolean_t * valp)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
ipmi_entity_present(ipmi_handle_t * ihp,ipmi_entity_t * ep,boolean_t * valp)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
ipmi_entity_refresh(ipmi_handle_t * ihp)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
ipmi_entity_iter(ipmi_handle_t * ihp,int (* func)(ipmi_handle_t *,ipmi_entity_t *,void *),void * data)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
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*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
ipmi_entity_iter_children(ipmi_handle_t * ihp,ipmi_entity_t * ep,int (* func)(ipmi_handle_t *,ipmi_entity_t *,void *),void * data)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 *
ipmi_entity_parent(ipmi_handle_t * ihp,ipmi_entity_t * ep)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 *
ipmi_entity_lookup(ipmi_handle_t * ihp,uint8_t type,uint8_t instance)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 *
ipmi_entity_lookup_sdr(ipmi_handle_t * ihp,const char * name)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 *
ipmi_entity_hash_convert(const void * p)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
ipmi_entity_hash_compute(const void * p)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
ipmi_entity_hash_compare(const void * a,const void * b)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
ipmi_entity_init(ipmi_handle_t * ihp)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
ipmi_entity_clear(ipmi_handle_t * ihp)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
ipmi_entity_fini(ipmi_handle_t * ihp)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