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