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