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