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