xref: /titanic_50/usr/src/uts/sun4u/lw8/io/sgfru.c (revision f38cb554a534c6df738be3f4d23327e69888e634)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/file.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/modctl.h>
34 #include <sys/sunndi.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/obpdefs.h>
37 #include <sys/cmn_err.h>
38 #include <sys/errno.h>
39 #include <sys/debug.h>
40 #include <sys/sysmacros.h>
41 #include <sys/autoconf.h>
42 #include <sys/stat.h>
43 #include <sys/kmem.h>
44 #include <sys/sgsbbc_mailbox.h>
45 #include <sys/sgfrutree.h>
46 #include <sys/sgfru_priv.h>
47 #include <sys/sgfru_mbox.h>
48 
49 /*
50  * This driver implements the ioctls for the serengeti frutree picl plugin
51  * and the serengeti fruaccess library. These are all private,
52  * platform-dependent interfaces.
53  */
54 
55 /* Global Variables */
56 
57 #ifdef DEBUG
58 uint_t sgfru_debug = 0;
59 #endif /* DEBUG */
60 
61 /* Opaque state structure pointer */
62 static void *sgfru_statep;	/* sgfru soft state hook */
63 
64 /*
65  * the maximum amount of time this driver is prepared to wait for the mailbox
66  * to reply before it decides to timeout.
67  */
68 int sgfru_mbox_wait = SGFRU_DEFAULT_MAX_MBOX_WAIT_TIME;
69 
70 /* Module Variables */
71 
72 /*
73  * Driver entry points. These are located in sgfru.c so as to
74  * not cause a warning for the sgfru adb macro.
75  */
76 static struct cb_ops sgfru_cb_ops = {
77 	sgfru_open,		/* open */
78 	sgfru_close,		/* close */
79 	nulldev,		/* strategy */
80 	nulldev,		/* print */
81 	nulldev,		/* dump */
82 	nulldev,		/* read */
83 	nulldev,		/* write */
84 	sgfru_ioctl,		/* ioctl */
85 	nulldev,		/* devmap */
86 	nulldev,		/* mmap */
87 	nulldev,		/* segmap */
88 	nochpoll,		/* poll */
89 	ddi_prop_op,		/* cb_prop_op */
90 	NULL,			/* streamtab */
91 	D_NEW | D_MP		/* Driver compatibility flag */
92 };
93 
94 static struct dev_ops sgfru_ops = {
95 	DEVO_REV,		/* devo_rev, */
96 	0,			/* refcnt  */
97 	ddi_getinfo_1to1,	/* info */
98 	nulldev,		/* identify */
99 	nulldev,		/* probe */
100 	sgfru_attach,		/* attach */
101 	sgfru_detach,		/* detach */
102 	nodev,			/* reset */
103 	&sgfru_cb_ops,		/* driver operations */
104 	(struct bus_ops *)0,	/* bus operations */
105 	nulldev,		/* power */
106 	ddi_quiesce_not_needed,		/* quiesce */
107 };
108 
109 /*
110  * Loadable module support. This is located in sgfru.c so as to
111  * pick up the 1.8 version of sgfru.c.
112  */
113 extern struct mod_ops mod_driverops;
114 
115 static struct modldrv modldrv = {
116 	&mod_driverops,	/* Type of module.  This one is a pseudo driver */
117 	"FRU Driver",
118 	&sgfru_ops,	/* driver ops */
119 };
120 
121 static struct modlinkage modlinkage = {
122 	MODREV_1,
123 	(void *)&modldrv,
124 	NULL
125 };
126 
127 int
128 _init(void)
129 {
130 	int error = 0;
131 
132 	/* Allocate the soft state info and add the module. */
133 	if ((error = ddi_soft_state_init(&sgfru_statep,
134 	    sizeof (sgfru_soft_state_t), 1)) == 0 &&
135 	    (error = mod_install(&modlinkage)) != 0) {
136 		ddi_soft_state_fini(&sgfru_statep);
137 	}
138 	return (error);
139 }
140 
141 int
142 _fini(void)
143 {
144 	int error = 0;
145 
146 	/* Remove the module and free the soft state info. */
147 	if ((error = mod_remove(&modlinkage)) == 0) {
148 		ddi_soft_state_fini(&sgfru_statep);
149 	}
150 	return (error);
151 }
152 
153 int
154 _info(struct modinfo *modinfop)
155 {
156 	return (mod_info(&modlinkage, modinfop));
157 }
158 
159 static int
160 sgfru_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
161 {
162 	sgfru_soft_state_t *softsp;
163 	int instance;
164 	int error;
165 	static fn_t f = "sgfru_attach";
166 
167 	switch (cmd) {
168 	case DDI_ATTACH:
169 		instance = ddi_get_instance(dip);
170 
171 		error = ddi_soft_state_zalloc(sgfru_statep, instance);
172 		if (error != DDI_SUCCESS) {
173 			cmn_err(CE_WARN, "sgfru:%s: cannot allocate fru state "
174 			    "for inst %d.", f, instance);
175 			return (DDI_FAILURE);
176 		}
177 		softsp = ddi_get_soft_state(sgfru_statep, instance);
178 		if (softsp == NULL) {
179 			ddi_soft_state_free(sgfru_statep, instance);
180 			cmn_err(CE_WARN, "sgfru:%s: could not get state "
181 			    "structure for inst %d.", f, instance);
182 			return (DDI_FAILURE);
183 		}
184 		softsp->fru_dip = dip;
185 		softsp->fru_pdip = ddi_get_parent(softsp->fru_dip);
186 		softsp->instance = instance;
187 
188 		error = ddi_create_minor_node(dip, SGFRU_DRV_NAME, S_IFCHR,
189 		    instance, DDI_PSEUDO, NULL);
190 		if (error == DDI_FAILURE) {
191 			ddi_soft_state_free(sgfru_statep, instance);
192 			return (DDI_FAILURE);
193 		}
194 
195 		ddi_report_dev(dip);
196 
197 		return (DDI_SUCCESS);
198 
199 	case DDI_RESUME:
200 		return (DDI_SUCCESS);
201 
202 	default:
203 		return (DDI_FAILURE);
204 	}
205 }
206 
207 static int
208 sgfru_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
209 {
210 	int instance;
211 	sgfru_soft_state_t *softsp;
212 	static fn_t f = "sgfru_detach";
213 
214 	instance = ddi_get_instance(dip);
215 
216 	softsp = ddi_get_soft_state(sgfru_statep, instance);
217 	if (softsp == NULL) {
218 		cmn_err(CE_WARN, "sgfru:%s: could not get state "
219 		    "structure for inst %d.", f, instance);
220 		return (DDI_FAILURE);
221 	}
222 
223 	switch (cmd) {
224 	case DDI_DETACH:
225 		ddi_soft_state_free(sgfru_statep, instance);
226 		ddi_remove_minor_node(dip, NULL);
227 		return (DDI_SUCCESS);
228 
229 	case DDI_SUSPEND:
230 		return (DDI_SUCCESS);
231 
232 	default:
233 		return (DDI_FAILURE);
234 	}
235 }
236 
237 /*ARGSUSED*/
238 static int
239 sgfru_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
240 {
241 	int error = 0;
242 	int instance = getminor(*dev_p);
243 	sgfru_soft_state_t *softsp;
244 	static fn_t f = "sgfru_open";
245 
246 	if ((error = drv_priv(cred_p)) != 0) {
247 		cmn_err(CE_WARN, "sgfru:%s: inst %d drv_priv failed",
248 		    f, instance);
249 		return (error);
250 	}
251 	softsp = (sgfru_soft_state_t *)ddi_get_soft_state(sgfru_statep,
252 	    instance);
253 	if (softsp == (sgfru_soft_state_t *)NULL) {
254 		cmn_err(CE_WARN, "sgfru:%s: inst %d ddi_get_soft_state failed",
255 		    f, instance);
256 		return (ENXIO);
257 	}
258 	return (error);
259 }
260 
261 /*ARGSUSED*/
262 static int
263 sgfru_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
264 {
265 	int instance = getminor(dev);
266 	sgfru_soft_state_t *softsp = (sgfru_soft_state_t *)
267 	    ddi_get_soft_state(sgfru_statep, instance);
268 
269 	if (softsp == (sgfru_soft_state_t *)NULL)
270 		return (ENXIO);
271 	return (DDI_SUCCESS);
272 }
273 
274 /*
275  * This function disperses the ioctls from the serengeti libpiclfruhier plugin
276  * and the serengeti libpiclfruaccess library to the appropriate sub-functions.
277  */
278 /*ARGSUSED*/
279 static int
280 sgfru_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
281     int *rval_p)
282 {
283 	sgfru_soft_state_t *softsp;
284 	int instance = getminor(dev);
285 	sgfru_init_arg_t init_arg;
286 	int32_t ret = 0;
287 	static fn_t f = "sgfru_ioctl";
288 
289 
290 	softsp = ddi_get_soft_state(sgfru_statep, instance);
291 	if (softsp == NULL) {
292 		return (ENXIO);
293 	}
294 	PR_STATE("sgfru:%s: dev %lx cmd %d, instance %d\n",
295 	    f, dev, cmd, instance);
296 
297 	init_arg.dev = dev;
298 	init_arg.cmd = cmd;
299 	init_arg.mode = mode;
300 	init_arg.argp = arg;
301 
302 	switch (cmd) {
303 
304 	case SGFRU_GETSECTIONS:
305 		ret = sgfru_getsections(&init_arg);
306 		break;
307 
308 	case SGFRU_GETSEGMENTS:
309 		ret = sgfru_getsegments(&init_arg);
310 		break;
311 
312 	case SGFRU_ADDSEGMENT:
313 		ret = sgfru_addsegment(&init_arg);
314 		break;
315 
316 	case SGFRU_READRAWSEGMENT:
317 		ret = sgfru_readsegment(&init_arg);
318 		break;
319 
320 	case SGFRU_WRITERAWSEGMENT:
321 		ret = sgfru_writesegment(&init_arg);
322 		break;
323 
324 	case SGFRU_GETPACKETS:
325 		ret = sgfru_getpackets(&init_arg);
326 		break;
327 
328 	case SGFRU_APPENDPACKET:
329 		ret = sgfru_appendpacket(&init_arg);
330 		break;
331 
332 	case SGFRU_GETPAYLOAD:
333 		ret = sgfru_getpayload(&init_arg);
334 		break;
335 
336 	case SGFRU_UPDATEPAYLOAD:
337 		ret = sgfru_updatepayload(&init_arg);
338 		break;
339 
340 	case SGFRU_GETNUMSECTIONS:
341 	case SGFRU_GETNUMSEGMENTS:
342 	case SGFRU_GETNUMPACKETS:
343 		ret = sgfru_getnum(&init_arg);
344 		break;
345 
346 	case SGFRU_DELETESEGMENT:
347 	case SGFRU_DELETEPACKET:
348 		ret = sgfru_delete(&init_arg);
349 		break;
350 
351 	case SGFRU_GETCHILDLIST:
352 		ret = sgfru_getchildlist(&init_arg);
353 		break;
354 
355 	case SGFRU_GETCHILDHANDLES:
356 		ret = sgfru_getchildhandles(&init_arg);
357 		break;
358 
359 	case SGFRU_GETNODEINFO:
360 		ret = sgfru_getnodeinfo(&init_arg);
361 		break;
362 
363 	default:
364 		ret = EINVAL;
365 		break;
366 	}
367 
368 	return (ret);
369 }
370 
371 /*
372  * Used for private SGFRU_GETCHILDLIST ioctl.
373  */
374 static int
375 sgfru_getchildlist(const sgfru_init_arg_t *iargp)
376 {
377 	int32_t ret;
378 	caddr_t datap;
379 	size_t ssize, size;
380 	frup_info_t clist;
381 	fru_cnt_t max_cnt;
382 	node_t *clistp;
383 	static fn_t f = "sgfru_getchildlist";
384 
385 	/* copyin child_info_t aka frup_info_t */
386 	if (sgfru_copyin_frup(iargp, &clist) != 0) {
387 		return (EFAULT);
388 	}
389 
390 	/* check on kmem_alloc space requirements */
391 	max_cnt = clist.fru_cnt;
392 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
393 		return (EINVAL);
394 	}
395 
396 	/* allocate buffer for unpadded fru_info_t + node_t's */
397 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * NODE_SIZE));
398 	datap = kmem_zalloc(size, KM_SLEEP);
399 	PR_NODE("sgfru:%s: FRU_INFO_SIZE %lu NODE_SIZE %lu size %lu\n",
400 	    f, FRU_INFO_SIZE, NODE_SIZE, size);
401 	PR_NODE("sgfru:%s: handle %lx cnt %d buffer 0x%p\n", f,
402 	    clist.fru_hdl, clist.fru_cnt, clist.frus);
403 
404 	/* call mailbox */
405 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &clist.fru_info))
406 	    != 0) {
407 		kmem_free(datap, size);
408 		return (ret);
409 	}
410 
411 	/* allocate buffer for padded node_t's */
412 	ssize = (size_t)(max_cnt * sizeof (node_t));
413 	clistp = (node_t *)kmem_zalloc(ssize, KM_SLEEP);
414 
415 	/* translate unpadded to padded fru_info_t + node_t's */
416 	if ((ret = sgfru_node_pad(datap, max_cnt, &clist.fru_info, clistp))
417 	    != 0) {
418 		kmem_free(datap, size);
419 		kmem_free(clistp, ssize);
420 		return (ret);
421 	}
422 	/* free node_t buffer */
423 	kmem_free(datap, size);
424 
425 	/* copy out fru_info_t */
426 	if (sgfru_copyout_fru(iargp, &clist.fru_info) != 0) {
427 		kmem_free(clistp, ssize);
428 		return (EFAULT);
429 	}
430 	/* copyout node_t's */
431 	if (sgfru_copyout_nodes(iargp, &clist, clistp) != 0) {
432 		kmem_free(clistp, ssize);
433 		return (EFAULT);
434 	}
435 	/* free node_t buffer */
436 	kmem_free(clistp, ssize);
437 
438 	return (ret);
439 }
440 
441 /*
442  * Used for private SGFRU_GETCHILDHANDLES ioctl.
443  */
444 static int
445 sgfru_getchildhandles(const sgfru_init_arg_t *iargp)
446 {
447 	int32_t ret;
448 	size_t size;
449 	caddr_t datap, tdatap;
450 	frup_info_t hdls;
451 	fru_info_t hinfo;
452 	fru_cnt_t max_cnt;
453 	static fn_t f = "sgfru_getchildhandles";
454 
455 	/* copyin handles_t aka frup_info_t */
456 	if (sgfru_copyin_frup(iargp, &hdls) != 0) {
457 		return (EFAULT);
458 	}
459 	PR_HANDLE("sgfru:%s: handle %lx\n", f, hdls.fru_hdl);
460 
461 	/* check on kmem_alloc space requirements */
462 	max_cnt = hdls.fru_cnt;
463 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
464 		return (EINVAL);
465 	}
466 
467 	/* allocate buffer for child fru_hdl_t's */
468 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * FRU_HDL_SIZE));
469 	datap = kmem_zalloc(size, KM_SLEEP);
470 
471 	/* call mailbox */
472 	ret = sgfru_mbox(iargp->cmd, datap, size, &hdls.fru_info);
473 	if (ret != 0) {
474 		kmem_free(datap, size);
475 		return (ret);
476 	}
477 
478 	/* translate unpadded to fru_info_t */
479 	tdatap = sgfru_fru_pad(datap, &hinfo);
480 
481 	/* copyout actual fru_cnt */
482 	if (sgfru_copyout_fru(iargp, &hinfo) != 0) {
483 		kmem_free(datap, size);
484 		return (EFAULT);
485 	}
486 	PR_HANDLE("sgfru:%s: count %x\n", f, hinfo.cnt);
487 
488 	/* copyout fru_hdl_t's */
489 	if (sgfru_copyout_handles(iargp, &hdls, (fru_hdl_t *)tdatap) != 0) {
490 		kmem_free(datap, size);
491 		return (EFAULT);
492 	}
493 
494 	/* free datap buffer */
495 	kmem_free(datap, size);
496 
497 	return (ret);
498 }
499 
500 /*
501  * Used for private SGFRU_GETNODEINFO ioctl.
502  */
503 static int
504 sgfru_getnodeinfo(const sgfru_init_arg_t *iargp)
505 {
506 	int32_t ret;
507 	caddr_t datap;
508 	size_t size;
509 	frup_info_t nodeinfo;
510 	node_t node;
511 	static fn_t f = "sgfru_getnodeinfo";
512 
513 	/* copyin node_info_t aka frup_info_t */
514 	if (sgfru_copyin_frup(iargp, &nodeinfo) != 0) {
515 		return (EFAULT);
516 	}
517 
518 	/* allocate unpadded buffer for node_t */
519 	size = (size_t)(NODE_SIZE);
520 	datap = kmem_zalloc(size, KM_SLEEP);
521 
522 	PR_NODE("sgfru:%s: handle %lx size 0x%lx\n", f, nodeinfo.fru_hdl, size);
523 	/* call mailbox */
524 	ret = sgfru_mbox(iargp->cmd, datap, size, &nodeinfo.fru_info);
525 	if (ret != 0) {
526 		kmem_free(datap, size);
527 		return (ret);
528 	}
529 
530 	/* translate unpadded to padded node_t */
531 	if ((ret = sgfru_node_pad(datap, 0, NULL, &node))
532 	    != 0) {
533 		kmem_free(datap, size);
534 		return (ret);
535 	}
536 
537 	/* free node_t buffer */
538 	kmem_free(datap, size);
539 
540 	/* copyout node_t */
541 	if (sgfru_copyout_nodes(iargp, &nodeinfo, &node) != 0) {
542 		return (EFAULT);
543 	}
544 	PR_NODE("sgfru:%s: handle %lx nodename %s has_children %d class %d\n",
545 	    f, node.handle, node.nodename, node.has_children, node.class);
546 
547 	return (ret);
548 }
549 
550 /*
551  * Used for fru_get_sections().
552  */
553 static int
554 sgfru_getsections(const sgfru_init_arg_t *iargp)
555 {
556 	int32_t ret;
557 	caddr_t datap;
558 	size_t ssize, size;
559 	frup_info_t sects;
560 	fru_cnt_t max_cnt;
561 	section_t *sectp;
562 
563 	/* copyin sections_t aka frup_info_t */
564 	if (sgfru_copyin_frup(iargp, &sects) != 0) {
565 		return (EFAULT);
566 	}
567 	/* check on kmem_alloc space requirements */
568 	max_cnt = sects.fru_cnt;
569 	if ((max_cnt <= 0) || (max_cnt > MAX_SECTIONS)) {
570 		return (EINVAL);
571 	}
572 
573 	/* allocate buffer for unpadded fru_info_t + section_t's */
574 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SECTION_SIZE));
575 	datap = kmem_zalloc(size, KM_SLEEP);
576 
577 	/* call mailbox */
578 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &sects.fru_info))
579 	    != 0) {
580 		kmem_free(datap, size);
581 		return (ret);
582 	}
583 
584 	/* allocate buffer for padded section_t's */
585 	ssize = (size_t)(max_cnt * sizeof (section_t));
586 	sectp = (section_t *)kmem_zalloc(ssize, KM_SLEEP);
587 
588 	/* translate unpadded to padded fru_info_t + section_t's */
589 	if ((ret = sgfru_section_pad(datap, max_cnt, &sects.fru_info, sectp))
590 	    != 0) {
591 		kmem_free(datap, size);
592 		kmem_free(sectp, ssize);
593 		return (ret);
594 	}
595 	/* free section_t buffer */
596 	kmem_free(datap, size);
597 
598 	/* copy out fru_info_t */
599 	if (sgfru_copyout_fru(iargp, &sects.fru_info) != 0) {
600 		kmem_free(sectp, ssize);
601 		return (EFAULT);
602 	}
603 	/* copyout section_t's */
604 	if (sgfru_copyout_sections(iargp, &sects, sectp) != 0) {
605 		kmem_free(sectp, ssize);
606 		return (EFAULT);
607 	}
608 	/* free section_t buffer */
609 	kmem_free(sectp, ssize);
610 
611 	return (ret);
612 }
613 
614 /*
615  * Used for fru_get_segments().
616  */
617 static int
618 sgfru_getsegments(const sgfru_init_arg_t *iargp)
619 {
620 	int32_t ret;
621 	caddr_t datap;
622 	size_t ssize, size;
623 	frup_info_t segs;
624 	fru_cnt_t max_cnt;
625 	segment_t *segp;
626 
627 	/* copyin frup_info_t */
628 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
629 		return (EFAULT);
630 	}
631 	/* check on kmem_alloc space requirements */
632 	max_cnt = segs.fru_cnt;
633 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTS)) {
634 		return (EINVAL);
635 	}
636 
637 	/* allocate unpadded buffer for fru_info_t + segment_t's */
638 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SEGMENT_SIZE));
639 	datap = kmem_zalloc(size, KM_SLEEP);
640 
641 	/* call mailbox */
642 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
643 		kmem_free(datap, size);
644 		return (ret);
645 	}
646 
647 	/* allocate buffer for padded segment_t's */
648 	ssize = (size_t)(max_cnt * sizeof (segment_t));
649 	segp = (segment_t *)kmem_zalloc(ssize, KM_SLEEP);
650 
651 	/* translate unpadded to padded fru_info_t + segment_t's */
652 	if ((ret = sgfru_segment_pad(datap, max_cnt, &segs.fru_info, segp))
653 	    != 0) {
654 		kmem_free(datap, size);
655 		kmem_free(segp, ssize);
656 		return (ret);
657 	}
658 	/* free segment_t buffer */
659 	kmem_free(datap, size);
660 
661 	/* copy out fru_info_t */
662 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
663 		kmem_free(segp, ssize);
664 		return (EFAULT);
665 	}
666 	/* copyout segment_t's */
667 	if (sgfru_copyout_segments(iargp, &segs, segp) != 0) {
668 		kmem_free(segp, ssize);
669 		return (EFAULT);
670 	}
671 	/* free segment_t buffer */
672 	kmem_free(segp, ssize);
673 
674 	return (ret);
675 }
676 
677 static int
678 sgfru_addsegment(const sgfru_init_arg_t *iargp)
679 {
680 	int32_t ret;
681 	caddr_t datap;
682 	size_t size;
683 	frup_info_t seg;
684 	segment_t segment;
685 	fru_hdl_t *hdlp;
686 	static fn_t f = "sgfru_addsegment";
687 
688 	/* copyin frup_info_t */
689 	if (sgfru_copyin_frup(iargp, &seg) != 0) {
690 		return (EFAULT);
691 	}
692 	/* copyin segment_t */
693 	if (sgfru_copyin_segment(iargp, &seg, &segment) != 0) {
694 		return (EFAULT);
695 	}
696 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
697 	    f, seg.fru_hdl, seg.fru_cnt);
698 	PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, "
699 	    "offset 0x%x, length 0x%x\n", f, segment.handle, segment.name,
700 	    segment.descriptor, segment.offset, segment.length);
701 
702 	/* allocate buffer for unpadded section_hdl_t + segment_t */
703 	size = (size_t)(SECTION_HDL_SIZE + SEGMENT_SIZE);
704 	datap = kmem_zalloc(size, KM_SLEEP);
705 	/* translate padded to unpadded section_hdl_t + segment_t */
706 	sgfru_segment_unpad(&seg.fru_info, &segment, datap);
707 
708 	/* call mailbox */
709 	ret = sgfru_mbox(iargp->cmd, datap, size, &seg.fru_info);
710 	if (ret != 0) {
711 		kmem_free(datap, size);
712 		return (ret);
713 	}
714 
715 	/* copyout updated section_hdl_t */
716 	hdlp = (fru_hdl_t *)(datap + sizeof (fru_hdl_t));
717 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
718 		kmem_free(datap, size);
719 		return (EFAULT);
720 	}
721 	/* copyout new segment_hdl_t */
722 	if (sgfru_copyout_handle(iargp, seg.frus, --hdlp) != 0) {
723 		kmem_free(datap, size);
724 		return (EFAULT);
725 	}
726 	/* free segment_t buffer */
727 	kmem_free(datap, size);
728 
729 	return (ret);
730 }
731 
732 /*
733  * Used for fru_read_segment().
734  */
735 static int
736 sgfru_readsegment(const sgfru_init_arg_t *iargp)
737 {
738 	int32_t ret;
739 	caddr_t datap, tdatap;
740 	size_t size;
741 	frup_info_t segs;
742 	fru_info_t sinfo;
743 	fru_cnt_t max_cnt;
744 	static fn_t f = "sgfru_readsegment";
745 
746 	/* copyin one segments_t aka frup_info_t */
747 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
748 		return (EFAULT);
749 	}
750 	/* check on kmem_alloc space requirements */
751 	max_cnt = segs.fru_cnt;
752 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
753 		return (EINVAL);
754 	}
755 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
756 	    f, segs.fru_hdl, segs.fru_cnt);
757 
758 	/* allocate unpadded buffer for raw data */
759 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
760 	datap = kmem_zalloc(size, KM_SLEEP);
761 
762 	/* call mailbox */
763 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
764 		kmem_free(datap, size);
765 		return (ret);
766 	}
767 
768 	/* translate unpadded to padded fru_info_t */
769 	tdatap = sgfru_fru_pad(datap, &sinfo);
770 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
771 	    f, sinfo.hdl, sinfo.cnt);
772 
773 	/* copyout actual fru_cnt */
774 	if (sgfru_copyout_fru(iargp, &sinfo) != 0) {
775 		kmem_free(datap, size);
776 		return (EFAULT);
777 	}
778 	/* copyout raw segment data */
779 	if (sgfru_copyout_buffer(iargp, &segs, tdatap) != 0) {
780 		kmem_free(datap, size);
781 		return (EFAULT);
782 	}
783 	/* free buffer */
784 	kmem_free(datap, size);
785 
786 	return (ret);
787 }
788 
789 /*
790  * Used for fru_write_segment().
791  */
792 static int
793 sgfru_writesegment(const sgfru_init_arg_t *iargp)
794 {
795 	int32_t ret;
796 	caddr_t datap, tdatap;
797 	size_t size;
798 	frup_info_t segs;
799 	fru_cnt_t max_cnt;
800 	static fn_t f = "sgfru_writesegment";
801 
802 	/* copyin frup_info_t */
803 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
804 		return (EFAULT);
805 	}
806 	/* check on kmem_alloc space requirements */
807 	max_cnt = segs.fru_cnt;
808 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
809 		return (EINVAL);
810 	}
811 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
812 	    f, segs.fru_hdl, segs.fru_cnt);
813 
814 	/* allocate unpadded buffer for fru_info_t + raw data */
815 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
816 	datap = kmem_zalloc(size, KM_SLEEP);
817 
818 	/* translate padded to unpadded fru_info_t */
819 	tdatap = sgfru_fru_unpad(&segs.fru_info, datap);
820 
821 	/* copyin raw segment data */
822 	if (sgfru_copyin_buffer(iargp, segs.frus, max_cnt, tdatap) != 0) {
823 		kmem_free(datap, size);
824 		return (EFAULT);
825 	}
826 
827 	/* call mailbox */
828 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
829 		kmem_free(datap, size);
830 		return (ret);
831 	}
832 	/* free buffer */
833 	kmem_free(datap, size);
834 
835 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
836 	    f, segs.fru_hdl, segs.fru_cnt);
837 	/* copyout updated segment handle and actual fru_cnt */
838 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
839 		return (EFAULT);
840 	}
841 
842 	return (ret);
843 }
844 
845 /*
846  * Used for fru_get_packets().
847  */
848 static int
849 sgfru_getpackets(const sgfru_init_arg_t *iargp)
850 {
851 	int32_t ret;
852 	caddr_t datap;
853 	size_t ssize, size;
854 	frup_info_t packs;
855 	fru_cnt_t max_cnt;
856 	packet_t *packp;
857 
858 	/* copyin packets_t aka frup_info_t */
859 	if (sgfru_copyin_frup(iargp, &packs) != 0) {
860 		return (EFAULT);
861 	}
862 	/* check on kmem_alloc space requirements */
863 	max_cnt = packs.fru_cnt;
864 	if ((max_cnt <= 0) || (max_cnt > MAX_PACKETS)) {
865 		return (EINVAL);
866 	}
867 
868 	/* allocate buffer for unpadded fru_info_t + packet_t's */
869 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * PACKET_SIZE));
870 	datap = kmem_zalloc(size, KM_SLEEP);
871 
872 	/* call mailbox */
873 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &packs.fru_info))
874 	    != 0) {
875 		kmem_free(datap, size);
876 		return (ret);
877 	}
878 
879 	/* allocate buffer for padded packet_t's */
880 	ssize = (size_t)(max_cnt * sizeof (packet_t));
881 	packp = (packet_t *)kmem_zalloc(ssize, KM_SLEEP);
882 
883 	/* translate unpadded to padded fru_info_t + packet_t's */
884 	if ((ret = sgfru_packet_pad(datap, max_cnt, &packs.fru_info, packp))
885 	    != 0) {
886 		kmem_free(datap, size);
887 		kmem_free(packp, ssize);
888 		return (ret);
889 	}
890 	/* free packet_t buffer */
891 	kmem_free(datap, size);
892 
893 	/* copy out fru_info_t */
894 	if (sgfru_copyout_fru(iargp, &packs.fru_info) != 0) {
895 		kmem_free(packp, ssize);
896 		return (EFAULT);
897 	}
898 	/* copyout packet_t's */
899 	if (sgfru_copyout_packets(iargp, &packs, packp) != 0) {
900 		kmem_free(packp, ssize);
901 		return (EFAULT);
902 	}
903 	/* free packet_t buffer */
904 	kmem_free(packp, ssize);
905 
906 	return (ret);
907 }
908 
909 /*
910  * Used for fru_append_packet().
911  */
912 static int
913 sgfru_appendpacket(const sgfru_init_arg_t *iargp)
914 {
915 	int32_t ret = 0;
916 	caddr_t datap, tdatap;
917 	size_t size;
918 	append_info_t append;
919 	fru_cnt_t max_cnt;
920 	fru_hdl_t *hdlp;
921 	caddr_t addr;
922 
923 	/* copyin append_info_t */
924 	if (sgfru_copyin_append(iargp, &append) != 0) {
925 		return (EFAULT);
926 	}
927 	/* check on kmem_alloc space requirements */
928 	max_cnt = append.payload_cnt;
929 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
930 		return (EINVAL);
931 	}
932 
933 	/* allocate buffer for unpadded fru_info_t + packet_t + payload */
934 	size = (size_t)(FRU_INFO_SIZE + PACKET_SIZE + max_cnt);
935 	datap = kmem_zalloc(size, KM_SLEEP);
936 	/* translate padded to unpadded fru_info_t plus packet_t */
937 	tdatap = sgfru_packet_unpad(&append.payload.fru_info, &append.packet,
938 	    datap);
939 
940 	/* copyin payload to the end of the unpadded buffer */
941 	if (sgfru_copyin_buffer(iargp, append.payload_data, append.payload_cnt,
942 	    tdatap) != 0) {
943 		kmem_free(datap, size);
944 		return (EFAULT);
945 	}
946 
947 	/* call mailbox */
948 	if ((ret = sgfru_mbox(iargp->cmd, datap, size,
949 	    &append.payload.fru_info)) != 0) {
950 		kmem_free(datap, size);
951 		return (ret);
952 	}
953 
954 	/* copyout new packet_hdl_t */
955 	hdlp = (fru_hdl_t *)datap;
956 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
957 		kmem_free(datap, size);
958 		return (EFAULT);
959 	}
960 	/* copyout updated segment_hdl_t */
961 	addr = (caddr_t)(iargp->argp + sizeof (packet_t));
962 	if (sgfru_copyout_handle(iargp, addr, ++hdlp) != 0) {
963 		kmem_free(datap, size);
964 		return (EFAULT);
965 	}
966 
967 	/* free buffer */
968 	kmem_free(datap, size);
969 
970 	return (ret);
971 }
972 
973 /*
974  * Used for fru_get_payload().
975  */
976 static int
977 sgfru_getpayload(const sgfru_init_arg_t *iargp)
978 {
979 	int32_t ret;
980 	caddr_t datap, tdatap;
981 	size_t size;
982 	frup_info_t payld;
983 	fru_info_t pinfo;
984 	fru_cnt_t max_cnt;
985 	static fn_t f = "sgfru_getpayload";
986 
987 	/* copyin payload_t aka frup_info_t */
988 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
989 		return (EFAULT);
990 	}
991 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
992 	    f, payld.fru_hdl, payld.fru_cnt);
993 
994 	/* check on kmem_alloc space requirements */
995 	max_cnt = payld.fru_cnt;
996 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
997 		return (EINVAL);
998 	}
999 
1000 	/* allocate buffer for fru_info_t + payload */
1001 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
1002 	datap = kmem_zalloc(size, KM_SLEEP);
1003 
1004 	/* call mailbox */
1005 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
1006 	    != 0) {
1007 		kmem_free(datap, size);
1008 		return (ret);
1009 	}
1010 
1011 	/* translate unpadded to padded fru_info_t */
1012 	tdatap = sgfru_fru_pad(datap, &pinfo);
1013 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
1014 	    f, pinfo.hdl, pinfo.cnt);
1015 
1016 	/* copyout actual fru_cnt */
1017 	if (sgfru_copyout_fru(iargp, &pinfo) != 0) {
1018 		kmem_free(datap, size);
1019 		return (EFAULT);
1020 	}
1021 	/* copyout raw packet data, aka the payload */
1022 	if (sgfru_copyout_buffer(iargp, &payld, tdatap) != 0) {
1023 		kmem_free(datap, size);
1024 		return (EFAULT);
1025 	}
1026 
1027 	/* free buffer */
1028 	kmem_free(datap, size);
1029 
1030 	return (ret);
1031 }
1032 
1033 /*
1034  * Used for fru_update_payload().
1035  */
1036 static int
1037 sgfru_updatepayload(const sgfru_init_arg_t *iargp)
1038 {
1039 	int32_t ret;
1040 	caddr_t datap, tdatap;
1041 	size_t size;
1042 	frup_info_t payld;
1043 	fru_cnt_t max_cnt;
1044 	static fn_t f = "sgfru_updatepayload";
1045 
1046 	/* copyin frup_info_t */
1047 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
1048 		return (EFAULT);
1049 	}
1050 	/* check on kmem_alloc space requirements */
1051 	max_cnt = payld.fru_cnt;
1052 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
1053 		return (EINVAL);
1054 	}
1055 
1056 	/* allocate buffer for fru_info_t + payload */
1057 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
1058 	datap = kmem_zalloc(size, KM_SLEEP);
1059 
1060 	/* translate padded to unpadded fru_info_t */
1061 	tdatap = sgfru_fru_unpad(&payld.fru_info, datap);
1062 
1063 	/* copyin payload */
1064 	if (sgfru_copyin_buffer(iargp, payld.frus, max_cnt, tdatap) != 0) {
1065 		kmem_free(datap, size);
1066 		return (EFAULT);
1067 	}
1068 	PR_PAYLOAD("sgfru_updatepayload: handle %lx, actual cnt %d\n",
1069 	    payld.fru_hdl, payld.fru_cnt);
1070 
1071 	/* call mailbox */
1072 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
1073 	    != 0) {
1074 		kmem_free(datap, size);
1075 		return (ret);
1076 	}
1077 
1078 	/* free buffer */
1079 	kmem_free(datap, size);
1080 
1081 	/* copyout new packet_hdl_t and actual count */
1082 	if (sgfru_copyout_fru(iargp, &payld.fru_info) != 0) {
1083 		return (EFAULT);
1084 	}
1085 	PR_PAYLOAD("sgfru:%s: new handle %lx, cnt %d\n",
1086 	    f, payld.fru_hdl, payld.fru_cnt);
1087 
1088 	return (ret);
1089 }
1090 
1091 /*
1092  * Used for fru_get_num_[sections|segments|packets]().
1093  */
1094 static int
1095 sgfru_getnum(const sgfru_init_arg_t *iargp)
1096 {
1097 	int32_t ret;
1098 	caddr_t datap;
1099 	size_t size;
1100 	fru_info_t fru_info;
1101 
1102 	/* copyin fru_info_t */
1103 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
1104 		return (EFAULT);
1105 	}
1106 
1107 	size = sizeof (fru_cnt_t);
1108 	datap = (caddr_t)&fru_info.cnt;
1109 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
1110 		return (ret);
1111 	}
1112 
1113 	/* copyout fru_info_t */
1114 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
1115 		return (EFAULT);
1116 	}
1117 	return (ret);
1118 }
1119 
1120 /*
1121  * Used for fru_delete_[segment|packet].
1122  */
1123 static int
1124 sgfru_delete(const sgfru_init_arg_t *iargp)
1125 {
1126 	int32_t ret;
1127 	caddr_t datap;
1128 	size_t size;
1129 	fru_info_t fru_info;
1130 	static fn_t f = "sgfru_delete";
1131 
1132 	/* copyin fru_info_t */
1133 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
1134 		return (EFAULT);
1135 	}
1136 	PR_SEGMENT("sgfru:%s: delete handle %lx\n", f, fru_info.hdl);
1137 
1138 	size = sizeof (fru_hdl_t);
1139 	datap = (caddr_t)&fru_info.hdl;
1140 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
1141 		return (ret);
1142 	}
1143 
1144 	PR_SEGMENT("sgfru:%s: new parent handle %lx\n", f, fru_info.hdl);
1145 	/* copyout fru_info_t */
1146 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
1147 		return (EFAULT);
1148 	}
1149 	return (ret);
1150 }
1151 
1152 /*
1153  * Calls the sgsbbc mailbox with data, returns data and status info.
1154  */
1155 static int
1156 sgfru_mbox(const int cmd, char *datap, const size_t size, fru_info_t *fru)
1157 {
1158 	sbbc_msg_t request, *reqp = &request;
1159 	sbbc_msg_t response, *resp = &response;
1160 	fru_hdl_t hdls[2] = {0, 0};
1161 	fru_hdl_t hdl = fru->hdl;
1162 	int rv = 0;
1163 	static fn_t f = "sgfru_mbox";
1164 
1165 	bzero((caddr_t)&request, sizeof (sbbc_msg_t));
1166 	reqp->msg_type.type = SGFRU_MBOX;
1167 	bzero((caddr_t)&response, sizeof (sbbc_msg_t));
1168 	resp->msg_type.type = SGFRU_MBOX;
1169 	PR_MBOX("sgfru:%s: cmd 0x%x, size %lu\n", f, cmd, size);
1170 
1171 	switch (cmd) {
1172 
1173 	case SGFRU_GETCHILDLIST:
1174 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
1175 		reqp->msg_len = sizeof (fru_info_t);
1176 		reqp->msg_buf = (caddr_t)fru;
1177 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
1178 		resp->msg_len = size;
1179 		resp->msg_buf = datap;
1180 		break;
1181 
1182 	case SGFRU_GETCHILDHANDLES:
1183 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
1184 		reqp->msg_len = sizeof (fru_info_t);
1185 		reqp->msg_buf = (caddr_t)fru;
1186 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
1187 		resp->msg_len = size;
1188 		resp->msg_buf = datap;
1189 		break;
1190 
1191 	case SGFRU_GETNODEINFO:
1192 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
1193 		reqp->msg_len = sizeof (fru_hdl_t);
1194 		reqp->msg_buf = (caddr_t)&hdl;
1195 		resp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
1196 		resp->msg_len = size;
1197 		resp->msg_buf = datap;
1198 		break;
1199 
1200 	case SGFRU_GETNUMSECTIONS:
1201 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
1202 		reqp->msg_len = sizeof (fru_hdl_t);
1203 		reqp->msg_buf = (caddr_t)&hdl;
1204 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
1205 		resp->msg_len = size;
1206 		resp->msg_buf = datap;
1207 		break;
1208 
1209 	case SGFRU_GETNUMSEGMENTS:
1210 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
1211 		reqp->msg_len = sizeof (fru_hdl_t);
1212 		reqp->msg_buf = (caddr_t)&hdl;
1213 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
1214 		resp->msg_len = size;
1215 		resp->msg_buf = datap;
1216 		break;
1217 
1218 	case SGFRU_GETNUMPACKETS:
1219 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
1220 		reqp->msg_len = sizeof (fru_hdl_t);
1221 		reqp->msg_buf = (caddr_t)&hdl;
1222 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
1223 		resp->msg_len = size;
1224 		resp->msg_buf = datap;
1225 		break;
1226 
1227 	case SGFRU_GETSECTIONS:
1228 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
1229 		reqp->msg_len = sizeof (fru_info_t);
1230 		reqp->msg_buf = (caddr_t)fru;
1231 		resp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
1232 		resp->msg_len = size;
1233 		resp->msg_buf = datap;
1234 		break;
1235 
1236 	case SGFRU_GETSEGMENTS:
1237 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
1238 		reqp->msg_len = sizeof (fru_info_t);
1239 		reqp->msg_buf = (caddr_t)fru;
1240 		resp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
1241 		resp->msg_len = size;
1242 		resp->msg_buf = datap;
1243 		break;
1244 
1245 	case SGFRU_GETPACKETS:
1246 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
1247 		reqp->msg_len = sizeof (fru_info_t);
1248 		reqp->msg_buf = (caddr_t)fru;
1249 		resp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
1250 		resp->msg_len = size;
1251 		resp->msg_buf = datap;
1252 		break;
1253 
1254 	case SGFRU_ADDSEGMENT:
1255 		reqp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
1256 		reqp->msg_len = size;
1257 		reqp->msg_buf = datap;
1258 		resp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
1259 		resp->msg_len = sizeof (hdls);
1260 		resp->msg_buf = (caddr_t)&hdls;
1261 		break;
1262 
1263 	case SGFRU_APPENDPACKET:
1264 		reqp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
1265 		reqp->msg_len = size;
1266 		reqp->msg_buf = (caddr_t)datap;
1267 		resp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
1268 		resp->msg_len = sizeof (hdls);
1269 		resp->msg_buf = (caddr_t)&hdls;
1270 		break;
1271 
1272 	case SGFRU_DELETESEGMENT:
1273 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
1274 		reqp->msg_len = size;
1275 		reqp->msg_buf = (caddr_t)datap;
1276 		resp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
1277 		resp->msg_len = sizeof (fru_hdl_t);
1278 		resp->msg_buf = (caddr_t)&hdl;
1279 		break;
1280 
1281 	case SGFRU_READRAWSEGMENT:
1282 		reqp->msg_type.sub_type = SGFRU_MBOX_READRAWSEGMENT;
1283 		reqp->msg_len = sizeof (fru_info_t);
1284 		reqp->msg_buf = (caddr_t)fru;
1285 		resp->msg_type.sub_type = SGFRU_READRAWSEGMENT;
1286 		resp->msg_len = size;
1287 		resp->msg_buf = datap;
1288 		break;
1289 
1290 	case SGFRU_WRITERAWSEGMENT:
1291 		reqp->msg_type.sub_type = SGFRU_MBOX_WRITERAWSEGMENT;
1292 		reqp->msg_len = size;
1293 		reqp->msg_buf = datap;
1294 		resp->msg_type.sub_type = SGFRU_WRITERAWSEGMENT;
1295 		resp->msg_len = sizeof (fru_info_t);
1296 		resp->msg_buf = (caddr_t)fru;
1297 		break;
1298 
1299 	case SGFRU_DELETEPACKET:
1300 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
1301 		reqp->msg_len = size;
1302 		reqp->msg_buf = (caddr_t)datap;
1303 		resp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
1304 		resp->msg_len = sizeof (fru_hdl_t);
1305 		resp->msg_buf = (caddr_t)&hdl;
1306 		break;
1307 
1308 	case SGFRU_GETPAYLOAD:
1309 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
1310 		reqp->msg_len = sizeof (fru_info_t);
1311 		reqp->msg_buf = (caddr_t)fru;
1312 		resp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
1313 		resp->msg_len = size;
1314 		resp->msg_buf = datap;
1315 		break;
1316 
1317 	case SGFRU_UPDATEPAYLOAD:
1318 		reqp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
1319 		reqp->msg_len = size;
1320 		reqp->msg_buf = datap;
1321 		resp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
1322 		resp->msg_len = sizeof (fru_info_t);
1323 		resp->msg_buf = (caddr_t)fru;
1324 		break;
1325 
1326 	default:
1327 		return (EINVAL);
1328 	}
1329 
1330 	rv = sbbc_mbox_request_response(reqp, resp, sgfru_mbox_wait);
1331 	PR_MBOX("sgfru:%s: rv %d, msg_status %d\n", f, rv, resp->msg_status);
1332 
1333 	if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
1334 
1335 		/* errors from sgsbbc */
1336 		if (resp->msg_status > 0) {
1337 			return (resp->msg_status);
1338 		}
1339 
1340 		/* errors from SCAPP */
1341 		switch (resp->msg_status) {
1342 
1343 		case SG_MBOX_STATUS_COMMAND_FAILURE:
1344 			/* internal SCAPP error */
1345 			return (EINTR);
1346 
1347 		case SG_MBOX_STATUS_HARDWARE_FAILURE:
1348 			/* seprom read/write errors */
1349 			return (EIO);
1350 
1351 		case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
1352 			/* illegal ioctl parameter */
1353 			return (EINVAL);
1354 
1355 		case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
1356 			/* board access denied */
1357 			return (EACCES);
1358 
1359 		case SG_MBOX_STATUS_STALE_CONTENTS:
1360 			/* stale contents */
1361 			return (ESTALE);
1362 
1363 		case SG_MBOX_STATUS_STALE_OBJECT:
1364 			/* stale handle */
1365 			return (ENOENT);
1366 
1367 		case SG_MBOX_STATUS_NO_SEPROM_SPACE:
1368 			/* seprom lacks space */
1369 			return (ENOSPC);
1370 
1371 		case SG_MBOX_STATUS_NO_MEMORY:
1372 			/* user prog. lacks space */
1373 			return (ENOMEM);
1374 
1375 		case SG_MBOX_STATUS_NOT_SUPPORTED:
1376 			/* unsupported operation */
1377 			return (ENOTSUP);
1378 
1379 		default:
1380 			return (EIO);
1381 		}
1382 	}
1383 
1384 	switch (cmd) {
1385 
1386 	/*
1387 	 * These two calls get back two handles, a new handle for the
1388 	 * added segment or packet, and an updated parent handle.
1389 	 */
1390 	case SGFRU_ADDSEGMENT:
1391 	case SGFRU_APPENDPACKET:
1392 		bcopy(hdls, datap, sizeof (hdls));
1393 		break;
1394 
1395 	/* These two calls get an updated parent handle. */
1396 	case SGFRU_DELETESEGMENT:
1397 	case SGFRU_DELETEPACKET:
1398 		fru->hdl = hdl;
1399 		break;
1400 
1401 	default:
1402 		break;
1403 	}
1404 
1405 	return (0);
1406 }
1407 
1408 /*
1409  * Used to copy in one frup_info_t from user.
1410  */
1411 static int
1412 sgfru_copyin_frup(const sgfru_init_arg_t *argp, frup_info_t *frup)
1413 {
1414 	static fn_t f = "sgfru_copyin_frup";
1415 
1416 	bzero((caddr_t)frup, sizeof (frup_info_t));
1417 #ifdef _MULTI_DATAMODEL
1418 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
1419 		frup32_info_t frup32;
1420 
1421 		bzero((caddr_t)&frup32, sizeof (frup32_info_t));
1422 		if (ddi_copyin((void *)argp->argp, (void *)&frup32,
1423 		    sizeof (frup32_info_t), argp->mode) != DDI_SUCCESS) {
1424 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
1425 			    "frup32_t struct", f);
1426 			return (EFAULT);
1427 		}
1428 		frup->fru_hdl = frup32.fru_hdl;
1429 		frup->fru_cnt = frup32.fru_cnt;
1430 		frup->frus = (void *)(uintptr_t)frup32.frus;
1431 		PR_STATE("sgfru:%s: frus %p %x hdl %lx cnt %d\n",
1432 		    f, frup->frus, frup32.frus, frup->fru_hdl, frup->fru_cnt);
1433 
1434 	} else
1435 #endif /* _MULTI_DATAMODEL */
1436 	if (ddi_copyin((void *)argp->argp, (void *)frup,
1437 	    sizeof (frup_info_t), argp->mode) != DDI_SUCCESS) {
1438 		cmn_err(CE_WARN,
1439 		    "sgfru:%s: failed to copyin frup_info_t struct", f);
1440 		return (EFAULT);
1441 	}
1442 	return (0);
1443 }
1444 
1445 /*
1446  * Used to copy in one fru_info_t from user.
1447  */
1448 static int
1449 sgfru_copyin_fru(const sgfru_init_arg_t *argp, fru_info_t *fru)
1450 {
1451 	static fn_t f = "sgfru_copyin_fru";
1452 
1453 	bzero((caddr_t)fru, sizeof (fru_info_t));
1454 	if (ddi_copyin((void *)argp->argp, (void *)fru,
1455 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
1456 		cmn_err(CE_WARN,
1457 		    "sgfru:%s: failed to copyin fru_info_t struct", f);
1458 		return (EFAULT);
1459 	}
1460 	return (0);
1461 }
1462 
1463 /*
1464  * Used to copy in segment_t from user.
1465  */
1466 static int
1467 sgfru_copyin_segment(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1468     segment_t *segp)
1469 {
1470 	static fn_t f = "sgfru_copyin_segment";
1471 
1472 	bzero((caddr_t)segp, sizeof (segment_t));
1473 	if (ddi_copyin((void *)frup->frus, (void *)segp,
1474 	    sizeof (segment_t), argp->mode) != DDI_SUCCESS) {
1475 		cmn_err(CE_WARN,
1476 		    "sgfru:%s: failed to copyin segment_t struct", f);
1477 		return (EFAULT);
1478 	}
1479 	return (0);
1480 }
1481 
1482 /*
1483  * Used to copy in segment handle, packet and payload data from user.
1484  */
1485 static int
1486 sgfru_copyin_append(const sgfru_init_arg_t *argp, append_info_t *app)
1487 {
1488 	static fn_t f = "sgfru_copyin_append";
1489 
1490 	bzero((caddr_t)app, sizeof (append_info_t));
1491 #ifdef _MULTI_DATAMODEL
1492 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
1493 		append32_info_t app32;
1494 
1495 		bzero((caddr_t)&app32, sizeof (append32_info_t));
1496 		if (ddi_copyin((void *)argp->argp, (void *)&app32,
1497 		    sizeof (append32_info_t), argp->mode) != DDI_SUCCESS) {
1498 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
1499 			    "append32_info_t struct", f);
1500 			return (EFAULT);
1501 		}
1502 		app->packet = app32.packet;
1503 		app->payload_hdl = app32.payload_hdl;
1504 		app->payload_cnt = app32.payload_cnt;
1505 		app->payload_data = (void *)(uintptr_t)app32.payload_data;
1506 		PR_PAYLOAD("sgfru:%s:: data %p hdl %lx cnt %d\n",
1507 		    f, app->payload_data, app->payload_hdl, app->payload_cnt);
1508 
1509 	} else
1510 #endif /* _MULTI_DATAMODEL */
1511 	if (ddi_copyin((void *)argp->argp, (void *)app,
1512 	    sizeof (append_info_t), argp->mode) != DDI_SUCCESS) {
1513 		cmn_err(CE_WARN,
1514 		    "sgfru:%s: failed to copyin append_info_t struct", f);
1515 		return (EFAULT);
1516 	}
1517 	PR_PAYLOAD("sgfru:%s: hdl %lx, cnt %d pkt hdl %lx "
1518 	    "tag %lx\n", f, app->payload_hdl, app->payload_cnt,
1519 	    app->packet.handle, app->packet.tag);
1520 	return (0);
1521 }
1522 
1523 /*
1524  * Used to copy in raw segment and payload data from user.
1525  */
1526 static int
1527 sgfru_copyin_buffer(const sgfru_init_arg_t *argp, const caddr_t data,
1528 	const int cnt, char *buffer)
1529 {
1530 	static fn_t f = "sgfru_copyin_buffer";
1531 
1532 	if (ddi_copyin((void *)data, (void *)buffer, cnt, argp->mode)
1533 	    != DDI_SUCCESS) {
1534 		cmn_err(CE_WARN, "sgfru:%s: failed to copyin buffer", f);
1535 		return (EFAULT);
1536 	}
1537 	return (0);
1538 }
1539 
1540 /*
1541  * Used to copy out one fru_info_t to user.
1542  */
1543 static int
1544 sgfru_copyout_fru(const sgfru_init_arg_t *argp, const fru_info_t *frup)
1545 {
1546 	static fn_t f = "sgfru_copyout_fru";
1547 
1548 	if (ddi_copyout((void *)frup, (void *)argp->argp,
1549 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
1550 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout fru", f);
1551 		return (EFAULT);
1552 	}
1553 	return (0);
1554 }
1555 
1556 /*
1557  * Used to copy out one fru_hdl_t to user.
1558  */
1559 static int
1560 sgfru_copyout_handle(const sgfru_init_arg_t *argp, const void *addr,
1561     const fru_hdl_t *hdlp)
1562 {
1563 	static fn_t f = "sgfru_copyout_handle";
1564 
1565 	if (ddi_copyout((void *)hdlp, (void *)addr, sizeof (fru_hdl_t),
1566 	    argp->mode) != DDI_SUCCESS) {
1567 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handle", f);
1568 		return (EFAULT);
1569 	}
1570 	return (0);
1571 }
1572 
1573 /*
1574  * Used to copy out an array of fru_hdl_t's to user.
1575  */
1576 static int
1577 sgfru_copyout_handles(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1578     const fru_hdl_t *hdlp)
1579 {
1580 	static fn_t f = "sgfru_copyout_handles";
1581 
1582 	size_t size = (size_t)(frup->fru_cnt * sizeof (fru_hdl_t));
1583 	/* copyout fru_hdl_t's */
1584 	if (ddi_copyout((void *)hdlp, (void *)frup->frus, size, argp->mode)
1585 	    != DDI_SUCCESS) {
1586 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handles", f);
1587 		return (EFAULT);
1588 	}
1589 	return (0);
1590 }
1591 
1592 /*
1593  * Used to copy out one or more node_t's to user.
1594  */
1595 static int
1596 sgfru_copyout_nodes(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1597     const node_t *nodep)
1598 {
1599 	static fn_t f = "sgfru_copyout_nodes";
1600 
1601 	size_t size = (size_t)(frup->fru_cnt * sizeof (node_t));
1602 	/* copyout node_t's */
1603 	if (ddi_copyout((void *)nodep, (void *)frup->frus, size, argp->mode)
1604 	    != DDI_SUCCESS) {
1605 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout nodes", f);
1606 		return (EFAULT);
1607 	}
1608 	return (0);
1609 }
1610 
1611 /*
1612  * Used to copy out section_t's to user.
1613  */
1614 static int
1615 sgfru_copyout_sections(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1616     const section_t *sectp)
1617 {
1618 	static fn_t f = "sgfru_copyout_sections";
1619 
1620 	size_t size = (size_t)(frup->fru_cnt * sizeof (section_t));
1621 	/* copyout section_t's */
1622 	if (ddi_copyout((void *)sectp, (void *)frup->frus, size, argp->mode)
1623 	    != DDI_SUCCESS) {
1624 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout sections", f);
1625 		return (EFAULT);
1626 	}
1627 	return (0);
1628 }
1629 
1630 /*
1631  * Used to copy out segment_t's to user.
1632  */
1633 static int
1634 sgfru_copyout_segments(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1635     const segment_t *segp)
1636 {
1637 	static fn_t f = "sgfru_copyout_segments";
1638 
1639 	size_t size = (size_t)(frup->fru_cnt * sizeof (segment_t));
1640 	/* copyout segment_t's */
1641 	if (ddi_copyout((void *)segp, (void *)frup->frus, size, argp->mode)
1642 	    != DDI_SUCCESS) {
1643 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout segments", f);
1644 		return (EFAULT);
1645 	}
1646 	return (0);
1647 }
1648 
1649 /*
1650  * Used to copy out packet_t's to user.
1651  */
1652 static int
1653 sgfru_copyout_packets(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1654     const packet_t *packp)
1655 {
1656 	static fn_t f = "sgfru_copyout_packets";
1657 
1658 	size_t size = (size_t)(frup->fru_cnt * sizeof (packet_t));
1659 	/* copyout packet_t's */
1660 	if (ddi_copyout((void *)packp, (void *)frup->frus, size, argp->mode)
1661 	    != DDI_SUCCESS) {
1662 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout packets", f);
1663 		return (EFAULT);
1664 	}
1665 	return (0);
1666 }
1667 
1668 /*
1669  * Used to copy out raw segment and payload data to user.
1670  */
1671 static int
1672 sgfru_copyout_buffer(const sgfru_init_arg_t *argp, const frup_info_t *frup,
1673     const char *buffer)
1674 {
1675 	static fn_t f = "sgfru_copyout_buffer";
1676 
1677 	size_t size = (size_t)(frup->fru_cnt);
1678 	/* copyout packet_t */
1679 	if (ddi_copyout((void *)buffer, (void *)frup->frus, size, argp->mode)
1680 	    != DDI_SUCCESS) {
1681 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout buffer", f);
1682 		return (EFAULT);
1683 	}
1684 	return (0);
1685 }
1686 
1687 /*
1688  * Used to pad a Java (SCAPP) fru_info_t, in preparation for sending it to
1689  * C (Solaris).  Assumes one fru_info_t.
1690  */
1691 static caddr_t
1692 sgfru_fru_pad(const caddr_t datap, fru_info_t *fru)
1693 {
1694 	caddr_t tdatap = datap;
1695 
1696 	bcopy(tdatap, (caddr_t)&fru->hdl, FRU_HDL_SIZE);
1697 	tdatap += FRU_HDL_SIZE;
1698 	bcopy(tdatap, (caddr_t)&fru->cnt, FRU_CNT_SIZE);
1699 	tdatap += FRU_CNT_SIZE;
1700 	return (tdatap);
1701 }
1702 
1703 /*
1704  * Used to pad a Java (SCAPP) node_t, in preparation for sending it to
1705  * C (Solaris).  Assumes a fru_info_t and one or more node_t's.
1706  */
1707 static int
1708 sgfru_node_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
1709     node_t *nodep)
1710 {
1711 	caddr_t tdatap = datap;
1712 	node_t *np;
1713 	int i, cnt = 1;
1714 
1715 	if (fru != NULL) {
1716 		tdatap = sgfru_fru_pad(datap, fru);
1717 		if (max_cnt < fru->cnt) {
1718 			return (ENOMEM);
1719 		} else {
1720 			cnt = fru->cnt;
1721 		}
1722 	}
1723 	for (i = 0, np = nodep; i < cnt; i++, np++) {
1724 		bcopy(tdatap, (caddr_t)&np->handle, FRU_HDL_SIZE);
1725 		tdatap += FRU_HDL_SIZE;
1726 		bcopy(tdatap, (caddr_t)&np->nodename, NODENAME_SIZE);
1727 		tdatap += NODENAME_SIZE;
1728 		bcopy(tdatap, (caddr_t)&np->has_children, HASCHILDREN_SIZE);
1729 		tdatap += HASCHILDREN_SIZE;
1730 		bcopy(tdatap, (caddr_t)&np->class, CLASS_SIZE);
1731 		tdatap += CLASS_SIZE;
1732 		if (np->class == LOCATION_CLASS) {
1733 			bcopy(tdatap, (caddr_t)&np->location_slot, SLOT_SIZE);
1734 			tdatap += SLOT_SIZE;
1735 			bcopy(tdatap, (caddr_t)&np->location_label, LABEL_SIZE);
1736 			tdatap += LABEL_SIZE;
1737 		}
1738 	}
1739 	return (0);
1740 }
1741 
1742 /*
1743  * Used to pad a Java (SCAPP) section, in preparation for sending it to
1744  * C (Solaris).  Assumes a fru_info_t and multiple section_t's.
1745  */
1746 static int
1747 sgfru_section_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
1748     section_t *sectp)
1749 {
1750 	caddr_t tdatap = datap;
1751 	section_t *sp;
1752 	int i;
1753 
1754 	tdatap = sgfru_fru_pad(datap, fru);
1755 	if (max_cnt < fru->cnt)
1756 		return (ENOMEM);
1757 	for (i = 0, sp = sectp; i < fru->cnt; i++, sp++) {
1758 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
1759 		tdatap += FRU_HDL_SIZE;
1760 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
1761 		tdatap += OFFSET_SIZE;
1762 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
1763 		tdatap += LENGTH_SIZE;
1764 		bcopy(tdatap, (caddr_t)&sp->protected, PROTECTED_SIZE);
1765 		tdatap += PROTECTED_SIZE;
1766 		bcopy(tdatap, (caddr_t)&sp->version, VERSION_SIZE);
1767 		tdatap += VERSION_SIZE;
1768 	}
1769 	return (0);
1770 }
1771 
1772 /*
1773  * Used to pad a Java (SCAPP) segment, in preparation for sending it to
1774  * C (Solaris).  Assumes a fru_info_t and multiple segment_t's.
1775  */
1776 static int
1777 sgfru_segment_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
1778     segment_t *segp)
1779 {
1780 	caddr_t tdatap = datap;
1781 	segment_t *sp;
1782 	int i;
1783 
1784 	tdatap = sgfru_fru_pad(datap, fru);
1785 	if (max_cnt < fru->cnt)
1786 		return (ENOMEM);
1787 	for (i = 0, sp = segp; i < fru->cnt; i++, sp++) {
1788 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
1789 		tdatap += FRU_HDL_SIZE;
1790 		bcopy(tdatap, (caddr_t)&sp->name, NAME_SIZE);
1791 		tdatap += NAME_SIZE;
1792 		bcopy(tdatap, (caddr_t)&sp->descriptor, DESCRIPTOR_SIZE);
1793 		tdatap += DESCRIPTOR_SIZE;
1794 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
1795 		tdatap += OFFSET_SIZE;
1796 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
1797 		tdatap += LENGTH_SIZE;
1798 	}
1799 	return (0);
1800 }
1801 
1802 /*
1803  * Used to pad a Java (SCAPP) packet, in preparation for sending it to
1804  * C (Solaris).  Assumes a fru_info_t and multiple packet_t's.
1805  */
1806 static int
1807 sgfru_packet_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
1808     packet_t *packp)
1809 {
1810 	caddr_t tdatap = datap;
1811 	packet_t *pp;
1812 	int i;
1813 
1814 	tdatap = sgfru_fru_pad(datap, fru);
1815 	if (max_cnt < fru->cnt)
1816 		return (ENOMEM);
1817 	for (i = 0, pp = packp; i < fru->cnt; i++, pp++) {
1818 		bcopy(tdatap, (caddr_t)&pp->handle, FRU_HDL_SIZE);
1819 		tdatap += FRU_HDL_SIZE;
1820 		bcopy(tdatap, (caddr_t)&pp->tag, TAG_SIZE);
1821 		tdatap += TAG_SIZE;
1822 	}
1823 	return (0);
1824 }
1825 
1826 /*
1827  * Used to unpad a C (Solaris) fru_info_t, in preparation for sending it to
1828  * Java (SCAPP).  Assumes a fru_info_t.
1829  */
1830 static caddr_t
1831 sgfru_fru_unpad(const fru_info_t *fru, caddr_t datap)
1832 {
1833 	caddr_t tdatap = datap;
1834 
1835 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
1836 	tdatap += FRU_HDL_SIZE;
1837 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
1838 	tdatap += FRU_CNT_SIZE;
1839 	return (tdatap);
1840 }
1841 
1842 /*
1843  * Used to unpad a C (Solaris) segment, in preparation for sending it to
1844  * Java (SCAPP). Assumes a section_hdl_t and one segment_t.
1845  */
1846 static void
1847 sgfru_segment_unpad(const fru_info_t *fru, const segment_t *segp,
1848     caddr_t datap)
1849 {
1850 	caddr_t tdatap = datap;
1851 
1852 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
1853 	tdatap += FRU_HDL_SIZE;
1854 	bcopy((caddr_t)&segp->handle, tdatap, FRU_HDL_SIZE);
1855 	tdatap += FRU_HDL_SIZE;
1856 	bcopy((caddr_t)&segp->name, tdatap, NAME_SIZE);
1857 	tdatap += NAME_SIZE;
1858 	bcopy((caddr_t)&segp->descriptor, tdatap, DESCRIPTOR_SIZE);
1859 	tdatap += DESCRIPTOR_SIZE;
1860 	bcopy((caddr_t)&segp->offset, tdatap, OFFSET_SIZE);
1861 	tdatap += OFFSET_SIZE;
1862 	bcopy((caddr_t)&segp->length, tdatap, LENGTH_SIZE);
1863 }
1864 
1865 /*
1866  * Used to unpad a C (Solaris) packet, in preparation for sending it to
1867  * Java (SCAPP).  Assumes a fru_info_t and one packet_t.
1868  */
1869 static caddr_t
1870 sgfru_packet_unpad(const fru_info_t *fru, const packet_t *packp, caddr_t datap)
1871 {
1872 	caddr_t tdatap = datap;
1873 
1874 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
1875 	tdatap += FRU_HDL_SIZE;
1876 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
1877 	tdatap += FRU_CNT_SIZE;
1878 	bcopy((caddr_t)&packp->handle, tdatap, FRU_HDL_SIZE);
1879 	tdatap += FRU_HDL_SIZE;
1880 	bcopy((caddr_t)&packp->tag, tdatap, TAG_SIZE);
1881 	tdatap += TAG_SIZE;
1882 	return (tdatap);
1883 }
1884