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 2004 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 <limits.h> 30 #include <alloca.h> 31 #include "fru_access_impl.h" 32 33 #pragma init(initialize_fruaccess) /* .init section */ 34 35 static hash_obj_t *hash_table[TABLE_SIZE]; 36 37 /* 38 * seeprom is the driver_name for the SEEPROM device drivers in excalibur 39 * Define the devfsadm command to load the seeprom drivers if open fails. 40 */ 41 42 static char devfsadm_cmd[] = "/usr/sbin/devfsadm -i seeprom"; 43 44 /* this routine initialize the hash table. */ 45 46 static void 47 initialize_fruaccess(void) 48 { 49 int count; 50 for (count = 0; count < TABLE_SIZE; count++) { 51 hash_table[count] = NULL; 52 } 53 } 54 55 /* 56 * called to lookup hash object for specified handle in the hash table. 57 * 58 */ 59 60 static hash_obj_t * 61 lookup_handle_object(handle_t handle, int object_type) 62 { 63 handle_t index_to_hash; 64 hash_obj_t *first_hash_obj; 65 hash_obj_t *next_hash_obj; 66 67 index_to_hash = (handle % TABLE_SIZE); 68 69 first_hash_obj = hash_table[index_to_hash]; 70 for (next_hash_obj = first_hash_obj; next_hash_obj != NULL; 71 next_hash_obj = next_hash_obj->next) { 72 if ((handle == next_hash_obj->obj_hdl) && 73 (object_type == next_hash_obj->object_type)) { 74 return (next_hash_obj); 75 } 76 } 77 return (NULL); 78 } 79 80 /* called to allocate container hash object */ 81 82 static hash_obj_t * 83 create_container_hash_object(void) 84 { 85 hash_obj_t *hash_obj; 86 container_obj_t *cont_obj; 87 88 cont_obj = malloc(sizeof (container_obj_t)); 89 if (cont_obj == NULL) { 90 return (NULL); 91 } 92 93 hash_obj = malloc(sizeof (hash_obj_t)); 94 if (hash_obj == NULL) { 95 free(cont_obj); 96 return (NULL); 97 } 98 99 cont_obj->sec_obj_list = NULL; 100 101 hash_obj->object_type = CONTAINER_TYPE; 102 hash_obj->u.cont_obj = cont_obj; 103 hash_obj->next = NULL; 104 hash_obj->prev = NULL; 105 106 return (hash_obj); 107 } 108 109 /* called to allocate section hash object */ 110 111 static hash_obj_t * 112 create_section_hash_object(void) 113 { 114 hash_obj_t *hash_obj; 115 section_obj_t *sec_obj; 116 117 sec_obj = malloc(sizeof (section_obj_t)); 118 if (sec_obj == NULL) { 119 return (NULL); 120 } 121 122 hash_obj = malloc(sizeof (hash_obj_t)); 123 if (hash_obj == NULL) { 124 free(sec_obj); 125 return (NULL); 126 } 127 128 sec_obj->next = NULL; 129 sec_obj->seg_obj_list = NULL; 130 131 hash_obj->u.sec_obj = sec_obj; 132 hash_obj->object_type = SECTION_TYPE; 133 hash_obj->next = NULL; 134 hash_obj->prev = NULL; 135 136 return (hash_obj); 137 } 138 139 /* called to allocate segment hash object */ 140 141 static hash_obj_t * 142 create_segment_hash_object(void) 143 { 144 hash_obj_t *hash_obj; 145 segment_obj_t *seg_obj; 146 147 seg_obj = malloc(sizeof (segment_obj_t)); 148 if (seg_obj == NULL) { 149 return (NULL); 150 } 151 152 hash_obj = malloc(sizeof (hash_obj_t)); 153 if (hash_obj == NULL) { 154 free(seg_obj); 155 return (NULL); 156 } 157 158 seg_obj->next = NULL; 159 seg_obj->pkt_obj_list = NULL; 160 161 hash_obj->object_type = SEGMENT_TYPE; 162 hash_obj->u.seg_obj = seg_obj; 163 hash_obj->next = NULL; 164 hash_obj->prev = NULL; 165 166 return (hash_obj); 167 } 168 169 /* called to allocate packet hash object */ 170 171 static hash_obj_t * 172 create_packet_hash_object(void) 173 { 174 hash_obj_t *hash_obj; 175 packet_obj_t *pkt_obj; 176 177 pkt_obj = malloc(sizeof (packet_obj_t)); 178 if (pkt_obj == NULL) { 179 return (NULL); 180 } 181 182 hash_obj = malloc(sizeof (hash_obj_t)); 183 if (hash_obj == NULL) { 184 free(pkt_obj); 185 return (NULL); 186 } 187 188 pkt_obj->next = NULL; 189 190 hash_obj->object_type = PACKET_TYPE; 191 hash_obj->u.pkt_obj = pkt_obj; 192 hash_obj->next = NULL; 193 hash_obj->prev = NULL; 194 195 return (hash_obj); 196 } 197 198 /* called to add allocated hash object into the hash table */ 199 200 static void 201 add_hashobject_to_hashtable(hash_obj_t *hash_obj) 202 { 203 handle_t index_to_hash; 204 static uint64_t handle_count = 0; 205 206 hash_obj->obj_hdl = ++handle_count; /* store the handle */ 207 208 /* where to add ? */ 209 index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE); 210 211 hash_obj->next = hash_table[index_to_hash]; 212 hash_table[index_to_hash] = hash_obj; /* hash obj. added */ 213 214 if (hash_obj->next != NULL) { 215 hash_obj->next->prev = hash_obj; 216 } 217 } 218 219 /* called to add section object list into the section list */ 220 221 static void 222 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 223 { 224 hash_obj_t *next_hash; 225 226 child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl; 227 if (parent_obj->u.cont_obj->sec_obj_list == NULL) { 228 parent_obj->u.cont_obj->sec_obj_list = child_obj; 229 return; 230 } 231 232 for (next_hash = parent_obj->u.cont_obj->sec_obj_list; 233 next_hash->u.sec_obj->next != NULL; 234 next_hash = next_hash->u.sec_obj->next) { 235 ; 236 } 237 238 next_hash->u.sec_obj->next = child_obj; 239 } 240 241 /* called to add segment object list into segment list */ 242 243 static void 244 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 245 { 246 hash_obj_t *next_hash; 247 248 child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl; 249 if (parent_obj->u.sec_obj->seg_obj_list == NULL) { 250 parent_obj->u.sec_obj->seg_obj_list = child_obj; 251 return; 252 } 253 254 for (next_hash = parent_obj->u.sec_obj->seg_obj_list; 255 next_hash->u.seg_obj->next != NULL; 256 next_hash = next_hash->u.seg_obj->next) { 257 ; 258 } 259 260 next_hash->u.seg_obj->next = child_obj; 261 } 262 263 /* called to add packet object list into packet list */ 264 265 static void 266 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 267 { 268 hash_obj_t *next_hash; 269 270 /* add the packet object in the end of list */ 271 child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl; 272 273 if (parent_obj->u.seg_obj->pkt_obj_list == NULL) { 274 parent_obj->u.seg_obj->pkt_obj_list = child_obj; 275 return; 276 } 277 278 for (next_hash = parent_obj->u.seg_obj->pkt_obj_list; 279 next_hash->u.pkt_obj->next != NULL; 280 next_hash = next_hash->u.pkt_obj->next) { 281 ; 282 } 283 284 next_hash->u.pkt_obj->next = child_obj; 285 } 286 287 static void 288 copy_segment_layout(segment_t *seghdr, void *layout) 289 { 290 segment_layout_t *seg_layout; 291 292 seg_layout = (segment_layout_t *)layout; 293 (void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN); 294 seghdr->descriptor = GET_SEGMENT_DESCRIPTOR; 295 seghdr->offset = seg_layout->offset; 296 seghdr->length = seg_layout->length; 297 } 298 299 static hash_obj_t * 300 get_container_hash_object(int object_type, handle_t handle) 301 { 302 hash_obj_t *hash_obj; 303 304 switch (object_type) { 305 case CONTAINER_TYPE : 306 break; 307 case SECTION_TYPE : 308 hash_obj = lookup_handle_object(handle, CONTAINER_TYPE); 309 if (hash_obj == NULL) { 310 return (NULL); 311 } 312 break; 313 case SEGMENT_TYPE : 314 hash_obj = lookup_handle_object(handle, SECTION_TYPE); 315 if (hash_obj == NULL) { 316 return (NULL); 317 } 318 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl, 319 CONTAINER_TYPE); 320 break; 321 case PACKET_TYPE : 322 break; 323 default : 324 return (NULL); 325 } 326 return (hash_obj); 327 } 328 329 330 static void 331 sort_offsettbl(int segcnt, seg_info_t *offset_tbl) 332 { 333 int cntx; 334 int cnty; 335 seg_info_t tmp; 336 337 for (cntx = 0; cntx < segcnt+2; cntx++) { 338 for (cnty = cntx+1; cnty < segcnt + 2; cnty++) { 339 if (offset_tbl[cntx].offset > 340 offset_tbl[cnty].offset) { 341 (void) memcpy(&tmp, &offset_tbl[cnty], 342 sizeof (seg_info_t)); 343 (void) memcpy(&offset_tbl[cnty], 344 &offset_tbl[cntx], sizeof (seg_info_t)); 345 346 (void) memcpy(&offset_tbl[cntx], &tmp, 347 sizeof (seg_info_t)); 348 } 349 } 350 } 351 } 352 353 /* 354 * Description : move_segment_data() reads the segment data and writes it 355 * back to the new segment offset. 356 */ 357 358 static void 359 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd) 360 { 361 int ret; 362 char *buffer; 363 segment_layout_t *segment; 364 365 segment = (segment_layout_t *)seghdr; 366 367 buffer = alloca(segment->length); 368 if (buffer == NULL) { 369 return; 370 } 371 372 ret = pread(contfd, buffer, segment->length, segment->offset); 373 if (ret != segment->length) { 374 return; 375 } 376 377 segment->offset = newoffset; 378 379 ret = pwrite(contfd, buffer, segment->length, segment->offset); 380 if (ret != segment->length) { 381 return; 382 } 383 } 384 385 /* 386 * Description : pack_segment_data() moves the segment data if there is 387 * a hole between two segments. 388 */ 389 390 static void 391 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd, 392 seg_info_t *offset_tbl) 393 { 394 int cnt; 395 int diff; 396 int newoffset; 397 398 for (cnt = segcnt + 1; cnt > 0; cnt--) { 399 if (!offset_tbl[cnt - 1].fixed) { 400 if (offset_tbl[cnt].offset - 401 (offset_tbl[cnt -1 ].offset + 402 offset_tbl[cnt - 1].length) > 0) { 403 404 diff = offset_tbl[cnt].offset - 405 (offset_tbl[cnt - 1].offset + 406 offset_tbl[cnt - 1].length); 407 newoffset = offset_tbl[cnt - 1].offset + diff; 408 409 move_segment_data(seghdr, newoffset, contfd); 410 411 offset_tbl[cnt - 1].offset = newoffset; 412 413 sort_offsettbl(segcnt, offset_tbl); 414 } 415 } 416 } 417 } 418 419 /* 420 * Description : build_offset_tbl() builds the offset table by reading all the 421 * segment header. it makes two more entry into the table one for 422 * section size and another with start of the section after the 423 * segment header. 424 */ 425 426 static int 427 build_offset_tbl(void *seghdr, int segcnt, int secsize, 428 seg_info_t *offset_tbl) 429 { 430 int cnt; 431 fru_segdesc_t segdesc; 432 segment_layout_t *segment; 433 434 for (cnt = 0; cnt < segcnt; cnt++) { 435 segment = (segment_layout_t *)(seghdr) + cnt; 436 437 (void) memcpy(&segdesc, &segment->descriptor, 438 sizeof (uint32_t)); 439 offset_tbl[cnt].segnum = cnt; 440 offset_tbl[cnt].offset = segment->offset; 441 offset_tbl[cnt].length = segment->length; 442 offset_tbl[cnt].fixed = segdesc.field.fixed; 443 } 444 445 /* upper boundary of segment area (lower address bytes) */ 446 offset_tbl[cnt].segnum = -1; 447 offset_tbl[cnt].offset = sizeof (section_layout_t) + 448 ((cnt + 1) * sizeof (segment_layout_t)); 449 450 offset_tbl[cnt].length = 0; 451 offset_tbl[cnt].fixed = 1; 452 /* lower boundary of segment area (higher address bytes) */ 453 454 offset_tbl[cnt+1].segnum = -1; 455 offset_tbl[cnt+1].offset = secsize; 456 offset_tbl[cnt+1].length = 0; 457 offset_tbl[cnt+1].fixed = 1; 458 return (0); 459 } 460 461 static int 462 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl) 463 { 464 int cnt = 0; 465 466 *totsize = 0; 467 for (cnt = segcnt + 1; cnt > 0; cnt--) { 468 if (bytes <= offset_tbl[cnt].offset - 469 (offset_tbl[cnt - 1].offset + 470 offset_tbl[cnt - 1].length)) { 471 return (offset_tbl[cnt].offset - bytes); 472 } 473 474 *totsize += offset_tbl[cnt].offset - 475 (offset_tbl[cnt - 1].offset + offset_tbl[cnt - 1].length); 476 } 477 return (0); 478 } 479 480 481 /* 482 * Description : segment_hdr_present() verify space for new segment header to 483 * be added. 484 */ 485 486 static int 487 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl) 488 { 489 if ((segoffset + size) <= offset_tbl[0].offset) 490 return (0); 491 else 492 return (-1); 493 } 494 495 /* 496 * Description : find_offset() is called from fru_add_segment routine to find 497 * a valid offset. 498 */ 499 500 static int 501 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset, 502 int segsize, int fix, container_hdl_t contfd) 503 { 504 int ret; 505 int newoffset; 506 int totsize = 0; 507 seg_info_t *offset_tbl; 508 509 if (segcnt == 0) { 510 if (!fix) { /* if not fixed segment */ 511 *sectionoffset = secsize - segsize; 512 } 513 return (0); 514 } 515 516 /* 517 * two extra segment info structure are allocated for start of segment 518 * and other end of segment. first segment offset is first available 519 * space and length is 0. second segment offset is is segment length and 520 * offset is 0. build_offset_tbl() explains how upper boundary and lower 521 * boudary segment area are initialized in seg_info_t table. 522 */ 523 524 offset_tbl = malloc((segcnt + 2) * sizeof (seg_info_t)); 525 if (offset_tbl == NULL) { 526 return (-1); 527 } 528 529 /* read all the segment header to make offset table */ 530 ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl); 531 if (ret != 0) { 532 free(offset_tbl); 533 return (-1); 534 } 535 536 /* sort the table */ 537 sort_offsettbl(segcnt, offset_tbl); 538 539 /* new segment header offset */ 540 newoffset = sizeof (section_layout_t) + segcnt * 541 sizeof (segment_layout_t); 542 543 /* do? new segment header overlap any existing data */ 544 ret = segment_hdr_present(newoffset, sizeof (segment_layout_t), 545 offset_tbl); 546 if (ret != 0) { /* make room for new segment if possible */ 547 548 /* look for hole in order to move segment data */ 549 if (offset_tbl[0].fixed == SEGMENT_FIXED) { /* fixed segment */ 550 free(offset_tbl); 551 return (-1); 552 } 553 554 newoffset = hole_discovery(offset_tbl[0].length, segcnt, 555 &totsize, offset_tbl); 556 if (newoffset != 0) { /* found new offset */ 557 /* now new offset */ 558 offset_tbl[0].offset = newoffset; 559 560 /* move the segment data */ 561 move_segment_data(seghdr, newoffset, contfd); 562 /* again sort the offset table */ 563 sort_offsettbl(segcnt, offset_tbl); 564 } else { 565 /* pack the existing hole */ 566 if (totsize > offset_tbl[0].length) { 567 pack_segment_data(seghdr, segcnt, contfd, 568 offset_tbl); 569 } else { 570 free(offset_tbl); 571 return (-1); 572 } 573 } 574 } 575 576 totsize = 0; 577 newoffset = hole_discovery(segsize, segcnt, &totsize, offset_tbl); 578 579 if (newoffset == 0) { /* No hole found */ 580 if (totsize >= segsize) { 581 pack_segment_data(seghdr, segcnt, contfd, offset_tbl); 582 newoffset = hole_discovery(segsize, segcnt, &totsize, 583 offset_tbl); 584 if (newoffset != 0) { 585 *sectionoffset = newoffset; 586 free(offset_tbl); 587 return (0); 588 } 589 } 590 } else { 591 *sectionoffset = newoffset; 592 free(offset_tbl); 593 return (0); 594 } 595 free(offset_tbl); 596 return (-1); 597 } 598 599 static char * 600 tokenizer(char *buf, char *separator, char **nextBuf, char *matched) 601 { 602 int i = 0; 603 int j = 0; 604 605 for (i = 0; buf[i] != '\0'; i++) { 606 for (j = 0; j < strlen(separator); j++) { 607 if (buf[i] == separator[j]) { 608 buf[i] = '\0'; 609 *nextBuf = &(buf[i+1]); 610 *matched = separator[j]; 611 return (buf); 612 } 613 } 614 } 615 616 *nextBuf = buf; 617 *matched = '\0'; 618 return (NULL); 619 } 620 621 static int 622 get_container_info(const char *def_file, const char *cont_desc_str, 623 container_info_t *cont_info) 624 { 625 char *item; 626 char *token; 627 char *field; 628 char matched; 629 char buf[1024]; 630 int foundIt = 0; 631 int ro_tok; 632 int index; 633 FILE *file = fopen(def_file, "r"); 634 635 if (file == NULL) 636 return (-1); 637 638 cont_info->num_sections = 0; 639 640 while (fgets(buf, sizeof (buf), file) != NULL) { 641 /* ignore all comments */ 642 token = tokenizer(buf, "#", &field, &matched); 643 /* find the names */ 644 token = tokenizer(buf, ":", &field, &matched); 645 if (token != 0x00) { 646 token = tokenizer(token, "|", &item, &matched); 647 while (token != 0x00) { 648 if (strcmp(token, cont_desc_str) == 0) { 649 foundIt = 1; 650 goto found; 651 } 652 token = tokenizer(item, "|", &item, &matched); 653 } 654 /* check the last remaining item */ 655 if ((item != 0x00) && 656 (strcmp(item, cont_desc_str) == 0)) { 657 foundIt = 1; 658 goto found; 659 } 660 } 661 } 662 663 found : 664 if (foundIt == 1) { 665 token = tokenizer(field, ":", &field, &matched); 666 if (token == 0x00) { 667 (void) fclose(file); 668 return (-1); 669 } 670 cont_info->header_ver = (headerrev_t)atoi(token); 671 672 token = tokenizer(field, ":\n", &field, &matched); 673 while (token != 0x00) { 674 token = tokenizer(token, ",", &item, &matched); 675 if (token == 0x00) { 676 (void) fclose(file); 677 return (-1); 678 } 679 ro_tok = atoi(token); 680 index = cont_info->num_sections; 681 cont_info->section_info[index].encoding = ENC_STANDARD; 682 if (ro_tok == 1) { 683 cont_info->section_info[index].description. 684 field.read_only = 1; 685 } else if (ro_tok == 0) { 686 cont_info->section_info[index].description. 687 field.read_only = 0; 688 } else if (ro_tok == 2) { 689 /* 690 * a value of 2 in the read-only token means 691 * that the data in this section needs 692 * re-interpreting 693 */ 694 cont_info->section_info[index].description. 695 field.read_only = 1; 696 } else { 697 (void) fclose(file); 698 return (-1); 699 } 700 701 token = tokenizer(item, ",", &item, &matched); 702 if (token == 0x00) { 703 (void) fclose(file); 704 return (-1); 705 } 706 707 cont_info->section_info[index].address = atoi(token); 708 if (ro_tok == 2) { 709 /* 710 * expect an extra parameter to define the 711 * data interpreter 712 */ 713 token = tokenizer(item, ",", &item, &matched); 714 if (token == 0x00) { 715 (void) fclose(file); 716 return (-1); 717 } 718 } 719 if (item == '\0') { 720 (void) fclose(file); 721 return (-1); 722 } 723 cont_info->section_info[index].size = 724 ro_tok == 2 ? atoi(token) : atoi(item); 725 if (ro_tok == 2) { 726 if (strcmp(item, "SPD") == 0) 727 cont_info->section_info[index]. 728 encoding = ENC_SPD; 729 else { 730 (void) fclose(file); 731 return (-1); 732 } 733 } 734 (cont_info->num_sections)++; 735 736 token = tokenizer(field, ":\n ", &field, &matched); 737 } 738 } 739 (void) fclose(file); 740 return (0); 741 } 742 743 /* 744 * Description :fru_open_container() opens the container associated with a fru. 745 * it's called by data plugin module before creating container 746 * property. it calls picltree library routine to get the 747 * device path and driver binding name for the fru to get the 748 * corresponding fru name that describe the fru layout. 749 * 750 * Arguments :picl_hdl_t fru 751 * A handle for PICL tree node of class "fru" representing the 752 * FRU with the container to open. 753 * 754 * Return : 755 * On Success, a Positive integer container handle. is returned 756 * for use in subsequent fru operations;on error, 0 is returned 757 * and "errno" is set appropriately. 758 */ 759 760 container_hdl_t 761 fru_open_container(picl_nodehdl_t fruhdl) 762 { 763 int retval; 764 int count; 765 char *bname; 766 char devpath[PATH_MAX]; 767 char nmbuf[SYS_NMLN]; 768 hash_obj_t *cont_hash_obj; 769 hash_obj_t *sec_hash_obj; 770 picl_nodehdl_t tmphdl; 771 picl_prophdl_t prophdl; 772 ptree_propinfo_t propinfo; 773 container_info_t cont_info; 774 775 /* Get property handle of _seeprom_source under fru node */ 776 retval = ptree_get_propval_by_name(fruhdl, PICL_REFPROP_SEEPROM_SRC, 777 &tmphdl, sizeof (tmphdl)); 778 if (retval != PICL_SUCCESS) { 779 return (NULL); 780 } 781 782 /* Get the device path of the fru */ 783 retval = ptree_get_propval_by_name(tmphdl, PICL_PROP_DEVICEPATH, 784 devpath, PATH_MAX); 785 if (retval != PICL_SUCCESS) { 786 return (NULL); 787 } 788 789 retval = ptree_get_prop_by_name(tmphdl, PICL_PROP_BINDING_NAME, 790 &prophdl); 791 if (retval != PICL_SUCCESS) { 792 return (NULL); 793 } 794 795 retval = ptree_get_propinfo(prophdl, &propinfo); 796 if (retval != PICL_SUCCESS) { 797 return (NULL); 798 } 799 800 bname = alloca(propinfo.piclinfo.size); 801 if (bname == NULL) { 802 return (NULL); 803 } 804 805 /* get the driver binding name */ 806 retval = ptree_get_propval(prophdl, bname, propinfo.piclinfo.size); 807 if (retval != PICL_SUCCESS) { 808 return (NULL); 809 } 810 811 cont_hash_obj = create_container_hash_object(); 812 if (cont_hash_obj == NULL) { 813 return (NULL); 814 } 815 816 add_hashobject_to_hashtable(cont_hash_obj); 817 818 (void) strlcpy(cont_hash_obj->u.cont_obj->device_pathname, devpath, 819 sizeof (devpath)); 820 821 /* if there's a platform-specific conf file, use that */ 822 retval = -1; 823 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 824 (void) snprintf(devpath, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, 825 nmbuf); 826 (void) strlcat(devpath, FRU_CONTAINER_CONF, PATH_MAX); 827 retval = access(devpath, R_OK); 828 } 829 if (retval != 0) { 830 /* nothing for the platform, try the base name */ 831 (void) snprintf(devpath, PATH_MAX, "%s/%s", 832 CONTAINER_DIR, FRU_CONTAINER_CONF); 833 retval = access(devpath, R_OK); 834 } 835 /* matches driver binding name to get container information */ 836 if (retval == 0) { 837 retval = get_container_info(devpath, bname, &cont_info); 838 } 839 if (retval < 0) { 840 return (NULL); 841 } 842 843 cont_hash_obj->u.cont_obj->num_of_section = cont_info.num_sections; 844 cont_hash_obj->u.cont_obj->sec_obj_list = NULL; 845 846 for (count = 0; count < cont_info.num_sections; count++) { 847 sec_hash_obj = create_section_hash_object(); 848 if (sec_hash_obj == NULL) { 849 return (NULL); 850 } 851 852 add_hashobject_to_hashtable(sec_hash_obj); 853 854 sec_hash_obj->u.sec_obj->section.offset = 855 cont_info.section_info[count].address; 856 857 sec_hash_obj->u.sec_obj->section.protection = 858 cont_info.section_info[count].description.field.read_only; 859 860 sec_hash_obj->u.sec_obj->section.length = 861 cont_info.section_info[count].size; 862 863 sec_hash_obj->u.sec_obj->section.version = cont_info.header_ver; 864 sec_hash_obj->u.sec_obj->encoding = 865 cont_info.section_info[count].encoding; 866 867 add_to_sec_object_list(cont_hash_obj, sec_hash_obj); 868 } 869 return (cont_hash_obj->obj_hdl); 870 } 871 872 static int 873 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length) 874 { 875 int crc_offset = 0; 876 unsigned char orig_crc8 = 0; 877 unsigned char calc_crc8 = 0; 878 879 switch (head_ver) { 880 case SECTION_HDR_VER: 881 crc_offset = 4; 882 break; 883 default: 884 errno = EINVAL; 885 return (0); 886 } 887 888 orig_crc8 = bytes[crc_offset]; 889 bytes[crc_offset] = 0x00; /* clear for calc */ 890 calc_crc8 = compute_crc8(bytes, length); 891 bytes[crc_offset] = orig_crc8; /* restore */ 892 return (orig_crc8 == calc_crc8); 893 } 894 895 /* 896 * Description : 897 * fru_get_num_sections() returns number of sections in a 898 * container. it calls get_container_index() to get the container 899 * index number in the container list. 900 * 901 * Arguments : 902 * container_hdl_t : container handle. 903 * 904 * Return : 905 * int 906 * On success, returns number of sections in a container. 907 * 908 */ 909 910 /* ARGSUSED */ 911 int 912 fru_get_num_sections(container_hdl_t container, door_cred_t *cred) 913 { 914 hash_obj_t *hash_object; 915 916 hash_object = lookup_handle_object(container, CONTAINER_TYPE); 917 if (hash_object == NULL) { 918 return (-1); 919 } 920 921 return (hash_object->u.cont_obj->num_of_section); 922 } 923 924 /* 925 * called from fru_get_sections() 926 */ 927 928 static void 929 get_section(int fd, hash_obj_t *sec_hash, section_t *section) 930 { 931 int retval; 932 int size; 933 int count; 934 uint16_t hdrver; 935 hash_obj_t *seg_hash; 936 unsigned char *buffer; 937 section_obj_t *sec_obj; 938 section_layout_t sec_hdr; 939 segment_layout_t *seg_hdr; 940 segment_layout_t *seg_buf; 941 942 sec_obj = sec_hash->u.sec_obj; 943 if (sec_obj == NULL) { 944 return; 945 } 946 947 /* populate section_t */ 948 section->handle = sec_hash->obj_hdl; 949 section->offset = sec_obj->section.offset; 950 section->length = sec_obj->section.length; 951 section->protection = sec_obj->section.protection; 952 section->version = sec_obj->section.version; 953 sec_obj->num_of_segment = 0; 954 955 switch (sec_obj->encoding) { 956 case ENC_STANDARD: 957 /* read section header layout */ 958 retval = pread(fd, &sec_hdr, sizeof (sec_hdr), 959 sec_obj->section.offset); 960 break; 961 962 case ENC_SPD: 963 retval = get_sp_sec_hdr(&sec_hdr, sizeof (sec_hdr)); 964 break; 965 966 default: 967 return; 968 } 969 970 if (retval != sizeof (sec_hdr)) { 971 return; 972 } 973 974 hdrver = GET_SECTION_HDR_VERSION; 975 976 if ((sec_hdr.headertag != SECTION_HDR_TAG) && 977 (hdrver != section->version)) { 978 return; 979 } 980 981 /* size = section layout + total sizeof segment header */ 982 size = sizeof (sec_hdr) + ((sec_hdr.segmentcount) * 983 sizeof (segment_layout_t)); 984 985 buffer = alloca(size); 986 if (buffer == NULL) { 987 return; 988 } 989 990 /* segment header buffer */ 991 seg_buf = alloca(size - sizeof (sec_hdr)); 992 if (seg_buf == NULL) { 993 return; 994 } 995 996 switch (sec_obj->encoding) { 997 case ENC_STANDARD: 998 /* read segment header */ 999 retval = pread(fd, seg_buf, size - sizeof (sec_hdr), 1000 sec_obj->section.offset + sizeof (sec_hdr)); 1001 break; 1002 1003 case ENC_SPD: 1004 retval = 1005 get_sp_seg_hdr(seg_buf, size - sizeof (sec_hdr)); 1006 break; 1007 1008 default: 1009 return; 1010 } 1011 1012 if (retval != (size - sizeof (sec_hdr))) { 1013 return; 1014 } 1015 1016 /* copy section header layout */ 1017 (void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr)); 1018 1019 /* copy segment header layout */ 1020 (void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size - 1021 sizeof (sec_hdr)); 1022 1023 /* verify crc8 */ 1024 retval = verify_header_crc8(hdrver, buffer, size); 1025 if (retval != TRUE) { 1026 return; 1027 } 1028 1029 section->version = hdrver; 1030 sec_obj->section.version = hdrver; 1031 1032 seg_hdr = (segment_layout_t *)seg_buf; 1033 1034 for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) { 1035 seg_hash = create_segment_hash_object(); 1036 if (seg_hash == NULL) { 1037 return; 1038 } 1039 1040 add_hashobject_to_hashtable(seg_hash); 1041 1042 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr); 1043 1044 add_to_seg_object_list(sec_hash, seg_hash); 1045 1046 sec_obj->num_of_segment++; 1047 } 1048 } 1049 1050 1051 static int 1052 call_devfsadm(void) 1053 { 1054 char *phys_path; 1055 di_node_t root_node; 1056 di_node_t prom_node; 1057 di_node_t f_node; 1058 1059 if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 1060 return (-1); 1061 } 1062 1063 f_node = di_drv_first_node(PICL_CLASS_SEEPROM, root_node); 1064 if (f_node != DI_NODE_NIL) { 1065 phys_path = di_devfs_path(f_node); 1066 if ((prom_node = di_init(phys_path, DINFOMINOR)) != 1067 DI_NODE_NIL) { 1068 di_fini(prom_node); 1069 di_fini(root_node); 1070 (void) pclose(popen(devfsadm_cmd, "r")); 1071 return (0); 1072 } 1073 } 1074 di_fini(root_node); 1075 return (-1); 1076 } 1077 1078 /* 1079 * Description : 1080 * fru_get_sections() fills an array of section structures passed 1081 * as an argument. 1082 * 1083 * Arguments : 1084 * container_hdl_t : container handle(device descriptor). 1085 * section_t : array of section structure. 1086 * int : maximum number of section in a container. 1087 * 1088 * Returns : 1089 * int 1090 * On success,the number of section structures written is returned; 1091 * on error, -1 is returned and "errno" is set appropriately. 1092 * 1093 */ 1094 1095 /* ARGSUSED */ 1096 int 1097 fru_get_sections(container_hdl_t container, section_t *section, int maxsec, 1098 door_cred_t *cred) 1099 { 1100 int device_fd; 1101 int retrys = 1; 1102 int count; 1103 hash_obj_t *cont_object; 1104 hash_obj_t *sec_hash; 1105 1106 cont_object = lookup_handle_object(container, CONTAINER_TYPE); 1107 1108 if (cont_object == NULL) { 1109 return (-1); 1110 } 1111 1112 if (cont_object->u.cont_obj->num_of_section > maxsec) { 1113 return (-1); 1114 } 1115 1116 sec_hash = cont_object->u.cont_obj->sec_obj_list; 1117 if (sec_hash == NULL) { 1118 return (-1); 1119 } 1120 1121 do { 1122 device_fd = 1123 open(cont_object->u.cont_obj->device_pathname, O_RDONLY); 1124 if (device_fd >= 0) { 1125 break; 1126 } 1127 } while ((retrys-- > 0) && (call_devfsadm() == 0)); 1128 1129 if (device_fd < 0) { 1130 return (-1); 1131 } 1132 1133 for (count = 0; count < cont_object->u.cont_obj->num_of_section; 1134 count++, section++) { 1135 section->version = -1; 1136 /* populate section_t */ 1137 get_section(device_fd, sec_hash, section); 1138 sec_hash = sec_hash->u.sec_obj->next; 1139 } 1140 1141 (void) close(device_fd); 1142 return (count); 1143 } 1144 1145 /* 1146 * Description : 1147 * fru_get_num_segments() returns the current number of segments 1148 * in a section. 1149 * 1150 * Arguments : 1151 * section_hdl_t : section header holding section information. 1152 * 1153 * Return : 1154 * int 1155 * On success, the number of segments in the argument section is 1156 * returned; on error -1 is returned. 1157 */ 1158 1159 /* ARGSUSED */ 1160 int 1161 fru_get_num_segments(section_hdl_t section, door_cred_t *cred) 1162 { 1163 hash_obj_t *sec_object; 1164 section_obj_t *sec_obj; 1165 1166 sec_object = lookup_handle_object(section, SECTION_TYPE); 1167 if (sec_object == NULL) { 1168 return (-1); 1169 } 1170 1171 sec_obj = sec_object->u.sec_obj; 1172 if (sec_obj == NULL) { 1173 return (-1); 1174 } 1175 1176 return (sec_obj->num_of_segment); 1177 } 1178 1179 /* 1180 * Description : 1181 * fru_get_segments() fills an array of structures representing the 1182 * segments in a section. 1183 * 1184 * Arguments : 1185 * section_hdl_t : holds section number. 1186 * segment_t : on success will hold segment information. 1187 * int : maximum number of segment. 1188 * 1189 * Return : 1190 * int 1191 * On success, the number of segment structures written is 1192 * returned; on errno -1 is returned. 1193 */ 1194 1195 /* ARGSUSED */ 1196 int 1197 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg, 1198 door_cred_t *cred) 1199 { 1200 int count; 1201 hash_obj_t *sec_object; 1202 hash_obj_t *seg_object; 1203 section_obj_t *sec_obj; 1204 1205 sec_object = lookup_handle_object(section, SECTION_TYPE); 1206 if (sec_object == NULL) { 1207 return (-1); 1208 } 1209 1210 sec_obj = sec_object->u.sec_obj; 1211 if (sec_obj == NULL) { 1212 return (-1); 1213 } 1214 1215 if (sec_obj->num_of_segment > maxseg) { 1216 return (-1); 1217 } 1218 1219 seg_object = sec_object->u.sec_obj->seg_obj_list; 1220 if (seg_object == NULL) { 1221 return (-1); 1222 } 1223 1224 for (count = 0; count < sec_obj->num_of_segment; count++) { 1225 1226 /* populate segment_t */ 1227 segment->handle = seg_object->obj_hdl; 1228 (void) memcpy(segment->name, 1229 seg_object->u.seg_obj->segment.name, SEG_NAME_LEN); 1230 segment->descriptor = seg_object->u.seg_obj->segment.descriptor; 1231 1232 segment->offset = seg_object->u.seg_obj->segment.offset; 1233 segment->length = seg_object->u.seg_obj->segment.length; 1234 seg_object = seg_object->u.seg_obj->next; 1235 segment++; 1236 } 1237 return (0); 1238 } 1239 1240 /* 1241 * Description : 1242 * fru_add_segment() adds a segment to a section. 1243 * 1244 * Arguments : 1245 * section_hdl_t section 1246 * A handle for the section in which to add the segment. 1247 * 1248 * segment_t *segment 1249 * On entry, the "handle" component of "segment" is ignored and the 1250 * remaining components specify the parameters of the segment to be 1251 * added. On return, the "handle" component is set to the handle 1252 * for the added segment. The segment offset is mandatory for FIXED 1253 * segments; otherwise, the offset is advisory. 1254 * 1255 * Return : 1256 * int 1257 * On success, 0 is returned; on error -1 is returned. 1258 * 1259 */ 1260 1261 int 1262 fru_add_segment(section_hdl_t section, segment_t *segment, 1263 section_hdl_t *newsection, door_cred_t *cred) 1264 { 1265 int fd; 1266 int retval; 1267 int offset; 1268 int sec_size; 1269 int seg_cnt; 1270 int bufsize; 1271 int new_seg_offset; 1272 int new_seg_length; 1273 int fixed_segment; 1274 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00 }; 1275 hash_obj_t *cont_hash; 1276 hash_obj_t *sec_hash; 1277 hash_obj_t *seg_hash; 1278 fru_segdesc_t *new_seg_desc; 1279 unsigned char *crcbuf; 1280 section_layout_t sec_layout; 1281 segment_layout_t *seg_layout; 1282 segment_layout_t *segment_buf; 1283 1284 /* check the effective uid of the client */ 1285 if (cred->dc_euid != 0) { 1286 errno = EPERM; 1287 return (-1); /* not a root */ 1288 } 1289 1290 /* section hash */ 1291 sec_hash = lookup_handle_object(section, SECTION_TYPE); 1292 if (sec_hash == NULL) { 1293 return (-1); 1294 } 1295 1296 /* check for read-only section */ 1297 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 1298 errno = EPERM; 1299 return (-1); 1300 } 1301 1302 /* look for duplicate segment */ 1303 seg_hash = sec_hash->u.sec_obj->seg_obj_list; 1304 while (seg_hash != NULL) { 1305 if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name, 1306 SEG_NAME_LEN) == 0) { 1307 errno = EEXIST; 1308 return (-1); /* can't add duplicate segment */ 1309 } 1310 seg_hash = seg_hash->u.seg_obj->next; 1311 } 1312 1313 /* get the container hash */ 1314 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 1315 CONTAINER_TYPE); 1316 if (cont_hash == NULL) { 1317 return (-1); 1318 } 1319 1320 /* open the container */ 1321 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR); 1322 if (fd < 0) { 1323 return (-1); 1324 } 1325 1326 /* section start here */ 1327 offset = sec_hash->u.sec_obj->section.offset; 1328 1329 /* read section header layout */ 1330 retval = pread(fd, &sec_layout, sizeof (sec_layout), offset); 1331 if (retval != sizeof (sec_layout)) { 1332 (void) close(fd); 1333 return (-1); 1334 } 1335 1336 /* check for valid section header */ 1337 if (sec_layout.headertag != SECTION_HDR_TAG) { 1338 /* write a new one */ 1339 sec_layout.headertag = SECTION_HDR_TAG; 1340 sec_layout.headerversion[0] = SECTION_HDR_VER_BIT0; 1341 sec_layout.headerversion[1] = SECTION_HDR_VER_BIT1; 1342 sec_layout.headerlength = sizeof (sec_layout); 1343 sec_layout.segmentcount = 0; 1344 } 1345 1346 /* section size */ 1347 sec_size = sec_hash->u.sec_obj->section.length; 1348 1349 /* number of segment in the section */ 1350 seg_cnt = sec_layout.segmentcount; 1351 1352 /* total sizeof segment + new segment */ 1353 bufsize = sizeof (segment_layout_t) * (seg_cnt + 1); 1354 segment_buf = alloca(bufsize); 1355 if (segment_buf == NULL) { 1356 return (-1); 1357 } 1358 1359 /* read entire segment header */ 1360 retval = pread(fd, segment_buf, (bufsize - sizeof (segment_layout_t)), 1361 offset + sizeof (section_layout_t)); 1362 if (retval != (bufsize - sizeof (segment_layout_t))) { 1363 (void) close(fd); 1364 return (-1); 1365 } 1366 1367 new_seg_offset = segment->offset; /* new segment offset */ 1368 new_seg_length = segment->length; /* new segment length */ 1369 1370 new_seg_desc = (fru_segdesc_t *)&segment->descriptor; 1371 1372 fixed_segment = new_seg_desc->field.fixed; 1373 1374 /* get new offset for new segment to be addedd */ 1375 retval = find_offset((char *)segment_buf, seg_cnt, sec_size, 1376 &new_seg_offset, new_seg_length, fixed_segment, fd); 1377 1378 if (retval != 0) { 1379 (void) close(fd); 1380 errno = EAGAIN; 1381 return (-1); 1382 } 1383 1384 /* copy new segment data in segment layout */ 1385 seg_layout = (segment_layout_t *)(segment_buf + seg_cnt); 1386 (void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN); 1387 (void) memcpy(seg_layout->descriptor, &segment->descriptor, 1388 sizeof (uint32_t)); 1389 seg_layout->length = segment->length; 1390 seg_layout->offset = new_seg_offset; /* new segment offset */ 1391 1392 sec_layout.segmentcount += 1; 1393 1394 crcbuf = alloca(sizeof (section_layout_t) + bufsize); 1395 if (crcbuf == NULL) { 1396 (void) close(fd); 1397 return (-1); 1398 } 1399 1400 sec_layout.headercrc8 = 0; 1401 sec_layout.headerlength += sizeof (segment_layout_t); 1402 1403 (void) memcpy(crcbuf, (char *)&sec_layout, sizeof (section_layout_t)); 1404 (void) memcpy(crcbuf + sizeof (section_layout_t), segment_buf, bufsize); 1405 1406 sec_layout.headercrc8 = compute_crc8(crcbuf, bufsize + 1407 sizeof (section_layout_t)); 1408 1409 /* write section header */ 1410 retval = pwrite(fd, &sec_layout, sizeof (section_layout_t), offset); 1411 if (retval != sizeof (section_layout_t)) { 1412 (void) close(fd); 1413 return (-1); 1414 } 1415 1416 /* write segment header */ 1417 retval = pwrite(fd, segment_buf, bufsize, offset + 1418 sizeof (section_layout_t)); 1419 if (retval != bufsize) { 1420 (void) close(fd); 1421 return (-1); 1422 } 1423 1424 /* write segment trailer */ 1425 retval = pwrite(fd, &trailer, sizeof (trailer), new_seg_offset); 1426 if (retval != sizeof (trailer)) { 1427 (void) close(fd); 1428 return (-1); 1429 } 1430 1431 (void) close(fd); 1432 1433 /* create new segment hash object */ 1434 seg_hash = create_segment_hash_object(); 1435 if (seg_hash == NULL) { 1436 return (-1); 1437 } 1438 1439 add_hashobject_to_hashtable(seg_hash); 1440 1441 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_layout); 1442 1443 add_to_seg_object_list(sec_hash, seg_hash); 1444 1445 sec_hash->u.sec_obj->num_of_segment += 1; 1446 seg_hash->u.seg_obj->trailer_offset = new_seg_offset; 1447 *newsection = section; /* return the new section handle */ 1448 return (0); 1449 } 1450 1451 static void 1452 free_pkt_object_list(hash_obj_t *hash_obj) 1453 { 1454 hash_obj_t *next_obj; 1455 hash_obj_t *free_obj; 1456 1457 next_obj = hash_obj->u.seg_obj->pkt_obj_list; 1458 while (next_obj != NULL) { 1459 free_obj = next_obj; 1460 next_obj = next_obj->u.pkt_obj->next; 1461 /* if prev is NULL it's the first object in the list */ 1462 if (free_obj->prev == NULL) { 1463 hash_table[(free_obj->obj_hdl % TABLE_SIZE)] = 1464 free_obj->next; 1465 if (free_obj->next != NULL) { 1466 free_obj->next->prev = free_obj->prev; 1467 } 1468 } else { 1469 free_obj->prev->next = free_obj->next; 1470 if (free_obj->next != NULL) { 1471 free_obj->next->prev = free_obj->prev; 1472 } 1473 } 1474 1475 free(free_obj->u.pkt_obj->payload); 1476 free(free_obj->u.pkt_obj); 1477 free(free_obj); 1478 } 1479 1480 hash_obj->u.seg_obj->pkt_obj_list = NULL; 1481 } 1482 1483 static void 1484 free_segment_hash(handle_t handle, hash_obj_t *sec_hash) 1485 { 1486 hash_obj_t *seg_hash; 1487 hash_obj_t *next_hash; 1488 1489 seg_hash = sec_hash->u.sec_obj->seg_obj_list; 1490 if (seg_hash == NULL) { 1491 return; 1492 } 1493 1494 if (seg_hash->obj_hdl == handle) { 1495 sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next; 1496 } else { 1497 while (seg_hash->obj_hdl != handle) { 1498 next_hash = seg_hash; 1499 seg_hash = seg_hash->u.seg_obj->next; 1500 if (seg_hash == NULL) { 1501 return; 1502 } 1503 } 1504 next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next; 1505 } 1506 1507 if (seg_hash->prev == NULL) { 1508 hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next; 1509 if (seg_hash->next != NULL) { 1510 seg_hash->next->prev = NULL; 1511 } 1512 } else { 1513 seg_hash->prev->next = seg_hash->next; 1514 if (seg_hash->next != NULL) { 1515 seg_hash->next->prev = seg_hash->prev; 1516 } 1517 } 1518 1519 free_pkt_object_list(seg_hash); 1520 free(seg_hash->u.seg_obj); 1521 free(seg_hash); 1522 } 1523 1524 /* 1525 * Description : 1526 * fru_delete_segment() deletes a segment from a section; the 1527 * associated container data is not altered. 1528 * 1529 * Arguments : segment_hdl_t segment handle. 1530 * section_hdl_t new section handle. 1531 * 1532 * Return : 1533 * int 1534 * On success, 0 returned; On error -1 is returned. 1535 */ 1536 1537 int 1538 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection, 1539 door_cred_t *cred) 1540 { 1541 int num_of_seg; 1542 int bufsize; 1543 int count; 1544 int retval; 1545 int fd; 1546 int segnum; 1547 hash_obj_t *seg_hash; 1548 hash_obj_t *sec_hash; 1549 hash_obj_t *cont_hash; 1550 hash_obj_t *tmp_hash; 1551 unsigned char *buffer; 1552 fru_segdesc_t *desc; 1553 segment_layout_t *seg_buf; 1554 section_layout_t *sec_layout; 1555 segment_layout_t *seg_layout; 1556 segment_layout_t *next_layout; 1557 1558 /* check the effective uid of the client */ 1559 if (cred->dc_euid != 0) { 1560 errno = EPERM; 1561 return (-1); /* not a root */ 1562 } 1563 1564 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 1565 if (seg_hash == NULL) { 1566 return (-1); 1567 } 1568 1569 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 1570 if (!(desc->field.field_perm & SEGMENT_DELETE)) { 1571 errno = EPERM; 1572 return (-1); /* can't delete this segment */ 1573 } 1574 1575 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 1576 SECTION_TYPE); 1577 if (sec_hash == NULL) { 1578 return (-1); 1579 } 1580 1581 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 1582 errno = EPERM; 1583 return (-1); 1584 } 1585 1586 num_of_seg = sec_hash->u.sec_obj->num_of_segment; 1587 1588 bufsize = (sizeof (segment_layout_t) * num_of_seg); 1589 1590 seg_buf = alloca(bufsize); 1591 if (seg_buf == NULL) { 1592 return (-1); 1593 } 1594 1595 segnum = 0; 1596 for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL; 1597 tmp_hash = tmp_hash->u.seg_obj->next) { 1598 if (tmp_hash->obj_hdl == segment) { 1599 break; 1600 } 1601 segnum++; 1602 } 1603 1604 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 1605 CONTAINER_TYPE); 1606 if (cont_hash == NULL) { 1607 return (-1); 1608 } 1609 1610 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR); 1611 if (fd < 0) { 1612 return (-1); 1613 } 1614 1615 sec_layout = alloca(sizeof (section_layout_t)); 1616 if (sec_layout == NULL) { 1617 (void) close(fd); 1618 return (-1); 1619 } 1620 1621 /* read section layout header */ 1622 retval = pread(fd, sec_layout, sizeof (section_layout_t), 1623 sec_hash->u.sec_obj->section.offset); 1624 if (retval != sizeof (section_layout_t)) { 1625 (void) close(fd); 1626 return (-1); 1627 } 1628 1629 /* read segment header layout */ 1630 retval = pread(fd, seg_buf, bufsize, 1631 sec_hash->u.sec_obj->section.offset + sizeof (section_layout_t)); 1632 if (retval != bufsize) { 1633 (void) close(fd); 1634 return (-1); 1635 } 1636 1637 seg_layout = (segment_layout_t *)(seg_buf + segnum); 1638 next_layout = seg_layout; 1639 for (count = segnum; 1640 count < sec_hash->u.sec_obj->num_of_segment - 1; count++) { 1641 next_layout++; 1642 (void) memcpy(seg_layout, next_layout, 1643 sizeof (segment_layout_t)); 1644 seg_layout++; 1645 } 1646 1647 (void) memset(seg_layout, '\0', sizeof (segment_layout_t)); 1648 1649 sec_layout->headercrc8 = 0; 1650 1651 sec_layout->headerlength -= sizeof (segment_layout_t); 1652 sec_layout->segmentcount -= 1; 1653 1654 buffer = alloca(sec_layout->headerlength); 1655 if (buffer == NULL) { 1656 (void) close(fd); 1657 return (-1); 1658 } 1659 1660 (void) memcpy(buffer, sec_layout, sizeof (section_layout_t)); 1661 (void) memcpy(buffer + sizeof (section_layout_t), seg_buf, bufsize - 1662 sizeof (segment_layout_t)); 1663 sec_layout->headercrc8 = compute_crc8(buffer, sec_layout->headerlength); 1664 1665 /* write section header with update crc8 and header length */ 1666 retval = pwrite(fd, sec_layout, sizeof (section_layout_t), 1667 sec_hash->u.sec_obj->section.offset); 1668 if (retval != sizeof (section_layout_t)) { 1669 (void) close(fd); 1670 return (-1); 1671 } 1672 1673 /* write the update segment header */ 1674 retval = pwrite(fd, seg_buf, bufsize, 1675 sec_hash->u.sec_obj->section.offset + sizeof (section_layout_t)); 1676 (void) close(fd); 1677 if (retval != bufsize) { 1678 return (-1); 1679 } 1680 1681 free_segment_hash(segment, sec_hash); 1682 1683 *newsection = sec_hash->obj_hdl; 1684 sec_hash->u.sec_obj->num_of_segment = sec_layout->segmentcount; 1685 1686 return (0); 1687 } 1688 1689 /* 1690 * Description : 1691 * fru_read_segment() reads the raw contents of a segment. 1692 * 1693 * Arguments : segment_hdl_t : segment handle. 1694 * void * : buffer containing segment data when function returns. 1695 * size_t :number of bytes. 1696 * 1697 * Return : 1698 * int 1699 * On success, the number of bytes read is returned; 1700 * 1701 * Notes : 1702 * Segments containing packets can be read in structured fashion 1703 * using the fru_get_packets() and fru_get_payload() primitives;the 1704 * entire byte range of a segment can be read using 1705 * fru_read_segment(). 1706 */ 1707 1708 /* ARGSUSED */ 1709 ssize_t 1710 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes, 1711 door_cred_t *cred) 1712 { 1713 int fd; 1714 int retval; 1715 hash_obj_t *seg_hash; 1716 hash_obj_t *sec_hash; 1717 hash_obj_t *cont_hash; 1718 1719 /* segment hash object */ 1720 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 1721 if (seg_hash == NULL) { 1722 return (-1); 1723 } 1724 1725 /* section hash object */ 1726 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 1727 SECTION_TYPE); 1728 if (sec_hash == NULL) { 1729 return (-1); 1730 } 1731 1732 /* container hash object */ 1733 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 1734 CONTAINER_TYPE); 1735 if (cont_hash == NULL) { 1736 return (-1); 1737 } 1738 1739 if (seg_hash->u.seg_obj->segment.length < nbytes) { 1740 return (-1); 1741 } 1742 1743 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDONLY); 1744 if (fd < 0) { 1745 return (-1); 1746 } 1747 1748 switch (sec_hash->u.sec_obj->encoding) { 1749 case ENC_STANDARD: 1750 retval = pread(fd, buffer, nbytes, 1751 seg_hash->u.seg_obj->segment.offset); 1752 (void) close(fd); 1753 if (retval != nbytes) { 1754 return (-1); 1755 } 1756 break; 1757 1758 case ENC_SPD: { 1759 char *spd_buf; 1760 uchar_t *ptr; 1761 size_t len; 1762 1763 spd_buf = alloca(sec_hash->u.sec_obj->section.length); 1764 if (spd_buf == NULL) 1765 retval = -1; 1766 else { 1767 retval = get_spd_data(fd, spd_buf, 1768 sec_hash->u.sec_obj->section.length, 1769 seg_hash->u.seg_obj->segment.offset); 1770 } 1771 (void) close(fd); 1772 if (retval != 0) { 1773 return (-1); 1774 } 1775 retval = cvrt_dim_data(spd_buf, 1776 sec_hash->u.sec_obj->section.length, &ptr, &len); 1777 if (retval != 0) { 1778 return (-1); 1779 } 1780 if (nbytes > len) 1781 nbytes = len; 1782 (void) memcpy(buffer, ptr, nbytes); 1783 free(ptr); 1784 break; 1785 } 1786 1787 default: 1788 return (-1); 1789 } 1790 1791 return (nbytes); 1792 } 1793 1794 /* 1795 * Description : 1796 * fru_write_segment() writes a raw segment. 1797 * 1798 * Arguments : segment_hdl_t :segment handle. 1799 * const void * : data buffer. 1800 * size_t : number of bytes. 1801 * segment_hdl_t : new segment handle. 1802 * 1803 * Returns : 1804 * int 1805 * On success, the number of bytes written is returned 1806 * 1807 */ 1808 /*ARGSUSED*/ 1809 int 1810 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes, 1811 segment_hdl_t *newsegment, door_cred_t *cred) 1812 { 1813 return (ENOTSUP); 1814 } 1815 1816 1817 static int 1818 get_packet(int device_fd, void *buffer, int size, int offset) 1819 { 1820 int retval; 1821 1822 retval = pread(device_fd, (char *)buffer, size, offset); 1823 if (retval != -1) { 1824 return (0); 1825 } 1826 return (-1); 1827 } 1828 1829 static uint32_t 1830 get_checksum_crc(hash_obj_t *seg_hash, int data_size) 1831 { 1832 int protection; 1833 int offset = 0; 1834 uint32_t crc; 1835 hash_obj_t *sec_hash; 1836 hash_obj_t *pkt_hash; 1837 unsigned char *buffer; 1838 1839 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 1840 SECTION_TYPE); 1841 if (sec_hash == NULL) { 1842 return ((uint32_t)-1); 1843 } 1844 1845 buffer = alloca(data_size); 1846 if (buffer == NULL) { 1847 return ((uint32_t)-1); 1848 } 1849 1850 /* traverse the packet object list for all the tags and payload */ 1851 for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; 1852 pkt_hash != NULL; pkt_hash = pkt_hash->u.pkt_obj->next) { 1853 (void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag, 1854 pkt_hash->u.pkt_obj->tag_size); 1855 offset += pkt_hash->u.pkt_obj->tag_size; 1856 (void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload, 1857 pkt_hash->u.pkt_obj->paylen); 1858 offset += pkt_hash->u.pkt_obj->paylen; 1859 } 1860 1861 protection = sec_hash->u.sec_obj->section.protection; 1862 1863 if (protection == READ_ONLY_SECTION) { /* read-only section */ 1864 crc = compute_crc32(buffer, data_size); 1865 } else { /* read/write section */ 1866 crc = compute_checksum32(buffer, data_size); 1867 } 1868 return (crc); /* computed crc */ 1869 } 1870 1871 static int 1872 get_dev_or_buffered_packets(hash_obj_t *seg_hash, int device_fd, int offset, 1873 int length, const char *buf) 1874 { 1875 int tag_size; 1876 int paylen; 1877 int retval; 1878 int seg_limit = 0; 1879 int pktcnt = 0; 1880 char *data; 1881 uint32_t crc; 1882 uint32_t origcrc; 1883 fru_tag_t tag; 1884 hash_obj_t *pkt_hash_obj; 1885 fru_segdesc_t *segdesc; 1886 fru_tagtype_t tagtype; 1887 1888 if (buf == NULL) { 1889 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), 1890 offset); 1891 if (retval == -1) { 1892 return (-1); 1893 } 1894 } else if (length - offset < sizeof (fru_tag_t)) { 1895 return (-1); 1896 } else { 1897 (void) memcpy(&tag, buf + offset, sizeof (fru_tag_t)); 1898 } 1899 1900 seg_hash->u.seg_obj->trailer_offset = offset; 1901 1902 data = (char *)&tag; 1903 while (data[0] != SEG_TRAILER_TAG) { 1904 tagtype = get_tag_type(&tag); /* verify tag type */ 1905 if (tagtype == -1) { 1906 return (-1); 1907 } 1908 1909 tag_size = get_tag_size(tagtype); 1910 if (tag_size == -1) { 1911 return (-1); 1912 } 1913 1914 seg_limit += tag_size; 1915 if (seg_limit > length) { 1916 return (-1); 1917 } 1918 1919 paylen = get_payload_length((void *)&tag); 1920 if (paylen == -1) { 1921 return (-1); 1922 } 1923 1924 seg_limit += paylen; 1925 if (seg_limit > length) { 1926 return (-1); 1927 } 1928 1929 pkt_hash_obj = create_packet_hash_object(); 1930 if (pkt_hash_obj == NULL) { 1931 return (-1); 1932 } 1933 1934 pkt_hash_obj->u.pkt_obj->payload = malloc(paylen); 1935 if (pkt_hash_obj->u.pkt_obj->payload == NULL) { 1936 free(pkt_hash_obj); 1937 return (-1); 1938 } 1939 1940 offset += tag_size; 1941 if (buf == NULL) { 1942 retval = pread(device_fd, 1943 pkt_hash_obj->u.pkt_obj->payload, paylen, offset); 1944 } else if (paylen + offset > length) { 1945 retval = 0; 1946 } else { 1947 (void) memcpy(pkt_hash_obj->u.pkt_obj->payload, 1948 buf + offset, paylen); 1949 retval = paylen; 1950 } 1951 if (retval != paylen) { 1952 free(pkt_hash_obj->u.pkt_obj->payload); 1953 free(pkt_hash_obj); 1954 return (-1); 1955 } 1956 1957 /* don't change this */ 1958 pkt_hash_obj->u.pkt_obj->tag.raw_data = 0; 1959 (void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size); 1960 pkt_hash_obj->u.pkt_obj->paylen = paylen; 1961 pkt_hash_obj->u.pkt_obj->tag_size = tag_size; 1962 pkt_hash_obj->u.pkt_obj->payload_offset = offset; 1963 1964 offset += paylen; 1965 1966 add_hashobject_to_hashtable(pkt_hash_obj); 1967 add_to_pkt_object_list(seg_hash, pkt_hash_obj); 1968 1969 pktcnt++; 1970 1971 if (buf == NULL) { 1972 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), 1973 offset); 1974 if (retval == -1) { 1975 return (-1); 1976 } 1977 } else if (length - offset < sizeof (fru_tag_t)) { 1978 if (length - offset > 0) { 1979 /* 1980 * not enough data for a full fru_tag_t 1981 * just return what there is 1982 */ 1983 (void) memset(&tag, 0, sizeof (fru_tag_t)); 1984 (void) memcpy(&tag, buf + offset, 1985 length - offset); 1986 } 1987 } else { 1988 (void) memcpy(&tag, buf + offset, sizeof (fru_tag_t)); 1989 } 1990 1991 data = (char *)&tag; 1992 } 1993 1994 segdesc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 1995 1996 seg_hash->u.seg_obj->trailer_offset = offset; 1997 1998 if (!segdesc->field.ignore_checksum) { 1999 crc = get_checksum_crc(seg_hash, seg_limit); 2000 offset = seg_hash->u.seg_obj->segment.offset; 2001 2002 if (buf == NULL) { 2003 retval = pread(device_fd, &origcrc, sizeof (origcrc), 2004 offset + seg_limit + 1); 2005 if (retval != sizeof (origcrc)) { 2006 return (-1); 2007 } 2008 } else if (length - offset < sizeof (origcrc)) { 2009 return (-1); 2010 } else { 2011 (void) memcpy(&origcrc, buf + seg_limit + 1, 2012 sizeof (origcrc)); 2013 } 2014 2015 if (origcrc != crc) { 2016 seg_hash->u.seg_obj->trailer_offset = offset; 2017 } 2018 } 2019 2020 return (pktcnt); 2021 } 2022 2023 static int 2024 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length) 2025 { 2026 return (get_dev_or_buffered_packets(seg_hash, device_fd, offset, 2027 length, NULL)); 2028 } 2029 2030 static int 2031 get_buffered_packets(hash_obj_t *seg_hash, const char *seg_buf, size_t seg_len) 2032 { 2033 return (get_dev_or_buffered_packets(seg_hash, -1, 0, seg_len, seg_buf)); 2034 } 2035 2036 /* 2037 * Description : 2038 * fru_get_num_packets() returns the current number of packets 2039 * in a segment. 2040 * 2041 * Arguments : segment_hdl_t : segment handle. 2042 * 2043 * Return : 2044 * int 2045 * On success, the number of packets is returned; 2046 * -1 on failure. 2047 */ 2048 int 2049 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred) 2050 { 2051 int device_fd; 2052 int pktcnt; 2053 int length; 2054 uint16_t offset; 2055 hash_obj_t *cont_hash_obj; 2056 hash_obj_t *sec_hash; 2057 hash_obj_t *seg_hash; 2058 fru_segdesc_t *segdesc; 2059 segment_obj_t *segment_object; 2060 2061 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 2062 if (seg_hash == NULL) { 2063 return (-1); 2064 } 2065 2066 segment_object = seg_hash->u.seg_obj; 2067 if (segment_object == NULL) { 2068 return (-1); 2069 } 2070 2071 segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor; 2072 if (segdesc->field.opaque) { 2073 return (0); 2074 } 2075 2076 if (seg_hash->u.seg_obj->pkt_obj_list != NULL) { 2077 return (segment_object->num_of_packets); 2078 } 2079 2080 offset = segment_object->segment.offset; 2081 length = segment_object->segment.length; 2082 2083 /* section hash object */ 2084 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2085 SECTION_TYPE); 2086 if (sec_hash == NULL) { 2087 return (-1); 2088 } 2089 2090 segment_object->num_of_packets = 0; 2091 2092 switch (sec_hash->u.sec_obj->encoding) { 2093 case ENC_STANDARD: 2094 cont_hash_obj = get_container_hash_object(SEGMENT_TYPE, 2095 segment_object->section_hdl); 2096 if (cont_hash_obj == NULL) { 2097 return (-1); 2098 } 2099 device_fd = open(cont_hash_obj->u.cont_obj->device_pathname, 2100 O_RDWR); 2101 if (device_fd < 0) { 2102 return (-1); 2103 } 2104 2105 pktcnt = get_packets(seg_hash, device_fd, offset, length); 2106 (void) close(device_fd); 2107 break; 2108 2109 case ENC_SPD: { 2110 ssize_t spd_seg_len; 2111 size_t nbytes; 2112 char *seg_buf; 2113 2114 nbytes = segment_object->segment.length; 2115 seg_buf = alloca(nbytes); 2116 if (seg_buf == NULL) 2117 return (-1); 2118 spd_seg_len = 2119 fru_read_segment(segment, seg_buf, nbytes, cred); 2120 if (spd_seg_len < 0) 2121 return (-1); 2122 pktcnt = get_buffered_packets(seg_hash, seg_buf, 2123 spd_seg_len); 2124 break; 2125 } 2126 2127 default: 2128 return (-1); 2129 } 2130 2131 if (pktcnt == -1) { 2132 free_pkt_object_list(seg_hash); 2133 seg_hash->u.seg_obj->pkt_obj_list = NULL; 2134 } 2135 2136 segment_object->num_of_packets = pktcnt; 2137 2138 return (segment_object->num_of_packets); 2139 } 2140 2141 2142 /* 2143 * Description : 2144 * fru_get_packets() fills an array of structures representing the 2145 * packets in a segment. 2146 * 2147 * Arguments : segment_hdl_t : segment handle. 2148 * packet_t : packet buffer. 2149 * int : maximum number of packets. 2150 * 2151 * Return : 2152 * int 2153 * On success, the number of packet structures written is returned; 2154 * On failure -1 is returned; 2155 * 2156 */ 2157 2158 /* ARGSUSED */ 2159 int 2160 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets, 2161 door_cred_t *cred) 2162 { 2163 int count; 2164 hash_obj_t *seg_hash_obj; 2165 hash_obj_t *pkt_hash_obj; 2166 2167 /* segment hash object */ 2168 seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE); 2169 if (seg_hash_obj == NULL) { 2170 return (-1); 2171 } 2172 2173 if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) { 2174 return (-1); 2175 } 2176 2177 pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list; 2178 if (pkt_hash_obj == NULL) { 2179 return (-1); 2180 } 2181 2182 for (count = 0; count < maxpackets; count++, packet++) { 2183 packet->handle = pkt_hash_obj->obj_hdl; 2184 packet->tag = 0; 2185 (void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag, 2186 pkt_hash_obj->u.pkt_obj->tag_size); 2187 pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next; 2188 } 2189 2190 return (0); 2191 } 2192 2193 /* 2194 * Description : 2195 * fru_get_payload() copies the contents of a packet's payload. 2196 * 2197 * Arguments : packet_hdl_t : packet handle. 2198 * void * : payload buffer. 2199 * size_t : sizeof the buffer. 2200 * 2201 * Return : 2202 * int 2203 * On success, the number of bytes copied is returned; On error 2204 * -1 returned. 2205 */ 2206 2207 /* ARGSUSED */ 2208 ssize_t 2209 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes, 2210 door_cred_t *cred) 2211 { 2212 hash_obj_t *packet_hash_obj; 2213 2214 /* packet hash object */ 2215 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE); 2216 if (packet_hash_obj == NULL) { 2217 return (-1); 2218 } 2219 2220 /* verify payload length */ 2221 if (nbytes != packet_hash_obj->u.pkt_obj->paylen) { 2222 return (-1); 2223 } 2224 2225 (void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes); 2226 return (nbytes); 2227 } 2228 2229 /* 2230 * Description : 2231 * fru_update_payload() writes the contents of a packet's payload. 2232 * 2233 * Arguments : packet_hdl_t : packet handle. 2234 * const void * : data buffer. 2235 * size_t : buffer size. 2236 * packet_hdl_t : new packet handle. 2237 * 2238 * Return : 2239 * int 2240 * On success, 0 is returned; on failure 2241 * -1 is returned. 2242 */ 2243 2244 int 2245 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes, 2246 packet_hdl_t *newpacket, door_cred_t *cred) 2247 { 2248 int fd; 2249 int segment_offset; 2250 int trailer_offset; 2251 int retval; 2252 uint32_t crc; 2253 hash_obj_t *pkt_hash; 2254 hash_obj_t *seg_hash; 2255 hash_obj_t *sec_hash; 2256 hash_obj_t *cont_hash; 2257 fru_segdesc_t *desc; 2258 2259 /* check the effective uid of the client */ 2260 if (cred->dc_euid != 0) { 2261 errno = EPERM; 2262 return (-1); /* not a root */ 2263 } 2264 2265 /* packet hash object */ 2266 pkt_hash = lookup_handle_object(packet, PACKET_TYPE); 2267 if (pkt_hash == NULL) { 2268 return (-1); 2269 } 2270 2271 /* segment hash object */ 2272 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl, 2273 SEGMENT_TYPE); 2274 if (seg_hash == NULL) { 2275 return (-1); 2276 } 2277 2278 /* check for write perm. */ 2279 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2280 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2281 errno = EPERM; 2282 return (-1); /* write not allowed */ 2283 } 2284 2285 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2286 SECTION_TYPE); 2287 if (sec_hash == NULL) { 2288 return (-1); 2289 } 2290 2291 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2292 errno = EPERM; 2293 return (-1); /* read-only section */ 2294 } 2295 2296 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2297 CONTAINER_TYPE); 2298 if (cont_hash == NULL) { 2299 return (-1); 2300 } 2301 2302 if (pkt_hash->u.pkt_obj->paylen != nbytes) { 2303 return (-1); 2304 } 2305 2306 (void) memcpy(pkt_hash->u.pkt_obj->payload, (char *)data, nbytes); 2307 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR); 2308 if (fd < 0) { 2309 return (-1); 2310 } 2311 2312 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2313 segment_offset = seg_hash->u.seg_obj->segment.offset; 2314 2315 crc = get_checksum_crc(seg_hash, (trailer_offset - segment_offset)); 2316 retval = pwrite(fd, data, nbytes, pkt_hash->u.pkt_obj->payload_offset); 2317 if (retval != nbytes) { 2318 (void) close(fd); 2319 return (-1); 2320 } 2321 2322 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1); 2323 (void) close(fd); 2324 if (retval != sizeof (crc)) { 2325 return (-1); 2326 } 2327 *newpacket = packet; 2328 return (0); 2329 } 2330 2331 /* 2332 * Description : 2333 * fru_append_packet() appends a packet to a segment. 2334 * 2335 * Arguments : 2336 * segment_hdl_t segment 2337 * A handle for the segment to which the packet will be appended. 2338 * 2339 * packet_t *packet 2340 * On entry, the "tag" component of "packet" specifies the tag 2341 * value for the added packet; the "handle" component is ignored. 2342 * On return, the "handle" component is set to the handle of the 2343 * appended packet. 2344 * 2345 * const void *payload 2346 * A pointer to the caller's buffer containing the payload data for 2347 * the appended packet. 2348 * 2349 * size_t nbytes 2350 * The size of the caller buffer. 2351 * 2352 * Return : 2353 * int 2354 * On success, 0 is returned; on error -1 is returned; 2355 */ 2356 2357 int 2358 fru_append_packet(segment_hdl_t segment, packet_t *packet, const void *payload, 2359 size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred) 2360 { 2361 int trailer_offset; 2362 int tag_size; 2363 int fd; 2364 int retval; 2365 char trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00}; 2366 uint32_t crc; 2367 hash_obj_t *seg_hash; 2368 hash_obj_t *sec_hash; 2369 hash_obj_t *pkt_hash; 2370 hash_obj_t *cont_hash; 2371 fru_tagtype_t tagtype; 2372 fru_segdesc_t *desc; 2373 2374 /* check the effective uid of the client */ 2375 if (cred->dc_euid != 0) { 2376 errno = EPERM; 2377 return (-1); /* not a root */ 2378 } 2379 2380 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 2381 if (seg_hash == NULL) { 2382 return (-1); 2383 } 2384 2385 /* check for write perm. */ 2386 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2387 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2388 errno = EPERM; 2389 return (-1); /* write not allowed */ 2390 } 2391 2392 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2393 SECTION_TYPE); 2394 if (sec_hash == NULL) { 2395 return (-1); 2396 } 2397 2398 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2399 errno = EPERM; 2400 return (-1); /* read-only section */ 2401 } 2402 2403 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2404 2405 /* 2406 * if trailer offset is 0 than parse the segment data to get the trailer 2407 * offset to compute the remaining space left in the segment area for 2408 * new packet to be added. 2409 */ 2410 if (trailer_offset == 0) { 2411 (void) fru_get_num_packets(segment, cred); 2412 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2413 } 2414 2415 tagtype = get_tag_type((void *)&packet->tag); 2416 if (tagtype == -1) { 2417 return (-1); 2418 } 2419 2420 tag_size = get_tag_size(tagtype); 2421 if (tag_size == -1) { 2422 return (-1); 2423 } 2424 2425 if (seg_hash->u.seg_obj->segment.length > 2426 ((trailer_offset - seg_hash->u.seg_obj->segment.offset) + 2427 tag_size + nbytes + sizeof (char) + sizeof (uint32_t))) { 2428 /* create new packet hash */ 2429 pkt_hash = create_packet_hash_object(); 2430 if (pkt_hash == NULL) { 2431 return (-1); 2432 } 2433 2434 /* tag initialization */ 2435 (void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag, 2436 tag_size); 2437 pkt_hash->u.pkt_obj->tag_size = tag_size; 2438 2439 /* payload inititalization */ 2440 pkt_hash->u.pkt_obj->payload = malloc(nbytes); 2441 if (pkt_hash->u.pkt_obj->payload == NULL) { 2442 free(pkt_hash); 2443 return (-1); 2444 } 2445 2446 (void) memcpy(pkt_hash->u.pkt_obj->payload, payload, nbytes); 2447 pkt_hash->u.pkt_obj->paylen = nbytes; 2448 pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size; 2449 2450 /* add to hash table */ 2451 add_hashobject_to_hashtable(pkt_hash); 2452 2453 add_to_pkt_object_list(seg_hash, pkt_hash); 2454 2455 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2456 CONTAINER_TYPE); 2457 if (cont_hash == NULL) { 2458 return (-1); 2459 } 2460 2461 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR); 2462 if (fd < 0) { 2463 return (-1); 2464 } 2465 2466 /* update the trailer offset */ 2467 trailer_offset += tag_size + nbytes; 2468 2469 /* calculate new checksum */ 2470 crc = get_checksum_crc(seg_hash, (trailer_offset - 2471 seg_hash->u.seg_obj->segment.offset)); 2472 2473 retval = pwrite(fd, &packet->tag, tag_size, 2474 trailer_offset - (tag_size + nbytes)); 2475 if (retval != tag_size) { 2476 (void) close(fd); 2477 return (-1); 2478 } 2479 2480 retval = pwrite(fd, payload, nbytes, trailer_offset - nbytes); 2481 if (retval != nbytes) { 2482 (void) close(fd); 2483 return (-1); 2484 } 2485 2486 retval = pwrite(fd, trailer, sizeof (trailer), trailer_offset); 2487 if (retval != sizeof (trailer)) { 2488 (void) close(fd); 2489 return (-1); 2490 } 2491 2492 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1); 2493 (void) close(fd); 2494 if (retval != sizeof (crc)) { 2495 return (-1); 2496 } 2497 2498 seg_hash->u.seg_obj->trailer_offset = trailer_offset; 2499 seg_hash->u.seg_obj->num_of_packets += 1; 2500 2501 *newsegment = segment; /* return new segment handle */ 2502 return (0); 2503 } else { 2504 errno = EAGAIN; 2505 } 2506 2507 return (-1); 2508 } 2509 2510 static void 2511 adjust_packets(int fd, hash_obj_t *free_obj, hash_obj_t *object_list) 2512 { 2513 int retval; 2514 uint32_t new_offset; 2515 hash_obj_t *hash_ptr; 2516 2517 new_offset = free_obj->u.pkt_obj->payload_offset - 2518 free_obj->u.pkt_obj->tag_size; 2519 for (hash_ptr = object_list; 2520 hash_ptr != NULL; hash_ptr = hash_ptr->u.pkt_obj->next) { 2521 retval = pwrite(fd, &hash_ptr->u.pkt_obj->tag, 2522 hash_ptr->u.pkt_obj->tag_size, new_offset); 2523 if (retval != hash_ptr->u.pkt_obj->tag_size) { 2524 return; 2525 } 2526 new_offset += hash_ptr->u.pkt_obj->tag_size; 2527 hash_ptr->u.pkt_obj->payload_offset = new_offset; 2528 retval = pwrite(fd, hash_ptr->u.pkt_obj->payload, 2529 hash_ptr->u.pkt_obj->paylen, new_offset); 2530 if (retval != hash_ptr->u.pkt_obj->paylen) { 2531 return; 2532 } 2533 new_offset += hash_ptr->u.pkt_obj->paylen; 2534 } 2535 } 2536 2537 static void 2538 free_packet_object(handle_t handle, hash_obj_t *seg_hash) 2539 { 2540 hash_obj_t *pkt_hash; 2541 hash_obj_t *next_hash; 2542 2543 pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; 2544 if (pkt_hash == NULL) { 2545 return; 2546 } 2547 2548 if (pkt_hash->obj_hdl == handle) { 2549 seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next; 2550 } else { 2551 while (pkt_hash->obj_hdl != handle) { 2552 next_hash = pkt_hash; 2553 pkt_hash = pkt_hash->u.pkt_obj->next; 2554 if (pkt_hash == NULL) { 2555 return; 2556 } 2557 } 2558 next_hash->u.pkt_obj->next = pkt_hash->u.pkt_obj->next; 2559 } 2560 2561 if (pkt_hash->prev == NULL) { 2562 hash_table[(pkt_hash->obj_hdl % TABLE_SIZE)] = pkt_hash->next; 2563 if (pkt_hash->next != NULL) { 2564 pkt_hash->next->prev = NULL; 2565 } 2566 } else { 2567 pkt_hash->prev->next = pkt_hash->next; 2568 if (pkt_hash->next != NULL) { 2569 pkt_hash->next->prev = pkt_hash->prev; 2570 } 2571 } 2572 2573 free(pkt_hash->u.pkt_obj->payload); 2574 free(pkt_hash->u.pkt_obj); 2575 free(pkt_hash); 2576 } 2577 2578 /* 2579 * Description : 2580 * fru_delete_packet() deletes a packet from a segment. 2581 * 2582 * Arguments : packet_hdl_t : packet number to be deleted. 2583 * segment_hdl_t : new segment handler. 2584 * 2585 * Return : 2586 * int 2587 * On success, 0 is returned; on error, -1. 2588 * 2589 * NOTES 2590 * Packets are adjacent; thus, deleting a packet requires moving 2591 * succeeding packets to compact the resulting hole. 2592 */ 2593 2594 int 2595 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment, 2596 door_cred_t *cred) 2597 { 2598 int retval; 2599 int fd; 2600 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00}; 2601 uint32_t crc; 2602 hash_obj_t *tmp_obj; 2603 hash_obj_t *pkt_hash; 2604 hash_obj_t *sec_hash; 2605 hash_obj_t *cont_hash; 2606 hash_obj_t *prev_obj; 2607 hash_obj_t *seg_hash; 2608 fru_segdesc_t *desc; 2609 2610 /* check the effective uid of the client */ 2611 if (cred->dc_euid != 0) { 2612 errno = EPERM; 2613 return (-1); /* not a root */ 2614 } 2615 2616 /* packet hash object */ 2617 pkt_hash = lookup_handle_object(packet, PACKET_TYPE); 2618 if (pkt_hash == NULL) { 2619 return (-1); 2620 } 2621 2622 /* segment hash object */ 2623 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl, 2624 SEGMENT_TYPE); 2625 if (seg_hash == NULL) { 2626 return (-1); 2627 } 2628 2629 /* check for write perm. */ 2630 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2631 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2632 errno = EPERM; 2633 return (-1); /* write not allowed */ 2634 } 2635 2636 /* section hash object */ 2637 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2638 SECTION_TYPE); 2639 if (sec_hash == NULL) { 2640 return (-1); 2641 } 2642 2643 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2644 errno = EPERM; 2645 return (-1); /* read-only section */ 2646 } 2647 2648 prev_obj = seg_hash->u.seg_obj->pkt_obj_list; 2649 if (prev_obj == NULL) { 2650 return (-1); 2651 } 2652 2653 /* container hash object */ 2654 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2655 CONTAINER_TYPE); 2656 if (cont_hash == NULL) { 2657 return (-1); 2658 } 2659 2660 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR); 2661 if (fd < 0) { 2662 return (-1); 2663 } 2664 2665 if (prev_obj->obj_hdl == packet) { /* first object to be deleted */ 2666 adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next); 2667 seg_hash->u.seg_obj->trailer_offset -= 2668 (prev_obj->u.pkt_obj->tag_size + 2669 prev_obj->u.pkt_obj->paylen); 2670 free_packet_object(packet, seg_hash); 2671 } else { 2672 for (tmp_obj = prev_obj; 2673 tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) { 2674 /* found the object */ 2675 if (tmp_obj->obj_hdl == packet) { 2676 adjust_packets(fd, tmp_obj, 2677 tmp_obj->u.pkt_obj->next); 2678 seg_hash->u.seg_obj->trailer_offset -= 2679 (tmp_obj->u.pkt_obj->tag_size + 2680 tmp_obj->u.pkt_obj->paylen); 2681 free_packet_object(packet, seg_hash); 2682 } 2683 } 2684 } 2685 2686 seg_hash->u.seg_obj->num_of_packets -= 1; 2687 2688 /* calculate checksum */ 2689 crc = get_checksum_crc(seg_hash, (seg_hash->u.seg_obj->trailer_offset - 2690 seg_hash->u.seg_obj->segment.offset)); 2691 /* write trailer at new offset */ 2692 retval = pwrite(fd, &trailer, sizeof (trailer), 2693 seg_hash->u.seg_obj->trailer_offset); 2694 if (retval != sizeof (trailer)) { 2695 (void) close(fd); 2696 return (-1); 2697 } 2698 2699 /* write the checksum value */ 2700 retval = pwrite(fd, &crc, sizeof (crc), 2701 seg_hash->u.seg_obj->trailer_offset + 1); 2702 (void) close(fd); 2703 if (retval != sizeof (crc)) { 2704 return (-1); 2705 } 2706 2707 *newsegment = seg_hash->obj_hdl; /* return new segment handle */ 2708 return (0); 2709 } 2710 2711 /* 2712 * Description : 2713 * fru_close_container() removes the association between a 2714 * container and its handle. this routines free's up all the 2715 * hash object contained under container. 2716 * 2717 * Arguments : 2718 * container_hdl_t holds the file descriptor of the fru. 2719 * 2720 * Return : 2721 * int 2722 * return 0. 2723 * 2724 */ 2725 2726 /* ARGSUSED */ 2727 int 2728 fru_close_container(container_hdl_t container) 2729 { 2730 hash_obj_t *hash_obj; 2731 hash_obj_t *prev_hash; 2732 hash_obj_t *sec_hash_obj; 2733 handle_t obj_hdl; 2734 2735 /* lookup for container hash object */ 2736 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 2737 if (hash_obj == NULL) { 2738 return (0); 2739 } 2740 2741 /* points to section object list */ 2742 sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list; 2743 2744 /* traverse section object list */ 2745 while (sec_hash_obj != NULL) { 2746 2747 /* traverse segment hash object in the section */ 2748 while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) { 2749 /* object handle of the segment hash object */ 2750 obj_hdl = 2751 sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl; 2752 free_segment_hash(obj_hdl, sec_hash_obj); 2753 } 2754 2755 /* going to free section hash object, relink the hash object */ 2756 if (sec_hash_obj->prev == NULL) { 2757 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] = 2758 sec_hash_obj->next; 2759 if (sec_hash_obj->next != NULL) { 2760 sec_hash_obj->next->prev = NULL; 2761 } 2762 } else { 2763 sec_hash_obj->prev->next = sec_hash_obj->next; 2764 if (sec_hash_obj->next != NULL) { 2765 sec_hash_obj->next->prev = sec_hash_obj->prev; 2766 } 2767 } 2768 2769 prev_hash = sec_hash_obj; 2770 2771 sec_hash_obj = sec_hash_obj->u.sec_obj->next; 2772 2773 free(prev_hash->u.sec_obj); /* free section hash object */ 2774 free(prev_hash); /* free section hash */ 2775 } 2776 2777 /* free container hash object */ 2778 if (hash_obj->prev == NULL) { 2779 hash_table[(hash_obj->obj_hdl % TABLE_SIZE)] = hash_obj->next; 2780 if (hash_obj->next != NULL) { 2781 hash_obj->next->prev = NULL; 2782 } 2783 } else { 2784 hash_obj->prev->next = hash_obj->next; 2785 if (hash_obj->next != NULL) { 2786 hash_obj->next->prev = hash_obj->prev; 2787 } 2788 } 2789 2790 free(hash_obj->u.cont_obj); 2791 free(hash_obj); 2792 return (0); 2793 } 2794 2795 /* 2796 * Description : 2797 * fru_is_data_available() checks to see if the frudata 2798 * is available on a fru. 2799 * 2800 * Arguments : 2801 * picl_nodehdl_t holds the picl node handle of the fru. 2802 * 2803 * Return : 2804 * int 2805 * return 1: if FRUID information is available 2806 * return 0: if FRUID information is not present 2807 * 2808 */ 2809 2810 /* ARGSUSED */ 2811 int 2812 fru_is_data_available(picl_nodehdl_t fru) 2813 { 2814 return (0); 2815 } 2816