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, §_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, §_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), §_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, §_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), §ion)) 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, §ion) == 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 §ion, sizeof (section)); 979 status == PICL_SUCCESS; 980 status = ptree_get_propval_by_name(section, PICL_PROP_PEER, 981 §ion, 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