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