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, §ion->offset,
1773 &prophdl) != PICL_SUCCESS) {
1774 freeup(chld_node);
1775 return (PICL_FAILURE);
1776 }
1777
1778 /* length */
1779 (void) strcpy(prop.piclinfo.name, PICL_PROP_LENGTH);
1780 if (ptree_create_and_add_prop(chld_node, &prop, §ion->length,
1781 &prophdl) != PICL_SUCCESS) {
1782 freeup(chld_node);
1783 return (PICL_FAILURE);
1784 }
1785
1786
1787 /* protected */
1788 (void) strcpy(prop.piclinfo.name, PICL_PROP_PROTECTED);
1789 if (ptree_create_and_add_prop(chld_node, &prop, §ion->protection,
1790 &prophdl) != PICL_SUCCESS) {
1791 freeup(chld_node);
1792 return (PICL_FAILURE);
1793 }
1794
1795 prop.piclinfo.accessmode = PICL_READ|PICL_VOLATILE;
1796 prop.read = frudata_read_segment;
1797
1798 (void) strcpy(prop.piclinfo.name, PICL_PROP_NUM_SEGMENTS);
1799
1800 if (ptree_create_and_add_prop(chld_node, &prop, NULL, &prophdl)
1801 != PICL_SUCCESS) {
1802 freeup(chld_node);
1803 return (PICL_FAILURE);
1804 }
1805
1806
1807 prop.piclinfo.type = PICL_PTYPE_BYTEARRAY;
1808 prop.piclinfo.size = sizeof (fru_segdef_t);
1809
1810 prop.piclinfo.accessmode = PICL_WRITE|PICL_READ|PICL_VOLATILE;
1811 prop.write = frudata_add_segment; /* callback routine */
1812 prop.read = frudata_read_callback;
1813
1814 (void) strcpy(prop.piclinfo.name, PICL_PROP_ADD_SEGMENT);
1815 /* add-segment prop if read/write section */
1816 if (section->protection == 0) {
1817 if (ptree_create_and_add_prop(chld_node, &prop, NULL, &prophdl)
1818 != PICL_SUCCESS) {
1819 freeup(chld_node);
1820 return (PICL_FAILURE);
1821 }
1822 }
1823
1824 if (ptree_add_node(nodehdl, chld_node) != PICL_SUCCESS) {
1825 freeup(chld_node);
1826 return (PICL_FAILURE);
1827 }
1828
1829 /* lookup for container handle */
1830 cont_hash = lookup_node_object(nodehdl, CONTAINER_NODE, cont_tbl);
1831 if (cont_hash == NULL) {
1832 freeup(chld_node);
1833 return (PICL_FAILURE);
1834 }
1835
1836 hash_obj = alloc_section_node_object(chld_node, section);
1837 if (hash_obj == NULL) {
1838 freeup(chld_node);
1839 return (PICL_FAILURE);
1840 }
1841
1842 add_nodeobject_to_hashtable(hash_obj, cont_tbl);
1843
1844 add_to_section_list(cont_hash, hash_obj);
1845 return (PICL_SUCCESS);
1846 }
1847
1848
1849 /*
1850 * Description :frudata_write_section is called when volatile container
1851 * property is accessed. it reads the section table associated
1852 * with the specified node handle(container) in ptree_rarg_t.
1853 * it calls search_root_node to search the node handle to open the
1854 * device associated with the node handle. it creates section
1855 * node and it's associated property. it also creates
1856 * volatile property num_segments.
1857 *
1858 * Argument : ptree_rarg_t : contains node handle of fru container the
1859 * container.
1860 * property handle of the container.
1861 *
1862 * Return : PICL_SUCCESS on success.
1863 *
1864 */
1865
1866 /* ARGSUSED */
1867
1868 static int
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