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 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
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.
34 *
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.
38 *
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.
42 *
43 * We don't currently support device-relative entities.
44 */
45
46 #include <libipmi.h>
47 #include <ipmi_impl.h>
48 #include <stddef.h>
49
50 typedef struct ipmi_entity_sdr {
51 ipmi_list_t ies_list;
52 const char *ies_name;
53 ipmi_sdr_t *ies_sdr;
54 } ipmi_entity_sdr_t;
55
56 typedef struct ipmi_entity_impl {
57 ipmi_list_t ie_list;
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;
63 } ipmi_entity_impl_t;
64
65 #define ENTITY_TO_IMPL(ep) \
66 ((ipmi_entity_impl_t *)((char *)(ep) - \
67 offsetof(ipmi_entity_impl_t, ie_entity)))
68
69 static int
ipmi_entity_add_assoc(ipmi_handle_t * ihp,ipmi_entity_impl_t * eip,uint8_t id,uint8_t instance)70 ipmi_entity_add_assoc(ipmi_handle_t *ihp, ipmi_entity_impl_t *eip,
71 uint8_t id, uint8_t instance)
72 {
73 ipmi_entity_impl_t *cp;
74 ipmi_entity_t search;
75
76 search.ie_type = id;
77 search.ie_instance = instance;
78
79 if ((cp = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
80 if ((cp = ipmi_zalloc(ihp,
81 sizeof (ipmi_entity_impl_t))) == NULL)
82 return (-1);
83
84 cp->ie_entity.ie_type = id;
85 cp->ie_entity.ie_instance = instance;
86
87 ipmi_hash_insert(ihp->ih_entities, cp);
88 }
89
90 if (cp->ie_parent != NULL) {
91 /*
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.
95 */
96 return (0);
97 }
98
99 cp->ie_parent = eip;
100 ipmi_list_append(&eip->ie_child_list, cp);
101 eip->ie_entity.ie_children++;
102
103 return (0);
104 }
105
106 static int
ipmi_entity_sdr_parse(ipmi_sdr_t * sdrp,uint8_t * id,uint8_t * instance,boolean_t * logical)107 ipmi_entity_sdr_parse(ipmi_sdr_t *sdrp, uint8_t *id, uint8_t *instance,
108 boolean_t *logical)
109 {
110 switch (sdrp->is_type) {
111 case IPMI_SDR_TYPE_FULL_SENSOR:
112 {
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;
118 break;
119 }
120
121 case IPMI_SDR_TYPE_COMPACT_SENSOR:
122 {
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;
128 break;
129 }
130
131 case IPMI_SDR_TYPE_EVENT_ONLY:
132 {
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;
138 break;
139 }
140
141 case IPMI_SDR_TYPE_ENTITY_ASSOCIATION:
142 {
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;
147 *logical = B_TRUE;
148 break;
149 }
150
151 case IPMI_SDR_TYPE_GENERIC_LOCATOR:
152 {
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;
157 *logical = B_FALSE;
158 break;
159 }
160
161 case IPMI_SDR_TYPE_FRU_LOCATOR:
162 {
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;
167 *logical = B_FALSE;
168 break;
169 }
170
171 case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
172 {
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;
177 *logical = B_FALSE;
178 break;
179 }
180
181 default:
182 return (-1);
183 }
184
185 return (0);
186 }
187
188 /*
189 * This function is responsible for gathering all entities, inserting them into
190 * the global hash, and establishing any associations.
191 */
192 /*ARGSUSED*/
193 static int
ipmi_entity_visit(ipmi_handle_t * ihp,const char * name,ipmi_sdr_t * sdrp,void * unused)194 ipmi_entity_visit(ipmi_handle_t *ihp, const char *name, ipmi_sdr_t *sdrp,
195 void *unused)
196 {
197 uint8_t id, instance;
198 boolean_t logical;
199 ipmi_entity_t search;
200 ipmi_entity_impl_t *eip;
201 ipmi_entity_sdr_t *esp;
202
203 if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0)
204 return (0);
205
206 search.ie_type = id;
207 search.ie_instance = instance;
208
209 if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
210 if ((eip = ipmi_zalloc(ihp,
211 sizeof (ipmi_entity_impl_t))) == NULL)
212 return (-1);
213
214 eip->ie_entity.ie_type = id;
215 eip->ie_entity.ie_instance = instance;
216
217 ipmi_hash_insert(ihp->ih_entities, eip);
218 }
219
220 eip->ie_entity.ie_logical |= logical;
221
222 if (sdrp->is_type == IPMI_SDR_TYPE_ENTITY_ASSOCIATION) {
223 uint8_t start, end;
224 uint8_t i, type;
225
226 ipmi_sdr_entity_association_t *eap =
227 (ipmi_sdr_entity_association_t *)sdrp->is_record;
228
229 if (eap->is_ea_range) {
230
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;
234
235 if (type != 0) {
236 for (i = start; i <= end; i++) {
237 if (ipmi_entity_add_assoc(ihp, eip,
238 type, i) != 0)
239 return (-1);
240 }
241 }
242
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;
246
247 if (type != 0) {
248 for (i = start; i <= end; i++) {
249 if (ipmi_entity_add_assoc(ihp, eip,
250 type, i) != 0)
251 return (-1);
252 }
253 }
254 } else {
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;
258
259 if (type == 0)
260 continue;
261
262 if (ipmi_entity_add_assoc(ihp, eip, type,
263 instance) != 0)
264 return (-1);
265 }
266 }
267 } else {
268 if ((esp = ipmi_zalloc(ihp,
269 sizeof (ipmi_entity_sdr_t))) == NULL)
270 return (-1);
271
272 esp->ies_sdr = sdrp;
273 esp->ies_name = name;
274 ipmi_list_append(&eip->ie_sdr_list, esp);
275 }
276
277 return (0);
278 }
279
280 /*
281 * Given a SDR record, return boolean values indicating whether the sensor
282 * indicates explicit presence.
283 *
284 * XXX this should really share code with entity_present()
285 */
286 int
ipmi_entity_present_sdr(ipmi_handle_t * ihp,ipmi_sdr_t * sdrp,boolean_t * valp)287 ipmi_entity_present_sdr(ipmi_handle_t *ihp, ipmi_sdr_t *sdrp,
288 boolean_t *valp)
289 {
290 uint16_t mask;
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;
295
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;
302 break;
303
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;
309 break;
310
311 default:
312 *valp = B_FALSE;
313 return (0);
314 }
315
316 switch (reading_type) {
317 case IPMI_RT_PRESENT:
318 mask = IPMI_SR_PRESENT_ASSERT;
319 break;
320
321 case IPMI_RT_SPECIFIC:
322 switch (sensor_type) {
323 case IPMI_ST_PROCESSOR:
324 mask = IPMI_EV_PROCESSOR_PRESENT;
325 break;
326
327 case IPMI_ST_POWER_SUPPLY:
328 mask = IPMI_EV_POWER_SUPPLY_PRESENT;
329 break;
330
331 case IPMI_ST_MEMORY:
332 mask = IPMI_EV_MEMORY_PRESENT;
333 break;
334
335 case IPMI_ST_BAY:
336 mask = IPMI_EV_BAY_PRESENT;
337 break;
338
339 default:
340 *valp = B_FALSE;
341 return (0);
342 }
343 break;
344
345 default:
346 *valp = B_FALSE;
347 return (0);
348 }
349
350 /*
351 * If we've reached here, then we have a dedicated sensor that
352 * indicates presence.
353 */
354 if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
355 if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) {
356 *valp = B_FALSE;
357 return (0);
358 }
359
360 return (-1);
361 }
362
363 *valp = (srp->isr_state & mask) != 0;
364 return (0);
365 }
366
367 /*
368 * This function follows the procedure documented in section 40 of the spec.
369 * To quote the conclusion from section 40.2:
370 *
371 * Thus, the steps to detecting an Entity are:
372 *
373 * a) Scan the SDRs for sensors associated with the entity.
374 *
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.
378 *
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
382 * found.
383 *
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.
390 *
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.
395 *
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.
398 *
399 */
400 int
ipmi_entity_present(ipmi_handle_t * ihp,ipmi_entity_t * ep,boolean_t * valp)401 ipmi_entity_present(ipmi_handle_t *ihp, ipmi_entity_t *ep, boolean_t *valp)
402 {
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;
407 ipmi_sdr_t *sdrp;
408 uint16_t mask;
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;
414 char *frudata;
415
416 /*
417 * Search the sensors for a present sensor or a discrete sensor that
418 * indicates presence.
419 */
420 for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
421 esp = ipmi_list_next(esp)) {
422 sdrp = esp->ies_sdr;
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;
429 break;
430
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;
436 break;
437
438 default:
439 continue;
440 }
441
442 switch (reading_type) {
443 case IPMI_RT_PRESENT:
444 mask = IPMI_SR_PRESENT_ASSERT;
445 break;
446
447 case IPMI_RT_SPECIFIC:
448 switch (sensor_type) {
449 case IPMI_ST_PROCESSOR:
450 mask = IPMI_EV_PROCESSOR_PRESENT;
451 break;
452
453 case IPMI_ST_POWER_SUPPLY:
454 mask = IPMI_EV_POWER_SUPPLY_PRESENT;
455 break;
456
457 case IPMI_ST_MEMORY:
458 mask = IPMI_EV_MEMORY_PRESENT;
459 break;
460
461 case IPMI_ST_BAY:
462 mask = IPMI_EV_BAY_PRESENT;
463 break;
464
465 default:
466 continue;
467 }
468 break;
469
470 default:
471 continue;
472 }
473
474 /*
475 * If we've reached here, then we have a dedicated sensor that
476 * indicates presence.
477 */
478 if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
479 if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) {
480 *valp = B_FALSE;
481 return (0);
482 }
483
484 return (-1);
485 }
486
487 *valp = (srp->isr_state & mask) != 0;
488 return (0);
489 }
490
491 /*
492 * No explicit presence sensor was found. See if there is at least one
493 * active sensor associated with the entity.
494 */
495 for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
496 esp = ipmi_list_next(esp)) {
497 sdrp = esp->ies_sdr;
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;
502 break;
503
504 case IPMI_SDR_TYPE_FULL_SENSOR:
505 fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record;
506 number = fsp->is_fs_number;
507 break;
508
509 default:
510 continue;
511 }
512
513 if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
514 if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT)
515 continue;
516
517 return (-1);
518 }
519
520 if (srp->isr_scanning_enabled) {
521 *valp = B_TRUE;
522 return (0);
523 }
524 }
525
526 /*
527 * If this entity has children, then it is present if any of its
528 * children are present.
529 */
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)
533 return (-1);
534
535 if (*valp)
536 return (0);
537 }
538
539 /*
540 * If the FRU device is present, then the entity is present.
541 */
542 for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
543 esp = ipmi_list_next(esp)) {
544 sdrp = esp->ies_sdr;
545 if (sdrp->is_type != IPMI_SDR_TYPE_FRU_LOCATOR)
546 continue;
547
548 frup = (ipmi_sdr_fru_locator_t *)sdrp->is_record;
549 if (ipmi_fru_read(ihp, frup, &frudata) >= 0) {
550 ipmi_free(ihp, frudata);
551 *valp = B_TRUE;
552 return (0);
553 }
554
555 if (ipmi_errno(ihp) != EIPMI_NOT_PRESENT)
556 return (-1);
557 }
558
559 *valp = B_FALSE;
560 return (0);
561 }
562
563 static int
ipmi_entity_refresh(ipmi_handle_t * ihp)564 ipmi_entity_refresh(ipmi_handle_t *ihp)
565 {
566 if (ipmi_hash_first(ihp->ih_entities) != NULL &&
567 !ipmi_sdr_changed(ihp))
568 return (0);
569
570 if (ipmi_sdr_iter(ihp, ipmi_entity_visit, NULL) != 0)
571 return (-1);
572
573 return (0);
574 }
575
576 int
ipmi_entity_iter(ipmi_handle_t * ihp,int (* func)(ipmi_handle_t *,ipmi_entity_t *,void *),void * data)577 ipmi_entity_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
578 ipmi_entity_t *, void *), void *data)
579 {
580 ipmi_entity_impl_t *eip;
581 int ret;
582
583 if (ipmi_entity_refresh(ihp) != 0)
584 return (-1);
585
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)
589 continue;
590
591 if ((ret = func(ihp, &eip->ie_entity, data)) != 0)
592 return (ret);
593 }
594
595 return (0);
596 }
597
598 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 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 *,
601 void *), void *data)
602 {
603 /* LINTED - alignment */
604 ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
605 ipmi_entity_sdr_t *isp;
606 int ret;
607
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)
612 return (ret);
613 }
614
615 return (0);
616 }
617
618 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 ipmi_entity_iter_children(ipmi_handle_t *ihp, ipmi_entity_t *ep,
620 int (*func)(ipmi_handle_t *, ipmi_entity_t *, void *), void *data)
621 {
622 /* LINTED - alignment */
623 ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
624 ipmi_entity_impl_t *cp;
625 int ret;
626
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)
630 return (ret);
631 }
632
633 return (0);
634 }
635
636 ipmi_entity_t *
ipmi_entity_parent(ipmi_handle_t * ihp,ipmi_entity_t * ep)637 ipmi_entity_parent(ipmi_handle_t *ihp, ipmi_entity_t *ep)
638 {
639 /* LINTED - alignment */
640 ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
641
642 if (eip->ie_parent == NULL) {
643 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
644 return (NULL);
645 }
646
647 return (&eip->ie_parent->ie_entity);
648 }
649
650 ipmi_entity_t *
ipmi_entity_lookup(ipmi_handle_t * ihp,uint8_t type,uint8_t instance)651 ipmi_entity_lookup(ipmi_handle_t *ihp, uint8_t type, uint8_t instance)
652 {
653 ipmi_entity_t search;
654 ipmi_entity_impl_t *eip;
655
656 if (ipmi_entity_refresh(ihp) != 0)
657 return (NULL);
658
659 search.ie_type = type;
660 search.ie_instance = instance;
661
662 if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
663 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
664 return (NULL);
665 }
666
667 return (&eip->ie_entity);
668 }
669
670 ipmi_entity_t *
ipmi_entity_lookup_sdr(ipmi_handle_t * ihp,const char * name)671 ipmi_entity_lookup_sdr(ipmi_handle_t *ihp, const char *name)
672 {
673 ipmi_sdr_t *sdrp;
674 uint8_t id, instance;
675 boolean_t logical;
676
677 if ((sdrp = ipmi_sdr_lookup(ihp, name)) == NULL)
678 return (NULL);
679
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);
683 return (NULL);
684 }
685
686 return (ipmi_entity_lookup(ihp, id, instance));
687 }
688
689 static const void *
ipmi_entity_hash_convert(const void * p)690 ipmi_entity_hash_convert(const void *p)
691 {
692 const ipmi_entity_impl_t *eip = p;
693
694 return (&eip->ie_entity);
695 }
696
697 static ulong_t
ipmi_entity_hash_compute(const void * p)698 ipmi_entity_hash_compute(const void *p)
699 {
700 const ipmi_entity_t *ep = p;
701
702 return ((ep->ie_type << 8) | ep->ie_instance);
703 }
704
705 static int
ipmi_entity_hash_compare(const void * a,const void * b)706 ipmi_entity_hash_compare(const void *a, const void *b)
707 {
708 const ipmi_entity_t *ea = a;
709 const ipmi_entity_t *eb = b;
710
711 if (ea->ie_type == eb->ie_type &&
712 ea->ie_instance == eb->ie_instance)
713 return (0);
714 else
715 return (-1);
716 }
717
718 int
ipmi_entity_init(ipmi_handle_t * ihp)719 ipmi_entity_init(ipmi_handle_t *ihp)
720 {
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)
726 return (-1);
727
728 return (0);
729 }
730
731 void
ipmi_entity_clear(ipmi_handle_t * ihp)732 ipmi_entity_clear(ipmi_handle_t *ihp)
733 {
734 ipmi_entity_impl_t *eip;
735 ipmi_entity_sdr_t *esp;
736
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);
740 ipmi_free(ihp, esp);
741 }
742 ipmi_hash_remove(ihp->ih_entities, eip);
743 ipmi_free(ihp, eip);
744 }
745 }
746
747 void
ipmi_entity_fini(ipmi_handle_t * ihp)748 ipmi_entity_fini(ipmi_handle_t *ihp)
749 {
750 if (ihp->ih_entities != NULL) {
751 ipmi_entity_clear(ihp);
752 ipmi_hash_destroy(ihp->ih_entities);
753 }
754 }
755