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