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
34static	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
41static	char	devfsadm_cmd[] = "/usr/sbin/devfsadm -i seeprom";
42
43/* this routine initialize the hash table. */
44
45static void
46initialize_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
59static hash_obj_t *
60lookup_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
81static hash_obj_t *
82create_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
110static hash_obj_t *
111create_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
140static hash_obj_t *
141create_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
170static hash_obj_t *
171create_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
199static void
200add_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
220static void
221add_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
242static void
243add_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
264static void
265add_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
286static void
287copy_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
298static hash_obj_t *
299get_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
329static void
330sort_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
357static void
358move_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
389static void
390pack_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
425static int
426build_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
460static int
461hole_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
485static int
486segment_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
499static int
500find_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
598static char *
599tokenizer(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
620static int
621get_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
662found :
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
759container_hdl_t
760fru_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
896static int
897verify_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 */
935int
936fru_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
952static void
953get_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
1075static int
1076call_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 */
1120int
1121fru_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 */
1184int
1185fru_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 */
1220int
1221fru_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
1285int
1286fru_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
1475static void
1476free_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
1507static void
1508free_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
1561int
1562fru_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 */
1733ssize_t
1734fru_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*/
1833int
1834fru_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
1841static int
1842get_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
1853static uint32_t
1854get_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
1895static int
1896get_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
2047static int
2048get_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
2054static int
2055get_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 */
2072int
2073fru_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 */
2183int
2184fru_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 */
2232ssize_t
2233fru_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
2268int
2269fru_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
2381int
2382fru_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
2534static void
2535adjust_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
2561static void
2562free_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
2618int
2619fru_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 */
2751int
2752fru_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 */
2835int
2836fru_is_data_available(picl_nodehdl_t fru)
2837{
2838	return (0);
2839}
2840