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