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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include "fru_access_impl.h"
33 #pragma init(initialize_fruaccess) /* .init section */
35 static hash_obj_t
*hash_table
[TABLE_SIZE
];
38 * seeprom is the driver_name for the SEEPROM device drivers in excalibur
39 * Define the devfsadm command to load the seeprom drivers if open fails.
42 static char devfsadm_cmd
[] = "/usr/sbin/devfsadm -i seeprom";
44 /* this routine initialize the hash table. */
47 initialize_fruaccess(void)
50 for (count
= 0; count
< TABLE_SIZE
; count
++) {
51 hash_table
[count
] = NULL
;
56 * called to lookup hash object for specified handle in the hash table.
61 lookup_handle_object(handle_t handle
, int object_type
)
63 handle_t index_to_hash
;
64 hash_obj_t
*first_hash_obj
;
65 hash_obj_t
*next_hash_obj
;
67 index_to_hash
= (handle
% TABLE_SIZE
);
69 first_hash_obj
= hash_table
[index_to_hash
];
70 for (next_hash_obj
= first_hash_obj
; next_hash_obj
!= NULL
;
71 next_hash_obj
= next_hash_obj
->next
) {
72 if ((handle
== next_hash_obj
->obj_hdl
) &&
73 (object_type
== next_hash_obj
->object_type
)) {
74 return (next_hash_obj
);
80 /* called to allocate container hash object */
83 create_container_hash_object(void)
86 container_obj_t
*cont_obj
;
88 cont_obj
= malloc(sizeof (container_obj_t
));
89 if (cont_obj
== NULL
) {
93 hash_obj
= malloc(sizeof (hash_obj_t
));
94 if (hash_obj
== NULL
) {
99 cont_obj
->sec_obj_list
= NULL
;
101 hash_obj
->object_type
= CONTAINER_TYPE
;
102 hash_obj
->u
.cont_obj
= cont_obj
;
103 hash_obj
->next
= NULL
;
104 hash_obj
->prev
= NULL
;
109 /* called to allocate section hash object */
112 create_section_hash_object(void)
114 hash_obj_t
*hash_obj
;
115 section_obj_t
*sec_obj
;
117 sec_obj
= malloc(sizeof (section_obj_t
));
118 if (sec_obj
== NULL
) {
122 hash_obj
= malloc(sizeof (hash_obj_t
));
123 if (hash_obj
== NULL
) {
128 sec_obj
->next
= NULL
;
129 sec_obj
->seg_obj_list
= NULL
;
131 hash_obj
->u
.sec_obj
= sec_obj
;
132 hash_obj
->object_type
= SECTION_TYPE
;
133 hash_obj
->next
= NULL
;
134 hash_obj
->prev
= NULL
;
139 /* called to allocate segment hash object */
142 create_segment_hash_object(void)
144 hash_obj_t
*hash_obj
;
145 segment_obj_t
*seg_obj
;
147 seg_obj
= malloc(sizeof (segment_obj_t
));
148 if (seg_obj
== NULL
) {
152 hash_obj
= malloc(sizeof (hash_obj_t
));
153 if (hash_obj
== NULL
) {
158 seg_obj
->next
= NULL
;
159 seg_obj
->pkt_obj_list
= NULL
;
161 hash_obj
->object_type
= SEGMENT_TYPE
;
162 hash_obj
->u
.seg_obj
= seg_obj
;
163 hash_obj
->next
= NULL
;
164 hash_obj
->prev
= NULL
;
169 /* called to allocate packet hash object */
172 create_packet_hash_object(void)
174 hash_obj_t
*hash_obj
;
175 packet_obj_t
*pkt_obj
;
177 pkt_obj
= malloc(sizeof (packet_obj_t
));
178 if (pkt_obj
== NULL
) {
182 hash_obj
= malloc(sizeof (hash_obj_t
));
183 if (hash_obj
== NULL
) {
188 pkt_obj
->next
= NULL
;
190 hash_obj
->object_type
= PACKET_TYPE
;
191 hash_obj
->u
.pkt_obj
= pkt_obj
;
192 hash_obj
->next
= NULL
;
193 hash_obj
->prev
= NULL
;
198 /* called to add allocated hash object into the hash table */
201 add_hashobject_to_hashtable(hash_obj_t
*hash_obj
)
203 handle_t index_to_hash
;
204 static uint64_t handle_count
= 0;
206 hash_obj
->obj_hdl
= ++handle_count
; /* store the handle */
209 index_to_hash
= ((hash_obj
->obj_hdl
) % TABLE_SIZE
);
211 hash_obj
->next
= hash_table
[index_to_hash
];
212 hash_table
[index_to_hash
] = hash_obj
; /* hash obj. added */
214 if (hash_obj
->next
!= NULL
) {
215 hash_obj
->next
->prev
= hash_obj
;
219 /* called to add section object list into the section list */
222 add_to_sec_object_list(hash_obj_t
*parent_obj
, hash_obj_t
*child_obj
)
224 hash_obj_t
*next_hash
;
226 child_obj
->u
.sec_obj
->cont_hdl
= parent_obj
->obj_hdl
;
227 if (parent_obj
->u
.cont_obj
->sec_obj_list
== NULL
) {
228 parent_obj
->u
.cont_obj
->sec_obj_list
= child_obj
;
232 for (next_hash
= parent_obj
->u
.cont_obj
->sec_obj_list
;
233 next_hash
->u
.sec_obj
->next
!= NULL
;
234 next_hash
= next_hash
->u
.sec_obj
->next
) {
238 next_hash
->u
.sec_obj
->next
= child_obj
;
241 /* called to add segment object list into segment list */
244 add_to_seg_object_list(hash_obj_t
*parent_obj
, hash_obj_t
*child_obj
)
246 hash_obj_t
*next_hash
;
248 child_obj
->u
.seg_obj
->section_hdl
= parent_obj
->obj_hdl
;
249 if (parent_obj
->u
.sec_obj
->seg_obj_list
== NULL
) {
250 parent_obj
->u
.sec_obj
->seg_obj_list
= child_obj
;
254 for (next_hash
= parent_obj
->u
.sec_obj
->seg_obj_list
;
255 next_hash
->u
.seg_obj
->next
!= NULL
;
256 next_hash
= next_hash
->u
.seg_obj
->next
) {
260 next_hash
->u
.seg_obj
->next
= child_obj
;
263 /* called to add packet object list into packet list */
266 add_to_pkt_object_list(hash_obj_t
*parent_obj
, hash_obj_t
*child_obj
)
268 hash_obj_t
*next_hash
;
270 /* add the packet object in the end of list */
271 child_obj
->u
.pkt_obj
->segment_hdl
= parent_obj
->obj_hdl
;
273 if (parent_obj
->u
.seg_obj
->pkt_obj_list
== NULL
) {
274 parent_obj
->u
.seg_obj
->pkt_obj_list
= child_obj
;
278 for (next_hash
= parent_obj
->u
.seg_obj
->pkt_obj_list
;
279 next_hash
->u
.pkt_obj
->next
!= NULL
;
280 next_hash
= next_hash
->u
.pkt_obj
->next
) {
284 next_hash
->u
.pkt_obj
->next
= child_obj
;
288 copy_segment_layout(segment_t
*seghdr
, void *layout
)
290 segment_layout_t
*seg_layout
;
292 seg_layout
= (segment_layout_t
*)layout
;
293 (void) memcpy(seghdr
->name
, &seg_layout
->name
, SEG_NAME_LEN
);
294 seghdr
->descriptor
= GET_SEGMENT_DESCRIPTOR
;
295 seghdr
->offset
= seg_layout
->offset
;
296 seghdr
->length
= seg_layout
->length
;
300 get_container_hash_object(int object_type
, handle_t handle
)
302 hash_obj_t
*hash_obj
;
304 switch (object_type
) {
305 case CONTAINER_TYPE
:
308 hash_obj
= lookup_handle_object(handle
, CONTAINER_TYPE
);
309 if (hash_obj
== NULL
) {
314 hash_obj
= lookup_handle_object(handle
, SECTION_TYPE
);
315 if (hash_obj
== NULL
) {
318 hash_obj
= lookup_handle_object(hash_obj
->u
.sec_obj
->cont_hdl
,
331 sort_offsettbl(int segcnt
, seg_info_t
*offset_tbl
)
337 for (cntx
= 0; cntx
< segcnt
+2; cntx
++) {
338 for (cnty
= cntx
+1; cnty
< segcnt
+ 2; cnty
++) {
339 if (offset_tbl
[cntx
].offset
>
340 offset_tbl
[cnty
].offset
) {
341 (void) memcpy(&tmp
, &offset_tbl
[cnty
],
342 sizeof (seg_info_t
));
343 (void) memcpy(&offset_tbl
[cnty
],
344 &offset_tbl
[cntx
], sizeof (seg_info_t
));
346 (void) memcpy(&offset_tbl
[cntx
], &tmp
,
347 sizeof (seg_info_t
));
354 * Description : move_segment_data() reads the segment data and writes it
355 * back to the new segment offset.
359 move_segment_data(void *seghdr
, int newoffset
, container_hdl_t contfd
)
363 segment_layout_t
*segment
;
365 segment
= (segment_layout_t
*)seghdr
;
367 buffer
= alloca(segment
->length
);
368 if (buffer
== NULL
) {
372 ret
= pread(contfd
, buffer
,
373 segment
->length
, segment
->offset
);
374 if (ret
!= segment
->length
) {
378 segment
->offset
= newoffset
;
380 ret
= pwrite(contfd
, buffer
, segment
->length
, segment
->offset
);
381 if (ret
!= segment
->length
) {
387 * Description : pack_segment_data() moves the segment data if there is
388 * a hole between two segments.
392 pack_segment_data(char *seghdr
, int segcnt
, container_hdl_t contfd
,
393 seg_info_t
*offset_tbl
)
399 for (cnt
= segcnt
+ 1; cnt
> 0; cnt
--) {
400 if (!offset_tbl
[cnt
- 1].fixed
) {
401 if (offset_tbl
[cnt
].offset
402 - (offset_tbl
[cnt
-1 ].offset
403 + offset_tbl
[cnt
- 1].length
) > 0) {
405 diff
= offset_tbl
[cnt
].offset
-
406 (offset_tbl
[cnt
- 1].offset
407 + offset_tbl
[cnt
- 1].length
);
408 newoffset
= offset_tbl
[cnt
- 1].offset
411 move_segment_data(seghdr
, newoffset
,
414 offset_tbl
[cnt
- 1].offset
= newoffset
;
416 sort_offsettbl(segcnt
, offset_tbl
);
423 * Description : build_offset_tbl() builds the offset table by reading all the
424 * segment header. it makes two more entry into the table one for
425 * section size and another with start of the section after the
430 build_offset_tbl(void *seghdr
, int segcnt
, int secsize
,
431 seg_info_t
*offset_tbl
)
434 fru_segdesc_t segdesc
;
435 segment_layout_t
*segment
;
437 for (cnt
= 0; cnt
< segcnt
; cnt
++) {
438 segment
= (segment_layout_t
*)(seghdr
) + cnt
;
440 (void) memcpy(&segdesc
, &segment
->descriptor
,
442 offset_tbl
[cnt
].segnum
= cnt
;
443 offset_tbl
[cnt
].offset
= segment
->offset
;
444 offset_tbl
[cnt
].length
= segment
->length
;
445 offset_tbl
[cnt
].fixed
= segdesc
.field
.fixed
;
448 /* upper boundary of segment area (lower address bytes) */
449 offset_tbl
[cnt
].segnum
= -1;
450 offset_tbl
[cnt
].offset
= sizeof (section_layout_t
) + ((cnt
+ 1)
451 * sizeof (segment_layout_t
));
453 offset_tbl
[cnt
].length
= 0;
454 offset_tbl
[cnt
].fixed
= 1;
455 /* lower boundary of segment area (higher address bytes) */
457 offset_tbl
[cnt
+1].segnum
= -1;
458 offset_tbl
[cnt
+1].offset
= secsize
;
459 offset_tbl
[cnt
+1].length
= 0;
460 offset_tbl
[cnt
+1].fixed
= 1;
465 hole_discovery(int bytes
, int segcnt
, int *totsize
, seg_info_t
*offset_tbl
)
470 for (cnt
= segcnt
+ 1; cnt
> 0; cnt
--) {
471 if (bytes
<= offset_tbl
[cnt
].offset
-
472 (offset_tbl
[cnt
- 1].offset
+
473 offset_tbl
[cnt
- 1].length
)) {
474 return (offset_tbl
[cnt
].offset
- bytes
);
477 *totsize
+= offset_tbl
[cnt
].offset
-
478 (offset_tbl
[cnt
- 1].offset
+
479 offset_tbl
[cnt
- 1].length
);
486 * Description : segment_hdr_present() verify space for new segment header to
491 segment_hdr_present(int segoffset
, int size
, seg_info_t
*offset_tbl
)
493 if ((segoffset
+ size
) <= offset_tbl
[0].offset
)
500 * Description : find_offset() is called from fru_add_segment routine to find
505 find_offset(char *seghdr
, int segcnt
, int secsize
, int *sectionoffset
,
506 int segsize
, int fix
, container_hdl_t contfd
)
511 seg_info_t
*offset_tbl
;
514 if (!fix
) { /* if not fixed segment */
515 *sectionoffset
= secsize
- segsize
;
521 * two extra segment info structure are allocated for start of segment
522 * and other end of segment. first segment offset is first available
523 * space and length is 0. second segment offset is is segment length and
524 * offset is 0. build_offset_tbl() explains how upper boundary and lower
525 * boudary segment area are initialized in seg_info_t table.
528 offset_tbl
= malloc((segcnt
+ 2) * sizeof (seg_info_t
));
529 if (offset_tbl
== NULL
) {
533 /* read all the segment header to make offset table */
534 ret
= build_offset_tbl(seghdr
, segcnt
, secsize
, offset_tbl
);
541 sort_offsettbl(segcnt
, offset_tbl
);
543 /* new segment header offset */
544 newoffset
= sizeof (section_layout_t
) + segcnt
*
545 sizeof (segment_layout_t
);
547 /* do? new segment header overlap any existing data */
548 ret
= segment_hdr_present(newoffset
, sizeof (segment_layout_t
),
550 if (ret
!= 0) { /* make room for new segment if possible */
552 /* look for hole in order to move segment data */
553 if (offset_tbl
[0].fixed
== SEGMENT_FIXED
) { /* fixed segment */
558 newoffset
= hole_discovery(offset_tbl
[0].length
,
559 segcnt
, &totsize
, offset_tbl
);
560 if (newoffset
!= 0) { /* found new offset */
562 offset_tbl
[0].offset
= newoffset
;
564 /* move the segment data */
565 move_segment_data(seghdr
, newoffset
, contfd
);
566 /* again sort the offset table */
567 sort_offsettbl(segcnt
, offset_tbl
);
569 /* pack the existing hole */
570 if (totsize
> offset_tbl
[0].length
) {
571 pack_segment_data(seghdr
, segcnt
,
581 newoffset
= hole_discovery(segsize
, segcnt
, &totsize
, offset_tbl
);
583 if (newoffset
== 0) { /* No hole found */
584 if (totsize
>= segsize
) {
585 pack_segment_data(seghdr
, segcnt
, contfd
,
587 newoffset
= hole_discovery(segsize
, segcnt
,
588 &totsize
, offset_tbl
);
589 if (newoffset
!= 0) {
590 *sectionoffset
= newoffset
;
596 *sectionoffset
= newoffset
;
605 tokenizer(char *buf
, char *separator
, char **nextBuf
, char *matched
)
610 for (i
= 0; buf
[i
] != '\0'; i
++) {
611 for (j
= 0; j
< strlen(separator
); j
++) {
612 if (buf
[i
] == separator
[j
]) {
614 *nextBuf
= &(buf
[i
+1]);
615 *matched
= separator
[j
];
627 get_container_info(const char *def_file
, const char *cont_desc_str
,
628 container_info_t
*cont_info
)
636 FILE *file
= fopen(def_file
, "r");
641 cont_info
->num_sections
= 0;
643 while (fgets(buf
, sizeof (buf
), file
) != NULL
) {
644 /* ignore all comments */
645 token
= tokenizer(buf
, "#", &field
, &matched
);
647 token
= tokenizer(buf
, ":", &field
, &matched
);
649 token
= tokenizer(token
, "|", &item
, &matched
);
650 while (token
!= 0x00) {
651 if (strcmp(token
, cont_desc_str
) == 0) {
655 token
= tokenizer(item
, "|", &item
, &matched
);
657 /* check the last remaining item */
658 if ((item
!= 0x00) &&
659 (strcmp(item
, cont_desc_str
) == 0)) {
668 token
= tokenizer(field
, ":", &field
, &matched
);
673 cont_info
->header_ver
= (headerrev_t
)atoi(token
);
675 token
= tokenizer(field
, ":\n", &field
, &matched
);
676 while (token
!= 0x00) {
677 token
= tokenizer(token
, ",", &item
, &matched
);
682 if (atoi(token
) == 1) {
683 cont_info
->section_info
[cont_info
->
684 num_sections
].description
.field
.read_only
= 1;
685 } else if (atoi(token
) == 0) {
686 cont_info
->section_info
[cont_info
->
687 num_sections
].description
.field
.read_only
= 0;
693 token
= tokenizer(item
, ",", &item
, &matched
);
699 if (atoi(token
) == 1) {
700 cont_info
->section_info
[cont_info
->
701 num_sections
].description
.field
.chk_type
= 1;
702 } else if (atoi(token
) == 0) {
703 cont_info
->section_info
[cont_info
->
704 num_sections
].description
.field
.chk_type
= 0;
711 token
= tokenizer(item
, ",", &item
, &matched
);
717 cont_info
->section_info
[cont_info
->num_sections
].
718 address
= atoi(token
);
725 cont_info
->section_info
[cont_info
->num_sections
].size
=
727 (cont_info
->num_sections
)++;
729 token
= tokenizer(field
, ":\n ", &field
, &matched
);
737 * Description :fru_open_container() opens the container associated with a fru.
738 * it's called by data plugin module before creating container
739 * property. it calls picltree library routine to get the
740 * device path and driver binding name for the fru to get the
741 * corresponding fru name that describe the fru layout.
743 * Arguments :picl_hdl_t fru
744 * A handle for PICL tree node of class "fru" representing the
745 * FRU with the container to open.
748 * On Success, a Positive integer container handle. is returned
749 * for use in subsequent fru operations;on error, 0 is returned
750 * and "errno" is set appropriately.
754 fru_open_container(picl_nodehdl_t fruhdl
)
759 char devpath
[PATH_MAX
];
760 hash_obj_t
*cont_hash_obj
;
761 hash_obj_t
*sec_hash_obj
;
762 picl_nodehdl_t tmphdl
;
763 picl_prophdl_t prophdl
;
764 ptree_propinfo_t propinfo
;
765 container_info_t cont_info
;
767 /* Get property handle of _seeprom_source under fru node */
768 retval
= ptree_get_propval_by_name(fruhdl
, PICL_REFPROP_SEEPROM_SRC
,
769 &tmphdl
, sizeof (tmphdl
));
770 if (retval
!= PICL_SUCCESS
) {
774 /* Get the device path of the fru */
775 retval
= ptree_get_propval_by_name(tmphdl
, PICL_PROP_DEVICEPATH
,
777 if (retval
!= PICL_SUCCESS
) {
781 retval
= ptree_get_prop_by_name(tmphdl
, PICL_PROP_BINDING_NAME
,
783 if (retval
!= PICL_SUCCESS
) {
787 retval
= ptree_get_propinfo(prophdl
, &propinfo
);
788 if (retval
!= PICL_SUCCESS
) {
792 bname
= alloca(propinfo
.piclinfo
.size
);
797 /* get the driver binding name */
798 retval
= ptree_get_propval(prophdl
, bname
, propinfo
.piclinfo
.size
);
799 if (retval
!= PICL_SUCCESS
) {
803 cont_hash_obj
= create_container_hash_object();
804 if (cont_hash_obj
== NULL
) {
808 add_hashobject_to_hashtable(cont_hash_obj
);
810 (void) strlcpy(cont_hash_obj
->u
.cont_obj
->device_pathname
, devpath
,
813 /* takes driver binding name as to get container information */
814 retval
= get_container_info(CONTAINER_CONF_FILE
, bname
, &cont_info
);
819 cont_hash_obj
->u
.cont_obj
->num_of_section
= cont_info
.num_sections
;
820 cont_hash_obj
->u
.cont_obj
->sec_obj_list
= NULL
;
822 for (count
= 0; count
< cont_info
.num_sections
; count
++) {
823 sec_hash_obj
= create_section_hash_object();
824 if (sec_hash_obj
== NULL
) {
828 add_hashobject_to_hashtable(sec_hash_obj
);
830 sec_hash_obj
->u
.sec_obj
->section
.offset
=
831 cont_info
.section_info
[count
].address
;
833 sec_hash_obj
->u
.sec_obj
->section
.protection
=
834 cont_info
.section_info
[count
].description
.field
.read_only
;
836 sec_hash_obj
->u
.sec_obj
->checksum_method
=
837 cont_info
.section_info
[count
].description
.field
.chk_type
;
839 sec_hash_obj
->u
.sec_obj
->section
.length
=
840 cont_info
.section_info
[count
].size
;
842 sec_hash_obj
->u
.sec_obj
->section
.version
= cont_info
.header_ver
;
844 add_to_sec_object_list(cont_hash_obj
, sec_hash_obj
);
846 return (cont_hash_obj
->obj_hdl
);
850 verify_header_crc8(headerrev_t head_ver
, unsigned char *bytes
, int length
)
853 unsigned char orig_crc8
= 0;
854 unsigned char calc_crc8
= 0;
857 case SECTION_HDR_VER
:
865 orig_crc8
= bytes
[crc_offset
];
866 bytes
[crc_offset
] = 0x00; /* clear for calc */
867 calc_crc8
= compute_crc8(bytes
, length
);
868 bytes
[crc_offset
] = orig_crc8
; /* restore */
870 return (orig_crc8
== calc_crc8
);
875 * fru_get_num_sections() returns number of sections in a
876 * container. it calls get_container_index() to get the container
877 * index number in the container list.
880 * container_hdl_t : container handle.
884 * On success, returns number of sections in a container.
889 fru_get_num_sections(container_hdl_t container
, door_cred_t
*cred
)
891 hash_obj_t
*hash_object
;
893 hash_object
= lookup_handle_object(container
, CONTAINER_TYPE
);
894 if (hash_object
== NULL
) {
898 return (hash_object
->u
.cont_obj
->num_of_section
);
902 * called from fru_get_sections()
906 get_section(int fd
, hash_obj_t
*sec_hash
, section_t
*section
)
912 hash_obj_t
*seg_hash
;
913 unsigned char *buffer
;
914 section_obj_t
*sec_obj
;
915 section_layout_t sec_hdr
;
916 segment_layout_t
*seg_hdr
;
917 segment_layout_t
*seg_buf
;
919 sec_obj
= sec_hash
->u
.sec_obj
;
920 if (sec_obj
== NULL
) {
924 /* populate section_t */
925 section
->handle
= sec_hash
->obj_hdl
;
926 section
->offset
= sec_obj
->section
.offset
;
927 section
->length
= sec_obj
->section
.length
;
928 section
->protection
= sec_obj
->section
.protection
;
929 section
->version
= sec_obj
->section
.version
;
930 sec_obj
->num_of_segment
= 0;
932 /* read section header layout */
933 retval
= pread(fd
, &sec_hdr
, sizeof (sec_hdr
),
934 sec_obj
->section
.offset
);
935 if (retval
!= sizeof (sec_hdr
)) {
939 hdrver
= GET_SECTION_HDR_VERSION
;
941 if ((sec_hdr
.headertag
!= SECTION_HDR_TAG
) &&
942 (hdrver
!= section
->version
)) {
946 /* size = section layout + total sizeof segment header */
947 size
= sizeof (sec_hdr
) + ((sec_hdr
.segmentcount
)
948 * sizeof (segment_layout_t
));
950 buffer
= alloca(size
);
951 if (buffer
== NULL
) {
955 /* segment header buffer */
956 seg_buf
= alloca(size
- sizeof (sec_hdr
));
957 if (seg_buf
== NULL
) {
961 /* read segment header */
962 retval
= pread(fd
, seg_buf
, size
- sizeof (sec_hdr
),
963 sec_obj
->section
.offset
+ sizeof (sec_hdr
));
964 if (retval
!= (size
- sizeof (sec_hdr
))) {
968 /* copy section header layout */
969 (void) memcpy(buffer
, &sec_hdr
, sizeof (sec_hdr
));
971 /* copy segment header layout */
972 (void) memcpy(buffer
+ sizeof (sec_hdr
), seg_buf
, size
-
976 retval
= verify_header_crc8(hdrver
, buffer
, size
);
977 if (retval
!= TRUE
) {
982 section
->version
= hdrver
;
983 sec_obj
->section
.version
= hdrver
;
985 seg_hdr
= (segment_layout_t
*)seg_buf
;
987 for (count
= 0; count
< sec_hdr
.segmentcount
; count
++, seg_hdr
++) {
988 seg_hash
= create_segment_hash_object();
989 if (seg_hash
== NULL
) {
993 add_hashobject_to_hashtable(seg_hash
);
995 copy_segment_layout(&seg_hash
->u
.seg_obj
->segment
, seg_hdr
);
997 add_to_seg_object_list(sec_hash
, seg_hash
);
999 sec_obj
->num_of_segment
++;
1008 di_node_t root_node
;
1009 di_node_t prom_node
;
1012 if ((root_node
= di_init("/", DINFOCPYALL
)) == DI_NODE_NIL
) {
1016 f_node
= di_drv_first_node(PICL_CLASS_SEEPROM
, root_node
);
1017 if (f_node
!= DI_NODE_NIL
) {
1018 phys_path
= di_devfs_path(f_node
);
1019 if ((prom_node
= di_init(phys_path
, DINFOMINOR
))
1023 (void) pclose(popen(devfsadm_cmd
, "r"));
1033 * fru_get_sections() fills an array of section structures passed
1037 * container_hdl_t : container handle(device descriptor).
1038 * section_t : array of section structure.
1039 * int : maximum number of section in a container.
1043 * On success,the number of section structures written is returned;
1044 * on error, -1 is returned and "errno" is set appropriately.
1050 fru_get_sections(container_hdl_t container
, section_t
*section
, int maxsec
,
1056 hash_obj_t
*cont_object
;
1057 hash_obj_t
*sec_hash
;
1059 cont_object
= lookup_handle_object(container
, CONTAINER_TYPE
);
1060 if (cont_object
== NULL
) {
1064 if (cont_object
->u
.cont_obj
->num_of_section
> maxsec
) {
1068 sec_hash
= cont_object
->u
.cont_obj
->sec_obj_list
;
1069 if (sec_hash
== NULL
) {
1074 device_fd
= open(cont_object
->u
.cont_obj
->device_pathname
,
1076 if (device_fd
>= 0) {
1079 } while ((retrys
-- > 0) && (call_devfsadm() == 0));
1081 if (device_fd
< 0) {
1085 for (count
= 0; count
< cont_object
->u
.cont_obj
->num_of_section
;
1086 count
++, section
++) {
1087 section
->version
= -1;
1088 /* populate section_t */
1089 get_section(device_fd
, sec_hash
, section
);
1090 sec_hash
= sec_hash
->u
.sec_obj
->next
;
1093 (void) close(device_fd
);
1100 * fru_get_num_segments() returns the current number of segments
1104 * section_hdl_t : section header holding section information.
1108 * On success, the number of segments in the argument section is
1109 * returned; on error -1 is returned.
1113 fru_get_num_segments(section_hdl_t section
, door_cred_t
*cred
)
1115 hash_obj_t
*sec_object
;
1116 section_obj_t
*sec_obj
;
1118 sec_object
= lookup_handle_object(section
, SECTION_TYPE
);
1119 if (sec_object
== NULL
) {
1123 sec_obj
= sec_object
->u
.sec_obj
;
1124 if (sec_obj
== NULL
) {
1128 return (sec_obj
->num_of_segment
);
1133 * fru_get_segments() fills an array of structures representing the
1134 * segments in a section.
1137 * section_hdl_t : holds section number.
1138 * segment_t : on success will hold segment information.
1139 * int : maximum number of segment.
1143 * On success, the number of segment structures written is
1144 * returned; on errno -1 is returned.
1149 fru_get_segments(section_hdl_t section
, segment_t
*segment
, int maxseg
,
1153 hash_obj_t
*sec_object
;
1154 hash_obj_t
*seg_object
;
1155 section_obj_t
*sec_obj
;
1157 sec_object
= lookup_handle_object(section
, SECTION_TYPE
);
1158 if (sec_object
== NULL
) {
1162 sec_obj
= sec_object
->u
.sec_obj
;
1163 if (sec_obj
== NULL
) {
1167 if (sec_obj
->num_of_segment
> maxseg
) {
1171 seg_object
= sec_object
->u
.sec_obj
->seg_obj_list
;
1172 if (seg_object
== NULL
) {
1176 for (count
= 0; count
< sec_obj
->num_of_segment
; count
++) {
1178 /* populate segment_t */
1179 segment
->handle
= seg_object
->obj_hdl
;
1180 (void) memcpy(segment
->name
,
1181 seg_object
->u
.seg_obj
->segment
.name
, SEG_NAME_LEN
);
1182 segment
->descriptor
= seg_object
->u
.seg_obj
->segment
.descriptor
;
1184 segment
->offset
= seg_object
->u
.seg_obj
->segment
.offset
;
1185 segment
->length
= seg_object
->u
.seg_obj
->segment
.length
;
1186 seg_object
= seg_object
->u
.seg_obj
->next
;
1194 * fru_add_segment() adds a segment to a section.
1197 * section_hdl_t section
1198 * A handle for the section in which to add the segment.
1200 * segment_t *segment
1201 * On entry, the "handle" component of "segment" is ignored and the
1202 * remaining components specify the parameters of the segment to be
1203 * added. On return, the "handle" component is set to the handle
1204 * for the added segment. The segment offset is mandatory for FIXED
1205 * segments; otherwise, the offset is advisory.
1209 * On success, 0 is returned; on error -1 is returned.
1214 fru_add_segment(section_hdl_t section
, segment_t
*segment
,
1215 section_hdl_t
*newsection
, door_cred_t
*cred
)
1226 char trailer
[] = { 0x0c, 0x00, 0x00, 0x00, 0x00 };
1227 hash_obj_t
*cont_hash
;
1228 hash_obj_t
*sec_hash
;
1229 hash_obj_t
*seg_hash
;
1230 fru_segdesc_t
*new_seg_desc
;
1231 unsigned char *crcbuf
;
1232 section_layout_t sec_layout
;
1233 segment_layout_t
*seg_layout
;
1234 segment_layout_t
*segment_buf
;
1236 /* check the effective uid of the client */
1237 if (cred
->dc_euid
!= 0) {
1239 return (-1); /* not a root */
1243 sec_hash
= lookup_handle_object(section
, SECTION_TYPE
);
1244 if (sec_hash
== NULL
) {
1248 /* check for read-only section */
1249 if (sec_hash
->u
.sec_obj
->section
.protection
== READ_ONLY_SECTION
) {
1254 /* look for duplicate segment */
1255 seg_hash
= sec_hash
->u
.sec_obj
->seg_obj_list
;
1256 while (seg_hash
!= NULL
) {
1257 if (strncmp(segment
->name
, seg_hash
->u
.seg_obj
->segment
.name
,
1258 SEG_NAME_LEN
) == 0) {
1260 return (-1); /* can't add duplicate segment */
1262 seg_hash
= seg_hash
->u
.seg_obj
->next
;
1265 /* get the container hash */
1266 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
1268 if (cont_hash
== NULL
) {
1272 /* open the container */
1273 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
1278 /* section start here */
1279 offset
= sec_hash
->u
.sec_obj
->section
.offset
;
1281 /* read section header layout */
1282 retval
= pread(fd
, &sec_layout
, sizeof (sec_layout
), offset
);
1283 if (retval
!= sizeof (sec_layout
)) {
1288 /* check for valid section header */
1289 if (sec_layout
.headertag
!= SECTION_HDR_TAG
) {
1290 /* write a new one */
1291 sec_layout
.headertag
= SECTION_HDR_TAG
;
1292 sec_layout
.headerversion
[0] = SECTION_HDR_VER_BIT0
;
1293 sec_layout
.headerversion
[1] = SECTION_HDR_VER_BIT1
;
1294 sec_layout
.headerlength
= sizeof (sec_layout
);
1295 sec_layout
.segmentcount
= 0;
1299 sec_size
= sec_hash
->u
.sec_obj
->section
.length
;
1301 /* number of segment in the section */
1302 seg_cnt
= sec_layout
.segmentcount
;
1304 /* total sizeof segment + new segment */
1305 bufsize
= sizeof (segment_layout_t
) * (seg_cnt
+ 1);
1306 segment_buf
= alloca(bufsize
);
1307 if (segment_buf
== NULL
) {
1311 /* read entire segment header */
1312 retval
= pread(fd
, segment_buf
, (bufsize
- sizeof (segment_layout_t
)),
1313 offset
+ sizeof (section_layout_t
));
1314 if (retval
!= (bufsize
- sizeof (segment_layout_t
))) {
1319 new_seg_offset
= segment
->offset
; /* new segment offset */
1320 new_seg_length
= segment
->length
; /* new segment length */
1322 new_seg_desc
= (fru_segdesc_t
*)&segment
->descriptor
;
1324 fixed_segment
= new_seg_desc
->field
.fixed
;
1326 /* get new offset for new segment to be addedd */
1327 retval
= find_offset((char *)segment_buf
, seg_cnt
, sec_size
,
1328 &new_seg_offset
, new_seg_length
, fixed_segment
, fd
);
1336 /* copy new segment data in segment layout */
1337 seg_layout
= (segment_layout_t
*)(segment_buf
+ seg_cnt
);
1338 (void) memcpy(&seg_layout
->name
, segment
->name
, SEG_NAME_LEN
);
1339 (void) memcpy(seg_layout
->descriptor
, &segment
->descriptor
,
1341 seg_layout
->length
= segment
->length
;
1342 seg_layout
->offset
= new_seg_offset
; /* new segment offset */
1344 sec_layout
.segmentcount
+= 1;
1346 crcbuf
= alloca(sizeof (section_layout_t
) + bufsize
);
1347 if (crcbuf
== NULL
) {
1352 sec_layout
.headercrc8
= 0;
1353 sec_layout
.headerlength
+= sizeof (segment_layout_t
);
1355 (void) memcpy(crcbuf
, (char *)&sec_layout
, sizeof (section_layout_t
));
1356 (void) memcpy(crcbuf
+ sizeof (section_layout_t
), segment_buf
, bufsize
);
1358 sec_layout
.headercrc8
= compute_crc8(crcbuf
, bufsize
+
1359 sizeof (section_layout_t
));
1361 /* write section header */
1362 retval
= pwrite(fd
, &sec_layout
, sizeof (section_layout_t
), offset
);
1363 if (retval
!= sizeof (section_layout_t
)) {
1368 /* write segment header */
1369 retval
= pwrite(fd
, segment_buf
, bufsize
, offset
+
1370 sizeof (section_layout_t
));
1371 if (retval
!= bufsize
) {
1376 /* write segment trailer */
1377 retval
= pwrite(fd
, &trailer
, sizeof (trailer
), new_seg_offset
);
1378 if (retval
!= sizeof (trailer
)) {
1385 /* create new segment hash object */
1386 seg_hash
= create_segment_hash_object();
1387 if (seg_hash
== NULL
) {
1391 add_hashobject_to_hashtable(seg_hash
);
1393 copy_segment_layout(&seg_hash
->u
.seg_obj
->segment
, seg_layout
);
1395 add_to_seg_object_list(sec_hash
, seg_hash
);
1397 sec_hash
->u
.sec_obj
->num_of_segment
+= 1;
1398 seg_hash
->u
.seg_obj
->trailer_offset
= new_seg_offset
;
1399 *newsection
= section
; /* return the new section handle */
1404 free_pkt_object_list(hash_obj_t
*hash_obj
)
1406 hash_obj_t
*next_obj
;
1407 hash_obj_t
*free_obj
;
1409 next_obj
= hash_obj
->u
.seg_obj
->pkt_obj_list
;
1410 while (next_obj
!= NULL
) {
1411 free_obj
= next_obj
;
1412 next_obj
= next_obj
->u
.pkt_obj
->next
;
1413 /* if prev is NULL it's the first object in the list */
1414 if (free_obj
->prev
== NULL
) {
1415 hash_table
[(free_obj
->obj_hdl
% TABLE_SIZE
)] =
1417 if (free_obj
->next
!= NULL
) {
1418 free_obj
->next
->prev
= free_obj
->prev
;
1421 free_obj
->prev
->next
= free_obj
->next
;
1422 if (free_obj
->next
!= NULL
) {
1423 free_obj
->next
->prev
= free_obj
->prev
;
1426 free(free_obj
->u
.pkt_obj
);
1430 hash_obj
->u
.seg_obj
->pkt_obj_list
= NULL
;
1434 free_segment_hash(handle_t handle
, hash_obj_t
*sec_hash
)
1436 hash_obj_t
*seg_hash
;
1437 hash_obj_t
*next_hash
;
1439 seg_hash
= sec_hash
->u
.sec_obj
->seg_obj_list
;
1440 if (seg_hash
== NULL
) {
1444 if (seg_hash
->obj_hdl
== handle
) {
1445 sec_hash
->u
.sec_obj
->seg_obj_list
= seg_hash
->u
.seg_obj
->next
;
1447 while (seg_hash
->obj_hdl
!= handle
) {
1448 next_hash
= seg_hash
;
1449 seg_hash
= seg_hash
->u
.seg_obj
->next
;
1450 if (seg_hash
== NULL
) {
1454 next_hash
->u
.seg_obj
->next
= seg_hash
->u
.seg_obj
->next
;
1457 if (seg_hash
->prev
== NULL
) {
1458 hash_table
[(seg_hash
->obj_hdl
% TABLE_SIZE
)] = seg_hash
->next
;
1459 if (seg_hash
->next
!= NULL
) {
1460 seg_hash
->next
->prev
= NULL
;
1463 seg_hash
->prev
->next
= seg_hash
->next
;
1464 if (seg_hash
->next
!= NULL
) {
1465 seg_hash
->next
->prev
= seg_hash
->prev
;
1469 free_pkt_object_list(seg_hash
);
1470 free(seg_hash
->u
.seg_obj
);
1476 * fru_delete_segment() deletes a segment from a section; the
1477 * associated container data is not altered.
1479 * Arguments : segment_hdl_t segment handle.
1480 * section_hdl_t new section handle.
1484 * On success, 0 returned; On error -1 is returned.
1488 fru_delete_segment(segment_hdl_t segment
, section_hdl_t
*newsection
,
1497 hash_obj_t
*seg_hash
;
1498 hash_obj_t
*sec_hash
;
1499 hash_obj_t
*cont_hash
;
1500 hash_obj_t
*tmp_hash
;
1501 unsigned char *buffer
;
1502 fru_segdesc_t
*desc
;
1503 segment_layout_t
*seg_buf
;
1504 section_layout_t
*sec_layout
;
1505 segment_layout_t
*seg_layout
;
1506 segment_layout_t
*next_layout
;
1508 /* check the effective uid of the client */
1509 if (cred
->dc_euid
!= 0) {
1511 return (-1); /* not a root */
1514 seg_hash
= lookup_handle_object(segment
, SEGMENT_TYPE
);
1515 if (seg_hash
== NULL
) {
1519 desc
= (fru_segdesc_t
*)&seg_hash
->u
.seg_obj
->segment
.descriptor
;
1520 if (!(desc
->field
.field_perm
& SEGMENT_DELETE
)) {
1522 return (-1); /* can't delete this segment */
1525 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
1527 if (sec_hash
== NULL
) {
1531 if (sec_hash
->u
.sec_obj
->section
.protection
== READ_ONLY_SECTION
) {
1536 num_of_seg
= sec_hash
->u
.sec_obj
->num_of_segment
;
1538 bufsize
= (sizeof (segment_layout_t
) * num_of_seg
);
1540 seg_buf
= alloca(bufsize
);
1541 if (seg_buf
== NULL
) {
1546 for (tmp_hash
= sec_hash
->u
.sec_obj
->seg_obj_list
; tmp_hash
!= NULL
;
1547 tmp_hash
= tmp_hash
->u
.seg_obj
->next
) {
1548 if (tmp_hash
->obj_hdl
== segment
) {
1554 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
1556 if (cont_hash
== NULL
) {
1560 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
1565 sec_layout
= alloca(sizeof (section_layout_t
));
1566 if (sec_layout
== NULL
) {
1571 /* read section layout header */
1572 retval
= pread(fd
, sec_layout
, sizeof (section_layout_t
),
1573 sec_hash
->u
.sec_obj
->section
.offset
);
1574 if (retval
!= sizeof (section_layout_t
)) {
1579 /* read segment header layout */
1580 retval
= pread(fd
, seg_buf
, bufsize
,
1581 sec_hash
->u
.sec_obj
->section
.offset
+
1582 sizeof (section_layout_t
));
1583 if (retval
!= bufsize
) {
1588 seg_layout
= (segment_layout_t
*)(seg_buf
+ segnum
);
1589 next_layout
= seg_layout
;
1590 for (count
= segnum
; count
< sec_hash
->u
.sec_obj
->num_of_segment
-1;
1593 (void) memcpy(seg_layout
, next_layout
,
1594 sizeof (segment_layout_t
));
1598 (void) memset(seg_layout
, '\0', sizeof (segment_layout_t
));
1600 sec_layout
->headercrc8
= 0;
1602 sec_layout
->headerlength
-= sizeof (segment_layout_t
);
1603 sec_layout
->segmentcount
-= 1;
1605 buffer
= alloca(sec_layout
->headerlength
);
1606 if (buffer
== NULL
) {
1611 (void) memcpy(buffer
, sec_layout
, sizeof (section_layout_t
));
1612 (void) memcpy(buffer
+ sizeof (section_layout_t
), seg_buf
, bufsize
1613 - sizeof (segment_layout_t
));
1614 sec_layout
->headercrc8
= compute_crc8(buffer
,
1615 sec_layout
->headerlength
);
1617 /* write section header with update crc8 and header length */
1618 retval
= pwrite(fd
, sec_layout
, sizeof (section_layout_t
),
1619 sec_hash
->u
.sec_obj
->section
.offset
);
1620 if (retval
!= sizeof (section_layout_t
)) {
1625 /* write the update segment header */
1626 retval
= pwrite(fd
, seg_buf
, bufsize
,
1627 sec_hash
->u
.sec_obj
->section
.offset
+
1628 sizeof (section_layout_t
));
1630 if (retval
!= bufsize
) {
1634 free_segment_hash(segment
, sec_hash
);
1636 *newsection
= sec_hash
->obj_hdl
;
1637 sec_hash
->u
.sec_obj
->num_of_segment
= sec_layout
->segmentcount
;
1644 * fru_read_segment() reads the raw contents of a segment.
1646 * Arguments : segment_hdl_t : segment handle.
1647 * void * : buffer containing segment data when function returns.
1648 * size_t :number of bytes.
1652 * On success, the number of bytes read is returned;
1655 * Segments containing packets can be read in structured fashion
1656 * using the fru_get_packets() and fru_get_payload() primitives;the
1657 * entire byte range of a segment can be read using
1658 * fru_read_segment().
1662 fru_read_segment(segment_hdl_t segment
, void *buffer
, size_t nbytes
,
1667 hash_obj_t
*seg_hash
;
1668 hash_obj_t
*sec_hash
;
1669 hash_obj_t
*cont_hash
;
1671 /* segment hash object */
1672 seg_hash
= lookup_handle_object(segment
, SEGMENT_TYPE
);
1673 if (seg_hash
== NULL
) {
1677 /* section hash object */
1678 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
1680 if (sec_hash
== NULL
) {
1684 /* container hash object */
1685 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
1687 if (cont_hash
== NULL
) {
1691 if (seg_hash
->u
.seg_obj
->segment
.length
< nbytes
) {
1695 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
1700 retval
= pread(fd
, buffer
, nbytes
, seg_hash
->u
.seg_obj
->segment
.offset
);
1702 if (retval
!= nbytes
) {
1710 * fru_write_segment() writes a raw segment.
1712 * Arguments : segment_hdl_t :segment handle.
1713 * const void * : data buffer.
1714 * size_t : number of bytes.
1715 * segment_hdl_t : new segment handle.
1719 * On success, the number of bytes written is returned
1724 fru_write_segment(segment_hdl_t segment
, const void *data
, size_t nbytes
,
1725 segment_hdl_t
*newsegment
, door_cred_t
*cred
)
1732 get_packet(int device_fd
, void *buffer
, int size
, int offset
)
1736 retval
= pread(device_fd
, (char *)buffer
, size
, offset
);
1745 * get_payload() populates a buffer with the packets payload
1747 * Arguments : hash_obj_t : packet.
1748 * int : device file descriptor
1749 * uint8_t* : pointer to a pre allocated buffer
1754 * On success, 0 is returned; on failure
1758 get_payload(int device_fd
, hash_obj_t
*packet
, uint8_t *payload
)
1761 packet_obj_t
*packet_object
;
1764 packet_object
= packet
->u
.pkt_obj
;
1765 if (packet_object
== NULL
) {
1770 retval
= pread(device_fd
, payload
, packet_object
->paylen
,
1771 packet_object
->payload_offset
);
1772 if (retval
!= packet_object
->paylen
) {
1783 get_checksum_crc(int device_fd
, hash_obj_t
*seg_hash
, int data_size
)
1790 hash_obj_t
*sec_hash
;
1791 hash_obj_t
*pkt_hash
;
1792 unsigned char *buffer
;
1794 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
1796 if (sec_hash
== NULL
) {
1797 return ((uint32_t)-1);
1800 buffer
= alloca(data_size
);
1801 if (buffer
== NULL
) {
1802 return ((uint32_t)-1);
1805 /* traverse the packet object list for all the tags and payload */
1806 for (pkt_hash
= seg_hash
->u
.seg_obj
->pkt_obj_list
; pkt_hash
!= NULL
;
1807 pkt_hash
= pkt_hash
->u
.pkt_obj
->next
) {
1808 (void) memcpy(buffer
+ offset
, &pkt_hash
->u
.pkt_obj
->tag
,
1809 pkt_hash
->u
.pkt_obj
->tag_size
);
1810 offset
+= pkt_hash
->u
.pkt_obj
->tag_size
;
1812 /* read packet payload */
1813 payload
= malloc(pkt_hash
->u
.pkt_obj
->paylen
);
1814 if (payload
== NULL
) {
1815 return ((uint32_t)-1);
1817 retval
= get_payload(device_fd
, pkt_hash
, payload
);
1820 return ((uint32_t)-1);
1822 (void) memcpy(buffer
+ offset
, payload
,
1823 pkt_hash
->u
.pkt_obj
->paylen
);
1824 offset
+= pkt_hash
->u
.pkt_obj
->paylen
;
1828 checksum
= sec_hash
->u
.sec_obj
->checksum_method
;
1830 if (checksum
== CRC32_SECTION
) { /* read-only section */
1831 crc
= compute_crc32(buffer
, data_size
);
1832 } else { /* read/write section */
1833 crc
= compute_checksum32(buffer
, data_size
);
1835 return (crc
); /* computed crc */
1839 get_packets(hash_obj_t
*seg_hash
, int device_fd
, int offset
, int length
)
1850 hash_obj_t
*pkt_hash_obj
;
1851 fru_segdesc_t
*segdesc
;
1852 fru_tagtype_t tagtype
;
1854 retval
= get_packet(device_fd
, &tag
, sizeof (fru_tag_t
), offset
);
1859 seg_hash
->u
.seg_obj
->trailer_offset
= offset
;
1861 data
= (char *)&tag
;
1862 while (data
[0] != SEG_TRAILER_TAG
) {
1863 tagtype
= get_tag_type(&tag
); /* verify tag type */
1864 if (tagtype
== -1) {
1868 tag_size
= get_tag_size(tagtype
);
1869 if (tag_size
== -1) {
1873 seg_limit
+= tag_size
;
1874 if (seg_limit
> length
) {
1878 paylen
= get_payload_length((void *)&tag
);
1883 seg_limit
+= paylen
;
1884 if (seg_limit
> length
) {
1888 pkt_hash_obj
= create_packet_hash_object();
1889 if (pkt_hash_obj
== NULL
) {
1895 /* don't change this */
1896 pkt_hash_obj
->u
.pkt_obj
->tag
.raw_data
= 0;
1897 (void) memcpy(&pkt_hash_obj
->u
.pkt_obj
->tag
, &tag
, tag_size
);
1898 pkt_hash_obj
->u
.pkt_obj
->paylen
= paylen
;
1899 pkt_hash_obj
->u
.pkt_obj
->tag_size
= tag_size
;
1900 pkt_hash_obj
->u
.pkt_obj
->payload_offset
= offset
;
1904 add_hashobject_to_hashtable(pkt_hash_obj
);
1905 add_to_pkt_object_list(seg_hash
, pkt_hash_obj
);
1909 retval
= get_packet(device_fd
, &tag
, sizeof (fru_tag_t
),
1915 data
= (char *)&tag
;
1918 segdesc
= (fru_segdesc_t
*)&seg_hash
->u
.seg_obj
->segment
.descriptor
;
1920 seg_hash
->u
.seg_obj
->trailer_offset
= offset
;
1922 if (!segdesc
->field
.ignore_checksum
) {
1923 crc
= get_checksum_crc(device_fd
, seg_hash
, seg_limit
);
1924 offset
= seg_hash
->u
.seg_obj
->segment
.offset
;
1926 retval
= pread(device_fd
, &origcrc
, sizeof (origcrc
),
1927 offset
+ seg_limit
+ 1);
1928 if (retval
!= sizeof (origcrc
)) {
1932 if (origcrc
!= crc
) {
1933 seg_hash
->u
.seg_obj
->trailer_offset
= offset
;
1943 * fru_get_num_packets() returns the current number of packets
1946 * Arguments : segment_hdl_t : segment handle.
1950 * On success, the number of packets is returned;
1955 fru_get_num_packets(segment_hdl_t segment
, door_cred_t
*cred
)
1961 hash_obj_t
*cont_hash_obj
;
1962 hash_obj_t
*seg_hash
;
1963 fru_segdesc_t
*segdesc
;
1964 segment_obj_t
*segment_object
;
1966 seg_hash
= lookup_handle_object(segment
, SEGMENT_TYPE
);
1967 if (seg_hash
== NULL
) {
1971 segment_object
= seg_hash
->u
.seg_obj
;
1972 if (segment_object
== NULL
) {
1977 segdesc
= (fru_segdesc_t
*)&segment_object
->segment
.descriptor
;
1978 if (segdesc
->field
.opaque
) {
1982 offset
= segment_object
->segment
.offset
;
1983 length
= segment_object
->segment
.length
;
1985 cont_hash_obj
= get_container_hash_object(SEGMENT_TYPE
,
1986 segment_object
->section_hdl
);
1988 if (cont_hash_obj
== NULL
) {
1992 if (seg_hash
->u
.seg_obj
->pkt_obj_list
!= NULL
) {
1993 return (segment_object
->num_of_packets
);
1996 segment_object
->num_of_packets
= 0;
1997 device_fd
= open(cont_hash_obj
->u
.cont_obj
->device_pathname
,
1999 if (device_fd
< 0) {
2003 pktcnt
= get_packets(seg_hash
, device_fd
, offset
,
2006 free_pkt_object_list(seg_hash
);
2007 seg_hash
->u
.seg_obj
->pkt_obj_list
= NULL
;
2010 segment_object
->num_of_packets
= pktcnt
;
2011 (void) close(device_fd
);
2013 return (segment_object
->num_of_packets
);
2019 * fru_get_packets() fills an array of structures representing the
2020 * packets in a segment.
2022 * Arguments : segment_hdl_t : segment handle.
2023 * packet_t : packet buffer.
2024 * int : maximum number of packets.
2028 * On success, the number of packet structures written is returned;
2029 * On failure -1 is returned;
2034 fru_get_packets(segment_hdl_t segment
, packet_t
*packet
, int maxpackets
,
2038 hash_obj_t
*seg_hash_obj
;
2039 hash_obj_t
*pkt_hash_obj
;
2041 /* segment hash object */
2042 seg_hash_obj
= lookup_handle_object(segment
, SEGMENT_TYPE
);
2043 if (seg_hash_obj
== NULL
) {
2047 if (seg_hash_obj
->u
.seg_obj
->num_of_packets
!= maxpackets
) {
2051 pkt_hash_obj
= seg_hash_obj
->u
.seg_obj
->pkt_obj_list
;
2052 if (pkt_hash_obj
== NULL
) {
2056 for (count
= 0; count
< maxpackets
; count
++, packet
++) {
2057 packet
->handle
= pkt_hash_obj
->obj_hdl
;
2059 (void) memcpy(&packet
->tag
, &pkt_hash_obj
->u
.pkt_obj
->tag
,
2060 pkt_hash_obj
->u
.pkt_obj
->tag_size
);
2061 pkt_hash_obj
= pkt_hash_obj
->u
.pkt_obj
->next
;
2069 * fru_get_payload() copies the contents of a packet's payload.
2071 * Arguments : packet_hdl_t : packet handle.
2072 * void * : payload buffer.
2073 * size_t : sizeof the buffer.
2077 * On success, the number of bytes copied is returned; On error
2082 fru_get_payload(packet_hdl_t packet
, void *buffer
, size_t nbytes
,
2088 hash_obj_t
*packet_hash_obj
;
2089 hash_obj_t
*segment_hash_obj
;
2090 hash_obj_t
*container_hash_obj
;
2092 /* packet hash object */
2093 packet_hash_obj
= lookup_handle_object(packet
, PACKET_TYPE
);
2094 if (packet_hash_obj
== NULL
) {
2098 payload
= malloc(packet_hash_obj
->u
.pkt_obj
->paylen
);
2099 if (payload
== NULL
) {
2103 /* lookup the segment hash object */
2105 lookup_handle_object(packet_hash_obj
->u
.pkt_obj
->segment_hdl
,
2107 if (segment_hash_obj
== NULL
) {
2112 /* Get the container hash object to get the seeprom device path */
2113 container_hash_obj
= get_container_hash_object(SEGMENT_TYPE
,
2114 segment_hash_obj
->u
.seg_obj
->section_hdl
);
2115 if (container_hash_obj
== NULL
) {
2120 /* Open the seeprom device */
2121 device_fd
= open(container_hash_obj
->u
.cont_obj
->device_pathname
,
2123 if (device_fd
< 0) {
2129 /* Call to get the payload */
2130 retval
= get_payload(device_fd
, packet_hash_obj
, payload
);
2133 (void) close(device_fd
);
2138 /* verify payload length */
2139 if (nbytes
!= packet_hash_obj
->u
.pkt_obj
->paylen
) {
2141 (void) close(device_fd
);
2145 (void) memcpy(buffer
, payload
, nbytes
);
2147 (void) close(device_fd
);
2153 * fru_update_payload() writes the contents of a packet's payload.
2155 * Arguments : packet_hdl_t : packet handle.
2156 * const void * : data buffer.
2157 * size_t : buffer size.
2158 * packet_hdl_t : new packet handle.
2162 * On success, 0 is returned; on failure
2167 fru_update_payload(packet_hdl_t packet
, const void *data
, size_t nbytes
,
2168 packet_hdl_t
*newpacket
, door_cred_t
*cred
)
2175 hash_obj_t
*pkt_hash
;
2176 hash_obj_t
*seg_hash
;
2177 hash_obj_t
*sec_hash
;
2178 hash_obj_t
*cont_hash
;
2179 fru_segdesc_t
*desc
;
2181 /* check the effective uid of the client */
2182 if (cred
->dc_euid
!= 0) {
2184 return (-1); /* not a root */
2187 /* packet hash object */
2188 pkt_hash
= lookup_handle_object(packet
, PACKET_TYPE
);
2189 if (pkt_hash
== NULL
) {
2193 /* segment hash object */
2194 seg_hash
= lookup_handle_object(pkt_hash
->u
.pkt_obj
->segment_hdl
,
2196 if (seg_hash
== NULL
) {
2200 /* check for write perm. */
2201 desc
= (fru_segdesc_t
*)&seg_hash
->u
.seg_obj
->segment
.descriptor
;
2202 if (!(desc
->field
.field_perm
& SEGMENT_WRITE
)) {
2204 return (-1); /* write not allowed */
2207 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
2209 if (sec_hash
== NULL
) {
2213 if (sec_hash
->u
.sec_obj
->section
.protection
== READ_ONLY_SECTION
) {
2215 return (-1); /* read-only section */
2218 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
2220 if (cont_hash
== NULL
) {
2224 if (pkt_hash
->u
.pkt_obj
->paylen
!= nbytes
) {
2228 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
2233 trailer_offset
= seg_hash
->u
.seg_obj
->trailer_offset
;
2234 segment_offset
= seg_hash
->u
.seg_obj
->segment
.offset
;
2236 crc
= get_checksum_crc(fd
, seg_hash
, (trailer_offset
- segment_offset
));
2237 retval
= pwrite(fd
, data
, nbytes
, pkt_hash
->u
.pkt_obj
->payload_offset
);
2238 if (retval
!= nbytes
) {
2243 retval
= pwrite(fd
, &crc
, sizeof (crc
), trailer_offset
+ 1);
2245 if (retval
!= sizeof (crc
)) {
2248 *newpacket
= packet
;
2254 * fru_append_packet() appends a packet to a segment.
2257 * segment_hdl_t segment
2258 * A handle for the segment to which the packet will be appended.
2261 * On entry, the "tag" component of "packet" specifies the tag
2262 * value for the added packet; the "handle" component is ignored.
2263 * On return, the "handle" component is set to the handle of the
2266 * const void *payload
2267 * A pointer to the caller's buffer containing the payload data for
2268 * the appended packet.
2271 * The size of the caller buffer.
2275 * On success, 0 is returned; on error -1 is returned;
2279 fru_append_packet(segment_hdl_t segment
, packet_t
*packet
, const void *payload
,
2280 size_t nbytes
, segment_hdl_t
*newsegment
, door_cred_t
*cred
)
2286 char trailer
[] = {0x0c, 0x00, 0x00, 0x00, 0x00};
2288 hash_obj_t
*seg_hash
;
2289 hash_obj_t
*sec_hash
;
2290 hash_obj_t
*pkt_hash
;
2291 hash_obj_t
*cont_hash
;
2292 fru_tagtype_t tagtype
;
2293 fru_segdesc_t
*desc
;
2295 /* check the effective uid of the client */
2296 if (cred
->dc_euid
!= 0) {
2298 return (-1); /* not a root */
2301 seg_hash
= lookup_handle_object(segment
, SEGMENT_TYPE
);
2302 if (seg_hash
== NULL
) {
2306 /* check for write perm. */
2307 desc
= (fru_segdesc_t
*)&seg_hash
->u
.seg_obj
->segment
.descriptor
;
2308 if (!(desc
->field
.field_perm
& SEGMENT_WRITE
)) {
2310 return (-1); /* write not allowed */
2313 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
2315 if (sec_hash
== NULL
) {
2319 if (sec_hash
->u
.sec_obj
->section
.protection
== READ_ONLY_SECTION
) {
2321 return (-1); /* read-only section */
2324 trailer_offset
= seg_hash
->u
.seg_obj
->trailer_offset
;
2327 * if trailer offset is 0 than parse the segment data to get the trailer
2328 * offset to compute the remaining space left in the segment area for
2329 * new packet to be added.
2331 if (trailer_offset
== 0) {
2332 (void) fru_get_num_packets(segment
, cred
);
2333 trailer_offset
= seg_hash
->u
.seg_obj
->trailer_offset
;
2336 tagtype
= get_tag_type((void *)&packet
->tag
);
2337 if (tagtype
== -1) {
2341 tag_size
= get_tag_size(tagtype
);
2342 if (tag_size
== -1) {
2346 if (seg_hash
->u
.seg_obj
->segment
.length
>
2347 ((trailer_offset
- seg_hash
->u
.seg_obj
->segment
.offset
) +
2348 tag_size
+ nbytes
+ sizeof (char)
2349 + sizeof (uint32_t))) {
2350 /* create new packet hash */
2351 pkt_hash
= create_packet_hash_object();
2352 if (pkt_hash
== NULL
) {
2356 /* tag initialization */
2357 (void) memcpy(&pkt_hash
->u
.pkt_obj
->tag
, &packet
->tag
,
2359 pkt_hash
->u
.pkt_obj
->tag_size
= tag_size
;
2360 pkt_hash
->u
.pkt_obj
->paylen
= nbytes
;
2361 pkt_hash
->u
.pkt_obj
->payload_offset
= trailer_offset
+ tag_size
;
2363 /* add to hash table */
2364 add_hashobject_to_hashtable(pkt_hash
);
2366 add_to_pkt_object_list(seg_hash
, pkt_hash
);
2368 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
2370 if (cont_hash
== NULL
) {
2374 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
2379 /* update the trailer offset */
2380 trailer_offset
+= tag_size
+ nbytes
;
2382 /* calculate new checksum */
2383 crc
= get_checksum_crc(fd
, seg_hash
, (trailer_offset
-
2384 seg_hash
->u
.seg_obj
->segment
.offset
));
2386 retval
= pwrite(fd
, &packet
->tag
, tag_size
, trailer_offset
2387 - (tag_size
+ nbytes
));
2388 if (retval
!= tag_size
) {
2393 retval
= pwrite(fd
, payload
, nbytes
, trailer_offset
- nbytes
);
2394 if (retval
!= nbytes
) {
2399 retval
= pwrite(fd
, trailer
, sizeof (trailer
), trailer_offset
);
2400 if (retval
!= sizeof (trailer
)) {
2405 retval
= pwrite(fd
, &crc
, sizeof (crc
), trailer_offset
+ 1);
2407 if (retval
!= sizeof (crc
)) {
2411 seg_hash
->u
.seg_obj
->trailer_offset
= trailer_offset
;
2412 seg_hash
->u
.seg_obj
->num_of_packets
+= 1;
2414 *newsegment
= segment
; /* return new segment handle */
2424 adjust_packets(int fd
, hash_obj_t
*free_obj
, hash_obj_t
*object_list
)
2428 uint32_t new_offset
;
2429 hash_obj_t
*hash_ptr
;
2432 new_offset
= free_obj
->u
.pkt_obj
->payload_offset
2433 - free_obj
->u
.pkt_obj
->tag_size
;
2434 for (hash_ptr
= object_list
; hash_ptr
!= NULL
;
2435 hash_ptr
= hash_ptr
->u
.pkt_obj
->next
) {
2437 payload
= malloc(hash_ptr
->u
.pkt_obj
->paylen
);
2438 if (payload
== NULL
) {
2441 retval
= get_payload(fd
, hash_ptr
, payload
);
2447 retval
= pwrite(fd
, &hash_ptr
->u
.pkt_obj
->tag
,
2448 hash_ptr
->u
.pkt_obj
->tag_size
, new_offset
);
2449 if (retval
!= hash_ptr
->u
.pkt_obj
->tag_size
) {
2453 new_offset
+= hash_ptr
->u
.pkt_obj
->tag_size
;
2454 hash_ptr
->u
.pkt_obj
->payload_offset
= new_offset
;
2455 retval
= pwrite(fd
, payload
,
2456 hash_ptr
->u
.pkt_obj
->paylen
, new_offset
);
2457 if (retval
!= hash_ptr
->u
.pkt_obj
->paylen
) {
2461 new_offset
+= hash_ptr
->u
.pkt_obj
->paylen
;
2467 free_packet_object(handle_t handle
, hash_obj_t
*seg_hash
)
2469 hash_obj_t
*pkt_hash
;
2470 hash_obj_t
*next_hash
;
2472 pkt_hash
= seg_hash
->u
.seg_obj
->pkt_obj_list
;
2473 if (pkt_hash
== NULL
) {
2477 if (pkt_hash
->obj_hdl
== handle
) {
2478 seg_hash
->u
.seg_obj
->pkt_obj_list
= pkt_hash
->u
.pkt_obj
->next
;
2480 while (pkt_hash
->obj_hdl
!= handle
) {
2481 next_hash
= pkt_hash
;
2482 pkt_hash
= pkt_hash
->u
.pkt_obj
->next
;
2483 if (pkt_hash
== NULL
) {
2487 next_hash
->u
.pkt_obj
->next
= pkt_hash
->u
.pkt_obj
->next
;
2490 if (pkt_hash
->prev
== NULL
) {
2491 hash_table
[(pkt_hash
->obj_hdl
% TABLE_SIZE
)] = pkt_hash
->next
;
2492 if (pkt_hash
->next
!= NULL
) {
2493 pkt_hash
->next
->prev
= NULL
;
2496 pkt_hash
->prev
->next
= pkt_hash
->next
;
2497 if (pkt_hash
->next
!= NULL
) {
2498 pkt_hash
->next
->prev
= pkt_hash
->prev
;
2502 free(pkt_hash
->u
.pkt_obj
);
2508 * fru_delete_packet() deletes a packet from a segment.
2510 * Arguments : packet_hdl_t : packet number to be deleted.
2511 * segment_hdl_t : new segment handler.
2515 * On success, 0 is returned; on error, -1.
2518 * Packets are adjacent; thus, deleting a packet requires moving
2519 * succeeding packets to compact the resulting hole.
2523 fru_delete_packet(packet_hdl_t packet
, segment_hdl_t
*newsegment
,
2528 char trailer
[] = { 0x0c, 0x00, 0x00, 0x00, 0x00};
2530 hash_obj_t
*tmp_obj
;
2531 hash_obj_t
*pkt_hash
;
2532 hash_obj_t
*sec_hash
;
2533 hash_obj_t
*cont_hash
;
2534 hash_obj_t
*prev_obj
;
2535 hash_obj_t
*seg_hash
;
2536 fru_segdesc_t
*desc
;
2538 /* check the effective uid of the client */
2539 if (cred
->dc_euid
!= 0) {
2541 return (-1); /* not a root */
2544 /* packet hash object */
2545 pkt_hash
= lookup_handle_object(packet
, PACKET_TYPE
);
2546 if (pkt_hash
== NULL
) {
2550 /* segment hash object */
2551 seg_hash
= lookup_handle_object(pkt_hash
->u
.pkt_obj
->segment_hdl
,
2553 if (seg_hash
== NULL
) {
2557 /* check for write perm. */
2558 desc
= (fru_segdesc_t
*)&seg_hash
->u
.seg_obj
->segment
.descriptor
;
2559 if (!(desc
->field
.field_perm
& SEGMENT_WRITE
)) {
2561 return (-1); /* write not allowed */
2564 /* section hash object */
2565 sec_hash
= lookup_handle_object(seg_hash
->u
.seg_obj
->section_hdl
,
2567 if (sec_hash
== NULL
) {
2571 if (sec_hash
->u
.sec_obj
->section
.protection
== READ_ONLY_SECTION
) {
2573 return (-1); /* read-only section */
2576 prev_obj
= seg_hash
->u
.seg_obj
->pkt_obj_list
;
2577 if (prev_obj
== NULL
) {
2581 /* container hash object */
2582 cont_hash
= lookup_handle_object(sec_hash
->u
.sec_obj
->cont_hdl
,
2584 if (cont_hash
== NULL
) {
2588 fd
= open(cont_hash
->u
.cont_obj
->device_pathname
, O_RDWR
);
2593 if (prev_obj
->obj_hdl
== packet
) { /* first object to be deleted */
2594 adjust_packets(fd
, prev_obj
, prev_obj
->u
.pkt_obj
->next
);
2595 seg_hash
->u
.seg_obj
->trailer_offset
-=
2596 (prev_obj
->u
.pkt_obj
->tag_size
2597 + prev_obj
->u
.pkt_obj
->paylen
);
2598 free_packet_object(packet
, seg_hash
);
2600 for (tmp_obj
= prev_obj
;
2601 tmp_obj
!= NULL
; tmp_obj
= tmp_obj
->u
.pkt_obj
->next
) {
2602 /* found the object */
2603 if (tmp_obj
->obj_hdl
== packet
) {
2604 adjust_packets(fd
, tmp_obj
,
2605 tmp_obj
->u
.pkt_obj
->next
);
2606 seg_hash
->u
.seg_obj
->trailer_offset
-=
2607 (tmp_obj
->u
.pkt_obj
->tag_size
2608 + tmp_obj
->u
.pkt_obj
->paylen
);
2609 free_packet_object(packet
, seg_hash
);
2614 seg_hash
->u
.seg_obj
->num_of_packets
-= 1;
2616 /* calculate checksum */
2617 crc
= get_checksum_crc(fd
, seg_hash
,
2618 (seg_hash
->u
.seg_obj
->trailer_offset
2619 - seg_hash
->u
.seg_obj
->segment
.offset
));
2620 /* write trailer at new offset */
2621 retval
= pwrite(fd
, &trailer
, sizeof (trailer
),
2622 seg_hash
->u
.seg_obj
->trailer_offset
);
2623 if (retval
!= sizeof (trailer
)) {
2628 /* write the checksum value */
2629 retval
= pwrite(fd
, &crc
, sizeof (crc
),
2630 seg_hash
->u
.seg_obj
->trailer_offset
+ 1);
2632 if (retval
!= sizeof (crc
)) {
2636 *newsegment
= seg_hash
->obj_hdl
; /* return new segment handle */
2642 * fru_close_container() removes the association between a
2643 * container and its handle. this routines free's up all the
2644 * hash object contained under container.
2647 * container_hdl_t holds the file descriptor of the fru.
2657 fru_close_container(container_hdl_t container
)
2659 hash_obj_t
*hash_obj
;
2660 hash_obj_t
*prev_hash
;
2661 hash_obj_t
*sec_hash_obj
;
2664 /* lookup for container hash object */
2665 hash_obj
= lookup_handle_object(container
, CONTAINER_TYPE
);
2666 if (hash_obj
== NULL
) {
2670 /* points to section object list */
2671 sec_hash_obj
= hash_obj
->u
.cont_obj
->sec_obj_list
;
2673 /* traverse section object list */
2674 while (sec_hash_obj
!= NULL
) {
2676 /* traverse segment hash object in the section */
2677 while (sec_hash_obj
->u
.sec_obj
->seg_obj_list
!= NULL
) {
2678 /* object handle of the segment hash object */
2680 sec_hash_obj
->u
.sec_obj
->seg_obj_list
->obj_hdl
;
2681 free_segment_hash(obj_hdl
, sec_hash_obj
);
2684 /* going to free section hash object, relink the hash object */
2685 if (sec_hash_obj
->prev
== NULL
) {
2686 hash_table
[(sec_hash_obj
->obj_hdl
% TABLE_SIZE
)]
2687 = sec_hash_obj
->next
;
2688 if (sec_hash_obj
->next
!= NULL
) {
2689 sec_hash_obj
->next
->prev
= NULL
;
2692 sec_hash_obj
->prev
->next
= sec_hash_obj
->next
;
2693 if (sec_hash_obj
->next
!= NULL
) {
2694 sec_hash_obj
->next
->prev
= sec_hash_obj
->prev
;
2698 free(sec_hash_obj
->u
.sec_obj
); /* free section hash object */
2700 prev_hash
= sec_hash_obj
;
2702 sec_hash_obj
= sec_hash_obj
->u
.sec_obj
->next
;
2704 free(prev_hash
); /* free section hash */
2707 /* free container hash object */
2708 if (hash_obj
->prev
== NULL
) {
2709 hash_table
[(sec_hash_obj
->obj_hdl
% TABLE_SIZE
)] =
2711 if (hash_obj
->next
!= NULL
) {
2712 hash_obj
->next
->prev
= NULL
;
2715 hash_obj
->prev
->next
= hash_obj
->next
;
2716 if (hash_obj
->next
!= NULL
) {
2717 hash_obj
->next
->prev
= hash_obj
->prev
;
2721 free(hash_obj
->u
.cont_obj
);
2728 * fru_is_data_available() checks to see if the frudata
2729 * is available on a fru.
2732 * picl_nodehdl_t holds the picl node handle of the fru.
2736 * return 1: if FRUID information is available
2737 * return 0: if FRUID information is not present
2743 fru_is_data_available(picl_nodehdl_t fru
)