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