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