xref: /onnv-gate/usr/src/uts/sun4u/lw8/io/sgfru.c (revision 7656:2621e50fdf4a)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel #include <sys/types.h>
291708Sstevel #include <sys/conf.h>
301708Sstevel #include <sys/file.h>
311708Sstevel #include <sys/ddi.h>
321708Sstevel #include <sys/sunddi.h>
331708Sstevel #include <sys/modctl.h>
341708Sstevel #include <sys/sunndi.h>
351708Sstevel #include <sys/ddi_impldefs.h>
361708Sstevel #include <sys/obpdefs.h>
371708Sstevel #include <sys/cmn_err.h>
381708Sstevel #include <sys/errno.h>
391708Sstevel #include <sys/debug.h>
401708Sstevel #include <sys/sysmacros.h>
411708Sstevel #include <sys/autoconf.h>
421708Sstevel #include <sys/stat.h>
431708Sstevel #include <sys/kmem.h>
441708Sstevel #include <sys/sgsbbc_mailbox.h>
451708Sstevel #include <sys/sgfrutree.h>
461708Sstevel #include <sys/sgfru_priv.h>
471708Sstevel #include <sys/sgfru_mbox.h>
481708Sstevel 
491708Sstevel /*
501708Sstevel  * This driver implements the ioctls for the serengeti frutree picl plugin
511708Sstevel  * and the serengeti fruaccess library. These are all private,
521708Sstevel  * platform-dependent interfaces.
531708Sstevel  */
541708Sstevel 
551708Sstevel /* Global Variables */
561708Sstevel 
571708Sstevel #ifdef DEBUG
581708Sstevel uint_t sgfru_debug = 0;
591708Sstevel #endif /* DEBUG */
601708Sstevel 
611708Sstevel /* Opaque state structure pointer */
621708Sstevel static void *sgfru_statep;	/* sgfru soft state hook */
631708Sstevel 
641708Sstevel /*
651708Sstevel  * the maximum amount of time this driver is prepared to wait for the mailbox
661708Sstevel  * to reply before it decides to timeout.
671708Sstevel  */
681708Sstevel int sgfru_mbox_wait = SGFRU_DEFAULT_MAX_MBOX_WAIT_TIME;
691708Sstevel 
701708Sstevel /* Module Variables */
711708Sstevel 
721708Sstevel /*
731708Sstevel  * Driver entry points. These are located in sgfru.c so as to
741708Sstevel  * not cause a warning for the sgfru adb macro.
751708Sstevel  */
761708Sstevel static struct cb_ops sgfru_cb_ops = {
771708Sstevel 	sgfru_open,		/* open */
781708Sstevel 	sgfru_close,		/* close */
791708Sstevel 	nulldev,		/* strategy */
801708Sstevel 	nulldev,		/* print */
811708Sstevel 	nulldev,		/* dump */
821708Sstevel 	nulldev,		/* read */
831708Sstevel 	nulldev,		/* write */
841708Sstevel 	sgfru_ioctl,		/* ioctl */
851708Sstevel 	nulldev,		/* devmap */
861708Sstevel 	nulldev,		/* mmap */
871708Sstevel 	nulldev,		/* segmap */
881708Sstevel 	nochpoll,		/* poll */
891708Sstevel 	ddi_prop_op,		/* cb_prop_op */
901708Sstevel 	NULL,			/* streamtab */
911708Sstevel 	D_NEW | D_MP		/* Driver compatibility flag */
921708Sstevel };
931708Sstevel 
941708Sstevel static struct dev_ops sgfru_ops = {
951708Sstevel 	DEVO_REV,		/* devo_rev, */
961708Sstevel 	0,			/* refcnt  */
971708Sstevel 	ddi_getinfo_1to1,	/* info */
981708Sstevel 	nulldev,		/* identify */
991708Sstevel 	nulldev,		/* probe */
1001708Sstevel 	sgfru_attach,		/* attach */
1011708Sstevel 	sgfru_detach,		/* detach */
1021708Sstevel 	nodev,			/* reset */
1031708Sstevel 	&sgfru_cb_ops,		/* driver operations */
1041708Sstevel 	(struct bus_ops *)0,	/* bus operations */
105*7656SSherry.Moore@Sun.COM 	nulldev,		/* power */
106*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
1071708Sstevel };
1081708Sstevel 
1091708Sstevel /*
1101708Sstevel  * Loadable module support. This is located in sgfru.c so as to
111*7656SSherry.Moore@Sun.COM  * pick up the 1.8 version of sgfru.c.
1121708Sstevel  */
1131708Sstevel extern struct mod_ops mod_driverops;
1141708Sstevel 
1151708Sstevel static struct modldrv modldrv = {
1161708Sstevel 	&mod_driverops,	/* Type of module.  This one is a pseudo driver */
117*7656SSherry.Moore@Sun.COM 	"FRU Driver",
1181708Sstevel 	&sgfru_ops,	/* driver ops */
1191708Sstevel };
1201708Sstevel 
1211708Sstevel static struct modlinkage modlinkage = {
1221708Sstevel 	MODREV_1,
1231708Sstevel 	(void *)&modldrv,
1241708Sstevel 	NULL
1251708Sstevel };
1261708Sstevel 
1271708Sstevel int
_init(void)1281708Sstevel _init(void)
1291708Sstevel {
1301708Sstevel 	int error = 0;
1311708Sstevel 
1321708Sstevel 	/* Allocate the soft state info and add the module. */
1331708Sstevel 	if ((error = ddi_soft_state_init(&sgfru_statep,
1341708Sstevel 	    sizeof (sgfru_soft_state_t), 1)) == 0 &&
1351708Sstevel 	    (error = mod_install(&modlinkage)) != 0) {
1361708Sstevel 		ddi_soft_state_fini(&sgfru_statep);
1371708Sstevel 	}
1381708Sstevel 	return (error);
1391708Sstevel }
1401708Sstevel 
1411708Sstevel int
_fini(void)1421708Sstevel _fini(void)
1431708Sstevel {
1441708Sstevel 	int error = 0;
1451708Sstevel 
1461708Sstevel 	/* Remove the module and free the soft state info. */
1471708Sstevel 	if ((error = mod_remove(&modlinkage)) == 0) {
1481708Sstevel 		ddi_soft_state_fini(&sgfru_statep);
1491708Sstevel 	}
1501708Sstevel 	return (error);
1511708Sstevel }
1521708Sstevel 
1531708Sstevel int
_info(struct modinfo * modinfop)1541708Sstevel _info(struct modinfo *modinfop)
1551708Sstevel {
1561708Sstevel 	return (mod_info(&modlinkage, modinfop));
1571708Sstevel }
1581708Sstevel 
1591708Sstevel static int
sgfru_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1601708Sstevel sgfru_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1611708Sstevel {
1621708Sstevel 	sgfru_soft_state_t *softsp;
1631708Sstevel 	int instance;
1641708Sstevel 	int error;
1651708Sstevel 	static fn_t f = "sgfru_attach";
1661708Sstevel 
1671708Sstevel 	switch (cmd) {
1681708Sstevel 	case DDI_ATTACH:
1691708Sstevel 		instance = ddi_get_instance(dip);
1701708Sstevel 
1711708Sstevel 		error = ddi_soft_state_zalloc(sgfru_statep, instance);
1721708Sstevel 		if (error != DDI_SUCCESS) {
1731708Sstevel 			cmn_err(CE_WARN, "sgfru:%s: cannot allocate fru state "
1741708Sstevel 			    "for inst %d.", f, instance);
1751708Sstevel 			return (DDI_FAILURE);
1761708Sstevel 		}
1771708Sstevel 		softsp = ddi_get_soft_state(sgfru_statep, instance);
1781708Sstevel 		if (softsp == NULL) {
1791708Sstevel 			ddi_soft_state_free(sgfru_statep, instance);
1801708Sstevel 			cmn_err(CE_WARN, "sgfru:%s: could not get state "
1811708Sstevel 			    "structure for inst %d.", f, instance);
1821708Sstevel 			return (DDI_FAILURE);
1831708Sstevel 		}
1841708Sstevel 		softsp->fru_dip = dip;
1851708Sstevel 		softsp->fru_pdip = ddi_get_parent(softsp->fru_dip);
1861708Sstevel 		softsp->instance = instance;
1871708Sstevel 
1881708Sstevel 		error = ddi_create_minor_node(dip, SGFRU_DRV_NAME, S_IFCHR,
1891708Sstevel 		    instance, DDI_PSEUDO, NULL);
1901708Sstevel 		if (error == DDI_FAILURE) {
1911708Sstevel 			ddi_soft_state_free(sgfru_statep, instance);
1921708Sstevel 			return (DDI_FAILURE);
1931708Sstevel 		}
1941708Sstevel 
1951708Sstevel 		ddi_report_dev(dip);
1961708Sstevel 
1971708Sstevel 		return (DDI_SUCCESS);
1981708Sstevel 
1991708Sstevel 	case DDI_RESUME:
2001708Sstevel 		return (DDI_SUCCESS);
2011708Sstevel 
2021708Sstevel 	default:
2031708Sstevel 		return (DDI_FAILURE);
2041708Sstevel 	}
2051708Sstevel }
2061708Sstevel 
2071708Sstevel static int
sgfru_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2081708Sstevel sgfru_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2091708Sstevel {
2101708Sstevel 	int instance;
2111708Sstevel 	sgfru_soft_state_t *softsp;
2121708Sstevel 	static fn_t f = "sgfru_detach";
2131708Sstevel 
2141708Sstevel 	instance = ddi_get_instance(dip);
2151708Sstevel 
2161708Sstevel 	softsp = ddi_get_soft_state(sgfru_statep, instance);
2171708Sstevel 	if (softsp == NULL) {
2181708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: could not get state "
2191708Sstevel 		    "structure for inst %d.", f, instance);
2201708Sstevel 		return (DDI_FAILURE);
2211708Sstevel 	}
2221708Sstevel 
2231708Sstevel 	switch (cmd) {
2241708Sstevel 	case DDI_DETACH:
2251708Sstevel 		ddi_soft_state_free(sgfru_statep, instance);
2261708Sstevel 		ddi_remove_minor_node(dip, NULL);
2271708Sstevel 		return (DDI_SUCCESS);
2281708Sstevel 
2291708Sstevel 	case DDI_SUSPEND:
2301708Sstevel 		return (DDI_SUCCESS);
2311708Sstevel 
2321708Sstevel 	default:
2331708Sstevel 		return (DDI_FAILURE);
2341708Sstevel 	}
2351708Sstevel }
2361708Sstevel 
2371708Sstevel /*ARGSUSED*/
2381708Sstevel static int
sgfru_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)2391708Sstevel sgfru_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
2401708Sstevel {
2411708Sstevel 	int error = 0;
2421708Sstevel 	int instance = getminor(*dev_p);
2431708Sstevel 	sgfru_soft_state_t *softsp;
2441708Sstevel 	static fn_t f = "sgfru_open";
2451708Sstevel 
2461708Sstevel 	if ((error = drv_priv(cred_p)) != 0) {
2471708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: inst %d drv_priv failed",
2481708Sstevel 		    f, instance);
2491708Sstevel 		return (error);
2501708Sstevel 	}
2511708Sstevel 	softsp = (sgfru_soft_state_t *)ddi_get_soft_state(sgfru_statep,
2521708Sstevel 	    instance);
2531708Sstevel 	if (softsp == (sgfru_soft_state_t *)NULL) {
2541708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: inst %d ddi_get_soft_state failed",
2551708Sstevel 		    f, instance);
2561708Sstevel 		return (ENXIO);
2571708Sstevel 	}
2581708Sstevel 	return (error);
2591708Sstevel }
2601708Sstevel 
2611708Sstevel /*ARGSUSED*/
2621708Sstevel static int
sgfru_close(dev_t dev,int flag,int otyp,cred_t * cred_p)2631708Sstevel sgfru_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
2641708Sstevel {
2651708Sstevel 	int instance = getminor(dev);
2661708Sstevel 	sgfru_soft_state_t *softsp = (sgfru_soft_state_t *)
2671708Sstevel 	    ddi_get_soft_state(sgfru_statep, instance);
2681708Sstevel 
2691708Sstevel 	if (softsp == (sgfru_soft_state_t *)NULL)
2701708Sstevel 		return (ENXIO);
2711708Sstevel 	return (DDI_SUCCESS);
2721708Sstevel }
2731708Sstevel 
2741708Sstevel /*
2751708Sstevel  * This function disperses the ioctls from the serengeti libpiclfruhier plugin
2761708Sstevel  * and the serengeti libpiclfruaccess library to the appropriate sub-functions.
2771708Sstevel  */
2781708Sstevel /*ARGSUSED*/
2791708Sstevel static int
sgfru_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)2801708Sstevel sgfru_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
2811708Sstevel     int *rval_p)
2821708Sstevel {
2831708Sstevel 	sgfru_soft_state_t *softsp;
2841708Sstevel 	int instance = getminor(dev);
2851708Sstevel 	sgfru_init_arg_t init_arg;
2861708Sstevel 	int32_t ret = 0;
2871708Sstevel 	static fn_t f = "sgfru_ioctl";
2881708Sstevel 
2891708Sstevel 
2901708Sstevel 	softsp = ddi_get_soft_state(sgfru_statep, instance);
2911708Sstevel 	if (softsp == NULL) {
2921708Sstevel 		return (ENXIO);
2931708Sstevel 	}
2941708Sstevel 	PR_STATE("sgfru:%s: dev %lx cmd %d, instance %d\n",
2951708Sstevel 	    f, dev, cmd, instance);
2961708Sstevel 
2971708Sstevel 	init_arg.dev = dev;
2981708Sstevel 	init_arg.cmd = cmd;
2991708Sstevel 	init_arg.mode = mode;
3001708Sstevel 	init_arg.argp = arg;
3011708Sstevel 
3021708Sstevel 	switch (cmd) {
3031708Sstevel 
3041708Sstevel 	case SGFRU_GETSECTIONS:
3051708Sstevel 		ret = sgfru_getsections(&init_arg);
3061708Sstevel 		break;
3071708Sstevel 
3081708Sstevel 	case SGFRU_GETSEGMENTS:
3091708Sstevel 		ret = sgfru_getsegments(&init_arg);
3101708Sstevel 		break;
3111708Sstevel 
3121708Sstevel 	case SGFRU_ADDSEGMENT:
3131708Sstevel 		ret = sgfru_addsegment(&init_arg);
3141708Sstevel 		break;
3151708Sstevel 
3161708Sstevel 	case SGFRU_READRAWSEGMENT:
3171708Sstevel 		ret = sgfru_readsegment(&init_arg);
3181708Sstevel 		break;
3191708Sstevel 
3201708Sstevel 	case SGFRU_WRITERAWSEGMENT:
3211708Sstevel 		ret = sgfru_writesegment(&init_arg);
3221708Sstevel 		break;
3231708Sstevel 
3241708Sstevel 	case SGFRU_GETPACKETS:
3251708Sstevel 		ret = sgfru_getpackets(&init_arg);
3261708Sstevel 		break;
3271708Sstevel 
3281708Sstevel 	case SGFRU_APPENDPACKET:
3291708Sstevel 		ret = sgfru_appendpacket(&init_arg);
3301708Sstevel 		break;
3311708Sstevel 
3321708Sstevel 	case SGFRU_GETPAYLOAD:
3331708Sstevel 		ret = sgfru_getpayload(&init_arg);
3341708Sstevel 		break;
3351708Sstevel 
3361708Sstevel 	case SGFRU_UPDATEPAYLOAD:
3371708Sstevel 		ret = sgfru_updatepayload(&init_arg);
3381708Sstevel 		break;
3391708Sstevel 
3401708Sstevel 	case SGFRU_GETNUMSECTIONS:
3411708Sstevel 	case SGFRU_GETNUMSEGMENTS:
3421708Sstevel 	case SGFRU_GETNUMPACKETS:
3431708Sstevel 		ret = sgfru_getnum(&init_arg);
3441708Sstevel 		break;
3451708Sstevel 
3461708Sstevel 	case SGFRU_DELETESEGMENT:
3471708Sstevel 	case SGFRU_DELETEPACKET:
3481708Sstevel 		ret = sgfru_delete(&init_arg);
3491708Sstevel 		break;
3501708Sstevel 
3511708Sstevel 	case SGFRU_GETCHILDLIST:
3521708Sstevel 		ret = sgfru_getchildlist(&init_arg);
3531708Sstevel 		break;
3541708Sstevel 
3551708Sstevel 	case SGFRU_GETCHILDHANDLES:
3561708Sstevel 		ret = sgfru_getchildhandles(&init_arg);
3571708Sstevel 		break;
3581708Sstevel 
3591708Sstevel 	case SGFRU_GETNODEINFO:
3601708Sstevel 		ret = sgfru_getnodeinfo(&init_arg);
3611708Sstevel 		break;
3621708Sstevel 
3631708Sstevel 	default:
3641708Sstevel 		ret = EINVAL;
3651708Sstevel 		break;
3661708Sstevel 	}
3671708Sstevel 
3681708Sstevel 	return (ret);
3691708Sstevel }
3701708Sstevel 
3711708Sstevel /*
3721708Sstevel  * Used for private SGFRU_GETCHILDLIST ioctl.
3731708Sstevel  */
3741708Sstevel static int
sgfru_getchildlist(const sgfru_init_arg_t * iargp)3751708Sstevel sgfru_getchildlist(const sgfru_init_arg_t *iargp)
3761708Sstevel {
3771708Sstevel 	int32_t ret;
3781708Sstevel 	caddr_t datap;
3791708Sstevel 	size_t ssize, size;
3801708Sstevel 	frup_info_t clist;
3811708Sstevel 	fru_cnt_t max_cnt;
3821708Sstevel 	node_t *clistp;
3831708Sstevel 	static fn_t f = "sgfru_getchildlist";
3841708Sstevel 
3851708Sstevel 	/* copyin child_info_t aka frup_info_t */
3861708Sstevel 	if (sgfru_copyin_frup(iargp, &clist) != 0) {
3871708Sstevel 		return (EFAULT);
3881708Sstevel 	}
3891708Sstevel 
3901708Sstevel 	/* check on kmem_alloc space requirements */
3911708Sstevel 	max_cnt = clist.fru_cnt;
3921708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
3931708Sstevel 		return (EINVAL);
3941708Sstevel 	}
3951708Sstevel 
3961708Sstevel 	/* allocate buffer for unpadded fru_info_t + node_t's */
3971708Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * NODE_SIZE));
3981708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
3991708Sstevel 	PR_NODE("sgfru:%s: FRU_INFO_SIZE %lu NODE_SIZE %lu size %lu\n",
4001708Sstevel 	    f, FRU_INFO_SIZE, NODE_SIZE, size);
4011708Sstevel 	PR_NODE("sgfru:%s: handle %lx cnt %d buffer 0x%p\n", f,
4021708Sstevel 	    clist.fru_hdl, clist.fru_cnt, clist.frus);
4031708Sstevel 
4041708Sstevel 	/* call mailbox */
4051708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &clist.fru_info))
4061708Sstevel 	    != 0) {
4071708Sstevel 		kmem_free(datap, size);
4081708Sstevel 		return (ret);
4091708Sstevel 	}
4101708Sstevel 
4111708Sstevel 	/* allocate buffer for padded node_t's */
4121708Sstevel 	ssize = (size_t)(max_cnt * sizeof (node_t));
4131708Sstevel 	clistp = (node_t *)kmem_zalloc(ssize, KM_SLEEP);
4141708Sstevel 
4151708Sstevel 	/* translate unpadded to padded fru_info_t + node_t's */
4161708Sstevel 	if ((ret = sgfru_node_pad(datap, max_cnt, &clist.fru_info, clistp))
4171708Sstevel 	    != 0) {
4181708Sstevel 		kmem_free(datap, size);
4191708Sstevel 		kmem_free(clistp, ssize);
4201708Sstevel 		return (ret);
4211708Sstevel 	}
4221708Sstevel 	/* free node_t buffer */
4231708Sstevel 	kmem_free(datap, size);
4241708Sstevel 
4251708Sstevel 	/* copy out fru_info_t */
4261708Sstevel 	if (sgfru_copyout_fru(iargp, &clist.fru_info) != 0) {
4271708Sstevel 		kmem_free(clistp, ssize);
4281708Sstevel 		return (EFAULT);
4291708Sstevel 	}
4301708Sstevel 	/* copyout node_t's */
4311708Sstevel 	if (sgfru_copyout_nodes(iargp, &clist, clistp) != 0) {
4321708Sstevel 		kmem_free(clistp, ssize);
4331708Sstevel 		return (EFAULT);
4341708Sstevel 	}
4351708Sstevel 	/* free node_t buffer */
4361708Sstevel 	kmem_free(clistp, ssize);
4371708Sstevel 
4381708Sstevel 	return (ret);
4391708Sstevel }
4401708Sstevel 
4411708Sstevel /*
4421708Sstevel  * Used for private SGFRU_GETCHILDHANDLES ioctl.
4431708Sstevel  */
4441708Sstevel static int
sgfru_getchildhandles(const sgfru_init_arg_t * iargp)4451708Sstevel sgfru_getchildhandles(const sgfru_init_arg_t *iargp)
4461708Sstevel {
4471708Sstevel 	int32_t ret;
4481708Sstevel 	size_t size;
4491708Sstevel 	caddr_t datap, tdatap;
4501708Sstevel 	frup_info_t hdls;
4511708Sstevel 	fru_info_t hinfo;
4521708Sstevel 	fru_cnt_t max_cnt;
4531708Sstevel 	static fn_t f = "sgfru_getchildhandles";
4541708Sstevel 
4551708Sstevel 	/* copyin handles_t aka frup_info_t */
4561708Sstevel 	if (sgfru_copyin_frup(iargp, &hdls) != 0) {
4571708Sstevel 		return (EFAULT);
4581708Sstevel 	}
4591708Sstevel 	PR_HANDLE("sgfru:%s: handle %lx\n", f, hdls.fru_hdl);
4601708Sstevel 
4611708Sstevel 	/* check on kmem_alloc space requirements */
4621708Sstevel 	max_cnt = hdls.fru_cnt;
4631708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
4641708Sstevel 		return (EINVAL);
4651708Sstevel 	}
4661708Sstevel 
4671708Sstevel 	/* allocate buffer for child fru_hdl_t's */
4681708Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * FRU_HDL_SIZE));
4691708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
4701708Sstevel 
4711708Sstevel 	/* call mailbox */
4721708Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &hdls.fru_info);
4731708Sstevel 	if (ret != 0) {
4741708Sstevel 		kmem_free(datap, size);
4751708Sstevel 		return (ret);
4761708Sstevel 	}
4771708Sstevel 
4781708Sstevel 	/* translate unpadded to fru_info_t */
4791708Sstevel 	tdatap = sgfru_fru_pad(datap, &hinfo);
4801708Sstevel 
4811708Sstevel 	/* copyout actual fru_cnt */
4821708Sstevel 	if (sgfru_copyout_fru(iargp, &hinfo) != 0) {
4831708Sstevel 		kmem_free(datap, size);
4841708Sstevel 		return (EFAULT);
4851708Sstevel 	}
4861708Sstevel 	PR_HANDLE("sgfru:%s: count %x\n", f, hinfo.cnt);
4871708Sstevel 
4881708Sstevel 	/* copyout fru_hdl_t's */
4891708Sstevel 	if (sgfru_copyout_handles(iargp, &hdls, (fru_hdl_t *)tdatap) != 0) {
4901708Sstevel 		kmem_free(datap, size);
4911708Sstevel 		return (EFAULT);
4921708Sstevel 	}
4931708Sstevel 
4941708Sstevel 	/* free datap buffer */
4951708Sstevel 	kmem_free(datap, size);
4961708Sstevel 
4971708Sstevel 	return (ret);
4981708Sstevel }
4991708Sstevel 
5001708Sstevel /*
5011708Sstevel  * Used for private SGFRU_GETNODEINFO ioctl.
5021708Sstevel  */
5031708Sstevel static int
sgfru_getnodeinfo(const sgfru_init_arg_t * iargp)5041708Sstevel sgfru_getnodeinfo(const sgfru_init_arg_t *iargp)
5051708Sstevel {
5061708Sstevel 	int32_t ret;
5071708Sstevel 	caddr_t datap;
5081708Sstevel 	size_t size;
5091708Sstevel 	frup_info_t nodeinfo;
5101708Sstevel 	node_t node;
5111708Sstevel 	static fn_t f = "sgfru_getnodeinfo";
5121708Sstevel 
5131708Sstevel 	/* copyin node_info_t aka frup_info_t */
5141708Sstevel 	if (sgfru_copyin_frup(iargp, &nodeinfo) != 0) {
5151708Sstevel 		return (EFAULT);
5161708Sstevel 	}
5171708Sstevel 
5181708Sstevel 	/* allocate unpadded buffer for node_t */
5191708Sstevel 	size = (size_t)(NODE_SIZE);
5201708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
5211708Sstevel 
5221708Sstevel 	PR_NODE("sgfru:%s: handle %lx size 0x%lx\n", f, nodeinfo.fru_hdl, size);
5231708Sstevel 	/* call mailbox */
5241708Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &nodeinfo.fru_info);
5251708Sstevel 	if (ret != 0) {
5261708Sstevel 		kmem_free(datap, size);
5271708Sstevel 		return (ret);
5281708Sstevel 	}
5291708Sstevel 
5301708Sstevel 	/* translate unpadded to padded node_t */
5311708Sstevel 	if ((ret = sgfru_node_pad(datap, 0, NULL, &node))
5321708Sstevel 	    != 0) {
5331708Sstevel 		kmem_free(datap, size);
5341708Sstevel 		return (ret);
5351708Sstevel 	}
5361708Sstevel 
5371708Sstevel 	/* free node_t buffer */
5381708Sstevel 	kmem_free(datap, size);
5391708Sstevel 
5401708Sstevel 	/* copyout node_t */
5411708Sstevel 	if (sgfru_copyout_nodes(iargp, &nodeinfo, &node) != 0) {
5421708Sstevel 		return (EFAULT);
5431708Sstevel 	}
5441708Sstevel 	PR_NODE("sgfru:%s: handle %lx nodename %s has_children %d class %d\n",
5451708Sstevel 	    f, node.handle, node.nodename, node.has_children, node.class);
5461708Sstevel 
5471708Sstevel 	return (ret);
5481708Sstevel }
5491708Sstevel 
5501708Sstevel /*
5511708Sstevel  * Used for fru_get_sections().
5521708Sstevel  */
5531708Sstevel static int
sgfru_getsections(const sgfru_init_arg_t * iargp)5541708Sstevel sgfru_getsections(const sgfru_init_arg_t *iargp)
5551708Sstevel {
5561708Sstevel 	int32_t ret;
5571708Sstevel 	caddr_t datap;
5581708Sstevel 	size_t ssize, size;
5591708Sstevel 	frup_info_t sects;
5601708Sstevel 	fru_cnt_t max_cnt;
5611708Sstevel 	section_t *sectp;
5621708Sstevel 
5631708Sstevel 	/* copyin sections_t aka frup_info_t */
5641708Sstevel 	if (sgfru_copyin_frup(iargp, &sects) != 0) {
5651708Sstevel 		return (EFAULT);
5661708Sstevel 	}
5671708Sstevel 	/* check on kmem_alloc space requirements */
5681708Sstevel 	max_cnt = sects.fru_cnt;
5691708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SECTIONS)) {
5701708Sstevel 		return (EINVAL);
5711708Sstevel 	}
5721708Sstevel 
5731708Sstevel 	/* allocate buffer for unpadded fru_info_t + section_t's */
5741708Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SECTION_SIZE));
5751708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
5761708Sstevel 
5771708Sstevel 	/* call mailbox */
5781708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &sects.fru_info))
5791708Sstevel 	    != 0) {
5801708Sstevel 		kmem_free(datap, size);
5811708Sstevel 		return (ret);
5821708Sstevel 	}
5831708Sstevel 
5841708Sstevel 	/* allocate buffer for padded section_t's */
5851708Sstevel 	ssize = (size_t)(max_cnt * sizeof (section_t));
5861708Sstevel 	sectp = (section_t *)kmem_zalloc(ssize, KM_SLEEP);
5871708Sstevel 
5881708Sstevel 	/* translate unpadded to padded fru_info_t + section_t's */
5891708Sstevel 	if ((ret = sgfru_section_pad(datap, max_cnt, &sects.fru_info, sectp))
5901708Sstevel 	    != 0) {
5911708Sstevel 		kmem_free(datap, size);
5921708Sstevel 		kmem_free(sectp, ssize);
5931708Sstevel 		return (ret);
5941708Sstevel 	}
5951708Sstevel 	/* free section_t buffer */
5961708Sstevel 	kmem_free(datap, size);
5971708Sstevel 
5981708Sstevel 	/* copy out fru_info_t */
5991708Sstevel 	if (sgfru_copyout_fru(iargp, &sects.fru_info) != 0) {
6001708Sstevel 		kmem_free(sectp, ssize);
6011708Sstevel 		return (EFAULT);
6021708Sstevel 	}
6031708Sstevel 	/* copyout section_t's */
6041708Sstevel 	if (sgfru_copyout_sections(iargp, &sects, sectp) != 0) {
6051708Sstevel 		kmem_free(sectp, ssize);
6061708Sstevel 		return (EFAULT);
6071708Sstevel 	}
6081708Sstevel 	/* free section_t buffer */
6091708Sstevel 	kmem_free(sectp, ssize);
6101708Sstevel 
6111708Sstevel 	return (ret);
6121708Sstevel }
6131708Sstevel 
6141708Sstevel /*
6151708Sstevel  * Used for fru_get_segments().
6161708Sstevel  */
6171708Sstevel static int
sgfru_getsegments(const sgfru_init_arg_t * iargp)6181708Sstevel sgfru_getsegments(const sgfru_init_arg_t *iargp)
6191708Sstevel {
6201708Sstevel 	int32_t ret;
6211708Sstevel 	caddr_t datap;
6221708Sstevel 	size_t ssize, size;
6231708Sstevel 	frup_info_t segs;
6241708Sstevel 	fru_cnt_t max_cnt;
6251708Sstevel 	segment_t *segp;
6261708Sstevel 
6271708Sstevel 	/* copyin frup_info_t */
6281708Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
6291708Sstevel 		return (EFAULT);
6301708Sstevel 	}
6311708Sstevel 	/* check on kmem_alloc space requirements */
6321708Sstevel 	max_cnt = segs.fru_cnt;
6331708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTS)) {
6341708Sstevel 		return (EINVAL);
6351708Sstevel 	}
6361708Sstevel 
6371708Sstevel 	/* allocate unpadded buffer for fru_info_t + segment_t's */
6381708Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SEGMENT_SIZE));
6391708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
6401708Sstevel 
6411708Sstevel 	/* call mailbox */
6421708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
6431708Sstevel 		kmem_free(datap, size);
6441708Sstevel 		return (ret);
6451708Sstevel 	}
6461708Sstevel 
6471708Sstevel 	/* allocate buffer for padded segment_t's */
6481708Sstevel 	ssize = (size_t)(max_cnt * sizeof (segment_t));
6491708Sstevel 	segp = (segment_t *)kmem_zalloc(ssize, KM_SLEEP);
6501708Sstevel 
6511708Sstevel 	/* translate unpadded to padded fru_info_t + segment_t's */
6521708Sstevel 	if ((ret = sgfru_segment_pad(datap, max_cnt, &segs.fru_info, segp))
6531708Sstevel 	    != 0) {
6541708Sstevel 		kmem_free(datap, size);
6551708Sstevel 		kmem_free(segp, ssize);
6561708Sstevel 		return (ret);
6571708Sstevel 	}
6581708Sstevel 	/* free segment_t buffer */
6591708Sstevel 	kmem_free(datap, size);
6601708Sstevel 
6611708Sstevel 	/* copy out fru_info_t */
6621708Sstevel 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
6631708Sstevel 		kmem_free(segp, ssize);
6641708Sstevel 		return (EFAULT);
6651708Sstevel 	}
6661708Sstevel 	/* copyout segment_t's */
6671708Sstevel 	if (sgfru_copyout_segments(iargp, &segs, segp) != 0) {
6681708Sstevel 		kmem_free(segp, ssize);
6691708Sstevel 		return (EFAULT);
6701708Sstevel 	}
6711708Sstevel 	/* free segment_t buffer */
6721708Sstevel 	kmem_free(segp, ssize);
6731708Sstevel 
6741708Sstevel 	return (ret);
6751708Sstevel }
6761708Sstevel 
6771708Sstevel static int
sgfru_addsegment(const sgfru_init_arg_t * iargp)6781708Sstevel sgfru_addsegment(const sgfru_init_arg_t *iargp)
6791708Sstevel {
6801708Sstevel 	int32_t ret;
6811708Sstevel 	caddr_t datap;
6821708Sstevel 	size_t size;
6831708Sstevel 	frup_info_t seg;
6841708Sstevel 	segment_t segment;
6851708Sstevel 	fru_hdl_t *hdlp;
6861708Sstevel 	static fn_t f = "sgfru_addsegment";
6871708Sstevel 
6881708Sstevel 	/* copyin frup_info_t */
6891708Sstevel 	if (sgfru_copyin_frup(iargp, &seg) != 0) {
6901708Sstevel 		return (EFAULT);
6911708Sstevel 	}
6921708Sstevel 	/* copyin segment_t */
6931708Sstevel 	if (sgfru_copyin_segment(iargp, &seg, &segment) != 0) {
6941708Sstevel 		return (EFAULT);
6951708Sstevel 	}
6961708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
697*7656SSherry.Moore@Sun.COM 	    f, seg.fru_hdl, seg.fru_cnt);
6981708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, "
699*7656SSherry.Moore@Sun.COM 	    "offset 0x%x, length 0x%x\n", f, segment.handle, segment.name,
700*7656SSherry.Moore@Sun.COM 	    segment.descriptor, segment.offset, segment.length);
7011708Sstevel 
7021708Sstevel 	/* allocate buffer for unpadded section_hdl_t + segment_t */
7031708Sstevel 	size = (size_t)(SECTION_HDL_SIZE + SEGMENT_SIZE);
7041708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
7051708Sstevel 	/* translate padded to unpadded section_hdl_t + segment_t */
7061708Sstevel 	sgfru_segment_unpad(&seg.fru_info, &segment, datap);
7071708Sstevel 
7081708Sstevel 	/* call mailbox */
7091708Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &seg.fru_info);
7101708Sstevel 	if (ret != 0) {
7111708Sstevel 		kmem_free(datap, size);
7121708Sstevel 		return (ret);
7131708Sstevel 	}
7141708Sstevel 
7151708Sstevel 	/* copyout updated section_hdl_t */
7161708Sstevel 	hdlp = (fru_hdl_t *)(datap + sizeof (fru_hdl_t));
7171708Sstevel 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
7181708Sstevel 		kmem_free(datap, size);
7191708Sstevel 		return (EFAULT);
7201708Sstevel 	}
7211708Sstevel 	/* copyout new segment_hdl_t */
7221708Sstevel 	if (sgfru_copyout_handle(iargp, seg.frus, --hdlp) != 0) {
7231708Sstevel 		kmem_free(datap, size);
7241708Sstevel 		return (EFAULT);
7251708Sstevel 	}
7261708Sstevel 	/* free segment_t buffer */
7271708Sstevel 	kmem_free(datap, size);
7281708Sstevel 
7291708Sstevel 	return (ret);
7301708Sstevel }
7311708Sstevel 
7321708Sstevel /*
7331708Sstevel  * Used for fru_read_segment().
7341708Sstevel  */
7351708Sstevel static int
sgfru_readsegment(const sgfru_init_arg_t * iargp)7361708Sstevel sgfru_readsegment(const sgfru_init_arg_t *iargp)
7371708Sstevel {
7381708Sstevel 	int32_t ret;
7391708Sstevel 	caddr_t datap, tdatap;
7401708Sstevel 	size_t size;
7411708Sstevel 	frup_info_t segs;
7421708Sstevel 	fru_info_t sinfo;
7431708Sstevel 	fru_cnt_t max_cnt;
7441708Sstevel 	static fn_t f = "sgfru_readsegment";
7451708Sstevel 
7461708Sstevel 	/* copyin one segments_t aka frup_info_t */
7471708Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
7481708Sstevel 		return (EFAULT);
7491708Sstevel 	}
7501708Sstevel 	/* check on kmem_alloc space requirements */
7511708Sstevel 	max_cnt = segs.fru_cnt;
7521708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
7531708Sstevel 		return (EINVAL);
7541708Sstevel 	}
7551708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
756*7656SSherry.Moore@Sun.COM 	    f, segs.fru_hdl, segs.fru_cnt);
7571708Sstevel 
7581708Sstevel 	/* allocate unpadded buffer for raw data */
7591708Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
7601708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
7611708Sstevel 
7621708Sstevel 	/* call mailbox */
7631708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
7641708Sstevel 		kmem_free(datap, size);
7651708Sstevel 		return (ret);
7661708Sstevel 	}
7671708Sstevel 
7681708Sstevel 	/* translate unpadded to padded fru_info_t */
7691708Sstevel 	tdatap = sgfru_fru_pad(datap, &sinfo);
7701708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
771*7656SSherry.Moore@Sun.COM 	    f, sinfo.hdl, sinfo.cnt);
7721708Sstevel 
7731708Sstevel 	/* copyout actual fru_cnt */
7741708Sstevel 	if (sgfru_copyout_fru(iargp, &sinfo) != 0) {
7751708Sstevel 		kmem_free(datap, size);
7761708Sstevel 		return (EFAULT);
7771708Sstevel 	}
7781708Sstevel 	/* copyout raw segment data */
7791708Sstevel 	if (sgfru_copyout_buffer(iargp, &segs, tdatap) != 0) {
7801708Sstevel 		kmem_free(datap, size);
7811708Sstevel 		return (EFAULT);
7821708Sstevel 	}
7831708Sstevel 	/* free buffer */
7841708Sstevel 	kmem_free(datap, size);
7851708Sstevel 
7861708Sstevel 	return (ret);
7871708Sstevel }
7881708Sstevel 
7891708Sstevel /*
7901708Sstevel  * Used for fru_write_segment().
7911708Sstevel  */
7921708Sstevel static int
sgfru_writesegment(const sgfru_init_arg_t * iargp)7931708Sstevel sgfru_writesegment(const sgfru_init_arg_t *iargp)
7941708Sstevel {
7951708Sstevel 	int32_t ret;
7961708Sstevel 	caddr_t datap, tdatap;
7971708Sstevel 	size_t size;
7981708Sstevel 	frup_info_t segs;
7991708Sstevel 	fru_cnt_t max_cnt;
8001708Sstevel 	static fn_t f = "sgfru_writesegment";
8011708Sstevel 
8021708Sstevel 	/* copyin frup_info_t */
8031708Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
8041708Sstevel 		return (EFAULT);
8051708Sstevel 	}
8061708Sstevel 	/* check on kmem_alloc space requirements */
8071708Sstevel 	max_cnt = segs.fru_cnt;
8081708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
8091708Sstevel 		return (EINVAL);
8101708Sstevel 	}
8111708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
812*7656SSherry.Moore@Sun.COM 	    f, segs.fru_hdl, segs.fru_cnt);
8131708Sstevel 
8141708Sstevel 	/* allocate unpadded buffer for fru_info_t + raw data */
8151708Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
8161708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
8171708Sstevel 
8181708Sstevel 	/* translate padded to unpadded fru_info_t */
8191708Sstevel 	tdatap = sgfru_fru_unpad(&segs.fru_info, datap);
8201708Sstevel 
8211708Sstevel 	/* copyin raw segment data */
8221708Sstevel 	if (sgfru_copyin_buffer(iargp, segs.frus, max_cnt, tdatap) != 0) {
8231708Sstevel 		kmem_free(datap, size);
8241708Sstevel 		return (EFAULT);
8251708Sstevel 	}
8261708Sstevel 
8271708Sstevel 	/* call mailbox */
8281708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
8291708Sstevel 		kmem_free(datap, size);
8301708Sstevel 		return (ret);
8311708Sstevel 	}
8321708Sstevel 	/* free buffer */
8331708Sstevel 	kmem_free(datap, size);
8341708Sstevel 
8351708Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
836*7656SSherry.Moore@Sun.COM 	    f, segs.fru_hdl, segs.fru_cnt);
8371708Sstevel 	/* copyout updated segment handle and actual fru_cnt */
8381708Sstevel 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
8391708Sstevel 		return (EFAULT);
8401708Sstevel 	}
8411708Sstevel 
8421708Sstevel 	return (ret);
8431708Sstevel }
8441708Sstevel 
8451708Sstevel /*
8461708Sstevel  * Used for fru_get_packets().
8471708Sstevel  */
8481708Sstevel static int
sgfru_getpackets(const sgfru_init_arg_t * iargp)8491708Sstevel sgfru_getpackets(const sgfru_init_arg_t *iargp)
8501708Sstevel {
8511708Sstevel 	int32_t ret;
8521708Sstevel 	caddr_t datap;
8531708Sstevel 	size_t ssize, size;
8541708Sstevel 	frup_info_t packs;
8551708Sstevel 	fru_cnt_t max_cnt;
8561708Sstevel 	packet_t *packp;
8571708Sstevel 
8581708Sstevel 	/* copyin packets_t aka frup_info_t */
8591708Sstevel 	if (sgfru_copyin_frup(iargp, &packs) != 0) {
8601708Sstevel 		return (EFAULT);
8611708Sstevel 	}
8621708Sstevel 	/* check on kmem_alloc space requirements */
8631708Sstevel 	max_cnt = packs.fru_cnt;
8641708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PACKETS)) {
8651708Sstevel 		return (EINVAL);
8661708Sstevel 	}
8671708Sstevel 
8681708Sstevel 	/* allocate buffer for unpadded fru_info_t + packet_t's */
8691708Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * PACKET_SIZE));
8701708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
8711708Sstevel 
8721708Sstevel 	/* call mailbox */
8731708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &packs.fru_info))
8741708Sstevel 	    != 0) {
8751708Sstevel 		kmem_free(datap, size);
8761708Sstevel 		return (ret);
8771708Sstevel 	}
8781708Sstevel 
8791708Sstevel 	/* allocate buffer for padded packet_t's */
8801708Sstevel 	ssize = (size_t)(max_cnt * sizeof (packet_t));
8811708Sstevel 	packp = (packet_t *)kmem_zalloc(ssize, KM_SLEEP);
8821708Sstevel 
8831708Sstevel 	/* translate unpadded to padded fru_info_t + packet_t's */
8841708Sstevel 	if ((ret = sgfru_packet_pad(datap, max_cnt, &packs.fru_info, packp))
8851708Sstevel 	    != 0) {
8861708Sstevel 		kmem_free(datap, size);
8871708Sstevel 		kmem_free(packp, ssize);
8881708Sstevel 		return (ret);
8891708Sstevel 	}
8901708Sstevel 	/* free packet_t buffer */
8911708Sstevel 	kmem_free(datap, size);
8921708Sstevel 
8931708Sstevel 	/* copy out fru_info_t */
8941708Sstevel 	if (sgfru_copyout_fru(iargp, &packs.fru_info) != 0) {
8951708Sstevel 		kmem_free(packp, ssize);
8961708Sstevel 		return (EFAULT);
8971708Sstevel 	}
8981708Sstevel 	/* copyout packet_t's */
8991708Sstevel 	if (sgfru_copyout_packets(iargp, &packs, packp) != 0) {
9001708Sstevel 		kmem_free(packp, ssize);
9011708Sstevel 		return (EFAULT);
9021708Sstevel 	}
9031708Sstevel 	/* free packet_t buffer */
9041708Sstevel 	kmem_free(packp, ssize);
9051708Sstevel 
9061708Sstevel 	return (ret);
9071708Sstevel }
9081708Sstevel 
9091708Sstevel /*
9101708Sstevel  * Used for fru_append_packet().
9111708Sstevel  */
9121708Sstevel static int
sgfru_appendpacket(const sgfru_init_arg_t * iargp)9131708Sstevel sgfru_appendpacket(const sgfru_init_arg_t *iargp)
9141708Sstevel {
9151708Sstevel 	int32_t ret = 0;
9161708Sstevel 	caddr_t datap, tdatap;
9171708Sstevel 	size_t size;
9181708Sstevel 	append_info_t append;
9191708Sstevel 	fru_cnt_t max_cnt;
9201708Sstevel 	fru_hdl_t *hdlp;
9211708Sstevel 	caddr_t addr;
9221708Sstevel 
9231708Sstevel 	/* copyin append_info_t */
9241708Sstevel 	if (sgfru_copyin_append(iargp, &append) != 0) {
9251708Sstevel 		return (EFAULT);
9261708Sstevel 	}
9271708Sstevel 	/* check on kmem_alloc space requirements */
9281708Sstevel 	max_cnt = append.payload_cnt;
9291708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
9301708Sstevel 		return (EINVAL);
9311708Sstevel 	}
9321708Sstevel 
9331708Sstevel 	/* allocate buffer for unpadded fru_info_t + packet_t + payload */
9341708Sstevel 	size = (size_t)(FRU_INFO_SIZE + PACKET_SIZE + max_cnt);
9351708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
9361708Sstevel 	/* translate padded to unpadded fru_info_t plus packet_t */
9371708Sstevel 	tdatap = sgfru_packet_unpad(&append.payload.fru_info, &append.packet,
9381708Sstevel 	    datap);
9391708Sstevel 
9401708Sstevel 	/* copyin payload to the end of the unpadded buffer */
9411708Sstevel 	if (sgfru_copyin_buffer(iargp, append.payload_data, append.payload_cnt,
9421708Sstevel 	    tdatap) != 0) {
9431708Sstevel 		kmem_free(datap, size);
9441708Sstevel 		return (EFAULT);
9451708Sstevel 	}
9461708Sstevel 
9471708Sstevel 	/* call mailbox */
9481708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size,
9491708Sstevel 	    &append.payload.fru_info)) != 0) {
9501708Sstevel 		kmem_free(datap, size);
9511708Sstevel 		return (ret);
9521708Sstevel 	}
9531708Sstevel 
9541708Sstevel 	/* copyout new packet_hdl_t */
9551708Sstevel 	hdlp = (fru_hdl_t *)datap;
9561708Sstevel 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
9571708Sstevel 		kmem_free(datap, size);
9581708Sstevel 		return (EFAULT);
9591708Sstevel 	}
9601708Sstevel 	/* copyout updated segment_hdl_t */
9611708Sstevel 	addr = (caddr_t)(iargp->argp + sizeof (packet_t));
9621708Sstevel 	if (sgfru_copyout_handle(iargp, addr, ++hdlp) != 0) {
9631708Sstevel 		kmem_free(datap, size);
9641708Sstevel 		return (EFAULT);
9651708Sstevel 	}
9661708Sstevel 
9671708Sstevel 	/* free buffer */
9681708Sstevel 	kmem_free(datap, size);
9691708Sstevel 
9701708Sstevel 	return (ret);
9711708Sstevel }
9721708Sstevel 
9731708Sstevel /*
9741708Sstevel  * Used for fru_get_payload().
9751708Sstevel  */
9761708Sstevel static int
sgfru_getpayload(const sgfru_init_arg_t * iargp)9771708Sstevel sgfru_getpayload(const sgfru_init_arg_t *iargp)
9781708Sstevel {
9791708Sstevel 	int32_t ret;
9801708Sstevel 	caddr_t datap, tdatap;
9811708Sstevel 	size_t size;
9821708Sstevel 	frup_info_t payld;
9831708Sstevel 	fru_info_t pinfo;
9841708Sstevel 	fru_cnt_t max_cnt;
9851708Sstevel 	static fn_t f = "sgfru_getpayload";
9861708Sstevel 
9871708Sstevel 	/* copyin payload_t aka frup_info_t */
9881708Sstevel 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
9891708Sstevel 		return (EFAULT);
9901708Sstevel 	}
9911708Sstevel 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
992*7656SSherry.Moore@Sun.COM 	    f, payld.fru_hdl, payld.fru_cnt);
9931708Sstevel 
9941708Sstevel 	/* check on kmem_alloc space requirements */
9951708Sstevel 	max_cnt = payld.fru_cnt;
9961708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
9971708Sstevel 		return (EINVAL);
9981708Sstevel 	}
9991708Sstevel 
10001708Sstevel 	/* allocate buffer for fru_info_t + payload */
10011708Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
10021708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
10031708Sstevel 
10041708Sstevel 	/* call mailbox */
10051708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
10061708Sstevel 	    != 0) {
10071708Sstevel 		kmem_free(datap, size);
10081708Sstevel 		return (ret);
10091708Sstevel 	}
10101708Sstevel 
10111708Sstevel 	/* translate unpadded to padded fru_info_t */
10121708Sstevel 	tdatap = sgfru_fru_pad(datap, &pinfo);
10131708Sstevel 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
1014*7656SSherry.Moore@Sun.COM 	    f, pinfo.hdl, pinfo.cnt);
10151708Sstevel 
10161708Sstevel 	/* copyout actual fru_cnt */
10171708Sstevel 	if (sgfru_copyout_fru(iargp, &pinfo) != 0) {
10181708Sstevel 		kmem_free(datap, size);
10191708Sstevel 		return (EFAULT);
10201708Sstevel 	}
10211708Sstevel 	/* copyout raw packet data, aka the payload */
10221708Sstevel 	if (sgfru_copyout_buffer(iargp, &payld, tdatap) != 0) {
10231708Sstevel 		kmem_free(datap, size);
10241708Sstevel 		return (EFAULT);
10251708Sstevel 	}
10261708Sstevel 
10271708Sstevel 	/* free buffer */
10281708Sstevel 	kmem_free(datap, size);
10291708Sstevel 
10301708Sstevel 	return (ret);
10311708Sstevel }
10321708Sstevel 
10331708Sstevel /*
10341708Sstevel  * Used for fru_update_payload().
10351708Sstevel  */
10361708Sstevel static int
sgfru_updatepayload(const sgfru_init_arg_t * iargp)10371708Sstevel sgfru_updatepayload(const sgfru_init_arg_t *iargp)
10381708Sstevel {
10391708Sstevel 	int32_t ret;
10401708Sstevel 	caddr_t datap, tdatap;
10411708Sstevel 	size_t size;
10421708Sstevel 	frup_info_t payld;
10431708Sstevel 	fru_cnt_t max_cnt;
10441708Sstevel 	static fn_t f = "sgfru_updatepayload";
10451708Sstevel 
10461708Sstevel 	/* copyin frup_info_t */
10471708Sstevel 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
10481708Sstevel 		return (EFAULT);
10491708Sstevel 	}
10501708Sstevel 	/* check on kmem_alloc space requirements */
10511708Sstevel 	max_cnt = payld.fru_cnt;
10521708Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
10531708Sstevel 		return (EINVAL);
10541708Sstevel 	}
10551708Sstevel 
10561708Sstevel 	/* allocate buffer for fru_info_t + payload */
10571708Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
10581708Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
10591708Sstevel 
10601708Sstevel 	/* translate padded to unpadded fru_info_t */
10611708Sstevel 	tdatap = sgfru_fru_unpad(&payld.fru_info, datap);
10621708Sstevel 
10631708Sstevel 	/* copyin payload */
10641708Sstevel 	if (sgfru_copyin_buffer(iargp, payld.frus, max_cnt, tdatap) != 0) {
10651708Sstevel 		kmem_free(datap, size);
10661708Sstevel 		return (EFAULT);
10671708Sstevel 	}
10681708Sstevel 	PR_PAYLOAD("sgfru_updatepayload: handle %lx, actual cnt %d\n",
1069*7656SSherry.Moore@Sun.COM 	    payld.fru_hdl, payld.fru_cnt);
10701708Sstevel 
10711708Sstevel 	/* call mailbox */
10721708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
10731708Sstevel 	    != 0) {
10741708Sstevel 		kmem_free(datap, size);
10751708Sstevel 		return (ret);
10761708Sstevel 	}
10771708Sstevel 
10781708Sstevel 	/* free buffer */
10791708Sstevel 	kmem_free(datap, size);
10801708Sstevel 
10811708Sstevel 	/* copyout new packet_hdl_t and actual count */
10821708Sstevel 	if (sgfru_copyout_fru(iargp, &payld.fru_info) != 0) {
10831708Sstevel 		return (EFAULT);
10841708Sstevel 	}
10851708Sstevel 	PR_PAYLOAD("sgfru:%s: new handle %lx, cnt %d\n",
1086*7656SSherry.Moore@Sun.COM 	    f, payld.fru_hdl, payld.fru_cnt);
10871708Sstevel 
10881708Sstevel 	return (ret);
10891708Sstevel }
10901708Sstevel 
10911708Sstevel /*
10921708Sstevel  * Used for fru_get_num_[sections|segments|packets]().
10931708Sstevel  */
10941708Sstevel static int
sgfru_getnum(const sgfru_init_arg_t * iargp)10951708Sstevel sgfru_getnum(const sgfru_init_arg_t *iargp)
10961708Sstevel {
10971708Sstevel 	int32_t ret;
10981708Sstevel 	caddr_t datap;
10991708Sstevel 	size_t size;
11001708Sstevel 	fru_info_t fru_info;
11011708Sstevel 
11021708Sstevel 	/* copyin fru_info_t */
11031708Sstevel 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
11041708Sstevel 		return (EFAULT);
11051708Sstevel 	}
11061708Sstevel 
11071708Sstevel 	size = sizeof (fru_cnt_t);
11081708Sstevel 	datap = (caddr_t)&fru_info.cnt;
11091708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
11101708Sstevel 		return (ret);
11111708Sstevel 	}
11121708Sstevel 
11131708Sstevel 	/* copyout fru_info_t */
11141708Sstevel 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
11151708Sstevel 		return (EFAULT);
11161708Sstevel 	}
11171708Sstevel 	return (ret);
11181708Sstevel }
11191708Sstevel 
11201708Sstevel /*
11211708Sstevel  * Used for fru_delete_[segment|packet].
11221708Sstevel  */
11231708Sstevel static int
sgfru_delete(const sgfru_init_arg_t * iargp)11241708Sstevel sgfru_delete(const sgfru_init_arg_t *iargp)
11251708Sstevel {
11261708Sstevel 	int32_t ret;
11271708Sstevel 	caddr_t datap;
11281708Sstevel 	size_t size;
11291708Sstevel 	fru_info_t fru_info;
11301708Sstevel 	static fn_t f = "sgfru_delete";
11311708Sstevel 
11321708Sstevel 	/* copyin fru_info_t */
11331708Sstevel 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
11341708Sstevel 		return (EFAULT);
11351708Sstevel 	}
11361708Sstevel 	PR_SEGMENT("sgfru:%s: delete handle %lx\n", f, fru_info.hdl);
11371708Sstevel 
11381708Sstevel 	size = sizeof (fru_hdl_t);
11391708Sstevel 	datap = (caddr_t)&fru_info.hdl;
11401708Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
11411708Sstevel 		return (ret);
11421708Sstevel 	}
11431708Sstevel 
11441708Sstevel 	PR_SEGMENT("sgfru:%s: new parent handle %lx\n", f, fru_info.hdl);
11451708Sstevel 	/* copyout fru_info_t */
11461708Sstevel 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
11471708Sstevel 		return (EFAULT);
11481708Sstevel 	}
11491708Sstevel 	return (ret);
11501708Sstevel }
11511708Sstevel 
11521708Sstevel /*
11531708Sstevel  * Calls the sgsbbc mailbox with data, returns data and status info.
11541708Sstevel  */
11551708Sstevel static int
sgfru_mbox(const int cmd,char * datap,const size_t size,fru_info_t * fru)11561708Sstevel sgfru_mbox(const int cmd, char *datap, const size_t size, fru_info_t *fru)
11571708Sstevel {
11581708Sstevel 	sbbc_msg_t request, *reqp = &request;
11591708Sstevel 	sbbc_msg_t response, *resp = &response;
11601708Sstevel 	fru_hdl_t hdls[2] = {0, 0};
11611708Sstevel 	fru_hdl_t hdl = fru->hdl;
11621708Sstevel 	int rv = 0;
11631708Sstevel 	static fn_t f = "sgfru_mbox";
11641708Sstevel 
11651708Sstevel 	bzero((caddr_t)&request, sizeof (sbbc_msg_t));
11661708Sstevel 	reqp->msg_type.type = SGFRU_MBOX;
11671708Sstevel 	bzero((caddr_t)&response, sizeof (sbbc_msg_t));
11681708Sstevel 	resp->msg_type.type = SGFRU_MBOX;
11691708Sstevel 	PR_MBOX("sgfru:%s: cmd 0x%x, size %lu\n", f, cmd, size);
11701708Sstevel 
11711708Sstevel 	switch (cmd) {
11721708Sstevel 
11731708Sstevel 	case SGFRU_GETCHILDLIST:
11741708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
11751708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
11761708Sstevel 		reqp->msg_buf = (caddr_t)fru;
11771708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
11781708Sstevel 		resp->msg_len = size;
11791708Sstevel 		resp->msg_buf = datap;
11801708Sstevel 		break;
11811708Sstevel 
11821708Sstevel 	case SGFRU_GETCHILDHANDLES:
11831708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
11841708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
11851708Sstevel 		reqp->msg_buf = (caddr_t)fru;
11861708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
11871708Sstevel 		resp->msg_len = size;
11881708Sstevel 		resp->msg_buf = datap;
11891708Sstevel 		break;
11901708Sstevel 
11911708Sstevel 	case SGFRU_GETNODEINFO:
11921708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
11931708Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
11941708Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
11951708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
11961708Sstevel 		resp->msg_len = size;
11971708Sstevel 		resp->msg_buf = datap;
11981708Sstevel 		break;
11991708Sstevel 
12001708Sstevel 	case SGFRU_GETNUMSECTIONS:
12011708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
12021708Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
12031708Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
12041708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
12051708Sstevel 		resp->msg_len = size;
12061708Sstevel 		resp->msg_buf = datap;
12071708Sstevel 		break;
12081708Sstevel 
12091708Sstevel 	case SGFRU_GETNUMSEGMENTS:
12101708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
12111708Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
12121708Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
12131708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
12141708Sstevel 		resp->msg_len = size;
12151708Sstevel 		resp->msg_buf = datap;
12161708Sstevel 		break;
12171708Sstevel 
12181708Sstevel 	case SGFRU_GETNUMPACKETS:
12191708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
12201708Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
12211708Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
12221708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
12231708Sstevel 		resp->msg_len = size;
12241708Sstevel 		resp->msg_buf = datap;
12251708Sstevel 		break;
12261708Sstevel 
12271708Sstevel 	case SGFRU_GETSECTIONS:
12281708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
12291708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
12301708Sstevel 		reqp->msg_buf = (caddr_t)fru;
12311708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
12321708Sstevel 		resp->msg_len = size;
12331708Sstevel 		resp->msg_buf = datap;
12341708Sstevel 		break;
12351708Sstevel 
12361708Sstevel 	case SGFRU_GETSEGMENTS:
12371708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
12381708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
12391708Sstevel 		reqp->msg_buf = (caddr_t)fru;
12401708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
12411708Sstevel 		resp->msg_len = size;
12421708Sstevel 		resp->msg_buf = datap;
12431708Sstevel 		break;
12441708Sstevel 
12451708Sstevel 	case SGFRU_GETPACKETS:
12461708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
12471708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
12481708Sstevel 		reqp->msg_buf = (caddr_t)fru;
12491708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
12501708Sstevel 		resp->msg_len = size;
12511708Sstevel 		resp->msg_buf = datap;
12521708Sstevel 		break;
12531708Sstevel 
12541708Sstevel 	case SGFRU_ADDSEGMENT:
12551708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
12561708Sstevel 		reqp->msg_len = size;
12571708Sstevel 		reqp->msg_buf = datap;
12581708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
12591708Sstevel 		resp->msg_len = sizeof (hdls);
12601708Sstevel 		resp->msg_buf = (caddr_t)&hdls;
12611708Sstevel 		break;
12621708Sstevel 
12631708Sstevel 	case SGFRU_APPENDPACKET:
12641708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
12651708Sstevel 		reqp->msg_len = size;
12661708Sstevel 		reqp->msg_buf = (caddr_t)datap;
12671708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
12681708Sstevel 		resp->msg_len = sizeof (hdls);
12691708Sstevel 		resp->msg_buf = (caddr_t)&hdls;
12701708Sstevel 		break;
12711708Sstevel 
12721708Sstevel 	case SGFRU_DELETESEGMENT:
12731708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
12741708Sstevel 		reqp->msg_len = size;
12751708Sstevel 		reqp->msg_buf = (caddr_t)datap;
12761708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
12771708Sstevel 		resp->msg_len = sizeof (fru_hdl_t);
12781708Sstevel 		resp->msg_buf = (caddr_t)&hdl;
12791708Sstevel 		break;
12801708Sstevel 
12811708Sstevel 	case SGFRU_READRAWSEGMENT:
12821708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_READRAWSEGMENT;
12831708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
12841708Sstevel 		reqp->msg_buf = (caddr_t)fru;
12851708Sstevel 		resp->msg_type.sub_type = SGFRU_READRAWSEGMENT;
12861708Sstevel 		resp->msg_len = size;
12871708Sstevel 		resp->msg_buf = datap;
12881708Sstevel 		break;
12891708Sstevel 
12901708Sstevel 	case SGFRU_WRITERAWSEGMENT:
12911708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_WRITERAWSEGMENT;
12921708Sstevel 		reqp->msg_len = size;
12931708Sstevel 		reqp->msg_buf = datap;
12941708Sstevel 		resp->msg_type.sub_type = SGFRU_WRITERAWSEGMENT;
12951708Sstevel 		resp->msg_len = sizeof (fru_info_t);
12961708Sstevel 		resp->msg_buf = (caddr_t)fru;
12971708Sstevel 		break;
12981708Sstevel 
12991708Sstevel 	case SGFRU_DELETEPACKET:
13001708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
13011708Sstevel 		reqp->msg_len = size;
13021708Sstevel 		reqp->msg_buf = (caddr_t)datap;
13031708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
13041708Sstevel 		resp->msg_len = sizeof (fru_hdl_t);
13051708Sstevel 		resp->msg_buf = (caddr_t)&hdl;
13061708Sstevel 		break;
13071708Sstevel 
13081708Sstevel 	case SGFRU_GETPAYLOAD:
13091708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
13101708Sstevel 		reqp->msg_len = sizeof (fru_info_t);
13111708Sstevel 		reqp->msg_buf = (caddr_t)fru;
13121708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
13131708Sstevel 		resp->msg_len = size;
13141708Sstevel 		resp->msg_buf = datap;
13151708Sstevel 		break;
13161708Sstevel 
13171708Sstevel 	case SGFRU_UPDATEPAYLOAD:
13181708Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
13191708Sstevel 		reqp->msg_len = size;
13201708Sstevel 		reqp->msg_buf = datap;
13211708Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
13221708Sstevel 		resp->msg_len = sizeof (fru_info_t);
13231708Sstevel 		resp->msg_buf = (caddr_t)fru;
13241708Sstevel 		break;
13251708Sstevel 
13261708Sstevel 	default:
13271708Sstevel 		return (EINVAL);
13281708Sstevel 	}
13291708Sstevel 
13301708Sstevel 	rv = sbbc_mbox_request_response(reqp, resp, sgfru_mbox_wait);
13311708Sstevel 	PR_MBOX("sgfru:%s: rv %d, msg_status %d\n", f, rv, resp->msg_status);
13321708Sstevel 
13331708Sstevel 	if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
13341708Sstevel 
13351708Sstevel 		/* errors from sgsbbc */
13361708Sstevel 		if (resp->msg_status > 0) {
13371708Sstevel 			return (resp->msg_status);
13381708Sstevel 		}
13391708Sstevel 
13401708Sstevel 		/* errors from SCAPP */
13411708Sstevel 		switch (resp->msg_status) {
13421708Sstevel 
13431708Sstevel 		case SG_MBOX_STATUS_COMMAND_FAILURE:
13441708Sstevel 			/* internal SCAPP error */
13451708Sstevel 			return (EINTR);
13461708Sstevel 
13471708Sstevel 		case SG_MBOX_STATUS_HARDWARE_FAILURE:
13481708Sstevel 			/* seprom read/write errors */
13491708Sstevel 			return (EIO);
13501708Sstevel 
13511708Sstevel 		case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
13521708Sstevel 			/* illegal ioctl parameter */
13531708Sstevel 			return (EINVAL);
13541708Sstevel 
13551708Sstevel 		case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
13561708Sstevel 			/* board access denied */
13571708Sstevel 			return (EACCES);
13581708Sstevel 
13591708Sstevel 		case SG_MBOX_STATUS_STALE_CONTENTS:
13601708Sstevel 			/* stale contents */
13611708Sstevel 			return (ESTALE);
13621708Sstevel 
13631708Sstevel 		case SG_MBOX_STATUS_STALE_OBJECT:
13641708Sstevel 			/* stale handle */
13651708Sstevel 			return (ENOENT);
13661708Sstevel 
13671708Sstevel 		case SG_MBOX_STATUS_NO_SEPROM_SPACE:
13681708Sstevel 			/* seprom lacks space */
13691708Sstevel 			return (ENOSPC);
13701708Sstevel 
13711708Sstevel 		case SG_MBOX_STATUS_NO_MEMORY:
13721708Sstevel 			/* user prog. lacks space */
13731708Sstevel 			return (ENOMEM);
13741708Sstevel 
13751708Sstevel 		case SG_MBOX_STATUS_NOT_SUPPORTED:
13761708Sstevel 			/* unsupported operation */
13771708Sstevel 			return (ENOTSUP);
13781708Sstevel 
13791708Sstevel 		default:
13801708Sstevel 			return (EIO);
13811708Sstevel 		}
13821708Sstevel 	}
13831708Sstevel 
13841708Sstevel 	switch (cmd) {
13851708Sstevel 
13861708Sstevel 	/*
13871708Sstevel 	 * These two calls get back two handles, a new handle for the
13881708Sstevel 	 * added segment or packet, and an updated parent handle.
13891708Sstevel 	 */
13901708Sstevel 	case SGFRU_ADDSEGMENT:
13911708Sstevel 	case SGFRU_APPENDPACKET:
13921708Sstevel 		bcopy(hdls, datap, sizeof (hdls));
13931708Sstevel 		break;
13941708Sstevel 
13951708Sstevel 	/* These two calls get an updated parent handle. */
13961708Sstevel 	case SGFRU_DELETESEGMENT:
13971708Sstevel 	case SGFRU_DELETEPACKET:
13981708Sstevel 		fru->hdl = hdl;
13991708Sstevel 		break;
14001708Sstevel 
14011708Sstevel 	default:
14021708Sstevel 		break;
14031708Sstevel 	}
14041708Sstevel 
14051708Sstevel 	return (0);
14061708Sstevel }
14071708Sstevel 
14081708Sstevel /*
14091708Sstevel  * Used to copy in one frup_info_t from user.
14101708Sstevel  */
14111708Sstevel static int
sgfru_copyin_frup(const sgfru_init_arg_t * argp,frup_info_t * frup)14121708Sstevel sgfru_copyin_frup(const sgfru_init_arg_t *argp, frup_info_t *frup)
14131708Sstevel {
14141708Sstevel 	static fn_t f = "sgfru_copyin_frup";
14151708Sstevel 
14161708Sstevel 	bzero((caddr_t)frup, sizeof (frup_info_t));
14171708Sstevel #ifdef _MULTI_DATAMODEL
14181708Sstevel 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
14191708Sstevel 		frup32_info_t frup32;
14201708Sstevel 
14211708Sstevel 		bzero((caddr_t)&frup32, sizeof (frup32_info_t));
14221708Sstevel 		if (ddi_copyin((void *)argp->argp, (void *)&frup32,
14231708Sstevel 		    sizeof (frup32_info_t), argp->mode) != DDI_SUCCESS) {
14241708Sstevel 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
14251708Sstevel 			    "frup32_t struct", f);
14261708Sstevel 			return (EFAULT);
14271708Sstevel 		}
14281708Sstevel 		frup->fru_hdl = frup32.fru_hdl;
14291708Sstevel 		frup->fru_cnt = frup32.fru_cnt;
14301708Sstevel 		frup->frus = (void *)(uintptr_t)frup32.frus;
14311708Sstevel 		PR_STATE("sgfru:%s: frus %p %x hdl %lx cnt %d\n",
14321708Sstevel 		    f, frup->frus, frup32.frus, frup->fru_hdl, frup->fru_cnt);
14331708Sstevel 
14341708Sstevel 	} else
14351708Sstevel #endif /* _MULTI_DATAMODEL */
14361708Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)frup,
14371708Sstevel 	    sizeof (frup_info_t), argp->mode) != DDI_SUCCESS) {
14381708Sstevel 		cmn_err(CE_WARN,
14391708Sstevel 		    "sgfru:%s: failed to copyin frup_info_t struct", f);
14401708Sstevel 		return (EFAULT);
14411708Sstevel 	}
14421708Sstevel 	return (0);
14431708Sstevel }
14441708Sstevel 
14451708Sstevel /*
14461708Sstevel  * Used to copy in one fru_info_t from user.
14471708Sstevel  */
14481708Sstevel static int
sgfru_copyin_fru(const sgfru_init_arg_t * argp,fru_info_t * fru)14491708Sstevel sgfru_copyin_fru(const sgfru_init_arg_t *argp, fru_info_t *fru)
14501708Sstevel {
14511708Sstevel 	static fn_t f = "sgfru_copyin_fru";
14521708Sstevel 
14531708Sstevel 	bzero((caddr_t)fru, sizeof (fru_info_t));
14541708Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)fru,
14551708Sstevel 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
14561708Sstevel 		cmn_err(CE_WARN,
14571708Sstevel 		    "sgfru:%s: failed to copyin fru_info_t struct", f);
14581708Sstevel 		return (EFAULT);
14591708Sstevel 	}
14601708Sstevel 	return (0);
14611708Sstevel }
14621708Sstevel 
14631708Sstevel /*
14641708Sstevel  * Used to copy in segment_t from user.
14651708Sstevel  */
14661708Sstevel static int
sgfru_copyin_segment(const sgfru_init_arg_t * argp,const frup_info_t * frup,segment_t * segp)14671708Sstevel sgfru_copyin_segment(const sgfru_init_arg_t *argp, const frup_info_t *frup,
14681708Sstevel     segment_t *segp)
14691708Sstevel {
14701708Sstevel 	static fn_t f = "sgfru_copyin_segment";
14711708Sstevel 
14721708Sstevel 	bzero((caddr_t)segp, sizeof (segment_t));
14731708Sstevel 	if (ddi_copyin((void *)frup->frus, (void *)segp,
14741708Sstevel 	    sizeof (segment_t), argp->mode) != DDI_SUCCESS) {
14751708Sstevel 		cmn_err(CE_WARN,
14761708Sstevel 		    "sgfru:%s: failed to copyin segment_t struct", f);
14771708Sstevel 		return (EFAULT);
14781708Sstevel 	}
14791708Sstevel 	return (0);
14801708Sstevel }
14811708Sstevel 
14821708Sstevel /*
14831708Sstevel  * Used to copy in segment handle, packet and payload data from user.
14841708Sstevel  */
14851708Sstevel static int
sgfru_copyin_append(const sgfru_init_arg_t * argp,append_info_t * app)14861708Sstevel sgfru_copyin_append(const sgfru_init_arg_t *argp, append_info_t *app)
14871708Sstevel {
14881708Sstevel 	static fn_t f = "sgfru_copyin_append";
14891708Sstevel 
14901708Sstevel 	bzero((caddr_t)app, sizeof (append_info_t));
14911708Sstevel #ifdef _MULTI_DATAMODEL
14921708Sstevel 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
14931708Sstevel 		append32_info_t app32;
14941708Sstevel 
14951708Sstevel 		bzero((caddr_t)&app32, sizeof (append32_info_t));
14961708Sstevel 		if (ddi_copyin((void *)argp->argp, (void *)&app32,
14971708Sstevel 		    sizeof (append32_info_t), argp->mode) != DDI_SUCCESS) {
14981708Sstevel 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
14991708Sstevel 			    "append32_info_t struct", f);
15001708Sstevel 			return (EFAULT);
15011708Sstevel 		}
15021708Sstevel 		app->packet = app32.packet;
15031708Sstevel 		app->payload_hdl = app32.payload_hdl;
15041708Sstevel 		app->payload_cnt = app32.payload_cnt;
15051708Sstevel 		app->payload_data = (void *)(uintptr_t)app32.payload_data;
15061708Sstevel 		PR_PAYLOAD("sgfru:%s:: data %p hdl %lx cnt %d\n",
15071708Sstevel 		    f, app->payload_data, app->payload_hdl, app->payload_cnt);
15081708Sstevel 
15091708Sstevel 	} else
15101708Sstevel #endif /* _MULTI_DATAMODEL */
15111708Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)app,
15121708Sstevel 	    sizeof (append_info_t), argp->mode) != DDI_SUCCESS) {
15131708Sstevel 		cmn_err(CE_WARN,
15141708Sstevel 		    "sgfru:%s: failed to copyin append_info_t struct", f);
15151708Sstevel 		return (EFAULT);
15161708Sstevel 	}
15171708Sstevel 	PR_PAYLOAD("sgfru:%s: hdl %lx, cnt %d pkt hdl %lx "
1518*7656SSherry.Moore@Sun.COM 	    "tag %lx\n", f, app->payload_hdl, app->payload_cnt,
1519*7656SSherry.Moore@Sun.COM 	    app->packet.handle, app->packet.tag);
15201708Sstevel 	return (0);
15211708Sstevel }
15221708Sstevel 
15231708Sstevel /*
15241708Sstevel  * Used to copy in raw segment and payload data from user.
15251708Sstevel  */
15261708Sstevel static int
sgfru_copyin_buffer(const sgfru_init_arg_t * argp,const caddr_t data,const int cnt,char * buffer)15271708Sstevel sgfru_copyin_buffer(const sgfru_init_arg_t *argp, const caddr_t data,
15281708Sstevel 	const int cnt, char *buffer)
15291708Sstevel {
15301708Sstevel 	static fn_t f = "sgfru_copyin_buffer";
15311708Sstevel 
15321708Sstevel 	if (ddi_copyin((void *)data, (void *)buffer, cnt, argp->mode)
15331708Sstevel 	    != DDI_SUCCESS) {
15341708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyin buffer", f);
15351708Sstevel 		return (EFAULT);
15361708Sstevel 	}
15371708Sstevel 	return (0);
15381708Sstevel }
15391708Sstevel 
15401708Sstevel /*
15411708Sstevel  * Used to copy out one fru_info_t to user.
15421708Sstevel  */
15431708Sstevel static int
sgfru_copyout_fru(const sgfru_init_arg_t * argp,const fru_info_t * frup)15441708Sstevel sgfru_copyout_fru(const sgfru_init_arg_t *argp, const fru_info_t *frup)
15451708Sstevel {
15461708Sstevel 	static fn_t f = "sgfru_copyout_fru";
15471708Sstevel 
15481708Sstevel 	if (ddi_copyout((void *)frup, (void *)argp->argp,
15491708Sstevel 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
15501708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout fru", f);
15511708Sstevel 		return (EFAULT);
15521708Sstevel 	}
15531708Sstevel 	return (0);
15541708Sstevel }
15551708Sstevel 
15561708Sstevel /*
15571708Sstevel  * Used to copy out one fru_hdl_t to user.
15581708Sstevel  */
15591708Sstevel static int
sgfru_copyout_handle(const sgfru_init_arg_t * argp,const void * addr,const fru_hdl_t * hdlp)15601708Sstevel sgfru_copyout_handle(const sgfru_init_arg_t *argp, const void *addr,
15611708Sstevel     const fru_hdl_t *hdlp)
15621708Sstevel {
15631708Sstevel 	static fn_t f = "sgfru_copyout_handle";
15641708Sstevel 
15651708Sstevel 	if (ddi_copyout((void *)hdlp, (void *)addr, sizeof (fru_hdl_t),
15661708Sstevel 	    argp->mode) != DDI_SUCCESS) {
15671708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handle", f);
15681708Sstevel 		return (EFAULT);
15691708Sstevel 	}
15701708Sstevel 	return (0);
15711708Sstevel }
15721708Sstevel 
15731708Sstevel /*
15741708Sstevel  * Used to copy out an array of fru_hdl_t's to user.
15751708Sstevel  */
15761708Sstevel static int
sgfru_copyout_handles(const sgfru_init_arg_t * argp,const frup_info_t * frup,const fru_hdl_t * hdlp)15771708Sstevel sgfru_copyout_handles(const sgfru_init_arg_t *argp, const frup_info_t *frup,
15781708Sstevel     const fru_hdl_t *hdlp)
15791708Sstevel {
15801708Sstevel 	static fn_t f = "sgfru_copyout_handles";
15811708Sstevel 
15821708Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (fru_hdl_t));
15831708Sstevel 	/* copyout fru_hdl_t's */
15841708Sstevel 	if (ddi_copyout((void *)hdlp, (void *)frup->frus, size, argp->mode)
15851708Sstevel 	    != DDI_SUCCESS) {
15861708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handles", f);
15871708Sstevel 		return (EFAULT);
15881708Sstevel 	}
15891708Sstevel 	return (0);
15901708Sstevel }
15911708Sstevel 
15921708Sstevel /*
15931708Sstevel  * Used to copy out one or more node_t's to user.
15941708Sstevel  */
15951708Sstevel static int
sgfru_copyout_nodes(const sgfru_init_arg_t * argp,const frup_info_t * frup,const node_t * nodep)15961708Sstevel sgfru_copyout_nodes(const sgfru_init_arg_t *argp, const frup_info_t *frup,
15971708Sstevel     const node_t *nodep)
15981708Sstevel {
15991708Sstevel 	static fn_t f = "sgfru_copyout_nodes";
16001708Sstevel 
16011708Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (node_t));
16021708Sstevel 	/* copyout node_t's */
16031708Sstevel 	if (ddi_copyout((void *)nodep, (void *)frup->frus, size, argp->mode)
16041708Sstevel 	    != DDI_SUCCESS) {
16051708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout nodes", f);
16061708Sstevel 		return (EFAULT);
16071708Sstevel 	}
16081708Sstevel 	return (0);
16091708Sstevel }
16101708Sstevel 
16111708Sstevel /*
16121708Sstevel  * Used to copy out section_t's to user.
16131708Sstevel  */
16141708Sstevel static int
sgfru_copyout_sections(const sgfru_init_arg_t * argp,const frup_info_t * frup,const section_t * sectp)16151708Sstevel sgfru_copyout_sections(const sgfru_init_arg_t *argp, const frup_info_t *frup,
16161708Sstevel     const section_t *sectp)
16171708Sstevel {
16181708Sstevel 	static fn_t f = "sgfru_copyout_sections";
16191708Sstevel 
16201708Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (section_t));
16211708Sstevel 	/* copyout section_t's */
16221708Sstevel 	if (ddi_copyout((void *)sectp, (void *)frup->frus, size, argp->mode)
16231708Sstevel 	    != DDI_SUCCESS) {
16241708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout sections", f);
16251708Sstevel 		return (EFAULT);
16261708Sstevel 	}
16271708Sstevel 	return (0);
16281708Sstevel }
16291708Sstevel 
16301708Sstevel /*
16311708Sstevel  * Used to copy out segment_t's to user.
16321708Sstevel  */
16331708Sstevel static int
sgfru_copyout_segments(const sgfru_init_arg_t * argp,const frup_info_t * frup,const segment_t * segp)16341708Sstevel sgfru_copyout_segments(const sgfru_init_arg_t *argp, const frup_info_t *frup,
16351708Sstevel     const segment_t *segp)
16361708Sstevel {
16371708Sstevel 	static fn_t f = "sgfru_copyout_segments";
16381708Sstevel 
16391708Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (segment_t));
16401708Sstevel 	/* copyout segment_t's */
16411708Sstevel 	if (ddi_copyout((void *)segp, (void *)frup->frus, size, argp->mode)
16421708Sstevel 	    != DDI_SUCCESS) {
16431708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout segments", f);
16441708Sstevel 		return (EFAULT);
16451708Sstevel 	}
16461708Sstevel 	return (0);
16471708Sstevel }
16481708Sstevel 
16491708Sstevel /*
16501708Sstevel  * Used to copy out packet_t's to user.
16511708Sstevel  */
16521708Sstevel static int
sgfru_copyout_packets(const sgfru_init_arg_t * argp,const frup_info_t * frup,const packet_t * packp)16531708Sstevel sgfru_copyout_packets(const sgfru_init_arg_t *argp, const frup_info_t *frup,
16541708Sstevel     const packet_t *packp)
16551708Sstevel {
16561708Sstevel 	static fn_t f = "sgfru_copyout_packets";
16571708Sstevel 
16581708Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (packet_t));
16591708Sstevel 	/* copyout packet_t's */
16601708Sstevel 	if (ddi_copyout((void *)packp, (void *)frup->frus, size, argp->mode)
16611708Sstevel 	    != DDI_SUCCESS) {
16621708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout packets", f);
16631708Sstevel 		return (EFAULT);
16641708Sstevel 	}
16651708Sstevel 	return (0);
16661708Sstevel }
16671708Sstevel 
16681708Sstevel /*
16691708Sstevel  * Used to copy out raw segment and payload data to user.
16701708Sstevel  */
16711708Sstevel static int
sgfru_copyout_buffer(const sgfru_init_arg_t * argp,const frup_info_t * frup,const char * buffer)16721708Sstevel sgfru_copyout_buffer(const sgfru_init_arg_t *argp, const frup_info_t *frup,
16731708Sstevel     const char *buffer)
16741708Sstevel {
16751708Sstevel 	static fn_t f = "sgfru_copyout_buffer";
16761708Sstevel 
16771708Sstevel 	size_t size = (size_t)(frup->fru_cnt);
16781708Sstevel 	/* copyout packet_t */
16791708Sstevel 	if (ddi_copyout((void *)buffer, (void *)frup->frus, size, argp->mode)
16801708Sstevel 	    != DDI_SUCCESS) {
16811708Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout buffer", f);
16821708Sstevel 		return (EFAULT);
16831708Sstevel 	}
16841708Sstevel 	return (0);
16851708Sstevel }
16861708Sstevel 
16871708Sstevel /*
16881708Sstevel  * Used to pad a Java (SCAPP) fru_info_t, in preparation for sending it to
16891708Sstevel  * C (Solaris).  Assumes one fru_info_t.
16901708Sstevel  */
16911708Sstevel static caddr_t
sgfru_fru_pad(const caddr_t datap,fru_info_t * fru)16921708Sstevel sgfru_fru_pad(const caddr_t datap, fru_info_t *fru)
16931708Sstevel {
16941708Sstevel 	caddr_t tdatap = datap;
16951708Sstevel 
16961708Sstevel 	bcopy(tdatap, (caddr_t)&fru->hdl, FRU_HDL_SIZE);
16971708Sstevel 	tdatap += FRU_HDL_SIZE;
16981708Sstevel 	bcopy(tdatap, (caddr_t)&fru->cnt, FRU_CNT_SIZE);
16991708Sstevel 	tdatap += FRU_CNT_SIZE;
17001708Sstevel 	return (tdatap);
17011708Sstevel }
17021708Sstevel 
17031708Sstevel /*
17041708Sstevel  * Used to pad a Java (SCAPP) node_t, in preparation for sending it to
17051708Sstevel  * C (Solaris).  Assumes a fru_info_t and one or more node_t's.
17061708Sstevel  */
17071708Sstevel static int
sgfru_node_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,node_t * nodep)17081708Sstevel sgfru_node_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
17091708Sstevel     node_t *nodep)
17101708Sstevel {
17111708Sstevel 	caddr_t tdatap = datap;
17121708Sstevel 	node_t *np;
17131708Sstevel 	int i, cnt = 1;
17141708Sstevel 
17151708Sstevel 	if (fru != NULL) {
17161708Sstevel 		tdatap = sgfru_fru_pad(datap, fru);
17171708Sstevel 		if (max_cnt < fru->cnt) {
17181708Sstevel 			return (ENOMEM);
17191708Sstevel 		} else {
17201708Sstevel 			cnt = fru->cnt;
17211708Sstevel 		}
17221708Sstevel 	}
17231708Sstevel 	for (i = 0, np = nodep; i < cnt; i++, np++) {
17241708Sstevel 		bcopy(tdatap, (caddr_t)&np->handle, FRU_HDL_SIZE);
17251708Sstevel 		tdatap += FRU_HDL_SIZE;
17261708Sstevel 		bcopy(tdatap, (caddr_t)&np->nodename, NODENAME_SIZE);
17271708Sstevel 		tdatap += NODENAME_SIZE;
17281708Sstevel 		bcopy(tdatap, (caddr_t)&np->has_children, HASCHILDREN_SIZE);
17291708Sstevel 		tdatap += HASCHILDREN_SIZE;
17301708Sstevel 		bcopy(tdatap, (caddr_t)&np->class, CLASS_SIZE);
17311708Sstevel 		tdatap += CLASS_SIZE;
17321708Sstevel 		if (np->class == LOCATION_CLASS) {
17331708Sstevel 			bcopy(tdatap, (caddr_t)&np->location_slot, SLOT_SIZE);
17341708Sstevel 			tdatap += SLOT_SIZE;
17351708Sstevel 			bcopy(tdatap, (caddr_t)&np->location_label, LABEL_SIZE);
17361708Sstevel 			tdatap += LABEL_SIZE;
17371708Sstevel 		}
17381708Sstevel 	}
17391708Sstevel 	return (0);
17401708Sstevel }
17411708Sstevel 
17421708Sstevel /*
17431708Sstevel  * Used to pad a Java (SCAPP) section, in preparation for sending it to
17441708Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple section_t's.
17451708Sstevel  */
17461708Sstevel static int
sgfru_section_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,section_t * sectp)17471708Sstevel sgfru_section_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
17481708Sstevel     section_t *sectp)
17491708Sstevel {
17501708Sstevel 	caddr_t tdatap = datap;
17511708Sstevel 	section_t *sp;
17521708Sstevel 	int i;
17531708Sstevel 
17541708Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
17551708Sstevel 	if (max_cnt < fru->cnt)
17561708Sstevel 		return (ENOMEM);
17571708Sstevel 	for (i = 0, sp = sectp; i < fru->cnt; i++, sp++) {
17581708Sstevel 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
17591708Sstevel 		tdatap += FRU_HDL_SIZE;
17601708Sstevel 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
17611708Sstevel 		tdatap += OFFSET_SIZE;
17621708Sstevel 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
17631708Sstevel 		tdatap += LENGTH_SIZE;
17641708Sstevel 		bcopy(tdatap, (caddr_t)&sp->protected, PROTECTED_SIZE);
17651708Sstevel 		tdatap += PROTECTED_SIZE;
17661708Sstevel 		bcopy(tdatap, (caddr_t)&sp->version, VERSION_SIZE);
17671708Sstevel 		tdatap += VERSION_SIZE;
17681708Sstevel 	}
17691708Sstevel 	return (0);
17701708Sstevel }
17711708Sstevel 
17721708Sstevel /*
17731708Sstevel  * Used to pad a Java (SCAPP) segment, in preparation for sending it to
17741708Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple segment_t's.
17751708Sstevel  */
17761708Sstevel static int
sgfru_segment_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,segment_t * segp)17771708Sstevel sgfru_segment_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
17781708Sstevel     segment_t *segp)
17791708Sstevel {
17801708Sstevel 	caddr_t tdatap = datap;
17811708Sstevel 	segment_t *sp;
17821708Sstevel 	int i;
17831708Sstevel 
17841708Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
17851708Sstevel 	if (max_cnt < fru->cnt)
17861708Sstevel 		return (ENOMEM);
17871708Sstevel 	for (i = 0, sp = segp; i < fru->cnt; i++, sp++) {
17881708Sstevel 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
17891708Sstevel 		tdatap += FRU_HDL_SIZE;
17901708Sstevel 		bcopy(tdatap, (caddr_t)&sp->name, NAME_SIZE);
17911708Sstevel 		tdatap += NAME_SIZE;
17921708Sstevel 		bcopy(tdatap, (caddr_t)&sp->descriptor, DESCRIPTOR_SIZE);
17931708Sstevel 		tdatap += DESCRIPTOR_SIZE;
17941708Sstevel 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
17951708Sstevel 		tdatap += OFFSET_SIZE;
17961708Sstevel 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
17971708Sstevel 		tdatap += LENGTH_SIZE;
17981708Sstevel 	}
17991708Sstevel 	return (0);
18001708Sstevel }
18011708Sstevel 
18021708Sstevel /*
18031708Sstevel  * Used to pad a Java (SCAPP) packet, in preparation for sending it to
18041708Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple packet_t's.
18051708Sstevel  */
18061708Sstevel static int
sgfru_packet_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,packet_t * packp)18071708Sstevel sgfru_packet_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
18081708Sstevel     packet_t *packp)
18091708Sstevel {
18101708Sstevel 	caddr_t tdatap = datap;
18111708Sstevel 	packet_t *pp;
18121708Sstevel 	int i;
18131708Sstevel 
18141708Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
18151708Sstevel 	if (max_cnt < fru->cnt)
18161708Sstevel 		return (ENOMEM);
18171708Sstevel 	for (i = 0, pp = packp; i < fru->cnt; i++, pp++) {
18181708Sstevel 		bcopy(tdatap, (caddr_t)&pp->handle, FRU_HDL_SIZE);
18191708Sstevel 		tdatap += FRU_HDL_SIZE;
18201708Sstevel 		bcopy(tdatap, (caddr_t)&pp->tag, TAG_SIZE);
18211708Sstevel 		tdatap += TAG_SIZE;
18221708Sstevel 	}
18231708Sstevel 	return (0);
18241708Sstevel }
18251708Sstevel 
18261708Sstevel /*
18271708Sstevel  * Used to unpad a C (Solaris) fru_info_t, in preparation for sending it to
18281708Sstevel  * Java (SCAPP).  Assumes a fru_info_t.
18291708Sstevel  */
18301708Sstevel static caddr_t
sgfru_fru_unpad(const fru_info_t * fru,caddr_t datap)18311708Sstevel sgfru_fru_unpad(const fru_info_t *fru, caddr_t datap)
18321708Sstevel {
18331708Sstevel 	caddr_t tdatap = datap;
18341708Sstevel 
18351708Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
18361708Sstevel 	tdatap += FRU_HDL_SIZE;
18371708Sstevel 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
18381708Sstevel 	tdatap += FRU_CNT_SIZE;
18391708Sstevel 	return (tdatap);
18401708Sstevel }
18411708Sstevel 
18421708Sstevel /*
18431708Sstevel  * Used to unpad a C (Solaris) segment, in preparation for sending it to
18441708Sstevel  * Java (SCAPP). Assumes a section_hdl_t and one segment_t.
18451708Sstevel  */
18461708Sstevel static void
sgfru_segment_unpad(const fru_info_t * fru,const segment_t * segp,caddr_t datap)18471708Sstevel sgfru_segment_unpad(const fru_info_t *fru, const segment_t *segp,
18481708Sstevel     caddr_t datap)
18491708Sstevel {
18501708Sstevel 	caddr_t tdatap = datap;
18511708Sstevel 
18521708Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
18531708Sstevel 	tdatap += FRU_HDL_SIZE;
18541708Sstevel 	bcopy((caddr_t)&segp->handle, tdatap, FRU_HDL_SIZE);
18551708Sstevel 	tdatap += FRU_HDL_SIZE;
18561708Sstevel 	bcopy((caddr_t)&segp->name, tdatap, NAME_SIZE);
18571708Sstevel 	tdatap += NAME_SIZE;
18581708Sstevel 	bcopy((caddr_t)&segp->descriptor, tdatap, DESCRIPTOR_SIZE);
18591708Sstevel 	tdatap += DESCRIPTOR_SIZE;
18601708Sstevel 	bcopy((caddr_t)&segp->offset, tdatap, OFFSET_SIZE);
18611708Sstevel 	tdatap += OFFSET_SIZE;
18621708Sstevel 	bcopy((caddr_t)&segp->length, tdatap, LENGTH_SIZE);
18631708Sstevel }
18641708Sstevel 
18651708Sstevel /*
18661708Sstevel  * Used to unpad a C (Solaris) packet, in preparation for sending it to
18671708Sstevel  * Java (SCAPP).  Assumes a fru_info_t and one packet_t.
18681708Sstevel  */
18691708Sstevel static caddr_t
sgfru_packet_unpad(const fru_info_t * fru,const packet_t * packp,caddr_t datap)18701708Sstevel sgfru_packet_unpad(const fru_info_t *fru, const packet_t *packp, caddr_t datap)
18711708Sstevel {
18721708Sstevel 	caddr_t tdatap = datap;
18731708Sstevel 
18741708Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
18751708Sstevel 	tdatap += FRU_HDL_SIZE;
18761708Sstevel 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
18771708Sstevel 	tdatap += FRU_CNT_SIZE;
18781708Sstevel 	bcopy((caddr_t)&packp->handle, tdatap, FRU_HDL_SIZE);
18791708Sstevel 	tdatap += FRU_HDL_SIZE;
18801708Sstevel 	bcopy((caddr_t)&packp->tag, tdatap, TAG_SIZE);
18811708Sstevel 	tdatap += TAG_SIZE;
18821708Sstevel 	return (tdatap);
18831708Sstevel }
1884