4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * IPMI entities are a strange beast. A reasonable assumption for those
30 * unfamiliar with the spec would be that there was a command to iterate over
31 * all entities, and a command to iterate over sensors associated with each
32 * entity. Instead, the entire IPMI world is derived from the SDR repository.
33 * Entities only exist in the sense that they are referenced by a SDR record.
35 * In addition, entities can be associated into groups, and determining entity
36 * presence is quite complicated. The IPMI spec dedicates an entire chapter
37 * (40) to the process of handling sensor associations.
39 * The above logic is implemented via the ipmi_entity_present() function. We
40 * make a first pass over the SDR repository to discover entities, creating
41 * entity groups and associating SDR records with the each.
43 * We don't currently support device-relative entities.
47 #include <ipmi_impl.h>
50 typedef struct ipmi_entity_sdr
{
56 typedef struct ipmi_entity_impl
{
58 ipmi_entity_t ie_entity
;
59 struct ipmi_entity_impl
*ie_parent
;
60 ipmi_hash_link_t ie_link
;
61 ipmi_list_t ie_child_list
;
62 ipmi_list_t ie_sdr_list
;
65 #define ENTITY_TO_IMPL(ep) \
66 ((ipmi_entity_impl_t *)((char *)(ep) - \
67 offsetof(ipmi_entity_impl_t, ie_entity)))
70 ipmi_entity_add_assoc(ipmi_handle_t
*ihp
, ipmi_entity_impl_t
*eip
,
71 uint8_t id
, uint8_t instance
)
73 ipmi_entity_impl_t
*cp
;
77 search
.ie_instance
= instance
;
79 if ((cp
= ipmi_hash_lookup(ihp
->ih_entities
, &search
)) == NULL
) {
80 if ((cp
= ipmi_zalloc(ihp
,
81 sizeof (ipmi_entity_impl_t
))) == NULL
)
84 cp
->ie_entity
.ie_type
= id
;
85 cp
->ie_entity
.ie_instance
= instance
;
87 ipmi_hash_insert(ihp
->ih_entities
, cp
);
90 if (cp
->ie_parent
!= NULL
) {
92 * This should never happen. However, we want to be tolerant of
93 * pathologically broken IPMI implementations, so we ignore this
94 * error, and the first parent wins.
100 ipmi_list_append(&eip
->ie_child_list
, cp
);
101 eip
->ie_entity
.ie_children
++;
107 ipmi_entity_sdr_parse(ipmi_sdr_t
*sdrp
, uint8_t *id
, uint8_t *instance
,
110 switch (sdrp
->is_type
) {
111 case IPMI_SDR_TYPE_FULL_SENSOR
:
113 ipmi_sdr_full_sensor_t
*fsp
=
114 (ipmi_sdr_full_sensor_t
*)sdrp
->is_record
;
115 *id
= fsp
->is_fs_entity_id
;
116 *instance
= fsp
->is_fs_entity_instance
;
117 *logical
= fsp
->is_fs_entity_logical
;
121 case IPMI_SDR_TYPE_COMPACT_SENSOR
:
123 ipmi_sdr_compact_sensor_t
*csp
=
124 (ipmi_sdr_compact_sensor_t
*)sdrp
->is_record
;
125 *id
= csp
->is_cs_entity_id
;
126 *instance
= csp
->is_cs_entity_instance
;
127 *logical
= csp
->is_cs_entity_logical
;
131 case IPMI_SDR_TYPE_EVENT_ONLY
:
133 ipmi_sdr_event_only_t
*eop
=
134 (ipmi_sdr_event_only_t
*)sdrp
->is_record
;
135 *id
= eop
->is_eo_entity_id
;
136 *instance
= eop
->is_eo_entity_instance
;
137 *logical
= eop
->is_eo_entity_logical
;
141 case IPMI_SDR_TYPE_ENTITY_ASSOCIATION
:
143 ipmi_sdr_entity_association_t
*eap
=
144 (ipmi_sdr_entity_association_t
*)sdrp
->is_record
;
145 *id
= eap
->is_ea_entity_id
;
146 *instance
= eap
->is_ea_entity_instance
;
151 case IPMI_SDR_TYPE_GENERIC_LOCATOR
:
153 ipmi_sdr_generic_locator_t
*glp
=
154 (ipmi_sdr_generic_locator_t
*)sdrp
->is_record
;
155 *id
= glp
->is_gl_entity
;
156 *instance
= glp
->is_gl_instance
;
161 case IPMI_SDR_TYPE_FRU_LOCATOR
:
163 ipmi_sdr_fru_locator_t
*flp
=
164 (ipmi_sdr_fru_locator_t
*)sdrp
->is_record
;
165 *id
= flp
->is_fl_entity
;
166 *instance
= flp
->is_fl_instance
;
171 case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR
:
173 ipmi_sdr_management_locator_t
*mlp
=
174 (ipmi_sdr_management_locator_t
*)sdrp
->is_record
;
175 *id
= mlp
->is_ml_entity_id
;
176 *instance
= mlp
->is_ml_entity_instance
;
189 * This function is responsible for gathering all entities, inserting them into
190 * the global hash, and establishing any associations.
194 ipmi_entity_visit(ipmi_handle_t
*ihp
, const char *name
, ipmi_sdr_t
*sdrp
,
197 uint8_t id
, instance
;
199 ipmi_entity_t search
;
200 ipmi_entity_impl_t
*eip
;
201 ipmi_entity_sdr_t
*esp
;
203 if (ipmi_entity_sdr_parse(sdrp
, &id
, &instance
, &logical
) != 0)
207 search
.ie_instance
= instance
;
209 if ((eip
= ipmi_hash_lookup(ihp
->ih_entities
, &search
)) == NULL
) {
210 if ((eip
= ipmi_zalloc(ihp
,
211 sizeof (ipmi_entity_impl_t
))) == NULL
)
214 eip
->ie_entity
.ie_type
= id
;
215 eip
->ie_entity
.ie_instance
= instance
;
217 ipmi_hash_insert(ihp
->ih_entities
, eip
);
220 eip
->ie_entity
.ie_logical
|= logical
;
222 if (sdrp
->is_type
== IPMI_SDR_TYPE_ENTITY_ASSOCIATION
) {
226 ipmi_sdr_entity_association_t
*eap
=
227 (ipmi_sdr_entity_association_t
*)sdrp
->is_record
;
229 if (eap
->is_ea_range
) {
231 type
= eap
->is_ea_sub
[0].is_ea_sub_id
;
232 start
= eap
->is_ea_sub
[0].is_ea_sub_instance
;
233 end
= eap
->is_ea_sub
[1].is_ea_sub_instance
;
236 for (i
= start
; i
<= end
; i
++) {
237 if (ipmi_entity_add_assoc(ihp
, eip
,
243 type
= eap
->is_ea_sub
[2].is_ea_sub_id
;
244 start
= eap
->is_ea_sub
[2].is_ea_sub_instance
;
245 end
= eap
->is_ea_sub
[3].is_ea_sub_instance
;
248 for (i
= start
; i
<= end
; i
++) {
249 if (ipmi_entity_add_assoc(ihp
, eip
,
255 for (i
= 0; i
< 4; i
++) {
256 type
= eap
->is_ea_sub
[i
].is_ea_sub_id
;
257 instance
= eap
->is_ea_sub
[i
].is_ea_sub_instance
;
262 if (ipmi_entity_add_assoc(ihp
, eip
, type
,
268 if ((esp
= ipmi_zalloc(ihp
,
269 sizeof (ipmi_entity_sdr_t
))) == NULL
)
273 esp
->ies_name
= name
;
274 ipmi_list_append(&eip
->ie_sdr_list
, esp
);
281 * Given a SDR record, return boolean values indicating whether the sensor
282 * indicates explicit presence.
284 * XXX this should really share code with entity_present()
287 ipmi_entity_present_sdr(ipmi_handle_t
*ihp
, ipmi_sdr_t
*sdrp
,
291 uint8_t number
, sensor_type
, reading_type
;
292 ipmi_sdr_compact_sensor_t
*csp
;
293 ipmi_sdr_full_sensor_t
*fsp
;
294 ipmi_sensor_reading_t
*srp
;
296 switch (sdrp
->is_type
) {
297 case IPMI_SDR_TYPE_COMPACT_SENSOR
:
298 csp
= (ipmi_sdr_compact_sensor_t
*)sdrp
->is_record
;
299 number
= csp
->is_cs_number
;
300 sensor_type
= csp
->is_cs_type
;
301 reading_type
= csp
->is_cs_reading_type
;
304 case IPMI_SDR_TYPE_FULL_SENSOR
:
305 fsp
= (ipmi_sdr_full_sensor_t
*)sdrp
->is_record
;
306 number
= fsp
->is_fs_number
;
307 sensor_type
= fsp
->is_fs_type
;
308 reading_type
= fsp
->is_fs_reading_type
;
316 switch (reading_type
) {
317 case IPMI_RT_PRESENT
:
318 mask
= IPMI_SR_PRESENT_ASSERT
;
321 case IPMI_RT_SPECIFIC
:
322 switch (sensor_type
) {
323 case IPMI_ST_PROCESSOR
:
324 mask
= IPMI_EV_PROCESSOR_PRESENT
;
327 case IPMI_ST_POWER_SUPPLY
:
328 mask
= IPMI_EV_POWER_SUPPLY_PRESENT
;
332 mask
= IPMI_EV_MEMORY_PRESENT
;
336 mask
= IPMI_EV_BAY_PRESENT
;
351 * If we've reached here, then we have a dedicated sensor that
352 * indicates presence.
354 if ((srp
= ipmi_get_sensor_reading(ihp
, number
)) == NULL
) {
355 if (ipmi_errno(ihp
) == EIPMI_NOT_PRESENT
) {
363 *valp
= (srp
->isr_state
& mask
) != 0;
368 * This function follows the procedure documented in section 40 of the spec.
369 * To quote the conclusion from section 40.2:
371 * Thus, the steps to detecting an Entity are:
373 * a) Scan the SDRs for sensors associated with the entity.
375 * b) If there is an active sensor that includes a presence bit, or the
376 * entity has an active Entity Presence sensor, use the sensor to
377 * determine the presence of the entity.
379 * c) Otherwise, check to see that there is at least one active sensor
380 * associated with the entity. Do this by doing 'Get Sensor Readings'
381 * to the sensors associated with the entity until a scanning sensor is
384 * d) If there are no active sensors directly associated with the entity,
385 * check the SDRs to see if the entity is a container entity in an
386 * entity-association. If so, check to see if any of the contained
387 * entities are present, if so, assume the container entity exists.
388 * Note that this may need to be iterative, since it's possible to have
389 * multi-level entity associations.
391 * e) If there are no active sensors for the entity, and the entity is not
392 * the container entity in an active entity-assocation, then the entity
393 * is present if (sic) there there is a FRU device for the entity, and
394 * the FRU device is present.
396 * It should not be considered an error if a FRU device locator record is
397 * present for a FRU device, but the FRU device is not there.
401 ipmi_entity_present(ipmi_handle_t
*ihp
, ipmi_entity_t
*ep
, boolean_t
*valp
)
403 /* LINTED - alignment */
404 ipmi_entity_impl_t
*eip
= ENTITY_TO_IMPL(ep
);
405 ipmi_entity_impl_t
*cp
;
406 ipmi_entity_sdr_t
*esp
;
409 uint8_t number
, sensor_type
, reading_type
;
410 ipmi_sensor_reading_t
*srp
;
411 ipmi_sdr_compact_sensor_t
*csp
;
412 ipmi_sdr_full_sensor_t
*fsp
;
413 ipmi_sdr_fru_locator_t
*frup
;
417 * Search the sensors for a present sensor or a discrete sensor that
418 * indicates presence.
420 for (esp
= ipmi_list_next(&eip
->ie_sdr_list
); esp
!= NULL
;
421 esp
= ipmi_list_next(esp
)) {
423 switch (sdrp
->is_type
) {
424 case IPMI_SDR_TYPE_COMPACT_SENSOR
:
425 csp
= (ipmi_sdr_compact_sensor_t
*)sdrp
->is_record
;
426 number
= csp
->is_cs_number
;
427 sensor_type
= csp
->is_cs_type
;
428 reading_type
= csp
->is_cs_reading_type
;
431 case IPMI_SDR_TYPE_FULL_SENSOR
:
432 fsp
= (ipmi_sdr_full_sensor_t
*)sdrp
->is_record
;
433 number
= fsp
->is_fs_number
;
434 sensor_type
= fsp
->is_fs_type
;
435 reading_type
= fsp
->is_fs_reading_type
;
442 switch (reading_type
) {
443 case IPMI_RT_PRESENT
:
444 mask
= IPMI_SR_PRESENT_ASSERT
;
447 case IPMI_RT_SPECIFIC
:
448 switch (sensor_type
) {
449 case IPMI_ST_PROCESSOR
:
450 mask
= IPMI_EV_PROCESSOR_PRESENT
;
453 case IPMI_ST_POWER_SUPPLY
:
454 mask
= IPMI_EV_POWER_SUPPLY_PRESENT
;
458 mask
= IPMI_EV_MEMORY_PRESENT
;
462 mask
= IPMI_EV_BAY_PRESENT
;
475 * If we've reached here, then we have a dedicated sensor that
476 * indicates presence.
478 if ((srp
= ipmi_get_sensor_reading(ihp
, number
)) == NULL
) {
479 if (ipmi_errno(ihp
) == EIPMI_NOT_PRESENT
) {
487 *valp
= (srp
->isr_state
& mask
) != 0;
492 * No explicit presence sensor was found. See if there is at least one
493 * active sensor associated with the entity.
495 for (esp
= ipmi_list_next(&eip
->ie_sdr_list
); esp
!= NULL
;
496 esp
= ipmi_list_next(esp
)) {
498 switch (sdrp
->is_type
) {
499 case IPMI_SDR_TYPE_COMPACT_SENSOR
:
500 csp
= (ipmi_sdr_compact_sensor_t
*)sdrp
->is_record
;
501 number
= csp
->is_cs_number
;
504 case IPMI_SDR_TYPE_FULL_SENSOR
:
505 fsp
= (ipmi_sdr_full_sensor_t
*)sdrp
->is_record
;
506 number
= fsp
->is_fs_number
;
513 if ((srp
= ipmi_get_sensor_reading(ihp
, number
)) == NULL
) {
514 if (ipmi_errno(ihp
) == EIPMI_NOT_PRESENT
)
520 if (srp
->isr_scanning_enabled
) {
527 * If this entity has children, then it is present if any of its
528 * children are present.
530 for (cp
= ipmi_list_next(&eip
->ie_child_list
); cp
!= NULL
;
531 cp
= ipmi_list_next(cp
)) {
532 if (ipmi_entity_present(ihp
, &cp
->ie_entity
, valp
) != 0)
540 * If the FRU device is present, then the entity is present.
542 for (esp
= ipmi_list_next(&eip
->ie_sdr_list
); esp
!= NULL
;
543 esp
= ipmi_list_next(esp
)) {
545 if (sdrp
->is_type
!= IPMI_SDR_TYPE_FRU_LOCATOR
)
548 frup
= (ipmi_sdr_fru_locator_t
*)sdrp
->is_record
;
549 if (ipmi_fru_read(ihp
, frup
, &frudata
) >= 0) {
550 ipmi_free(ihp
, frudata
);
555 if (ipmi_errno(ihp
) != EIPMI_NOT_PRESENT
)
564 ipmi_entity_refresh(ipmi_handle_t
*ihp
)
566 if (ipmi_hash_first(ihp
->ih_entities
) != NULL
&&
567 !ipmi_sdr_changed(ihp
))
570 if (ipmi_sdr_iter(ihp
, ipmi_entity_visit
, NULL
) != 0)
577 ipmi_entity_iter(ipmi_handle_t
*ihp
, int (*func
)(ipmi_handle_t
*,
578 ipmi_entity_t
*, void *), void *data
)
580 ipmi_entity_impl_t
*eip
;
583 if (ipmi_entity_refresh(ihp
) != 0)
586 for (eip
= ipmi_hash_first(ihp
->ih_entities
); eip
!= NULL
;
587 eip
= ipmi_hash_next(ihp
->ih_entities
, eip
)) {
588 if (eip
->ie_parent
!= NULL
)
591 if ((ret
= func(ihp
, &eip
->ie_entity
, data
)) != 0)
599 ipmi_entity_iter_sdr(ipmi_handle_t
*ihp
, ipmi_entity_t
*ep
,
600 int (*func
)(ipmi_handle_t
*, ipmi_entity_t
*, const char *, ipmi_sdr_t
*,
603 /* LINTED - alignment */
604 ipmi_entity_impl_t
*eip
= ENTITY_TO_IMPL(ep
);
605 ipmi_entity_sdr_t
*isp
;
608 for (isp
= ipmi_list_next(&eip
->ie_sdr_list
); isp
!= NULL
;
609 isp
= ipmi_list_next(isp
)) {
610 if ((ret
= func(ihp
, ep
, isp
->ies_name
,
611 isp
->ies_sdr
, data
)) != 0)
619 ipmi_entity_iter_children(ipmi_handle_t
*ihp
, ipmi_entity_t
*ep
,
620 int (*func
)(ipmi_handle_t
*, ipmi_entity_t
*, void *), void *data
)
622 /* LINTED - alignment */
623 ipmi_entity_impl_t
*eip
= ENTITY_TO_IMPL(ep
);
624 ipmi_entity_impl_t
*cp
;
627 for (cp
= ipmi_list_next(&eip
->ie_child_list
); cp
!= NULL
;
628 cp
= ipmi_list_next(cp
)) {
629 if ((ret
= func(ihp
, &cp
->ie_entity
, data
)) != 0)
637 ipmi_entity_parent(ipmi_handle_t
*ihp
, ipmi_entity_t
*ep
)
639 /* LINTED - alignment */
640 ipmi_entity_impl_t
*eip
= ENTITY_TO_IMPL(ep
);
642 if (eip
->ie_parent
== NULL
) {
643 (void) ipmi_set_error(ihp
, EIPMI_NOT_PRESENT
, NULL
);
647 return (&eip
->ie_parent
->ie_entity
);
651 ipmi_entity_lookup(ipmi_handle_t
*ihp
, uint8_t type
, uint8_t instance
)
653 ipmi_entity_t search
;
654 ipmi_entity_impl_t
*eip
;
656 if (ipmi_entity_refresh(ihp
) != 0)
659 search
.ie_type
= type
;
660 search
.ie_instance
= instance
;
662 if ((eip
= ipmi_hash_lookup(ihp
->ih_entities
, &search
)) == NULL
) {
663 (void) ipmi_set_error(ihp
, EIPMI_NOT_PRESENT
, NULL
);
667 return (&eip
->ie_entity
);
671 ipmi_entity_lookup_sdr(ipmi_handle_t
*ihp
, const char *name
)
674 uint8_t id
, instance
;
677 if ((sdrp
= ipmi_sdr_lookup(ihp
, name
)) == NULL
)
680 if (ipmi_entity_sdr_parse(sdrp
, &id
, &instance
, &logical
) != 0) {
681 (void) ipmi_set_error(ihp
, EIPMI_NOT_PRESENT
,
682 "SDR record %s has no associated entity", name
);
686 return (ipmi_entity_lookup(ihp
, id
, instance
));
690 ipmi_entity_hash_convert(const void *p
)
692 const ipmi_entity_impl_t
*eip
= p
;
694 return (&eip
->ie_entity
);
698 ipmi_entity_hash_compute(const void *p
)
700 const ipmi_entity_t
*ep
= p
;
702 return ((ep
->ie_type
<< 8) | ep
->ie_instance
);
706 ipmi_entity_hash_compare(const void *a
, const void *b
)
708 const ipmi_entity_t
*ea
= a
;
709 const ipmi_entity_t
*eb
= b
;
711 if (ea
->ie_type
== eb
->ie_type
&&
712 ea
->ie_instance
== eb
->ie_instance
)
719 ipmi_entity_init(ipmi_handle_t
*ihp
)
721 if ((ihp
->ih_entities
= ipmi_hash_create(ihp
,
722 offsetof(ipmi_entity_impl_t
, ie_link
),
723 ipmi_entity_hash_convert
,
724 ipmi_entity_hash_compute
,
725 ipmi_entity_hash_compare
)) == NULL
)
732 ipmi_entity_clear(ipmi_handle_t
*ihp
)
734 ipmi_entity_impl_t
*eip
;
735 ipmi_entity_sdr_t
*esp
;
737 while ((eip
= ipmi_hash_first(ihp
->ih_entities
)) != NULL
) {
738 while ((esp
= ipmi_list_next(&eip
->ie_sdr_list
)) != NULL
) {
739 ipmi_list_delete(&eip
->ie_sdr_list
, esp
);
742 ipmi_hash_remove(ihp
->ih_entities
, eip
);
748 ipmi_entity_fini(ipmi_handle_t
*ihp
)
750 if (ihp
->ih_entities
!= NULL
) {
751 ipmi_entity_clear(ihp
);
752 ipmi_hash_destroy(ihp
->ih_entities
);