xref: /illumos-gate/usr/src/lib/libfru/libfrupicltree/frupicltree.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2000-2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <alloca.h>
30 #include <picl.h>
31 #include <picltree.h>
32 
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 
38 #include "picldefs.h"
39 #include "fru_data.h"
40 
41 #include "libfruds.h"
42 #include "libfrup.h"
43 
44 #define	FRU_LABEL_PADDING 10
45 
46 /* ========================================================================= */
47 #define	TREEHDL_TO_PICLHDL(treehdl) ((picl_nodehdl_t)treehdl)
48 #define	PICLHDL_TO_TREEHDL(piclhdl) ((fru_treehdl_t)piclhdl)
49 
50 #define	TREESEGHDL_TO_PICLHDL(treeseghdl) ((picl_nodehdl_t)treeseghdl)
51 #define	PICLHDL_TO_TREESEGHDL(piclhdl) ((fru_treeseghdl_t)piclhdl)
52 
53 /* Cache of the root node for quick checks */
54 static picl_nodehdl_t picl_root_node;
55 
56 /* ========================================================================= */
57 /*
58  * Map the PICL errors the plugin would give me to FRU errors
59  */
60 static fru_errno_t
61 map_plugin_err(int picl_err)
62 {
63 	switch (picl_err) {
64 		case PICL_SUCCESS:
65 			return (FRU_SUCCESS);
66 		case PICL_PERMDENIED:
67 			return (FRU_INVALPERM);
68 		case PICL_PROPEXISTS:
69 			return (FRU_DUPSEG);
70 		case PICL_NOSPACE:
71 			return (FRU_NOSPACE);
72 	}
73 	return (FRU_IOERROR);
74 }
75 
76 /* ========================================================================= */
77 /*
78  * cause a refresh of the sub-nodes by writing anything to the container
79  * property of the node.
80  */
81 static fru_errno_t
82 update_data_nodes(picl_nodehdl_t handle)
83 {
84 	uint32_t container = FRUDATA_DELETE_TAG_KEY;
85 	int picl_err = PICL_SUCCESS;
86 
87 	if ((picl_err = ptree_update_propval_by_name(handle,
88 		PICL_PROP_CONTAINER, (void *)&container,
89 		sizeof (container))) != PICL_SUCCESS) {
90 		return (map_plugin_err(picl_err));
91 	}
92 
93 	return (FRU_SUCCESS);
94 }
95 
96 /* ========================================================================= */
97 /*
98  * picl like function which gets a string property with the proper length
99  * NOTE: returns picl errno values NOT fru_errno_t
100  */
101 static int
102 get_strprop_by_name(picl_nodehdl_t handle, char *prop_name, char **string)
103 {
104 	int picl_err = PICL_SUCCESS;
105 	picl_prophdl_t proph;
106 
107 	size_t buf_size = 0;
108 	char *tmp_buf = NULL;
109 
110 	ptree_propinfo_t prop_info;
111 
112 	if ((picl_err = ptree_get_prop_by_name(handle, prop_name, &proph))
113 			!= PICL_SUCCESS) {
114 		return (picl_err);
115 	}
116 	if ((picl_err = ptree_get_propinfo(proph, &prop_info))
117 			!= PICL_SUCCESS) {
118 		return (picl_err);
119 	}
120 	buf_size = prop_info.piclinfo.size;
121 
122 	tmp_buf = malloc((sizeof (*tmp_buf) * buf_size));
123 	if (tmp_buf == NULL) {
124 		return (PICL_FAILURE);
125 	}
126 
127 	if ((picl_err = ptree_get_propval(proph, tmp_buf, buf_size))
128 			!= PICL_SUCCESS) {
129 		free(tmp_buf);
130 		return (picl_err);
131 	}
132 
133 	*string = tmp_buf;
134 	return (PICL_SUCCESS);
135 }
136 
137 /* ========================================================================= */
138 static fru_errno_t
139 fpt_get_name_from_hdl(fru_treehdl_t node, char **name)
140 {
141 	int picl_err = PICL_SUCCESS;
142 	char *tmp_name = NULL;
143 	char *label = NULL;
144 	picl_nodehdl_t handle = TREEHDL_TO_PICLHDL(node);
145 
146 	/* get the name */
147 	if ((picl_err = get_strprop_by_name(handle, PICL_PROP_NAME,
148 		&tmp_name)) != PICL_SUCCESS) {
149 		return (FRU_IOERROR);
150 	}
151 
152 	/* get the label, if any */
153 	if ((picl_err = get_strprop_by_name(handle, PICL_PROP_LABEL,
154 		&label)) != PICL_SUCCESS) {
155 		if (picl_err != PICL_PROPNOTFOUND) {
156 			free(tmp_name);
157 			return (FRU_IOERROR);
158 		}
159 		/* else PICL_PROPNOTFOUND is OK because not all nodes */
160 		/* will have a label. */
161 	}
162 
163 	/* construct the name as nessecary */
164 	if (label == NULL) {
165 		*name = strdup(tmp_name);
166 	} else {
167 		size_t buf_size = strlen(tmp_name) + strlen(label) +
168 			FRU_LABEL_PADDING;
169 		char *tmp = malloc(buf_size);
170 		if (tmp == NULL) {
171 			free(tmp_name);
172 			free(label);
173 			return (FRU_FAILURE);
174 		}
175 		snprintf(tmp, buf_size, "%s?%s=%s", tmp_name,
176 			PICL_PROP_LABEL, label);
177 		*name = tmp;
178 	}
179 
180 	free(tmp_name);
181 	free(label);
182 	return (FRU_SUCCESS);
183 }
184 
185 /* ========================================================================= */
186 /* compare the node name to the name passed */
187 static fru_errno_t
188 cmp_node_name(picl_nodehdl_t node, const char *name)
189 {
190 	char *node_name = NULL;
191 
192 	if (get_strprop_by_name(node, PICL_PROP_NAME, &node_name)
193 			!= PICL_SUCCESS) {
194 		return (FRU_FAILURE);
195 	}
196 
197 	if (strcmp(node_name, name) == 0) {
198 		free(node_name);
199 		return (FRU_SUCCESS);
200 	}
201 
202 	free(node_name);
203 	return (FRU_FAILURE);
204 }
205 
206 /* ========================================================================= */
207 /* compare the node class name to the name passed */
208 static fru_errno_t
209 cmp_class_name(picl_nodehdl_t node, const char *name)
210 {
211 	char *class_name = NULL;
212 
213 	if (get_strprop_by_name(node, PICL_PROP_CLASSNAME, &class_name)
214 			!= PICL_SUCCESS) {
215 		return (FRU_FAILURE);
216 	}
217 
218 	if (strcmp(class_name, name) == 0) {
219 		free(class_name);
220 		return (FRU_SUCCESS);
221 	}
222 
223 	free(class_name);
224 	return (FRU_FAILURE);
225 }
226 
227 
228 /* ========================================================================= */
229 /* get the "frutree" root node */
230 static fru_errno_t
231 fpt_get_root(fru_treehdl_t *node)
232 {
233 	picl_nodehdl_t picl_node;
234 	int picl_err = PICL_SUCCESS;
235 
236 	picl_err = ptree_get_root(&picl_node);
237 	if ((picl_err = ptree_get_propval_by_name(picl_node, PICL_PROP_CHILD,
238 		(void *)&picl_node, sizeof (picl_node)))
239 		!= PICL_SUCCESS) {
240 		return (FRU_IOERROR);
241 	}
242 
243 	while (cmp_node_name(picl_node, PICL_NODE_FRUTREE)
244 			!= FRU_SUCCESS) {
245 
246 		if ((picl_err = ptree_get_propval_by_name(picl_node,
247 			PICL_PROP_PEER, (void *)&picl_node,
248 			sizeof (picl_node))) == PICL_PROPNOTFOUND) {
249 			return (FRU_NODENOTFOUND);
250 		} else if (picl_err != PICL_SUCCESS) {
251 			return (FRU_IOERROR);
252 		}
253 	}
254 
255 	picl_root_node = picl_node;
256 	*node = PICLHDL_TO_TREEHDL(picl_node);
257 	return (FRU_SUCCESS);
258 }
259 
260 /* ========================================================================= */
261 static fru_errno_t
262 fpt_get_peer(fru_treehdl_t sibling, fru_treehdl_t *peer)
263 {
264 	int rc = PICL_SUCCESS;
265 	picl_nodehdl_t handle = TREEHDL_TO_PICLHDL(sibling);
266 	picl_nodehdl_t picl_peer;
267 
268 	rc = ptree_get_propval_by_name(handle, PICL_PROP_PEER,
269 		(void *)&picl_peer, sizeof (picl_peer));
270 	if (rc != PICL_SUCCESS) {
271 		if (rc == PICL_PROPNOTFOUND)
272 			return (FRU_NODENOTFOUND);
273 		else
274 			return (FRU_IOERROR);
275 	}
276 
277 	*peer = PICLHDL_TO_TREEHDL(picl_peer);
278 	return (FRU_SUCCESS);
279 }
280 
281 /* ========================================================================= */
282 static fru_errno_t
283 fpt_get_child(fru_treehdl_t handle, fru_treehdl_t *child)
284 {
285 	picl_nodehdl_t p_child;
286 	int rc = ptree_get_propval_by_name(TREEHDL_TO_PICLHDL(handle),
287 		PICL_PROP_CHILD, (void *)&p_child, sizeof (p_child));
288 	if (rc != PICL_SUCCESS) {
289 		if (rc == PICL_PROPNOTFOUND)
290 			return (FRU_NODENOTFOUND);
291 		else
292 			return (FRU_IOERROR);
293 	}
294 
295 	*child = PICLHDL_TO_TREEHDL(p_child);
296 	return (FRU_SUCCESS);
297 }
298 
299 /* ========================================================================= */
300 static fru_errno_t
301 fpt_get_parent(fru_treehdl_t handle, fru_treehdl_t *parent)
302 {
303 	int rc = PICL_SUCCESS;
304 	picl_nodehdl_t p_parent;
305 
306 	/* do not allow the libfru users to see the parent of the root */
307 	if (TREEHDL_TO_PICLHDL(handle) == picl_root_node) {
308 		return (FRU_NODENOTFOUND);
309 	}
310 
311 	rc = ptree_get_propval_by_name(TREEHDL_TO_PICLHDL(handle),
312 		PICL_PROP_PARENT, (void *)&p_parent, sizeof (p_parent));
313 	if (rc != PICL_SUCCESS) {
314 		if (rc == PICL_PROPNOTFOUND)
315 			return (FRU_NODENOTFOUND);
316 		else
317 			return (FRU_IOERROR);
318 	}
319 
320 	*parent = PICLHDL_TO_TREEHDL(p_parent);
321 	return (FRU_SUCCESS);
322 }
323 
324 /* ========================================================================= */
325 static fru_errno_t
326 fpt_get_node_type(fru_treehdl_t node, fru_node_t *type)
327 {
328 	char picl_class[PICL_PROPNAMELEN_MAX];
329 	picl_nodehdl_t handle = TREEHDL_TO_PICLHDL(node);
330 
331 	if (ptree_get_propval_by_name(handle, PICL_PROP_CLASSNAME,
332 		picl_class, sizeof (picl_class)) != PICL_SUCCESS) {
333 		return (FRU_IOERROR);
334 	}
335 
336 	if (strcmp(picl_class, PICL_CLASS_LOCATION) == 0)  {
337 		*type = FRU_NODE_LOCATION;
338 		return (FRU_SUCCESS);
339 	} else if (strcmp(picl_class, PICL_CLASS_FRU) == 0) {
340 		picl_prophdl_t proph;
341 
342 		/* check for the CONTAINER_PROP property which indicates */
343 		/* there is data for this node.  (ie fru is a container) */
344 		if (ptree_get_prop_by_name(handle,
345 			PICL_PROP_CONTAINER, &proph) == PICL_SUCCESS) {
346 			*type = FRU_NODE_CONTAINER;
347 			return (FRU_SUCCESS);
348 		}
349 		*type = FRU_NODE_FRU;
350 		return (FRU_SUCCESS);
351 	}
352 
353 	*type = FRU_NODE_UNKNOWN;
354 	return (FRU_SUCCESS);
355 }
356 
357 /* ========================================================================= */
358 /* find the next section or return NODENOTFOUND */
359 static fru_errno_t
360 find_next_section(picl_nodehdl_t current, picl_nodehdl_t *next)
361 {
362 	picl_nodehdl_t rc_next;
363 
364 	if (ptree_get_propval_by_name(current, PICL_PROP_PEER,
365 		(void *)&rc_next, sizeof (rc_next)) != PICL_SUCCESS) {
366 		return (FRU_NODENOTFOUND);
367 	}
368 
369 	/* Make sure this is a "Section" node */
370 	if (cmp_class_name(rc_next, PICL_CLASS_SECTION)
371 			== FRU_SUCCESS) {
372 		*next = rc_next;
373 		return (FRU_SUCCESS);
374 	}
375 
376 	/* and if this is not good keep trying to find a peer which */
377 	/* is a section */
378 	return (find_next_section(rc_next, next));
379 }
380 
381 /* ========================================================================= */
382 /* find the first section or return NODENOTFOUND */
383 static fru_errno_t
384 find_first_section(picl_nodehdl_t parent, picl_nodehdl_t *section)
385 {
386 	picl_nodehdl_t rc_section;
387 
388 	if (ptree_get_propval_by_name(parent, PICL_PROP_CHILD,
389 		(void *)&rc_section, sizeof (rc_section)) != PICL_SUCCESS) {
390 		return (FRU_NODENOTFOUND);
391 	}
392 
393 	/* Make sure this is a "Section" node */
394 	if (cmp_class_name(rc_section, PICL_CLASS_SECTION)
395 			== FRU_SUCCESS) {
396 		*section = rc_section;
397 		return (FRU_SUCCESS);
398 	}
399 
400 	/* and if this is not good keep trying to find a peer which */
401 	/* is a section */
402 	return (find_next_section(rc_section, section));
403 }
404 
405 /* ========================================================================= */
406 /*
407  * Find the handle of the segment node "segment".
408  * also returns the hardware description of this segment.  (read from the
409  * section this was found in.)
410  * If the ign_cor_flg is set this will still succeed even if the segment is
411  * corrupt, otherwise it will return FRU_SEGCORRUPT for corrupt segments
412  */
413 #define	IGN_CORRUPT_YES 1
414 #define	IGN_CORRUPT_NO 0
415 static fru_errno_t
416 get_segment_node(picl_nodehdl_t handle, const char *segment,
417 	picl_nodehdl_t *seg_hdl, fru_seg_hwdesc_t *hw_desc, int ign_cor_flg)
418 {
419 	fru_errno_t err = FRU_SUCCESS;
420 	picl_nodehdl_t sect_node;
421 
422 	if ((err = update_data_nodes(handle)) != FRU_SUCCESS) {
423 		return (err);
424 	}
425 
426 	if ((err = find_first_section(handle, &sect_node)) != FRU_SUCCESS) {
427 		return (err);
428 	}
429 
430 	/* while there are sections. */
431 	while (err == FRU_SUCCESS) {
432 		uint32_t num_segs = 0;
433 		int rc = PICL_SUCCESS;
434 		picl_nodehdl_t seg_node;
435 
436 		/* do this just in case the Segments have not been built. */
437 		if ((rc = ptree_get_propval_by_name(sect_node,
438 			PICL_PROP_NUM_SEGMENTS,
439 			(void *)&num_segs,
440 			sizeof (num_segs))) != PICL_SUCCESS) {
441 			return (map_plugin_err(rc));
442 		}
443 
444 		/* while there are segments. */
445 		rc = ptree_get_propval_by_name(sect_node, PICL_PROP_CHILD,
446 			(void *)&seg_node, sizeof (seg_node));
447 		while (rc == PICL_SUCCESS) {
448 			char name[PICL_PROPNAMELEN_MAX];
449 			ptree_get_propval_by_name(seg_node, PICL_PROP_NAME,
450 				name, sizeof (name));
451 			if (strcmp(segment, name) == 0) {
452 				int dummy = 0;
453 				int protection = 0;
454 				/* NUM_TAGS prop exists iff segment is OK */
455 				if ((ign_cor_flg == IGN_CORRUPT_NO) &&
456 					(ptree_get_propval_by_name(seg_node,
457 					PICL_PROP_NUM_TAGS,
458 					(void *)&dummy,
459 					sizeof (dummy)) != PICL_SUCCESS)) {
460 					return (FRU_SEGCORRUPT);
461 				}
462 				/* get the HW protections of this section. */
463 				if (ptree_get_propval_by_name(sect_node,
464 					PICL_PROP_PROTECTED,
465 					(void *)&protection,
466 					sizeof (protection)) != PICL_SUCCESS) {
467 					return (FRU_IOERROR);
468 				}
469 				hw_desc->all_bits = 0;
470 				hw_desc->field.read_only = protection;
471 
472 				*seg_hdl = seg_node;
473 				return (FRU_SUCCESS);
474 			}
475 			rc = ptree_get_propval_by_name(seg_node, PICL_PROP_PEER,
476 				(void *)&seg_node, sizeof (seg_node));
477 		}
478 
479 		/* Peer property not found is ok */
480 		if (rc != PICL_PROPNOTFOUND) {
481 			return (FRU_IOERROR);
482 		}
483 
484 		err = find_next_section(sect_node, &sect_node);
485 	}
486 
487 	return (FRU_INVALSEG);
488 }
489 
490 /* ========================================================================= */
491 /*
492  * For the section handle passed add to list all the segment names found.
493  * Also incriments total by the number found.
494  */
495 static fru_errno_t
496 add_segs_for_section(picl_nodehdl_t section, fru_strlist_t *list)
497 {
498 	int num_segments = 0;
499 	int rc = PICL_SUCCESS;
500 
501 	if ((rc = ptree_get_propval_by_name(section,
502 		PICL_PROP_NUM_SEGMENTS,
503 		(void *)&num_segments,
504 		sizeof (num_segments))) != PICL_SUCCESS) {
505 		fru_destroy_strlist(list);
506 		return (map_plugin_err(rc));
507 	}
508 
509 	if (num_segments != 0) {
510 		picl_nodehdl_t seg_node;
511 		int total_space = list->num + num_segments;
512 
513 		list->strs = realloc(list->strs,
514 			(sizeof (*(list->strs)) * (total_space)));
515 		if (list->strs == NULL) {
516 			return (FRU_FAILURE);
517 		}
518 
519 		/* get the first segment */
520 		rc = ptree_get_propval_by_name(section,
521 			PICL_PROP_CHILD, (void *)&seg_node,
522 			sizeof (seg_node));
523 
524 		/* while there are more segments. */
525 		while (rc == PICL_SUCCESS) {
526 			char name[FRU_SEGNAMELEN +1];
527 
528 			if ((rc = ptree_get_propval_by_name(seg_node,
529 				PICL_PROP_NAME, name,
530 				sizeof (name))) != PICL_SUCCESS) {
531 				break;
532 			}
533 
534 			/* check array bounds */
535 			if (list->num >= total_space) {
536 				/* PICL reported incorrect number of segs */
537 				return (FRU_IOERROR);
538 			}
539 			list->strs[(list->num)++] = strdup(name);
540 
541 			rc = ptree_get_propval_by_name(seg_node,
542 				PICL_PROP_PEER, (void *)&seg_node,
543 				sizeof (seg_node));
544 		}
545 
546 		/* Peer property not found is ok */
547 		if (rc != PICL_PROPNOTFOUND) {
548 			return (FRU_IOERROR);
549 		}
550 
551 	}
552 	return (FRU_SUCCESS);
553 }
554 
555 /* ========================================================================= */
556 static fru_errno_t
557 fpt_get_seg_list(fru_treehdl_t handle, fru_strlist_t *list)
558 {
559 	fru_errno_t err;
560 	picl_nodehdl_t sect_node;
561 	fru_strlist_t rc_list;
562 	rc_list.num = 0;
563 	rc_list.strs = NULL;
564 
565 	if ((err = update_data_nodes(TREEHDL_TO_PICLHDL(handle)))
566 			!= FRU_SUCCESS) {
567 		return (err);
568 	}
569 
570 	if ((err = find_first_section(TREEHDL_TO_PICLHDL(handle), &sect_node))
571 			!= FRU_SUCCESS) {
572 		return (err);
573 	}
574 
575 	/* while there are sections. */
576 	while (err == FRU_SUCCESS) {
577 		if ((err = add_segs_for_section(sect_node, &rc_list))
578 				!= FRU_SUCCESS) {
579 			fru_destroy_strlist(&rc_list);
580 			return (err);
581 		}
582 		err = find_next_section(sect_node, &sect_node);
583 	}
584 
585 	list->num = rc_list.num;
586 	list->strs = rc_list.strs;
587 
588 	return (FRU_SUCCESS);
589 }
590 
591 /* ========================================================================= */
592 static fru_errno_t
593 fpt_get_seg_def(fru_treehdl_t handle, const char *seg_name, fru_segdef_t *def)
594 {
595 	fru_errno_t err = FRU_SUCCESS;
596 	picl_nodehdl_t seg_node;
597 	fru_seg_hwdesc_t hw_desc;
598 
599 	fru_segdesc_t desc;
600 	uint32_t size;
601 	uint32_t address;
602 	/* LINTED */
603 	int picl_err = PICL_SUCCESS;
604 
605 	if ((err = get_segment_node(TREEHDL_TO_PICLHDL(handle), seg_name,
606 		&seg_node, &hw_desc, IGN_CORRUPT_YES)) != FRU_SUCCESS)
607 		return (err);
608 
609 	if ((picl_err = ptree_get_propval_by_name(seg_node,
610 		PICL_PROP_DESCRIPTOR,
611 		&desc, sizeof (desc))) != PICL_SUCCESS) {
612 		return (FRU_IOERROR);
613 	}
614 
615 	if ((picl_err = ptree_get_propval_by_name(seg_node,
616 		PICL_PROP_LENGTH,
617 		&size, sizeof (size))) != PICL_SUCCESS) {
618 		return (FRU_IOERROR);
619 	}
620 
621 	if ((picl_err = ptree_get_propval_by_name(seg_node,
622 		PICL_PROP_OFFSET,
623 		&address, sizeof (address))) != PICL_SUCCESS) {
624 		return (FRU_IOERROR);
625 	}
626 
627 	def->version = LIBFRU_VERSION;
628 	strlcpy(def->name, seg_name, FRU_SEGNAMELEN+1);
629 	def->desc = desc;
630 	def->size = size;
631 	def->address = address;
632 	def->hw_desc = hw_desc;
633 
634 	return (FRU_SUCCESS);
635 }
636 
637 /* ========================================================================= */
638 static fru_errno_t
639 fpt_add_seg(fru_treehdl_t handle, fru_segdef_t *def)
640 {
641 	fru_errno_t err = FRU_SUCCESS;
642 	int picl_err = PICL_SUCCESS;
643 	picl_nodehdl_t section;
644 
645 /*
646  * for every section which has a ADD_SEGMENT_PROP try and add the segment
647  */
648 	if ((err = find_first_section(TREEHDL_TO_PICLHDL(handle), &section))
649 		!= FRU_SUCCESS) {
650 		return (err);
651 	}
652 	do {
653 		fru_segdef_t dummy;
654 		if ((picl_err = ptree_get_propval_by_name(section,
655 			PICL_PROP_ADD_SEGMENT, &dummy, sizeof (dummy)))
656 				== PICL_SUCCESS) {
657 
658 			picl_err = ptree_update_propval_by_name(section,
659 				PICL_PROP_ADD_SEGMENT, def, sizeof (*def));
660 
661 			return (map_plugin_err(picl_err));
662 		}
663 	} while (find_next_section(section, &section) == FRU_SUCCESS);
664 
665 	return (map_plugin_err(picl_err));
666 }
667 
668 /* ========================================================================= */
669 static fru_errno_t
670 fpt_delete_seg(fru_treehdl_t handle, const char *seg_name)
671 {
672 	picl_nodehdl_t seg_hdl;
673 	fru_seg_hwdesc_t hw_desc;
674 	fru_errno_t err;
675 
676 	int dead_flag = FRUDATA_DELETE_TAG_KEY;
677 	int rc = PICL_SUCCESS;
678 
679 	if ((err = get_segment_node(TREEHDL_TO_PICLHDL(handle), seg_name,
680 		&seg_hdl, &hw_desc, IGN_CORRUPT_YES)) != FRU_SUCCESS) {
681 		return (err);
682 	}
683 
684 	rc = ptree_update_propval_by_name(seg_hdl, PICL_PROP_DELETE_SEGMENT,
685 		&dead_flag, sizeof (dead_flag));
686 	return (map_plugin_err(rc));
687 }
688 
689 /* ========================================================================= */
690 static fru_errno_t
691 fpt_add_tag_to_seg(fru_treehdl_t handle, const char *seg_name,
692 		fru_tag_t tag, uint8_t *data, size_t data_len)
693 {
694 	fru_errno_t err = FRU_SUCCESS;
695 	picl_nodehdl_t segHdl;
696 	fru_seg_hwdesc_t hw_desc;
697 	int picl_err = PICL_SUCCESS;
698 	size_t buf_size = 0;
699 	uint8_t *buffer = NULL;
700 	picl_prophdl_t add_prop;
701 	ptree_propinfo_t add_prop_info;
702 
703 	if ((err = get_segment_node(TREEHDL_TO_PICLHDL(handle), seg_name,
704 		&segHdl, &hw_desc, IGN_CORRUPT_NO)) != FRU_SUCCESS) {
705 		return (err);
706 	}
707 
708 	/* get the length of the buffer required. */
709 	if ((picl_err = ptree_get_prop_by_name(segHdl,
710 		PICL_PROP_ADD_PACKET,
711 		&add_prop)) != PICL_SUCCESS) {
712 		return (FRU_IOERROR);
713 	}
714 
715 	if ((picl_err = ptree_get_propinfo(add_prop, &add_prop_info))
716 			!= PICL_SUCCESS) {
717 		return (FRU_IOERROR);
718 	}
719 	buf_size = add_prop_info.piclinfo.size;
720 
721 	if (data_len >= (buf_size -  get_tag_size(get_tag_type(&tag)))) {
722 		return (FRU_NOSPACE);
723 	}
724 
725 	buffer = malloc(buf_size);
726 	if (buffer == NULL) {
727 		return (FRU_FAILURE);
728 	}
729 	/* write the tag and data into the buffer */
730 	memcpy(buffer, &tag, get_tag_size(get_tag_type(&tag)));
731 	memcpy((void *)(buffer+get_tag_size(get_tag_type(&tag))),
732 		data, data_len);
733 
734 	picl_err = ptree_update_propval(add_prop, buffer, buf_size);
735 	free(buffer);
736 	return (map_plugin_err(picl_err));
737 }
738 
739 /* ========================================================================= */
740 static fru_errno_t
741 fpt_get_tag_list(fru_treehdl_t handle, const char *seg_name,
742 		fru_tag_t **tags, int *number)
743 {
744 	picl_nodehdl_t seg_node;
745 	fru_seg_hwdesc_t hw_desc;
746 	fru_errno_t err = FRU_SUCCESS;
747 	picl_prophdl_t tagTable;
748 	int picl_err = PICL_SUCCESS;
749 	unsigned int total_tags = 0;
750 
751 	/* return variables */
752 	fru_tag_t *rc_tags = NULL;
753 	unsigned int rc_num = 0;
754 
755 	if ((err = get_segment_node(TREEHDL_TO_PICLHDL(handle), seg_name,
756 		&seg_node, &hw_desc, IGN_CORRUPT_NO)) != FRU_SUCCESS) {
757 		return (err);
758 	}
759 
760 	/* get the number of tags and allocate array for them */
761 	if ((picl_err = ptree_get_propval_by_name(seg_node,
762 		PICL_PROP_NUM_TAGS,
763 		(void *)&total_tags,
764 		sizeof (total_tags))) != PICL_SUCCESS) {
765 		return (FRU_IOERROR);
766 	}
767 
768 	if (total_tags == 0) {
769 		*tags = rc_tags;
770 		*number = rc_num;
771 		return (FRU_SUCCESS);
772 	}
773 
774 	rc_tags = malloc((sizeof (*rc_tags) * total_tags));
775 	if (rc_tags == NULL) {
776 		return (FRU_FAILURE);
777 	}
778 
779 	/* go through the tagTable and fill in the array */
780 	if ((picl_err = ptree_get_propval_by_name(seg_node,
781 		PICL_PROP_PACKET_TABLE,
782 		&tagTable, sizeof (tagTable))) != PICL_SUCCESS) {
783 		free(rc_tags);
784 		return (FRU_IOERROR);
785 	}
786 	picl_err = ptree_get_next_by_col(tagTable, &tagTable);
787 	while (picl_err == PICL_SUCCESS) {
788 		/* check array bounds */
789 		if (rc_num >= total_tags) {
790 			free(rc_tags);
791 			return (FRU_FAILURE);
792 		}
793 		/* fill in the array */
794 		if ((picl_err = ptree_get_propval(tagTable,
795 			(void *)&(rc_tags[rc_num++]),
796 			sizeof (fru_tag_t))) != PICL_SUCCESS) {
797 			free(rc_tags);
798 			return (FRU_IOERROR);
799 		}
800 		/* get the next tag */
801 		picl_err = ptree_get_next_by_col(tagTable, &tagTable);
802 	}
803 
804 	if (picl_err == PICL_ENDOFLIST) {
805 		*tags = rc_tags;
806 		*number = rc_num;
807 		return (FRU_SUCCESS);
808 	}
809 	return (FRU_IOERROR);
810 }
811 
812 /* ========================================================================= */
813 /*
814  * From the handle, segment name, tag, and instance of the tag get me:
815  * segHdl: The segment handle for this segment.
816  * tagHdl: tag property handle in the tag table for this instance "tag"
817  */
818 static fru_errno_t
819 get_tag_handle(picl_nodehdl_t handle, const char *segment,
820 		fru_tag_t tag, int instance,
821 		picl_nodehdl_t *segHdl,
822 		picl_prophdl_t *tagHdl)
823 {
824 	fru_seg_hwdesc_t hw_desc;
825 	fru_errno_t err;
826 	picl_prophdl_t tagTable = 0;
827 	int picl_err = PICL_SUCCESS;
828 	picl_nodehdl_t tmp_seg;
829 
830 	fru_tag_t foundTag;
831 
832 	if ((err = get_segment_node(TREEHDL_TO_PICLHDL(handle), segment,
833 		&tmp_seg, &hw_desc, IGN_CORRUPT_NO)) != FRU_SUCCESS) {
834 		return (err);
835 	}
836 
837 	foundTag.raw_data = 0;
838 	if ((picl_err = ptree_get_propval_by_name(tmp_seg,
839 		PICL_PROP_PACKET_TABLE,
840 		&tagTable, sizeof (tagTable))) != PICL_SUCCESS) {
841 		return (FRU_IOERROR);
842 	}
843 
844 	picl_err = ptree_get_next_by_col(tagTable, &tagTable);
845 	while ((picl_err != PICL_ENDOFLIST) &&
846 		(picl_err == PICL_SUCCESS)) {
847 		if ((picl_err = ptree_get_propval(tagTable, (void *)&foundTag,
848 			sizeof (foundTag))) != PICL_SUCCESS) {
849 			return (FRU_IOERROR);
850 		}
851 		if ((tags_equal(tag, foundTag) == 1) && (instance-- == 0)) {
852 			*segHdl = tmp_seg;
853 			*tagHdl = tagTable;
854 			return (FRU_SUCCESS);
855 		}
856 		picl_err = ptree_get_next_by_col(tagTable, &tagTable);
857 	}
858 
859 	if (picl_err == PICL_ENDOFLIST)
860 		return (FRU_DATANOTFOUND);
861 
862 	return (FRU_IOERROR);
863 }
864 
865 /* ========================================================================= */
866 static fru_errno_t
867 fpt_get_tag_data(fru_treehdl_t handle, const char *seg_name,
868 		fru_tag_t tag, int instance,
869 		uint8_t **data, size_t *data_len)
870 {
871 	fru_errno_t err = FRU_SUCCESS;
872 	int picl_err = PICL_SUCCESS;
873 	uint8_t *buffer;
874 	int buf_len = 0;
875 
876 	picl_nodehdl_t seg;
877 	picl_prophdl_t tagHdl;
878 
879 	if ((err = get_tag_handle(TREEHDL_TO_PICLHDL(handle), seg_name,
880 		tag, instance, &seg, &tagHdl)) != FRU_SUCCESS) {
881 		return (err);
882 	}
883 
884 	if ((picl_err = ptree_get_next_by_row(tagHdl, &tagHdl))
885 		!= PICL_SUCCESS) {
886 		return (FRU_IOERROR);
887 	}
888 
889 	buf_len = get_payload_length(&tag);
890 	buffer = malloc(buf_len);
891 	if (buffer == NULL) {
892 		return (FRU_FAILURE);
893 	}
894 
895 	if ((picl_err = ptree_get_propval(tagHdl, buffer, buf_len))
896 		!= PICL_SUCCESS) {
897 		free(buffer);
898 		return (map_plugin_err(picl_err));
899 	}
900 
901 	*data = buffer;
902 	*data_len = buf_len;
903 	return (FRU_SUCCESS);
904 }
905 
906 /* ========================================================================= */
907 static fru_errno_t
908 fpt_set_tag_data(fru_treehdl_t handle, const char *seg_name,
909 		fru_tag_t tag, int instance,
910 		uint8_t *data, size_t data_len)
911 {
912 	fru_errno_t rc = FRU_SUCCESS;
913 	int picl_err = PICL_SUCCESS;
914 
915 	picl_nodehdl_t seg;
916 	picl_prophdl_t tagHdl;
917 
918 	if ((rc = get_tag_handle(TREEHDL_TO_PICLHDL(handle), seg_name,
919 		tag, instance, &seg, &tagHdl)) != FRU_SUCCESS) {
920 		return (rc);
921 	}
922 
923 	if ((picl_err = ptree_get_next_by_row(tagHdl, &tagHdl))
924 		!= PICL_SUCCESS) {
925 		return (FRU_IOERROR);
926 	}
927 
928 	if ((picl_err = ptree_update_propval(tagHdl, data, data_len))
929 		!= PICL_SUCCESS) {
930 		return (map_plugin_err(picl_err));
931 	}
932 
933 	return (FRU_SUCCESS);
934 }
935 
936 /* ========================================================================= */
937 static fru_errno_t
938 fpt_delete_tag(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
939 		int instance)
940 {
941 	fru_errno_t rc = FRU_SUCCESS;
942 	int picl_err = PICL_SUCCESS;
943 
944 	picl_nodehdl_t segHdl;
945 	picl_prophdl_t tagHdl;
946 
947 	/* get tag handle */
948 	if ((rc = get_tag_handle(TREEHDL_TO_PICLHDL(handle), seg_name,
949 		tag, instance, &segHdl, &tagHdl)) != FRU_SUCCESS) {
950 		return (rc);
951 	}
952 
953 	/* set up key */
954 	tag.raw_data &= FRUDATA_DELETE_TAG_MASK;
955 	tag.raw_data |= FRUDATA_DELETE_TAG_KEY;
956 
957 	/* Write back */
958 	picl_err = ptree_update_propval(tagHdl, (void *)&(tag.raw_data),
959 		sizeof (tag.raw_data));
960 	return (map_plugin_err(picl_err));
961 }
962 
963 /* ========================================================================= */
964 static fru_errno_t
965 fpt_for_each_segment(fru_treehdl_t treenode,
966 			int (*function)(fru_treeseghdl_t segment, void *args),
967 			void *args)
968 {
969 	int		num_segments = 0, status;
970 
971 	fru_errno_t	saved_status = FRU_SUCCESS;
972 
973 	picl_nodehdl_t	container = TREEHDL_TO_PICLHDL(treenode),
974 			section, segment;
975 
976 
977 	if ((status = update_data_nodes(container)) != FRU_SUCCESS)
978 		return (status);
979 
980 	/* process each section */
981 	for (status = ptree_get_propval_by_name(container, PICL_PROP_CHILD,
982 						&section, sizeof (section));
983 		status == PICL_SUCCESS;
984 		status = ptree_get_propval_by_name(section, PICL_PROP_PEER,
985 							&section,
986 							sizeof (section))) {
987 
988 		if (cmp_class_name(section, PICL_CLASS_SECTION) != FRU_SUCCESS)
989 			continue;
990 
991 		if ((status = ptree_get_propval_by_name(section,
992 							PICL_PROP_NUM_SEGMENTS,
993 							&num_segments,
994 							sizeof (num_segments)))
995 		    == PICL_PROPNOTFOUND) {
996 			continue;
997 		} else if (status != PICL_SUCCESS) {
998 			saved_status = map_plugin_err(status);
999 			continue;
1000 		} else if (num_segments == 0) {
1001 			continue;
1002 		}
1003 
1004 		/* process each segment */
1005 		for (status = ptree_get_propval_by_name(section,
1006 							PICL_PROP_CHILD,
1007 							&segment,
1008 							sizeof (segment));
1009 			status == PICL_SUCCESS;
1010 			status = ptree_get_propval_by_name(segment,
1011 							PICL_PROP_PEER,
1012 							&segment,
1013 							sizeof (segment))) {
1014 
1015 			if (cmp_class_name(segment, PICL_CLASS_SEGMENT)
1016 			    != FRU_SUCCESS) continue;
1017 
1018 			if ((status = function(PICLHDL_TO_TREESEGHDL(segment),
1019 						args))
1020 			    != FRU_SUCCESS) return (status);
1021 		}
1022 
1023 		if (status != PICL_PROPNOTFOUND)
1024 			saved_status = map_plugin_err(status);
1025 	}
1026 
1027 	if (status != PICL_PROPNOTFOUND)
1028 		saved_status = map_plugin_err(status);
1029 
1030 	return (saved_status);
1031 }
1032 
1033 /* ========================================================================= */
1034 static fru_errno_t
1035 fpt_get_segment_name(fru_treeseghdl_t segment, char **name)
1036 {
1037 	char			*propval;
1038 
1039 	int			status;
1040 
1041 	picl_prophdl_t		proph = 0;
1042 
1043 	ptree_propinfo_t	propinfo;
1044 
1045 
1046 	if (ptree_get_prop_by_name(TREESEGHDL_TO_PICLHDL(segment),
1047 		PICL_PROP_NAME, &proph)
1048 	    != PICL_SUCCESS)
1049 		return (FRU_IOERROR);
1050 
1051 	if (ptree_get_propinfo(proph, &propinfo) != PICL_SUCCESS)
1052 		return (FRU_IOERROR);
1053 
1054 	if (propinfo.piclinfo.size == 0)
1055 		return (FRU_INVALDATASIZE);
1056 
1057 	if ((propval = malloc(propinfo.piclinfo.size)) == NULL)
1058 		return (FRU_NOSPACE);
1059 
1060 	if ((status = ptree_get_propval(proph, propval, propinfo.piclinfo.size))
1061 	    != PICL_SUCCESS) {
1062 		free(propval);
1063 		return (map_plugin_err(status));
1064 	}
1065 
1066 	*name = propval;
1067 
1068 	return (FRU_SUCCESS);
1069 }
1070 
1071 /* ========================================================================= */
1072 static fru_errno_t
1073 fpt_for_each_packet(fru_treeseghdl_t treesegment,
1074 			int (*function)(fru_tag_t *tag, uint8_t *payload,
1075 					size_t length,
1076 			void *args),
1077     void *args)
1078 {
1079 	int			status;
1080 
1081 	uint8_t			*payload;
1082 
1083 	picl_nodehdl_t		segment = TREESEGHDL_TO_PICLHDL(treesegment);
1084 
1085 	picl_prophdl_t		packet, payloadh = 0;
1086 
1087 	ptree_propinfo_t	propinfo;
1088 
1089 	fru_segdesc_t		descriptor;
1090 
1091 	fru_tag_t		tag;
1092 
1093 
1094 	if ((status = ptree_get_propval_by_name(segment, PICL_PROP_DESCRIPTOR,
1095 						&descriptor,
1096 						sizeof (descriptor)))
1097 	    != PICL_SUCCESS) return (map_plugin_err(status));
1098 
1099 	if (descriptor.field.opaque)
1100 		return (FRU_SUCCESS);
1101 
1102 	if (descriptor.field.encrypted && (encrypt_func == NULL))
1103 		return (FRU_SUCCESS);
1104 
1105 	if ((status = ptree_get_propval_by_name(segment, PICL_PROP_PACKET_TABLE,
1106 						&packet, sizeof (packet)))
1107 	    == PICL_PROPNOTFOUND)
1108 		return (FRU_SUCCESS);
1109 	else if (status != PICL_SUCCESS)
1110 		return (map_plugin_err(status));
1111 
1112 	while ((status = ptree_get_next_by_col(packet, &packet))
1113 		== PICL_SUCCESS) {
1114 		if (((status = ptree_get_propval(packet, &tag, sizeof (tag)))
1115 			!= PICL_SUCCESS) ||
1116 		    ((status = ptree_get_next_by_row(packet, &payloadh))
1117 			!= PICL_SUCCESS) ||
1118 		    ((status = ptree_get_propinfo(payloadh, &propinfo))
1119 			!= PICL_SUCCESS))
1120 			return (map_plugin_err(status));
1121 
1122 		if (propinfo.piclinfo.size > 0) {
1123 			payload = alloca(propinfo.piclinfo.size);
1124 			if ((status = ptree_get_propval(payloadh, payload,
1125 							propinfo.piclinfo.size))
1126 			    != PICL_SUCCESS) return (map_plugin_err(status));
1127 		} else {
1128 			payload = NULL;
1129 		}
1130 
1131 		if ((descriptor.field.encrypted) &&
1132 		    ((status = encrypt_func(FRU_DECRYPT, payload,
1133 						propinfo.piclinfo.size))
1134 			!= FRU_SUCCESS)) return status;
1135 
1136 		if ((status = function(&tag, payload, propinfo.piclinfo.size,
1137 					args))
1138 		    != FRU_SUCCESS) return (status);
1139 	}
1140 
1141 	if (status == PICL_ENDOFLIST)
1142 		return (FRU_SUCCESS);
1143 	else
1144 		return (map_plugin_err(status));
1145 }
1146 
1147 /* ========================================================================= */
1148 /* ARGSUSED0 */
1149 static fru_errno_t
1150 initialize(int argc, char **argv)
1151 {
1152 	return (FRU_SUCCESS);
1153 }
1154 
1155 /* ========================================================================= */
1156 static fru_errno_t
1157 shutdown(void)
1158 {
1159 	return (FRU_SUCCESS);
1160 }
1161 
1162 /* ========================================================================= */
1163 /* object for libfru to link to */
1164 fru_datasource_t data_source =
1165 {
1166 	LIBFRU_DS_VER,
1167 	initialize,
1168 	shutdown,
1169 	fpt_get_root,
1170 	fpt_get_child,
1171 	fpt_get_peer,
1172 	fpt_get_parent,
1173 	fpt_get_name_from_hdl,
1174 	fpt_get_node_type,
1175 	fpt_get_seg_list,
1176 	fpt_get_seg_def,
1177 	fpt_add_seg,
1178 	fpt_delete_seg,
1179 	fpt_for_each_segment,
1180 	fpt_get_segment_name,
1181 	fpt_add_tag_to_seg,
1182 	fpt_get_tag_list,
1183 	fpt_get_tag_data,
1184 	fpt_set_tag_data,
1185 	fpt_delete_tag,
1186 	fpt_for_each_packet
1187 };
1188