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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <picl.h> 29 #include <limits.h> 30 #include <alloca.h> 31 #include <stdarg.h> 32 #include "smc_if.h" 33 #include "fru_access_impl.h" 34 35 #pragma init(initialize_fruaccess) /* .init section */ 36 37 /* 38 * This module translates all the frudata plugin requests into platform 39 * specific commands and provides information back to frudata plugin. 40 */ 41 42 /* 43 * precedence for format. 44 * define an ENV variable (SUNW_FRUACCESS_IPMI_PRECEDENCE) to make 45 * ipmi format has more precedence than sun format. 46 */ 47 static int precedence = SUN_FORMAT; /* by default */ 48 #define FRUACCESS_PRECEDENCE "SUNW_FRUACCESS_IPMI_PRECEDENCE" 49 50 extern ssize_t pread_new(int, void *, size_t, off_t, format_t *); 51 extern ssize_t pwrite_new(int, const void *, size_t, off_t, format_t *); 52 extern int get_manr(format_t *, payload_t *); 53 extern int is_fru_data_available(int, int, format_t *); 54 extern picl_errno_t fruaccess_platmod_init_format(uint8_t, format_t *); 55 extern int fruaccess_platmod_check_chassis(); 56 extern int fruaccess_platmod_check_fru(picl_nodehdl_t parenth); 57 58 static container_hdl_t sun_fru_open_container(picl_nodehdl_t); 59 static int sun_fru_close_container(container_hdl_t); 60 static int sun_fru_get_num_sections(container_hdl_t, door_cred_t *); 61 static int sun_fru_get_sections(container_hdl_t, section_t *, 62 int, door_cred_t *); 63 static int sun_fru_get_num_segments(section_hdl_t, door_cred_t *); 64 static int sun_fru_get_segments(section_hdl_t, segment_t *, 65 int, door_cred_t *); 66 static int sun_fru_add_segment(section_hdl_t, segment_t *, 67 section_hdl_t *, door_cred_t *); 68 static int sun_fru_delete_segment(segment_hdl_t, section_hdl_t *, 69 door_cred_t *); 70 static ssize_t sun_fru_read_segment(segment_hdl_t, void *, size_t, 71 door_cred_t *); 72 static int sun_fru_write_segment(segment_hdl_t, const void *, size_t, 73 segment_hdl_t *, door_cred_t *); 74 static int sun_fru_get_num_packets(segment_hdl_t, door_cred_t *); 75 static int sun_fru_get_packets(segment_hdl_t, packet_t *, 76 int, door_cred_t *); 77 static ssize_t sun_fru_get_payload(packet_hdl_t, void *, size_t, 78 door_cred_t *); 79 static int sun_fru_update_payload(packet_hdl_t, const void *, size_t, 80 packet_hdl_t *, door_cred_t *); 81 static int sun_fru_append_packet(segment_hdl_t, packet_t *, 82 const void *, size_t, segment_hdl_t *, 83 door_cred_t *); 84 static int sun_fru_delete_packet(packet_hdl_t, segment_hdl_t *, door_cred_t *); 85 86 static container_hdl_t ipmi_fru_open_container(picl_nodehdl_t); 87 static int ipmi_fru_close_container(container_hdl_t); 88 static int ipmi_fru_get_num_sections(container_hdl_t, door_cred_t *); 89 static int ipmi_fru_get_sections(container_hdl_t, section_t *, 90 int, door_cred_t *); 91 static int ipmi_fru_get_num_segments(section_hdl_t, door_cred_t *); 92 static int ipmi_fru_get_segments(section_hdl_t, segment_t *, 93 int, door_cred_t *); 94 static int ipmi_fru_add_segment(section_hdl_t, segment_t *, 95 section_hdl_t *, door_cred_t *); 96 static int ipmi_fru_delete_segment(segment_hdl_t, section_hdl_t *, 97 door_cred_t *); 98 static ssize_t ipmi_fru_read_segment(segment_hdl_t, void *, size_t, 99 door_cred_t *); 100 static int ipmi_fru_write_segment(segment_hdl_t, const void *, size_t, 101 segment_hdl_t *, door_cred_t *); 102 static int ipmi_fru_get_num_packets(segment_hdl_t, door_cred_t *); 103 static int ipmi_fru_get_packets(segment_hdl_t, packet_t *, 104 int, door_cred_t *); 105 static ssize_t ipmi_fru_get_payload(packet_hdl_t, void *, size_t, 106 door_cred_t *); 107 static int ipmi_fru_update_payload(packet_hdl_t, const void *, size_t, 108 packet_hdl_t *, door_cred_t *); 109 static int ipmi_fru_append_packet(segment_hdl_t, packet_t *, 110 const void *, size_t, segment_hdl_t *, 111 door_cred_t *); 112 static int ipmi_fru_delete_packet(packet_hdl_t, segment_hdl_t *, door_cred_t *); 113 114 typedef struct { 115 container_hdl_t (* open_container)(picl_nodehdl_t); 116 int (* close_container)(container_hdl_t); 117 int (* get_num_sections)(container_hdl_t, door_cred_t *); 118 int (* get_sections)(container_hdl_t, section_t *, 119 int, door_cred_t *); 120 int (* get_num_segments)(section_hdl_t, door_cred_t *); 121 int (* get_segments)(section_hdl_t, segment_t *, 122 int, door_cred_t *); 123 int (* add_segment)(section_hdl_t, segment_t *, 124 section_hdl_t *, door_cred_t *); 125 int (* delete_segment)(segment_hdl_t, section_hdl_t *, 126 door_cred_t *); 127 ssize_t (* read_segment)(segment_hdl_t, void *, size_t, 128 door_cred_t *); 129 int (* write_segment)(segment_hdl_t, const void *, size_t, 130 segment_hdl_t *, door_cred_t *); 131 int (* get_num_packets)(segment_hdl_t, door_cred_t *); 132 int (* get_packets)(segment_hdl_t, packet_t *, 133 int, door_cred_t *); 134 ssize_t (* get_payload)(packet_hdl_t, void *, size_t, 135 door_cred_t *); 136 int (* update_payload)(packet_hdl_t, const void *, size_t, 137 packet_hdl_t *, door_cred_t *); 138 int (* append_packet)(segment_hdl_t, packet_t *, 139 const void *, size_t, segment_hdl_t *, 140 door_cred_t *); 141 int (* delete_packet)(packet_hdl_t, segment_hdl_t *, door_cred_t *); 142 } fruaccess_func_ptrs_t; 143 144 static fruaccess_func_ptrs_t fruaccess_func[2] = { 145 { 146 ipmi_fru_open_container, 147 ipmi_fru_close_container, 148 ipmi_fru_get_num_sections, 149 ipmi_fru_get_sections, 150 ipmi_fru_get_num_segments, 151 ipmi_fru_get_segments, 152 ipmi_fru_add_segment, 153 ipmi_fru_delete_segment, 154 ipmi_fru_read_segment, 155 ipmi_fru_write_segment, 156 ipmi_fru_get_num_packets, 157 ipmi_fru_get_packets, 158 ipmi_fru_get_payload, 159 ipmi_fru_update_payload, 160 ipmi_fru_append_packet, 161 ipmi_fru_delete_packet, 162 }, 163 { 164 sun_fru_open_container, 165 sun_fru_close_container, 166 sun_fru_get_num_sections, 167 sun_fru_get_sections, 168 sun_fru_get_num_segments, 169 sun_fru_get_segments, 170 sun_fru_add_segment, 171 sun_fru_delete_segment, 172 sun_fru_read_segment, 173 sun_fru_write_segment, 174 sun_fru_get_num_packets, 175 sun_fru_get_packets, 176 sun_fru_get_payload, 177 sun_fru_update_payload, 178 sun_fru_append_packet, 179 sun_fru_delete_packet, 180 }, 181 }; 182 183 static int is_valid_chassis = -1; 184 static hash_obj_t *hash_table[TABLE_SIZE]; 185 186 static void 187 initialize_fruaccess(void) 188 { 189 int count; 190 for (count = 0; count < TABLE_SIZE; count++) { 191 hash_table[count] = NULL; 192 } 193 194 /* check if ipmi format has precedence */ 195 if (getenv(FRUACCESS_PRECEDENCE)) { 196 precedence = IPMI_FORMAT; 197 } 198 } 199 200 /* called to lookup hash object for specified handle in the hash table. */ 201 static hash_obj_t * 202 lookup_handle_object(handle_t handle, int object_type) 203 { 204 handle_t index_to_hash; 205 hash_obj_t *first_hash_obj; 206 hash_obj_t *next_hash_obj; 207 208 index_to_hash = (handle % TABLE_SIZE); 209 210 first_hash_obj = hash_table[index_to_hash]; 211 for (next_hash_obj = first_hash_obj; next_hash_obj != NULL; 212 next_hash_obj = next_hash_obj->next) { 213 if ((handle == next_hash_obj->obj_hdl) && 214 (object_type == next_hash_obj->object_type)) { 215 return (next_hash_obj); 216 } 217 } 218 return (NULL); 219 } 220 221 /* called to allocate container hash object */ 222 static hash_obj_t * 223 create_container_hash_object(void) 224 { 225 hash_obj_t *hash_obj; 226 container_obj_t *cont_obj; 227 228 cont_obj = malloc(sizeof (container_obj_t)); 229 if (cont_obj == NULL) { 230 return (NULL); 231 } 232 233 hash_obj = malloc(sizeof (hash_obj_t)); 234 if (hash_obj == NULL) { 235 free(cont_obj); 236 return (NULL); 237 } 238 239 cont_obj->sec_obj_list = NULL; 240 241 hash_obj->object_type = CONTAINER_TYPE; 242 hash_obj->u.cont_obj = cont_obj; 243 hash_obj->next = NULL; 244 hash_obj->prev = NULL; 245 246 return (hash_obj); 247 } 248 249 /* called to allocate section hash object */ 250 static hash_obj_t * 251 create_section_hash_object(void) 252 { 253 hash_obj_t *hash_obj; 254 section_obj_t *sec_obj; 255 256 sec_obj = malloc(sizeof (section_obj_t)); 257 if (sec_obj == NULL) { 258 return (NULL); 259 } 260 261 hash_obj = malloc(sizeof (hash_obj_t)); 262 if (hash_obj == NULL) { 263 free(sec_obj); 264 return (NULL); 265 } 266 267 sec_obj->next = NULL; 268 sec_obj->seg_obj_list = NULL; 269 270 hash_obj->u.sec_obj = sec_obj; 271 hash_obj->object_type = SECTION_TYPE; 272 hash_obj->next = NULL; 273 hash_obj->prev = NULL; 274 275 return (hash_obj); 276 } 277 278 /* called to allocate segment hash object */ 279 static hash_obj_t * 280 create_segment_hash_object(void) 281 { 282 hash_obj_t *hash_obj; 283 segment_obj_t *seg_obj; 284 285 seg_obj = malloc(sizeof (segment_obj_t)); 286 if (seg_obj == NULL) { 287 return (NULL); 288 } 289 290 hash_obj = malloc(sizeof (hash_obj_t)); 291 if (hash_obj == NULL) { 292 free(seg_obj); 293 return (NULL); 294 } 295 296 seg_obj->next = NULL; 297 seg_obj->pkt_obj_list = NULL; 298 299 hash_obj->object_type = SEGMENT_TYPE; 300 hash_obj->u.seg_obj = seg_obj; 301 hash_obj->next = NULL; 302 hash_obj->prev = NULL; 303 304 return (hash_obj); 305 } 306 307 /* called to allocate packet hash object */ 308 static hash_obj_t * 309 create_packet_hash_object(void) 310 { 311 hash_obj_t *hash_obj; 312 packet_obj_t *pkt_obj; 313 314 pkt_obj = malloc(sizeof (packet_obj_t)); 315 if (pkt_obj == NULL) { 316 return (NULL); 317 } 318 319 hash_obj = malloc(sizeof (hash_obj_t)); 320 if (hash_obj == NULL) { 321 free(pkt_obj); 322 return (NULL); 323 } 324 325 pkt_obj->next = NULL; 326 327 hash_obj->object_type = PACKET_TYPE; 328 hash_obj->u.pkt_obj = pkt_obj; 329 hash_obj->next = NULL; 330 hash_obj->prev = NULL; 331 332 return (hash_obj); 333 } 334 335 /* called to add allocated hash object into the hash table */ 336 static void 337 add_hashobject_to_hashtable(hash_obj_t *hash_obj, int object_type) 338 { 339 handle_t index_to_hash; 340 static uint64_t handle_count = 0; 341 342 if (object_type != CONTAINER_TYPE) { 343 hash_obj->obj_hdl = ++handle_count; 344 } 345 346 /* where to add ? */ 347 index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE); 348 349 hash_obj->next = hash_table[index_to_hash]; 350 hash_table[index_to_hash] = hash_obj; /* hash obj. added */ 351 352 if (hash_obj->next != NULL) { 353 hash_obj->next->prev = hash_obj; 354 } 355 } 356 357 /* called to add section object list into the section list */ 358 static void 359 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 360 { 361 hash_obj_t *next_hash; 362 363 child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl; 364 if (parent_obj->u.cont_obj->sec_obj_list == NULL) { 365 parent_obj->u.cont_obj->sec_obj_list = child_obj; 366 return; 367 } 368 369 for (next_hash = parent_obj->u.cont_obj->sec_obj_list; 370 next_hash->u.sec_obj->next != NULL; 371 next_hash = next_hash->u.sec_obj->next) { 372 ; 373 } 374 375 next_hash->u.sec_obj->next = child_obj; 376 } 377 378 /* called to add segment object list into segment list */ 379 static void 380 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 381 { 382 hash_obj_t *next_hash; 383 384 child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl; 385 if (parent_obj->u.sec_obj->seg_obj_list == NULL) { 386 parent_obj->u.sec_obj->seg_obj_list = child_obj; 387 return; 388 } 389 390 for (next_hash = parent_obj->u.sec_obj->seg_obj_list; 391 next_hash->u.seg_obj->next != NULL; 392 next_hash = next_hash->u.seg_obj->next) { 393 ; 394 } 395 396 next_hash->u.seg_obj->next = child_obj; 397 } 398 399 /* called to add packet object list into packet list */ 400 static void 401 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj) 402 { 403 hash_obj_t *next_hash; 404 405 /* add the packet object in the end of list */ 406 child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl; 407 408 if (parent_obj->u.seg_obj->pkt_obj_list == NULL) { 409 parent_obj->u.seg_obj->pkt_obj_list = child_obj; 410 return; 411 } 412 413 for (next_hash = parent_obj->u.seg_obj->pkt_obj_list; 414 next_hash->u.pkt_obj->next != NULL; 415 next_hash = next_hash->u.pkt_obj->next) { 416 ; 417 } 418 419 next_hash->u.pkt_obj->next = child_obj; 420 } 421 422 /* fill the information, payload in the conatiner */ 423 /*ARGSUSED*/ 424 static int 425 initialize_ipmi_container(picl_nodehdl_t fru, hash_obj_t *cont_hash_obj) 426 { 427 payload_t manr; 428 hash_obj_t *seg_hash_obj, *sec_hash_obj, *pkt_hash_obj; 429 format_t format; 430 431 format = cont_hash_obj->u.cont_obj->format; 432 /* plug to SMC driver to fetch the data */ 433 if (get_manr(&format, &manr) != 0) { 434 return (-1); 435 } 436 437 cont_hash_obj->u.cont_obj->num_of_section = 1; 438 cont_hash_obj->u.cont_obj->sec_obj_list = NULL; 439 440 sec_hash_obj = create_section_hash_object(); 441 if (sec_hash_obj == NULL) { 442 return (-1); 443 } 444 445 add_hashobject_to_hashtable(sec_hash_obj, SECTION_TYPE); 446 447 /* create fake section info here */ 448 sec_hash_obj->u.sec_obj->num_of_segment = 1; 449 sec_hash_obj->u.sec_obj->section.handle = sec_hash_obj->obj_hdl; 450 sec_hash_obj->u.sec_obj->section.offset = 0; 451 sec_hash_obj->u.sec_obj->section.protection = READ_ONLY_SECTION; 452 453 sec_hash_obj->u.sec_obj->section.length = STATIC_LENGTH; 454 sec_hash_obj->u.sec_obj->section.version = SECTION_HDR_VER; 455 add_to_sec_object_list(cont_hash_obj, sec_hash_obj); 456 457 seg_hash_obj = create_segment_hash_object(); 458 if (seg_hash_obj == NULL) { 459 return (-1); 460 } 461 462 add_hashobject_to_hashtable(seg_hash_obj, SEGMENT_TYPE); 463 464 seg_hash_obj->u.seg_obj->num_of_packets = 1; 465 seg_hash_obj->u.seg_obj->segment.handle = seg_hash_obj->obj_hdl; 466 (void) strncpy(seg_hash_obj->u.seg_obj->segment.name, 467 SD_SEGMENT_NAME, 468 sizeof (seg_hash_obj->u.seg_obj->segment.name)); 469 seg_hash_obj->u.seg_obj->segment.descriptor = SD_SEGMENT_DESCRIPTOR; 470 /* tag + payload */ 471 seg_hash_obj->u.seg_obj->segment.length = MANR_SIZE + 472 SEGMENT_TRAILER_LEN + SEGMENT_CHKSM_LEN; 473 add_to_seg_object_list(sec_hash_obj, seg_hash_obj); 474 475 pkt_hash_obj = create_packet_hash_object(); 476 if (pkt_hash_obj == NULL) { 477 return (-1); 478 } 479 add_hashobject_to_hashtable(pkt_hash_obj, PACKET_TYPE); 480 481 pkt_hash_obj->u.pkt_obj->payload_data = manr; 482 if (mk_tag(FRU_F, 0x001, 0x0B7, &pkt_hash_obj->u.pkt_obj->tag) == 4) { 483 add_to_pkt_object_list(seg_hash_obj, pkt_hash_obj); 484 } 485 return (0); 486 } 487 488 /* Look up the container_hdl in the PICL tree. */ 489 static container_hdl_t 490 ipmi_fru_open_container(picl_nodehdl_t fruh) 491 { 492 int err; 493 hash_obj_t *cont_hash_obj; 494 495 err = ptree_get_propval_by_name(fruh, PICL_PROP_FRUDATA_AVAIL, 496 NULL, NULL); 497 if (err != PICL_SUCCESS) { 498 return (0); 499 } 500 501 cont_hash_obj = lookup_handle_object((handle_t)fruh, CONTAINER_TYPE); 502 if (cont_hash_obj == NULL) { 503 return (0); 504 } 505 506 /* initialize the container */ 507 if (initialize_ipmi_container(fruh, cont_hash_obj) != 0) { 508 return (0); 509 } 510 return (cont_hash_obj->obj_hdl); 511 } 512 513 /*ARGSUSED*/ 514 static int 515 ipmi_fru_get_num_sections(container_hdl_t container, door_cred_t *cred) 516 { 517 hash_obj_t *cont_hash_obj; 518 519 cont_hash_obj = lookup_handle_object((handle_t)container, 520 CONTAINER_TYPE); 521 if (cont_hash_obj == NULL) { 522 return (-1); 523 } 524 return (cont_hash_obj->u.cont_obj->num_of_section); 525 } 526 527 /*ARGSUSED*/ 528 static int 529 ipmi_fru_get_sections(container_hdl_t container, section_t *section, 530 int max_sections, door_cred_t *cred) 531 { 532 int count; 533 hash_obj_t *cont_object; 534 hash_obj_t *sec_hash; 535 536 cont_object = lookup_handle_object((handle_t)container, 537 CONTAINER_TYPE); 538 if (cont_object == NULL) { 539 return (-1); 540 } 541 542 if (cont_object->u.cont_obj->num_of_section > max_sections) { 543 return (-1); 544 } 545 sec_hash = cont_object->u.cont_obj->sec_obj_list; 546 547 for (count = 0; count < cont_object->u.cont_obj->num_of_section && 548 sec_hash != NULL; count++, section++) { 549 /* populate section_t */ 550 section->handle = sec_hash->u.sec_obj->section.handle; 551 section->offset = sec_hash->u.sec_obj->section.offset; 552 section->length = sec_hash->u.sec_obj->section.length; 553 section->protection = sec_hash->u.sec_obj->section.protection; 554 section->version = sec_hash->u.sec_obj->section.version; 555 sec_hash = sec_hash->u.sec_obj->next; 556 } 557 return (count); 558 } 559 560 /*ARGSUSED*/ 561 static int 562 ipmi_fru_get_num_segments(section_hdl_t section, door_cred_t *cred) 563 { 564 hash_obj_t *sec_object; 565 566 sec_object = lookup_handle_object((handle_t)section, SECTION_TYPE); 567 if (sec_object == NULL) { 568 return (-1); 569 } 570 return (sec_object->u.sec_obj->num_of_segment); 571 } 572 573 /*ARGSUSED*/ 574 static int 575 ipmi_fru_get_segments(section_hdl_t section, segment_t *segment, 576 int max_segments, door_cred_t *cred) 577 { 578 int count; 579 hash_obj_t *seg_hash; 580 hash_obj_t *sec_object; 581 582 sec_object = lookup_handle_object((handle_t)section, SECTION_TYPE); 583 if (sec_object == NULL) { 584 return (-1); 585 } 586 587 if (sec_object->u.sec_obj->num_of_segment > max_segments) { 588 return (-1); 589 } 590 591 seg_hash = sec_object->u.sec_obj->seg_obj_list; 592 593 for (count = 0; count < sec_object->u.sec_obj->num_of_segment && 594 seg_hash != NULL; count++, segment++) { 595 /* populate the segment info */ 596 segment->handle = seg_hash->u.seg_obj->segment.handle; 597 (void) memcpy(segment->name, seg_hash->u.seg_obj->segment.name, 598 SEG_NAME_LEN); 599 segment->descriptor = seg_hash->u.seg_obj->segment.descriptor; 600 segment->offset = seg_hash->u.seg_obj->segment.offset; 601 segment->length = seg_hash->u.seg_obj->segment.length; 602 seg_hash = seg_hash->u.seg_obj->next; 603 } 604 return (count); 605 } 606 607 /*ARGSUSED*/ 608 static int 609 ipmi_fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred) 610 { 611 hash_obj_t *seg_object; 612 613 seg_object = lookup_handle_object((handle_t)segment, SEGMENT_TYPE); 614 if (seg_object == NULL) { 615 return (-1); 616 } 617 return (seg_object->u.seg_obj->num_of_packets); 618 } 619 620 /*ARGSUSED*/ 621 static int 622 ipmi_fru_get_packets(segment_hdl_t segment, packet_t *packet, 623 int max_packets, door_cred_t *cred) 624 { 625 int count; 626 hash_obj_t *pkt_hash; 627 hash_obj_t *seg_object; 628 629 seg_object = lookup_handle_object((handle_t)segment, SEGMENT_TYPE); 630 if (seg_object == NULL) { 631 return (-1); 632 } 633 634 if (seg_object->u.seg_obj->num_of_packets > max_packets) { 635 return (-1); 636 } 637 638 pkt_hash = seg_object->u.seg_obj->pkt_obj_list; 639 640 for (count = 0; count < seg_object->u.seg_obj->num_of_packets && 641 pkt_hash != NULL; count++, packet++) { 642 /* populate the segment info */ 643 packet->handle = pkt_hash->obj_hdl; 644 (void) memcpy(&packet->tag, &pkt_hash->u.pkt_obj->tag, 4); 645 pkt_hash = pkt_hash->u.pkt_obj->next; 646 } 647 648 return (count); 649 } 650 651 /*ARGSUSED*/ 652 static ssize_t 653 ipmi_fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes, 654 door_cred_t *cred) 655 { 656 hash_obj_t *seg_hash; 657 hash_obj_t *pkt_hash; 658 659 /* segment hash object */ 660 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 661 if (seg_hash == NULL) { 662 return (-1); 663 } 664 665 if (seg_hash->u.seg_obj->segment.length < nbytes) { 666 return (-1); 667 } 668 669 pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; 670 671 if (pkt_hash == NULL) { 672 return (-1); 673 } 674 675 (void) memcpy(buffer, &pkt_hash->u.pkt_obj->payload_data, 676 sizeof (payload_t)); 677 return (nbytes); 678 } 679 680 /*ARGSUSED*/ 681 static ssize_t 682 ipmi_fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes, 683 door_cred_t *cred) 684 { 685 hash_obj_t *packet_hash_obj; 686 687 /* size = size of ManR */ 688 if (nbytes != MANR_SIZE) { 689 return (-1); 690 } 691 692 /* packet hash object */ 693 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE); 694 if (packet_hash_obj == NULL) { 695 return (-1); 696 } 697 698 (void) memcpy(buffer, &(packet_hash_obj->u.pkt_obj->payload_data), 699 MANR_SIZE); 700 return (nbytes); 701 } 702 703 /*ARGSUSED*/ 704 static int 705 ipmi_fru_add_segment(section_hdl_t section, segment_t *segment, 706 section_hdl_t *newsection, door_cred_t *cred) 707 { 708 errno = ENOTSUP; 709 return (-1); 710 } 711 712 /*ARGSUSED*/ 713 static int 714 ipmi_fru_delete_segment(segment_hdl_t segment, 715 section_hdl_t *newsection, door_cred_t *cred) 716 { 717 errno = ENOTSUP; 718 return (-1); 719 } 720 721 722 /*ARGSUSED*/ 723 static ssize_t 724 ipmi_fru_write_segment(segment_hdl_t segment, const void *data, 725 size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred) 726 { 727 errno = ENOTSUP; 728 return (-1); 729 } 730 731 /*ARGSUSED*/ 732 static int 733 ipmi_fru_update_payload(packet_hdl_t packet, const void *data, 734 size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred) 735 { 736 errno = ENOTSUP; 737 return (-1); 738 } 739 740 /*ARGSUSED*/ 741 static int 742 ipmi_fru_append_packet(segment_hdl_t segment, packet_t *packet, 743 const void *payload, size_t nbytes, segment_hdl_t *newsegment, 744 door_cred_t *cred) 745 { 746 errno = ENOTSUP; 747 return (-1); 748 } 749 750 /*ARGSUSED*/ 751 static int 752 ipmi_fru_delete_packet(packet_hdl_t packet, 753 segment_hdl_t *newsegment, door_cred_t *cred) 754 { 755 errno = ENOTSUP; 756 return (-1); 757 } 758 759 static void 760 free_pkt_object_list(hash_obj_t *hash_obj) 761 { 762 hash_obj_t *next_obj; 763 hash_obj_t *free_obj; 764 765 next_obj = hash_obj->u.seg_obj->pkt_obj_list; 766 while (next_obj != NULL) { 767 free_obj = next_obj; 768 next_obj = next_obj->u.pkt_obj->next; 769 /* if prev is NULL it's the first object in the list */ 770 if (free_obj->prev == NULL) { 771 hash_table[(free_obj->obj_hdl % TABLE_SIZE)] = 772 free_obj->next; 773 if (free_obj->next != NULL) { 774 free_obj->next->prev = free_obj->prev; 775 } 776 } else { 777 free_obj->prev->next = free_obj->next; 778 if (free_obj->next != NULL) { 779 free_obj->next->prev = free_obj->prev; 780 } 781 } 782 783 free(free_obj->u.pkt_obj); 784 free(free_obj); 785 } 786 787 hash_obj->u.seg_obj->pkt_obj_list = NULL; 788 } 789 790 static void 791 free_segment_hash(handle_t handle, hash_obj_t *sec_hash) 792 { 793 hash_obj_t *seg_hash; 794 hash_obj_t *next_hash; 795 796 seg_hash = sec_hash->u.sec_obj->seg_obj_list; 797 if (seg_hash == NULL) { 798 return; 799 } 800 801 if (seg_hash->obj_hdl == handle) { 802 sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next; 803 } else { 804 while (seg_hash->obj_hdl != handle) { 805 next_hash = seg_hash; 806 seg_hash = seg_hash->u.seg_obj->next; 807 if (seg_hash == NULL) { 808 return; 809 } 810 } 811 next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next; 812 } 813 814 if (seg_hash->prev == NULL) { 815 hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next; 816 if (seg_hash->next != NULL) { 817 seg_hash->next->prev = NULL; 818 } 819 } else { 820 seg_hash->prev->next = seg_hash->next; 821 if (seg_hash->next != NULL) { 822 seg_hash->next->prev = seg_hash->prev; 823 } 824 } 825 826 free_pkt_object_list(seg_hash); 827 free(seg_hash->u.seg_obj); 828 free(seg_hash); 829 } 830 831 static int 832 ipmi_fru_close_container(container_hdl_t container) 833 { 834 hash_obj_t *hash_obj; 835 hash_obj_t *prev_hash; 836 hash_obj_t *sec_hash_obj; 837 handle_t obj_hdl; 838 839 /* lookup for container hash object */ 840 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 841 if (hash_obj == NULL) { 842 return (0); 843 } 844 845 /* points to section object list */ 846 sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list; 847 848 /* traverse section object list */ 849 while (sec_hash_obj != NULL) { 850 851 /* traverse segment hash object in the section */ 852 while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) { 853 /* object handle of the segment hash object */ 854 obj_hdl = 855 sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl; 856 free_segment_hash(obj_hdl, sec_hash_obj); 857 } 858 859 /* going to free section hash object, relink the hash object */ 860 if (sec_hash_obj->prev == NULL) { 861 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] 862 = sec_hash_obj->next; 863 if (sec_hash_obj->next != NULL) { 864 sec_hash_obj->next->prev = NULL; 865 } 866 } else { 867 sec_hash_obj->prev->next = sec_hash_obj->next; 868 if (sec_hash_obj->next != NULL) { 869 sec_hash_obj->next->prev = sec_hash_obj->prev; 870 } 871 } 872 873 free(sec_hash_obj->u.sec_obj); /* free section hash object */ 874 875 prev_hash = sec_hash_obj; 876 877 sec_hash_obj = sec_hash_obj->u.sec_obj->next; 878 879 free(prev_hash); /* free section hash */ 880 } 881 882 /* free container hash object */ 883 if (hash_obj->prev == NULL) { 884 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] = 885 hash_obj->next; 886 if (hash_obj->next != NULL) { 887 hash_obj->next->prev = NULL; 888 } 889 } else { 890 hash_obj->prev->next = hash_obj->next; 891 if (hash_obj->next != NULL) { 892 hash_obj->next->prev = hash_obj->prev; 893 } 894 } 895 896 free(hash_obj->u.cont_obj); 897 free(hash_obj); 898 return (0); 899 } 900 901 /* opens the binary file and returns the file descriptor */ 902 static int 903 open_file() 904 { 905 int fd; 906 907 if ((fd = open(INPUT_FILE, O_RDWR)) == -1) { 908 return (-1); 909 } 910 return (fd); 911 } 912 913 static void 914 copy_segment_layout(segment_t *seghdr, void *layout) 915 { 916 segment_layout_t *seg_layout; 917 918 seg_layout = (segment_layout_t *)layout; 919 (void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN); 920 seghdr->descriptor = GET_SEGMENT_DESCRIPTOR; 921 seghdr->offset = seg_layout->offset; 922 seghdr->length = seg_layout->length; 923 } 924 925 static hash_obj_t * 926 get_container_hash_object(int object_type, handle_t handle) 927 { 928 hash_obj_t *hash_obj; 929 930 switch (object_type) { 931 case CONTAINER_TYPE : 932 break; 933 934 case SECTION_TYPE : 935 hash_obj = lookup_handle_object(handle, CONTAINER_TYPE); 936 if (hash_obj == NULL) { 937 return (NULL); 938 } 939 break; 940 case SEGMENT_TYPE : 941 hash_obj = lookup_handle_object(handle, SECTION_TYPE); 942 if (hash_obj == NULL) { 943 return (NULL); 944 } 945 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl, 946 CONTAINER_TYPE); 947 break; 948 case PACKET_TYPE : 949 950 hash_obj = lookup_handle_object(handle, SEGMENT_TYPE); 951 if (hash_obj == NULL) { 952 return (NULL); 953 } 954 hash_obj = lookup_handle_object( 955 hash_obj->u.seg_obj->section_hdl, SECTION_TYPE); 956 if (hash_obj == NULL) { 957 return (NULL); 958 } 959 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl, 960 CONTAINER_TYPE); 961 break; 962 default : 963 return (NULL); 964 } 965 return (hash_obj); 966 } 967 968 static void 969 sort_offsettbl(int segcnt, seg_info_t *offset_tbl) 970 { 971 int cntx; 972 int cnty; 973 seg_info_t tmp; 974 975 for (cntx = 0; cntx < segcnt+2; cntx++) { 976 for (cnty = cntx+1; cnty < segcnt + 2; cnty++) { 977 if (offset_tbl[cntx].offset > 978 offset_tbl[cnty].offset) { 979 (void) memcpy(&tmp, &offset_tbl[cnty], 980 sizeof (seg_info_t)); 981 (void) memcpy(&offset_tbl[cnty], 982 &offset_tbl[cntx], 983 sizeof (seg_info_t)); 984 985 (void) memcpy(&offset_tbl[cntx], &tmp, 986 sizeof (seg_info_t)); 987 } 988 } 989 } 990 } 991 992 /* 993 * Description : move_segment_data() reads the segment data and writes it 994 * back to the new segment offset. 995 */ 996 997 static void 998 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd) 999 { 1000 int ret; 1001 char *buffer; 1002 segment_layout_t *segment; 1003 format_t format; 1004 hash_obj_t *cont_hash; 1005 1006 segment = (segment_layout_t *)seghdr; 1007 1008 buffer = alloca(segment->length); 1009 if (buffer == NULL) { 1010 return; 1011 } 1012 1013 cont_hash = lookup_handle_object((handle_t)contfd, CONTAINER_TYPE); 1014 if (cont_hash == NULL) { 1015 return; 1016 } 1017 1018 format = cont_hash->u.cont_obj->format; 1019 1020 ret = pread_new(contfd, buffer, 1021 segment->length, segment->offset, &format); 1022 if (ret != segment->length) { 1023 return; 1024 } 1025 1026 segment->offset = newoffset; 1027 1028 ret = pwrite_new(contfd, buffer, segment->length, segment->offset, 1029 &format); 1030 if (ret != segment->length) { 1031 return; 1032 } 1033 } 1034 1035 /* 1036 * Description : pack_segment_data() moves the segment data if there is 1037 * a hole between two segments. 1038 */ 1039 1040 static void 1041 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd, 1042 seg_info_t *offset_tbl) 1043 { 1044 int cnt; 1045 int diff; 1046 int newoffset; 1047 1048 for (cnt = segcnt + 1; cnt > 0; cnt--) { 1049 if (!offset_tbl[cnt - 1].fixed) { 1050 if (offset_tbl[cnt].offset 1051 - (offset_tbl[cnt -1 ].offset 1052 + offset_tbl[cnt - 1].length) > 0) { 1053 1054 diff = offset_tbl[cnt].offset - 1055 (offset_tbl[cnt - 1].offset 1056 + offset_tbl[cnt - 1].length); 1057 newoffset = offset_tbl[cnt - 1].offset 1058 + diff; 1059 1060 move_segment_data(seghdr, newoffset, 1061 contfd); 1062 1063 offset_tbl[cnt - 1].offset = newoffset; 1064 1065 sort_offsettbl(segcnt, offset_tbl); 1066 } 1067 } 1068 } 1069 } 1070 1071 /* 1072 * Description : build_offset_tbl() builds the offset table by reading all the 1073 * segment header. it makes two more entry into the table one for 1074 * section size and another with start of the section after the 1075 * segment header. 1076 */ 1077 1078 static int 1079 build_offset_tbl(void *seghdr, int segcnt, int secsize, 1080 seg_info_t *offset_tbl) 1081 { 1082 int cnt; 1083 fru_segdesc_t segdesc; 1084 segment_layout_t *segment; 1085 1086 for (cnt = 0; cnt < segcnt; cnt++) { 1087 segment = (segment_layout_t *)(seghdr) + cnt; 1088 1089 (void) memcpy(&segdesc, &segment->descriptor, 1090 sizeof (uint32_t)); 1091 offset_tbl[cnt].segnum = cnt; 1092 offset_tbl[cnt].offset = segment->offset; 1093 offset_tbl[cnt].length = segment->length; 1094 offset_tbl[cnt].fixed = segdesc.field.fixed; 1095 } 1096 1097 /* upper boundary of segment area (lower address bytes) */ 1098 offset_tbl[cnt].segnum = -1; 1099 offset_tbl[cnt].offset = sizeof (section_layout_t) + ((cnt + 1) 1100 * sizeof (segment_layout_t)); 1101 1102 offset_tbl[cnt].length = 0; 1103 offset_tbl[cnt].fixed = 1; 1104 /* lower boundary of segment area (higher address bytes) */ 1105 1106 offset_tbl[cnt+1].segnum = -1; 1107 offset_tbl[cnt+1].offset = secsize; 1108 offset_tbl[cnt+1].length = 0; 1109 offset_tbl[cnt+1].fixed = 1; 1110 return (0); 1111 } 1112 1113 static int 1114 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl) 1115 { 1116 int cnt = 0; 1117 1118 *totsize = 0; 1119 for (cnt = segcnt + 1; cnt > 0; cnt--) { 1120 if (bytes <= offset_tbl[cnt].offset - 1121 (offset_tbl[cnt - 1].offset + 1122 offset_tbl[cnt - 1].length)) { 1123 return (offset_tbl[cnt].offset - bytes); 1124 } 1125 1126 *totsize += offset_tbl[cnt].offset - 1127 (offset_tbl[cnt - 1].offset + 1128 offset_tbl[cnt - 1].length); 1129 } 1130 return (0); 1131 } 1132 1133 1134 /* 1135 * Description : segment_hdr_present() verify space for new segment header to 1136 * be added. 1137 */ 1138 1139 static int 1140 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl) 1141 { 1142 if ((segoffset + size) <= offset_tbl[0].offset) 1143 return (0); 1144 else 1145 return (-1); 1146 } 1147 1148 /* 1149 * Description : find_offset() is called from fru_add_segment routine to find 1150 * a valid offset. 1151 */ 1152 1153 static int 1154 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset, 1155 int segsize, int fix, container_hdl_t contfd) 1156 { 1157 int ret; 1158 int newoffset; 1159 int totsize = 0; 1160 seg_info_t *offset_tbl; 1161 1162 if (segcnt == 0) { 1163 if (!fix) { /* if not fixed segment */ 1164 *sectionoffset = secsize - segsize; 1165 } 1166 return (0); 1167 } 1168 1169 /* 1170 * two extra segment info structure are allocated for start of segment 1171 * and other end of segment. first segment offset is first available 1172 * space and length is 0. second segment offset is is segment length and 1173 * offset is 0. build_offset_tbl() explains how upper boundary and lower 1174 * boudary segment area are initialized in seg_info_t table. 1175 */ 1176 1177 offset_tbl = malloc((segcnt + 2) * sizeof (seg_info_t)); 1178 if (offset_tbl == NULL) { 1179 return (-1); 1180 } 1181 1182 /* read all the segment header to make offset table */ 1183 ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl); 1184 if (ret != 0) { 1185 free(offset_tbl); 1186 return (-1); 1187 } 1188 1189 /* sort the table */ 1190 sort_offsettbl(segcnt, offset_tbl); 1191 1192 /* new segment header offset */ 1193 newoffset = sizeof (section_layout_t) + segcnt * 1194 sizeof (segment_layout_t); 1195 1196 /* do? new segment header overlap any existing data */ 1197 ret = segment_hdr_present(newoffset, sizeof (segment_layout_t), 1198 offset_tbl); 1199 if (ret != 0) { /* make room for new segment if possible */ 1200 1201 /* look for hole in order to move segment data */ 1202 if (offset_tbl[0].fixed == SEGMENT_FIXED) { /* fixed segment */ 1203 free(offset_tbl); 1204 return (-1); 1205 } 1206 1207 newoffset = hole_discovery(offset_tbl[0].length, 1208 segcnt, &totsize, offset_tbl); 1209 if (newoffset != 0) { /* found new offset */ 1210 /* now new offset */ 1211 offset_tbl[0].offset = newoffset; 1212 1213 /* move the segment data */ 1214 move_segment_data(seghdr, newoffset, contfd); 1215 /* again sort the offset table */ 1216 sort_offsettbl(segcnt, offset_tbl); 1217 } else { 1218 /* pack the existing hole */ 1219 if (totsize > offset_tbl[0].length) { 1220 pack_segment_data(seghdr, segcnt, 1221 contfd, offset_tbl); 1222 } else { 1223 free(offset_tbl); 1224 return (-1); 1225 } 1226 } 1227 } 1228 1229 totsize = 0; 1230 newoffset = hole_discovery(segsize, segcnt, &totsize, offset_tbl); 1231 1232 if (newoffset == 0) { /* No hole found */ 1233 if (totsize >= segsize) { 1234 pack_segment_data(seghdr, segcnt, contfd, 1235 offset_tbl); 1236 newoffset = hole_discovery(segsize, segcnt, 1237 &totsize, offset_tbl); 1238 if (newoffset != 0) { 1239 *sectionoffset = newoffset; 1240 free(offset_tbl); 1241 return (0); 1242 } 1243 } 1244 } else { 1245 *sectionoffset = newoffset; 1246 free(offset_tbl); 1247 return (0); 1248 } 1249 free(offset_tbl); 1250 return (-1); 1251 } 1252 1253 /* 1254 * Description :sun_fru_open_container() opens the container associated with 1255 * a fru. it's called by data plugin module before creating 1256 * container property. it calls picltree library routine to get 1257 * the device path and driver binding name for the fru to get the 1258 * corresponding fru name that describe the fru layout. 1259 * 1260 * Arguments :picl_hdl_t fru 1261 * A handle for PICL tree node of class "fru" representing the 1262 * FRU with the container to open. 1263 * 1264 * Return : 1265 * On Success, a Positive integer container handle. is returned 1266 * for use in subsequent fru operations;on error, 0 is returned 1267 * and "errno" is set appropriately. 1268 */ 1269 static container_hdl_t 1270 sun_fru_open_container(picl_nodehdl_t fruhdl) 1271 { 1272 int count; 1273 hash_obj_t *cont_hash_obj; 1274 hash_obj_t *sec_hash_obj; 1275 1276 cont_hash_obj = lookup_handle_object((handle_t)fruhdl, CONTAINER_TYPE); 1277 if (cont_hash_obj == NULL) { 1278 return (NULL); 1279 } 1280 1281 cont_hash_obj->u.cont_obj->num_of_section = NUM_OF_SECTIONS; 1282 cont_hash_obj->u.cont_obj->sec_obj_list = NULL; 1283 1284 for (count = 0; count < NUM_OF_SECTIONS; count++) { 1285 sec_hash_obj = create_section_hash_object(); 1286 if (sec_hash_obj == NULL) { 1287 return (NULL); 1288 } 1289 1290 add_hashobject_to_hashtable(sec_hash_obj, SECTION_TYPE); 1291 1292 if (count == 0) { 1293 sec_hash_obj->u.sec_obj->section.offset = 1294 DYNAMIC_OFFSET; 1295 sec_hash_obj->u.sec_obj->section.protection = 1296 WRITE_SECTION; 1297 sec_hash_obj->u.sec_obj->section.length = 1298 DYNAMIC_LENGTH; 1299 } else { 1300 sec_hash_obj->u.sec_obj->section.offset = STATIC_OFFSET; 1301 sec_hash_obj->u.sec_obj->section.protection = 1302 READ_ONLY_SECTION; 1303 sec_hash_obj->u.sec_obj->section.length = STATIC_LENGTH; 1304 } 1305 1306 sec_hash_obj->u.sec_obj->section.version = SECTION_HDR_VER; 1307 1308 add_to_sec_object_list(cont_hash_obj, sec_hash_obj); 1309 } 1310 1311 return (cont_hash_obj->obj_hdl); 1312 } 1313 1314 static int 1315 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length) 1316 { 1317 int crc_offset = 0; 1318 unsigned char orig_crc8 = 0; 1319 unsigned char calc_crc8 = 0; 1320 1321 switch (head_ver) { 1322 case SECTION_HDR_VER: 1323 crc_offset = 4; 1324 break; 1325 default: 1326 errno = EINVAL; 1327 return (0); 1328 } 1329 1330 orig_crc8 = bytes[crc_offset]; 1331 bytes[crc_offset] = 0x00; /* clear for calc */ 1332 calc_crc8 = compute_crc8(bytes, length); 1333 bytes[crc_offset] = orig_crc8; /* restore */ 1334 1335 return (orig_crc8 == calc_crc8); 1336 } 1337 1338 /* 1339 * Description : 1340 * sun_fru_get_num_sections() returns number of sections in a 1341 * container. it calls get_container_index() to get the container 1342 * index number in the container list. 1343 * 1344 * Arguments : 1345 * container_hdl_t : container handle. 1346 * 1347 * Return : 1348 * int 1349 * On success, returns number of sections in a container. 1350 * 1351 */ 1352 /*ARGSUSED*/ 1353 static int 1354 sun_fru_get_num_sections(container_hdl_t container, door_cred_t *cred) 1355 { 1356 hash_obj_t *hash_object; 1357 1358 hash_object = lookup_handle_object(container, CONTAINER_TYPE); 1359 if (hash_object == NULL) { 1360 return (-1); 1361 } 1362 1363 return (hash_object->u.cont_obj->num_of_section); 1364 } 1365 1366 /* 1367 * called from fru_get_sections() 1368 */ 1369 1370 static void 1371 get_section(int fd, hash_obj_t *sec_hash, section_t *section) 1372 { 1373 int retval; 1374 int size; 1375 int count; 1376 uint16_t hdrver; 1377 hash_obj_t *seg_hash; 1378 unsigned char *buffer; 1379 section_obj_t *sec_obj; 1380 section_layout_t sec_hdr; 1381 segment_layout_t *seg_hdr; 1382 segment_layout_t *seg_buf; 1383 format_t format; 1384 hash_obj_t *cont_hash; 1385 1386 sec_obj = sec_hash->u.sec_obj; 1387 if (sec_obj == NULL) { 1388 return; 1389 } 1390 1391 /* populate section_t */ 1392 section->handle = sec_hash->obj_hdl; 1393 section->offset = sec_obj->section.offset; 1394 section->length = sec_obj->section.length; 1395 section->protection = sec_obj->section.protection; 1396 section->version = sec_obj->section.version; 1397 sec_obj->num_of_segment = 0; 1398 1399 cont_hash = get_container_hash_object(SEGMENT_TYPE, sec_hash->obj_hdl); 1400 if (cont_hash == NULL) { 1401 return; 1402 } 1403 1404 format = cont_hash->u.cont_obj->format; 1405 1406 /* read section header layout */ 1407 retval = pread_new(fd, &sec_hdr, sizeof (sec_hdr), 1408 sec_obj->section.offset, &format); 1409 if (retval != sizeof (sec_hdr)) { 1410 return; 1411 } 1412 1413 hdrver = GET_SECTION_HDR_VERSION; 1414 1415 if ((sec_hdr.headertag != SECTION_HDR_TAG) && 1416 (hdrver != section->version)) { 1417 return; 1418 } 1419 1420 /* size = section layout + total sizeof segment header */ 1421 size = sizeof (sec_hdr) + ((sec_hdr.segmentcount) 1422 * sizeof (segment_layout_t)); 1423 buffer = alloca(size); 1424 if (buffer == NULL) { 1425 return; 1426 } 1427 1428 /* segment header buffer */ 1429 seg_buf = alloca(size - sizeof (sec_hdr)); 1430 if (seg_buf == NULL) { 1431 return; 1432 } 1433 1434 /* read segment header */ 1435 retval = pread_new(fd, seg_buf, size - sizeof (sec_hdr), 1436 sec_obj->section.offset + sizeof (sec_hdr), &format); 1437 if (retval != (size - sizeof (sec_hdr))) { 1438 return; 1439 } 1440 1441 /* copy section header layout */ 1442 (void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr)); 1443 1444 /* copy segment header layout */ 1445 (void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size - 1446 sizeof (sec_hdr)); 1447 1448 /* verify crc8 */ 1449 retval = verify_header_crc8(hdrver, buffer, size); 1450 if (retval != TRUE) { 1451 return; 1452 } 1453 1454 section->version = hdrver; 1455 sec_obj->section.version = hdrver; 1456 1457 seg_hdr = (segment_layout_t *)seg_buf; 1458 1459 for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) { 1460 seg_hash = create_segment_hash_object(); 1461 if (seg_hash == NULL) { 1462 return; 1463 } 1464 1465 add_hashobject_to_hashtable(seg_hash, SEGMENT_TYPE); 1466 1467 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr); 1468 1469 add_to_seg_object_list(sec_hash, seg_hash); 1470 1471 sec_obj->num_of_segment++; 1472 } 1473 } 1474 1475 /* 1476 * Description : 1477 * sun_fru_get_sections() fills an array of section structures 1478 * passed as an argument. 1479 * 1480 * Arguments : 1481 * container_hdl_t : container handle(device descriptor). 1482 * section_t : array of section structure. 1483 * int : maximum number of section in a container. 1484 * 1485 * Returns : 1486 * int 1487 * On success,the number of section structures written is returned; 1488 * on error, -1 is returned and "errno" is set appropriately. 1489 * 1490 */ 1491 /*ARGSUSED*/ 1492 static int 1493 sun_fru_get_sections(container_hdl_t container, section_t *section, int maxsec, 1494 door_cred_t *cred) 1495 { 1496 int device_fd; 1497 int count; 1498 hash_obj_t *cont_object; 1499 hash_obj_t *sec_hash; 1500 1501 cont_object = lookup_handle_object(container, CONTAINER_TYPE); 1502 if (cont_object == NULL) { 1503 return (-1); 1504 } 1505 1506 if (cont_object->u.cont_obj->num_of_section > maxsec) { 1507 return (-1); 1508 } 1509 1510 sec_hash = cont_object->u.cont_obj->sec_obj_list; 1511 if (sec_hash == NULL) { 1512 return (-1); 1513 } 1514 1515 device_fd = open_file(); 1516 1517 if (device_fd < 0) { 1518 return (-1); 1519 } 1520 1521 for (count = 0; count < cont_object->u.cont_obj->num_of_section; 1522 count++, section++) { 1523 section->version = -1; 1524 /* populate section_t */ 1525 get_section(device_fd, sec_hash, section); 1526 sec_hash = sec_hash->u.sec_obj->next; 1527 } 1528 1529 (void) close(device_fd); 1530 1531 return (count); 1532 } 1533 1534 /* 1535 * Description : 1536 * sun_fru_get_num_segments() returns the current number of 1537 * segments in a section. 1538 * 1539 * Arguments : 1540 * section_hdl_t : section header holding section information. 1541 * 1542 * Return : 1543 * int 1544 * On success, the number of segments in the argument section is 1545 * returned; on error -1 is returned. 1546 */ 1547 /*ARGSUSED*/ 1548 static int 1549 sun_fru_get_num_segments(section_hdl_t section, door_cred_t *cred) 1550 { 1551 hash_obj_t *sec_object; 1552 section_obj_t *sec_obj; 1553 1554 sec_object = lookup_handle_object(section, SECTION_TYPE); 1555 if (sec_object == NULL) { 1556 return (-1); 1557 } 1558 1559 sec_obj = sec_object->u.sec_obj; 1560 if (sec_obj == NULL) { 1561 return (-1); 1562 } 1563 1564 return (sec_obj->num_of_segment); 1565 } 1566 1567 /* 1568 * Description : 1569 * sun_fru_get_segments() fills an array of structures 1570 * representing the segments in a section. 1571 * 1572 * Arguments : 1573 * section_hdl_t : holds section number. 1574 * segment_t : on success will hold segment information. 1575 * int : maximum number of segment. 1576 * 1577 * Return : 1578 * int 1579 * On success, the number of segment structures written is 1580 * returned; on errno -1 is returned. 1581 */ 1582 /* ARGSUSED */ 1583 static int 1584 sun_fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg, 1585 door_cred_t *cred) 1586 { 1587 int count; 1588 hash_obj_t *sec_object; 1589 hash_obj_t *seg_object; 1590 section_obj_t *sec_obj; 1591 1592 sec_object = lookup_handle_object(section, SECTION_TYPE); 1593 if (sec_object == NULL) { 1594 return (-1); 1595 } 1596 1597 sec_obj = sec_object->u.sec_obj; 1598 if (sec_obj == NULL) { 1599 return (-1); 1600 } 1601 1602 if (sec_obj->num_of_segment > maxseg) { 1603 return (-1); 1604 } 1605 1606 seg_object = sec_object->u.sec_obj->seg_obj_list; 1607 if (seg_object == NULL) { 1608 return (-1); 1609 } 1610 1611 for (count = 0; count < sec_obj->num_of_segment; count++) { 1612 1613 /* populate segment_t */ 1614 segment->handle = seg_object->obj_hdl; 1615 (void) memcpy(segment->name, 1616 seg_object->u.seg_obj->segment.name, SEG_NAME_LEN); 1617 segment->descriptor = seg_object->u.seg_obj->segment.descriptor; 1618 segment->offset = seg_object->u.seg_obj->segment.offset; 1619 segment->length = seg_object->u.seg_obj->segment.length; 1620 seg_object = seg_object->u.seg_obj->next; 1621 segment++; 1622 } 1623 return (0); 1624 } 1625 1626 /* 1627 * Description : 1628 * sun_fru_add_segment() adds a segment to a section. 1629 * 1630 * Arguments : 1631 * section_hdl_t section 1632 * A handle for the section in which to add the segment. 1633 * 1634 * segment_t *segment 1635 * On entry, the "handle" component of "segment" is ignored and the 1636 * remaining components specify the parameters of the segment to be 1637 * added. On return, the "handle" component is set to the handle 1638 * for the added segment. The segment offset is mandatory for FIXED 1639 * segments; otherwise, the offset is advisory. 1640 * 1641 * Return : 1642 * int 1643 * On success, 0 is returned; on error -1 is returned. 1644 * 1645 */ 1646 static int 1647 sun_fru_add_segment(section_hdl_t section, segment_t *segment, 1648 section_hdl_t *newsection, door_cred_t *cred) 1649 { 1650 int fd; 1651 int retval; 1652 int offset; 1653 int sec_size; 1654 int seg_cnt; 1655 int bufsize; 1656 int new_seg_offset; 1657 int new_seg_length; 1658 int fixed_segment; 1659 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00 }; 1660 hash_obj_t *cont_hash; 1661 hash_obj_t *sec_hash; 1662 hash_obj_t *seg_hash; 1663 fru_segdesc_t *new_seg_desc; 1664 unsigned char *crcbuf; 1665 section_layout_t sec_layout; 1666 segment_layout_t *seg_layout; 1667 segment_layout_t *segment_buf; 1668 format_t format; 1669 1670 /* check the effective uid of the client */ 1671 if (cred->dc_euid != 0) { 1672 errno = EPERM; 1673 return (-1); /* not a root */ 1674 } 1675 1676 /* section hash */ 1677 sec_hash = lookup_handle_object(section, SECTION_TYPE); 1678 if (sec_hash == NULL) { 1679 return (-1); 1680 } 1681 1682 /* check for read-only section */ 1683 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 1684 errno = EPERM; 1685 return (-1); 1686 } 1687 1688 /* look for duplicate segment */ 1689 seg_hash = sec_hash->u.sec_obj->seg_obj_list; 1690 while (seg_hash != NULL) { 1691 if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name, 1692 SEG_NAME_LEN) == 0) { 1693 errno = EEXIST; 1694 return (-1); /* can't add duplicate segment */ 1695 } 1696 seg_hash = seg_hash->u.seg_obj->next; 1697 } 1698 1699 /* get the container hash */ 1700 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 1701 CONTAINER_TYPE); 1702 if (cont_hash == NULL) { 1703 return (-1); 1704 } 1705 1706 format = cont_hash->u.cont_obj->format; 1707 1708 /* open the container */ 1709 fd = open_file(); 1710 if (fd < 0) { 1711 return (-1); 1712 } 1713 1714 /* section start here */ 1715 offset = sec_hash->u.sec_obj->section.offset; 1716 1717 /* read section header layout */ 1718 retval = pread_new(fd, &sec_layout, sizeof (sec_layout), offset, 1719 &format); 1720 if (retval != sizeof (sec_layout)) { 1721 (void) close(fd); 1722 return (-1); 1723 } 1724 1725 /* check for valid section header */ 1726 if (sec_layout.headertag != SECTION_HDR_TAG) { 1727 /* write a new one */ 1728 sec_layout.headertag = SECTION_HDR_TAG; 1729 sec_layout.headerversion[0] = SECTION_HDR_VER_BIT0; 1730 sec_layout.headerversion[1] = SECTION_HDR_VER_BIT1; 1731 sec_layout.headerlength = sizeof (sec_layout); 1732 sec_layout.segmentcount = 0; 1733 } 1734 1735 /* section size */ 1736 sec_size = sec_hash->u.sec_obj->section.length; 1737 1738 /* number of segment in the section */ 1739 seg_cnt = sec_layout.segmentcount; 1740 1741 /* total sizeof segment + new segment */ 1742 bufsize = sizeof (segment_layout_t) * (seg_cnt + 1); 1743 segment_buf = alloca(bufsize); 1744 if (segment_buf == NULL) { 1745 return (-1); 1746 } 1747 1748 /* read entire segment header */ 1749 retval = pread_new(fd, segment_buf, 1750 (bufsize - sizeof (segment_layout_t)), 1751 offset + sizeof (section_layout_t), &format); 1752 if (retval != (bufsize - sizeof (segment_layout_t))) { 1753 (void) close(fd); 1754 return (-1); 1755 } 1756 1757 new_seg_offset = segment->offset; /* new segment offset */ 1758 new_seg_length = segment->length; /* new segment length */ 1759 1760 new_seg_desc = (fru_segdesc_t *)&segment->descriptor; 1761 1762 fixed_segment = new_seg_desc->field.fixed; 1763 1764 /* get new offset for new segment to be addedd */ 1765 retval = find_offset((char *)segment_buf, seg_cnt, sec_size, 1766 &new_seg_offset, new_seg_length, fixed_segment, fd); 1767 1768 if (retval != 0) { 1769 (void) close(fd); 1770 errno = EAGAIN; 1771 return (-1); 1772 } 1773 1774 /* copy new segment data in segment layout */ 1775 seg_layout = (segment_layout_t *)(segment_buf + seg_cnt); 1776 (void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN); 1777 (void) memcpy(seg_layout->descriptor, &segment->descriptor, 1778 sizeof (uint32_t)); 1779 seg_layout->length = segment->length; 1780 seg_layout->offset = new_seg_offset; /* new segment offset */ 1781 1782 sec_layout.segmentcount += 1; 1783 1784 crcbuf = alloca(sizeof (section_layout_t) + bufsize); 1785 if (crcbuf == NULL) { 1786 (void) close(fd); 1787 return (-1); 1788 } 1789 1790 sec_layout.headercrc8 = 0; 1791 sec_layout.headerlength += sizeof (segment_layout_t); 1792 1793 (void) memcpy(crcbuf, (char *)&sec_layout, sizeof (section_layout_t)); 1794 (void) memcpy(crcbuf + sizeof (section_layout_t), segment_buf, bufsize); 1795 1796 sec_layout.headercrc8 = compute_crc8(crcbuf, bufsize + 1797 sizeof (section_layout_t)); 1798 1799 /* write section header */ 1800 retval = pwrite_new(fd, &sec_layout, sizeof (section_layout_t), 1801 offset, &format); 1802 if (retval != sizeof (section_layout_t)) { 1803 (void) close(fd); 1804 return (-1); 1805 } 1806 1807 /* write segment header */ 1808 retval = pwrite_new(fd, segment_buf, bufsize, offset + 1809 sizeof (section_layout_t), &format); 1810 if (retval != bufsize) { 1811 (void) close(fd); 1812 return (-1); 1813 } 1814 1815 /* write segment trailer */ 1816 retval = pwrite_new(fd, &trailer, sizeof (trailer), new_seg_offset, 1817 &format); 1818 if (retval != sizeof (trailer)) { 1819 (void) close(fd); 1820 return (-1); 1821 } 1822 1823 (void) close(fd); 1824 1825 /* create new segment hash object */ 1826 seg_hash = create_segment_hash_object(); 1827 if (seg_hash == NULL) { 1828 return (-1); 1829 } 1830 1831 add_hashobject_to_hashtable(seg_hash, SEGMENT_TYPE); 1832 1833 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_layout); 1834 1835 add_to_seg_object_list(sec_hash, seg_hash); 1836 1837 sec_hash->u.sec_obj->num_of_segment += 1; 1838 seg_hash->u.seg_obj->trailer_offset = new_seg_offset; 1839 *newsection = section; /* return the new section handle */ 1840 return (0); 1841 } 1842 1843 /* 1844 * Description : 1845 * sun_fru_delete_segment() deletes a segment from a section; the 1846 * associated container data is not altered. 1847 * 1848 * Arguments : segment_hdl_t segment handle. 1849 * section_hdl_t new section handle. 1850 * 1851 * Return : 1852 * int 1853 * On success, 0 returned; On error -1 is returned. 1854 */ 1855 static int 1856 sun_fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection, 1857 door_cred_t *cred) 1858 { 1859 int num_of_seg; 1860 int bufsize; 1861 int count; 1862 int retval; 1863 int fd; 1864 int segnum; 1865 hash_obj_t *seg_hash; 1866 hash_obj_t *sec_hash; 1867 hash_obj_t *cont_hash; 1868 hash_obj_t *tmp_hash; 1869 unsigned char *buffer; 1870 fru_segdesc_t *desc; 1871 segment_layout_t *seg_buf; 1872 section_layout_t *sec_layout; 1873 segment_layout_t *seg_layout; 1874 segment_layout_t *next_layout; 1875 format_t format; 1876 1877 /* check the effective uid of the client */ 1878 if (cred->dc_euid != 0) { 1879 errno = EPERM; 1880 return (-1); /* not a root */ 1881 } 1882 1883 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 1884 if (seg_hash == NULL) { 1885 return (-1); 1886 } 1887 1888 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 1889 if (!(desc->field.field_perm & SEGMENT_DELETE)) { 1890 errno = EPERM; 1891 return (-1); /* can't delete this segment */ 1892 } 1893 1894 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 1895 SECTION_TYPE); 1896 if (sec_hash == NULL) { 1897 return (-1); 1898 } 1899 1900 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 1901 errno = EPERM; 1902 return (-1); 1903 } 1904 1905 num_of_seg = sec_hash->u.sec_obj->num_of_segment; 1906 1907 bufsize = (sizeof (segment_layout_t) * num_of_seg); 1908 1909 seg_buf = alloca(bufsize); 1910 if (seg_buf == NULL) { 1911 return (-1); 1912 } 1913 1914 segnum = 0; 1915 for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL; 1916 tmp_hash = tmp_hash->u.seg_obj->next) { 1917 if (tmp_hash->obj_hdl == segment) { 1918 break; 1919 } 1920 segnum++; 1921 } 1922 1923 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 1924 CONTAINER_TYPE); 1925 if (cont_hash == NULL) { 1926 return (-1); 1927 } 1928 format = cont_hash->u.cont_obj->format; 1929 1930 fd = open_file(); 1931 if (fd < 0) { 1932 return (-1); 1933 } 1934 1935 sec_layout = alloca(sizeof (section_layout_t)); 1936 if (sec_layout == NULL) { 1937 (void) close(fd); 1938 return (-1); 1939 } 1940 1941 /* read section layout header */ 1942 retval = pread_new(fd, sec_layout, sizeof (section_layout_t), 1943 sec_hash->u.sec_obj->section.offset, &format); 1944 if (retval != sizeof (section_layout_t)) { 1945 (void) close(fd); 1946 return (-1); 1947 } 1948 1949 /* read segment header layout */ 1950 retval = pread_new(fd, seg_buf, bufsize, 1951 sec_hash->u.sec_obj->section.offset + 1952 sizeof (section_layout_t), &format); 1953 if (retval != bufsize) { 1954 (void) close(fd); 1955 return (-1); 1956 } 1957 1958 seg_layout = (segment_layout_t *)(seg_buf + segnum); 1959 next_layout = seg_layout; 1960 for (count = segnum; count < sec_hash->u.sec_obj->num_of_segment-1; 1961 count++) { 1962 next_layout++; 1963 (void) memcpy(seg_layout, next_layout, 1964 sizeof (segment_layout_t)); 1965 seg_layout++; 1966 } 1967 1968 (void) memset(seg_layout, '\0', sizeof (segment_layout_t)); 1969 1970 sec_layout->headercrc8 = 0; 1971 1972 sec_layout->headerlength -= sizeof (segment_layout_t); 1973 sec_layout->segmentcount -= 1; 1974 1975 buffer = alloca(sec_layout->headerlength); 1976 if (buffer == NULL) { 1977 (void) close(fd); 1978 return (-1); 1979 } 1980 1981 (void) memcpy(buffer, sec_layout, sizeof (section_layout_t)); 1982 (void) memcpy(buffer + sizeof (section_layout_t), seg_buf, bufsize 1983 - sizeof (segment_layout_t)); 1984 sec_layout->headercrc8 = compute_crc8(buffer, 1985 sec_layout->headerlength); 1986 1987 /* write section header with update crc8 and header length */ 1988 retval = pwrite_new(fd, sec_layout, sizeof (section_layout_t), 1989 sec_hash->u.sec_obj->section.offset, &format); 1990 if (retval != sizeof (section_layout_t)) { 1991 (void) close(fd); 1992 return (-1); 1993 } 1994 1995 /* write the update segment header */ 1996 retval = pwrite_new(fd, seg_buf, bufsize, 1997 sec_hash->u.sec_obj->section.offset + 1998 sizeof (section_layout_t), &format); 1999 (void) close(fd); 2000 if (retval != bufsize) { 2001 return (-1); 2002 } 2003 2004 free_segment_hash(segment, sec_hash); 2005 2006 *newsection = sec_hash->obj_hdl; 2007 sec_hash->u.sec_obj->num_of_segment = sec_layout->segmentcount; 2008 2009 return (0); 2010 } 2011 2012 /* 2013 * Description : 2014 * sun_fru_read_segment() reads the raw contents of a segment. 2015 * 2016 * Arguments : segment_hdl_t : segment handle. 2017 * void * : buffer containing segment data when function returns. 2018 * size_t :number of bytes. 2019 * 2020 * Return : 2021 * int 2022 * On success, the number of bytes read is returned; 2023 * 2024 * Notes : 2025 * Segments containing packets can be read in structured fashion 2026 * using the fru_get_packets() and fru_get_payload() primitives;the 2027 * entire byte range of a segment can be read using 2028 * fru_read_segment(). 2029 */ 2030 /*ARGSUSED*/ 2031 static ssize_t 2032 sun_fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes, 2033 door_cred_t *cred) 2034 { 2035 int fd; 2036 int retval; 2037 hash_obj_t *seg_hash; 2038 hash_obj_t *sec_hash; 2039 hash_obj_t *cont_hash; 2040 format_t format; 2041 2042 /* segment hash object */ 2043 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 2044 if (seg_hash == NULL) { 2045 return (-1); 2046 } 2047 2048 /* section hash object */ 2049 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2050 SECTION_TYPE); 2051 if (sec_hash == NULL) { 2052 return (-1); 2053 } 2054 2055 /* container hash object */ 2056 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2057 CONTAINER_TYPE); 2058 if (cont_hash == NULL) { 2059 return (-1); 2060 } 2061 format = cont_hash->u.cont_obj->format; 2062 2063 if (seg_hash->u.seg_obj->segment.length < nbytes) { 2064 return (-1); 2065 } 2066 2067 fd = open_file(); 2068 if (fd < 0) { 2069 return (-1); 2070 } 2071 2072 retval = pread_new(fd, buffer, nbytes, 2073 seg_hash->u.seg_obj->segment.offset, &format); 2074 (void) close(fd); 2075 if (retval != nbytes) { 2076 return (-1); 2077 } 2078 return (nbytes); 2079 } 2080 2081 /* 2082 * Description : 2083 * sun_fru_write_segment() writes a raw segment. 2084 * 2085 * Arguments : segment_hdl_t :segment handle. 2086 * const void * : data buffer. 2087 * size_t : number of bytes. 2088 * segment_hdl_t : new segment handle. 2089 * 2090 * Returns : 2091 * int 2092 * On success, the number of bytes written is returned 2093 * 2094 */ 2095 /*ARGSUSED*/ 2096 static int 2097 sun_fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes, 2098 segment_hdl_t *newsegment, door_cred_t *cred) 2099 { 2100 return (ENOTSUP); 2101 } 2102 2103 2104 static int 2105 get_packet(int device_fd, void *buffer, int size, int offset, format_t *format) 2106 { 2107 int retval; 2108 2109 retval = pread_new(device_fd, (char *)buffer, size, offset, format); 2110 if (retval != -1) { 2111 return (0); 2112 } 2113 return (-1); 2114 } 2115 2116 static uint32_t 2117 get_checksum_crc(hash_obj_t *seg_hash, int data_size) 2118 { 2119 int protection; 2120 int offset = 0; 2121 uint32_t crc; 2122 hash_obj_t *sec_hash; 2123 hash_obj_t *pkt_hash; 2124 unsigned char *buffer; 2125 2126 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2127 SECTION_TYPE); 2128 if (sec_hash == NULL) { 2129 return ((uint32_t)-1); 2130 } 2131 2132 buffer = alloca(data_size); 2133 if (buffer == NULL) { 2134 return ((uint32_t)-1); 2135 } 2136 2137 /* traverse the packet object list for all the tags and payload */ 2138 for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL; 2139 pkt_hash = pkt_hash->u.pkt_obj->next) { 2140 (void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag, 2141 pkt_hash->u.pkt_obj->tag_size); 2142 offset += pkt_hash->u.pkt_obj->tag_size; 2143 (void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload, 2144 pkt_hash->u.pkt_obj->paylen); 2145 offset += pkt_hash->u.pkt_obj->paylen; 2146 } 2147 2148 protection = sec_hash->u.sec_obj->section.protection; 2149 2150 if (protection == READ_ONLY_SECTION) { /* read-only section */ 2151 crc = compute_crc32(buffer, data_size); 2152 } else { /* read/write section */ 2153 crc = compute_checksum32(buffer, data_size); 2154 } 2155 return (crc); /* computed crc */ 2156 } 2157 2158 static int 2159 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length) 2160 { 2161 int tag_size; 2162 int paylen; 2163 int retval; 2164 int seg_limit = 0; 2165 int pktcnt = 0; 2166 char *data; 2167 uint32_t crc; 2168 uint32_t origcrc; 2169 fru_tag_t tag; 2170 hash_obj_t *pkt_hash_obj; 2171 fru_segdesc_t *segdesc; 2172 fru_tagtype_t tagtype; 2173 format_t format; 2174 hash_obj_t *cont_hash; 2175 2176 cont_hash = get_container_hash_object(PACKET_TYPE, seg_hash->obj_hdl); 2177 if (cont_hash == NULL) { 2178 return (NULL); 2179 } 2180 format = cont_hash->u.cont_obj->format; 2181 2182 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), offset, 2183 &format); 2184 if (retval == -1) { 2185 return (-1); 2186 } 2187 2188 seg_hash->u.seg_obj->trailer_offset = offset; 2189 2190 data = (char *)&tag; 2191 while (data[0] != SEG_TRAILER_TAG) { 2192 tagtype = get_tag_type(&tag); /* verify tag type */ 2193 if (tagtype == -1) { 2194 return (-1); 2195 } 2196 2197 tag_size = get_tag_size(tagtype); 2198 if (tag_size == -1) { 2199 return (-1); 2200 } 2201 2202 seg_limit += tag_size; 2203 if (seg_limit > length) { 2204 return (-1); 2205 } 2206 2207 paylen = get_payload_length((void *)&tag); 2208 if (paylen == -1) { 2209 return (-1); 2210 } 2211 2212 seg_limit += paylen; 2213 if (seg_limit > length) { 2214 return (-1); 2215 } 2216 2217 pkt_hash_obj = create_packet_hash_object(); 2218 if (pkt_hash_obj == NULL) { 2219 return (-1); 2220 } 2221 2222 pkt_hash_obj->u.pkt_obj->payload = malloc(paylen); 2223 if (pkt_hash_obj->u.pkt_obj->payload == NULL) { 2224 free(pkt_hash_obj); 2225 return (-1); 2226 } 2227 2228 offset += tag_size; 2229 retval = pread_new(device_fd, pkt_hash_obj->u.pkt_obj->payload, 2230 paylen, offset, &format); 2231 if (retval != paylen) { 2232 free(pkt_hash_obj->u.pkt_obj->payload); 2233 free(pkt_hash_obj); 2234 return (-1); 2235 } 2236 2237 /* don't change this */ 2238 pkt_hash_obj->u.pkt_obj->tag.raw_data = 0; 2239 (void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size); 2240 pkt_hash_obj->u.pkt_obj->paylen = paylen; 2241 pkt_hash_obj->u.pkt_obj->tag_size = tag_size; 2242 pkt_hash_obj->u.pkt_obj->payload_offset = offset; 2243 2244 offset += paylen; 2245 2246 add_hashobject_to_hashtable(pkt_hash_obj, PACKET_TYPE); 2247 add_to_pkt_object_list(seg_hash, pkt_hash_obj); 2248 2249 pktcnt++; 2250 2251 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), 2252 offset, &format); 2253 if (retval == -1) { 2254 return (retval); 2255 } 2256 2257 data = (char *)&tag; 2258 } 2259 2260 segdesc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2261 2262 seg_hash->u.seg_obj->trailer_offset = offset; 2263 2264 if (!segdesc->field.ignore_checksum) { 2265 crc = get_checksum_crc(seg_hash, seg_limit); 2266 offset = seg_hash->u.seg_obj->segment.offset; 2267 2268 retval = pread_new(device_fd, &origcrc, sizeof (origcrc), 2269 offset + seg_limit + 1, &format); 2270 if (retval != sizeof (origcrc)) { 2271 return (-1); 2272 } 2273 2274 if (origcrc != crc) { 2275 seg_hash->u.seg_obj->trailer_offset = offset; 2276 return (-1); 2277 } 2278 } 2279 return (pktcnt); 2280 } 2281 2282 /* 2283 * Description : 2284 * sun_fru_get_num_packets() returns the current number of packets 2285 * in a segment. 2286 * 2287 * Arguments : segment_hdl_t : segment handle. 2288 * 2289 * Return : 2290 * int 2291 * On success, the number of packets is returned; 2292 * -1 on failure. 2293 */ 2294 /*ARGSUSED*/ 2295 static int 2296 sun_fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred) 2297 { 2298 int device_fd; 2299 int pktcnt; 2300 int length; 2301 uint16_t offset; 2302 hash_obj_t *cont_hash_obj; 2303 hash_obj_t *seg_hash; 2304 fru_segdesc_t *segdesc; 2305 segment_obj_t *segment_object; 2306 2307 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 2308 if (seg_hash == NULL) { 2309 return (-1); 2310 } 2311 2312 segment_object = seg_hash->u.seg_obj; 2313 if (segment_object == NULL) { 2314 return (-1); 2315 } 2316 2317 2318 segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor; 2319 if (segdesc->field.opaque) { 2320 return (0); 2321 } 2322 2323 offset = segment_object->segment.offset; 2324 length = segment_object->segment.length; 2325 2326 cont_hash_obj = get_container_hash_object(SEGMENT_TYPE, 2327 segment_object->section_hdl); 2328 2329 if (cont_hash_obj == NULL) { 2330 return (-1); 2331 } 2332 2333 if (seg_hash->u.seg_obj->pkt_obj_list != NULL) { 2334 return (segment_object->num_of_packets); 2335 } 2336 2337 segment_object->num_of_packets = 0; 2338 device_fd = open_file(); 2339 if (device_fd < 0) { 2340 return (-1); 2341 } 2342 2343 pktcnt = get_packets(seg_hash, device_fd, offset, 2344 length); 2345 if (pktcnt == -1) { 2346 free_pkt_object_list(seg_hash); 2347 seg_hash->u.seg_obj->pkt_obj_list = NULL; 2348 } 2349 2350 segment_object->num_of_packets = pktcnt; 2351 (void) close(device_fd); 2352 2353 return (segment_object->num_of_packets); 2354 } 2355 2356 /* 2357 * Description : 2358 * sun_fru_get_packets() fills an array of structures 2359 * representing the packets in a segment. 2360 * 2361 * Arguments : segment_hdl_t : segment handle. 2362 * packet_t : packet buffer. 2363 * int : maximum number of packets. 2364 * 2365 * Return : 2366 * int 2367 * On success, the number of packet structures written is returned; 2368 * On failure -1 is returned; 2369 * 2370 */ 2371 /*ARGSUSED*/ 2372 static int 2373 sun_fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets, 2374 door_cred_t *cred) 2375 { 2376 int count; 2377 hash_obj_t *seg_hash_obj; 2378 hash_obj_t *pkt_hash_obj; 2379 2380 /* segment hash object */ 2381 seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE); 2382 if (seg_hash_obj == NULL) { 2383 return (-1); 2384 } 2385 2386 if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) { 2387 return (-1); 2388 } 2389 2390 pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list; 2391 if (pkt_hash_obj == NULL) { 2392 return (-1); 2393 } 2394 2395 for (count = 0; count < maxpackets; count++, packet++) { 2396 packet->handle = pkt_hash_obj->obj_hdl; 2397 packet->tag = 0; 2398 (void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag, 2399 pkt_hash_obj->u.pkt_obj->tag_size); 2400 pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next; 2401 } 2402 2403 return (0); 2404 } 2405 2406 /* 2407 * Description : 2408 * sun_fru_get_payload() copies the contents of a packet's payload. 2409 * 2410 * Arguments : packet_hdl_t : packet handle. 2411 * void * : payload buffer. 2412 * size_t : sizeof the buffer. 2413 * 2414 * Return : 2415 * int 2416 * On success, the number of bytes copied is returned; On error 2417 * -1 returned. 2418 */ 2419 /*ARGSUSED*/ 2420 static ssize_t 2421 sun_fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes, 2422 door_cred_t *cred) 2423 { 2424 hash_obj_t *packet_hash_obj; 2425 2426 /* packet hash object */ 2427 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE); 2428 if (packet_hash_obj == NULL) { 2429 return (-1); 2430 } 2431 2432 /* verify payload length */ 2433 if (nbytes != packet_hash_obj->u.pkt_obj->paylen) { 2434 return (-1); 2435 } 2436 2437 (void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes); 2438 return (nbytes); 2439 } 2440 2441 /* 2442 * Description : 2443 * sun_fru_update_payload() writes the contents of a packet's 2444 * payload. 2445 * 2446 * Arguments : packet_hdl_t : packet handle. 2447 * const void * : data buffer. 2448 * size_t : buffer size. 2449 * packet_hdl_t : new packet handle. 2450 * 2451 * Return : 2452 * int 2453 * On success, 0 is returned; on failure 2454 * -1 is returned. 2455 */ 2456 /*ARGSUSED*/ 2457 static int 2458 sun_fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes, 2459 packet_hdl_t *newpacket, door_cred_t *cred) 2460 { 2461 int fd; 2462 int segment_offset; 2463 int trailer_offset; 2464 int retval; 2465 uint32_t crc; 2466 hash_obj_t *pkt_hash; 2467 hash_obj_t *seg_hash; 2468 hash_obj_t *sec_hash; 2469 hash_obj_t *cont_hash; 2470 fru_segdesc_t *desc; 2471 format_t format; 2472 2473 /* check the effective uid of the client */ 2474 if (cred->dc_euid != 0) { 2475 errno = EPERM; 2476 return (-1); /* not a root */ 2477 } 2478 2479 /* packet hash object */ 2480 pkt_hash = lookup_handle_object(packet, PACKET_TYPE); 2481 if (pkt_hash == NULL) { 2482 return (-1); 2483 } 2484 2485 /* segment hash object */ 2486 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl, 2487 SEGMENT_TYPE); 2488 if (seg_hash == NULL) { 2489 return (-1); 2490 } 2491 2492 /* check for write perm. */ 2493 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2494 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2495 errno = EPERM; 2496 return (-1); /* write not allowed */ 2497 } 2498 2499 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2500 SECTION_TYPE); 2501 if (sec_hash == NULL) { 2502 return (-1); 2503 } 2504 2505 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2506 errno = EPERM; 2507 return (-1); /* read-only section */ 2508 } 2509 2510 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2511 CONTAINER_TYPE); 2512 if (cont_hash == NULL) { 2513 return (-1); 2514 } 2515 2516 format = cont_hash->u.cont_obj->format; 2517 2518 if (pkt_hash->u.pkt_obj->paylen != nbytes) { 2519 return (-1); 2520 } 2521 2522 (void) memcpy(pkt_hash->u.pkt_obj->payload, (char *)data, nbytes); 2523 fd = open_file(); 2524 if (fd < 0) { 2525 return (-1); 2526 } 2527 2528 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2529 segment_offset = seg_hash->u.seg_obj->segment.offset; 2530 2531 crc = get_checksum_crc(seg_hash, (trailer_offset - segment_offset)); 2532 retval = pwrite_new(fd, data, nbytes, 2533 pkt_hash->u.pkt_obj->payload_offset, &format); 2534 if (retval != nbytes) { 2535 (void) close(fd); 2536 return (-1); 2537 } 2538 2539 retval = pwrite_new(fd, &crc, sizeof (crc), 2540 trailer_offset + 1, &format); 2541 (void) close(fd); 2542 if (retval != sizeof (crc)) { 2543 return (-1); 2544 } 2545 *newpacket = packet; 2546 return (0); 2547 } 2548 2549 /* 2550 * Description : 2551 * sun_fru_append_packet() appends a packet to a segment. 2552 * 2553 * Arguments : 2554 * segment_hdl_t segment 2555 * A handle for the segment to which the packet will be appended. 2556 * 2557 * packet_t *packet 2558 * On entry, the "tag" component of "packet" specifies the tag 2559 * value for the added packet; the "handle" component is ignored. 2560 * On return, the "handle" component is set to the handle of the 2561 * appended packet. 2562 * 2563 * const void *payload 2564 * A pointer to the caller's buffer containing the payload data for 2565 * the appended packet. 2566 * 2567 * size_t nbytes 2568 * The size of the caller buffer. 2569 * 2570 * Return : 2571 * int 2572 * On success, 0 is returned; on error -1 is returned; 2573 */ 2574 static int 2575 sun_fru_append_packet(segment_hdl_t segment, packet_t *packet, 2576 const void *payload, size_t nbytes, segment_hdl_t *newsegment, 2577 door_cred_t *cred) 2578 { 2579 int trailer_offset; 2580 int tag_size; 2581 int fd; 2582 int retval; 2583 char trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00}; 2584 uint32_t crc; 2585 hash_obj_t *seg_hash; 2586 hash_obj_t *sec_hash; 2587 hash_obj_t *pkt_hash; 2588 hash_obj_t *cont_hash; 2589 fru_tagtype_t tagtype; 2590 fru_segdesc_t *desc; 2591 format_t format; 2592 2593 /* check the effective uid of the client */ 2594 if (cred->dc_euid != 0) { 2595 errno = EPERM; 2596 return (-1); /* not a root */ 2597 } 2598 2599 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE); 2600 if (seg_hash == NULL) { 2601 return (-1); 2602 } 2603 2604 /* check for write perm. */ 2605 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2606 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2607 errno = EPERM; 2608 return (-1); /* write not allowed */ 2609 } 2610 2611 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2612 SECTION_TYPE); 2613 if (sec_hash == NULL) { 2614 return (-1); 2615 } 2616 2617 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2618 errno = EPERM; 2619 return (-1); /* read-only section */ 2620 } 2621 2622 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2623 2624 /* 2625 * if trailer offset is 0 than parse the segment data to get the trailer 2626 * offset to compute the remaining space left in the segment area for 2627 * new packet to be added. 2628 */ 2629 if (trailer_offset == 0) { 2630 (void) sun_fru_get_num_packets(segment, cred); 2631 trailer_offset = seg_hash->u.seg_obj->trailer_offset; 2632 } 2633 2634 tagtype = get_tag_type((void *)&packet->tag); 2635 if (tagtype == -1) { 2636 return (-1); 2637 } 2638 2639 tag_size = get_tag_size(tagtype); 2640 if (tag_size == -1) { 2641 return (-1); 2642 } 2643 2644 if (seg_hash->u.seg_obj->segment.length > 2645 ((trailer_offset - seg_hash->u.seg_obj->segment.offset) + 2646 tag_size + nbytes + 2647 sizeof (char) + sizeof (uint32_t))) { 2648 /* create new packet hash */ 2649 pkt_hash = create_packet_hash_object(); 2650 if (pkt_hash == NULL) { 2651 return (-1); 2652 } 2653 2654 /* tag initialization */ 2655 (void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag, 2656 tag_size); 2657 pkt_hash->u.pkt_obj->tag_size = tag_size; 2658 2659 /* payload inititalization */ 2660 pkt_hash->u.pkt_obj->payload = malloc(nbytes); 2661 if (pkt_hash->u.pkt_obj->payload == NULL) { 2662 free(pkt_hash); 2663 return (-1); 2664 } 2665 2666 (void) memcpy(pkt_hash->u.pkt_obj->payload, payload, nbytes); 2667 pkt_hash->u.pkt_obj->paylen = nbytes; 2668 pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size; 2669 2670 /* add to hash table */ 2671 add_hashobject_to_hashtable(pkt_hash, PACKET_TYPE); 2672 2673 add_to_pkt_object_list(seg_hash, pkt_hash); 2674 2675 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2676 CONTAINER_TYPE); 2677 if (cont_hash == NULL) { 2678 return (-1); 2679 } 2680 format = cont_hash->u.cont_obj->format; 2681 2682 fd = open_file(); 2683 if (fd < 0) { 2684 return (-1); 2685 } 2686 2687 /* update the trailer offset */ 2688 trailer_offset += tag_size + nbytes; 2689 2690 /* calculate new checksum */ 2691 crc = get_checksum_crc(seg_hash, (trailer_offset - 2692 seg_hash->u.seg_obj->segment.offset)); 2693 2694 retval = pwrite_new(fd, &packet->tag, tag_size, trailer_offset 2695 - (tag_size + nbytes), &format); 2696 if (retval != tag_size) { 2697 (void) close(fd); 2698 return (-1); 2699 } 2700 2701 retval = pwrite_new(fd, payload, nbytes, 2702 trailer_offset - nbytes, &format); 2703 if (retval != nbytes) { 2704 (void) close(fd); 2705 return (-1); 2706 } 2707 2708 retval = pwrite_new(fd, trailer, sizeof (trailer), 2709 trailer_offset, &format); 2710 if (retval != sizeof (trailer)) { 2711 (void) close(fd); 2712 return (-1); 2713 } 2714 2715 retval = pwrite_new(fd, &crc, sizeof (crc), 2716 trailer_offset + 1, &format); 2717 (void) close(fd); 2718 if (retval != sizeof (crc)) { 2719 return (-1); 2720 } 2721 2722 seg_hash->u.seg_obj->trailer_offset = trailer_offset; 2723 seg_hash->u.seg_obj->num_of_packets += 1; 2724 2725 *newsegment = segment; /* return new segment handle */ 2726 return (0); 2727 } else { 2728 errno = EAGAIN; 2729 } 2730 2731 return (-1); 2732 } 2733 2734 static void 2735 adjust_packets(int fd, hash_obj_t *free_obj, hash_obj_t *object_list) 2736 { 2737 int retval; 2738 uint32_t new_offset; 2739 hash_obj_t *hash_ptr; 2740 format_t format; 2741 hash_obj_t *hash_obj; 2742 2743 hash_obj = lookup_handle_object(free_obj->obj_hdl, PACKET_TYPE); 2744 if (hash_obj == NULL) { 2745 return; 2746 } 2747 hash_obj = get_container_hash_object(PACKET_TYPE, 2748 hash_obj->u.pkt_obj->segment_hdl); 2749 if (hash_obj == NULL) { 2750 return; 2751 } 2752 format = hash_obj->u.cont_obj->format; 2753 2754 new_offset = free_obj->u.pkt_obj->payload_offset 2755 - free_obj->u.pkt_obj->tag_size; 2756 for (hash_ptr = object_list; hash_ptr != NULL; 2757 hash_ptr = hash_ptr->u.pkt_obj->next) { 2758 retval = pwrite_new(fd, &hash_ptr->u.pkt_obj->tag, 2759 hash_ptr->u.pkt_obj->tag_size, new_offset, &format); 2760 if (retval != hash_ptr->u.pkt_obj->tag_size) { 2761 return; 2762 } 2763 new_offset += hash_ptr->u.pkt_obj->tag_size; 2764 hash_ptr->u.pkt_obj->payload_offset = new_offset; 2765 retval = pwrite_new(fd, hash_ptr->u.pkt_obj->payload, 2766 hash_ptr->u.pkt_obj->paylen, new_offset, &format); 2767 if (retval != hash_ptr->u.pkt_obj->paylen) { 2768 return; 2769 } 2770 new_offset += hash_ptr->u.pkt_obj->paylen; 2771 } 2772 } 2773 2774 static void 2775 free_packet_object(handle_t handle, hash_obj_t *seg_hash) 2776 { 2777 hash_obj_t *pkt_hash; 2778 hash_obj_t *next_hash; 2779 2780 pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; 2781 if (pkt_hash == NULL) { 2782 return; 2783 } 2784 2785 if (pkt_hash->obj_hdl == handle) { 2786 seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next; 2787 } else { 2788 while (pkt_hash->obj_hdl != handle) { 2789 next_hash = pkt_hash; 2790 pkt_hash = pkt_hash->u.pkt_obj->next; 2791 if (pkt_hash == NULL) { 2792 return; 2793 } 2794 } 2795 next_hash->u.pkt_obj->next = pkt_hash->u.pkt_obj->next; 2796 } 2797 2798 if (pkt_hash->prev == NULL) { 2799 hash_table[(pkt_hash->obj_hdl % TABLE_SIZE)] = pkt_hash->next; 2800 if (pkt_hash->next != NULL) { 2801 pkt_hash->next->prev = NULL; 2802 } 2803 } else { 2804 pkt_hash->prev->next = pkt_hash->next; 2805 if (pkt_hash->next != NULL) { 2806 pkt_hash->next->prev = pkt_hash->prev; 2807 } 2808 } 2809 2810 free(pkt_hash->u.pkt_obj->payload); 2811 free(pkt_hash->u.pkt_obj); 2812 free(pkt_hash); 2813 } 2814 2815 /* 2816 * Description : 2817 * sun_fru_delete_packet() deletes a packet from a segment. 2818 * 2819 * Arguments : packet_hdl_t : packet number to be deleted. 2820 * segment_hdl_t : new segment handler. 2821 * 2822 * Return : 2823 * int 2824 * On success, 0 is returned; on error, -1. 2825 * 2826 * NOTES 2827 * Packets are adjacent; thus, deleting a packet requires moving 2828 * succeeding packets to compact the resulting hole. 2829 */ 2830 static int 2831 sun_fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment, 2832 door_cred_t *cred) 2833 { 2834 int retval; 2835 int fd; 2836 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00}; 2837 uint32_t crc; 2838 hash_obj_t *tmp_obj; 2839 hash_obj_t *pkt_hash; 2840 hash_obj_t *sec_hash; 2841 hash_obj_t *cont_hash; 2842 hash_obj_t *prev_obj; 2843 hash_obj_t *seg_hash; 2844 fru_segdesc_t *desc; 2845 format_t format; 2846 2847 /* check the effective uid of the client */ 2848 if (cred->dc_euid != 0) { 2849 errno = EPERM; 2850 return (-1); /* not a root */ 2851 } 2852 2853 /* packet hash object */ 2854 pkt_hash = lookup_handle_object(packet, PACKET_TYPE); 2855 if (pkt_hash == NULL) { 2856 return (-1); 2857 } 2858 2859 /* segment hash object */ 2860 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl, 2861 SEGMENT_TYPE); 2862 if (seg_hash == NULL) { 2863 return (-1); 2864 } 2865 2866 /* check for write perm. */ 2867 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor; 2868 if (!(desc->field.field_perm & SEGMENT_WRITE)) { 2869 errno = EPERM; 2870 return (-1); /* write not allowed */ 2871 } 2872 2873 /* section hash object */ 2874 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl, 2875 SECTION_TYPE); 2876 if (sec_hash == NULL) { 2877 return (-1); 2878 } 2879 2880 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) { 2881 errno = EPERM; 2882 return (-1); /* read-only section */ 2883 } 2884 2885 prev_obj = seg_hash->u.seg_obj->pkt_obj_list; 2886 if (prev_obj == NULL) { 2887 return (-1); 2888 } 2889 2890 /* container hash object */ 2891 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl, 2892 CONTAINER_TYPE); 2893 if (cont_hash == NULL) { 2894 return (-1); 2895 } 2896 2897 format = cont_hash->u.cont_obj->format; 2898 2899 fd = open_file(); 2900 if (fd < 0) { 2901 return (-1); 2902 } 2903 2904 if (prev_obj->obj_hdl == packet) { /* first object to be deleted */ 2905 adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next); 2906 seg_hash->u.seg_obj->trailer_offset -= 2907 (prev_obj->u.pkt_obj->tag_size 2908 + prev_obj->u.pkt_obj->paylen); 2909 free_packet_object(packet, seg_hash); 2910 } else { 2911 for (tmp_obj = prev_obj; 2912 tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) { 2913 /* found the object */ 2914 if (tmp_obj->obj_hdl == packet) { 2915 adjust_packets(fd, tmp_obj, 2916 tmp_obj->u.pkt_obj->next); 2917 seg_hash->u.seg_obj->trailer_offset -= 2918 (tmp_obj->u.pkt_obj->tag_size 2919 + tmp_obj->u.pkt_obj->paylen); 2920 free_packet_object(packet, seg_hash); 2921 } 2922 } 2923 } 2924 2925 seg_hash->u.seg_obj->num_of_packets -= 1; 2926 2927 /* calculate checksum */ 2928 crc = get_checksum_crc(seg_hash, (seg_hash->u.seg_obj->trailer_offset 2929 - seg_hash->u.seg_obj->segment.offset)); 2930 /* write trailer at new offset */ 2931 retval = pwrite_new(fd, &trailer, sizeof (trailer), 2932 seg_hash->u.seg_obj->trailer_offset, &format); 2933 if (retval != sizeof (trailer)) { 2934 (void) close(fd); 2935 return (-1); 2936 } 2937 2938 /* write the checksum value */ 2939 retval = pwrite_new(fd, &crc, sizeof (crc), 2940 seg_hash->u.seg_obj->trailer_offset + 1, &format); 2941 (void) close(fd); 2942 if (retval != sizeof (crc)) { 2943 return (-1); 2944 } 2945 2946 *newsegment = seg_hash->obj_hdl; /* return new segment handle */ 2947 return (0); 2948 } 2949 2950 /* 2951 * Description : 2952 * sun_fru_close_container() removes the association between a 2953 * container and its handle. this routines free's up all the 2954 * hash object contained under container. 2955 * 2956 * Arguments : 2957 * container_hdl_t holds the file descriptor of the fru. 2958 * 2959 * Return : 2960 * int 2961 * return 0. 2962 * 2963 */ 2964 /* ARGSUSED */ 2965 static int 2966 sun_fru_close_container(container_hdl_t container) 2967 { 2968 hash_obj_t *hash_obj; 2969 hash_obj_t *prev_hash; 2970 hash_obj_t *sec_hash_obj; 2971 handle_t obj_hdl; 2972 2973 /* lookup for container hash object */ 2974 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 2975 if (hash_obj == NULL) { 2976 return (0); 2977 } 2978 2979 /* points to section object list */ 2980 sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list; 2981 2982 /* traverse section object list */ 2983 while (sec_hash_obj != NULL) { 2984 2985 /* traverse segment hash object in the section */ 2986 while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) { 2987 /* object handle of the segment hash object */ 2988 obj_hdl = 2989 sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl; 2990 free_segment_hash(obj_hdl, sec_hash_obj); 2991 } 2992 2993 /* going to free section hash object, relink the hash object */ 2994 if (sec_hash_obj->prev == NULL) { 2995 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] 2996 = sec_hash_obj->next; 2997 if (sec_hash_obj->next != NULL) { 2998 sec_hash_obj->next->prev = NULL; 2999 } 3000 } else { 3001 sec_hash_obj->prev->next = sec_hash_obj->next; 3002 if (sec_hash_obj->next != NULL) { 3003 sec_hash_obj->next->prev = sec_hash_obj->prev; 3004 } 3005 } 3006 3007 free(sec_hash_obj->u.sec_obj); /* free section hash object */ 3008 3009 prev_hash = sec_hash_obj; 3010 3011 sec_hash_obj = sec_hash_obj->u.sec_obj->next; 3012 3013 free(prev_hash); /* free section hash */ 3014 } 3015 3016 /* free container hash object */ 3017 if (hash_obj->prev == NULL) { 3018 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] = 3019 hash_obj->next; 3020 if (hash_obj->next != NULL) { 3021 hash_obj->next->prev = NULL; 3022 } 3023 } else { 3024 hash_obj->prev->next = hash_obj->next; 3025 if (hash_obj->next != NULL) { 3026 hash_obj->next->prev = hash_obj->prev; 3027 } 3028 } 3029 3030 free(hash_obj->u.cont_obj); 3031 free(hash_obj); 3032 return (0); 3033 } 3034 3035 /* 3036 * FRU ACCESS API 3037 */ 3038 3039 /* 3040 * Description : 3041 * fru_is_data_available checks if the fruid information 3042 * is available or not on a give fru 3043 * 3044 * Arguments : 3045 * picl_nodehdl_t hold picl node handle of the fru. 3046 * 3047 * Return : 3048 * int 3049 * return 0 - if fruid is not present. 3050 * return 1 - if fruid is present. 3051 */ 3052 int 3053 fru_is_data_available(picl_nodehdl_t fruh) 3054 { 3055 int retval, ret; 3056 uint8_t slot_no; 3057 picl_nodehdl_t parenth; 3058 format_t fru_format; 3059 hash_obj_t *cont_hash_obj; 3060 3061 if (is_valid_chassis == -1) { 3062 if (fruaccess_platmod_check_chassis() == 0) { 3063 is_valid_chassis = 1; 3064 } else { 3065 is_valid_chassis = 0; 3066 } 3067 } 3068 3069 if (!is_valid_chassis) { 3070 return (0); 3071 } 3072 3073 retval = ptree_get_propval_by_name(fruh, PICL_PROP_PARENT, 3074 &parenth, sizeof (picl_nodehdl_t)); 3075 if (retval != PICL_SUCCESS) { 3076 return (0); 3077 } 3078 3079 if (fruaccess_platmod_check_fru(parenth) != 0) { 3080 return (0); 3081 } 3082 3083 retval = ptree_get_propval_by_name(parenth, PICL_PROP_GEO_ADDR, 3084 &slot_no, sizeof (uint8_t)); 3085 if (retval != PICL_SUCCESS) { 3086 return (0); 3087 } 3088 3089 if (fruaccess_platmod_init_format(slot_no, &fru_format) != 3090 PICL_SUCCESS) { 3091 return (0); 3092 } 3093 3094 ret = is_fru_data_available(precedence, slot_no, &fru_format); 3095 if (ret && (fru_format.format != NO_FRUDATA)) { 3096 goto create; 3097 } else { 3098 return (0); 3099 } 3100 create: 3101 3102 cont_hash_obj = create_container_hash_object(); 3103 if (cont_hash_obj == NULL) { 3104 return (0); 3105 } 3106 3107 cont_hash_obj->obj_hdl = fruh; 3108 cont_hash_obj->u.cont_obj->format = fru_format; 3109 3110 /* if both formats are present follow the precedence */ 3111 if (fru_format.format == 0x3) { 3112 if (precedence == IPMI_FORMAT) { 3113 cont_hash_obj->u.cont_obj->format.format = IPMI_FORMAT; 3114 } else { 3115 cont_hash_obj->u.cont_obj->format.format = SUN_FORMAT; 3116 } 3117 } 3118 add_hashobject_to_hashtable(cont_hash_obj, CONTAINER_TYPE); 3119 return (1); 3120 } 3121 3122 /* 3123 * FRU ACCESS API 3124 */ 3125 3126 /* 3127 * All the routines check the fruid format and redirects the call to 3128 * to appropriate routines depending on fruid format. 3129 * All SUN format routines start with sun_ prefix. 3130 * All IPMI format routines start with ipmi_ prefix. 3131 */ 3132 container_hdl_t 3133 fru_open_container(picl_nodehdl_t fru) 3134 { 3135 hash_obj_t *hash_obj; 3136 format_t fru_format; 3137 3138 hash_obj = lookup_handle_object((handle_t)fru, CONTAINER_TYPE); 3139 if (hash_obj == NULL) { 3140 return (-1); 3141 } 3142 fru_format = hash_obj->u.cont_obj->format; 3143 return (fruaccess_func[fru_format.format - 1].open_container(fru)); 3144 } 3145 3146 int 3147 fru_close_container(container_hdl_t container) 3148 { 3149 int ret; 3150 format_t fru_format; 3151 hash_obj_t *hash_obj; 3152 3153 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 3154 if (hash_obj == NULL) { 3155 return (-1); 3156 } 3157 3158 fru_format = hash_obj->u.cont_obj->format; 3159 ret = fruaccess_func[fru_format.format - 1].close_container(container); 3160 return (ret); 3161 } 3162 3163 int 3164 fru_get_num_sections(container_hdl_t container, door_cred_t *cred) 3165 { 3166 int ret; 3167 format_t fru_format; 3168 hash_obj_t *hash_obj; 3169 3170 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 3171 if (hash_obj == NULL) { 3172 return (-1); 3173 } 3174 fru_format = hash_obj->u.cont_obj->format; 3175 ret = fruaccess_func[fru_format.format - 1].get_num_sections(container, 3176 cred); 3177 return (ret); 3178 } 3179 3180 int 3181 fru_get_sections(container_hdl_t container, section_t *section, 3182 int max_sections, door_cred_t *cred) 3183 { 3184 int ret; 3185 format_t fru_format; 3186 hash_obj_t *hash_obj; 3187 3188 hash_obj = lookup_handle_object(container, CONTAINER_TYPE); 3189 if (hash_obj == NULL) { 3190 return (-1); 3191 } 3192 fru_format = hash_obj->u.cont_obj->format; 3193 3194 ret = fruaccess_func[fru_format.format - 1].get_sections(container, 3195 section, max_sections, cred); 3196 return (ret); 3197 } 3198 3199 int 3200 fru_get_num_segments(section_hdl_t section, door_cred_t *rarg) 3201 { 3202 int ret; 3203 format_t fru_format; 3204 hash_obj_t *hash_obj; 3205 3206 hash_obj = get_container_hash_object(SEGMENT_TYPE, section); 3207 if (hash_obj == NULL) { 3208 return (-1); 3209 } 3210 fru_format = hash_obj->u.cont_obj->format; 3211 3212 ret = fruaccess_func[fru_format.format - 1].get_num_segments(section, 3213 rarg); 3214 return (ret); 3215 } 3216 3217 int 3218 fru_get_segments(section_hdl_t section, segment_t *segment, 3219 int max_segments, door_cred_t *rarg) 3220 { 3221 int ret; 3222 format_t fru_format; 3223 hash_obj_t *hash_obj; 3224 3225 hash_obj = get_container_hash_object(SEGMENT_TYPE, section); 3226 if (hash_obj == NULL) { 3227 return (-1); 3228 } 3229 fru_format = hash_obj->u.cont_obj->format; 3230 ret = fruaccess_func[fru_format.format - 1].get_segments(section, 3231 segment, max_segments, rarg); 3232 return (ret); 3233 } 3234 3235 int 3236 fru_add_segment(section_hdl_t section, segment_t *segment, 3237 section_hdl_t *newsection, door_cred_t *cred) 3238 { 3239 int ret; 3240 format_t fru_format; 3241 hash_obj_t *hash_obj; 3242 3243 hash_obj = get_container_hash_object(SEGMENT_TYPE, section); 3244 if (hash_obj == NULL) { 3245 return (-1); 3246 } 3247 fru_format = hash_obj->u.cont_obj->format; 3248 3249 ret = fruaccess_func[fru_format.format - 1].add_segment(section, 3250 segment, newsection, cred); 3251 return (ret); 3252 } 3253 3254 int 3255 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection, 3256 door_cred_t *cred) 3257 { 3258 int ret; 3259 format_t fru_format; 3260 hash_obj_t *hash_obj; 3261 3262 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3263 if (hash_obj == NULL) { 3264 return (-1); 3265 } 3266 fru_format = hash_obj->u.cont_obj->format; 3267 ret = fruaccess_func[fru_format.format - 1].delete_segment(segment, 3268 newsection, cred); 3269 return (ret); 3270 } 3271 3272 ssize_t 3273 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes, 3274 door_cred_t *cred) 3275 { 3276 ssize_t ret; 3277 format_t fru_format; 3278 hash_obj_t *hash_obj; 3279 3280 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3281 if (hash_obj == NULL) { 3282 return (-1); 3283 } 3284 fru_format = hash_obj->u.cont_obj->format; 3285 ret = fruaccess_func[fru_format.format - 1].read_segment(segment, 3286 buffer, nbytes, cred); 3287 return (ret); 3288 } 3289 3290 int 3291 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes, 3292 segment_hdl_t *newsegment, door_cred_t *cred) 3293 { 3294 int ret; 3295 format_t fru_format; 3296 hash_obj_t *hash_obj; 3297 3298 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3299 if (hash_obj == NULL) { 3300 return (-1); 3301 } 3302 fru_format = hash_obj->u.cont_obj->format; 3303 3304 ret = fruaccess_func[fru_format.format - 1].write_segment(segment, 3305 data, nbytes, newsegment, cred); 3306 return (ret); 3307 } 3308 3309 int 3310 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred) 3311 { 3312 int ret; 3313 format_t fru_format; 3314 hash_obj_t *hash_obj; 3315 3316 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3317 if (hash_obj == NULL) { 3318 return (-1); 3319 } 3320 fru_format = hash_obj->u.cont_obj->format; 3321 3322 ret = fruaccess_func[fru_format.format - 1].get_num_packets(segment, 3323 cred); 3324 return (ret); 3325 } 3326 3327 int 3328 fru_get_packets(segment_hdl_t segment, packet_t *packet, 3329 int max_packets, door_cred_t *cred) 3330 { 3331 int ret; 3332 format_t fru_format; 3333 hash_obj_t *hash_obj; 3334 3335 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3336 if (hash_obj == NULL) { 3337 return (-1); 3338 } 3339 fru_format = hash_obj->u.cont_obj->format; 3340 3341 ret = fruaccess_func[fru_format.format - 1].get_packets(segment, 3342 packet, max_packets, cred); 3343 return (ret); 3344 } 3345 3346 ssize_t 3347 fru_get_payload(packet_hdl_t packet, void *buffer, 3348 size_t nbytes, door_cred_t *cred) 3349 { 3350 ssize_t ret; 3351 format_t fru_format; 3352 hash_obj_t *hash_obj; 3353 3354 hash_obj = lookup_handle_object(packet, PACKET_TYPE); 3355 if (hash_obj == NULL) { 3356 return (-1); 3357 } 3358 3359 hash_obj = get_container_hash_object(PACKET_TYPE, 3360 hash_obj->u.pkt_obj->segment_hdl); 3361 if (hash_obj == NULL) { 3362 return (-1); 3363 } 3364 fru_format = hash_obj->u.cont_obj->format; 3365 3366 ret = fruaccess_func[fru_format.format - 1].get_payload(packet, buffer, 3367 nbytes, cred); 3368 return (ret); 3369 } 3370 3371 int 3372 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes, 3373 packet_hdl_t *newpacket, door_cred_t *cred) 3374 { 3375 int ret; 3376 format_t fru_format; 3377 hash_obj_t *hash_obj; 3378 3379 hash_obj = lookup_handle_object(packet, PACKET_TYPE); 3380 if (hash_obj == NULL) { 3381 return (-1); 3382 } 3383 3384 hash_obj = get_container_hash_object(PACKET_TYPE, 3385 hash_obj->u.pkt_obj->segment_hdl); 3386 if (hash_obj == NULL) { 3387 return (-1); 3388 } 3389 fru_format = hash_obj->u.cont_obj->format; 3390 ret = fruaccess_func[fru_format.format - 1].update_payload(packet, data, 3391 nbytes, newpacket, cred); 3392 return (ret); 3393 } 3394 3395 int 3396 fru_append_packet(segment_hdl_t segment, packet_t *packet, 3397 const void *payload, size_t nbytes, segment_hdl_t *newsegment, 3398 door_cred_t *cred) 3399 { 3400 int ret; 3401 format_t fru_format; 3402 hash_obj_t *hash_obj; 3403 3404 hash_obj = get_container_hash_object(PACKET_TYPE, segment); 3405 if (hash_obj == NULL) { 3406 return (-1); 3407 } 3408 fru_format = hash_obj->u.cont_obj->format; 3409 3410 ret = fruaccess_func[fru_format.format - 1].append_packet(segment, 3411 packet, payload, nbytes, newsegment, cred); 3412 return (ret); 3413 } 3414 3415 int 3416 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment, 3417 door_cred_t *cred) 3418 { 3419 int ret; 3420 format_t fru_format; 3421 hash_obj_t *hash_obj; 3422 3423 hash_obj = lookup_handle_object(packet, PACKET_TYPE); 3424 if (hash_obj == NULL) { 3425 return (-1); 3426 } 3427 3428 hash_obj = get_container_hash_object(PACKET_TYPE, 3429 hash_obj->u.pkt_obj->segment_hdl); 3430 if (hash_obj == NULL) { 3431 return (-1); 3432 } 3433 fru_format = hash_obj->u.cont_obj->format; 3434 3435 ret = fruaccess_func[fru_format.format - 1].delete_packet(packet, 3436 newsegment, cred); 3437 return (ret); 3438 }