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