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
map_plugin_err(int picl_err)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
update_data_nodes(picl_nodehdl_t handle)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
get_strprop_by_name(picl_nodehdl_t handle,char * prop_name,char ** string)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
fpt_get_name_from_hdl(fru_treehdl_t node,char ** name)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
cmp_node_name(picl_nodehdl_t node,const char * name)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
cmp_class_name(picl_nodehdl_t node,const char * name)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
fpt_get_root(fru_treehdl_t * node)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
fpt_get_peer(fru_treehdl_t sibling,fru_treehdl_t * peer)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
fpt_get_child(fru_treehdl_t handle,fru_treehdl_t * child)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
fpt_get_parent(fru_treehdl_t handle,fru_treehdl_t * parent)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
fpt_get_node_type(fru_treehdl_t node,fru_node_t * type)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
find_next_section(picl_nodehdl_t current,picl_nodehdl_t * next)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
find_first_section(picl_nodehdl_t parent,picl_nodehdl_t * section)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
get_segment_node(picl_nodehdl_t handle,const char * segment,picl_nodehdl_t * seg_hdl,fru_seg_hwdesc_t * hw_desc,int ign_cor_flg)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, §_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, §_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
add_segs_for_section(picl_nodehdl_t section,fru_strlist_t * list)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
fpt_get_seg_list(fru_treehdl_t handle,fru_strlist_t * list)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), §_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, §_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
fpt_get_seg_def(fru_treehdl_t handle,const char * seg_name,fru_segdef_t * def)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
fpt_add_seg(fru_treehdl_t handle,fru_segdef_t * def)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), §ion))
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, §ion) == FRU_SUCCESS);
661
662 return (map_plugin_err(picl_err));
663 }
664
665 /* ========================================================================= */
666 static fru_errno_t
fpt_delete_seg(fru_treehdl_t handle,const char * seg_name)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
fpt_add_tag_to_seg(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,uint8_t * data,size_t data_len)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
fpt_get_tag_list(fru_treehdl_t handle,const char * seg_name,fru_tag_t ** tags,int * number)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
get_tag_handle(picl_nodehdl_t handle,const char * segment,fru_tag_t tag,int instance,picl_nodehdl_t * segHdl,picl_prophdl_t * tagHdl)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
fpt_get_tag_data(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,int instance,uint8_t ** data,size_t * data_len)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
fpt_set_tag_data(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,int instance,uint8_t * data,size_t data_len)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
fpt_delete_tag(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,int instance)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
fpt_for_each_segment(fru_treehdl_t treenode,int (* function)(fru_treeseghdl_t segment,void * args),void * args)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 §ion, sizeof (section));
977 status == PICL_SUCCESS;
978 status = ptree_get_propval_by_name(section, PICL_PROP_PEER,
979 §ion,
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
fpt_get_segment_name(fru_treeseghdl_t segment,char ** name)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
fpt_for_each_packet(fru_treeseghdl_t treesegment,int (* function)(fru_tag_t * tag,uint8_t * payload,size_t length,void * args),void * args)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
initialize(int argc,char ** argv)1144 initialize(int argc, char **argv)
1145 {
1146 return (FRU_SUCCESS);
1147 }
1148
1149 /* ========================================================================= */
1150 static fru_errno_t
shutdown(void)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