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