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