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 }