8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / frudata / fru_data.c
blobe0849ebc471d81558f982d8374c9e35f704d1b1e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
45 #pragma init(frudata_plugin_register) /* .init section */
47 static void frudata_plugin_init(void);
48 static void frudata_plugin_fini(void);
49 static container_tbl_t *container_table[TABLE_SIZE];
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.
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.
63 static pthread_mutex_t cont_tbl_lock = PTHREAD_MUTEX_INITIALIZER;
65 static int add_row_to_table(hash_obj_t *, picl_nodehdl_t,
66 packet_t *, container_tbl_t *);
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 */
76 /* initialization function */
77 static void
78 frudata_plugin_register(void)
80 /* register plugin with daemon */
81 if (picld_plugin_register(&frudata_reg_info) != PICL_SUCCESS) {
82 syslog(LOG_ERR, "SUNW_piclfrudata plugin registration failed");
86 static int
87 map_access_err(int err)
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);
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.
109 static void
110 unlock_container_lock(container_tbl_t *cont_hash)
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);
119 /* volatile callback read routine */
120 /* ARGSUSED */
121 static int
122 frudata_read_callback(ptree_rarg_t *rarg, void *buf)
124 return (PICL_SUCCESS);
128 * called to get hash object for specified node and object type from
129 * hash table.
131 static container_tbl_t *
132 lookup_container_table(picl_nodehdl_t nodehdl, int object_type)
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;
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);
158 if (retval != PICL_SUCCESS) {
159 return (NULL);
162 index_to_hash = (parenthdl % TABLE_SIZE);
164 first_hash = container_table[index_to_hash];
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);
172 return (NULL);
175 static int
176 lock_readwrite_lock(container_tbl_t *cont_obj, int operation)
178 /* if write operation */
179 if (operation == PICL_WRITE) {
180 return (pthread_rwlock_trywrlock(&cont_obj->rwlock));
182 /* read operation */
183 return (pthread_rwlock_tryrdlock(&cont_obj->rwlock));
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.
194 static container_tbl_t *
195 lock_container_lock(picl_nodehdl_t nodehdl, int object_type, int operation)
197 container_tbl_t *cont_obj = NULL;
199 (void) pthread_mutex_lock(&cont_tbl_lock);
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);
206 (void) pthread_mutex_unlock(&cont_tbl_lock);
208 return (cont_obj);
211 static hash_obj_t *
212 lookup_node_object(picl_nodehdl_t nodehdl, int object_type,
213 container_tbl_t *cont_tbl)
215 int index_to_hash;
216 hash_obj_t *first_hash;
217 hash_obj_t *next_hash;
220 index_to_hash = (nodehdl % TABLE_SIZE);
222 first_hash = &cont_tbl->hash_obj[index_to_hash];
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);
231 return (NULL);
235 * called to add newly created container hash table into container hash table.
238 static void
239 add_tblobject_to_container_tbl(container_tbl_t *cont_tbl)
241 int cnt;
242 int index_to_hash;
243 hash_obj_t *hash_ptr;
245 index_to_hash = ((cont_tbl->picl_hdl) % TABLE_SIZE);
247 cont_tbl->next = container_table[index_to_hash];
248 container_table[index_to_hash] = cont_tbl;
249 hash_ptr = cont_tbl->hash_obj;
251 /* initialize the bucket of this container hash table. */
253 for (cnt = 0; cnt < TABLE_SIZE; cnt++) {
254 hash_ptr->next = NULL;
255 hash_ptr->prev = NULL;
256 hash_ptr++;
258 if (cont_tbl->next != NULL) {
259 cont_tbl->next->prev = cont_tbl;
263 static void
264 add_nodeobject_to_hashtable(hash_obj_t *hash_obj, container_tbl_t *cont_tbl)
266 int index_to_hash;
267 hash_obj_t *hash_table;
269 index_to_hash = ((hash_obj->picl_hdl) % TABLE_SIZE);
270 hash_table = &cont_tbl->hash_obj[index_to_hash];
272 hash_obj->next = hash_table->next;
273 hash_table->next = hash_obj;
275 if (hash_obj->next != NULL) {
276 hash_obj->next->prev = hash_obj;
280 static container_tbl_t *
281 alloc_container_table(picl_nodehdl_t nodehdl)
283 container_tbl_t *cont_tbl;
285 cont_tbl = malloc(sizeof (container_tbl_t));
286 if (cont_tbl == NULL) {
287 return (NULL);
290 cont_tbl->picl_hdl = nodehdl;
292 cont_tbl->hash_obj = malloc(sizeof (hash_obj_t[TABLE_SIZE]));
293 cont_tbl->next = NULL;
294 cont_tbl->prev = NULL;
296 if (cont_tbl->hash_obj == NULL) {
297 (void) free(cont_tbl);
298 return (NULL);
301 (void) pthread_rwlock_init(&cont_tbl->rwlock, NULL);
302 (void) pthread_cond_init(&cont_tbl->cond_var, NULL);
304 return (cont_tbl);
308 * called to allocate container node object for container property and a
309 * container table.
312 static hash_obj_t *
313 alloc_container_node_object(picl_nodehdl_t nodehdl)
315 hash_obj_t *hash_obj;
316 fru_access_hdl_t acc_hdl;
317 container_node_t *cont_node;
319 /* open the container (call fruaccess) */
320 acc_hdl = fru_open_container(nodehdl);
321 if (acc_hdl == (container_hdl_t)0) {
322 return (NULL);
325 /* allocate container node object */
326 cont_node = malloc(sizeof (container_node_t));
327 if (cont_node == NULL) {
328 return (NULL);
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);
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;
346 return (hash_obj);
350 * called to allocate node object for section node.
353 static hash_obj_t *
354 alloc_section_node_object(picl_nodehdl_t nodehdl, section_t *section)
356 hash_obj_t *hash_obj;
357 section_node_t *sec_node;
359 /* allocate section node object */
360 sec_node = malloc(sizeof (section_node_t));
361 if (sec_node == NULL) {
362 return (NULL);
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);
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;
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;
383 return (hash_obj);
387 * called to allocate segment node object.
390 static hash_obj_t *
391 alloc_segment_node_object(picl_nodehdl_t nodehdl, segment_t *segment)
393 hash_obj_t *hash_obj;
394 segment_node_t *seg_node;
396 /* allocate segment node object */
397 seg_node = malloc(sizeof (segment_node_t));
398 if (seg_node == NULL) {
399 return (NULL);
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);
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;
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;
422 return (hash_obj);
426 * called to allocate node object for packet.
429 static hash_obj_t *
430 alloc_packet_node_object(picl_nodehdl_t nodehdl, packet_t *packet)
432 hash_obj_t *hash_obj;
433 packet_node_t *pkt_node;
435 /* allocate packet node object */
436 pkt_node = malloc(sizeof (packet_node_t));
437 if (pkt_node == NULL) {
438 return (NULL);
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);
448 /* fruaccess handle */
449 pkt_node->pkt_handle = packet->handle;
450 pkt_node->next = NULL;
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;
458 return (hash_obj);
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)
465 hash_obj_t *next_hash;
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;
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) {
479 next_hash->u.sec_node->next = sect_hash;
482 /* add new segment hash object to the existing list */
484 static void
485 add_to_segment_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
487 hash_obj_t *next_hash;
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;
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) {
500 next_hash->u.seg_node->next = child_obj;
504 * called to add packet node object to the existing packet list.
506 static void
507 add_to_packet_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
509 hash_obj_t *next_hash;
511 if (parent_obj->u.seg_node->packet_list == NULL) {
512 parent_obj->u.seg_node->packet_list = child_obj;
513 return;
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) {
521 next_hash->u.pkt_node->next = child_obj;
525 * free the packet hash list.
528 static void
529 free_packet_list(hash_obj_t *hash_obj, container_tbl_t *cont_tbl)
531 hash_obj_t *next_obj;
532 hash_obj_t *free_obj;
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;
545 } else {
546 free_obj->prev->next = free_obj->next;
547 if (free_obj->next != NULL) {
548 free_obj->next->prev = free_obj->prev;
552 free(free_obj->u.pkt_node);
553 free(free_obj);
555 hash_obj->u.seg_node->packet_list = NULL;
559 * free the segment hash node object.
562 static void
563 free_segment_node(hash_obj_t *hash_obj, picl_nodehdl_t nodehdl,
564 container_tbl_t *cont_tbl)
566 hash_obj_t *prev_hash_obj;
567 hash_obj_t *next_obj;
569 /* segment hash object list */
570 next_obj = hash_obj->u.sec_node->segment_list;
571 if (next_obj == NULL) {
572 return;
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;
591 if (next_obj == NULL) {
592 return;
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;
609 free_packet_list(next_obj, cont_tbl);
610 free(next_obj->u.seg_node);
611 free(next_obj);
616 * Description : frudata_delete_segment is called when volatile property
617 * delete_segment under class segment is accessed.
619 * Arguments : ptree_warg_t is holds node handle of segment node and property
620 * handle of delete_segment property.
623 /* ARGSUSED */
624 static int
625 frudata_delete_segment(ptree_warg_t *warg, const void *buf)
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;
643 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE);
644 if (!cont_tbl) {
645 return (PICL_FAILURE);
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);
655 /* fruaccess segment handle */
656 seg_acc_hdl = hash_obj->u.seg_node->segment_hdl;
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));
665 if (ptree_delete_node(warg->nodeh) != PICL_SUCCESS) {
666 unlock_container_lock(cont_tbl);
667 return (PICL_FAILURE);
670 if (ptree_destroy_node(warg->nodeh) != PICL_SUCCESS) {
671 unlock_container_lock(cont_tbl);
672 return (PICL_FAILURE);
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);
685 free_segment_node(hash_obj, warg->nodeh, cont_tbl);
687 hash_obj->u.sec_node->num_of_segment = 0;
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);
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);
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);
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);
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;
724 if (desc->field.opaque) {
725 seg_hash = seg_hash->u.seg_node->next;
726 continue;
729 hash_obj->u.sec_node->num_of_segment++;
731 seg_hash->u.seg_node->segment_hdl = seg_buffer[count].handle;
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;
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);
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;
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;
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;
766 seg_hash = seg_hash->u.seg_node->next;
767 if (seg_hash == NULL) {
768 break;
772 /* updated with new section handle */
773 hash_obj->u.sec_node->section_hdl = new_sec_acc_hdl;
775 unlock_container_lock(cont_tbl);
777 return (PICL_SUCCESS);
781 * Description : frudata_read_payload is called when volatile property
782 * payload is read.
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.
788 * Returns : PICL_SUCCESS on success.
789 * PICL_FAILURE on failure.
792 static int
793 frudata_read_payload(ptree_rarg_t *rarg, void *buf)
795 int num_bytes;
796 hash_obj_t *hash_obj;
797 fru_access_hdl_t pkt_acc_hdl;
798 container_tbl_t *cont_tbl;
801 cont_tbl = lock_container_lock(rarg->nodeh, SEGMENT_NODE, PICL_READ);
802 if (!cont_tbl) {
803 return (PICL_FAILURE);
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);
812 pkt_acc_hdl = hash_obj->u.pkt_node->pkt_handle;
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);
821 unlock_container_lock(cont_tbl);
823 return (PICL_SUCCESS);
827 * Description : frudata_write_payload is called when payload property cell
828 * is accessed.
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.
834 * Returns : PICL_SUCCESS on success.
838 static int
839 frudata_write_payload(ptree_warg_t *warg, const void *buf)
841 int retval;
842 hash_obj_t *hash_obj;
843 fru_access_hdl_t pkt_acc_hdl;
844 container_tbl_t *cont_tbl;
846 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE);
847 if (!cont_tbl) {
848 return (PICL_FAILURE);
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);
857 pkt_acc_hdl = hash_obj->u.pkt_node->pkt_handle;
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));
867 hash_obj->u.pkt_node->pkt_handle = pkt_acc_hdl;
869 unlock_container_lock(cont_tbl);
871 return (PICL_SUCCESS);
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).
882 static int
883 frudata_read_tag(ptree_rarg_t *rarg, void *buf)
885 int retval;
886 hash_obj_t *hash_obj;
887 picl_prophdl_t rowproph;
888 container_tbl_t *cont_tbl;
890 cont_tbl = lock_container_lock(rarg->nodeh, SEGMENT_NODE, PICL_READ);
891 if (!cont_tbl) {
892 return (PICL_FAILURE);
895 retval = ptree_get_next_by_row(rarg->proph, &rowproph);
896 if (retval != PICL_SUCCESS) {
897 unlock_container_lock(cont_tbl);
898 return (retval);
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);
907 (void) memcpy(buf, &hash_obj->u.pkt_node->tag, sizeof (tag_t));
909 unlock_container_lock(cont_tbl);
910 return (PICL_SUCCESS);
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.
921 static int
922 create_packet_table(picl_nodehdl_t seghdl, picl_prophdl_t *thdl)
924 int retval;
925 picl_prophdl_t tblhdl;
926 picl_nodehdl_t prophdl;
927 ptree_propinfo_t prop;
929 retval = ptree_create_table(&tblhdl);
930 if (retval != PICL_SUCCESS) {
931 return (retval);
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);
942 retval = ptree_create_and_add_prop(seghdl, &prop, &tblhdl,
943 &prophdl);
944 if (retval != PICL_SUCCESS) {
945 return (retval);
948 /* hold the table handle */
949 *thdl = tblhdl;
951 return (PICL_SUCCESS);
955 * Description : frudata_delete_packet is called when write operation is
956 * performed on tag volatile property.
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
964 * Returns : PICL_SUCCESS on success
968 static int
969 frudata_delete_packet(ptree_warg_t *warg, const void *buf)
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;
983 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE);
984 if (!cont_tbl) {
985 return (PICL_FAILURE);
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);
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);
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);
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));
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);
1027 retval = ptree_delete_prop(tblhdl);
1028 if (retval != PICL_SUCCESS) {
1029 unlock_container_lock(cont_tbl);
1030 return (retval);
1033 retval = ptree_destroy_prop(tblhdl);
1034 if (retval != PICL_SUCCESS) {
1035 unlock_container_lock(cont_tbl);
1036 return (retval);
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);
1047 /* free all packet hash object */
1048 free_packet_list(seg_hash_obj, cont_tbl);
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);
1057 seg_hash_obj->u.seg_node->segment_hdl = new_seg_acc_hdl;
1059 seg_hash_obj->u.seg_node->num_of_pkt = 0;
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);
1067 if (num_of_pkt == 0) {
1068 unlock_container_lock(cont_tbl);
1069 return (PICL_SUCCESS);
1072 packet = alloca(sizeof (packet_t) * num_of_pkt);
1073 if (packet == NULL) {
1074 unlock_container_lock(cont_tbl);
1075 return (PICL_FAILURE);
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);
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);
1091 seg_hash_obj->u.seg_node->num_of_pkt = num_of_pkt;
1093 (void) ptree_update_propval_by_name(warg->nodeh, PICL_PROP_NUM_TAGS,
1094 &num_of_pkt, sizeof (uint32_t));
1096 unlock_container_lock(cont_tbl);
1098 return (PICL_SUCCESS);
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.
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)
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;
1120 prop.version = PTREE_PROPINFO_VERSION;
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;
1128 /* tag property node */
1129 (void) strcpy(prop.piclinfo.name, PICL_PROP_TAG);
1131 paylen = get_payload_length((void *)&pkt->tag);
1132 if (paylen < 0) {
1133 return (PICL_FAILURE);
1136 retval = ptree_create_prop(&prop, NULL, &prophdl[0]);
1137 if (retval != PICL_SUCCESS) {
1138 return (retval);
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;
1150 retval = ptree_create_prop(&prop, NULL, &prophdl[1]);
1151 if (retval != PICL_SUCCESS) {
1152 return (retval);
1155 hash_obj = alloc_packet_node_object(prophdl[1], pkt);
1156 if (hash_obj == NULL) {
1157 return (PICL_FAILURE);
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);
1167 tagtype = get_tag_type((fru_tag_t *)&pkt->tag);
1168 if (tagtype == -1) {
1169 return (PICL_FAILURE);
1172 tag_size = get_tag_size(tagtype);
1173 if (tag_size == (size_t)-1) {
1174 return (PICL_FAILURE);
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);
1181 add_nodeobject_to_hashtable(hash_obj, cont_tbl);
1183 add_to_packet_list(seg_obj, hash_obj);
1185 return (PICL_SUCCESS);
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.
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)
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;
1207 hash_obj = lookup_node_object(nodeh, SEGMENT_NODE, cont_tbl);
1208 if (hash_obj == NULL) {
1209 return (PICL_FAILURE);
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));
1222 if (num_of_pkt == 0) {
1223 hash_obj->u.seg_node->num_of_pkt = 0;
1224 return (0);
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);
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);
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);
1246 hash_obj->u.seg_node->num_of_pkt = num_of_pkt;
1248 return (0);
1253 * Description : frudata_add_packet is called when add-packet volatile
1254 * property is accessed.
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.
1260 * Return : PICL_SUCCESS on success.
1264 /* ARGSUSED */
1265 static int
1266 frudata_add_packet(ptree_warg_t *warg, const void *buf)
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;
1283 cont_tbl = lock_container_lock(warg->nodeh, SEGMENT_NODE, PICL_WRITE);
1284 if (!cont_tbl) {
1285 return (PICL_FAILURE);
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);
1294 seg_acc_hdl = hash_obj->u.seg_node->segment_hdl;
1296 tagtype = get_tag_type((void *)buf);
1297 if (tagtype == -1) {
1298 unlock_container_lock(cont_tbl);
1299 return (PICL_FAILURE);
1302 tag_size = get_tag_size(tagtype);
1303 if (tag_size == (size_t)-1) {
1304 unlock_container_lock(cont_tbl);
1305 return (PICL_FAILURE);
1308 paylen = get_payload_length((void *)buf);
1309 if (paylen == -1) {
1310 unlock_container_lock(cont_tbl);
1311 return (PICL_FAILURE);
1314 packet.tag = 0;
1315 (void) memcpy(&packet.tag, buf, tag_size);
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));
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);
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);
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);
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);
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);
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);
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;
1366 hash_obj->u.seg_node->num_of_pkt = num_of_pkt;
1368 (void) ptree_update_propval_by_name(warg->nodeh, PICL_PROP_NUM_TAGS,
1369 &num_of_pkt, sizeof (uint32_t));
1371 unlock_container_lock(cont_tbl);
1373 return (PICL_SUCCESS);
1376 static void
1377 freeup(picl_nodehdl_t nodeh)
1379 (void) ptree_delete_node(nodeh);
1380 (void) ptree_destroy_node(nodeh);
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.
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)
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;
1404 (void) strlcpy(segname, segment->name, SEG_NAME_LEN + 1);
1405 segname[SEG_NAME_LEN] = '\0';
1407 if (!(isprint(segname[0]) || isprint(segname[1]))) {
1408 return (PICL_FAILURE);
1411 if (ptree_create_node(segname, PICL_CLASS_SEGMENT, &nodehdl)
1412 != PICL_SUCCESS) {
1413 return (PICL_FAILURE);
1417 /* create property node */
1418 prop.version = PTREE_PROPINFO_VERSION;
1419 prop.piclinfo.accessmode = PICL_READ;
1420 prop.read = NULL;
1421 prop.write = NULL;
1423 prop.piclinfo.type = PICL_PTYPE_UNSIGNED_INT;
1424 prop.piclinfo.size = sizeof (uint32_t);
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);
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);
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);
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);
1460 if (create_packet_table(nodehdl, &tblhdl) != PICL_SUCCESS) {
1461 freeup(nodehdl);
1462 return (PICL_FAILURE);
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);
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;
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);
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;
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);
1503 if (ptree_add_node(sec_node, nodehdl) != PICL_SUCCESS) {
1504 freeup(nodehdl);
1505 return (PICL_FAILURE);
1508 hash_obj = alloc_segment_node_object(nodehdl, segment);
1509 if (hash_obj == NULL) {
1510 freeup(nodehdl);
1511 return (PICL_FAILURE);
1514 add_nodeobject_to_hashtable(hash_obj, cont_tbl);
1516 add_to_segment_list(sec_obj, hash_obj);
1518 retval = frudata_read_packet(nodehdl, &tblhdl, cont_tbl, cred);
1519 if (retval != 0) {
1520 return (PICL_SUCCESS);
1523 (void) ptree_update_propval_by_name(nodehdl, PICL_PROP_NUM_TAGS,
1524 &hash_obj->u.seg_node->num_of_pkt, sizeof (uint32_t));
1526 return (PICL_SUCCESS);
1530 * Description :frudata_read_segment is called when num_segment volatile
1531 * property is accessed.
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.
1537 * Returns : PICL_SUCCESS on success.
1538 * PICL_FAILURE on failure.
1541 static int
1542 frudata_read_segment(ptree_rarg_t *rarg, void *buf)
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;
1553 cont_tbl = lock_container_lock(rarg->nodeh, SECTION_NODE, PICL_READ);
1554 if (!cont_tbl) {
1555 return (PICL_FAILURE);
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);
1564 if (hash_obj->u.sec_node->num_of_segment == -1) {
1565 sec_acc_hdl = hash_obj->u.sec_node->section_hdl;
1567 hash_obj->u.sec_node->num_of_segment = 0;
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);
1577 if (num_of_segment == 0) {
1578 *(int *)buf = 0;
1579 unlock_container_lock(cont_tbl);
1580 return (PICL_SUCCESS);
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);
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);
1598 for (cnt = 0; cnt < num_of_segment; cnt++) {
1600 desc = (fru_segdesc_t *)&segment[cnt].descriptor;
1601 if (!(desc->field.field_perm & SEGMENT_READ)) {
1602 continue;
1605 /* if opaque segment don't create segment node */
1606 if (desc->field.opaque) {
1607 continue;
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++;
1615 /* return number of segment in the section */
1616 *(int *)buf = hash_obj->u.sec_node->num_of_segment;
1618 unlock_container_lock(cont_tbl);
1620 return (PICL_SUCCESS);
1625 * Description : frudata_add_segment is called when volatile property
1626 * add_segment under class node section is accessed.
1628 * Arguments : ptree_warg_t holds node handle for the section node.
1629 * property handle for the add_segment property.
1631 * Returns : PICL_SUCCESS on success.
1632 * PICL_FAILURE on failure.
1635 static int
1636 frudata_add_segment(ptree_warg_t *warg, const void *buf)
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;
1650 seg_def = (fru_segdef_t *)buf;
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 */
1659 desc = (fru_segdesc_t *)&segment.descriptor;
1660 if (!(desc->field.field_perm & SEGMENT_READ)) {
1661 return (PICL_PERMDENIED);
1664 cont_tbl = lock_container_lock(warg->nodeh, SECTION_NODE, PICL_WRITE);
1665 if (!cont_tbl) {
1666 return (PICL_FAILURE);
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);
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));
1683 /* call access module with new section handle */
1684 num_of_segment = fru_get_num_segments(new_sec_acc_hdl, &warg->cred);
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);
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);
1699 segment.offset = seg_buf[(num_of_segment -1)].offset;
1700 segment.handle = seg_buf[(num_of_segment-1)].handle;
1702 (void) create_segment_node(hash_obj, warg->nodeh, &segment,
1703 cont_tbl, &warg->cred);
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);
1712 hash_obj->u.sec_node->num_of_segment = 0;
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;
1720 /* if opaque segment don't create segment node */
1721 if (desc->field.opaque) {
1722 continue;
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++;
1731 /* update with new section handle */
1732 hash_obj->u.sec_node->section_hdl = new_sec_acc_hdl;
1734 unlock_container_lock(cont_tbl);
1736 return (PICL_SUCCESS);
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.
1746 static int
1747 create_section_node(picl_nodehdl_t nodehdl, int section_count,
1748 section_t *section, container_tbl_t *cont_tbl)
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;
1757 (void) snprintf(sec_name, SECNAMESIZE, "section%d", section_count);
1759 if (ptree_create_node(sec_name, PICL_CLASS_SECTION, &chld_node)
1760 != PICL_SUCCESS) {
1761 return (PICL_FAILURE);
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;
1770 /* offset */
1771 (void) strcpy(prop.piclinfo.name, PICL_PROP_OFFSET);
1772 if (ptree_create_and_add_prop(chld_node, &prop, &section->offset,
1773 &prophdl) != PICL_SUCCESS) {
1774 freeup(chld_node);
1775 return (PICL_FAILURE);
1778 /* length */
1779 (void) strcpy(prop.piclinfo.name, PICL_PROP_LENGTH);
1780 if (ptree_create_and_add_prop(chld_node, &prop, &section->length,
1781 &prophdl) != PICL_SUCCESS) {
1782 freeup(chld_node);
1783 return (PICL_FAILURE);
1787 /* protected */
1788 (void) strcpy(prop.piclinfo.name, PICL_PROP_PROTECTED);
1789 if (ptree_create_and_add_prop(chld_node, &prop, &section->protection,
1790 &prophdl) != PICL_SUCCESS) {
1791 freeup(chld_node);
1792 return (PICL_FAILURE);
1795 prop.piclinfo.accessmode = PICL_READ|PICL_VOLATILE;
1796 prop.read = frudata_read_segment;
1798 (void) strcpy(prop.piclinfo.name, PICL_PROP_NUM_SEGMENTS);
1800 if (ptree_create_and_add_prop(chld_node, &prop, NULL, &prophdl)
1801 != PICL_SUCCESS) {
1802 freeup(chld_node);
1803 return (PICL_FAILURE);
1807 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY;
1808 prop.piclinfo.size = sizeof (fru_segdef_t);
1810 prop.piclinfo.accessmode = PICL_WRITE|PICL_READ|PICL_VOLATILE;
1811 prop.write = frudata_add_segment; /* callback routine */
1812 prop.read = frudata_read_callback;
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);
1824 if (ptree_add_node(nodehdl, chld_node) != PICL_SUCCESS) {
1825 freeup(chld_node);
1826 return (PICL_FAILURE);
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);
1836 hash_obj = alloc_section_node_object(chld_node, section);
1837 if (hash_obj == NULL) {
1838 freeup(chld_node);
1839 return (PICL_FAILURE);
1842 add_nodeobject_to_hashtable(hash_obj, cont_tbl);
1844 add_to_section_list(cont_hash, hash_obj);
1845 return (PICL_SUCCESS);
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.
1858 * Argument : ptree_rarg_t : contains node handle of fru container the
1859 * container.
1860 * property handle of the container.
1862 * Return : PICL_SUCCESS on success.
1866 /* ARGSUSED */
1868 static int
1869 frudata_write_section(ptree_warg_t *warg, const void *buf)
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;
1879 (void) pthread_mutex_lock(&cont_tbl_lock);
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.
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);
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.
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));
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));
1913 /* add container table object to container table */
1914 add_tblobject_to_container_tbl(cont_tbl);
1916 /* add the hash object to container hash table. */
1917 add_nodeobject_to_hashtable(hash_obj, cont_tbl);
1919 while (pthread_rwlock_trywrlock(&cont_tbl->rwlock) == EBUSY) {
1920 pthread_cond_wait(&cont_tbl->cond_var, &cont_tbl_lock);
1923 (void) pthread_mutex_unlock(&cont_tbl_lock);
1925 /* fruaccess handle */
1926 cont_acc_hdl = hash_obj->u.cont_node->cont_hdl;
1928 num_of_section = fru_get_num_sections(cont_acc_hdl, &warg->cred);
1930 if (num_of_section == -1) {
1931 free(hash_obj);
1932 unlock_container_lock(cont_tbl);
1933 return (PICL_FAILURE);
1936 section = alloca(num_of_section * sizeof (section_t));
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);
1946 hash_obj->u.cont_node->num_of_section = num_of_section;
1948 for (count = 0; count < num_of_section; count++) {
1949 (void) create_section_node(warg->nodeh, count,
1950 section + count, cont_tbl);
1953 unlock_container_lock(cont_tbl);
1955 return (PICL_SUCCESS);
1958 /* create container and add-segment property */
1960 static int
1961 create_container_prop(picl_nodehdl_t fruhdl)
1963 int retval;
1964 picl_prophdl_t prophdl;
1965 ptree_propinfo_t prop;
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 */
1975 /* create a property */
1976 retval = ptree_create_and_add_prop(fruhdl, &prop, NULL, &prophdl);
1978 return (retval);
1981 /* search for FRUDataAvailable and create container and add segment property */
1983 static void
1984 create_frudata_props(picl_prophdl_t fruhdl)
1986 int retval;
1987 picl_nodehdl_t chldhdl;
1988 picl_nodehdl_t tmphdl;
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;
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);
2004 /* Traverse tree recursively */
2005 (void) create_frudata_props(chldhdl);
2010 * Search for the frutree config file from the platform specific
2011 * directory to the common directory.
2013 * The size of outfilename must be PATH_MAX
2015 static int
2016 get_config_file(char *outfilename)
2018 char nmbuf[SYS_NMLN];
2019 char pname[PATH_MAX];
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);
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);
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);
2043 return (-1);
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.
2052 static void
2053 free_section_node(hash_obj_t *sec_hash, container_tbl_t *cont_tbl)
2055 hash_obj_t *seg_hash;
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);
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;
2068 } else {
2069 sec_hash->prev->next = sec_hash->next;
2070 if (sec_hash->next != NULL) {
2071 sec_hash->next->prev = sec_hash->prev;
2075 /* delete & destroy section node */
2076 (void) ptree_delete_node(sec_hash->picl_hdl);
2077 (void) ptree_destroy_node(sec_hash->picl_hdl);
2079 free(sec_hash->u.sec_node);
2080 free(sec_hash);
2084 * called from delete_frudata_props(), this routine free's the container
2085 * hash object.
2088 static void
2089 unlink_container_node(container_tbl_t *cont_hash)
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;
2097 } else {
2098 cont_hash->prev->next = cont_hash->next;
2099 if (cont_hash->next != NULL) {
2100 cont_hash->next->prev = cont_hash->prev;
2106 * called from frudata_event_handler() to free the corresponding hash object
2107 * of the removed fru.
2110 static void
2111 delete_frudata_props(picl_nodehdl_t fru_hdl)
2113 hash_obj_t *cont_hash;
2114 hash_obj_t *free_obj;
2115 hash_obj_t *sec_hash;
2116 container_tbl_t *cont_tbl;
2118 (void) pthread_mutex_lock(&cont_tbl_lock);
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;
2126 /* remove the container object from the container table */
2127 unlink_container_node(cont_tbl);
2129 (void) pthread_cond_broadcast(&cont_tbl->cond_var);
2131 (void) pthread_mutex_unlock(&cont_tbl_lock);
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.
2138 (void) pthread_rwlock_wrlock(&cont_tbl->rwlock);
2140 (void) pthread_rwlock_unlock(&cont_tbl->rwlock);
2143 cont_hash = lookup_node_object(fru_hdl, CONTAINER_NODE, cont_tbl);
2144 if (cont_hash == NULL) {
2145 return;
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);
2154 (void) fru_close_container(cont_hash->u.cont_node->cont_hdl);
2156 free(cont_hash->u.cont_node);
2157 free(cont_hash);
2159 free(cont_tbl->hash_obj);
2160 free(cont_tbl);
2164 * called when there is any state-change in location, fru, port nodes.
2165 * this event handler handles only location state-changes.
2167 /* ARGSUSED */
2168 static void
2169 frudata_state_change_evhandler(const char *event_name, const void *event_arg,
2170 size_t size, void *cookie)
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];
2180 if (strcmp(event_name, PICLEVENT_STATE_CHANGE) != 0)
2181 return;
2183 if (nvlist_unpack((char *)event_arg, size, &nvlp, NULL)) {
2184 return;
2187 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE,
2188 &loch) == -1) {
2189 nvlist_free(nvlp);
2190 return;
2193 if (ptree_get_propval_by_name(loch, PICL_PROP_CLASSNAME, name,
2194 sizeof (name)) != PICL_SUCCESS) {
2195 nvlist_free(nvlp);
2196 return;
2199 /* handle only location events */
2200 if (strcmp(name, PICL_CLASS_LOCATION) != 0) {
2201 nvlist_free(nvlp);
2202 return;
2205 if (nvlist_lookup_string(nvlp, PICLEVENTARG_STATE,
2206 &present_state)) {
2207 nvlist_free(nvlp);
2208 return;
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;
2218 /* fru removed */
2219 if (strcmp(present_state, PICLEVENTARGVAL_EMPTY) == 0) {
2220 delete_frudata_props(fruh);
2221 nvlist_free(nvlp);
2222 return;
2225 if (nvlist_lookup_string(nvlp, PICLEVENTARG_LAST_STATE,
2226 &last_state)) {
2227 nvlist_free(nvlp);
2228 return;
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;
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));
2250 rc = ptree_create_prop(&prop, NULL, &prophdl);
2251 if (rc != PICL_SUCCESS) {
2252 nvlist_free(nvlp);
2253 return;
2255 rc = ptree_add_prop(fruh, prophdl);
2256 if (rc != PICL_SUCCESS) {
2257 nvlist_free(nvlp);
2258 return;
2261 (void) create_container_prop(fruh);
2263 nvlist_free(nvlp);
2267 * called when event is posted when is fru is either added or removed from
2268 * the picltree.
2271 /* ARGSUSED */
2272 static void
2273 frudata_event_handler(const char *event_name, const void *event_arg,
2274 size_t size, void *cookie)
2276 int retval;
2277 char fullfilename[PATH_MAX];
2278 picl_nodehdl_t fru_picl_hdl;
2279 picl_nodehdl_t roothdl;
2281 if (strcmp(event_name, PICL_FRU_REMOVED) == 0) {
2283 retval = nvlist_lookup_uint64((nvlist_t *)event_arg,
2284 PICLEVENTARG_FRUHANDLE, &fru_picl_hdl);
2285 if (retval != PICL_SUCCESS) {
2286 return;
2289 /* free the hash object */
2290 delete_frudata_props(fru_picl_hdl);
2292 } else if (strcmp(event_name, PICL_FRU_ADDED) == 0) {
2294 * reparse the configuration file to create
2295 * FRUDevicePath Prop.
2297 (void) get_config_file(fullfilename);
2298 retval = ptree_get_root(&roothdl);
2299 if (retval != PICL_SUCCESS) {
2300 return;
2303 (void) picld_pluginutil_parse_config_file(roothdl,
2304 fullfilename);
2306 retval = nvlist_lookup_uint64((nvlist_t *)event_arg,
2307 PICLEVENTARG_PARENTHANDLE, &fru_picl_hdl);
2308 if (retval != PICL_SUCCESS) {
2309 return;
2312 /* create container property */
2313 create_frudata_props(fru_picl_hdl);
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.
2323 static void
2324 frudata_plugin_init(void)
2326 int retval;
2327 int count;
2328 char fullfilename[PATH_MAX];
2329 picl_nodehdl_t fru_nodehdl;
2330 picl_nodehdl_t roothdl;
2332 retval = ptree_get_root(&roothdl);
2333 if (retval != PICL_SUCCESS) {
2334 return;
2337 (void) ptree_register_handler(PICL_FRU_ADDED,
2338 frudata_event_handler, NULL);
2340 (void) ptree_register_handler(PICL_FRU_REMOVED,
2341 frudata_event_handler, NULL);
2343 (void) ptree_register_handler(PICLEVENT_STATE_CHANGE,
2344 frudata_state_change_evhandler, NULL);
2346 (void) pthread_mutex_lock(&cont_tbl_lock);
2347 for (count = 0; count < TABLE_SIZE; count++) {
2348 container_table[count] = NULL;
2350 (void) pthread_mutex_unlock(&cont_tbl_lock);
2352 (void) get_config_file(fullfilename);
2354 (void) picld_pluginutil_parse_config_file(roothdl, fullfilename);
2356 retval = ptree_get_node_by_path(FRUTREE_PATH, &fru_nodehdl);
2358 if (retval != PICL_SUCCESS) {
2359 return;
2362 create_frudata_props(fru_nodehdl);
2366 static void
2367 free_packet_hash_object(hash_obj_t *pkt_obj)
2369 hash_obj_t *tmp_obj;
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;
2379 static void
2380 free_segment_hash_object(hash_obj_t *seg_obj)
2382 hash_obj_t *tmp_obj;
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;
2393 static void
2394 free_hash_objects(hash_obj_t *sec_obj)
2396 hash_obj_t *tmp_obj;
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;
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.
2412 static void
2413 free_hash_table(void)
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;
2421 for (cnt = 0; cnt < TABLE_SIZE; cnt++) {
2423 while (container_table[cnt]) {
2425 (void) pthread_mutex_lock(&cont_tbl_lock);
2427 cont_tbl = container_table[cnt];
2428 nodehdl = cont_tbl->picl_hdl;
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;
2437 unlink_container_node(cont_tbl);
2439 pthread_cond_broadcast(&cont_tbl->cond_var);
2441 (void) pthread_mutex_unlock(&cont_tbl_lock);
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.
2448 (void) pthread_rwlock_wrlock(&cont_tbl->rwlock);
2450 (void) pthread_rwlock_unlock(&cont_tbl->rwlock);
2452 next_obj = cont_tbl->hash_obj->next;
2453 if (next_obj == NULL) {
2454 break;
2457 if (next_obj->object_type == CONTAINER_NODE) {
2458 sec_obj = next_obj->u.cont_node->section_list;
2459 free_hash_objects(sec_obj);
2462 free(next_obj->u.cont_node);
2463 free(next_obj);
2464 container_table[cnt] = cont_tbl->next;
2466 free(cont_tbl);
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.
2476 static void
2477 frudata_plugin_fini(void)
2480 free_hash_table();
2482 (void) ptree_unregister_handler(PICL_FRU_ADDED,
2483 frudata_event_handler, NULL);
2485 (void) ptree_unregister_handler(PICL_FRU_REMOVED,
2486 frudata_event_handler, NULL);
2488 (void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE,
2489 frudata_state_change_evhandler, NULL);