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