xref: /titanic_50/usr/src/cmd/picl/plugins/sun4u/snowbird/lib/fruaccess/libfruaccess.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <picl.h>
29 #include <limits.h>
30 #include <alloca.h>
31 #include <stdarg.h>
32 #include "smc_if.h"
33 #include "fru_access_impl.h"
34 
35 #pragma init(initialize_fruaccess)	/* .init section */
36 
37 /*
38  * This module translates all the frudata plugin requests into platform
39  * specific commands and provides information back to frudata plugin.
40  */
41 
42 /*
43  * precedence for format.
44  * define an ENV variable (SUNW_FRUACCESS_IPMI_PRECEDENCE) to make
45  * ipmi format has more precedence than sun format.
46  */
47 static int precedence = SUN_FORMAT;	/* by default */
48 #define	FRUACCESS_PRECEDENCE	"SUNW_FRUACCESS_IPMI_PRECEDENCE"
49 
50 extern ssize_t pread_new(int, void  *, size_t,  off_t, format_t *);
51 extern ssize_t pwrite_new(int, const void *, size_t, off_t, format_t *);
52 extern int get_manr(format_t *, payload_t *);
53 extern int is_fru_data_available(int, int, format_t *);
54 extern picl_errno_t fruaccess_platmod_init_format(uint8_t, format_t *);
55 extern int fruaccess_platmod_check_chassis();
56 extern int fruaccess_platmod_check_fru(picl_nodehdl_t parenth);
57 
58 static container_hdl_t sun_fru_open_container(picl_nodehdl_t);
59 static int sun_fru_close_container(container_hdl_t);
60 static int sun_fru_get_num_sections(container_hdl_t, door_cred_t *);
61 static int sun_fru_get_sections(container_hdl_t, section_t *,
62 			int, door_cred_t *);
63 static int sun_fru_get_num_segments(section_hdl_t, door_cred_t *);
64 static int sun_fru_get_segments(section_hdl_t, segment_t *,
65 			int, door_cred_t *);
66 static int sun_fru_add_segment(section_hdl_t, segment_t *,
67 			section_hdl_t *, door_cred_t *);
68 static int sun_fru_delete_segment(segment_hdl_t, section_hdl_t *,
69 			door_cred_t *);
70 static ssize_t sun_fru_read_segment(segment_hdl_t, void *, size_t,
71 			door_cred_t *);
72 static int sun_fru_write_segment(segment_hdl_t, const void *, size_t,
73 			segment_hdl_t *, door_cred_t *);
74 static int sun_fru_get_num_packets(segment_hdl_t, door_cred_t *);
75 static int sun_fru_get_packets(segment_hdl_t, packet_t *,
76 			int, door_cred_t *);
77 static ssize_t sun_fru_get_payload(packet_hdl_t, void *, size_t,
78 			door_cred_t *);
79 static int sun_fru_update_payload(packet_hdl_t, const void *, size_t,
80 			packet_hdl_t *, door_cred_t *);
81 static int sun_fru_append_packet(segment_hdl_t, packet_t *,
82 			const void *, size_t, segment_hdl_t *,
83 			door_cred_t *);
84 static int sun_fru_delete_packet(packet_hdl_t, segment_hdl_t *, door_cred_t *);
85 
86 static container_hdl_t ipmi_fru_open_container(picl_nodehdl_t);
87 static int ipmi_fru_close_container(container_hdl_t);
88 static int ipmi_fru_get_num_sections(container_hdl_t, door_cred_t *);
89 static int ipmi_fru_get_sections(container_hdl_t, section_t *,
90 			int, door_cred_t *);
91 static int ipmi_fru_get_num_segments(section_hdl_t, door_cred_t *);
92 static int ipmi_fru_get_segments(section_hdl_t, segment_t *,
93 			int, door_cred_t *);
94 static int ipmi_fru_add_segment(section_hdl_t, segment_t *,
95 			section_hdl_t *, door_cred_t *);
96 static int ipmi_fru_delete_segment(segment_hdl_t, section_hdl_t *,
97 			door_cred_t *);
98 static ssize_t ipmi_fru_read_segment(segment_hdl_t, void *, size_t,
99 			door_cred_t *);
100 static int ipmi_fru_write_segment(segment_hdl_t, const void *, size_t,
101 			segment_hdl_t *, door_cred_t *);
102 static int ipmi_fru_get_num_packets(segment_hdl_t, door_cred_t *);
103 static int ipmi_fru_get_packets(segment_hdl_t, packet_t *,
104 			int, door_cred_t *);
105 static ssize_t ipmi_fru_get_payload(packet_hdl_t, void *, size_t,
106 			door_cred_t *);
107 static int ipmi_fru_update_payload(packet_hdl_t, const void *, size_t,
108 			packet_hdl_t *, door_cred_t *);
109 static int ipmi_fru_append_packet(segment_hdl_t, packet_t *,
110 			const void *, size_t, segment_hdl_t *,
111 			door_cred_t *);
112 static int ipmi_fru_delete_packet(packet_hdl_t, segment_hdl_t *, door_cred_t *);
113 
114 typedef struct {
115 	container_hdl_t (* open_container)(picl_nodehdl_t);
116 	int (* close_container)(container_hdl_t);
117 	int (* get_num_sections)(container_hdl_t, door_cred_t *);
118 	int (* get_sections)(container_hdl_t, section_t *,
119 			int, door_cred_t *);
120 	int (* get_num_segments)(section_hdl_t, door_cred_t *);
121 	int (* get_segments)(section_hdl_t, segment_t *,
122 			int, door_cred_t *);
123 	int (* add_segment)(section_hdl_t, segment_t *,
124 			section_hdl_t *, door_cred_t *);
125 	int (* delete_segment)(segment_hdl_t, section_hdl_t *,
126 			door_cred_t *);
127 	ssize_t (* read_segment)(segment_hdl_t, void *, size_t,
128 			door_cred_t *);
129 	int (* write_segment)(segment_hdl_t, const void *, size_t,
130 			segment_hdl_t *, door_cred_t *);
131 	int (* get_num_packets)(segment_hdl_t, door_cred_t *);
132 	int (* get_packets)(segment_hdl_t, packet_t *,
133 			int, door_cred_t *);
134 	ssize_t (* get_payload)(packet_hdl_t, void *, size_t,
135 			door_cred_t *);
136 	int (* update_payload)(packet_hdl_t, const void *, size_t,
137 			packet_hdl_t *, door_cred_t *);
138 	int (* append_packet)(segment_hdl_t, packet_t *,
139 			const void *, size_t, segment_hdl_t *,
140 			door_cred_t *);
141 	int (* delete_packet)(packet_hdl_t, segment_hdl_t *, door_cred_t *);
142 } fruaccess_func_ptrs_t;
143 
144 static fruaccess_func_ptrs_t fruaccess_func[2] = {
145 		{
146 			ipmi_fru_open_container,
147 			ipmi_fru_close_container,
148 			ipmi_fru_get_num_sections,
149 			ipmi_fru_get_sections,
150 			ipmi_fru_get_num_segments,
151 			ipmi_fru_get_segments,
152 			ipmi_fru_add_segment,
153 			ipmi_fru_delete_segment,
154 			ipmi_fru_read_segment,
155 			ipmi_fru_write_segment,
156 			ipmi_fru_get_num_packets,
157 			ipmi_fru_get_packets,
158 			ipmi_fru_get_payload,
159 			ipmi_fru_update_payload,
160 			ipmi_fru_append_packet,
161 			ipmi_fru_delete_packet,
162 		},
163 		{
164 			sun_fru_open_container,
165 			sun_fru_close_container,
166 			sun_fru_get_num_sections,
167 			sun_fru_get_sections,
168 			sun_fru_get_num_segments,
169 			sun_fru_get_segments,
170 			sun_fru_add_segment,
171 			sun_fru_delete_segment,
172 			sun_fru_read_segment,
173 			sun_fru_write_segment,
174 			sun_fru_get_num_packets,
175 			sun_fru_get_packets,
176 			sun_fru_get_payload,
177 			sun_fru_update_payload,
178 			sun_fru_append_packet,
179 			sun_fru_delete_packet,
180 		},
181 	};
182 
183 static int is_valid_chassis = -1;
184 static hash_obj_t *hash_table[TABLE_SIZE];
185 
186 static void
initialize_fruaccess(void)187 initialize_fruaccess(void)
188 {
189 	int	count;
190 	for (count = 0; count < TABLE_SIZE; count++) {
191 		hash_table[count] = NULL;
192 	}
193 
194 	/* check if ipmi format has precedence */
195 	if (getenv(FRUACCESS_PRECEDENCE)) {
196 		precedence = IPMI_FORMAT;
197 	}
198 }
199 
200 /* called to lookup hash object for specified handle in the hash table. */
201 static hash_obj_t *
lookup_handle_object(handle_t handle,int object_type)202 lookup_handle_object(handle_t	handle, int object_type)
203 {
204 	handle_t	index_to_hash;
205 	hash_obj_t	*first_hash_obj;
206 	hash_obj_t	*next_hash_obj;
207 
208 	index_to_hash	= (handle % TABLE_SIZE);
209 
210 	first_hash_obj = hash_table[index_to_hash];
211 	for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
212 		next_hash_obj = next_hash_obj->next) {
213 		if ((handle == next_hash_obj->obj_hdl) &&
214 			(object_type == next_hash_obj->object_type)) {
215 			return (next_hash_obj);
216 		}
217 	}
218 	return (NULL);
219 }
220 
221 /* called to allocate container hash object */
222 static hash_obj_t *
create_container_hash_object(void)223 create_container_hash_object(void)
224 {
225 	hash_obj_t		*hash_obj;
226 	container_obj_t		*cont_obj;
227 
228 	cont_obj = malloc(sizeof (container_obj_t));
229 	if (cont_obj == NULL) {
230 		return (NULL);
231 	}
232 
233 	hash_obj = malloc(sizeof (hash_obj_t));
234 	if (hash_obj == NULL) {
235 		free(cont_obj);
236 		return (NULL);
237 	}
238 
239 	cont_obj->sec_obj_list = NULL;
240 
241 	hash_obj->object_type = CONTAINER_TYPE;
242 	hash_obj->u.cont_obj = cont_obj;
243 	hash_obj->next = NULL;
244 	hash_obj->prev = NULL;
245 
246 	return (hash_obj);
247 }
248 
249 /* called to allocate section hash object */
250 static hash_obj_t *
create_section_hash_object(void)251 create_section_hash_object(void)
252 {
253 	hash_obj_t *hash_obj;
254 	section_obj_t *sec_obj;
255 
256 	sec_obj	= malloc(sizeof (section_obj_t));
257 	if (sec_obj == NULL) {
258 		return (NULL);
259 	}
260 
261 	hash_obj = malloc(sizeof (hash_obj_t));
262 	if (hash_obj == NULL) {
263 		free(sec_obj);
264 		return (NULL);
265 	}
266 
267 	sec_obj->next = NULL;
268 	sec_obj->seg_obj_list = NULL;
269 
270 	hash_obj->u.sec_obj = sec_obj;
271 	hash_obj->object_type = SECTION_TYPE;
272 	hash_obj->next = NULL;
273 	hash_obj->prev = NULL;
274 
275 	return (hash_obj);
276 }
277 
278 /* called to allocate segment hash object */
279 static hash_obj_t *
create_segment_hash_object(void)280 create_segment_hash_object(void)
281 {
282 	hash_obj_t *hash_obj;
283 	segment_obj_t *seg_obj;
284 
285 	seg_obj	= malloc(sizeof (segment_obj_t));
286 	if (seg_obj == NULL) {
287 		return (NULL);
288 	}
289 
290 	hash_obj = malloc(sizeof (hash_obj_t));
291 	if (hash_obj == NULL) {
292 		free(seg_obj);
293 		return (NULL);
294 	}
295 
296 	seg_obj->next		= NULL;
297 	seg_obj->pkt_obj_list	= NULL;
298 
299 	hash_obj->object_type	= SEGMENT_TYPE;
300 	hash_obj->u.seg_obj	= seg_obj;
301 	hash_obj->next		= NULL;
302 	hash_obj->prev		= NULL;
303 
304 	return (hash_obj);
305 }
306 
307 /* called to allocate packet hash object */
308 static hash_obj_t *
create_packet_hash_object(void)309 create_packet_hash_object(void)
310 {
311 	hash_obj_t		*hash_obj;
312 	packet_obj_t		*pkt_obj;
313 
314 	pkt_obj	= malloc(sizeof (packet_obj_t));
315 	if (pkt_obj == NULL) {
316 		return (NULL);
317 	}
318 
319 	hash_obj = malloc(sizeof (hash_obj_t));
320 	if (hash_obj == NULL) {
321 		free(pkt_obj);
322 		return (NULL);
323 	}
324 
325 	pkt_obj->next		= NULL;
326 
327 	hash_obj->object_type	= PACKET_TYPE;
328 	hash_obj->u.pkt_obj	= pkt_obj;
329 	hash_obj->next		= NULL;
330 	hash_obj->prev		= NULL;
331 
332 	return (hash_obj);
333 }
334 
335 /* called to add allocated hash object into the hash table */
336 static void
add_hashobject_to_hashtable(hash_obj_t * hash_obj,int object_type)337 add_hashobject_to_hashtable(hash_obj_t *hash_obj, int object_type)
338 {
339 	handle_t		index_to_hash;
340 	static	uint64_t	handle_count	= 0;
341 
342 	if (object_type != CONTAINER_TYPE) {
343 		hash_obj->obj_hdl = ++handle_count;
344 	}
345 
346 	/* where to add ? */
347 	index_to_hash	= ((hash_obj->obj_hdl) % TABLE_SIZE);
348 
349 	hash_obj->next	= hash_table[index_to_hash];
350 	hash_table[index_to_hash] = hash_obj;	/* hash obj. added */
351 
352 	if (hash_obj->next != NULL) {
353 		hash_obj->next->prev = hash_obj;
354 	}
355 }
356 
357 /* called to add section object list into the section list */
358 static void
add_to_sec_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)359 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
360 {
361 	hash_obj_t	*next_hash;
362 
363 	child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
364 	if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
365 		parent_obj->u.cont_obj->sec_obj_list = child_obj;
366 		return;
367 	}
368 
369 	for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
370 		next_hash->u.sec_obj->next != NULL;
371 		next_hash = next_hash->u.sec_obj->next) {
372 		;
373 	}
374 
375 	next_hash->u.sec_obj->next	= child_obj;
376 }
377 
378 /* called to add segment object list into segment list */
379 static void
add_to_seg_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)380 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
381 {
382 	hash_obj_t	*next_hash;
383 
384 	child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
385 	if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
386 		parent_obj->u.sec_obj->seg_obj_list = child_obj;
387 		return;
388 	}
389 
390 	for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
391 		next_hash->u.seg_obj->next != NULL;
392 		next_hash = next_hash->u.seg_obj->next) {
393 		;
394 	}
395 
396 	next_hash->u.seg_obj->next	= child_obj;
397 }
398 
399 /* called to add packet object list into packet list */
400 static void
add_to_pkt_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)401 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
402 {
403 	hash_obj_t	*next_hash;
404 
405 	/* add the packet object in the end of list */
406 	child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;
407 
408 	if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
409 		parent_obj->u.seg_obj->pkt_obj_list = child_obj;
410 		return;
411 	}
412 
413 	for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
414 		next_hash->u.pkt_obj->next != NULL;
415 		next_hash = next_hash->u.pkt_obj->next) {
416 			;
417 	}
418 
419 	next_hash->u.pkt_obj->next = child_obj;
420 }
421 
422 /* fill the information, payload in the conatiner */
423 /*ARGSUSED*/
424 static int
initialize_ipmi_container(picl_nodehdl_t fru,hash_obj_t * cont_hash_obj)425 initialize_ipmi_container(picl_nodehdl_t fru, hash_obj_t *cont_hash_obj)
426 {
427 	payload_t manr;
428 	hash_obj_t *seg_hash_obj, *sec_hash_obj, *pkt_hash_obj;
429 	format_t format;
430 
431 	format = cont_hash_obj->u.cont_obj->format;
432 	/* plug to SMC driver to fetch the data */
433 	if (get_manr(&format, &manr) != 0) {
434 		return (-1);
435 	}
436 
437 	cont_hash_obj->u.cont_obj->num_of_section =  1;
438 	cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
439 
440 	sec_hash_obj = create_section_hash_object();
441 	if (sec_hash_obj == NULL) {
442 		return (-1);
443 	}
444 
445 	add_hashobject_to_hashtable(sec_hash_obj, SECTION_TYPE);
446 
447 	/* create fake section info here */
448 	sec_hash_obj->u.sec_obj->num_of_segment = 1;
449 	sec_hash_obj->u.sec_obj->section.handle = sec_hash_obj->obj_hdl;
450 	sec_hash_obj->u.sec_obj->section.offset = 0;
451 	sec_hash_obj->u.sec_obj->section.protection = READ_ONLY_SECTION;
452 
453 	sec_hash_obj->u.sec_obj->section.length = STATIC_LENGTH;
454 	sec_hash_obj->u.sec_obj->section.version = SECTION_HDR_VER;
455 	add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
456 
457 	seg_hash_obj = create_segment_hash_object();
458 	if (seg_hash_obj == NULL) {
459 		return (-1);
460 	}
461 
462 	add_hashobject_to_hashtable(seg_hash_obj, SEGMENT_TYPE);
463 
464 	seg_hash_obj->u.seg_obj->num_of_packets = 1;
465 	seg_hash_obj->u.seg_obj->segment.handle = seg_hash_obj->obj_hdl;
466 	(void) strncpy(seg_hash_obj->u.seg_obj->segment.name,
467 		SD_SEGMENT_NAME,
468 		sizeof (seg_hash_obj->u.seg_obj->segment.name));
469 	seg_hash_obj->u.seg_obj->segment.descriptor = SD_SEGMENT_DESCRIPTOR;
470 						/* tag + payload */
471 	seg_hash_obj->u.seg_obj->segment.length = MANR_SIZE +
472 		SEGMENT_TRAILER_LEN + SEGMENT_CHKSM_LEN;
473 	add_to_seg_object_list(sec_hash_obj, seg_hash_obj);
474 
475 	pkt_hash_obj = create_packet_hash_object();
476 	if (pkt_hash_obj == NULL) {
477 		return (-1);
478 	}
479 	add_hashobject_to_hashtable(pkt_hash_obj, PACKET_TYPE);
480 
481 	pkt_hash_obj->u.pkt_obj->payload_data = manr;
482 	if (mk_tag(FRU_F, 0x001, 0x0B7, &pkt_hash_obj->u.pkt_obj->tag) == 4) {
483 		add_to_pkt_object_list(seg_hash_obj, pkt_hash_obj);
484 	}
485 	return (0);
486 }
487 
488 /* Look up the container_hdl in the PICL tree. */
489 static container_hdl_t
ipmi_fru_open_container(picl_nodehdl_t fruh)490 ipmi_fru_open_container(picl_nodehdl_t fruh)
491 {
492 	int err;
493 	hash_obj_t		*cont_hash_obj;
494 
495 	err = ptree_get_propval_by_name(fruh, PICL_PROP_FRUDATA_AVAIL,
496 		NULL, NULL);
497 	if (err != PICL_SUCCESS) {
498 		return (0);
499 	}
500 
501 	cont_hash_obj = lookup_handle_object((handle_t)fruh, CONTAINER_TYPE);
502 	if (cont_hash_obj == NULL) {
503 		return (0);
504 	}
505 
506 	/* initialize the container */
507 	if (initialize_ipmi_container(fruh, cont_hash_obj) != 0) {
508 		return (0);
509 	}
510 	return (cont_hash_obj->obj_hdl);
511 }
512 
513 /*ARGSUSED*/
514 static int
ipmi_fru_get_num_sections(container_hdl_t container,door_cred_t * cred)515 ipmi_fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
516 {
517 	hash_obj_t 	*cont_hash_obj;
518 
519 	cont_hash_obj = lookup_handle_object((handle_t)container,
520 		CONTAINER_TYPE);
521 	if (cont_hash_obj == NULL) {
522 		return (-1);
523 	}
524 	return (cont_hash_obj->u.cont_obj->num_of_section);
525 }
526 
527 /*ARGSUSED*/
528 static int
ipmi_fru_get_sections(container_hdl_t container,section_t * section,int max_sections,door_cred_t * cred)529 ipmi_fru_get_sections(container_hdl_t container, section_t *section,
530 	int max_sections, door_cred_t *cred)
531 {
532 	int count;
533 	hash_obj_t	*cont_object;
534 	hash_obj_t	*sec_hash;
535 
536 	cont_object = lookup_handle_object((handle_t)container,
537 		CONTAINER_TYPE);
538 	if (cont_object == NULL) {
539 		return (-1);
540 	}
541 
542 	if (cont_object->u.cont_obj->num_of_section > max_sections) {
543 		return (-1);
544 	}
545 	sec_hash = cont_object->u.cont_obj->sec_obj_list;
546 
547 	for (count = 0; count < cont_object->u.cont_obj->num_of_section &&
548 		sec_hash != NULL; count++, section++) {
549 		/* populate section_t */
550 		section->handle = sec_hash->u.sec_obj->section.handle;
551 		section->offset = sec_hash->u.sec_obj->section.offset;
552 		section->length = sec_hash->u.sec_obj->section.length;
553 		section->protection = sec_hash->u.sec_obj->section.protection;
554 		section->version = sec_hash->u.sec_obj->section.version;
555 		sec_hash = sec_hash->u.sec_obj->next;
556 	}
557 	return (count);
558 }
559 
560 /*ARGSUSED*/
561 static int
ipmi_fru_get_num_segments(section_hdl_t section,door_cred_t * cred)562 ipmi_fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
563 {
564 	hash_obj_t	*sec_object;
565 
566 	sec_object = lookup_handle_object((handle_t)section, SECTION_TYPE);
567 	if (sec_object == NULL) {
568 		return (-1);
569 	}
570 	return (sec_object->u.sec_obj->num_of_segment);
571 }
572 
573 /*ARGSUSED*/
574 static int
ipmi_fru_get_segments(section_hdl_t section,segment_t * segment,int max_segments,door_cred_t * cred)575 ipmi_fru_get_segments(section_hdl_t section, segment_t *segment,
576 	int max_segments, door_cred_t *cred)
577 {
578 	int count;
579 	hash_obj_t	*seg_hash;
580 	hash_obj_t	*sec_object;
581 
582 	sec_object = lookup_handle_object((handle_t)section, SECTION_TYPE);
583 	if (sec_object == NULL) {
584 		return (-1);
585 	}
586 
587 	if (sec_object->u.sec_obj->num_of_segment > max_segments) {
588 		return (-1);
589 	}
590 
591 	seg_hash = sec_object->u.sec_obj->seg_obj_list;
592 
593 	for (count = 0; count < sec_object->u.sec_obj->num_of_segment &&
594 		seg_hash != NULL; count++, segment++) {
595 		/* populate the segment info */
596 		segment->handle = seg_hash->u.seg_obj->segment.handle;
597 		(void) memcpy(segment->name, seg_hash->u.seg_obj->segment.name,
598 			SEG_NAME_LEN);
599 		segment->descriptor = seg_hash->u.seg_obj->segment.descriptor;
600 		segment->offset = seg_hash->u.seg_obj->segment.offset;
601 		segment->length = seg_hash->u.seg_obj->segment.length;
602 		seg_hash = seg_hash->u.seg_obj->next;
603 	}
604 	return (count);
605 }
606 
607 /*ARGSUSED*/
608 static int
ipmi_fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)609 ipmi_fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
610 {
611 	hash_obj_t	*seg_object;
612 
613 	seg_object = lookup_handle_object((handle_t)segment, SEGMENT_TYPE);
614 	if (seg_object == NULL) {
615 		return (-1);
616 	}
617 	return (seg_object->u.seg_obj->num_of_packets);
618 }
619 
620 /*ARGSUSED*/
621 static int
ipmi_fru_get_packets(segment_hdl_t segment,packet_t * packet,int max_packets,door_cred_t * cred)622 ipmi_fru_get_packets(segment_hdl_t segment, packet_t *packet,
623 		    int max_packets, door_cred_t *cred)
624 {
625 	int count;
626 	hash_obj_t	*pkt_hash;
627 	hash_obj_t	*seg_object;
628 
629 	seg_object = lookup_handle_object((handle_t)segment, SEGMENT_TYPE);
630 	if (seg_object == NULL) {
631 		return (-1);
632 	}
633 
634 	if (seg_object->u.seg_obj->num_of_packets > max_packets) {
635 		return (-1);
636 	}
637 
638 	pkt_hash = seg_object->u.seg_obj->pkt_obj_list;
639 
640 	for (count = 0; count < seg_object->u.seg_obj->num_of_packets &&
641 		pkt_hash != NULL; count++, packet++) {
642 		/* populate the segment info */
643 		packet->handle = pkt_hash->obj_hdl;
644 		(void) memcpy(&packet->tag, &pkt_hash->u.pkt_obj->tag, 4);
645 		pkt_hash = pkt_hash->u.pkt_obj->next;
646 	}
647 
648 	return (count);
649 }
650 
651 /*ARGSUSED*/
652 static ssize_t
ipmi_fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)653 ipmi_fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
654 		door_cred_t *cred)
655 {
656 	hash_obj_t	*seg_hash;
657 	hash_obj_t	*pkt_hash;
658 
659 	/* segment hash object */
660 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
661 	if (seg_hash == NULL) {
662 		return (-1);
663 	}
664 
665 	if (seg_hash->u.seg_obj->segment.length < nbytes) {
666 		return (-1);
667 	}
668 
669 	pkt_hash = seg_hash->u.seg_obj->pkt_obj_list;
670 
671 	if (pkt_hash == NULL) {
672 		return (-1);
673 	}
674 
675 	(void) memcpy(buffer, &pkt_hash->u.pkt_obj->payload_data,
676 		sizeof (payload_t));
677 	return (nbytes);
678 }
679 
680 /*ARGSUSED*/
681 static ssize_t
ipmi_fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)682 ipmi_fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
683 	door_cred_t *cred)
684 {
685 	hash_obj_t	*packet_hash_obj;
686 
687 	/* size  = size of ManR */
688 	if (nbytes != MANR_SIZE) {
689 		return (-1);
690 	}
691 
692 	/* packet hash object */
693 	packet_hash_obj	= lookup_handle_object(packet, PACKET_TYPE);
694 	if (packet_hash_obj == NULL) {
695 		return (-1);
696 	}
697 
698 	(void) memcpy(buffer, &(packet_hash_obj->u.pkt_obj->payload_data),
699 		MANR_SIZE);
700 	return (nbytes);
701 }
702 
703 /*ARGSUSED*/
704 static int
ipmi_fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)705 ipmi_fru_add_segment(section_hdl_t section, segment_t *segment,
706     section_hdl_t *newsection, door_cred_t *cred)
707 {
708 	errno = ENOTSUP;
709 	return (-1);
710 }
711 
712 /*ARGSUSED*/
713 static int
ipmi_fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)714 ipmi_fru_delete_segment(segment_hdl_t segment,
715     section_hdl_t *newsection, door_cred_t *cred)
716 {
717 	errno = ENOTSUP;
718 	return (-1);
719 }
720 
721 
722 /*ARGSUSED*/
723 static ssize_t
ipmi_fru_write_segment(segment_hdl_t segment,const void * data,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)724 ipmi_fru_write_segment(segment_hdl_t segment, const void *data,
725     size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred)
726 {
727 	errno = ENOTSUP;
728 	return (-1);
729 }
730 
731 /*ARGSUSED*/
732 static int
ipmi_fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)733 ipmi_fru_update_payload(packet_hdl_t packet, const void *data,
734     size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred)
735 {
736 	errno = ENOTSUP;
737 	return (-1);
738 }
739 
740 /*ARGSUSED*/
741 static int
ipmi_fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)742 ipmi_fru_append_packet(segment_hdl_t segment, packet_t *packet,
743     const void *payload, size_t nbytes, segment_hdl_t *newsegment,
744     door_cred_t *cred)
745 {
746 	errno = ENOTSUP;
747 	return (-1);
748 }
749 
750 /*ARGSUSED*/
751 static int
ipmi_fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)752 ipmi_fru_delete_packet(packet_hdl_t packet,
753     segment_hdl_t *newsegment, door_cred_t *cred)
754 {
755 	errno = ENOTSUP;
756 	return (-1);
757 }
758 
759 static void
free_pkt_object_list(hash_obj_t * hash_obj)760 free_pkt_object_list(hash_obj_t	*hash_obj)
761 {
762 	hash_obj_t	*next_obj;
763 	hash_obj_t	*free_obj;
764 
765 	next_obj = hash_obj->u.seg_obj->pkt_obj_list;
766 	while (next_obj != NULL) {
767 		free_obj = next_obj;
768 		next_obj = next_obj->u.pkt_obj->next;
769 		/* if prev is NULL it's the first object in the list */
770 		if (free_obj->prev == NULL) {
771 			hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
772 				free_obj->next;
773 			if (free_obj->next != NULL) {
774 				free_obj->next->prev = free_obj->prev;
775 			}
776 		} else {
777 			free_obj->prev->next = free_obj->next;
778 			if (free_obj->next != NULL) {
779 				free_obj->next->prev = free_obj->prev;
780 			}
781 		}
782 
783 		free(free_obj->u.pkt_obj);
784 		free(free_obj);
785 	}
786 
787 	hash_obj->u.seg_obj->pkt_obj_list = NULL;
788 }
789 
790 static void
free_segment_hash(handle_t handle,hash_obj_t * sec_hash)791 free_segment_hash(handle_t handle, hash_obj_t *sec_hash)
792 {
793 	hash_obj_t	*seg_hash;
794 	hash_obj_t	*next_hash;
795 
796 	seg_hash	= sec_hash->u.sec_obj->seg_obj_list;
797 	if (seg_hash == NULL) {
798 		return;
799 	}
800 
801 	if (seg_hash->obj_hdl == handle) {
802 		sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
803 	} else {
804 		while (seg_hash->obj_hdl != handle) {
805 			next_hash	= seg_hash;
806 			seg_hash = seg_hash->u.seg_obj->next;
807 			if (seg_hash == NULL) {
808 				return;
809 			}
810 		}
811 		next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
812 	}
813 
814 	if (seg_hash->prev == NULL) {
815 		hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
816 		if (seg_hash->next != NULL) {
817 			seg_hash->next->prev = NULL;
818 		}
819 	} else {
820 		seg_hash->prev->next = seg_hash->next;
821 		if (seg_hash->next != NULL) {
822 			seg_hash->next->prev = seg_hash->prev;
823 		}
824 	}
825 
826 	free_pkt_object_list(seg_hash);
827 	free(seg_hash->u.seg_obj);
828 	free(seg_hash);
829 }
830 
831 static int
ipmi_fru_close_container(container_hdl_t container)832 ipmi_fru_close_container(container_hdl_t container)
833 {
834 	hash_obj_t	*hash_obj;
835 	hash_obj_t	*prev_hash;
836 	hash_obj_t	*sec_hash_obj;
837 	handle_t	obj_hdl;
838 
839 	/* lookup for container hash object */
840 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
841 	if (hash_obj == NULL) {
842 		return (0);
843 	}
844 
845 	/* points to section object list */
846 	sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
847 
848 	/* traverse section object list */
849 	while (sec_hash_obj != NULL) {
850 
851 		/* traverse segment hash object in the section */
852 		while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
853 			/* object handle of the segment hash object */
854 			obj_hdl	=
855 				sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
856 			free_segment_hash(obj_hdl, sec_hash_obj);
857 		}
858 
859 		/* going to free section hash object, relink the hash object */
860 		if (sec_hash_obj->prev == NULL) {
861 			hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)]
862 							= sec_hash_obj->next;
863 			if (sec_hash_obj->next != NULL) {
864 				sec_hash_obj->next->prev = NULL;
865 			}
866 		} else {
867 			sec_hash_obj->prev->next = sec_hash_obj->next;
868 			if (sec_hash_obj->next != NULL) {
869 				sec_hash_obj->next->prev = sec_hash_obj->prev;
870 			}
871 		}
872 
873 		free(sec_hash_obj->u.sec_obj); /* free section hash object */
874 
875 		prev_hash = sec_hash_obj;
876 
877 		sec_hash_obj = sec_hash_obj->u.sec_obj->next;
878 
879 		free(prev_hash); /* free section hash */
880 	}
881 
882 	/* free container hash object */
883 	if (hash_obj->prev == NULL) {
884 		hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
885 			hash_obj->next;
886 		if (hash_obj->next != NULL) {
887 			hash_obj->next->prev = NULL;
888 		}
889 	} else {
890 		hash_obj->prev->next = hash_obj->next;
891 		if (hash_obj->next != NULL) {
892 			hash_obj->next->prev = hash_obj->prev;
893 		}
894 	}
895 
896 	free(hash_obj->u.cont_obj);
897 	free(hash_obj);
898 	return (0);
899 }
900 
901 /* opens the binary file and returns the file descriptor */
902 static int
open_file()903 open_file()
904 {
905 	int fd;
906 
907 	if ((fd = open(INPUT_FILE, O_RDWR)) == -1) {
908 		return (-1);
909 	}
910 	return (fd);
911 }
912 
913 static void
copy_segment_layout(segment_t * seghdr,void * layout)914 copy_segment_layout(segment_t	*seghdr, void	*layout)
915 {
916 	segment_layout_t	*seg_layout;
917 
918 	seg_layout	= (segment_layout_t *)layout;
919 	(void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
920 	seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
921 	seghdr->offset	= seg_layout->offset;
922 	seghdr->length	= seg_layout->length;
923 }
924 
925 static hash_obj_t *
get_container_hash_object(int object_type,handle_t handle)926 get_container_hash_object(int	object_type, handle_t	handle)
927 {
928 	hash_obj_t	*hash_obj;
929 
930 	switch (object_type) {
931 	case	CONTAINER_TYPE	:
932 		break;
933 
934 	case	SECTION_TYPE	:
935 		hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
936 		if (hash_obj == NULL) {
937 			return (NULL);
938 		}
939 		break;
940 	case	SEGMENT_TYPE	:
941 		hash_obj = lookup_handle_object(handle, SECTION_TYPE);
942 		if (hash_obj == NULL) {
943 			return (NULL);
944 		}
945 		hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
946 			CONTAINER_TYPE);
947 		break;
948 	case	PACKET_TYPE	:
949 
950 		hash_obj = lookup_handle_object(handle, SEGMENT_TYPE);
951 		if (hash_obj == NULL) {
952 			return (NULL);
953 		}
954 		hash_obj = lookup_handle_object(
955 			hash_obj->u.seg_obj->section_hdl, SECTION_TYPE);
956 		if (hash_obj == NULL) {
957 			return (NULL);
958 		}
959 		hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
960 			CONTAINER_TYPE);
961 		break;
962 	default	:
963 		return (NULL);
964 	}
965 	return (hash_obj);
966 }
967 
968 static void
sort_offsettbl(int segcnt,seg_info_t * offset_tbl)969 sort_offsettbl(int	segcnt, seg_info_t	*offset_tbl)
970 {
971 	int		cntx;
972 	int		cnty;
973 	seg_info_t	tmp;
974 
975 	for (cntx = 0; cntx < segcnt+2; cntx++) {
976 		for (cnty = cntx+1; cnty < segcnt + 2; cnty++) {
977 			if (offset_tbl[cntx].offset >
978 					offset_tbl[cnty].offset) {
979 				(void) memcpy(&tmp, &offset_tbl[cnty],
980 					sizeof (seg_info_t));
981 				(void) memcpy(&offset_tbl[cnty],
982 					&offset_tbl[cntx],
983 					sizeof (seg_info_t));
984 
985 				(void) memcpy(&offset_tbl[cntx], &tmp,
986 					sizeof (seg_info_t));
987 			}
988 		}
989 	}
990 }
991 
992 /*
993  * Description : move_segment_data() reads the segment data and writes it
994  *      back to the new segment offset.
995  */
996 
997 static void
move_segment_data(void * seghdr,int newoffset,container_hdl_t contfd)998 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd)
999 {
1000 	int			ret;
1001 	char			*buffer;
1002 	segment_layout_t	*segment;
1003 	format_t		format;
1004 	hash_obj_t		*cont_hash;
1005 
1006 	segment	= (segment_layout_t *)seghdr;
1007 
1008 	buffer = alloca(segment->length);
1009 	if (buffer == NULL) {
1010 		return;
1011 	}
1012 
1013 	cont_hash = lookup_handle_object((handle_t)contfd, CONTAINER_TYPE);
1014 	if (cont_hash == NULL) {
1015 		return;
1016 	}
1017 
1018 	format = cont_hash->u.cont_obj->format;
1019 
1020 	ret = pread_new(contfd, buffer,
1021 		segment->length, segment->offset, &format);
1022 	if (ret != segment->length) {
1023 		return;
1024 	}
1025 
1026 	segment->offset = newoffset;
1027 
1028 	ret = pwrite_new(contfd, buffer, segment->length, segment->offset,
1029 		&format);
1030 	if (ret != segment->length) {
1031 		return;
1032 	}
1033 }
1034 
1035 /*
1036  * Description : pack_segment_data() moves the segment data if there is
1037  *              a hole between two segments.
1038  */
1039 
1040 static void
pack_segment_data(char * seghdr,int segcnt,container_hdl_t contfd,seg_info_t * offset_tbl)1041 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd,
1042 	seg_info_t *offset_tbl)
1043 {
1044 	int	cnt;
1045 	int	diff;
1046 	int	newoffset;
1047 
1048 	for (cnt = segcnt + 1; cnt > 0; cnt--) {
1049 		if (!offset_tbl[cnt - 1].fixed) {
1050 			if (offset_tbl[cnt].offset
1051 				- (offset_tbl[cnt -1 ].offset
1052 					+ offset_tbl[cnt - 1].length) > 0) {
1053 
1054 				diff = offset_tbl[cnt].offset -
1055 					(offset_tbl[cnt - 1].offset
1056 					+ offset_tbl[cnt - 1].length);
1057 				newoffset = offset_tbl[cnt - 1].offset
1058 								+ diff;
1059 
1060 				move_segment_data(seghdr, newoffset,
1061 					contfd);
1062 
1063 				offset_tbl[cnt - 1].offset = newoffset;
1064 
1065 				sort_offsettbl(segcnt, offset_tbl);
1066 			}
1067 		}
1068 	}
1069 }
1070 
1071 /*
1072  * Description : build_offset_tbl() builds the offset table by reading all the
1073  *              segment header. it makes two more entry into the table one for
1074  *              section size and another with start of the section after the
1075  *              segment header.
1076  */
1077 
1078 static int
build_offset_tbl(void * seghdr,int segcnt,int secsize,seg_info_t * offset_tbl)1079 build_offset_tbl(void   *seghdr, int segcnt, int secsize,
1080 						seg_info_t *offset_tbl)
1081 {
1082 	int			cnt;
1083 	fru_segdesc_t		segdesc;
1084 	segment_layout_t	*segment;
1085 
1086 	for (cnt = 0; cnt < segcnt; cnt++) {
1087 		segment	= (segment_layout_t *)(seghdr) + cnt;
1088 
1089 		(void) memcpy(&segdesc, &segment->descriptor,
1090 			sizeof (uint32_t));
1091 		offset_tbl[cnt].segnum = cnt;
1092 		offset_tbl[cnt].offset = segment->offset;
1093 		offset_tbl[cnt].length = segment->length;
1094 		offset_tbl[cnt].fixed = segdesc.field.fixed;
1095 	}
1096 
1097 	/* upper boundary of segment area (lower address bytes) */
1098 	offset_tbl[cnt].segnum = -1;
1099 	offset_tbl[cnt].offset = sizeof (section_layout_t) + ((cnt + 1)
1100 		* sizeof (segment_layout_t));
1101 
1102 	offset_tbl[cnt].length = 0;
1103 	offset_tbl[cnt].fixed  = 1;
1104 	/* lower boundary of segment area (higher address bytes) */
1105 
1106 	offset_tbl[cnt+1].segnum = -1;
1107 	offset_tbl[cnt+1].offset = secsize;
1108 	offset_tbl[cnt+1].length = 0;
1109 	offset_tbl[cnt+1].fixed = 1;
1110 	return (0);
1111 }
1112 
1113 static int
hole_discovery(int bytes,int segcnt,int * totsize,seg_info_t * offset_tbl)1114 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl)
1115 {
1116 	int cnt = 0;
1117 
1118 	*totsize = 0;
1119 	for (cnt = segcnt + 1; cnt > 0; cnt--) {
1120 		if (bytes <= offset_tbl[cnt].offset -
1121 			(offset_tbl[cnt - 1].offset +
1122 			offset_tbl[cnt - 1].length)) {
1123 			return (offset_tbl[cnt].offset - bytes);
1124 		}
1125 
1126 		*totsize += offset_tbl[cnt].offset -
1127 			(offset_tbl[cnt - 1].offset +
1128 			offset_tbl[cnt - 1].length);
1129 	}
1130 	return (0);
1131 }
1132 
1133 
1134 /*
1135  * Description : segment_hdr_present() verify space for new segment header to
1136  *              be added.
1137  */
1138 
1139 static int
segment_hdr_present(int segoffset,int size,seg_info_t * offset_tbl)1140 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl)
1141 {
1142 	if ((segoffset + size) <= offset_tbl[0].offset)
1143 		return (0);
1144 	else
1145 		return (-1);
1146 }
1147 
1148 /*
1149  * Description : find_offset() is called from fru_add_segment routine to find
1150  *              a valid offset.
1151  */
1152 
1153 static int
find_offset(char * seghdr,int segcnt,int secsize,int * sectionoffset,int segsize,int fix,container_hdl_t contfd)1154 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset,
1155 		int segsize, int fix, container_hdl_t contfd)
1156 {
1157 	int		ret;
1158 	int		newoffset;
1159 	int		totsize = 0;
1160 	seg_info_t	*offset_tbl;
1161 
1162 	if (segcnt == 0) {
1163 		if (!fix) {	/* if not fixed segment */
1164 			*sectionoffset = secsize - segsize;
1165 		}
1166 		return (0);
1167 	}
1168 
1169 	/*
1170 	 * two extra segment info structure are allocated for start of segment
1171 	 * and other end of segment. first segment offset is first available
1172 	 * space and length is 0. second segment offset is is segment length and
1173 	 * offset is 0. build_offset_tbl() explains how upper boundary and lower
1174 	 * boudary segment area are initialized in seg_info_t table.
1175 	 */
1176 
1177 	offset_tbl    = malloc((segcnt + 2) * sizeof (seg_info_t));
1178 	if (offset_tbl == NULL) {
1179 		return (-1);
1180 	}
1181 
1182 	/* read all the segment header to make offset table */
1183 	ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl);
1184 	if (ret != 0) {
1185 		free(offset_tbl);
1186 		return (-1);
1187 	}
1188 
1189 	/* sort the table */
1190 	sort_offsettbl(segcnt, offset_tbl);
1191 
1192 	/* new segment header offset */
1193 	newoffset = sizeof (section_layout_t) + segcnt *
1194 		sizeof (segment_layout_t);
1195 
1196 	/* do? new segment header overlap any existing data */
1197 	ret = segment_hdr_present(newoffset, sizeof (segment_layout_t),
1198 		offset_tbl);
1199 	if (ret != 0) { /* make room for new segment if possible */
1200 
1201 	/* look for hole in order to move segment data */
1202 		if (offset_tbl[0].fixed == SEGMENT_FIXED) { /* fixed segment */
1203 			free(offset_tbl);
1204 			return (-1);
1205 		}
1206 
1207 		newoffset = hole_discovery(offset_tbl[0].length,
1208 			segcnt, &totsize, offset_tbl);
1209 		if (newoffset != 0) { /* found new offset */
1210 				/* now new offset */
1211 			offset_tbl[0].offset = newoffset;
1212 
1213 			/* move the segment data */
1214 			move_segment_data(seghdr, newoffset, contfd);
1215 			/* again sort the offset table */
1216 			sort_offsettbl(segcnt, offset_tbl);
1217 		} else {
1218 			/* pack the existing hole */
1219 			if (totsize > offset_tbl[0].length) {
1220 				pack_segment_data(seghdr, segcnt,
1221 					contfd, offset_tbl);
1222 			} else {
1223 				free(offset_tbl);
1224 				return (-1);
1225 			}
1226 		}
1227 	}
1228 
1229 	totsize = 0;
1230 	newoffset = hole_discovery(segsize, segcnt, &totsize, offset_tbl);
1231 
1232 	if (newoffset == 0) { /* No hole found */
1233 		if (totsize >= segsize) {
1234 			pack_segment_data(seghdr, segcnt, contfd,
1235 				offset_tbl);
1236 			newoffset = hole_discovery(segsize, segcnt,
1237 				&totsize, offset_tbl);
1238 			if (newoffset != 0) {
1239 				*sectionoffset = newoffset;
1240 				free(offset_tbl);
1241 				return (0);
1242 			}
1243 		}
1244 	} else {
1245 		*sectionoffset = newoffset;
1246 		free(offset_tbl);
1247 		return (0);
1248 	}
1249 	free(offset_tbl);
1250 	return (-1);
1251 }
1252 
1253 /*
1254  * Description :sun_fru_open_container() opens the container associated with
1255  *		a fru. it's called by data plugin module before creating
1256  *		container property.  it calls picltree library routine to get
1257  *		the device path and driver binding name for the fru to get the
1258  *              corresponding fru name that describe the fru layout.
1259  *
1260  * Arguments   :picl_hdl_t      fru
1261  *              A handle for PICL tree node of class "fru" representing the
1262  *              FRU with the container to open.
1263  *
1264  * Return      :
1265  *              On Success, a Positive integer container handle. is returned
1266  *              for use in subsequent fru operations;on error, 0 is returned
1267  *              and "errno" is set appropriately.
1268  */
1269 static container_hdl_t
sun_fru_open_container(picl_nodehdl_t fruhdl)1270 sun_fru_open_container(picl_nodehdl_t fruhdl)
1271 {
1272 	int			count;
1273 	hash_obj_t		*cont_hash_obj;
1274 	hash_obj_t		*sec_hash_obj;
1275 
1276 	cont_hash_obj = lookup_handle_object((handle_t)fruhdl, CONTAINER_TYPE);
1277 	if (cont_hash_obj == NULL) {
1278 		return (NULL);
1279 	}
1280 
1281 	cont_hash_obj->u.cont_obj->num_of_section = NUM_OF_SECTIONS;
1282 	cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
1283 
1284 	for (count = 0; count < NUM_OF_SECTIONS; count++) {
1285 		sec_hash_obj = create_section_hash_object();
1286 		if (sec_hash_obj == NULL) {
1287 			return (NULL);
1288 		}
1289 
1290 		add_hashobject_to_hashtable(sec_hash_obj, SECTION_TYPE);
1291 
1292 		if (count == 0) {
1293 			sec_hash_obj->u.sec_obj->section.offset =
1294 				DYNAMIC_OFFSET;
1295 			sec_hash_obj->u.sec_obj->section.protection =
1296 				WRITE_SECTION;
1297 			sec_hash_obj->u.sec_obj->section.length =
1298 				DYNAMIC_LENGTH;
1299 		} else {
1300 			sec_hash_obj->u.sec_obj->section.offset = STATIC_OFFSET;
1301 			sec_hash_obj->u.sec_obj->section.protection =
1302 				READ_ONLY_SECTION;
1303 			sec_hash_obj->u.sec_obj->section.length = STATIC_LENGTH;
1304 		}
1305 
1306 		sec_hash_obj->u.sec_obj->section.version = SECTION_HDR_VER;
1307 
1308 		add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
1309 	}
1310 
1311 	return (cont_hash_obj->obj_hdl);
1312 }
1313 
1314 static int
verify_header_crc8(headerrev_t head_ver,unsigned char * bytes,int length)1315 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
1316 {
1317 	int		crc_offset = 0;
1318 	unsigned char	orig_crc8 = 0;
1319 	unsigned char	calc_crc8 = 0;
1320 
1321 	switch (head_ver) {
1322 		case SECTION_HDR_VER:
1323 			crc_offset = 4;
1324 			break;
1325 		default:
1326 			errno = EINVAL;
1327 			return (0);
1328 	}
1329 
1330 	orig_crc8 = bytes[crc_offset];
1331 	bytes[crc_offset] = 0x00; /* clear for calc */
1332 	calc_crc8 = compute_crc8(bytes, length);
1333 	bytes[crc_offset] = orig_crc8; /* restore */
1334 
1335 	return (orig_crc8 == calc_crc8);
1336 }
1337 
1338 /*
1339  * Description	:
1340  *		sun_fru_get_num_sections() returns number of sections in a
1341  *		container. it calls get_container_index() to get the container
1342  *		index number in the container list.
1343  *
1344  * Arguments	:
1345  *		container_hdl_t	: container handle.
1346  *
1347  * Return	:
1348  *		int
1349  *		On success, returns number of sections in a container.
1350  *
1351  */
1352 /*ARGSUSED*/
1353 static int
sun_fru_get_num_sections(container_hdl_t container,door_cred_t * cred)1354 sun_fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
1355 {
1356 	hash_obj_t		*hash_object;
1357 
1358 	hash_object	= lookup_handle_object(container, CONTAINER_TYPE);
1359 	if (hash_object == NULL) {
1360 		return (-1);
1361 	}
1362 
1363 	return (hash_object->u.cont_obj->num_of_section);
1364 }
1365 
1366 /*
1367  * called from fru_get_sections()
1368  */
1369 
1370 static void
get_section(int fd,hash_obj_t * sec_hash,section_t * section)1371 get_section(int fd, hash_obj_t *sec_hash, section_t *section)
1372 {
1373 	int			retval;
1374 	int			size;
1375 	int			count;
1376 	uint16_t		hdrver;
1377 	hash_obj_t		*seg_hash;
1378 	unsigned char		*buffer;
1379 	section_obj_t		*sec_obj;
1380 	section_layout_t	sec_hdr;
1381 	segment_layout_t	*seg_hdr;
1382 	segment_layout_t	*seg_buf;
1383 	format_t		format;
1384 	hash_obj_t		*cont_hash;
1385 
1386 	sec_obj	= sec_hash->u.sec_obj;
1387 	if (sec_obj == NULL) {
1388 		return;
1389 	}
1390 
1391 	/* populate section_t */
1392 	section->handle = sec_hash->obj_hdl;
1393 	section->offset = sec_obj->section.offset;
1394 	section->length = sec_obj->section.length;
1395 	section->protection = sec_obj->section.protection;
1396 	section->version = sec_obj->section.version;
1397 	sec_obj->num_of_segment	= 0;
1398 
1399 	cont_hash = get_container_hash_object(SEGMENT_TYPE, sec_hash->obj_hdl);
1400 	if (cont_hash == NULL) {
1401 		return;
1402 	}
1403 
1404 	format = cont_hash->u.cont_obj->format;
1405 
1406 	/* read section header layout */
1407 	retval = pread_new(fd, &sec_hdr, sizeof (sec_hdr),
1408 		sec_obj->section.offset, &format);
1409 	if (retval != sizeof (sec_hdr)) {
1410 		return;
1411 	}
1412 
1413 	hdrver	= GET_SECTION_HDR_VERSION;
1414 
1415 	if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
1416 		(hdrver != section->version)) {
1417 		return;
1418 	}
1419 
1420 	/* size = section layout + total sizeof segment header */
1421 	size = sizeof (sec_hdr) + ((sec_hdr.segmentcount)
1422 		* sizeof (segment_layout_t));
1423 	buffer	= alloca(size);
1424 	if (buffer == NULL) {
1425 		return;
1426 	}
1427 
1428 	/* segment header buffer */
1429 	seg_buf = alloca(size - sizeof (sec_hdr));
1430 	if (seg_buf == NULL) {
1431 		return;
1432 	}
1433 
1434 	/* read segment header */
1435 	retval = pread_new(fd, seg_buf, size - sizeof (sec_hdr),
1436 		sec_obj->section.offset + sizeof (sec_hdr), &format);
1437 	if (retval != (size - sizeof (sec_hdr))) {
1438 		return;
1439 	}
1440 
1441 	/* copy section header layout */
1442 	(void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));
1443 
1444 	/* copy segment header layout */
1445 	(void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
1446 		sizeof (sec_hdr));
1447 
1448 	/* verify crc8 */
1449 	retval = verify_header_crc8(hdrver, buffer, size);
1450 	if (retval != TRUE) {
1451 		return;
1452 	}
1453 
1454 	section->version = hdrver;
1455 	sec_obj->section.version = hdrver;
1456 
1457 	seg_hdr	= (segment_layout_t *)seg_buf;
1458 
1459 	for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {
1460 		seg_hash = create_segment_hash_object();
1461 		if (seg_hash == NULL) {
1462 			return;
1463 		}
1464 
1465 		add_hashobject_to_hashtable(seg_hash, SEGMENT_TYPE);
1466 
1467 		copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
1468 
1469 		add_to_seg_object_list(sec_hash, seg_hash);
1470 
1471 		sec_obj->num_of_segment++;
1472 	}
1473 }
1474 
1475 /*
1476  * Description	:
1477  *   		sun_fru_get_sections() fills an array of section structures
1478  *		passed as an argument.
1479  *
1480  * Arguments	:
1481  *		container_hdl_t : container handle(device descriptor).
1482  *		section_t	: array of section structure.
1483  *		int		: maximum number of section in a container.
1484  *
1485  * Returns	:
1486  *   		int
1487  *     		On success,the number of section structures written is returned;
1488  *     		on error, -1 is returned and "errno" is set appropriately.
1489  *
1490  */
1491 /*ARGSUSED*/
1492 static int
sun_fru_get_sections(container_hdl_t container,section_t * section,int maxsec,door_cred_t * cred)1493 sun_fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
1494 	door_cred_t *cred)
1495 {
1496 	int		device_fd;
1497 	int		count;
1498 	hash_obj_t	*cont_object;
1499 	hash_obj_t	*sec_hash;
1500 
1501 	cont_object	= lookup_handle_object(container, CONTAINER_TYPE);
1502 	if (cont_object == NULL) {
1503 		return (-1);
1504 	}
1505 
1506 	if (cont_object->u.cont_obj->num_of_section > maxsec) {
1507 		return (-1);
1508 	}
1509 
1510 	sec_hash = cont_object->u.cont_obj->sec_obj_list;
1511 	if (sec_hash == NULL) {
1512 		return (-1);
1513 	}
1514 
1515 	device_fd = open_file();
1516 
1517 	if (device_fd < 0) {
1518 		return (-1);
1519 	}
1520 
1521 	for (count = 0; count < cont_object->u.cont_obj->num_of_section;
1522 		count++, section++) {
1523 		section->version = -1;
1524 		/* populate section_t */
1525 		get_section(device_fd, sec_hash, section);
1526 		sec_hash = sec_hash->u.sec_obj->next;
1527 	}
1528 
1529 	(void) close(device_fd);
1530 
1531 	return (count);
1532 }
1533 
1534 /*
1535  * Description	:
1536  * 		sun_fru_get_num_segments() returns the current number of
1537  *		segments in a section.
1538  *
1539  * Arguments	:
1540  *		section_hdl_t : section header holding section information.
1541  *
1542  * Return	:
1543  * 		int
1544  *     		On success, the number of segments in the argument section is
1545  *     		returned; on error -1 is returned.
1546  */
1547 /*ARGSUSED*/
1548 static int
sun_fru_get_num_segments(section_hdl_t section,door_cred_t * cred)1549 sun_fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
1550 {
1551 	hash_obj_t	*sec_object;
1552 	section_obj_t	*sec_obj;
1553 
1554 	sec_object	= lookup_handle_object(section, SECTION_TYPE);
1555 	if (sec_object == NULL) {
1556 		return (-1);
1557 	}
1558 
1559 	sec_obj	= sec_object->u.sec_obj;
1560 	if (sec_obj == NULL) {
1561 		return (-1);
1562 	}
1563 
1564 	return (sec_obj->num_of_segment);
1565 }
1566 
1567 /*
1568  * Description	:
1569  *		sun_fru_get_segments() fills an array of structures
1570  *		representing the segments in a section.
1571  *
1572  * Arguments	:
1573  *		section_hdl_t : holds section number.
1574  *		segment_t : on success will hold segment information.
1575  *		int	: maximum number of segment.
1576  *
1577  * Return	:
1578  *		int
1579  *		On success, the number of segment structures written is
1580  *		returned; on errno -1 is returned.
1581  */
1582 /* ARGSUSED */
1583 static int
sun_fru_get_segments(section_hdl_t section,segment_t * segment,int maxseg,door_cred_t * cred)1584 sun_fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
1585 	door_cred_t *cred)
1586 {
1587 	int		count;
1588 	hash_obj_t	*sec_object;
1589 	hash_obj_t	*seg_object;
1590 	section_obj_t	*sec_obj;
1591 
1592 	sec_object = lookup_handle_object(section, SECTION_TYPE);
1593 	if (sec_object == NULL) {
1594 		return (-1);
1595 	}
1596 
1597 	sec_obj	= sec_object->u.sec_obj;
1598 	if (sec_obj == NULL) {
1599 		return (-1);
1600 	}
1601 
1602 	if (sec_obj->num_of_segment > maxseg) {
1603 		return (-1);
1604 	}
1605 
1606 	seg_object	= sec_object->u.sec_obj->seg_obj_list;
1607 	if (seg_object == NULL) {
1608 		return (-1);
1609 	}
1610 
1611 	for (count = 0; count < sec_obj->num_of_segment; count++) {
1612 
1613 		/* populate segment_t */
1614 		segment->handle = seg_object->obj_hdl;
1615 		(void) memcpy(segment->name,
1616 			seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
1617 		segment->descriptor = seg_object->u.seg_obj->segment.descriptor;
1618 		segment->offset	= seg_object->u.seg_obj->segment.offset;
1619 		segment->length	= seg_object->u.seg_obj->segment.length;
1620 		seg_object = seg_object->u.seg_obj->next;
1621 		segment++;
1622 	}
1623 	return (0);
1624 }
1625 
1626 /*
1627  * Description	:
1628  *		sun_fru_add_segment() adds a segment to a section.
1629  *
1630  * Arguments	:
1631  *		section_hdl_t section
1632  *		A handle for the section in which to add the segment.
1633  *
1634  *		segment_t *segment
1635  *		On entry, the "handle" component of "segment" is ignored and the
1636  *		remaining components specify the parameters of the segment to be
1637  *		added.  On return, the "handle" component is set to the handle
1638  *		for the added segment. The segment offset is mandatory for FIXED
1639  *		segments; otherwise, the offset is advisory.
1640  *
1641  * Return	:
1642  *		int
1643  *		On success, 0 is returned; on error -1 is returned.
1644  *
1645  */
1646 static int
sun_fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)1647 sun_fru_add_segment(section_hdl_t section, segment_t *segment,
1648 	section_hdl_t *newsection, door_cred_t *cred)
1649 {
1650 	int		fd;
1651 	int		retval;
1652 	int		offset;
1653 	int		sec_size;
1654 	int		seg_cnt;
1655 	int		bufsize;
1656 	int		new_seg_offset;
1657 	int		new_seg_length;
1658 	int		fixed_segment;
1659 	char		trailer[]	= { 0x0c, 0x00, 0x00, 0x00, 0x00 };
1660 	hash_obj_t	*cont_hash;
1661 	hash_obj_t	*sec_hash;
1662 	hash_obj_t	*seg_hash;
1663 	fru_segdesc_t	*new_seg_desc;
1664 	unsigned char 	*crcbuf;
1665 	section_layout_t sec_layout;
1666 	segment_layout_t *seg_layout;
1667 	segment_layout_t *segment_buf;
1668 	format_t		format;
1669 
1670 	/* check the effective uid of the client */
1671 	if (cred->dc_euid != 0) {
1672 		errno = EPERM;
1673 		return (-1);	/* not a root */
1674 	}
1675 
1676 	/* section hash */
1677 	sec_hash = lookup_handle_object(section, SECTION_TYPE);
1678 	if (sec_hash == NULL) {
1679 		return (-1);
1680 	}
1681 
1682 	/* check for read-only section */
1683 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1684 		errno = EPERM;
1685 		return (-1);
1686 	}
1687 
1688 	/* look for duplicate segment */
1689 	seg_hash = sec_hash->u.sec_obj->seg_obj_list;
1690 	while (seg_hash != NULL) {
1691 		if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name,
1692 			SEG_NAME_LEN) == 0) {
1693 			errno = EEXIST;
1694 			return (-1); /* can't add duplicate segment */
1695 		}
1696 		seg_hash = seg_hash->u.seg_obj->next;
1697 	}
1698 
1699 	/* get the container hash */
1700 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1701 		CONTAINER_TYPE);
1702 	if (cont_hash == NULL) {
1703 		return (-1);
1704 	}
1705 
1706 	format = cont_hash->u.cont_obj->format;
1707 
1708 	/* open the container */
1709 	fd = open_file();
1710 	if (fd < 0) {
1711 		return (-1);
1712 	}
1713 
1714 	/* section start here */
1715 	offset	= sec_hash->u.sec_obj->section.offset;
1716 
1717 	/* read section header layout */
1718 	retval = pread_new(fd, &sec_layout, sizeof (sec_layout), offset,
1719 		&format);
1720 	if (retval != sizeof (sec_layout)) {
1721 		(void) close(fd);
1722 		return (-1);
1723 	}
1724 
1725 	/* check for valid section header */
1726 	if (sec_layout.headertag != SECTION_HDR_TAG) {
1727 		/* write a new one */
1728 		sec_layout.headertag		= SECTION_HDR_TAG;
1729 		sec_layout.headerversion[0]	= SECTION_HDR_VER_BIT0;
1730 		sec_layout.headerversion[1]	= SECTION_HDR_VER_BIT1;
1731 		sec_layout.headerlength		= sizeof (sec_layout);
1732 		sec_layout.segmentcount		= 0;
1733 	}
1734 
1735 	/* section size */
1736 	sec_size	= sec_hash->u.sec_obj->section.length;
1737 
1738 	/* number of segment in the section */
1739 	seg_cnt	= sec_layout.segmentcount;
1740 
1741 	/* total sizeof segment + new segment */
1742 	bufsize	=	sizeof (segment_layout_t) * (seg_cnt + 1);
1743 	segment_buf = alloca(bufsize);
1744 	if (segment_buf == NULL) {
1745 		return (-1);
1746 	}
1747 
1748 	/* read entire segment header */
1749 	retval = pread_new(fd, segment_buf,
1750 		(bufsize - sizeof (segment_layout_t)),
1751 		offset + sizeof (section_layout_t), &format);
1752 	if (retval != (bufsize - sizeof (segment_layout_t))) {
1753 		(void) close(fd);
1754 		return (-1);
1755 	}
1756 
1757 	new_seg_offset	= segment->offset; /* new segment offset */
1758 	new_seg_length	= segment->length; /* new segment length */
1759 
1760 	new_seg_desc	= (fru_segdesc_t *)&segment->descriptor;
1761 
1762 	fixed_segment	= new_seg_desc->field.fixed;
1763 
1764 	/* get new offset for new segment to be addedd */
1765 	retval = find_offset((char *)segment_buf, seg_cnt, sec_size,
1766 		&new_seg_offset, new_seg_length, fixed_segment, fd);
1767 
1768 	if (retval != 0)	{
1769 		(void) close(fd);
1770 		errno = EAGAIN;
1771 		return (-1);
1772 	}
1773 
1774 	/* copy new segment data in segment layout */
1775 	seg_layout	= (segment_layout_t *)(segment_buf + seg_cnt);
1776 	(void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN);
1777 	(void) memcpy(seg_layout->descriptor, &segment->descriptor,
1778 		sizeof (uint32_t));
1779 	seg_layout->length	= segment->length;
1780 	seg_layout->offset	= new_seg_offset; /* new segment offset */
1781 
1782 	sec_layout.segmentcount += 1;
1783 
1784 	crcbuf	= alloca(sizeof (section_layout_t) + bufsize);
1785 	if (crcbuf == NULL) {
1786 		(void) close(fd);
1787 		return (-1);
1788 	}
1789 
1790 	sec_layout.headercrc8 = 0;
1791 	sec_layout.headerlength += sizeof (segment_layout_t);
1792 
1793 	(void) memcpy(crcbuf, (char *)&sec_layout, sizeof (section_layout_t));
1794 	(void) memcpy(crcbuf + sizeof (section_layout_t), segment_buf, bufsize);
1795 
1796 	sec_layout.headercrc8 = compute_crc8(crcbuf, bufsize +
1797 		sizeof (section_layout_t));
1798 
1799 	/* write section header */
1800 	retval = pwrite_new(fd, &sec_layout, sizeof (section_layout_t),
1801 		offset, &format);
1802 	if (retval != sizeof (section_layout_t)) {
1803 		(void) close(fd);
1804 		return (-1);
1805 	}
1806 
1807 	/* write segment header */
1808 	retval = pwrite_new(fd, segment_buf, bufsize, offset +
1809 		sizeof (section_layout_t), &format);
1810 	if (retval != bufsize) {
1811 		(void) close(fd);
1812 		return (-1);
1813 	}
1814 
1815 	/* write segment trailer */
1816 	retval = pwrite_new(fd, &trailer, sizeof (trailer), new_seg_offset,
1817 		&format);
1818 	if (retval != sizeof (trailer)) {
1819 		(void) close(fd);
1820 		return (-1);
1821 	}
1822 
1823 	(void) close(fd);
1824 
1825 	/* create new segment hash object */
1826 	seg_hash	= create_segment_hash_object();
1827 	if (seg_hash == NULL) {
1828 		return (-1);
1829 	}
1830 
1831 	add_hashobject_to_hashtable(seg_hash, SEGMENT_TYPE);
1832 
1833 	copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_layout);
1834 
1835 	add_to_seg_object_list(sec_hash, seg_hash);
1836 
1837 	sec_hash->u.sec_obj->num_of_segment += 1;
1838 	seg_hash->u.seg_obj->trailer_offset = new_seg_offset;
1839 	*newsection	= section; /* return the new section handle */
1840 	return (0);
1841 }
1842 
1843 /*
1844  * Description	:
1845  *		sun_fru_delete_segment() deletes a segment from a section; the
1846  *		associated container data is not altered.
1847  *
1848  * Arguments	: segment_hdl_t	segment handle.
1849  *		  section_hdl_t	new section handle.
1850  *
1851  * Return	:
1852  *		int
1853  *		On success, 0 returned; On error -1 is returned.
1854  */
1855 static int
sun_fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)1856 sun_fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
1857 	door_cred_t *cred)
1858 {
1859 	int			num_of_seg;
1860 	int			bufsize;
1861 	int			count;
1862 	int			retval;
1863 	int			fd;
1864 	int			segnum;
1865 	hash_obj_t		*seg_hash;
1866 	hash_obj_t		*sec_hash;
1867 	hash_obj_t		*cont_hash;
1868 	hash_obj_t		*tmp_hash;
1869 	unsigned char		*buffer;
1870 	fru_segdesc_t		*desc;
1871 	segment_layout_t	*seg_buf;
1872 	section_layout_t	*sec_layout;
1873 	segment_layout_t	*seg_layout;
1874 	segment_layout_t	*next_layout;
1875 	format_t		format;
1876 
1877 	/* check the effective uid of the client */
1878 	if (cred->dc_euid != 0) {
1879 		errno = EPERM;
1880 		return (-1);	/* not a root */
1881 	}
1882 
1883 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1884 	if (seg_hash == NULL) {
1885 		return (-1);
1886 	}
1887 
1888 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
1889 	if (!(desc->field.field_perm & SEGMENT_DELETE)) {
1890 		errno = EPERM;
1891 		return (-1); /* can't delete this segment */
1892 	}
1893 
1894 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1895 		SECTION_TYPE);
1896 	if (sec_hash == NULL) {
1897 		return (-1);
1898 	}
1899 
1900 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1901 		errno = EPERM;
1902 		return (-1);
1903 	}
1904 
1905 	num_of_seg	= sec_hash->u.sec_obj->num_of_segment;
1906 
1907 	bufsize	= (sizeof (segment_layout_t) * num_of_seg);
1908 
1909 	seg_buf	= alloca(bufsize);
1910 	if (seg_buf == NULL) {
1911 		return (-1);
1912 	}
1913 
1914 	segnum	= 0;
1915 	for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL;
1916 		tmp_hash = tmp_hash->u.seg_obj->next) {
1917 		if (tmp_hash->obj_hdl == segment) {
1918 			break;
1919 		}
1920 		segnum++;
1921 	}
1922 
1923 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1924 		CONTAINER_TYPE);
1925 	if (cont_hash == NULL) {
1926 		return (-1);
1927 	}
1928 	format = cont_hash->u.cont_obj->format;
1929 
1930 	fd  = open_file();
1931 	if (fd < 0) {
1932 		return (-1);
1933 	}
1934 
1935 	sec_layout	= alloca(sizeof (section_layout_t));
1936 	if (sec_layout == NULL) {
1937 		(void) close(fd);
1938 		return (-1);
1939 	}
1940 
1941 	/* read section layout header */
1942 	retval = pread_new(fd, sec_layout, sizeof (section_layout_t),
1943 		sec_hash->u.sec_obj->section.offset, &format);
1944 	if (retval != sizeof (section_layout_t)) {
1945 		(void) close(fd);
1946 		return (-1);
1947 	}
1948 
1949 	/* read segment header layout */
1950 	retval = pread_new(fd, seg_buf, bufsize,
1951 		sec_hash->u.sec_obj->section.offset +
1952 		sizeof (section_layout_t), &format);
1953 	if (retval != bufsize) {
1954 		(void) close(fd);
1955 		return (-1);
1956 	}
1957 
1958 	seg_layout = (segment_layout_t *)(seg_buf + segnum);
1959 	next_layout	= seg_layout;
1960 	for (count = segnum; count < sec_hash->u.sec_obj->num_of_segment-1;
1961 		count++) {
1962 		next_layout++;
1963 		(void) memcpy(seg_layout, next_layout,
1964 			sizeof (segment_layout_t));
1965 		seg_layout++;
1966 	}
1967 
1968 	(void) memset(seg_layout, '\0', sizeof (segment_layout_t));
1969 
1970 	sec_layout->headercrc8 = 0;
1971 
1972 	sec_layout->headerlength -= sizeof (segment_layout_t);
1973 	sec_layout->segmentcount -= 1;
1974 
1975 	buffer = alloca(sec_layout->headerlength);
1976 	if (buffer == NULL) {
1977 		(void) close(fd);
1978 		return (-1);
1979 	}
1980 
1981 	(void) memcpy(buffer, sec_layout, sizeof (section_layout_t));
1982 	(void) memcpy(buffer + sizeof (section_layout_t), seg_buf, bufsize
1983 		- sizeof (segment_layout_t));
1984 	sec_layout->headercrc8 = compute_crc8(buffer,
1985 		sec_layout->headerlength);
1986 
1987 	/* write section header with update crc8 and header length */
1988 	retval = pwrite_new(fd, sec_layout, sizeof (section_layout_t),
1989 		sec_hash->u.sec_obj->section.offset, &format);
1990 	if (retval != sizeof (section_layout_t)) {
1991 		(void) close(fd);
1992 		return (-1);
1993 	}
1994 
1995 	/* write the update segment header */
1996 	retval = pwrite_new(fd, seg_buf, bufsize,
1997 		sec_hash->u.sec_obj->section.offset +
1998 		sizeof (section_layout_t), &format);
1999 	(void) close(fd);
2000 	if (retval != bufsize) {
2001 		return (-1);
2002 	}
2003 
2004 	free_segment_hash(segment, sec_hash);
2005 
2006 	*newsection	= sec_hash->obj_hdl;
2007 	sec_hash->u.sec_obj->num_of_segment = sec_layout->segmentcount;
2008 
2009 	return (0);
2010 }
2011 
2012 /*
2013  * Description	:
2014  * 		sun_fru_read_segment() reads the raw contents of a segment.
2015  *
2016  * Arguments	: segment_hdl_t : segment handle.
2017  *		 void *	: buffer containing segment data when function returns.
2018  *		size_t :number of bytes.
2019  *
2020  * Return	:
2021  * 		int
2022  *		On success, the number of bytes read is returned;
2023  *
2024  * Notes	:
2025  *		Segments containing packets can be read in structured fashion
2026  *		using the fru_get_packets() and fru_get_payload() primitives;the
2027  *		entire byte range of a segment can be read using
2028  *		fru_read_segment().
2029  */
2030 /*ARGSUSED*/
2031 static ssize_t
sun_fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)2032 sun_fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
2033 		door_cred_t *cred)
2034 {
2035 	int		fd;
2036 	int		retval;
2037 	hash_obj_t	*seg_hash;
2038 	hash_obj_t	*sec_hash;
2039 	hash_obj_t	*cont_hash;
2040 	format_t	format;
2041 
2042 	/* segment hash object */
2043 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2044 	if (seg_hash == NULL) {
2045 		return (-1);
2046 	}
2047 
2048 	/* section hash object */
2049 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2050 		SECTION_TYPE);
2051 	if (sec_hash == NULL) {
2052 		return (-1);
2053 	}
2054 
2055 	/* container hash object */
2056 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2057 		CONTAINER_TYPE);
2058 	if (cont_hash == NULL) {
2059 		return (-1);
2060 	}
2061 	format = cont_hash->u.cont_obj->format;
2062 
2063 	if (seg_hash->u.seg_obj->segment.length < nbytes) {
2064 		return (-1);
2065 	}
2066 
2067 	fd = open_file();
2068 	if (fd < 0) {
2069 		return (-1);
2070 	}
2071 
2072 	retval = pread_new(fd, buffer, nbytes,
2073 		seg_hash->u.seg_obj->segment.offset, &format);
2074 	(void) close(fd);
2075 	if (retval != nbytes) {
2076 		return (-1);
2077 	}
2078 	return (nbytes);
2079 }
2080 
2081 /*
2082  * Description	:
2083  *		sun_fru_write_segment() writes a raw segment.
2084  *
2085  * Arguments	: segment_hdl_t :segment handle.
2086  *		 const void * : data buffer.
2087  *		 size_t	: number of bytes.
2088  *		 segment_hdl_t : new segment handle.
2089  *
2090  * Returns	:
2091  *		int
2092  *		On success, the number of bytes written is returned
2093  *
2094  */
2095 /*ARGSUSED*/
2096 static int
sun_fru_write_segment(segment_hdl_t segment,const void * data,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)2097 sun_fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes,
2098 	segment_hdl_t *newsegment, door_cred_t *cred)
2099 {
2100 	return (ENOTSUP);
2101 }
2102 
2103 
2104 static int
get_packet(int device_fd,void * buffer,int size,int offset,format_t * format)2105 get_packet(int device_fd, void *buffer, int size, int offset, format_t *format)
2106 {
2107 	int	retval;
2108 
2109 	retval = pread_new(device_fd, (char *)buffer, size, offset, format);
2110 	if (retval != -1) {
2111 		return (0);
2112 	}
2113 	return (-1);
2114 }
2115 
2116 static uint32_t
get_checksum_crc(hash_obj_t * seg_hash,int data_size)2117 get_checksum_crc(hash_obj_t	*seg_hash, int data_size)
2118 {
2119 	int		protection;
2120 	int		offset = 0;
2121 	uint32_t	crc;
2122 	hash_obj_t	*sec_hash;
2123 	hash_obj_t	*pkt_hash;
2124 	unsigned char	*buffer;
2125 
2126 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2127 		SECTION_TYPE);
2128 	if (sec_hash == NULL) {
2129 		return ((uint32_t)-1);
2130 	}
2131 
2132 	buffer = alloca(data_size);
2133 	if (buffer == NULL) {
2134 		return ((uint32_t)-1);
2135 	}
2136 
2137 	/* traverse the packet object list for all the tags and payload */
2138 	for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL;
2139 		pkt_hash = pkt_hash->u.pkt_obj->next) {
2140 		(void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
2141 			pkt_hash->u.pkt_obj->tag_size);
2142 		offset += pkt_hash->u.pkt_obj->tag_size;
2143 		(void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload,
2144 			pkt_hash->u.pkt_obj->paylen);
2145 		offset += pkt_hash->u.pkt_obj->paylen;
2146 	}
2147 
2148 	protection	= sec_hash->u.sec_obj->section.protection;
2149 
2150 	if (protection == READ_ONLY_SECTION) { /* read-only section */
2151 		crc = compute_crc32(buffer, data_size);
2152 	} else {		/* read/write section */
2153 		crc = compute_checksum32(buffer, data_size);
2154 	}
2155 	return (crc);	/* computed crc */
2156 }
2157 
2158 static int
get_packets(hash_obj_t * seg_hash,int device_fd,int offset,int length)2159 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length)
2160 {
2161 	int		tag_size;
2162 	int		paylen;
2163 	int		retval;
2164 	int		seg_limit = 0;
2165 	int		pktcnt	= 0;
2166 	char		*data;
2167 	uint32_t	crc;
2168 	uint32_t	origcrc;
2169 	fru_tag_t	tag;
2170 	hash_obj_t	*pkt_hash_obj;
2171 	fru_segdesc_t	*segdesc;
2172 	fru_tagtype_t	tagtype;
2173 	format_t	format;
2174 	hash_obj_t	*cont_hash;
2175 
2176 	cont_hash = get_container_hash_object(PACKET_TYPE, seg_hash->obj_hdl);
2177 	if (cont_hash == NULL) {
2178 		return (NULL);
2179 	}
2180 	format = cont_hash->u.cont_obj->format;
2181 
2182 	retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), offset,
2183 		&format);
2184 	if (retval == -1) {
2185 		return (-1);
2186 	}
2187 
2188 	seg_hash->u.seg_obj->trailer_offset = offset;
2189 
2190 	data	= (char *)&tag;
2191 	while (data[0] != SEG_TRAILER_TAG) {
2192 		tagtype	= get_tag_type(&tag); /* verify tag type */
2193 		if (tagtype == -1) {
2194 			return (-1);
2195 		}
2196 
2197 		tag_size = get_tag_size(tagtype);
2198 		if (tag_size == -1) {
2199 			return (-1);
2200 		}
2201 
2202 		seg_limit += tag_size;
2203 		if (seg_limit > length) {
2204 			return (-1);
2205 		}
2206 
2207 		paylen = get_payload_length((void *)&tag);
2208 		if (paylen == -1) {
2209 			return (-1);
2210 		}
2211 
2212 		seg_limit += paylen;
2213 		if (seg_limit > length) {
2214 			return (-1);
2215 		}
2216 
2217 		pkt_hash_obj = create_packet_hash_object();
2218 		if (pkt_hash_obj == NULL) {
2219 			return (-1);
2220 		}
2221 
2222 		pkt_hash_obj->u.pkt_obj->payload = malloc(paylen);
2223 		if (pkt_hash_obj->u.pkt_obj->payload == NULL) {
2224 			free(pkt_hash_obj);
2225 			return (-1);
2226 		}
2227 
2228 		offset += tag_size;
2229 		retval = pread_new(device_fd, pkt_hash_obj->u.pkt_obj->payload,
2230 			paylen, offset, &format);
2231 		if (retval != paylen) {
2232 			free(pkt_hash_obj->u.pkt_obj->payload);
2233 			free(pkt_hash_obj);
2234 			return (-1);
2235 		}
2236 
2237 		/* don't change this */
2238 		pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
2239 		(void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
2240 		pkt_hash_obj->u.pkt_obj->paylen = paylen;
2241 		pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
2242 		pkt_hash_obj->u.pkt_obj->payload_offset = offset;
2243 
2244 		offset += paylen;
2245 
2246 		add_hashobject_to_hashtable(pkt_hash_obj, PACKET_TYPE);
2247 		add_to_pkt_object_list(seg_hash, pkt_hash_obj);
2248 
2249 		pktcnt++;
2250 
2251 		retval = get_packet(device_fd, &tag, sizeof (fru_tag_t),
2252 			offset, &format);
2253 		if (retval == -1) {
2254 			return (retval);
2255 		}
2256 
2257 		data	= (char *)&tag;
2258 	}
2259 
2260 	segdesc	= (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2261 
2262 	seg_hash->u.seg_obj->trailer_offset = offset;
2263 
2264 	if (!segdesc->field.ignore_checksum)  {
2265 		crc = get_checksum_crc(seg_hash, seg_limit);
2266 		offset	= seg_hash->u.seg_obj->segment.offset;
2267 
2268 		retval = pread_new(device_fd, &origcrc, sizeof (origcrc),
2269 			offset + seg_limit + 1, &format);
2270 		if (retval != sizeof (origcrc)) {
2271 			return (-1);
2272 		}
2273 
2274 		if (origcrc != crc) {
2275 			seg_hash->u.seg_obj->trailer_offset = offset;
2276 			return (-1);
2277 		}
2278 	}
2279 	return (pktcnt);
2280 }
2281 
2282 /*
2283  * Description	:
2284  *		sun_fru_get_num_packets() returns the current number of packets
2285  *		in a segment.
2286  *
2287  * Arguments	: segment_hdl_t : segment handle.
2288  *
2289  * Return	:
2290  *		int
2291  *		On success, the number of packets is returned;
2292  *		-1 on failure.
2293  */
2294 /*ARGSUSED*/
2295 static int
sun_fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)2296 sun_fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
2297 {
2298 	int		device_fd;
2299 	int		pktcnt;
2300 	int		length;
2301 	uint16_t	offset;
2302 	hash_obj_t	*cont_hash_obj;
2303 	hash_obj_t	*seg_hash;
2304 	fru_segdesc_t	*segdesc;
2305 	segment_obj_t	*segment_object;
2306 
2307 	seg_hash	= lookup_handle_object(segment, SEGMENT_TYPE);
2308 	if (seg_hash == NULL) {
2309 		return (-1);
2310 	}
2311 
2312 	segment_object	= seg_hash->u.seg_obj;
2313 	if (segment_object == NULL) {
2314 		return (-1);
2315 	}
2316 
2317 
2318 	segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
2319 	if (segdesc->field.opaque) {
2320 		return (0);
2321 	}
2322 
2323 	offset = segment_object->segment.offset;
2324 	length = segment_object->segment.length;
2325 
2326 	cont_hash_obj = get_container_hash_object(SEGMENT_TYPE,
2327 		segment_object->section_hdl);
2328 
2329 	if (cont_hash_obj == NULL) {
2330 		return (-1);
2331 	}
2332 
2333 	if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
2334 		return (segment_object->num_of_packets);
2335 	}
2336 
2337 	segment_object->num_of_packets = 0;
2338 	device_fd = open_file();
2339 	if (device_fd < 0) {
2340 		return (-1);
2341 	}
2342 
2343 	pktcnt = get_packets(seg_hash, device_fd, offset,
2344 		length);
2345 	if (pktcnt == -1) {
2346 		free_pkt_object_list(seg_hash);
2347 		seg_hash->u.seg_obj->pkt_obj_list = NULL;
2348 	}
2349 
2350 	segment_object->num_of_packets = pktcnt;
2351 	(void) close(device_fd);
2352 
2353 	return (segment_object->num_of_packets);
2354 }
2355 
2356 /*
2357  * Description	:
2358  *		sun_fru_get_packets() fills an array of structures
2359  *		representing the packets in a segment.
2360  *
2361  * Arguments	: segment_hdl_t : segment handle.
2362  *		packet_t	: packet buffer.
2363  *		int	: maximum number of packets.
2364  *
2365  * Return	:
2366  *		int
2367  *		On success, the number of packet structures written is returned;
2368  *		On failure -1 is returned;
2369  *
2370  */
2371 /*ARGSUSED*/
2372 static int
sun_fru_get_packets(segment_hdl_t segment,packet_t * packet,int maxpackets,door_cred_t * cred)2373 sun_fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
2374 	door_cred_t *cred)
2375 {
2376 	int		count;
2377 	hash_obj_t	*seg_hash_obj;
2378 	hash_obj_t	*pkt_hash_obj;
2379 
2380 	/* segment hash object */
2381 	seg_hash_obj	= lookup_handle_object(segment, SEGMENT_TYPE);
2382 	if (seg_hash_obj == NULL) {
2383 		return (-1);
2384 	}
2385 
2386 	if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
2387 		return (-1);
2388 	}
2389 
2390 	pkt_hash_obj	= seg_hash_obj->u.seg_obj->pkt_obj_list;
2391 	if (pkt_hash_obj == NULL) {
2392 		return (-1);
2393 	}
2394 
2395 	for (count = 0; count < maxpackets; count++, packet++) {
2396 		packet->handle	= pkt_hash_obj->obj_hdl;
2397 		packet->tag = 0;
2398 		(void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
2399 			pkt_hash_obj->u.pkt_obj->tag_size);
2400 		pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
2401 	}
2402 
2403 	return (0);
2404 }
2405 
2406 /*
2407  * Description	:
2408  *		sun_fru_get_payload() copies the contents of a packet's payload.
2409  *
2410  * Arguments	: packet_hdl_t : packet handle.
2411  *		void *	: payload buffer.
2412  *		size_t	: sizeof the buffer.
2413  *
2414  * Return	:
2415  *    		int
2416  *     		On success, the number of bytes copied is returned; On error
2417  *		-1 returned.
2418  */
2419 /*ARGSUSED*/
2420 static ssize_t
sun_fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)2421 sun_fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
2422 	door_cred_t *cred)
2423 {
2424 	hash_obj_t	*packet_hash_obj;
2425 
2426 	/* packet hash object */
2427 	packet_hash_obj	= lookup_handle_object(packet, PACKET_TYPE);
2428 	if (packet_hash_obj == NULL) {
2429 		return (-1);
2430 	}
2431 
2432 	/* verify payload length */
2433 	if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
2434 		return (-1);
2435 	}
2436 
2437 	(void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes);
2438 	return (nbytes);
2439 }
2440 
2441 /*
2442  * Description	:
2443  * 		sun_fru_update_payload() writes the contents of a packet's
2444  *		payload.
2445  *
2446  * Arguments	: packet_hdl_t : packet handle.
2447  *		const void * : data buffer.
2448  *		size_t	: buffer size.
2449  *		packet_hdl_t	: new packet handle.
2450  *
2451  * Return	:
2452  * 		int
2453  *		On success, 0 is returned; on failure
2454  *		-1 is returned.
2455  */
2456 /*ARGSUSED*/
2457 static int
sun_fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)2458 sun_fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
2459 	packet_hdl_t *newpacket, door_cred_t *cred)
2460 {
2461 	int		fd;
2462 	int		segment_offset;
2463 	int		trailer_offset;
2464 	int		retval;
2465 	uint32_t	crc;
2466 	hash_obj_t	*pkt_hash;
2467 	hash_obj_t	*seg_hash;
2468 	hash_obj_t	*sec_hash;
2469 	hash_obj_t	*cont_hash;
2470 	fru_segdesc_t	*desc;
2471 	format_t	format;
2472 
2473 	/* check the effective uid of the client */
2474 	if (cred->dc_euid != 0) {
2475 		errno = EPERM;
2476 		return (-1);	/* not a root */
2477 	}
2478 
2479 	/* packet hash object */
2480 	pkt_hash = lookup_handle_object(packet,	PACKET_TYPE);
2481 	if (pkt_hash == NULL) {
2482 		return (-1);
2483 	}
2484 
2485 	/* segment hash object */
2486 	seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2487 		SEGMENT_TYPE);
2488 	if (seg_hash == NULL) {
2489 		return (-1);
2490 	}
2491 
2492 	/* check for write perm. */
2493 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2494 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2495 		errno = EPERM;
2496 		return (-1); /* write not allowed */
2497 	}
2498 
2499 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2500 		SECTION_TYPE);
2501 	if (sec_hash == NULL) {
2502 		return (-1);
2503 	}
2504 
2505 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2506 		errno = EPERM;
2507 		return (-1);		/* read-only section */
2508 	}
2509 
2510 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2511 		CONTAINER_TYPE);
2512 	if (cont_hash == NULL) {
2513 		return (-1);
2514 	}
2515 
2516 	format = cont_hash->u.cont_obj->format;
2517 
2518 	if (pkt_hash->u.pkt_obj->paylen != nbytes) {
2519 		return (-1);
2520 	}
2521 
2522 	(void) memcpy(pkt_hash->u.pkt_obj->payload, (char *)data, nbytes);
2523 	fd	= open_file();
2524 	if (fd < 0) {
2525 		return (-1);
2526 	}
2527 
2528 	trailer_offset	= seg_hash->u.seg_obj->trailer_offset;
2529 	segment_offset	= seg_hash->u.seg_obj->segment.offset;
2530 
2531 	crc = get_checksum_crc(seg_hash, (trailer_offset - segment_offset));
2532 	retval = pwrite_new(fd, data, nbytes,
2533 		pkt_hash->u.pkt_obj->payload_offset, &format);
2534 	if (retval != nbytes) {
2535 		(void) close(fd);
2536 		return (-1);
2537 	}
2538 
2539 	retval = pwrite_new(fd, &crc, sizeof (crc),
2540 		trailer_offset + 1, &format);
2541 	(void) close(fd);
2542 	if (retval != sizeof (crc)) {
2543 		return (-1);
2544 	}
2545 	*newpacket = packet;
2546 	return (0);
2547 }
2548 
2549 /*
2550  * Description	:
2551  *		sun_fru_append_packet() appends a packet to a segment.
2552  *
2553  * Arguments	:
2554  *		segment_hdl_t segment
2555  *		A handle for the segment to which the packet will be appended.
2556  *
2557  *   		packet_t *packet
2558  *     		On entry, the "tag" component of "packet" specifies the tag
2559  *     		value for the added packet; the "handle" component is ignored.
2560  *     		On return, the "handle" component is set to the handle of the
2561  *     		appended packet.
2562  *
2563  *   		const void *payload
2564  *     		A pointer to the caller's buffer containing the payload data for
2565  *     		the appended packet.
2566  *
2567  *   		size_t nbytes
2568  *     		The size of the caller buffer.
2569  *
2570  * Return	:
2571  *   		int
2572  *     		On success, 0 is returned; on error -1 is returned;
2573  */
2574 static int
sun_fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)2575 sun_fru_append_packet(segment_hdl_t segment, packet_t *packet,
2576 	const void *payload, size_t nbytes, segment_hdl_t *newsegment,
2577 	door_cred_t *cred)
2578 {
2579 	int		trailer_offset;
2580 	int		tag_size;
2581 	int		fd;
2582 	int		retval;
2583 	char		trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00};
2584 	uint32_t	crc;
2585 	hash_obj_t	*seg_hash;
2586 	hash_obj_t	*sec_hash;
2587 	hash_obj_t	*pkt_hash;
2588 	hash_obj_t	*cont_hash;
2589 	fru_tagtype_t	tagtype;
2590 	fru_segdesc_t	*desc;
2591 	format_t	format;
2592 
2593 	/* check the effective uid of the client */
2594 	if (cred->dc_euid != 0) {
2595 		errno = EPERM;
2596 		return (-1);	/* not a root */
2597 	}
2598 
2599 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2600 	if (seg_hash == NULL) {
2601 		return (-1);
2602 	}
2603 
2604 	/* check for write perm. */
2605 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2606 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2607 		errno = EPERM;
2608 		return (-1); /* write not allowed */
2609 	}
2610 
2611 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2612 		SECTION_TYPE);
2613 	if (sec_hash == NULL) {
2614 		return (-1);
2615 	}
2616 
2617 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2618 		errno = EPERM;
2619 		return (-1);		/* read-only section */
2620 	}
2621 
2622 	trailer_offset	= seg_hash->u.seg_obj->trailer_offset;
2623 
2624 	/*
2625 	 * if trailer offset is 0 than parse the segment data to get the trailer
2626 	 * offset to compute the remaining space left in the segment area for
2627 	 * new packet to be added.
2628 	 */
2629 	if (trailer_offset == 0) {
2630 		(void) sun_fru_get_num_packets(segment, cred);
2631 		trailer_offset  = seg_hash->u.seg_obj->trailer_offset;
2632 	}
2633 
2634 	tagtype	= get_tag_type((void *)&packet->tag);
2635 	if (tagtype == -1) {
2636 		return (-1);
2637 	}
2638 
2639 	tag_size	= get_tag_size(tagtype);
2640 	if (tag_size == -1) {
2641 		return (-1);
2642 	}
2643 
2644 	if (seg_hash->u.seg_obj->segment.length >
2645 		((trailer_offset - seg_hash->u.seg_obj->segment.offset) +
2646 			tag_size + nbytes +
2647 			sizeof (char) + sizeof (uint32_t))) {
2648 		/* create new packet hash */
2649 		pkt_hash = create_packet_hash_object();
2650 		if (pkt_hash == NULL) {
2651 			return (-1);
2652 		}
2653 
2654 		/* tag initialization */
2655 		(void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag,
2656 			tag_size);
2657 		pkt_hash->u.pkt_obj->tag_size	= tag_size;
2658 
2659 		/* payload inititalization */
2660 		pkt_hash->u.pkt_obj->payload	= malloc(nbytes);
2661 		if (pkt_hash->u.pkt_obj->payload == NULL) {
2662 			free(pkt_hash);
2663 			return (-1);
2664 		}
2665 
2666 		(void) memcpy(pkt_hash->u.pkt_obj->payload, payload, nbytes);
2667 		pkt_hash->u.pkt_obj->paylen	= nbytes;
2668 		pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size;
2669 
2670 		/* add to hash table */
2671 		add_hashobject_to_hashtable(pkt_hash, PACKET_TYPE);
2672 
2673 		add_to_pkt_object_list(seg_hash, pkt_hash);
2674 
2675 		cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2676 			CONTAINER_TYPE);
2677 		if (cont_hash == NULL) {
2678 			return (-1);
2679 		}
2680 		format = cont_hash->u.cont_obj->format;
2681 
2682 		fd = open_file();
2683 		if (fd < 0) {
2684 			return (-1);
2685 		}
2686 
2687 		/* update the trailer offset  */
2688 		trailer_offset += tag_size + nbytes;
2689 
2690 		/* calculate new checksum */
2691 		crc = get_checksum_crc(seg_hash, (trailer_offset -
2692 			seg_hash->u.seg_obj->segment.offset));
2693 
2694 		retval = pwrite_new(fd, &packet->tag, tag_size, trailer_offset
2695 			- (tag_size + nbytes), &format);
2696 		if (retval != tag_size) {
2697 			(void) close(fd);
2698 			return (-1);
2699 		}
2700 
2701 		retval = pwrite_new(fd, payload, nbytes,
2702 			trailer_offset - nbytes, &format);
2703 		if (retval != nbytes) {
2704 			(void) close(fd);
2705 			return (-1);
2706 		}
2707 
2708 		retval = pwrite_new(fd, trailer, sizeof (trailer),
2709 			trailer_offset, &format);
2710 		if (retval != sizeof (trailer)) {
2711 			(void) close(fd);
2712 			return (-1);
2713 		}
2714 
2715 		retval = pwrite_new(fd, &crc, sizeof (crc),
2716 			trailer_offset + 1, &format);
2717 		(void) close(fd);
2718 		if (retval != sizeof (crc)) {
2719 			return (-1);
2720 		}
2721 
2722 		seg_hash->u.seg_obj->trailer_offset = trailer_offset;
2723 		seg_hash->u.seg_obj->num_of_packets += 1;
2724 
2725 		*newsegment	= segment; 	/* return new segment handle */
2726 		return (0);
2727 	} else {
2728 		errno = EAGAIN;
2729 	}
2730 
2731 	return (-1);
2732 }
2733 
2734 static void
adjust_packets(int fd,hash_obj_t * free_obj,hash_obj_t * object_list)2735 adjust_packets(int	fd, hash_obj_t	*free_obj, hash_obj_t	*object_list)
2736 {
2737 	int		retval;
2738 	uint32_t	new_offset;
2739 	hash_obj_t	*hash_ptr;
2740 	format_t	format;
2741 	hash_obj_t	*hash_obj;
2742 
2743 	hash_obj = lookup_handle_object(free_obj->obj_hdl, PACKET_TYPE);
2744 	if (hash_obj == NULL) {
2745 		return;
2746 	}
2747 	hash_obj = get_container_hash_object(PACKET_TYPE,
2748 		hash_obj->u.pkt_obj->segment_hdl);
2749 	if (hash_obj == NULL) {
2750 		return;
2751 	}
2752 	format = hash_obj->u.cont_obj->format;
2753 
2754 	new_offset = free_obj->u.pkt_obj->payload_offset
2755 		- free_obj->u.pkt_obj->tag_size;
2756 	for (hash_ptr = object_list; hash_ptr != NULL;
2757 		hash_ptr = hash_ptr->u.pkt_obj->next) {
2758 		retval = pwrite_new(fd, &hash_ptr->u.pkt_obj->tag,
2759 			hash_ptr->u.pkt_obj->tag_size, new_offset, &format);
2760 		if (retval != hash_ptr->u.pkt_obj->tag_size) {
2761 			return;
2762 		}
2763 		new_offset += hash_ptr->u.pkt_obj->tag_size;
2764 		hash_ptr->u.pkt_obj->payload_offset = new_offset;
2765 		retval = pwrite_new(fd, hash_ptr->u.pkt_obj->payload,
2766 			hash_ptr->u.pkt_obj->paylen, new_offset, &format);
2767 		if (retval != hash_ptr->u.pkt_obj->paylen) {
2768 			return;
2769 		}
2770 		new_offset += hash_ptr->u.pkt_obj->paylen;
2771 	}
2772 }
2773 
2774 static void
free_packet_object(handle_t handle,hash_obj_t * seg_hash)2775 free_packet_object(handle_t	handle, hash_obj_t *seg_hash)
2776 {
2777 	hash_obj_t	*pkt_hash;
2778 	hash_obj_t	*next_hash;
2779 
2780 	pkt_hash	= seg_hash->u.seg_obj->pkt_obj_list;
2781 	if (pkt_hash == NULL) {
2782 		return;
2783 	}
2784 
2785 	if (pkt_hash->obj_hdl == handle) {
2786 		seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next;
2787 	} else {
2788 		while (pkt_hash->obj_hdl != handle) {
2789 			next_hash = pkt_hash;
2790 			pkt_hash = pkt_hash->u.pkt_obj->next;
2791 			if (pkt_hash == NULL) {
2792 				return;
2793 			}
2794 		}
2795 		next_hash->u.pkt_obj->next = pkt_hash->u.pkt_obj->next;
2796 	}
2797 
2798 	if (pkt_hash->prev == NULL) {
2799 		hash_table[(pkt_hash->obj_hdl % TABLE_SIZE)] = pkt_hash->next;
2800 		if (pkt_hash->next != NULL) {
2801 			pkt_hash->next->prev = NULL;
2802 		}
2803 	} else {
2804 		pkt_hash->prev->next = pkt_hash->next;
2805 		if (pkt_hash->next != NULL) {
2806 			pkt_hash->next->prev = pkt_hash->prev;
2807 		}
2808 	}
2809 
2810 	free(pkt_hash->u.pkt_obj->payload);
2811 	free(pkt_hash->u.pkt_obj);
2812 	free(pkt_hash);
2813 }
2814 
2815 /*
2816  * Description	:
2817  *   		sun_fru_delete_packet() deletes a packet from a segment.
2818  *
2819  * Arguments	: packet_hdl_t : packet number to be deleted.
2820  *		segment_hdl_t : new segment handler.
2821  *
2822  * Return	:
2823  *   		int
2824  *     		On success, 0 is returned; on error, -1.
2825  *
2826  * NOTES
2827  * 		Packets are adjacent; thus, deleting a packet requires moving
2828  *   		succeeding packets to compact the resulting hole.
2829  */
2830 static int
sun_fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)2831 sun_fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
2832 	door_cred_t *cred)
2833 {
2834 	int		retval;
2835 	int		fd;
2836 	char		trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00};
2837 	uint32_t	crc;
2838 	hash_obj_t	*tmp_obj;
2839 	hash_obj_t	*pkt_hash;
2840 	hash_obj_t	*sec_hash;
2841 	hash_obj_t	*cont_hash;
2842 	hash_obj_t	*prev_obj;
2843 	hash_obj_t	*seg_hash;
2844 	fru_segdesc_t	*desc;
2845 	format_t	format;
2846 
2847 	/* check the effective uid of the client */
2848 	if (cred->dc_euid != 0) {
2849 		errno = EPERM;
2850 		return (-1);	/* not a root */
2851 	}
2852 
2853 	/* packet hash object */
2854 	pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2855 	if (pkt_hash == NULL) {
2856 		return (-1);
2857 	}
2858 
2859 	/* segment hash object */
2860 	seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2861 		SEGMENT_TYPE);
2862 	if (seg_hash == NULL) {
2863 		return (-1);
2864 	}
2865 
2866 	/* check for write perm. */
2867 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2868 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2869 		errno = EPERM;
2870 		return (-1); /* write not allowed */
2871 	}
2872 
2873 	/* section hash object */
2874 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2875 		SECTION_TYPE);
2876 	if (sec_hash == NULL) {
2877 		return (-1);
2878 	}
2879 
2880 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2881 		errno = EPERM;
2882 		return (-1); 		/* read-only section */
2883 	}
2884 
2885 	prev_obj	= seg_hash->u.seg_obj->pkt_obj_list;
2886 	if (prev_obj == NULL) {
2887 		return (-1);
2888 	}
2889 
2890 	/* container hash object */
2891 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2892 		CONTAINER_TYPE);
2893 	if (cont_hash == NULL) {
2894 		return (-1);
2895 	}
2896 
2897 	format = cont_hash->u.cont_obj->format;
2898 
2899 	fd = open_file();
2900 	if (fd < 0) {
2901 		return (-1);
2902 	}
2903 
2904 	if (prev_obj->obj_hdl == packet) { /* first object to be deleted */
2905 		adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next);
2906 		seg_hash->u.seg_obj->trailer_offset -=
2907 			(prev_obj->u.pkt_obj->tag_size
2908 			+ prev_obj->u.pkt_obj->paylen);
2909 		free_packet_object(packet, seg_hash);
2910 	} else {
2911 		for (tmp_obj = prev_obj;
2912 			tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) {
2913 			/* found the object */
2914 			if (tmp_obj->obj_hdl == packet) {
2915 				adjust_packets(fd, tmp_obj,
2916 					tmp_obj->u.pkt_obj->next);
2917 				seg_hash->u.seg_obj->trailer_offset -=
2918 					(tmp_obj->u.pkt_obj->tag_size
2919 					+ tmp_obj->u.pkt_obj->paylen);
2920 				free_packet_object(packet, seg_hash);
2921 			}
2922 		}
2923 	}
2924 
2925 	seg_hash->u.seg_obj->num_of_packets -= 1;
2926 
2927 	/* calculate checksum */
2928 	crc = get_checksum_crc(seg_hash, (seg_hash->u.seg_obj->trailer_offset
2929 		- seg_hash->u.seg_obj->segment.offset));
2930 	/* write trailer at new offset */
2931 	retval = pwrite_new(fd, &trailer, sizeof (trailer),
2932 		seg_hash->u.seg_obj->trailer_offset, &format);
2933 	if (retval != sizeof (trailer)) {
2934 		(void) close(fd);
2935 		return (-1);
2936 	}
2937 
2938 	/* write the checksum value */
2939 	retval = pwrite_new(fd, &crc, sizeof (crc),
2940 		seg_hash->u.seg_obj->trailer_offset + 1, &format);
2941 	(void) close(fd);
2942 	if (retval != sizeof (crc)) {
2943 		return (-1);
2944 	}
2945 
2946 	*newsegment = seg_hash->obj_hdl; /* return new segment handle */
2947 	return (0);
2948 }
2949 
2950 /*
2951  * Description :
2952  *		sun_fru_close_container() removes the association between a
2953  *		container and its handle. this routines free's up all the
2954  *		hash object contained under container.
2955  *
2956  * Arguments   :
2957  *		container_hdl_t holds the file descriptor of the fru.
2958  *
2959  * Return      :
2960  *		int
2961  *		return 0.
2962  *
2963  */
2964 /* ARGSUSED */
2965 static int
sun_fru_close_container(container_hdl_t container)2966 sun_fru_close_container(container_hdl_t container)
2967 {
2968 	hash_obj_t	*hash_obj;
2969 	hash_obj_t	*prev_hash;
2970 	hash_obj_t	*sec_hash_obj;
2971 	handle_t	obj_hdl;
2972 
2973 	/* lookup for container hash object */
2974 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
2975 	if (hash_obj == NULL) {
2976 		return (0);
2977 	}
2978 
2979 	/* points to section object list */
2980 	sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
2981 
2982 	/* traverse section object list */
2983 	while (sec_hash_obj != NULL) {
2984 
2985 		/* traverse segment hash object in the section */
2986 		while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
2987 			/* object handle of the segment hash object */
2988 			obj_hdl	=
2989 				sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
2990 			free_segment_hash(obj_hdl, sec_hash_obj);
2991 		}
2992 
2993 		/* going to free section hash object, relink the hash object */
2994 		if (sec_hash_obj->prev == NULL) {
2995 			hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)]
2996 							= sec_hash_obj->next;
2997 			if (sec_hash_obj->next != NULL) {
2998 				sec_hash_obj->next->prev = NULL;
2999 			}
3000 		} else {
3001 			sec_hash_obj->prev->next = sec_hash_obj->next;
3002 			if (sec_hash_obj->next != NULL) {
3003 				sec_hash_obj->next->prev = sec_hash_obj->prev;
3004 			}
3005 		}
3006 
3007 		free(sec_hash_obj->u.sec_obj); /* free section hash object */
3008 
3009 		prev_hash = sec_hash_obj;
3010 
3011 		sec_hash_obj = sec_hash_obj->u.sec_obj->next;
3012 
3013 		free(prev_hash); /* free section hash */
3014 	}
3015 
3016 	/* free container hash object */
3017 	if (hash_obj->prev == NULL) {
3018 		hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
3019 			hash_obj->next;
3020 		if (hash_obj->next != NULL) {
3021 			hash_obj->next->prev = NULL;
3022 		}
3023 	} else {
3024 		hash_obj->prev->next = hash_obj->next;
3025 		if (hash_obj->next != NULL) {
3026 			hash_obj->next->prev = hash_obj->prev;
3027 		}
3028 	}
3029 
3030 	free(hash_obj->u.cont_obj);
3031 	free(hash_obj);
3032 	return (0);
3033 }
3034 
3035 /*
3036  * FRU ACCESS API
3037  */
3038 
3039 /*
3040  * Description :
3041  *		fru_is_data_available checks if the fruid information
3042  *		is available or not on a give fru
3043  *
3044  * Arguments   :
3045  *		picl_nodehdl_t  hold picl node handle of the fru.
3046  *
3047  * Return      :
3048  *		int
3049  *		return 0 - if fruid is not present.
3050  *		return 1 - if fruid is present.
3051  */
3052 int
fru_is_data_available(picl_nodehdl_t fruh)3053 fru_is_data_available(picl_nodehdl_t fruh)
3054 {
3055 	int retval, ret;
3056 	uint8_t slot_no;
3057 	picl_nodehdl_t parenth;
3058 	format_t fru_format;
3059 	hash_obj_t *cont_hash_obj;
3060 
3061 	if (is_valid_chassis == -1) {
3062 		if (fruaccess_platmod_check_chassis() == 0) {
3063 			is_valid_chassis = 1;
3064 		} else {
3065 			is_valid_chassis = 0;
3066 		}
3067 	}
3068 
3069 	if (!is_valid_chassis) {
3070 		return (0);
3071 	}
3072 
3073 	retval = ptree_get_propval_by_name(fruh, PICL_PROP_PARENT,
3074 		&parenth, sizeof (picl_nodehdl_t));
3075 	if (retval != PICL_SUCCESS) {
3076 		return (0);
3077 	}
3078 
3079 	if (fruaccess_platmod_check_fru(parenth) != 0) {
3080 		return (0);
3081 	}
3082 
3083 	retval = ptree_get_propval_by_name(parenth, PICL_PROP_GEO_ADDR,
3084 		&slot_no, sizeof (uint8_t));
3085 	if (retval != PICL_SUCCESS) {
3086 		return (0);
3087 	}
3088 
3089 	if (fruaccess_platmod_init_format(slot_no, &fru_format) !=
3090 		PICL_SUCCESS) {
3091 		return (0);
3092 	}
3093 
3094 	ret = is_fru_data_available(precedence, slot_no, &fru_format);
3095 	if (ret && (fru_format.format != NO_FRUDATA)) {
3096 		goto create;
3097 	} else {
3098 		return (0);
3099 	}
3100 create:
3101 
3102 	cont_hash_obj = create_container_hash_object();
3103 	if (cont_hash_obj == NULL) {
3104 		return (0);
3105 	}
3106 
3107 	cont_hash_obj->obj_hdl = fruh;
3108 	cont_hash_obj->u.cont_obj->format = fru_format;
3109 
3110 	/* if both formats are present follow the precedence */
3111 	if (fru_format.format == 0x3) {
3112 		if (precedence == IPMI_FORMAT) {
3113 			cont_hash_obj->u.cont_obj->format.format = IPMI_FORMAT;
3114 		} else {
3115 			cont_hash_obj->u.cont_obj->format.format = SUN_FORMAT;
3116 		}
3117 	}
3118 	add_hashobject_to_hashtable(cont_hash_obj, CONTAINER_TYPE);
3119 	return (1);
3120 }
3121 
3122 /*
3123  * FRU ACCESS API
3124  */
3125 
3126 /*
3127  * All the routines check the fruid format and redirects the call to
3128  * to appropriate routines depending on fruid format.
3129  * All SUN format routines start with sun_ prefix.
3130  * All IPMI format routines start with ipmi_ prefix.
3131  */
3132 container_hdl_t
fru_open_container(picl_nodehdl_t fru)3133 fru_open_container(picl_nodehdl_t fru)
3134 {
3135 	hash_obj_t *hash_obj;
3136 	format_t fru_format;
3137 
3138 	hash_obj = lookup_handle_object((handle_t)fru, CONTAINER_TYPE);
3139 	if (hash_obj == NULL) {
3140 		return (-1);
3141 	}
3142 	fru_format = hash_obj->u.cont_obj->format;
3143 	return (fruaccess_func[fru_format.format - 1].open_container(fru));
3144 }
3145 
3146 int
fru_close_container(container_hdl_t container)3147 fru_close_container(container_hdl_t container)
3148 {
3149 	int ret;
3150 	format_t fru_format;
3151 	hash_obj_t *hash_obj;
3152 
3153 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
3154 	if (hash_obj == NULL) {
3155 		return (-1);
3156 	}
3157 
3158 	fru_format = hash_obj->u.cont_obj->format;
3159 	ret = fruaccess_func[fru_format.format - 1].close_container(container);
3160 	return (ret);
3161 }
3162 
3163 int
fru_get_num_sections(container_hdl_t container,door_cred_t * cred)3164 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
3165 {
3166 	int ret;
3167 	format_t fru_format;
3168 	hash_obj_t *hash_obj;
3169 
3170 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
3171 	if (hash_obj == NULL) {
3172 		return (-1);
3173 	}
3174 	fru_format = hash_obj->u.cont_obj->format;
3175 	ret = fruaccess_func[fru_format.format - 1].get_num_sections(container,
3176 		cred);
3177 	return (ret);
3178 }
3179 
3180 int
fru_get_sections(container_hdl_t container,section_t * section,int max_sections,door_cred_t * cred)3181 fru_get_sections(container_hdl_t container, section_t *section,
3182 	int max_sections, door_cred_t *cred)
3183 {
3184 	int ret;
3185 	format_t fru_format;
3186 	hash_obj_t *hash_obj;
3187 
3188 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
3189 	if (hash_obj == NULL) {
3190 		return (-1);
3191 	}
3192 	fru_format = hash_obj->u.cont_obj->format;
3193 
3194 	ret = fruaccess_func[fru_format.format - 1].get_sections(container,
3195 		section, max_sections, cred);
3196 	return (ret);
3197 }
3198 
3199 int
fru_get_num_segments(section_hdl_t section,door_cred_t * rarg)3200 fru_get_num_segments(section_hdl_t section, door_cred_t *rarg)
3201 {
3202 	int ret;
3203 	format_t fru_format;
3204 	hash_obj_t *hash_obj;
3205 
3206 	hash_obj = get_container_hash_object(SEGMENT_TYPE, section);
3207 	if (hash_obj == NULL) {
3208 		return (-1);
3209 	}
3210 	fru_format = hash_obj->u.cont_obj->format;
3211 
3212 	ret = fruaccess_func[fru_format.format - 1].get_num_segments(section,
3213 		rarg);
3214 	return (ret);
3215 }
3216 
3217 int
fru_get_segments(section_hdl_t section,segment_t * segment,int max_segments,door_cred_t * rarg)3218 fru_get_segments(section_hdl_t section, segment_t *segment,
3219 	int max_segments, door_cred_t *rarg)
3220 {
3221 	int ret;
3222 	format_t fru_format;
3223 	hash_obj_t *hash_obj;
3224 
3225 	hash_obj = get_container_hash_object(SEGMENT_TYPE, section);
3226 	if (hash_obj == NULL) {
3227 		return (-1);
3228 	}
3229 	fru_format = hash_obj->u.cont_obj->format;
3230 	ret = fruaccess_func[fru_format.format - 1].get_segments(section,
3231 		segment, max_segments, rarg);
3232 	return (ret);
3233 }
3234 
3235 int
fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)3236 fru_add_segment(section_hdl_t section, segment_t *segment,
3237 	section_hdl_t *newsection, door_cred_t *cred)
3238 {
3239 	int ret;
3240 	format_t fru_format;
3241 	hash_obj_t *hash_obj;
3242 
3243 	hash_obj = get_container_hash_object(SEGMENT_TYPE, section);
3244 	if (hash_obj == NULL) {
3245 		return (-1);
3246 	}
3247 	fru_format = hash_obj->u.cont_obj->format;
3248 
3249 	ret = fruaccess_func[fru_format.format - 1].add_segment(section,
3250 		segment, newsection, cred);
3251 	return (ret);
3252 }
3253 
3254 int
fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)3255 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
3256 	door_cred_t *cred)
3257 {
3258 	int ret;
3259 	format_t fru_format;
3260 	hash_obj_t *hash_obj;
3261 
3262 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3263 	if (hash_obj == NULL) {
3264 		return (-1);
3265 	}
3266 	fru_format = hash_obj->u.cont_obj->format;
3267 	ret = fruaccess_func[fru_format.format - 1].delete_segment(segment,
3268 		newsection, cred);
3269 	return (ret);
3270 }
3271 
3272 ssize_t
fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)3273 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
3274 	door_cred_t *cred)
3275 {
3276 	ssize_t ret;
3277 	format_t fru_format;
3278 	hash_obj_t *hash_obj;
3279 
3280 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3281 	if (hash_obj == NULL) {
3282 		return (-1);
3283 	}
3284 	fru_format = hash_obj->u.cont_obj->format;
3285 	ret = fruaccess_func[fru_format.format - 1].read_segment(segment,
3286 		buffer, nbytes, cred);
3287 	return (ret);
3288 }
3289 
3290 int
fru_write_segment(segment_hdl_t segment,const void * data,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)3291 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes,
3292 	segment_hdl_t *newsegment, door_cred_t *cred)
3293 {
3294 	int ret;
3295 	format_t fru_format;
3296 	hash_obj_t *hash_obj;
3297 
3298 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3299 	if (hash_obj == NULL) {
3300 		return (-1);
3301 	}
3302 	fru_format = hash_obj->u.cont_obj->format;
3303 
3304 	ret = fruaccess_func[fru_format.format - 1].write_segment(segment,
3305 		data, nbytes, newsegment, cred);
3306 	return (ret);
3307 }
3308 
3309 int
fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)3310 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
3311 {
3312 	int ret;
3313 	format_t fru_format;
3314 	hash_obj_t *hash_obj;
3315 
3316 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3317 	if (hash_obj == NULL) {
3318 		return (-1);
3319 	}
3320 	fru_format = hash_obj->u.cont_obj->format;
3321 
3322 	ret = fruaccess_func[fru_format.format - 1].get_num_packets(segment,
3323 		cred);
3324 	return (ret);
3325 }
3326 
3327 int
fru_get_packets(segment_hdl_t segment,packet_t * packet,int max_packets,door_cred_t * cred)3328 fru_get_packets(segment_hdl_t segment, packet_t *packet,
3329 	int max_packets, door_cred_t *cred)
3330 {
3331 	int ret;
3332 	format_t fru_format;
3333 	hash_obj_t *hash_obj;
3334 
3335 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3336 	if (hash_obj == NULL) {
3337 		return (-1);
3338 	}
3339 	fru_format = hash_obj->u.cont_obj->format;
3340 
3341 	ret = fruaccess_func[fru_format.format - 1].get_packets(segment,
3342 		packet, max_packets, cred);
3343 	return (ret);
3344 }
3345 
3346 ssize_t
fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)3347 fru_get_payload(packet_hdl_t packet, void *buffer,
3348 	size_t nbytes, door_cred_t *cred)
3349 {
3350 	ssize_t ret;
3351 	format_t fru_format;
3352 	hash_obj_t *hash_obj;
3353 
3354 	hash_obj = lookup_handle_object(packet, PACKET_TYPE);
3355 	if (hash_obj == NULL) {
3356 		return (-1);
3357 	}
3358 
3359 	hash_obj = get_container_hash_object(PACKET_TYPE,
3360 		hash_obj->u.pkt_obj->segment_hdl);
3361 	if (hash_obj == NULL) {
3362 		return (-1);
3363 	}
3364 	fru_format = hash_obj->u.cont_obj->format;
3365 
3366 	ret = fruaccess_func[fru_format.format - 1].get_payload(packet, buffer,
3367 		nbytes, cred);
3368 	return (ret);
3369 }
3370 
3371 int
fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)3372 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
3373 	packet_hdl_t *newpacket, door_cred_t *cred)
3374 {
3375 	int ret;
3376 	format_t fru_format;
3377 	hash_obj_t *hash_obj;
3378 
3379 	hash_obj = lookup_handle_object(packet, PACKET_TYPE);
3380 	if (hash_obj == NULL) {
3381 		return (-1);
3382 	}
3383 
3384 	hash_obj = get_container_hash_object(PACKET_TYPE,
3385 		hash_obj->u.pkt_obj->segment_hdl);
3386 	if (hash_obj == NULL) {
3387 		return (-1);
3388 	}
3389 	fru_format = hash_obj->u.cont_obj->format;
3390 	ret = fruaccess_func[fru_format.format - 1].update_payload(packet, data,
3391 		nbytes, newpacket, cred);
3392 	return (ret);
3393 }
3394 
3395 int
fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)3396 fru_append_packet(segment_hdl_t segment, packet_t *packet,
3397 	const void *payload, size_t nbytes, segment_hdl_t *newsegment,
3398 	door_cred_t *cred)
3399 {
3400 	int ret;
3401 	format_t fru_format;
3402 	hash_obj_t *hash_obj;
3403 
3404 	hash_obj = get_container_hash_object(PACKET_TYPE, segment);
3405 	if (hash_obj == NULL) {
3406 		return (-1);
3407 	}
3408 	fru_format = hash_obj->u.cont_obj->format;
3409 
3410 	ret = fruaccess_func[fru_format.format - 1].append_packet(segment,
3411 		packet, payload, nbytes, newsegment, cred);
3412 	return (ret);
3413 }
3414 
3415 int
fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)3416 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
3417 	door_cred_t *cred)
3418 {
3419 	int ret;
3420 	format_t fru_format;
3421 	hash_obj_t *hash_obj;
3422 
3423 	hash_obj = lookup_handle_object(packet, PACKET_TYPE);
3424 	if (hash_obj == NULL) {
3425 		return (-1);
3426 	}
3427 
3428 	hash_obj = get_container_hash_object(PACKET_TYPE,
3429 		hash_obj->u.pkt_obj->segment_hdl);
3430 	if (hash_obj == NULL) {
3431 		return (-1);
3432 	}
3433 	fru_format = hash_obj->u.cont_obj->format;
3434 
3435 	ret = fruaccess_func[fru_format.format - 1].delete_packet(packet,
3436 		newsegment, cred);
3437 	return (ret);
3438 }
3439