cmd: remove sparc-only virtinfo
[unleashed.git] / usr / src / cmd / picl / plugins / sun4u / blade / fruaccess / fru_access.c
blob5eb01b4ec6683db646d8130106e25cce3cb4e956
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <limits.h>
30 #include <alloca.h>
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. */
46 static void
47 initialize_fruaccess(void)
49 int count;
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.
60 static hash_obj_t *
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);
77 return (NULL);
80 /* called to allocate container hash object */
82 static hash_obj_t *
83 create_container_hash_object(void)
85 hash_obj_t *hash_obj;
86 container_obj_t *cont_obj;
88 cont_obj = malloc(sizeof (container_obj_t));
89 if (cont_obj == NULL) {
90 return (NULL);
93 hash_obj = malloc(sizeof (hash_obj_t));
94 if (hash_obj == NULL) {
95 free(cont_obj);
96 return (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;
106 return (hash_obj);
109 /* called to allocate section hash object */
111 static hash_obj_t *
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) {
119 return (NULL);
122 hash_obj = malloc(sizeof (hash_obj_t));
123 if (hash_obj == NULL) {
124 free(sec_obj);
125 return (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;
136 return (hash_obj);
139 /* called to allocate segment hash object */
141 static hash_obj_t *
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) {
149 return (NULL);
152 hash_obj = malloc(sizeof (hash_obj_t));
153 if (hash_obj == NULL) {
154 free(seg_obj);
155 return (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;
166 return (hash_obj);
169 /* called to allocate packet hash object */
171 static hash_obj_t *
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) {
179 return (NULL);
182 hash_obj = malloc(sizeof (hash_obj_t));
183 if (hash_obj == NULL) {
184 free(pkt_obj);
185 return (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;
195 return (hash_obj);
198 /* called to add allocated hash object into the hash table */
200 static void
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 */
208 /* where to add ? */
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 */
221 static void
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;
229 return;
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 */
243 static void
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;
251 return;
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 */
265 static void
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;
275 return;
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;
287 static void
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;
299 static hash_obj_t *
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 :
306 break;
307 case SECTION_TYPE :
308 hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
309 if (hash_obj == NULL) {
310 return (NULL);
312 break;
313 case SEGMENT_TYPE :
314 hash_obj = lookup_handle_object(handle, SECTION_TYPE);
315 if (hash_obj == NULL) {
316 return (NULL);
318 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
319 CONTAINER_TYPE);
320 break;
321 case PACKET_TYPE :
322 break;
323 default :
324 return (NULL);
326 return (hash_obj);
330 static void
331 sort_offsettbl(int segcnt, seg_info_t *offset_tbl)
333 int cntx;
334 int cnty;
335 seg_info_t tmp;
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.
358 static void
359 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd)
361 int ret;
362 char *buffer;
363 segment_layout_t *segment;
365 segment = (segment_layout_t *)seghdr;
367 buffer = alloca(segment->length);
368 if (buffer == NULL) {
369 return;
372 ret = pread(contfd, buffer,
373 segment->length, segment->offset);
374 if (ret != segment->length) {
375 return;
378 segment->offset = newoffset;
380 ret = pwrite(contfd, buffer, segment->length, segment->offset);
381 if (ret != segment->length) {
382 return;
387 * Description : pack_segment_data() moves the segment data if there is
388 * a hole between two segments.
391 static void
392 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd,
393 seg_info_t *offset_tbl)
395 int cnt;
396 int diff;
397 int newoffset;
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
409 + diff;
411 move_segment_data(seghdr, newoffset,
412 contfd);
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
426 * segment header.
429 static int
430 build_offset_tbl(void *seghdr, int segcnt, int secsize,
431 seg_info_t *offset_tbl)
433 int cnt;
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,
441 sizeof (uint32_t));
442 offset_tbl[cnt].segnum = cnt;
443 offset_tbl[cnt].offset = segment->offset;
444 offset_tbl[cnt].length = segment->length;
445 offset_tbl[cnt].fixed = segdesc.field.fixed;
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;
461 return (0);
464 static int
465 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl)
467 int cnt = 0;
469 *totsize = 0;
470 for (cnt = segcnt + 1; cnt > 0; cnt--) {
471 if (bytes <= offset_tbl[cnt].offset -
472 (offset_tbl[cnt - 1].offset +
473 offset_tbl[cnt - 1].length)) {
474 return (offset_tbl[cnt].offset - bytes);
477 *totsize += offset_tbl[cnt].offset -
478 (offset_tbl[cnt - 1].offset +
479 offset_tbl[cnt - 1].length);
481 return (0);
486 * Description : segment_hdr_present() verify space for new segment header to
487 * be added.
490 static int
491 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl)
493 if ((segoffset + size) <= offset_tbl[0].offset)
494 return (0);
495 else
496 return (-1);
500 * Description : find_offset() is called from fru_add_segment routine to find
501 * a valid offset.
504 static int
505 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset,
506 int segsize, int fix, container_hdl_t contfd)
508 int ret;
509 int newoffset;
510 int totsize = 0;
511 seg_info_t *offset_tbl;
513 if (segcnt == 0) {
514 if (!fix) { /* if not fixed segment */
515 *sectionoffset = secsize - segsize;
517 return (0);
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) {
530 return (-1);
533 /* read all the segment header to make offset table */
534 ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl);
535 if (ret != 0) {
536 free(offset_tbl);
537 return (-1);
540 /* sort the table */
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),
549 offset_tbl);
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 */
554 free(offset_tbl);
555 return (-1);
558 newoffset = hole_discovery(offset_tbl[0].length,
559 segcnt, &totsize, offset_tbl);
560 if (newoffset != 0) { /* found new offset */
561 /* now new offset */
562 offset_tbl[0].offset = newoffset;
564 /* move the segment data */
565 move_segment_data(seghdr, newoffset, contfd);
566 /* again sort the offset table */
567 sort_offsettbl(segcnt, offset_tbl);
568 } else {
569 /* pack the existing hole */
570 if (totsize > offset_tbl[0].length) {
571 pack_segment_data(seghdr, segcnt,
572 contfd, offset_tbl);
573 } else {
574 free(offset_tbl);
575 return (-1);
580 totsize = 0;
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,
586 offset_tbl);
587 newoffset = hole_discovery(segsize, segcnt,
588 &totsize, offset_tbl);
589 if (newoffset != 0) {
590 *sectionoffset = newoffset;
591 free(offset_tbl);
592 return (0);
595 } else {
596 *sectionoffset = newoffset;
597 free(offset_tbl);
598 return (0);
600 free(offset_tbl);
601 return (-1);
604 static char *
605 tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
607 int i = 0;
608 int j = 0;
610 for (i = 0; buf[i] != '\0'; i++) {
611 for (j = 0; j < strlen(separator); j++) {
612 if (buf[i] == separator[j]) {
613 buf[i] = '\0';
614 *nextBuf = &(buf[i+1]);
615 *matched = separator[j];
616 return (buf);
621 *nextBuf = buf;
622 *matched = '\0';
623 return (NULL);
626 static int
627 get_container_info(const char *def_file, const char *cont_desc_str,
628 container_info_t *cont_info)
630 char *item;
631 char *token;
632 char *field;
633 char matched;
634 char buf[1024];
635 int foundIt = 0;
636 FILE *file = fopen(def_file, "r");
638 if (file == NULL)
639 return (-1);
641 cont_info->num_sections = 0;
643 while (fgets(buf, sizeof (buf), file) != NULL) {
644 /* ignore all comments */
645 token = tokenizer(buf, "#", &field, &matched);
646 /* find the names */
647 token = tokenizer(buf, ":", &field, &matched);
648 if (token != 0x00) {
649 token = tokenizer(token, "|", &item, &matched);
650 while (token != 0x00) {
651 if (strcmp(token, cont_desc_str) == 0) {
652 foundIt = 1;
653 goto found;
655 token = tokenizer(item, "|", &item, &matched);
657 /* check the last remaining item */
658 if ((item != 0x00) &&
659 (strcmp(item, cont_desc_str) == 0)) {
660 foundIt = 1;
661 goto found;
666 found :
667 if (foundIt == 1) {
668 token = tokenizer(field, ":", &field, &matched);
669 if (token == 0x00) {
670 (void) fclose(file);
671 return (-1);
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);
678 if (token == 0x00) {
679 (void) fclose(file);
680 return (-1);
682 if (atoi(token) == 1) {
683 cont_info->section_info[cont_info->
684 num_sections].description.field.read_only = 1;
685 } else if (atoi(token) == 0) {
686 cont_info->section_info[cont_info->
687 num_sections].description.field.read_only = 0;
688 } else {
689 (void) fclose(file);
690 return (-1);
693 token = tokenizer(item, ",", &item, &matched);
694 if (token == 0x00) {
695 (void) fclose(file);
696 return (-1);
699 if (atoi(token) == 1) {
700 cont_info->section_info[cont_info->
701 num_sections].description.field.chk_type = 1;
702 } else if (atoi(token) == 0) {
703 cont_info->section_info[cont_info->
704 num_sections].description.field.chk_type = 0;
705 } else {
706 (void) fclose(file);
707 return (-1);
711 token = tokenizer(item, ",", &item, &matched);
712 if (token == 0x00) {
713 (void) fclose(file);
714 return (-1);
717 cont_info->section_info[cont_info->num_sections].
718 address = atoi(token);
721 if (item == '\0') {
722 (void) fclose(file);
723 return (-1);
725 cont_info->section_info[cont_info->num_sections].size =
726 atoi(item);
727 (cont_info->num_sections)++;
729 token = tokenizer(field, ":\n ", &field, &matched);
732 (void) fclose(file);
733 return (0);
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.
747 * Return :
748 * On Success, a Positive integer container handle. is returned
749 * for use in subsequent fru operations;on error, 0 is returned
750 * and "errno" is set appropriately.
753 container_hdl_t
754 fru_open_container(picl_nodehdl_t fruhdl)
756 int retval;
757 int count;
758 char *bname;
759 char devpath[PATH_MAX];
760 hash_obj_t *cont_hash_obj;
761 hash_obj_t *sec_hash_obj;
762 picl_nodehdl_t tmphdl;
763 picl_prophdl_t prophdl;
764 ptree_propinfo_t propinfo;
765 container_info_t cont_info;
767 /* Get property handle of _seeprom_source under fru node */
768 retval = ptree_get_propval_by_name(fruhdl, PICL_REFPROP_SEEPROM_SRC,
769 &tmphdl, sizeof (tmphdl));
770 if (retval != PICL_SUCCESS) {
771 return (NULL);
774 /* Get the device path of the fru */
775 retval = ptree_get_propval_by_name(tmphdl, PICL_PROP_DEVICEPATH,
776 devpath, PATH_MAX);
777 if (retval != PICL_SUCCESS) {
778 return (NULL);
781 retval = ptree_get_prop_by_name(tmphdl, PICL_PROP_BINDING_NAME,
782 &prophdl);
783 if (retval != PICL_SUCCESS) {
784 return (NULL);
787 retval = ptree_get_propinfo(prophdl, &propinfo);
788 if (retval != PICL_SUCCESS) {
789 return (NULL);
792 bname = alloca(propinfo.piclinfo.size);
793 if (bname == NULL) {
794 return (NULL);
797 /* get the driver binding name */
798 retval = ptree_get_propval(prophdl, bname, propinfo.piclinfo.size);
799 if (retval != PICL_SUCCESS) {
800 return (NULL);
803 cont_hash_obj = create_container_hash_object();
804 if (cont_hash_obj == NULL) {
805 return (NULL);
808 add_hashobject_to_hashtable(cont_hash_obj);
810 (void) strlcpy(cont_hash_obj->u.cont_obj->device_pathname, devpath,
811 sizeof (devpath));
813 /* takes driver binding name as to get container information */
814 retval = get_container_info(CONTAINER_CONF_FILE, bname, &cont_info);
815 if (retval < 0) {
816 return (NULL);
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) {
825 return (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);
849 static int
850 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
852 int crc_offset = 0;
853 unsigned char orig_crc8 = 0;
854 unsigned char calc_crc8 = 0;
856 switch (head_ver) {
857 case SECTION_HDR_VER:
858 crc_offset = 4;
859 break;
860 default:
861 errno = EINVAL;
862 return (0);
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);
874 * Description :
875 * fru_get_num_sections() returns number of sections in a
876 * container. it calls get_container_index() to get the container
877 * index number in the container list.
879 * Arguments :
880 * container_hdl_t : container handle.
882 * Return :
883 * int
884 * On success, returns number of sections in a container.
887 /*ARGSUSED*/
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) {
895 return (-1);
898 return (hash_object->u.cont_obj->num_of_section);
902 * called from fru_get_sections()
905 static void
906 get_section(int fd, hash_obj_t *sec_hash, section_t *section)
908 int retval;
909 int size;
910 int count;
911 uint16_t hdrver;
912 hash_obj_t *seg_hash;
913 unsigned char *buffer;
914 section_obj_t *sec_obj;
915 section_layout_t sec_hdr;
916 segment_layout_t *seg_hdr;
917 segment_layout_t *seg_buf;
919 sec_obj = sec_hash->u.sec_obj;
920 if (sec_obj == NULL) {
921 return;
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)) {
936 return;
939 hdrver = GET_SECTION_HDR_VERSION;
941 if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
942 (hdrver != section->version)) {
943 return;
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) {
952 return;
955 /* segment header buffer */
956 seg_buf = alloca(size - sizeof (sec_hdr));
957 if (seg_buf == NULL) {
958 return;
961 /* read segment header */
962 retval = pread(fd, seg_buf, size - sizeof (sec_hdr),
963 sec_obj->section.offset + sizeof (sec_hdr));
964 if (retval != (size - sizeof (sec_hdr))) {
965 return;
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 -
973 sizeof (sec_hdr));
975 /* verify crc8 */
976 retval = verify_header_crc8(hdrver, buffer, size);
977 if (retval != TRUE) {
978 return;
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) {
990 return;
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++;
1004 static int
1005 call_devfsadm(void)
1007 char *phys_path;
1008 di_node_t root_node;
1009 di_node_t prom_node;
1010 di_node_t f_node;
1012 if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1013 return (-1);
1016 f_node = di_drv_first_node(PICL_CLASS_SEEPROM, root_node);
1017 if (f_node != DI_NODE_NIL) {
1018 phys_path = di_devfs_path(f_node);
1019 if ((prom_node = di_init(phys_path, DINFOMINOR))
1020 != DI_NODE_NIL) {
1021 di_fini(prom_node);
1022 di_fini(root_node);
1023 (void) pclose(popen(devfsadm_cmd, "r"));
1024 return (0);
1027 di_fini(root_node);
1028 return (-1);
1032 * Description :
1033 * fru_get_sections() fills an array of section structures passed
1034 * as an argument.
1036 * Arguments :
1037 * container_hdl_t : container handle(device descriptor).
1038 * section_t : array of section structure.
1039 * int : maximum number of section in a container.
1041 * Returns :
1042 * int
1043 * On success,the number of section structures written is returned;
1044 * on error, -1 is returned and "errno" is set appropriately.
1048 /* ARGSUSED */
1050 fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
1051 door_cred_t *cred)
1053 int device_fd;
1054 int retrys = 1;
1055 int count;
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) {
1061 return (-1);
1064 if (cont_object->u.cont_obj->num_of_section > maxsec) {
1065 return (-1);
1068 sec_hash = cont_object->u.cont_obj->sec_obj_list;
1069 if (sec_hash == NULL) {
1070 return (-1);
1073 do {
1074 device_fd = open(cont_object->u.cont_obj->device_pathname,
1075 O_RDWR);
1076 if (device_fd >= 0) {
1077 break;
1079 } while ((retrys-- > 0) && (call_devfsadm() == 0));
1081 if (device_fd < 0) {
1082 return (-1);
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);
1095 return (count);
1099 * Description :
1100 * fru_get_num_segments() returns the current number of segments
1101 * in a section.
1103 * Arguments :
1104 * section_hdl_t : section header holding section information.
1106 * Return :
1107 * int
1108 * On success, the number of segments in the argument section is
1109 * returned; on error -1 is returned.
1111 /*ARGSUSED*/
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) {
1120 return (-1);
1123 sec_obj = sec_object->u.sec_obj;
1124 if (sec_obj == NULL) {
1125 return (-1);
1128 return (sec_obj->num_of_segment);
1132 * Description :
1133 * fru_get_segments() fills an array of structures representing the
1134 * segments in a section.
1136 * Arguments :
1137 * section_hdl_t : holds section number.
1138 * segment_t : on success will hold segment information.
1139 * int : maximum number of segment.
1141 * Return :
1142 * int
1143 * On success, the number of segment structures written is
1144 * returned; on errno -1 is returned.
1147 /* ARGSUSED */
1149 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
1150 door_cred_t *cred)
1152 int count;
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) {
1159 return (-1);
1162 sec_obj = sec_object->u.sec_obj;
1163 if (sec_obj == NULL) {
1164 return (-1);
1167 if (sec_obj->num_of_segment > maxseg) {
1168 return (-1);
1171 seg_object = sec_object->u.sec_obj->seg_obj_list;
1172 if (seg_object == NULL) {
1173 return (-1);
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;
1187 segment++;
1189 return (0);
1193 * Description :
1194 * fru_add_segment() adds a segment to a section.
1196 * Arguments :
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.
1207 * Return :
1208 * int
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)
1217 int fd;
1218 int retval;
1219 int offset;
1220 int sec_size;
1221 int seg_cnt;
1222 int bufsize;
1223 int new_seg_offset;
1224 int new_seg_length;
1225 int fixed_segment;
1226 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00 };
1227 hash_obj_t *cont_hash;
1228 hash_obj_t *sec_hash;
1229 hash_obj_t *seg_hash;
1230 fru_segdesc_t *new_seg_desc;
1231 unsigned char *crcbuf;
1232 section_layout_t sec_layout;
1233 segment_layout_t *seg_layout;
1234 segment_layout_t *segment_buf;
1236 /* check the effective uid of the client */
1237 if (cred->dc_euid != 0) {
1238 errno = EPERM;
1239 return (-1); /* not a root */
1242 /* section hash */
1243 sec_hash = lookup_handle_object(section, SECTION_TYPE);
1244 if (sec_hash == NULL) {
1245 return (-1);
1248 /* check for read-only section */
1249 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1250 errno = EPERM;
1251 return (-1);
1254 /* look for duplicate segment */
1255 seg_hash = sec_hash->u.sec_obj->seg_obj_list;
1256 while (seg_hash != NULL) {
1257 if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name,
1258 SEG_NAME_LEN) == 0) {
1259 errno = EEXIST;
1260 return (-1); /* can't add duplicate segment */
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,
1267 CONTAINER_TYPE);
1268 if (cont_hash == NULL) {
1269 return (-1);
1272 /* open the container */
1273 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1274 if (fd < 0) {
1275 return (-1);
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)) {
1284 (void) close(fd);
1285 return (-1);
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;
1298 /* section size */
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) {
1308 return (-1);
1311 /* read entire segment header */
1312 retval = pread(fd, segment_buf, (bufsize - sizeof (segment_layout_t)),
1313 offset + sizeof (section_layout_t));
1314 if (retval != (bufsize - sizeof (segment_layout_t))) {
1315 (void) close(fd);
1316 return (-1);
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);
1330 if (retval != 0) {
1331 (void) close(fd);
1332 errno = EAGAIN;
1333 return (-1);
1336 /* copy new segment data in segment layout */
1337 seg_layout = (segment_layout_t *)(segment_buf + seg_cnt);
1338 (void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN);
1339 (void) memcpy(seg_layout->descriptor, &segment->descriptor,
1340 sizeof (uint32_t));
1341 seg_layout->length = segment->length;
1342 seg_layout->offset = new_seg_offset; /* new segment offset */
1344 sec_layout.segmentcount += 1;
1346 crcbuf = alloca(sizeof (section_layout_t) + bufsize);
1347 if (crcbuf == NULL) {
1348 (void) close(fd);
1349 return (-1);
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)) {
1364 (void) close(fd);
1365 return (-1);
1368 /* write segment header */
1369 retval = pwrite(fd, segment_buf, bufsize, offset +
1370 sizeof (section_layout_t));
1371 if (retval != bufsize) {
1372 (void) close(fd);
1373 return (-1);
1376 /* write segment trailer */
1377 retval = pwrite(fd, &trailer, sizeof (trailer), new_seg_offset);
1378 if (retval != sizeof (trailer)) {
1379 (void) close(fd);
1380 return (-1);
1383 (void) close(fd);
1385 /* create new segment hash object */
1386 seg_hash = create_segment_hash_object();
1387 if (seg_hash == NULL) {
1388 return (-1);
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 */
1400 return (0);
1403 static void
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)] =
1416 free_obj->next;
1417 if (free_obj->next != NULL) {
1418 free_obj->next->prev = free_obj->prev;
1420 } else {
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);
1427 free(free_obj);
1430 hash_obj->u.seg_obj->pkt_obj_list = NULL;
1433 static void
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) {
1441 return;
1444 if (seg_hash->obj_hdl == handle) {
1445 sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
1446 } else {
1447 while (seg_hash->obj_hdl != handle) {
1448 next_hash = seg_hash;
1449 seg_hash = seg_hash->u.seg_obj->next;
1450 if (seg_hash == NULL) {
1451 return;
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;
1462 } else {
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);
1471 free(seg_hash);
1475 * Description :
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.
1482 * Return :
1483 * int
1484 * On success, 0 returned; On error -1 is returned.
1488 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
1489 door_cred_t *cred)
1491 int num_of_seg;
1492 int bufsize;
1493 int count;
1494 int retval;
1495 int fd;
1496 int segnum;
1497 hash_obj_t *seg_hash;
1498 hash_obj_t *sec_hash;
1499 hash_obj_t *cont_hash;
1500 hash_obj_t *tmp_hash;
1501 unsigned char *buffer;
1502 fru_segdesc_t *desc;
1503 segment_layout_t *seg_buf;
1504 section_layout_t *sec_layout;
1505 segment_layout_t *seg_layout;
1506 segment_layout_t *next_layout;
1508 /* check the effective uid of the client */
1509 if (cred->dc_euid != 0) {
1510 errno = EPERM;
1511 return (-1); /* not a root */
1514 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1515 if (seg_hash == NULL) {
1516 return (-1);
1519 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
1520 if (!(desc->field.field_perm & SEGMENT_DELETE)) {
1521 errno = EPERM;
1522 return (-1); /* can't delete this segment */
1525 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1526 SECTION_TYPE);
1527 if (sec_hash == NULL) {
1528 return (-1);
1531 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1532 errno = EPERM;
1533 return (-1);
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) {
1542 return (-1);
1545 segnum = 0;
1546 for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL;
1547 tmp_hash = tmp_hash->u.seg_obj->next) {
1548 if (tmp_hash->obj_hdl == segment) {
1549 break;
1551 segnum++;
1554 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1555 CONTAINER_TYPE);
1556 if (cont_hash == NULL) {
1557 return (-1);
1560 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1561 if (fd < 0) {
1562 return (-1);
1565 sec_layout = alloca(sizeof (section_layout_t));
1566 if (sec_layout == NULL) {
1567 (void) close(fd);
1568 return (-1);
1571 /* read section layout header */
1572 retval = pread(fd, sec_layout, sizeof (section_layout_t),
1573 sec_hash->u.sec_obj->section.offset);
1574 if (retval != sizeof (section_layout_t)) {
1575 (void) close(fd);
1576 return (-1);
1579 /* read segment header layout */
1580 retval = pread(fd, seg_buf, bufsize,
1581 sec_hash->u.sec_obj->section.offset +
1582 sizeof (section_layout_t));
1583 if (retval != bufsize) {
1584 (void) close(fd);
1585 return (-1);
1588 seg_layout = (segment_layout_t *)(seg_buf + segnum);
1589 next_layout = seg_layout;
1590 for (count = segnum; count < sec_hash->u.sec_obj->num_of_segment-1;
1591 count++) {
1592 next_layout++;
1593 (void) memcpy(seg_layout, next_layout,
1594 sizeof (segment_layout_t));
1595 seg_layout++;
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) {
1607 (void) close(fd);
1608 return (-1);
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)) {
1621 (void) close(fd);
1622 return (-1);
1625 /* write the update segment header */
1626 retval = pwrite(fd, seg_buf, bufsize,
1627 sec_hash->u.sec_obj->section.offset +
1628 sizeof (section_layout_t));
1629 (void) close(fd);
1630 if (retval != bufsize) {
1631 return (-1);
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;
1639 return (0);
1643 * Description :
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.
1650 * Return :
1651 * int
1652 * On success, the number of bytes read is returned;
1654 * Notes :
1655 * Segments containing packets can be read in structured fashion
1656 * using the fru_get_packets() and fru_get_payload() primitives;the
1657 * entire byte range of a segment can be read using
1658 * fru_read_segment().
1660 /*ARGSUSED*/
1661 ssize_t
1662 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
1663 door_cred_t *cred)
1665 int fd;
1666 int retval;
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) {
1674 return (-1);
1677 /* section hash object */
1678 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1679 SECTION_TYPE);
1680 if (sec_hash == NULL) {
1681 return (-1);
1684 /* container hash object */
1685 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1686 CONTAINER_TYPE);
1687 if (cont_hash == NULL) {
1688 return (-1);
1691 if (seg_hash->u.seg_obj->segment.length < nbytes) {
1692 return (-1);
1695 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1696 if (fd < 0) {
1697 return (-1);
1700 retval = pread(fd, buffer, nbytes, seg_hash->u.seg_obj->segment.offset);
1701 (void) close(fd);
1702 if (retval != nbytes) {
1703 return (-1);
1705 return (nbytes);
1709 * Description :
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.
1717 * Returns :
1718 * int
1719 * On success, the number of bytes written is returned
1722 /*ARGSUSED*/
1724 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes,
1725 segment_hdl_t *newsegment, door_cred_t *cred)
1727 return (ENOTSUP);
1731 static int
1732 get_packet(int device_fd, void *buffer, int size, int offset)
1734 int retval;
1736 retval = pread(device_fd, (char *)buffer, size, offset);
1737 if (retval != -1) {
1738 return (0);
1740 return (-1);
1744 * Description :
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
1752 * Return :
1753 * int
1754 * On success, 0 is returned; on failure
1755 * -1 returned.
1758 get_payload(int device_fd, hash_obj_t *packet, uint8_t *payload)
1760 int retval;
1761 packet_obj_t *packet_object;
1764 packet_object = packet->u.pkt_obj;
1765 if (packet_object == NULL) {
1766 return (-1);
1769 /* Get the data */
1770 retval = pread(device_fd, payload, packet_object->paylen,
1771 packet_object->payload_offset);
1772 if (retval != packet_object->paylen) {
1773 free(payload);
1774 return (-1);
1777 return (0);
1782 static uint32_t
1783 get_checksum_crc(int device_fd, hash_obj_t *seg_hash, int data_size)
1785 int checksum;
1786 int offset = 0;
1787 int retval;
1788 uint8_t *payload;
1789 uint32_t crc;
1790 hash_obj_t *sec_hash;
1791 hash_obj_t *pkt_hash;
1792 unsigned char *buffer;
1794 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1795 SECTION_TYPE);
1796 if (sec_hash == NULL) {
1797 return ((uint32_t)-1);
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);
1818 if (retval == -1) {
1819 free(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;
1825 free(payload);
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 */
1838 static int
1839 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length)
1841 int tag_size;
1842 int paylen;
1843 int retval;
1844 int seg_limit = 0;
1845 int pktcnt = 0;
1846 char *data;
1847 uint32_t crc;
1848 uint32_t origcrc;
1849 fru_tag_t tag;
1850 hash_obj_t *pkt_hash_obj;
1851 fru_segdesc_t *segdesc;
1852 fru_tagtype_t tagtype;
1854 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), offset);
1855 if (retval == -1) {
1856 return (-1);
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) {
1865 return (-1);
1868 tag_size = get_tag_size(tagtype);
1869 if (tag_size == -1) {
1870 return (-1);
1873 seg_limit += tag_size;
1874 if (seg_limit > length) {
1875 return (-1);
1878 paylen = get_payload_length((void *)&tag);
1879 if (paylen == -1) {
1880 return (-1);
1883 seg_limit += paylen;
1884 if (seg_limit > length) {
1885 return (-1);
1888 pkt_hash_obj = create_packet_hash_object();
1889 if (pkt_hash_obj == NULL) {
1890 return (-1);
1893 offset += tag_size;
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;
1902 offset += paylen;
1904 add_hashobject_to_hashtable(pkt_hash_obj);
1905 add_to_pkt_object_list(seg_hash, pkt_hash_obj);
1907 pktcnt++;
1909 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t),
1910 offset);
1911 if (retval == -1) {
1912 return (retval);
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)) {
1929 return (-1);
1932 if (origcrc != crc) {
1933 seg_hash->u.seg_obj->trailer_offset = offset;
1934 return (-1);
1938 return (pktcnt);
1942 * Description :
1943 * fru_get_num_packets() returns the current number of packets
1944 * in a segment.
1946 * Arguments : segment_hdl_t : segment handle.
1948 * Return :
1949 * int
1950 * On success, the number of packets is returned;
1951 * -1 on failure.
1953 /*ARGSUSED*/
1955 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
1957 int device_fd;
1958 int pktcnt;
1959 int length;
1960 uint16_t offset;
1961 hash_obj_t *cont_hash_obj;
1962 hash_obj_t *seg_hash;
1963 fru_segdesc_t *segdesc;
1964 segment_obj_t *segment_object;
1966 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1967 if (seg_hash == NULL) {
1968 return (-1);
1971 segment_object = seg_hash->u.seg_obj;
1972 if (segment_object == NULL) {
1973 return (-1);
1977 segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
1978 if (segdesc->field.opaque) {
1979 return (0);
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) {
1989 return (-1);
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,
1998 O_RDWR);
1999 if (device_fd < 0) {
2000 return (-1);
2003 pktcnt = get_packets(seg_hash, device_fd, offset,
2004 length);
2005 if (pktcnt == -1) {
2006 free_pkt_object_list(seg_hash);
2007 seg_hash->u.seg_obj->pkt_obj_list = NULL;
2010 segment_object->num_of_packets = pktcnt;
2011 (void) close(device_fd);
2013 return (segment_object->num_of_packets);
2018 * Description :
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.
2026 * Return :
2027 * int
2028 * On success, the number of packet structures written is returned;
2029 * On failure -1 is returned;
2032 /*ARGSUSED*/
2034 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
2035 door_cred_t *cred)
2037 int count;
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) {
2044 return (-1);
2047 if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
2048 return (-1);
2051 pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list;
2052 if (pkt_hash_obj == NULL) {
2053 return (-1);
2056 for (count = 0; count < maxpackets; count++, packet++) {
2057 packet->handle = pkt_hash_obj->obj_hdl;
2058 packet->tag = 0;
2059 (void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
2060 pkt_hash_obj->u.pkt_obj->tag_size);
2061 pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
2064 return (0);
2068 * Description :
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.
2075 * Return :
2076 * int
2077 * On success, the number of bytes copied is returned; On error
2078 * -1 returned.
2080 /*ARGSUSED*/
2081 ssize_t
2082 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
2083 door_cred_t *cred)
2085 int retval;
2086 int device_fd;
2087 uint8_t *payload;
2088 hash_obj_t *packet_hash_obj;
2089 hash_obj_t *segment_hash_obj;
2090 hash_obj_t *container_hash_obj;
2092 /* packet hash object */
2093 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE);
2094 if (packet_hash_obj == NULL) {
2095 return (-1);
2098 payload = malloc(packet_hash_obj->u.pkt_obj->paylen);
2099 if (payload == NULL) {
2100 return (-1);
2103 /* lookup the segment hash object */
2104 segment_hash_obj =
2105 lookup_handle_object(packet_hash_obj->u.pkt_obj->segment_hdl,
2106 SEGMENT_TYPE);
2107 if (segment_hash_obj == NULL) {
2108 free(payload);
2109 return (-1);
2112 /* Get the container hash object to get the seeprom device path */
2113 container_hash_obj = get_container_hash_object(SEGMENT_TYPE,
2114 segment_hash_obj->u.seg_obj->section_hdl);
2115 if (container_hash_obj == NULL) {
2116 free(payload);
2117 return (-1);
2120 /* Open the seeprom device */
2121 device_fd = open(container_hash_obj->u.cont_obj->device_pathname,
2122 O_RDWR);
2123 if (device_fd < 0) {
2124 free(payload);
2125 return (-1);
2129 /* Call to get the payload */
2130 retval = get_payload(device_fd, packet_hash_obj, payload);
2131 if (retval == -1) {
2132 free(payload);
2133 (void) close(device_fd);
2134 return (-1);
2138 /* verify payload length */
2139 if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
2140 free(payload);
2141 (void) close(device_fd);
2142 return (-1);
2145 (void) memcpy(buffer, payload, nbytes);
2146 free(payload);
2147 (void) close(device_fd);
2148 return (nbytes);
2152 * Description :
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.
2160 * Return :
2161 * int
2162 * On success, 0 is returned; on failure
2163 * -1 is returned.
2167 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
2168 packet_hdl_t *newpacket, door_cred_t *cred)
2170 int fd;
2171 int segment_offset;
2172 int trailer_offset;
2173 int retval;
2174 uint32_t crc;
2175 hash_obj_t *pkt_hash;
2176 hash_obj_t *seg_hash;
2177 hash_obj_t *sec_hash;
2178 hash_obj_t *cont_hash;
2179 fru_segdesc_t *desc;
2181 /* check the effective uid of the client */
2182 if (cred->dc_euid != 0) {
2183 errno = EPERM;
2184 return (-1); /* not a root */
2187 /* packet hash object */
2188 pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2189 if (pkt_hash == NULL) {
2190 return (-1);
2193 /* segment hash object */
2194 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2195 SEGMENT_TYPE);
2196 if (seg_hash == NULL) {
2197 return (-1);
2200 /* check for write perm. */
2201 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2202 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2203 errno = EPERM;
2204 return (-1); /* write not allowed */
2207 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2208 SECTION_TYPE);
2209 if (sec_hash == NULL) {
2210 return (-1);
2213 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2214 errno = EPERM;
2215 return (-1); /* read-only section */
2218 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2219 CONTAINER_TYPE);
2220 if (cont_hash == NULL) {
2221 return (-1);
2224 if (pkt_hash->u.pkt_obj->paylen != nbytes) {
2225 return (-1);
2228 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2229 if (fd < 0) {
2230 return (-1);
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) {
2239 (void) close(fd);
2240 return (-1);
2243 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2244 (void) close(fd);
2245 if (retval != sizeof (crc)) {
2246 return (-1);
2248 *newpacket = packet;
2249 return (0);
2253 * Description :
2254 * fru_append_packet() appends a packet to a segment.
2256 * Arguments :
2257 * segment_hdl_t segment
2258 * A handle for the segment to which the packet will be appended.
2260 * packet_t *packet
2261 * On entry, the "tag" component of "packet" specifies the tag
2262 * value for the added packet; the "handle" component is ignored.
2263 * On return, the "handle" component is set to the handle of the
2264 * appended packet.
2266 * const void *payload
2267 * A pointer to the caller's buffer containing the payload data for
2268 * the appended packet.
2270 * size_t nbytes
2271 * The size of the caller buffer.
2273 * Return :
2274 * int
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)
2282 int trailer_offset;
2283 int tag_size;
2284 int fd;
2285 int retval;
2286 char trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00};
2287 uint32_t crc;
2288 hash_obj_t *seg_hash;
2289 hash_obj_t *sec_hash;
2290 hash_obj_t *pkt_hash;
2291 hash_obj_t *cont_hash;
2292 fru_tagtype_t tagtype;
2293 fru_segdesc_t *desc;
2295 /* check the effective uid of the client */
2296 if (cred->dc_euid != 0) {
2297 errno = EPERM;
2298 return (-1); /* not a root */
2301 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2302 if (seg_hash == NULL) {
2303 return (-1);
2306 /* check for write perm. */
2307 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2308 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2309 errno = EPERM;
2310 return (-1); /* write not allowed */
2313 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2314 SECTION_TYPE);
2315 if (sec_hash == NULL) {
2316 return (-1);
2319 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2320 errno = EPERM;
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) {
2338 return (-1);
2341 tag_size = get_tag_size(tagtype);
2342 if (tag_size == -1) {
2343 return (-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) {
2353 return (-1);
2356 /* tag initialization */
2357 (void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag,
2358 tag_size);
2359 pkt_hash->u.pkt_obj->tag_size = tag_size;
2360 pkt_hash->u.pkt_obj->paylen = nbytes;
2361 pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size;
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,
2369 CONTAINER_TYPE);
2370 if (cont_hash == NULL) {
2371 return (-1);
2374 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2375 if (fd < 0) {
2376 return (-1);
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) {
2389 (void) close(fd);
2390 return (-1);
2393 retval = pwrite(fd, payload, nbytes, trailer_offset - nbytes);
2394 if (retval != nbytes) {
2395 (void) close(fd);
2396 return (-1);
2399 retval = pwrite(fd, trailer, sizeof (trailer), trailer_offset);
2400 if (retval != sizeof (trailer)) {
2401 (void) close(fd);
2402 return (-1);
2405 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2406 (void) close(fd);
2407 if (retval != sizeof (crc)) {
2408 return (-1);
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 */
2415 return (0);
2416 } else {
2417 errno = EAGAIN;
2420 return (-1);
2423 static void
2424 adjust_packets(int fd, hash_obj_t *free_obj, hash_obj_t *object_list)
2426 int retval;
2427 uint8_t *payload;
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) {
2439 return;
2441 retval = get_payload(fd, hash_ptr, payload);
2442 if (retval == -1) {
2443 free(payload);
2444 return;
2447 retval = pwrite(fd, &hash_ptr->u.pkt_obj->tag,
2448 hash_ptr->u.pkt_obj->tag_size, new_offset);
2449 if (retval != hash_ptr->u.pkt_obj->tag_size) {
2450 free(payload);
2451 return;
2453 new_offset += hash_ptr->u.pkt_obj->tag_size;
2454 hash_ptr->u.pkt_obj->payload_offset = new_offset;
2455 retval = pwrite(fd, payload,
2456 hash_ptr->u.pkt_obj->paylen, new_offset);
2457 if (retval != hash_ptr->u.pkt_obj->paylen) {
2458 free(payload);
2459 return;
2461 new_offset += hash_ptr->u.pkt_obj->paylen;
2462 free(payload);
2466 static void
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) {
2474 return;
2477 if (pkt_hash->obj_hdl == handle) {
2478 seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next;
2479 } else {
2480 while (pkt_hash->obj_hdl != handle) {
2481 next_hash = pkt_hash;
2482 pkt_hash = pkt_hash->u.pkt_obj->next;
2483 if (pkt_hash == NULL) {
2484 return;
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;
2495 } else {
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);
2503 free(pkt_hash);
2507 * Description :
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.
2513 * Return :
2514 * int
2515 * On success, 0 is returned; on error, -1.
2517 * NOTES
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,
2524 door_cred_t *cred)
2526 int retval;
2527 int fd;
2528 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00};
2529 uint32_t crc;
2530 hash_obj_t *tmp_obj;
2531 hash_obj_t *pkt_hash;
2532 hash_obj_t *sec_hash;
2533 hash_obj_t *cont_hash;
2534 hash_obj_t *prev_obj;
2535 hash_obj_t *seg_hash;
2536 fru_segdesc_t *desc;
2538 /* check the effective uid of the client */
2539 if (cred->dc_euid != 0) {
2540 errno = EPERM;
2541 return (-1); /* not a root */
2544 /* packet hash object */
2545 pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2546 if (pkt_hash == NULL) {
2547 return (-1);
2550 /* segment hash object */
2551 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2552 SEGMENT_TYPE);
2553 if (seg_hash == NULL) {
2554 return (-1);
2557 /* check for write perm. */
2558 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2559 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2560 errno = EPERM;
2561 return (-1); /* write not allowed */
2564 /* section hash object */
2565 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2566 SECTION_TYPE);
2567 if (sec_hash == NULL) {
2568 return (-1);
2571 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2572 errno = EPERM;
2573 return (-1); /* read-only section */
2576 prev_obj = seg_hash->u.seg_obj->pkt_obj_list;
2577 if (prev_obj == NULL) {
2578 return (-1);
2581 /* container hash object */
2582 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2583 CONTAINER_TYPE);
2584 if (cont_hash == NULL) {
2585 return (-1);
2588 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2589 if (fd < 0) {
2590 return (-1);
2593 if (prev_obj->obj_hdl == packet) { /* first object to be deleted */
2594 adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next);
2595 seg_hash->u.seg_obj->trailer_offset -=
2596 (prev_obj->u.pkt_obj->tag_size
2597 + prev_obj->u.pkt_obj->paylen);
2598 free_packet_object(packet, seg_hash);
2599 } else {
2600 for (tmp_obj = prev_obj;
2601 tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) {
2602 /* found the object */
2603 if (tmp_obj->obj_hdl == packet) {
2604 adjust_packets(fd, tmp_obj,
2605 tmp_obj->u.pkt_obj->next);
2606 seg_hash->u.seg_obj->trailer_offset -=
2607 (tmp_obj->u.pkt_obj->tag_size
2608 + tmp_obj->u.pkt_obj->paylen);
2609 free_packet_object(packet, seg_hash);
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)) {
2624 (void) close(fd);
2625 return (-1);
2628 /* write the checksum value */
2629 retval = pwrite(fd, &crc, sizeof (crc),
2630 seg_hash->u.seg_obj->trailer_offset + 1);
2631 (void) close(fd);
2632 if (retval != sizeof (crc)) {
2633 return (-1);
2636 *newsegment = seg_hash->obj_hdl; /* return new segment handle */
2637 return (0);
2641 * Description :
2642 * fru_close_container() removes the association between a
2643 * container and its handle. this routines free's up all the
2644 * hash object contained under container.
2646 * Arguments :
2647 * container_hdl_t holds the file descriptor of the fru.
2649 * Return :
2650 * int
2651 * return 0.
2655 /* ARGSUSED */
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;
2662 handle_t obj_hdl;
2664 /* lookup for container hash object */
2665 hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
2666 if (hash_obj == NULL) {
2667 return (0);
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 */
2679 obj_hdl =
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;
2691 } else {
2692 sec_hash_obj->prev->next = sec_hash_obj->next;
2693 if (sec_hash_obj->next != NULL) {
2694 sec_hash_obj->next->prev = sec_hash_obj->prev;
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)] =
2710 hash_obj->next;
2711 if (hash_obj->next != NULL) {
2712 hash_obj->next->prev = NULL;
2714 } else {
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);
2722 free(hash_obj);
2723 return (0);
2727 * Description :
2728 * fru_is_data_available() checks to see if the frudata
2729 * is available on a fru.
2731 * Arguments :
2732 * picl_nodehdl_t holds the picl node handle of the fru.
2734 * Return :
2735 * int
2736 * return 1: if FRUID information is available
2737 * return 0: if FRUID information is not present
2741 /* ARGSUSED */
2743 fru_is_data_available(picl_nodehdl_t fru)
2745 return (0);