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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <picl.h> 30 #include <syslog.h> 31 #include <strings.h> 32 #include <alloca.h> 33 #include <pthread.h> 34 #include <synch.h> 35 #include <limits.h> 36 #include <ctype.h> 37 #include <unistd.h> 38 #include <picltree.h> 39 #include <signal.h> 40 #include <sys/utsname.h> 41 #include <sys/systeminfo.h> 42 #include <libnvpair.h> 43 #include "fru_tag.h" 44 #include "fru_data_impl.h" 45 #include "fru_data.h" 46 #include "picld_pluginutil.h" 47 48 #pragma init(frudata_plugin_register) /* .init section */ 49 50 static void frudata_plugin_init(void); 51 static void frudata_plugin_fini(void); 52 static container_tbl_t *container_table[TABLE_SIZE]; 53 54 /* 55 * Locking Stragtegy : 56 * calling thread should hold the cont_tbl_lock during the course 57 * of container table lookup. release the cont_tbl_lock on lookup 58 * failure or on the condition wait. 59 * 60 * thread holding the container object rwlock should release lock 61 * and signal to unblock threads blocked on the condition variable 62 * upon i/o completion. 63 * 64 */ 65 66 static pthread_mutex_t cont_tbl_lock = PTHREAD_MUTEX_INITIALIZER; 67 68 static int add_row_to_table(hash_obj_t *, picl_nodehdl_t, 69 packet_t *, container_tbl_t *); 70 71 static picld_plugin_reg_t frudata_reg_info = { 72 PICLD_PLUGIN_VERSION_1, 73 PICLD_PLUGIN_NON_CRITICAL, 74 "SUNW_piclfrudata", 75 frudata_plugin_init, /* init entry point */ 76 frudata_plugin_fini /* cleanup entry point */ 77 }; 78 79 /* initialization function */ 80 static void 81 frudata_plugin_register(void) 82 { 83 /* register plugin with daemon */ 84 if (picld_plugin_register(&frudata_reg_info) != PICL_SUCCESS) { 85 syslog(LOG_ERR, "SUNW_piclfrudata plugin registration failed"); 86 } 87 } 88 89 static int 90 map_access_err(int err) 91 { 92 switch (err) { 93 case ENFILE : 94 return (PICL_PROPEXISTS); 95 case EAGAIN : 96 return (PICL_NOSPACE); 97 case EPERM : 98 return (PICL_PERMDENIED); 99 case EEXIST : 100 return (PICL_PROPEXISTS); 101 default : 102 return (PICL_FAILURE); 103 } 104 } 105 106 /* 107 * unlock_container_lock() should be always called by the thread holding the 108 * container object lock. it will signal block thread waiting on the condition 109 * variable. 110 */ 111 112 static void 113 unlock_container_lock(container_tbl_t *cont_hash) 114 { 115 (void) pthread_rwlock_unlock(&cont_hash->rwlock); 116 (void) pthread_mutex_lock(&cont_tbl_lock); 117 (void) pthread_cond_signal(&cont_hash->cond_var); 118 (void) pthread_mutex_unlock(&cont_tbl_lock); 119 } 120 121 122 /* volatile callback read routine */ 123 /* ARGSUSED */ 124 static int 125 frudata_read_callback(ptree_rarg_t *rarg, void *buf) 126 { 127 return (PICL_SUCCESS); 128 } 129 130 /* 131 * called to get hash object for specified node and object type from 132 * hash table. 133 */ 134 static container_tbl_t * 135 lookup_container_table(picl_nodehdl_t nodehdl, int object_type) 136 { 137 int index_to_hash; 138 int retval = PICL_SUCCESS; 139 container_tbl_t *first_hash; 140 container_tbl_t *next_hash; 141 picl_nodehdl_t parenthdl = 0; 142 143 switch (object_type) { 144 case SECTION_NODE: 145 retval = ptree_get_propval_by_name(nodehdl, PICL_PROP_PARENT, 146 &parenthdl, sizeof (picl_nodehdl_t)); 147 break; 148 case SEGMENT_NODE: 149 retval = ptree_get_propval_by_name(nodehdl, PICL_PROP_PARENT, 150 &parenthdl, sizeof (picl_nodehdl_t)); 151 retval = ptree_get_propval_by_name(parenthdl, PICL_PROP_PARENT, 152 &parenthdl, sizeof (picl_nodehdl_t)); 153 break; 154 case CONTAINER_NODE : 155 parenthdl = nodehdl; 156 break; 157 default : 158 return (NULL); 159 } 160 161 if (retval != PICL_SUCCESS) { 162 return (NULL); 163 } 164 165 index_to_hash = (parenthdl % TABLE_SIZE); 166 167 first_hash = container_table[index_to_hash]; 168 169 for (next_hash = first_hash; next_hash != NULL; 170 next_hash = next_hash->next) { 171 if (parenthdl == next_hash->picl_hdl) { 172 return (next_hash); 173 } 174 } 175 return (NULL); 176 } 177 178 static int 179 lock_readwrite_lock(container_tbl_t *cont_obj, int operation) 180 { 181 /* if write operation */ 182 if (operation == PICL_WRITE) { 183 return (pthread_rwlock_trywrlock(&cont_obj->rwlock)); 184 } 185 /* read operation */ 186 return (pthread_rwlock_tryrdlock(&cont_obj->rwlock)); 187 } 188 189 /* 190 * lock the container table, do lookup for the container object 191 * in the container table. if container object found try to lock 192 * the container object, if lock on container object is busy wait 193 * on condition variable till the thread holding the container 194 * object lock signal it. 195 */ 196 197 static container_tbl_t * 198 lock_container_lock(picl_nodehdl_t nodehdl, int object_type, int operation) 199 { 200 container_tbl_t *cont_obj = NULL; 201 202 (void) pthread_mutex_lock(&cont_tbl_lock); 203 204 while (((cont_obj = lookup_container_table(nodehdl, object_type)) != 205 NULL) && (lock_readwrite_lock(cont_obj, operation) == EBUSY)) { 206 pthread_cond_wait(&cont_obj->cond_var, &cont_tbl_lock); 207 } 208 209 (void) pthread_mutex_unlock(&cont_tbl_lock); 210 211 return (cont_obj); 212 } 213 214 static hash_obj_t * 215 lookup_node_object(picl_nodehdl_t nodehdl, int object_type, 216 container_tbl_t *cont_tbl) 217 { 218 int index_to_hash; 219 hash_obj_t *first_hash; 220 hash_obj_t *next_hash; 221 222 223 index_to_hash = (nodehdl % TABLE_SIZE); 224 225 first_hash = &cont_tbl->hash_obj[index_to_hash]; 226 227 for (next_hash = first_hash->next; next_hash != NULL; 228 next_hash = next_hash->next) { 229 if ((nodehdl == next_hash->picl_hdl) && 230 (object_type == next_hash->object_type)) { 231 return (next_hash); 232 } 233 } 234 return (NULL); 235 } 236 237 /* 238 * called to add newly created container hash table into container hash table. 239 * 240 */ 241 static void 242 add_tblobject_to_container_tbl(container_tbl_t *cont_tbl) 243 { 244 int cnt; 245 int index_to_hash; 246 hash_obj_t *hash_ptr; 247 248 index_to_hash = ((cont_tbl->picl_hdl) % TABLE_SIZE); 249 250 cont_tbl->next = container_table[index_to_hash]; 251 container_table[index_to_hash] = cont_tbl; 252 hash_ptr = cont_tbl->hash_obj; 253 254 /* initialize the bucket of this container hash table. */ 255 256 for (cnt = 0; cnt < TABLE_SIZE; cnt++) { 257 hash_ptr->next = NULL; 258 hash_ptr->prev = NULL; 259 hash_ptr++; 260 } 261 if (cont_tbl->next != NULL) { 262 cont_tbl->next->prev = cont_tbl; 263 } 264 } 265 266 static void 267 add_nodeobject_to_hashtable(hash_obj_t *hash_obj, container_tbl_t *cont_tbl) 268 { 269 int index_to_hash; 270 hash_obj_t *hash_table; 271 272 index_to_hash = ((hash_obj->picl_hdl) % TABLE_SIZE); 273 hash_table = &cont_tbl->hash_obj[index_to_hash]; 274 275 hash_obj->next = hash_table->next; 276 hash_table->next = hash_obj; 277 278 if (hash_obj->next != NULL) { 279 hash_obj->next->prev = hash_obj; 280 } 281 } 282 283 static container_tbl_t * 284 alloc_container_table(picl_nodehdl_t nodehdl) 285 { 286 container_tbl_t *cont_tbl; 287 288 cont_tbl = malloc(sizeof (container_tbl_t)); 289 if (cont_tbl == NULL) { 290 return (NULL); 291 } 292 293 cont_tbl->picl_hdl = nodehdl; 294 295 cont_tbl->hash_obj = malloc(sizeof (hash_obj_t[TABLE_SIZE])); 296 cont_tbl->next = NULL; 297 cont_tbl->prev = NULL; 298 299 if (cont_tbl->hash_obj == NULL) { 300 (void) free(cont_tbl); 301 return (NULL); 302 } 303 304 (void) pthread_rwlock_init(&cont_tbl->rwlock, NULL); 305 (void) pthread_cond_init(&cont_tbl->cond_var, NULL); 306 307 return (cont_tbl); 308 } 309 310 /* 311 * called to allocate container node object for container property and a 312 * container table. 313 */ 314 315 static hash_obj_t * 316 alloc_container_node_object(picl_nodehdl_t nodehdl) 317 { 318 hash_obj_t *hash_obj; 319 fru_access_hdl_t acc_hdl; 320 container_node_t *cont_node; 321 322 /* open the container (call fruaccess) */ 323 acc_hdl = fru_open_container(nodehdl); 324 if (acc_hdl == (container_hdl_t)0) { 325 return (NULL); 326 } 327 328 /* allocate container node object */ 329 cont_node = malloc(sizeof (container_node_t)); 330 if (cont_node == NULL) { 331 return (NULL); 332 } 333 334 /* allocate container hash object */ 335 hash_obj = malloc(sizeof (hash_obj_t)); 336 if (hash_obj == NULL) { 337 (void) free(cont_node); 338 return (NULL); 339 } 340 341 cont_node->cont_hdl = acc_hdl; /* fruaccess handle */ 342 cont_node->section_list = NULL; 343 hash_obj->picl_hdl = nodehdl; /* picl node handle */ 344 hash_obj->object_type = CONTAINER_NODE; 345 hash_obj->u.cont_node = cont_node; 346 hash_obj->next = NULL; 347 hash_obj->prev = NULL; 348 349 return (hash_obj); 350 } 351 352 /* 353 * called to allocate node object for section node. 354 */ 355 356 static hash_obj_t * 357 alloc_section_node_object(picl_nodehdl_t nodehdl, section_t *section) 358 { 359 hash_obj_t *hash_obj; 360 section_node_t *sec_node; 361 362 /* allocate section node object */ 363 sec_node = malloc(sizeof (section_node_t)); 364 if (sec_node == NULL) { 365 return (NULL); 366 } 367 368 /* allocate section hash object */ 369 hash_obj = malloc(sizeof (hash_obj_t)); 370 if (hash_obj == NULL) { 371 (void) free(sec_node); 372 return (NULL); 373 } 374 375 sec_node->section_hdl = section->handle; /* fruaccess hdl. */ 376 sec_node->segment_list = NULL; 377 sec_node->next = NULL; 378 sec_node->num_of_segment = -1; 379 380 hash_obj->picl_hdl = nodehdl; /* picl node handle */ 381 hash_obj->object_type = SECTION_NODE; 382 hash_obj->u.sec_node = sec_node; 383 hash_obj->next = NULL; 384 hash_obj->prev = NULL; 385 386 return (hash_obj); 387 } 388 389 /* 390 * called to allocate segment node object. 391 */ 392 393 static hash_obj_t * 394 alloc_segment_node_object(picl_nodehdl_t nodehdl, segment_t *segment) 395 { 396 hash_obj_t *hash_obj; 397 segment_node_t *seg_node; 398 399 /* allocate segment node object */ 400 seg_node = malloc(sizeof (segment_node_t)); 401 if (seg_node == NULL) { 402 return (NULL); 403 } 404 405 /* allocate segment hash object */ 406 hash_obj = malloc(sizeof (hash_obj_t)); 407 if (hash_obj == NULL) { 408 free(seg_node); 409 return (NULL); 410 } 411 412 /* fruaccess handle */ 413 seg_node->segment_hdl = segment->handle; 414 seg_node->packet_list = NULL; 415 seg_node->next = NULL; 416 seg_node->num_of_pkt = -1; 417 418 /* picl node handle */ 419 hash_obj->picl_hdl = nodehdl; 420 hash_obj->object_type = SEGMENT_NODE; 421 hash_obj->u.seg_node = seg_node; 422 hash_obj->next = NULL; 423 hash_obj->prev = NULL; 424 425 return (hash_obj); 426 } 427 428 /* 429 * called to allocate node object for packet. 430 */ 431 432 static hash_obj_t * 433 alloc_packet_node_object(picl_nodehdl_t nodehdl, packet_t *packet) 434 { 435 hash_obj_t *hash_obj; 436 packet_node_t *pkt_node; 437 438 /* allocate packet node object */ 439 pkt_node = malloc(sizeof (packet_node_t)); 440 if (pkt_node == NULL) { 441 return (NULL); 442 } 443 444 /* allocate packet hash object */ 445 hash_obj = malloc(sizeof (hash_obj_t)); 446 if (hash_obj == NULL) { 447 free(pkt_node); 448 return (NULL); 449 } 450 451 /* fruaccess handle */ 452 pkt_node->pkt_handle = packet->handle; 453 pkt_node->next = NULL; 454 455 hash_obj->picl_hdl = nodehdl; /* picl node handle */ 456 hash_obj->object_type = PACKET_NODE; 457 hash_obj->u.pkt_node = pkt_node; 458 hash_obj->next = NULL; 459 hash_obj->prev = NULL; 460 461 return (hash_obj); 462 } 463 464 /* add new section hash object to the section list */ 465 static void 466 add_to_section_list(hash_obj_t *container_hash, hash_obj_t *sect_hash) 467 { 468 hash_obj_t *next_hash; 469 470 sect_hash->u.sec_node->container_hdl = container_hash->picl_hdl; 471 if (container_hash->u.cont_node->section_list == NULL) { 472 container_hash->u.cont_node->section_list = sect_hash; 473 return; 474 } 475 476 for (next_hash = container_hash->u.cont_node->section_list; 477 next_hash->u.sec_node->next != NULL; 478 next_hash = next_hash->u.sec_node->next) { 479 ; 480 } 481 482 next_hash->u.sec_node->next = sect_hash; 483 } 484 485 /* add new segment hash object to the existing list */ 486 487 static void 488 add_to_segment_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 489 { 490 hash_obj_t *next_hash; 491 492 child_obj->u.seg_node->sec_nodehdl = parent_obj->picl_hdl; 493 if (parent_obj->u.sec_node->segment_list == NULL) { 494 parent_obj->u.sec_node->segment_list = child_obj; 495 return; 496 } 497 498 for (next_hash = parent_obj->u.sec_node->segment_list; 499 next_hash->u.seg_node->next != NULL; 500 next_hash = next_hash->u.seg_node->next) { 501 ; 502 } 503 next_hash->u.seg_node->next = child_obj; 504 } 505 506 /* 507 * called to add packet node object to the existing packet list. 508 */ 509 static void 510 add_to_packet_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 511 { 512 hash_obj_t *next_hash; 513 514 if (parent_obj->u.seg_node->packet_list == NULL) { 515 parent_obj->u.seg_node->packet_list = child_obj; 516 return; 517 } 518 519 for (next_hash = parent_obj->u.seg_node->packet_list; 520 next_hash->u.pkt_node->next != NULL; 521 next_hash = next_hash->u.pkt_node->next) { 522 ; 523 } 524 next_hash->u.pkt_node->next = child_obj; 525 } 526 527 /* 528 * free the packet hash list. 529 */ 530 531 static void 532 free_packet_list(hash_obj_t *hash_obj, container_tbl_t *cont_tbl) 533 { 534 hash_obj_t *next_obj; 535 hash_obj_t *free_obj; 536 537 /* packet hash object list */ 538 next_obj = hash_obj->u.seg_node->packet_list; 539 while (next_obj != NULL) { 540 free_obj = next_obj; 541 next_obj = next_obj->u.pkt_node->next; 542 if (free_obj->prev == NULL) { /* first node object */ 543 cont_tbl->hash_obj[(free_obj->picl_hdl % 544 TABLE_SIZE)].next = free_obj->next; 545 if (free_obj->next != NULL) { 546 free_obj->next->prev = NULL; 547 } 548 } else { 549 free_obj->prev->next = free_obj->next; 550 if (free_obj->next != NULL) { 551 free_obj->next->prev = free_obj->prev; 552 } 553 } 554 555 free(free_obj->u.pkt_node); 556 free(free_obj); 557 } 558 hash_obj->u.seg_node->packet_list = NULL; 559 } 560 561 /* 562 * free the segment hash node object. 563 */ 564 565 static void 566 free_segment_node(hash_obj_t *hash_obj, picl_nodehdl_t nodehdl, 567 container_tbl_t *cont_tbl) 568 { 569 hash_obj_t *prev_hash_obj; 570 hash_obj_t *next_obj; 571 572 /* segment hash object list */ 573 next_obj = hash_obj->u.sec_node->segment_list; 574 if (next_obj == NULL) { 575 return; 576 } 577 578 /* find the segment hash from the segment list to be deleted. */ 579 if (next_obj->picl_hdl == nodehdl) { 580 hash_obj->u.sec_node->segment_list = 581 next_obj->u.seg_node->next; 582 } else { 583 while (next_obj != NULL) { 584 if (next_obj->picl_hdl != nodehdl) { 585 prev_hash_obj = next_obj; 586 next_obj = next_obj->u.seg_node->next; 587 } else { 588 prev_hash_obj->u.seg_node->next = 589 next_obj->u.seg_node->next; 590 break; 591 } 592 } 593 594 if (next_obj == NULL) { 595 return; 596 } 597 598 } 599 600 if (next_obj->prev == NULL) { 601 cont_tbl->hash_obj[(next_obj->picl_hdl % TABLE_SIZE)].next = 602 next_obj->next; 603 if (next_obj->next != NULL) 604 next_obj->next->prev = NULL; 605 } else { 606 next_obj->prev->next = next_obj->next; 607 if (next_obj->next != NULL) { 608 next_obj->next->prev = next_obj->prev; 609 } 610 } 611 612 free_packet_list(next_obj, cont_tbl); 613 free(next_obj->u.seg_node); 614 free(next_obj); 615 } 616 617 618 /* 619 * Description : frudata_delete_segment is called when volatile property 620 * delete_segment under class segment is accessed. 621 * 622 * Arguments : ptree_warg_t is holds node handle of segment node and property 623 * handle of delete_segment property. 624 */ 625 626 /* ARGSUSED */ 627 static int 628 frudata_delete_segment(ptree_warg_t *warg, const void *buf) 629 { 630 int retval; 631 int num_of_segment; 632 int num_of_pkt; 633 int pkt_cnt; 634 int count; 635 packet_t *pkt_buf; 636 segment_t *seg_buffer; 637 hash_obj_t *seg_hash; 638 hash_obj_t *pkt_hash; 639 hash_obj_t *hash_obj; 640 fru_segdesc_t *desc; 641 picl_nodehdl_t sec_nodehdl; 642 container_tbl_t *cont_tbl; 643 fru_access_hdl_t seg_acc_hdl; 644 fru_access_hdl_t new_sec_acc_hdl; 645 646 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE); 647 if (!cont_tbl) { 648 return (PICL_FAILURE); 649 } 650 651 /* segment hash */ 652 hash_obj = lookup_node_object(warg->nodeh, SEGMENT_NODE, cont_tbl); 653 if (hash_obj == NULL) { 654 unlock_container_lock(cont_tbl); 655 return (PICL_FAILURE); 656 } 657 658 /* fruaccess segment handle */ 659 seg_acc_hdl = hash_obj->u.seg_node->segment_hdl; 660 661 /* call fruaccess to get new section handle */ 662 if (fru_delete_segment(seg_acc_hdl, &new_sec_acc_hdl, &warg->cred) 663 == -1) { 664 unlock_container_lock(cont_tbl); 665 return (map_access_err(errno)); 666 } 667 668 if (ptree_delete_node(warg->nodeh) != PICL_SUCCESS) { 669 unlock_container_lock(cont_tbl); 670 return (PICL_FAILURE); 671 } 672 673 if (ptree_destroy_node(warg->nodeh) != PICL_SUCCESS) { 674 unlock_container_lock(cont_tbl); 675 return (PICL_FAILURE); 676 } 677 678 679 /* get section node handle */ 680 sec_nodehdl = hash_obj->u.seg_node->sec_nodehdl; 681 /* get section hash */ 682 hash_obj = lookup_node_object(sec_nodehdl, SECTION_NODE, cont_tbl); 683 if (hash_obj == NULL) { 684 unlock_container_lock(cont_tbl); 685 return (PICL_FAILURE); 686 } 687 688 free_segment_node(hash_obj, warg->nodeh, cont_tbl); 689 690 hash_obj->u.sec_node->num_of_segment = 0; 691 692 /* call fruaccess with new section handle */ 693 num_of_segment = fru_get_num_segments(new_sec_acc_hdl, &warg->cred); 694 if (num_of_segment <= 0) { 695 unlock_container_lock(cont_tbl); 696 return (PICL_SUCCESS); 697 } 698 699 seg_buffer = alloca(sizeof (segment_t) * num_of_segment); 700 if (seg_buffer == NULL) { 701 unlock_container_lock(cont_tbl); 702 return (PICL_FAILURE); 703 } 704 705 /* get all the segments */ 706 retval = fru_get_segments(new_sec_acc_hdl, seg_buffer, 707 num_of_segment, &warg->cred); 708 if (retval == -1) { 709 unlock_container_lock(cont_tbl); 710 return (PICL_FAILURE); 711 } 712 713 seg_hash = hash_obj->u.sec_node->segment_list; 714 if (seg_hash == NULL) { 715 unlock_container_lock(cont_tbl); 716 return (PICL_SUCCESS); 717 } 718 719 /* rebuild the segment list */ 720 for (count = 0; count < num_of_segment; count++) { 721 desc = (fru_segdesc_t *)&seg_buffer[count].descriptor; 722 if (!(desc->field.field_perm & SEGMENT_READ)) { 723 seg_hash = seg_hash->u.seg_node->next; 724 continue; 725 } 726 727 if (desc->field.opaque) { 728 seg_hash = seg_hash->u.seg_node->next; 729 continue; 730 } 731 732 hash_obj->u.sec_node->num_of_segment++; 733 734 seg_hash->u.seg_node->segment_hdl = seg_buffer[count].handle; 735 736 num_of_pkt = 737 fru_get_num_packets(seg_buffer[count].handle, 738 &warg->cred); 739 if (num_of_pkt <= 0) { 740 seg_hash = seg_hash->u.seg_node->next; 741 continue; 742 } 743 744 pkt_buf = alloca(sizeof (packet_t) * num_of_pkt); 745 if (pkt_buf == NULL) { 746 unlock_container_lock(cont_tbl); 747 return (PICL_FAILURE); 748 } 749 750 retval = fru_get_packets(seg_buffer[count].handle, pkt_buf, 751 num_of_pkt, &warg->cred); 752 if (retval == -1) { 753 seg_hash = seg_hash->u.seg_node->next; 754 continue; 755 } 756 757 pkt_hash = seg_hash->u.seg_node->packet_list; 758 if (pkt_hash == NULL) { 759 seg_hash = seg_hash->u.seg_node->next; 760 continue; 761 } 762 763 /* rebuild the packet list */ 764 for (pkt_cnt = 0; pkt_cnt < num_of_pkt; pkt_cnt++) { 765 pkt_hash->u.pkt_node->pkt_handle = 766 pkt_buf[pkt_cnt].handle; 767 pkt_hash = pkt_hash->u.pkt_node->next; 768 } 769 770 seg_hash = seg_hash->u.seg_node->next; 771 if (seg_hash == NULL) { 772 break; 773 } 774 } 775 776 /* updated with new section handle */ 777 hash_obj->u.sec_node->section_hdl = new_sec_acc_hdl; 778 779 unlock_container_lock(cont_tbl); 780 781 return (PICL_SUCCESS); 782 } 783 784 /* 785 * Description : frudata_read_payload is called when volatile property 786 * payload is read. 787 * 788 * Arguments : ptree_rarg_t holds node handle of the table property. 789 * and property handle of the payload cell. 790 * p_buf contains payload data when function returns. 791 * 792 * Returns : PICL_SUCCESS on success. 793 * PICL_FAILURE on failure. 794 */ 795 796 static int 797 frudata_read_payload(ptree_rarg_t *rarg, void *buf) 798 { 799 int num_bytes; 800 hash_obj_t *hash_obj; 801 fru_access_hdl_t pkt_acc_hdl; 802 container_tbl_t *cont_tbl; 803 804 805 cont_tbl = lock_container_lock(rarg->nodeh, SEGMENT_NODE, PICL_READ); 806 if (!cont_tbl) { 807 return (PICL_FAILURE); 808 } 809 810 hash_obj = lookup_node_object(rarg->proph, PACKET_NODE, cont_tbl); 811 if (hash_obj == NULL) { 812 unlock_container_lock(cont_tbl); 813 return (PICL_FAILURE); 814 } 815 816 pkt_acc_hdl = hash_obj->u.pkt_node->pkt_handle; 817 818 num_bytes = fru_get_payload(pkt_acc_hdl, buf, 819 hash_obj->u.pkt_node->paylen, &rarg->cred); 820 if (num_bytes != hash_obj->u.pkt_node->paylen) { 821 unlock_container_lock(cont_tbl); 822 return (PICL_FAILURE); 823 } 824 825 unlock_container_lock(cont_tbl); 826 827 return (PICL_SUCCESS); 828 } 829 830 /* 831 * Description : frudata_write_payload is called when payload property cell 832 * is accessed. 833 * 834 * Arguments : ptree_warg_t holds node handle of the packet-table. 835 * and property handle of the payload cell. 836 * p_buf contains payload data. 837 * 838 * Returns : PICL_SUCCESS on success. 839 * 840 */ 841 842 static int 843 frudata_write_payload(ptree_warg_t *warg, const void *buf) 844 { 845 int retval; 846 hash_obj_t *hash_obj; 847 fru_access_hdl_t pkt_acc_hdl; 848 container_tbl_t *cont_tbl; 849 850 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE); 851 if (!cont_tbl) { 852 return (PICL_FAILURE); 853 } 854 855 hash_obj = lookup_node_object(warg->proph, PACKET_NODE, cont_tbl); 856 if (hash_obj == NULL) { 857 unlock_container_lock(cont_tbl); 858 return (PICL_FAILURE); 859 } 860 861 pkt_acc_hdl = hash_obj->u.pkt_node->pkt_handle; 862 863 retval = fru_update_payload(pkt_acc_hdl, buf, 864 hash_obj->u.pkt_node->paylen, 865 &pkt_acc_hdl, &warg->cred); 866 if (retval == -1) { 867 unlock_container_lock(cont_tbl); 868 return (map_access_err(errno)); 869 } 870 871 hash_obj->u.pkt_node->pkt_handle = pkt_acc_hdl; 872 873 unlock_container_lock(cont_tbl); 874 875 return (PICL_SUCCESS); 876 } 877 878 /* 879 * callback volatile function is called when tag volatile property 880 * is accessed. this routine holds a read lock over the hash table 881 * and do a lookup over the property handle i.e property handle of 882 * the tag property passed in rarg parameter. 883 * tag value is copied into the buffer (void *buf). 884 */ 885 886 static int 887 frudata_read_tag(ptree_rarg_t *rarg, void *buf) 888 { 889 int retval; 890 hash_obj_t *hash_obj; 891 picl_prophdl_t rowproph; 892 container_tbl_t *cont_tbl; 893 894 cont_tbl = lock_container_lock(rarg->nodeh, SEGMENT_NODE, PICL_READ); 895 if (!cont_tbl) { 896 return (PICL_FAILURE); 897 } 898 899 retval = ptree_get_next_by_row(rarg->proph, &rowproph); 900 if (retval != PICL_SUCCESS) { 901 unlock_container_lock(cont_tbl); 902 return (retval); 903 } 904 905 hash_obj = lookup_node_object(rowproph, PACKET_NODE, cont_tbl); 906 if (hash_obj == NULL) { 907 unlock_container_lock(cont_tbl); 908 return (PICL_FAILURE); 909 } 910 911 (void) memcpy(buf, &hash_obj->u.pkt_node->tag, sizeof (tag_t)); 912 913 unlock_container_lock(cont_tbl); 914 return (PICL_SUCCESS); 915 } 916 917 918 /* 919 * Description : create_packet_table() is called by fru_delete_packet_row(), 920 * to create a packet-table volatile property. it's called after 921 * deleting the packet-table. fru_delete_packet_row() calls 922 * frudata_read_packet_table() to add rows into the table. 923 */ 924 925 static int 926 create_packet_table(picl_nodehdl_t seghdl, picl_prophdl_t *thdl) 927 { 928 int retval; 929 picl_prophdl_t tblhdl; 930 picl_nodehdl_t prophdl; 931 ptree_propinfo_t prop; 932 933 retval = ptree_create_table(&tblhdl); 934 if (retval != PICL_SUCCESS) { 935 return (retval); 936 } 937 938 prop.version = PTREE_PROPINFO_VERSION; 939 prop.piclinfo.type = PICL_PTYPE_TABLE; 940 prop.piclinfo.accessmode = PICL_READ|PICL_WRITE; 941 prop.piclinfo.size = sizeof (picl_prophdl_t); 942 prop.read = NULL; 943 prop.write = NULL; 944 (void) strcpy(prop.piclinfo.name, PICL_PROP_PACKET_TABLE); 945 946 retval = ptree_create_and_add_prop(seghdl, &prop, &tblhdl, 947 &prophdl); 948 if (retval != PICL_SUCCESS) { 949 return (retval); 950 } 951 952 /* hold the table handle */ 953 *thdl = tblhdl; 954 955 return (PICL_SUCCESS); 956 } 957 958 /* 959 * Description : frudata_delete_packet is called when write operation is 960 * performed on tag volatile property. 961 * 962 * 963 * Arguments : ptree_warg_t holds node handle to the segment node. 964 * and property handle of the tag cell in the packet table to be 965 * deleted. 966 * buf contains the tag data + plus DELETE_KEY_TAG 967 * 968 * Returns : PICL_SUCCESS on success 969 * 970 */ 971 972 static int 973 frudata_delete_packet(ptree_warg_t *warg, const void *buf) 974 { 975 int count = 0; 976 int retval; 977 int num_of_pkt; 978 uint64_t tag; 979 packet_t *packet; 980 hash_obj_t *seg_hash_obj; 981 hash_obj_t *pkt_hash_obj; 982 container_tbl_t *cont_tbl; 983 picl_prophdl_t tblhdl; 984 picl_prophdl_t rowproph; 985 fru_access_hdl_t new_seg_acc_hdl; 986 987 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE); 988 if (!cont_tbl) { 989 return (PICL_FAILURE); 990 } 991 992 /* get the payload property handle */ 993 retval = ptree_get_next_by_row(warg->proph, &rowproph); 994 if (retval != PICL_SUCCESS) { 995 unlock_container_lock(cont_tbl); 996 return (retval); 997 } 998 999 /* do lookup on payload property handle */ 1000 pkt_hash_obj = lookup_node_object(rowproph, PACKET_NODE, cont_tbl); 1001 if (pkt_hash_obj == NULL) { 1002 unlock_container_lock(cont_tbl); 1003 return (PICL_FAILURE); 1004 } 1005 1006 /* verify the tag */ 1007 tag = pkt_hash_obj->u.pkt_node->tag.raw_data; 1008 tag &= FRUDATA_DELETE_TAG_MASK; 1009 tag |= FRUDATA_DELETE_TAG_KEY; 1010 if (*(uint64_t *)buf != tag) { 1011 unlock_container_lock(cont_tbl); 1012 return (PICL_FAILURE); 1013 } 1014 1015 /* call fruaccess module */ 1016 retval = fru_delete_packet(pkt_hash_obj->u.pkt_node->pkt_handle, 1017 &new_seg_acc_hdl, &warg->cred); 1018 if (retval == -1) { 1019 unlock_container_lock(cont_tbl); 1020 return (map_access_err(errno)); 1021 } 1022 1023 /* delete the packet table */ 1024 retval = ptree_get_prop_by_name(warg->nodeh, PICL_PROP_PACKET_TABLE, 1025 &tblhdl); 1026 if (retval != PICL_SUCCESS) { 1027 unlock_container_lock(cont_tbl); 1028 return (retval); 1029 } 1030 1031 retval = ptree_delete_prop(tblhdl); 1032 if (retval != PICL_SUCCESS) { 1033 unlock_container_lock(cont_tbl); 1034 return (retval); 1035 } 1036 1037 retval = ptree_destroy_prop(tblhdl); 1038 if (retval != PICL_SUCCESS) { 1039 unlock_container_lock(cont_tbl); 1040 return (retval); 1041 } 1042 1043 1044 seg_hash_obj = lookup_node_object(warg->nodeh, SEGMENT_NODE, 1045 cont_tbl); 1046 if (seg_hash_obj == NULL) { 1047 unlock_container_lock(cont_tbl); 1048 return (PICL_FAILURE); 1049 } 1050 1051 /* free all packet hash object */ 1052 free_packet_list(seg_hash_obj, cont_tbl); 1053 1054 /* recreate the packet table */ 1055 retval = create_packet_table(warg->nodeh, &tblhdl); 1056 if (retval != PICL_SUCCESS) { 1057 unlock_container_lock(cont_tbl); 1058 return (retval); 1059 } 1060 1061 seg_hash_obj->u.seg_node->segment_hdl = new_seg_acc_hdl; 1062 1063 seg_hash_obj->u.seg_node->num_of_pkt = 0; 1064 1065 num_of_pkt = fru_get_num_packets(new_seg_acc_hdl, &warg->cred); 1066 if (num_of_pkt == -1) { 1067 unlock_container_lock(cont_tbl); 1068 return (PICL_FAILURE); 1069 } 1070 1071 if (num_of_pkt == 0) { 1072 unlock_container_lock(cont_tbl); 1073 return (PICL_SUCCESS); 1074 } 1075 1076 packet = alloca(sizeof (packet_t) * num_of_pkt); 1077 if (packet == NULL) { 1078 unlock_container_lock(cont_tbl); 1079 return (PICL_FAILURE); 1080 } 1081 1082 retval = fru_get_packets(new_seg_acc_hdl, packet, 1083 num_of_pkt, &warg->cred); 1084 if (retval == -1) { 1085 unlock_container_lock(cont_tbl); 1086 return (PICL_FAILURE); 1087 } 1088 1089 /* rebuild the packet hash object */ 1090 for (count = 0; count < num_of_pkt; count++) { 1091 (void) add_row_to_table(seg_hash_obj, tblhdl, packet+count, 1092 cont_tbl); 1093 } 1094 1095 seg_hash_obj->u.seg_node->num_of_pkt = num_of_pkt; 1096 1097 (void) ptree_update_propval_by_name(warg->nodeh, PICL_PROP_NUM_TAGS, 1098 &num_of_pkt, sizeof (uint32_t)); 1099 1100 unlock_container_lock(cont_tbl); 1101 1102 return (PICL_SUCCESS); 1103 } 1104 1105 /* 1106 * called from frudata_delete_packet(), frudata_add_packet(), 1107 * frudata_read_packet() callback routine to add packet into 1108 * the packet table. it also create hash node object for each 1109 * individual packet and add the object to the packet list. 1110 */ 1111 1112 static int 1113 add_row_to_table(hash_obj_t *seg_obj, picl_nodehdl_t tblhdl, packet_t *pkt, 1114 container_tbl_t *cont_tbl) 1115 { 1116 int retval; 1117 int paylen; 1118 size_t tag_size; 1119 hash_obj_t *hash_obj; 1120 fru_tagtype_t tagtype; 1121 picl_prophdl_t prophdl[NUM_OF_COL_IN_PKT_TABLE]; 1122 ptree_propinfo_t prop; 1123 1124 prop.version = PTREE_PROPINFO_VERSION; 1125 1126 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY; 1127 prop.piclinfo.accessmode = PICL_READ|PICL_WRITE|PICL_VOLATILE; 1128 prop.piclinfo.size = sizeof (fru_tag_t); 1129 prop.read = frudata_read_tag; 1130 prop.write = frudata_delete_packet; 1131 1132 /* tag property node */ 1133 (void) strcpy(prop.piclinfo.name, PICL_PROP_TAG); 1134 1135 paylen = get_payload_length((void *)&pkt->tag); 1136 if (paylen < 0) { 1137 return (PICL_FAILURE); 1138 } 1139 1140 retval = ptree_create_prop(&prop, NULL, &prophdl[0]); 1141 if (retval != PICL_SUCCESS) { 1142 return (retval); 1143 } 1144 1145 1146 /* payload property node */ 1147 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY; 1148 prop.piclinfo.size = paylen; 1149 (void) strcpy(prop.piclinfo.name, PICL_PROP_PAYLOAD); 1150 prop.piclinfo.accessmode = PICL_READ|PICL_WRITE|PICL_VOLATILE; 1151 prop.read = frudata_read_payload; 1152 prop.write = frudata_write_payload; 1153 1154 retval = ptree_create_prop(&prop, NULL, &prophdl[1]); 1155 if (retval != PICL_SUCCESS) { 1156 return (retval); 1157 } 1158 1159 hash_obj = alloc_packet_node_object(prophdl[1], pkt); 1160 if (hash_obj == NULL) { 1161 return (PICL_FAILURE); 1162 } 1163 1164 retval = ptree_add_row_to_table(tblhdl, NUM_OF_COL_IN_PKT_TABLE, 1165 prophdl); 1166 if (retval != PICL_SUCCESS) { 1167 free(hash_obj); 1168 return (retval); 1169 } 1170 1171 tagtype = get_tag_type((fru_tag_t *)&pkt->tag); 1172 if (tagtype == -1) { 1173 return (PICL_FAILURE); 1174 } 1175 1176 tag_size = get_tag_size(tagtype); 1177 if (tag_size == (size_t)-1) { 1178 return (PICL_FAILURE); 1179 } 1180 1181 hash_obj->u.pkt_node->paylen = paylen; 1182 hash_obj->u.pkt_node->tag.raw_data = 0; 1183 (void) memcpy(&hash_obj->u.pkt_node->tag, &pkt->tag, tag_size); 1184 1185 add_nodeobject_to_hashtable(hash_obj, cont_tbl); 1186 1187 add_to_packet_list(seg_obj, hash_obj); 1188 1189 return (PICL_SUCCESS); 1190 } 1191 1192 /* 1193 * called from frudata_read_segment() callback routine. it's called after 1194 * creating the packet table under class segment. this routine reads the 1195 * segment data to get total number of packets in the segments and add 1196 * the tag and payload data into the table. it calls add_row_to_table 1197 * routine to add individual row into the packet table. 1198 */ 1199 1200 static int 1201 frudata_read_packet(picl_nodehdl_t nodeh, picl_prophdl_t *tblhdl, 1202 container_tbl_t *cont_tbl, door_cred_t *cred) 1203 { 1204 int cnt; 1205 int retval; 1206 int num_of_pkt; 1207 packet_t *packet; 1208 hash_obj_t *hash_obj; 1209 fru_access_hdl_t seg_acc_hdl; 1210 1211 hash_obj = lookup_node_object(nodeh, SEGMENT_NODE, cont_tbl); 1212 if (hash_obj == NULL) { 1213 return (PICL_FAILURE); 1214 } 1215 1216 if (hash_obj->u.seg_node->num_of_pkt == -1) { 1217 /* get the access handle */ 1218 seg_acc_hdl = hash_obj->u.seg_node->segment_hdl; 1219 /* get total number of packets */ 1220 num_of_pkt = fru_get_num_packets(seg_acc_hdl, cred); 1221 if (num_of_pkt < 0) { 1222 hash_obj->u.seg_node->num_of_pkt = 0; 1223 return (map_access_err(errno)); 1224 } 1225 1226 if (num_of_pkt == 0) { 1227 hash_obj->u.seg_node->num_of_pkt = 0; 1228 return (0); 1229 } 1230 1231 /* allocate buffer */ 1232 packet = alloca(sizeof (packet_t) * num_of_pkt); 1233 if (packet == NULL) { 1234 hash_obj->u.seg_node->num_of_pkt = 0; 1235 return (0); 1236 } 1237 1238 /* get all the packet into the packet buffer */ 1239 retval = fru_get_packets(seg_acc_hdl, packet, num_of_pkt, cred); 1240 if (retval == -1) { 1241 return (0); 1242 } 1243 1244 /* add payload and tag into the table. */ 1245 for (cnt = 0; cnt < num_of_pkt; cnt++) { 1246 (void) add_row_to_table(hash_obj, *tblhdl, packet+cnt, 1247 cont_tbl); 1248 } 1249 1250 hash_obj->u.seg_node->num_of_pkt = num_of_pkt; 1251 } 1252 return (0); 1253 } 1254 1255 1256 /* 1257 * Description : frudata_add_packet is called when add-packet volatile 1258 * property is accessed. 1259 * 1260 * Arguments : ptree_warg_t holds node handle of the segment node and 1261 * property handle of add-packet property. 1262 * p_buf- contains packet data to be added. 1263 * 1264 * Return : PICL_SUCCESS on success. 1265 * 1266 */ 1267 1268 /* ARGSUSED */ 1269 static int 1270 frudata_add_packet(ptree_warg_t *warg, const void *buf) 1271 { 1272 size_t tag_size; 1273 int paylen; 1274 int retval; 1275 int num_of_pkt; 1276 int cnt; 1277 packet_t packet; 1278 packet_t *pkt_buf; 1279 hash_obj_t *hash_obj; 1280 hash_obj_t *pkt_hash; 1281 container_tbl_t *cont_tbl; 1282 fru_tagtype_t tagtype; 1283 picl_prophdl_t tblhdl; 1284 fru_access_hdl_t seg_acc_hdl; 1285 fru_access_hdl_t new_seg_acc_hdl; 1286 1287 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE); 1288 if (!cont_tbl) { 1289 return (PICL_FAILURE); 1290 } 1291 1292 hash_obj = lookup_node_object(warg->nodeh, SEGMENT_NODE, cont_tbl); 1293 if (hash_obj == NULL) { 1294 unlock_container_lock(cont_tbl); 1295 return (PICL_FAILURE); 1296 } 1297 1298 seg_acc_hdl = hash_obj->u.seg_node->segment_hdl; 1299 1300 tagtype = get_tag_type((void *)buf); 1301 if (tagtype == -1) { 1302 unlock_container_lock(cont_tbl); 1303 return (PICL_FAILURE); 1304 } 1305 1306 tag_size = get_tag_size(tagtype); 1307 if (tag_size == (size_t)-1) { 1308 unlock_container_lock(cont_tbl); 1309 return (PICL_FAILURE); 1310 } 1311 1312 paylen = get_payload_length((void *)buf); 1313 if (paylen == -1) { 1314 unlock_container_lock(cont_tbl); 1315 return (PICL_FAILURE); 1316 } 1317 1318 packet.tag = 0; 1319 (void) memcpy(&packet.tag, buf, tag_size); 1320 1321 retval = fru_append_packet(seg_acc_hdl, &packet, (char *)buf + tag_size, 1322 paylen, &new_seg_acc_hdl, &warg->cred); 1323 if (retval == -1) { 1324 unlock_container_lock(cont_tbl); 1325 return (map_access_err(errno)); 1326 } 1327 1328 retval = ptree_get_propval_by_name(warg->nodeh, 1329 PICL_PROP_PACKET_TABLE, &tblhdl, sizeof (picl_prophdl_t)); 1330 if (retval != PICL_SUCCESS) { 1331 unlock_container_lock(cont_tbl); 1332 return (retval); 1333 } 1334 retval = add_row_to_table(hash_obj, tblhdl, &packet, cont_tbl); 1335 if (retval != PICL_SUCCESS) { 1336 unlock_container_lock(cont_tbl); 1337 return (retval); 1338 } 1339 1340 num_of_pkt = fru_get_num_packets(new_seg_acc_hdl, &warg->cred); 1341 if (num_of_pkt == -1) { 1342 unlock_container_lock(cont_tbl); 1343 return (PICL_FAILURE); 1344 } 1345 1346 pkt_buf = alloca(sizeof (packet_t) * num_of_pkt); 1347 if (pkt_buf == NULL) { 1348 unlock_container_lock(cont_tbl); 1349 return (PICL_FAILURE); 1350 } 1351 1352 retval = fru_get_packets(new_seg_acc_hdl, pkt_buf, 1353 num_of_pkt, &warg->cred); 1354 if (retval == -1) { 1355 unlock_container_lock(cont_tbl); 1356 return (PICL_FAILURE); 1357 } 1358 1359 pkt_hash = hash_obj->u.seg_node->packet_list; 1360 if (pkt_hash == NULL) { 1361 unlock_container_lock(cont_tbl); 1362 return (PICL_FAILURE); 1363 } 1364 1365 for (cnt = 0; cnt < num_of_pkt; cnt++) { 1366 pkt_hash->u.pkt_node->pkt_handle = pkt_buf[cnt].handle; 1367 pkt_hash = pkt_hash->u.pkt_node->next; 1368 } 1369 1370 hash_obj->u.seg_node->num_of_pkt = num_of_pkt; 1371 1372 (void) ptree_update_propval_by_name(warg->nodeh, PICL_PROP_NUM_TAGS, 1373 &num_of_pkt, sizeof (uint32_t)); 1374 1375 unlock_container_lock(cont_tbl); 1376 1377 return (PICL_SUCCESS); 1378 } 1379 1380 static void 1381 freeup(picl_nodehdl_t nodeh) 1382 { 1383 (void) ptree_delete_node(nodeh); 1384 (void) ptree_destroy_node(nodeh); 1385 } 1386 1387 /* 1388 * called by frudata_read_segment() and fru_data_add_segment() callback routine. 1389 * it's called to create a segment node and all it's property beneith the 1390 * segment node in the picl tree. 1391 */ 1392 1393 static int 1394 create_segment_node(hash_obj_t *sec_obj, picl_nodehdl_t sec_node, 1395 segment_t *segment, container_tbl_t *cont_tbl, door_cred_t *cred) 1396 { 1397 1398 int retval; 1399 char segname[SEG_NAME_LEN + 1]; 1400 uint32_t numoftags = 0; 1401 uint32_t protection; 1402 hash_obj_t *hash_obj; 1403 picl_nodehdl_t nodehdl; 1404 picl_prophdl_t prophdl; 1405 picl_nodehdl_t tblhdl; 1406 ptree_propinfo_t prop; 1407 1408 (void) strlcpy(segname, segment->name, SEG_NAME_LEN + 1); 1409 segname[SEG_NAME_LEN] = '\0'; 1410 1411 if (!(isprint(segname[0]) || isprint(segname[1]))) { 1412 return (PICL_FAILURE); 1413 } 1414 1415 if (ptree_create_node(segname, PICL_CLASS_SEGMENT, &nodehdl) 1416 != PICL_SUCCESS) { 1417 return (PICL_FAILURE); 1418 } 1419 1420 1421 /* create property node */ 1422 prop.version = PTREE_PROPINFO_VERSION; 1423 prop.piclinfo.accessmode = PICL_READ; 1424 prop.read = NULL; 1425 prop.write = NULL; 1426 1427 prop.piclinfo.type = PICL_PTYPE_UNSIGNED_INT; 1428 prop.piclinfo.size = sizeof (uint32_t); 1429 1430 /* descriptor property */ 1431 (void) strcpy(prop.piclinfo.name, PICL_PROP_DESCRIPTOR); 1432 if (ptree_create_and_add_prop(nodehdl, &prop, &segment->descriptor, 1433 &prophdl) != PICL_SUCCESS) { 1434 freeup(nodehdl); 1435 return (PICL_FAILURE); 1436 } 1437 1438 1439 /* offset property */ 1440 (void) strcpy(prop.piclinfo.name, PICL_PROP_OFFSET); 1441 if (ptree_create_and_add_prop(nodehdl, &prop, &segment->offset, 1442 &prophdl) != PICL_SUCCESS) { 1443 freeup(nodehdl); 1444 return (PICL_FAILURE); 1445 } 1446 1447 1448 /* length property */ 1449 (void) strcpy(prop.piclinfo.name, PICL_PROP_LENGTH); 1450 if (ptree_create_and_add_prop(nodehdl, &prop, &segment->length, 1451 &prophdl) != PICL_SUCCESS) { 1452 freeup(nodehdl); 1453 return (PICL_FAILURE); 1454 } 1455 1456 /* Number of Tags */ 1457 (void) strcpy(prop.piclinfo.name, PICL_PROP_NUM_TAGS); 1458 if (ptree_create_and_add_prop(nodehdl, &prop, &numoftags, &prophdl) 1459 != PICL_SUCCESS) { 1460 freeup(nodehdl); 1461 return (PICL_FAILURE); 1462 } 1463 1464 if (create_packet_table(nodehdl, &tblhdl) != PICL_SUCCESS) { 1465 freeup(nodehdl); 1466 return (PICL_FAILURE); 1467 } 1468 1469 retval = ptree_get_propval_by_name(sec_node, 1470 PICL_PROP_PROTECTED, &protection, sizeof (uint32_t)); 1471 if (retval != PICL_SUCCESS) { 1472 freeup(nodehdl); 1473 return (PICL_FAILURE); 1474 } 1475 1476 if (protection == 0) { /* to be added only read/write section */ 1477 /* delete segment volatile property */ 1478 prop.piclinfo.type = PICL_PTYPE_UNSIGNED_INT; 1479 prop.piclinfo.size = sizeof (uint32_t); 1480 prop.piclinfo.accessmode = PICL_WRITE|PICL_VOLATILE; 1481 prop.write = frudata_delete_segment; 1482 prop.read = frudata_read_callback; 1483 1484 (void) strcpy(prop.piclinfo.name, PICL_PROP_DELETE_SEGMENT); 1485 if (ptree_create_and_add_prop(nodehdl, &prop, NULL, &prophdl) 1486 != PICL_SUCCESS) { 1487 freeup(nodehdl); 1488 return (PICL_FAILURE); 1489 } 1490 1491 1492 /* add packet volatile property */ 1493 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY; 1494 prop.piclinfo.size = segment->length; /* segment length */ 1495 prop.piclinfo.accessmode = PICL_READ|PICL_WRITE|PICL_VOLATILE; 1496 prop.read = frudata_read_callback; 1497 prop.write = frudata_add_packet; 1498 1499 (void) strcpy(prop.piclinfo.name, PICL_PROP_ADD_PACKET); 1500 if (ptree_create_and_add_prop(nodehdl, &prop, NULL, &prophdl) 1501 != PICL_SUCCESS) { 1502 freeup(nodehdl); 1503 return (PICL_FAILURE); 1504 } 1505 } 1506 1507 if (ptree_add_node(sec_node, nodehdl) != PICL_SUCCESS) { 1508 freeup(nodehdl); 1509 return (PICL_FAILURE); 1510 } 1511 1512 hash_obj = alloc_segment_node_object(nodehdl, segment); 1513 if (hash_obj == NULL) { 1514 freeup(nodehdl); 1515 return (PICL_FAILURE); 1516 } 1517 1518 add_nodeobject_to_hashtable(hash_obj, cont_tbl); 1519 1520 add_to_segment_list(sec_obj, hash_obj); 1521 1522 retval = frudata_read_packet(nodehdl, &tblhdl, cont_tbl, cred); 1523 if (retval != 0) { 1524 return (PICL_SUCCESS); 1525 } 1526 1527 (void) ptree_update_propval_by_name(nodehdl, PICL_PROP_NUM_TAGS, 1528 &hash_obj->u.seg_node->num_of_pkt, sizeof (uint32_t)); 1529 1530 return (PICL_SUCCESS); 1531 } 1532 1533 /* 1534 * Description :frudata_read_segment is called when num_segment volatile 1535 * property is accessed. 1536 * 1537 * Arguments : ptree_rarg_t contains node handle of the section node. 1538 * and property node of num_segments. 1539 * void * will hold number of segment. 1540 * 1541 * Returns : PICL_SUCCESS on success. 1542 * PICL_FAILURE on failure. 1543 */ 1544 1545 static int 1546 frudata_read_segment(ptree_rarg_t *rarg, void *buf) 1547 { 1548 int num_of_segment; 1549 int cnt; 1550 int retval; 1551 segment_t *segment; 1552 hash_obj_t *hash_obj; 1553 fru_segdesc_t *desc; 1554 fru_access_hdl_t sec_acc_hdl; 1555 container_tbl_t *cont_tbl; 1556 1557 cont_tbl = lock_container_lock(rarg->nodeh, SECTION_NODE, PICL_READ); 1558 if (!cont_tbl) { 1559 return (PICL_FAILURE); 1560 } 1561 1562 hash_obj = lookup_node_object(rarg->nodeh, SECTION_NODE, cont_tbl); 1563 if (hash_obj == NULL) { 1564 unlock_container_lock(cont_tbl); 1565 return (PICL_FAILURE); 1566 } 1567 1568 if (hash_obj->u.sec_node->num_of_segment == -1) { 1569 sec_acc_hdl = hash_obj->u.sec_node->section_hdl; 1570 1571 hash_obj->u.sec_node->num_of_segment = 0; 1572 1573 num_of_segment = fru_get_num_segments(sec_acc_hdl, 1574 &rarg->cred); 1575 if (num_of_segment < 0) { 1576 *(int *)buf = 0; 1577 unlock_container_lock(cont_tbl); 1578 return (PICL_FAILURE); 1579 } 1580 1581 if (num_of_segment == 0) { 1582 *(int *)buf = 0; 1583 unlock_container_lock(cont_tbl); 1584 return (PICL_SUCCESS); 1585 } 1586 1587 segment = alloca(sizeof (segment_t) * num_of_segment); 1588 if (segment == NULL) { 1589 *(int *)buf = 0; 1590 unlock_container_lock(cont_tbl); 1591 return (PICL_SUCCESS); 1592 } 1593 1594 retval = fru_get_segments(sec_acc_hdl, segment, 1595 num_of_segment, &rarg->cred); 1596 if (retval == -1) { 1597 *(int *)buf = 0; 1598 unlock_container_lock(cont_tbl); 1599 return (PICL_SUCCESS); 1600 } 1601 1602 for (cnt = 0; cnt < num_of_segment; cnt++) { 1603 1604 desc = (fru_segdesc_t *)&segment[cnt].descriptor; 1605 if (!(desc->field.field_perm & SEGMENT_READ)) { 1606 continue; 1607 } 1608 1609 /* if opaque segment don't create segment node */ 1610 if (desc->field.opaque) { 1611 continue; 1612 } 1613 (void) create_segment_node(hash_obj, rarg->nodeh, 1614 &segment[cnt], cont_tbl, &rarg->cred); 1615 hash_obj->u.sec_node->num_of_segment++; 1616 } 1617 } 1618 1619 /* return number of segment in the section */ 1620 *(int *)buf = hash_obj->u.sec_node->num_of_segment; 1621 1622 unlock_container_lock(cont_tbl); 1623 1624 return (PICL_SUCCESS); 1625 } 1626 1627 1628 /* 1629 * Description : frudata_add_segment is called when volatile property 1630 * add_segment under class node section is accessed. 1631 * 1632 * Arguments : ptree_warg_t holds node handle for the section node. 1633 * property handle for the add_segment property. 1634 * 1635 * Returns : PICL_SUCCESS on success. 1636 * PICL_FAILURE on failure. 1637 */ 1638 1639 static int 1640 frudata_add_segment(ptree_warg_t *warg, const void *buf) 1641 { 1642 int retval; 1643 int cnt; 1644 int num_of_segment; 1645 segment_t *seg_buf; 1646 segment_t segment; 1647 hash_obj_t *seg_hash; 1648 hash_obj_t *hash_obj; 1649 container_tbl_t *cont_tbl; 1650 fru_segdef_t *seg_def; 1651 fru_segdesc_t *desc; 1652 fru_access_hdl_t new_sec_acc_hdl; 1653 1654 seg_def = (fru_segdef_t *)buf; 1655 1656 /* initialize segment_t */ 1657 segment.handle = 0; 1658 (void) memcpy(segment.name, seg_def->name, SEG_NAME_LEN); 1659 segment.descriptor = seg_def->desc.raw_data; 1660 segment.length = seg_def->size; /* segment length */ 1661 segment.offset = seg_def->address; /* segment offset */ 1662 1663 desc = (fru_segdesc_t *)&segment.descriptor; 1664 if (!(desc->field.field_perm & SEGMENT_READ)) { 1665 return (PICL_PERMDENIED); 1666 } 1667 1668 cont_tbl = lock_container_lock(warg->nodeh, SECTION_NODE, PICL_WRITE); 1669 if (!cont_tbl) { 1670 return (PICL_FAILURE); 1671 } 1672 1673 hash_obj = lookup_node_object(warg->nodeh, SECTION_NODE, cont_tbl); 1674 if (hash_obj == NULL) { 1675 unlock_container_lock(cont_tbl); 1676 return (PICL_FAILURE); 1677 } 1678 1679 /* call fruaccess module, get the new section handle. */ 1680 retval = fru_add_segment(hash_obj->u.sec_node->section_hdl, 1681 &segment, &new_sec_acc_hdl, &warg->cred); 1682 if (retval == -1) { 1683 unlock_container_lock(cont_tbl); 1684 return (map_access_err(errno)); 1685 } 1686 1687 /* call access module with new section handle */ 1688 num_of_segment = fru_get_num_segments(new_sec_acc_hdl, &warg->cred); 1689 1690 seg_buf = alloca(sizeof (segment_t) * num_of_segment); 1691 if (seg_buf == NULL) { 1692 unlock_container_lock(cont_tbl); 1693 return (PICL_FAILURE); 1694 } 1695 1696 retval = fru_get_segments(new_sec_acc_hdl, seg_buf, 1697 num_of_segment, &warg->cred); 1698 if (retval == -1) { 1699 unlock_container_lock(cont_tbl); 1700 return (PICL_FAILURE); 1701 } 1702 1703 segment.offset = seg_buf[(num_of_segment -1)].offset; 1704 segment.handle = seg_buf[(num_of_segment-1)].handle; 1705 1706 (void) create_segment_node(hash_obj, warg->nodeh, &segment, 1707 cont_tbl, &warg->cred); 1708 1709 /* rebuild segment list */ 1710 seg_hash = hash_obj->u.sec_node->segment_list; 1711 if (seg_hash == NULL) { 1712 unlock_container_lock(cont_tbl); 1713 return (PICL_FAILURE); 1714 } 1715 1716 hash_obj->u.sec_node->num_of_segment = 0; 1717 1718 for (cnt = 0; cnt < num_of_segment; cnt++) { 1719 desc = (fru_segdesc_t *)&seg_buf[cnt].descriptor; 1720 if (!(desc->field.field_perm & SEGMENT_READ)) { 1721 continue; 1722 } 1723 1724 /* if opaque segment don't create segment node */ 1725 if (desc->field.opaque) { 1726 continue; 1727 } 1728 1729 seg_hash->u.seg_node->segment_hdl = 1730 seg_buf[cnt].handle; 1731 seg_hash = seg_hash->u.seg_node->next; 1732 hash_obj->u.sec_node->num_of_segment++; 1733 } 1734 1735 /* update with new section handle */ 1736 hash_obj->u.sec_node->section_hdl = new_sec_acc_hdl; 1737 1738 unlock_container_lock(cont_tbl); 1739 1740 return (PICL_SUCCESS); 1741 } 1742 1743 /* 1744 * called from frudata_write_section() callback routine to create 1745 * section node and all the property under class section. it also 1746 * allocate hash node object for each section in the container and 1747 * add the section node object in the section list. 1748 */ 1749 1750 static int 1751 create_section_node(picl_nodehdl_t nodehdl, int section_count, 1752 section_t *section, container_tbl_t *cont_tbl) 1753 { 1754 char sec_name[SECNAMESIZE]; 1755 hash_obj_t *hash_obj; 1756 hash_obj_t *cont_hash; 1757 picl_nodehdl_t chld_node; 1758 picl_prophdl_t prophdl; 1759 ptree_propinfo_t prop; 1760 1761 (void) snprintf(sec_name, SECNAMESIZE, "section%d", section_count); 1762 1763 if (ptree_create_node(sec_name, PICL_CLASS_SECTION, &chld_node) 1764 != PICL_SUCCESS) { 1765 return (PICL_FAILURE); 1766 } 1767 prop.version = PTREE_PROPINFO_VERSION; 1768 prop.piclinfo.type = PICL_PTYPE_UNSIGNED_INT; 1769 prop.piclinfo.accessmode = PICL_READ; 1770 prop.piclinfo.size = sizeof (uint32_t); 1771 prop.read = NULL; 1772 prop.write = NULL; 1773 1774 /* offset */ 1775 (void) strcpy(prop.piclinfo.name, PICL_PROP_OFFSET); 1776 if (ptree_create_and_add_prop(chld_node, &prop, §ion->offset, 1777 &prophdl) != PICL_SUCCESS) { 1778 freeup(chld_node); 1779 return (PICL_FAILURE); 1780 } 1781 1782 /* length */ 1783 (void) strcpy(prop.piclinfo.name, PICL_PROP_LENGTH); 1784 if (ptree_create_and_add_prop(chld_node, &prop, §ion->length, 1785 &prophdl) != PICL_SUCCESS) { 1786 freeup(chld_node); 1787 return (PICL_FAILURE); 1788 } 1789 1790 1791 /* protected */ 1792 (void) strcpy(prop.piclinfo.name, PICL_PROP_PROTECTED); 1793 if (ptree_create_and_add_prop(chld_node, &prop, §ion->protection, 1794 &prophdl) != PICL_SUCCESS) { 1795 freeup(chld_node); 1796 return (PICL_FAILURE); 1797 } 1798 1799 prop.piclinfo.accessmode = PICL_READ|PICL_VOLATILE; 1800 prop.read = frudata_read_segment; 1801 1802 (void) strcpy(prop.piclinfo.name, PICL_PROP_NUM_SEGMENTS); 1803 1804 if (ptree_create_and_add_prop(chld_node, &prop, NULL, &prophdl) 1805 != PICL_SUCCESS) { 1806 freeup(chld_node); 1807 return (PICL_FAILURE); 1808 } 1809 1810 1811 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY; 1812 prop.piclinfo.size = sizeof (fru_segdef_t); 1813 1814 prop.piclinfo.accessmode = PICL_WRITE|PICL_READ|PICL_VOLATILE; 1815 prop.write = frudata_add_segment; /* callback routine */ 1816 prop.read = frudata_read_callback; 1817 1818 (void) strcpy(prop.piclinfo.name, PICL_PROP_ADD_SEGMENT); 1819 /* add-segment prop if read/write section */ 1820 if (section->protection == 0) { 1821 if (ptree_create_and_add_prop(chld_node, &prop, NULL, &prophdl) 1822 != PICL_SUCCESS) { 1823 freeup(chld_node); 1824 return (PICL_FAILURE); 1825 } 1826 } 1827 1828 if (ptree_add_node(nodehdl, chld_node) != PICL_SUCCESS) { 1829 freeup(chld_node); 1830 return (PICL_FAILURE); 1831 } 1832 1833 /* lookup for container handle */ 1834 cont_hash = lookup_node_object(nodehdl, CONTAINER_NODE, cont_tbl); 1835 if (cont_hash == NULL) { 1836 freeup(chld_node); 1837 return (PICL_FAILURE); 1838 } 1839 1840 hash_obj = alloc_section_node_object(chld_node, section); 1841 if (hash_obj == NULL) { 1842 freeup(chld_node); 1843 return (PICL_FAILURE); 1844 } 1845 1846 add_nodeobject_to_hashtable(hash_obj, cont_tbl); 1847 1848 add_to_section_list(cont_hash, hash_obj); 1849 return (PICL_SUCCESS); 1850 } 1851 1852 1853 /* 1854 * Description :frudata_write_section is called when volatile container 1855 * property is accessed. it reads the section table associated 1856 * with the specified node handle(container) in ptree_rarg_t. 1857 * it calls search_root_node to search the node handle to open the 1858 * device associated with the node handle. it creates section 1859 * node and it's associated property. it also creates 1860 * volatile property num_segments. 1861 * 1862 * Argument : ptree_rarg_t : contains node handle of fru container the 1863 * container. 1864 * property handle of the container. 1865 * 1866 * Return : PICL_SUCCESS on success. 1867 * 1868 */ 1869 1870 /* ARGSUSED */ 1871 1872 static int 1873 frudata_write_section(ptree_warg_t *warg, const void *buf) 1874 { 1875 int retval; 1876 int num_of_section; 1877 int count; 1878 section_t *section; 1879 hash_obj_t *hash_obj; 1880 container_tbl_t *cont_tbl = NULL; 1881 fru_access_hdl_t cont_acc_hdl; 1882 1883 (void) pthread_mutex_lock(&cont_tbl_lock); 1884 1885 /* 1886 * if lookup succeed return from this function with PICL_SUCCESS 1887 * because first write operation has already occurred on this container, 1888 * it also means that the container has been already initialzed. 1889 */ 1890 1891 cont_tbl = lookup_container_table(warg->nodeh, CONTAINER_NODE); 1892 if (cont_tbl != NULL) { /* found the hash obj in the hash table */ 1893 (void) pthread_mutex_unlock(&cont_tbl_lock); 1894 return (PICL_SUCCESS); 1895 } 1896 1897 /* 1898 * lookup failed that means this is first write on the 1899 * container property. allocate a new container hash table for this 1900 * new container and add to the cont_tbl hash table. 1901 */ 1902 1903 cont_tbl = alloc_container_table(warg->nodeh); 1904 if (cont_tbl == NULL) { 1905 (void) pthread_mutex_unlock(&cont_tbl_lock); 1906 return (map_access_err(errno)); 1907 } 1908 1909 hash_obj = alloc_container_node_object(warg->nodeh); 1910 if (hash_obj == NULL) { 1911 (void) pthread_mutex_unlock(&cont_tbl_lock); 1912 return (map_access_err(errno)); 1913 } 1914 1915 /* add container table object to container table */ 1916 add_tblobject_to_container_tbl(cont_tbl); 1917 1918 /* add the hash object to container hash table. */ 1919 add_nodeobject_to_hashtable(hash_obj, cont_tbl); 1920 1921 while (pthread_rwlock_trywrlock(&cont_tbl->rwlock) == EBUSY) { 1922 pthread_cond_wait(&cont_tbl->cond_var, &cont_tbl_lock); 1923 } 1924 1925 (void) pthread_mutex_unlock(&cont_tbl_lock); 1926 1927 /* fruaccess handle */ 1928 cont_acc_hdl = hash_obj->u.cont_node->cont_hdl; 1929 1930 num_of_section = fru_get_num_sections(cont_acc_hdl, &warg->cred); 1931 1932 if (num_of_section == -1) { 1933 free(hash_obj); 1934 unlock_container_lock(cont_tbl); 1935 return (PICL_FAILURE); 1936 } 1937 1938 section = alloca(num_of_section * sizeof (section_t)); 1939 1940 retval = fru_get_sections(cont_acc_hdl, section, 1941 num_of_section, &warg->cred); 1942 if (retval == -1) { 1943 free(hash_obj); 1944 unlock_container_lock(cont_tbl); 1945 return (PICL_FAILURE); 1946 } 1947 1948 hash_obj->u.cont_node->num_of_section = num_of_section; 1949 1950 for (count = 0; count < num_of_section; count++) { 1951 (void) create_section_node(warg->nodeh, count, 1952 section + count, cont_tbl); 1953 } 1954 1955 unlock_container_lock(cont_tbl); 1956 1957 return (PICL_SUCCESS); 1958 } 1959 1960 /* create container and add-segment property */ 1961 1962 static int 1963 create_container_prop(picl_nodehdl_t fruhdl) 1964 { 1965 int retval; 1966 picl_prophdl_t prophdl; 1967 ptree_propinfo_t prop; 1968 1969 prop.version = PTREE_PROPINFO_VERSION; 1970 prop.piclinfo.type = PICL_PTYPE_UNSIGNED_INT; 1971 prop.piclinfo.size = sizeof (uint32_t); 1972 prop.piclinfo.accessmode = PICL_WRITE|PICL_VOLATILE; 1973 (void) strcpy(prop.piclinfo.name, PICL_PROP_CONTAINER); 1974 prop.read = frudata_read_callback; 1975 prop.write = frudata_write_section; /* callback routine */ 1976 1977 /* create a property */ 1978 retval = ptree_create_and_add_prop(fruhdl, &prop, NULL, &prophdl); 1979 1980 return (retval); 1981 } 1982 1983 /* search for FRUDataAvailable and create container and add segment property */ 1984 1985 static void 1986 create_frudata_props(picl_prophdl_t fruhdl) 1987 { 1988 int retval; 1989 picl_nodehdl_t chldhdl; 1990 picl_nodehdl_t tmphdl; 1991 1992 for (retval = ptree_get_propval_by_name(fruhdl, PICL_PROP_CHILD, 1993 &chldhdl, sizeof (picl_nodehdl_t)); retval != PICL_PROPNOTFOUND; 1994 retval = ptree_get_propval_by_name(chldhdl, PICL_PROP_PEER, 1995 &chldhdl, sizeof (picl_nodehdl_t))) { 1996 if (retval != PICL_SUCCESS) 1997 return; 1998 1999 /* Does it have a FRUDataAvailable property */ 2000 retval = ptree_get_prop_by_name(chldhdl, 2001 PICL_PROP_FRUDATA_AVAIL, &tmphdl); 2002 if (retval == PICL_SUCCESS) { 2003 (void) create_container_prop(chldhdl); 2004 } 2005 2006 /* Traverse tree recursively */ 2007 (void) create_frudata_props(chldhdl); 2008 } 2009 } 2010 2011 /* 2012 * Search for the frutree config file from the platform specific 2013 * directory to the common directory. 2014 * 2015 * The size of outfilename must be PATH_MAX 2016 */ 2017 static int 2018 get_config_file(char *outfilename) 2019 { 2020 char nmbuf[SYS_NMLN]; 2021 char pname[PATH_MAX]; 2022 2023 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2024 (void) snprintf(pname, PATH_MAX, FRUDATA_CONFFILE_NAME, nmbuf); 2025 if (access(pname, R_OK) == 0) { 2026 (void) strlcpy(outfilename, pname, PATH_MAX); 2027 return (0); 2028 } 2029 } 2030 2031 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2032 (void) snprintf(pname, PATH_MAX, FRUDATA_CONFFILE_NAME, nmbuf); 2033 if (access(pname, R_OK) == 0) { 2034 (void) strlcpy(outfilename, pname, PATH_MAX); 2035 return (0); 2036 } 2037 } 2038 2039 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2040 FRUDATA_CONFFILE_NAME); 2041 if (access(pname, R_OK) == 0) { 2042 (void) strlcpy(outfilename, pname, PATH_MAX); 2043 return (0); 2044 } 2045 return (-1); 2046 } 2047 2048 /* 2049 * called from delete_frudata_props(), this routine delete the section node 2050 * and free's the section hash object. it calls free_segment_node() to 2051 * delete segment node beneath it. 2052 */ 2053 2054 static void 2055 free_section_node(hash_obj_t *sec_hash, container_tbl_t *cont_tbl) 2056 { 2057 hash_obj_t *seg_hash; 2058 2059 for (seg_hash = sec_hash->u.sec_node->segment_list; seg_hash != NULL; 2060 seg_hash = seg_hash->u.seg_node->next) { 2061 free_segment_node(seg_hash, seg_hash->picl_hdl, cont_tbl); 2062 } 2063 2064 if (sec_hash->prev == NULL) { 2065 cont_tbl->hash_obj[(sec_hash->picl_hdl % TABLE_SIZE)].next = 2066 sec_hash->next; 2067 if (sec_hash->next != NULL) { 2068 sec_hash->next->prev = NULL; 2069 } 2070 } else { 2071 sec_hash->prev->next = sec_hash->next; 2072 if (sec_hash->next != NULL) { 2073 sec_hash->next->prev = sec_hash->prev; 2074 } 2075 } 2076 2077 /* delete & destroy section node */ 2078 (void) ptree_delete_node(sec_hash->picl_hdl); 2079 (void) ptree_destroy_node(sec_hash->picl_hdl); 2080 2081 free(sec_hash->u.sec_node); 2082 free(sec_hash); 2083 } 2084 2085 /* 2086 * called from delete_frudata_props(), this routine free's the container 2087 * hash object. 2088 */ 2089 2090 static void 2091 unlink_container_node(container_tbl_t *cont_hash) 2092 { 2093 if (cont_hash->prev == NULL) { 2094 container_table[(cont_hash->picl_hdl % TABLE_SIZE)] = 2095 cont_hash->next; 2096 if (cont_hash->next != NULL) { 2097 cont_hash->next->prev = NULL; 2098 } 2099 } else { 2100 cont_hash->prev->next = cont_hash->next; 2101 if (cont_hash->next != NULL) { 2102 cont_hash->next->prev = cont_hash->prev; 2103 } 2104 } 2105 } 2106 2107 /* 2108 * called from frudata_event_handler() to free the corresponding hash object 2109 * of the removed fru. 2110 */ 2111 2112 static void 2113 delete_frudata_props(picl_nodehdl_t fru_hdl) 2114 { 2115 hash_obj_t *cont_hash; 2116 hash_obj_t *free_obj; 2117 hash_obj_t *sec_hash; 2118 container_tbl_t *cont_tbl; 2119 2120 (void) pthread_mutex_lock(&cont_tbl_lock); 2121 2122 cont_tbl = lookup_container_table(fru_hdl, CONTAINER_NODE); 2123 if (cont_tbl == NULL) { 2124 (void) pthread_mutex_unlock(&cont_tbl_lock); 2125 return; 2126 } 2127 2128 /* remove the container object from the container table */ 2129 unlink_container_node(cont_tbl); 2130 2131 (void) pthread_cond_broadcast(&cont_tbl->cond_var); 2132 2133 (void) pthread_mutex_unlock(&cont_tbl_lock); 2134 2135 /* 2136 * waiting/blocking calling thread for all I/O in 2137 * progress to complete. don't free the container 2138 * hash before all I/O is complete. 2139 */ 2140 (void) pthread_rwlock_wrlock(&cont_tbl->rwlock); 2141 2142 (void) pthread_rwlock_unlock(&cont_tbl->rwlock); 2143 2144 2145 cont_hash = lookup_node_object(fru_hdl, CONTAINER_NODE, cont_tbl); 2146 if (cont_hash == NULL) { 2147 return; 2148 } 2149 2150 free_obj = cont_hash->u.cont_node->section_list; 2151 /* walk through the section list */ 2152 for (sec_hash = free_obj; sec_hash != NULL; free_obj = sec_hash) { 2153 sec_hash = sec_hash->u.sec_node->next; 2154 free_section_node(free_obj, cont_tbl); 2155 } 2156 (void) fru_close_container(cont_hash->u.cont_node->cont_hdl); 2157 2158 free(cont_hash->u.cont_node); 2159 free(cont_hash); 2160 2161 free(cont_tbl->hash_obj); 2162 free(cont_tbl); 2163 } 2164 2165 /* 2166 * called when there is any state-change in location, fru, port nodes. 2167 * this event handler handles only location state-changes. 2168 */ 2169 /* ARGSUSED */ 2170 static void 2171 frudata_state_change_evhandler(const char *event_name, const void *event_arg, 2172 size_t size, void *cookie) 2173 { 2174 int rc; 2175 nvlist_t *nvlp; 2176 ptree_propinfo_t prop; 2177 picl_nodehdl_t loch, fruh; 2178 picl_prophdl_t proph, prophdl; 2179 char *present_state, *last_state; 2180 char name[PICL_PROPNAMELEN_MAX]; 2181 2182 if (strcmp(event_name, PICLEVENT_STATE_CHANGE) != 0) 2183 return; 2184 2185 if (nvlist_unpack((char *)event_arg, size, &nvlp, NULL)) { 2186 return; 2187 } 2188 2189 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, 2190 &loch) == -1) { 2191 nvlist_free(nvlp); 2192 return; 2193 } 2194 2195 if (ptree_get_propval_by_name(loch, PICL_PROP_CLASSNAME, name, 2196 sizeof (name)) != PICL_SUCCESS) { 2197 nvlist_free(nvlp); 2198 return; 2199 } 2200 2201 /* handle only location events */ 2202 if (strcmp(name, PICL_CLASS_LOCATION) != 0) { 2203 nvlist_free(nvlp); 2204 return; 2205 } 2206 2207 if (nvlist_lookup_string(nvlp, PICLEVENTARG_STATE, 2208 &present_state)) { 2209 nvlist_free(nvlp); 2210 return; 2211 } 2212 2213 rc = ptree_get_propval_by_name(loch, PICL_PROP_CHILD, 2214 &fruh, sizeof (picl_nodehdl_t)); 2215 if (rc != PICL_SUCCESS) { 2216 nvlist_free(nvlp); 2217 return; 2218 } 2219 2220 /* fru removed */ 2221 if (strcmp(present_state, PICLEVENTARGVAL_EMPTY) == 0) { 2222 delete_frudata_props(fruh); 2223 nvlist_free(nvlp); 2224 return; 2225 } 2226 2227 if (nvlist_lookup_string(nvlp, PICLEVENTARG_LAST_STATE, 2228 &last_state)) { 2229 nvlist_free(nvlp); 2230 return; 2231 } 2232 2233 /* fru added */ 2234 if ((strcmp(last_state, PICLEVENTARGVAL_EMPTY) == 0) || 2235 (strcmp(last_state, PICLEVENTARGVAL_UNKNOWN) == 0)) { 2236 rc = ptree_get_prop_by_name(fruh, PICL_PROP_FRUDATA_AVAIL, 2237 &proph); 2238 if (rc != PICL_SUCCESS) { 2239 if (fru_is_data_available(fruh) == 0) { 2240 nvlist_free(nvlp); 2241 return; 2242 } 2243 /* create the property */ 2244 prop.version = PTREE_PROPINFO_VERSION; 2245 prop.piclinfo.type = PICL_PTYPE_VOID; 2246 prop.piclinfo.accessmode = PICL_READ; 2247 prop.piclinfo.size = 0; 2248 (void) strncpy(prop.piclinfo.name, 2249 PICL_PROP_FRUDATA_AVAIL, 2250 sizeof (prop.piclinfo.name)); 2251 2252 rc = ptree_create_prop(&prop, NULL, &prophdl); 2253 if (rc != PICL_SUCCESS) { 2254 nvlist_free(nvlp); 2255 return; 2256 } 2257 rc = ptree_add_prop(fruh, prophdl); 2258 if (rc != PICL_SUCCESS) { 2259 nvlist_free(nvlp); 2260 return; 2261 } 2262 } 2263 (void) create_container_prop(fruh); 2264 } 2265 nvlist_free(nvlp); 2266 } 2267 2268 /* 2269 * called when event is posted when is fru is either added or removed from 2270 * the picltree. 2271 */ 2272 2273 /* ARGSUSED */ 2274 static void 2275 frudata_event_handler(const char *event_name, const void *event_arg, 2276 size_t size, void *cookie) 2277 { 2278 int retval; 2279 char fullfilename[PATH_MAX]; 2280 picl_nodehdl_t fru_picl_hdl; 2281 picl_nodehdl_t roothdl; 2282 2283 if (strcmp(event_name, PICL_FRU_REMOVED) == 0) { 2284 2285 retval = nvlist_lookup_uint64((nvlist_t *)event_arg, 2286 PICLEVENTARG_FRUHANDLE, &fru_picl_hdl); 2287 if (retval != PICL_SUCCESS) { 2288 return; 2289 } 2290 2291 /* free the hash object */ 2292 delete_frudata_props(fru_picl_hdl); 2293 2294 } else if (strcmp(event_name, PICL_FRU_ADDED) == 0) { 2295 /* 2296 * reparse the configuration file to create 2297 * FRUDevicePath Prop. 2298 */ 2299 (void) get_config_file(fullfilename); 2300 retval = ptree_get_root(&roothdl); 2301 if (retval != PICL_SUCCESS) { 2302 return; 2303 } 2304 2305 (void) picld_pluginutil_parse_config_file(roothdl, 2306 fullfilename); 2307 2308 retval = nvlist_lookup_uint64((nvlist_t *)event_arg, 2309 PICLEVENTARG_PARENTHANDLE, &fru_picl_hdl); 2310 if (retval != PICL_SUCCESS) { 2311 return; 2312 } 2313 2314 /* create container property */ 2315 create_frudata_props(fru_picl_hdl); 2316 } 2317 } 2318 2319 /* 2320 * Function : plugin_init() is called by daemon. this routine is specified 2321 * while registering with daemon. it performs the initialization 2322 * of plugin module. 2323 */ 2324 2325 static void 2326 frudata_plugin_init(void) 2327 { 2328 int retval; 2329 int count; 2330 char fullfilename[PATH_MAX]; 2331 picl_nodehdl_t fru_nodehdl; 2332 picl_nodehdl_t roothdl; 2333 2334 retval = ptree_get_root(&roothdl); 2335 if (retval != PICL_SUCCESS) { 2336 return; 2337 } 2338 2339 (void) ptree_register_handler(PICL_FRU_ADDED, 2340 frudata_event_handler, NULL); 2341 2342 (void) ptree_register_handler(PICL_FRU_REMOVED, 2343 frudata_event_handler, NULL); 2344 2345 (void) ptree_register_handler(PICLEVENT_STATE_CHANGE, 2346 frudata_state_change_evhandler, NULL); 2347 2348 (void) pthread_mutex_lock(&cont_tbl_lock); 2349 for (count = 0; count < TABLE_SIZE; count++) { 2350 container_table[count] = NULL; 2351 } 2352 (void) pthread_mutex_unlock(&cont_tbl_lock); 2353 2354 (void) get_config_file(fullfilename); 2355 2356 (void) picld_pluginutil_parse_config_file(roothdl, fullfilename); 2357 2358 retval = ptree_get_node_by_path(FRUTREE_PATH, &fru_nodehdl); 2359 2360 if (retval != PICL_SUCCESS) { 2361 return; 2362 } 2363 2364 create_frudata_props(fru_nodehdl); 2365 2366 } 2367 2368 static void 2369 free_packet_hash_object(hash_obj_t *pkt_obj) 2370 { 2371 hash_obj_t *tmp_obj; 2372 2373 while (pkt_obj != NULL) { 2374 tmp_obj = pkt_obj->u.pkt_node->next; 2375 free(pkt_obj->u.pkt_node); 2376 free(pkt_obj); 2377 pkt_obj = tmp_obj; 2378 } 2379 } 2380 2381 static void 2382 free_segment_hash_object(hash_obj_t *seg_obj) 2383 { 2384 hash_obj_t *tmp_obj; 2385 2386 while (seg_obj != NULL) { 2387 free_packet_hash_object(seg_obj->u.seg_node->packet_list); 2388 tmp_obj = seg_obj->u.seg_node->next; 2389 free(seg_obj->u.seg_node); 2390 free(seg_obj); 2391 seg_obj = tmp_obj; 2392 } 2393 } 2394 2395 static void 2396 free_hash_objects(hash_obj_t *sec_obj) 2397 { 2398 hash_obj_t *tmp_obj; 2399 2400 while (sec_obj != NULL) { 2401 free_segment_hash_object(sec_obj->u.sec_node->segment_list); 2402 tmp_obj = sec_obj->u.sec_node->next; 2403 free(sec_obj->u.sec_node); 2404 free(sec_obj); 2405 sec_obj = tmp_obj; 2406 } 2407 } 2408 2409 /* 2410 * called from frudata_plugin_fini() this routine walks through 2411 * the hash table to free each and very hash object in the hash table. 2412 */ 2413 2414 static void 2415 free_hash_table(void) 2416 { 2417 int cnt; 2418 picl_nodehdl_t nodehdl; 2419 hash_obj_t *next_obj; 2420 hash_obj_t *sec_obj; 2421 container_tbl_t *cont_tbl; 2422 2423 for (cnt = 0; cnt < TABLE_SIZE; cnt++) { 2424 2425 while (container_table[cnt]) { 2426 2427 (void) pthread_mutex_lock(&cont_tbl_lock); 2428 2429 cont_tbl = container_table[cnt]; 2430 nodehdl = cont_tbl->picl_hdl; 2431 2432 cont_tbl = lookup_container_table(nodehdl, 2433 CONTAINER_NODE); 2434 if (cont_tbl == NULL) { 2435 (void) pthread_mutex_unlock(&cont_tbl_lock); 2436 break; 2437 } 2438 2439 unlink_container_node(cont_tbl); 2440 2441 pthread_cond_broadcast(&cont_tbl->cond_var); 2442 2443 (void) pthread_mutex_unlock(&cont_tbl_lock); 2444 2445 /* 2446 * waiting/blocking calling thread for all I/O in 2447 * progress to complete. don't free the container 2448 * hash until all I/O is complete. 2449 */ 2450 (void) pthread_rwlock_wrlock(&cont_tbl->rwlock); 2451 2452 (void) pthread_rwlock_unlock(&cont_tbl->rwlock); 2453 2454 next_obj = cont_tbl->hash_obj->next; 2455 if (next_obj == NULL) { 2456 break; 2457 } 2458 2459 if (next_obj->object_type == CONTAINER_NODE) { 2460 sec_obj = next_obj->u.cont_node->section_list; 2461 free_hash_objects(sec_obj); 2462 } 2463 2464 free(next_obj->u.cont_node); 2465 free(next_obj); 2466 container_table[cnt] = cont_tbl->next; 2467 2468 free(cont_tbl); 2469 } 2470 } 2471 } 2472 2473 /* 2474 * called by the daemon and perform frudata cleanup. hold the write lock 2475 * over the entire hash table to free each and every hash object. 2476 */ 2477 2478 static void 2479 frudata_plugin_fini(void) 2480 { 2481 2482 free_hash_table(); 2483 2484 (void) ptree_unregister_handler(PICL_FRU_ADDED, 2485 frudata_event_handler, NULL); 2486 2487 (void) ptree_unregister_handler(PICL_FRU_REMOVED, 2488 frudata_event_handler, NULL); 2489 2490 (void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE, 2491 frudata_state_change_evhandler, NULL); 2492 } 2493