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