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