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