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