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