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