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