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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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