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