xref: /illumos-gate/usr/src/uts/sun4u/lw8/io/sgfru.c (revision d1d6926f)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
2319397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel #include <sys/types.h>
2903831d35Sstevel #include <sys/conf.h>
3003831d35Sstevel #include <sys/file.h>
3103831d35Sstevel #include <sys/ddi.h>
3203831d35Sstevel #include <sys/sunddi.h>
3303831d35Sstevel #include <sys/modctl.h>
3403831d35Sstevel #include <sys/sunndi.h>
3503831d35Sstevel #include <sys/ddi_impldefs.h>
3603831d35Sstevel #include <sys/obpdefs.h>
3703831d35Sstevel #include <sys/cmn_err.h>
3803831d35Sstevel #include <sys/errno.h>
3903831d35Sstevel #include <sys/debug.h>
4003831d35Sstevel #include <sys/sysmacros.h>
4103831d35Sstevel #include <sys/autoconf.h>
4203831d35Sstevel #include <sys/stat.h>
4303831d35Sstevel #include <sys/kmem.h>
4403831d35Sstevel #include <sys/sgsbbc_mailbox.h>
4503831d35Sstevel #include <sys/sgfrutree.h>
4603831d35Sstevel #include <sys/sgfru_priv.h>
4703831d35Sstevel #include <sys/sgfru_mbox.h>
4803831d35Sstevel 
4903831d35Sstevel /*
5003831d35Sstevel  * This driver implements the ioctls for the serengeti frutree picl plugin
5103831d35Sstevel  * and the serengeti fruaccess library. These are all private,
5203831d35Sstevel  * platform-dependent interfaces.
5303831d35Sstevel  */
5403831d35Sstevel 
5503831d35Sstevel /* Global Variables */
5603831d35Sstevel 
5703831d35Sstevel #ifdef DEBUG
5803831d35Sstevel uint_t sgfru_debug = 0;
5903831d35Sstevel #endif /* DEBUG */
6003831d35Sstevel 
6103831d35Sstevel /* Opaque state structure pointer */
6203831d35Sstevel static void *sgfru_statep;	/* sgfru soft state hook */
6303831d35Sstevel 
6403831d35Sstevel /*
6503831d35Sstevel  * the maximum amount of time this driver is prepared to wait for the mailbox
6603831d35Sstevel  * to reply before it decides to timeout.
6703831d35Sstevel  */
6803831d35Sstevel int sgfru_mbox_wait = SGFRU_DEFAULT_MAX_MBOX_WAIT_TIME;
6903831d35Sstevel 
7003831d35Sstevel /* Module Variables */
7103831d35Sstevel 
7203831d35Sstevel /*
7303831d35Sstevel  * Driver entry points. These are located in sgfru.c so as to
7403831d35Sstevel  * not cause a warning for the sgfru adb macro.
7503831d35Sstevel  */
7603831d35Sstevel static struct cb_ops sgfru_cb_ops = {
7703831d35Sstevel 	sgfru_open,		/* open */
7803831d35Sstevel 	sgfru_close,		/* close */
7903831d35Sstevel 	nulldev,		/* strategy */
8003831d35Sstevel 	nulldev,		/* print */
8103831d35Sstevel 	nulldev,		/* dump */
8203831d35Sstevel 	nulldev,		/* read */
8303831d35Sstevel 	nulldev,		/* write */
8403831d35Sstevel 	sgfru_ioctl,		/* ioctl */
8503831d35Sstevel 	nulldev,		/* devmap */
8603831d35Sstevel 	nulldev,		/* mmap */
8703831d35Sstevel 	nulldev,		/* segmap */
8803831d35Sstevel 	nochpoll,		/* poll */
8903831d35Sstevel 	ddi_prop_op,		/* cb_prop_op */
9003831d35Sstevel 	NULL,			/* streamtab */
9103831d35Sstevel 	D_NEW | D_MP		/* Driver compatibility flag */
9203831d35Sstevel };
9303831d35Sstevel 
9403831d35Sstevel static struct dev_ops sgfru_ops = {
9503831d35Sstevel 	DEVO_REV,		/* devo_rev, */
9603831d35Sstevel 	0,			/* refcnt  */
9703831d35Sstevel 	ddi_getinfo_1to1,	/* info */
9803831d35Sstevel 	nulldev,		/* identify */
9903831d35Sstevel 	nulldev,		/* probe */
10003831d35Sstevel 	sgfru_attach,		/* attach */
10103831d35Sstevel 	sgfru_detach,		/* detach */
10203831d35Sstevel 	nodev,			/* reset */
10303831d35Sstevel 	&sgfru_cb_ops,		/* driver operations */
10403831d35Sstevel 	(struct bus_ops *)0,	/* bus operations */
10519397407SSherry Moore 	nulldev,		/* power */
10619397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
10703831d35Sstevel };
10803831d35Sstevel 
10903831d35Sstevel /*
11003831d35Sstevel  * Loadable module support. This is located in sgfru.c so as to
11119397407SSherry Moore  * pick up the 1.8 version of sgfru.c.
11203831d35Sstevel  */
11303831d35Sstevel extern struct mod_ops mod_driverops;
11403831d35Sstevel 
11503831d35Sstevel static struct modldrv modldrv = {
11603831d35Sstevel 	&mod_driverops,	/* Type of module.  This one is a pseudo driver */
11719397407SSherry Moore 	"FRU Driver",
11803831d35Sstevel 	&sgfru_ops,	/* driver ops */
11903831d35Sstevel };
12003831d35Sstevel 
12103831d35Sstevel static struct modlinkage modlinkage = {
12203831d35Sstevel 	MODREV_1,
12303831d35Sstevel 	(void *)&modldrv,
12403831d35Sstevel 	NULL
12503831d35Sstevel };
12603831d35Sstevel 
12703831d35Sstevel int
_init(void)12803831d35Sstevel _init(void)
12903831d35Sstevel {
13003831d35Sstevel 	int error = 0;
13103831d35Sstevel 
13203831d35Sstevel 	/* Allocate the soft state info and add the module. */
13303831d35Sstevel 	if ((error = ddi_soft_state_init(&sgfru_statep,
13403831d35Sstevel 	    sizeof (sgfru_soft_state_t), 1)) == 0 &&
13503831d35Sstevel 	    (error = mod_install(&modlinkage)) != 0) {
13603831d35Sstevel 		ddi_soft_state_fini(&sgfru_statep);
13703831d35Sstevel 	}
13803831d35Sstevel 	return (error);
13903831d35Sstevel }
14003831d35Sstevel 
14103831d35Sstevel int
_fini(void)14203831d35Sstevel _fini(void)
14303831d35Sstevel {
14403831d35Sstevel 	int error = 0;
14503831d35Sstevel 
14603831d35Sstevel 	/* Remove the module and free the soft state info. */
14703831d35Sstevel 	if ((error = mod_remove(&modlinkage)) == 0) {
14803831d35Sstevel 		ddi_soft_state_fini(&sgfru_statep);
14903831d35Sstevel 	}
15003831d35Sstevel 	return (error);
15103831d35Sstevel }
15203831d35Sstevel 
15303831d35Sstevel int
_info(struct modinfo * modinfop)15403831d35Sstevel _info(struct modinfo *modinfop)
15503831d35Sstevel {
15603831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
15703831d35Sstevel }
15803831d35Sstevel 
15903831d35Sstevel static int
sgfru_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)16003831d35Sstevel sgfru_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
16103831d35Sstevel {
16203831d35Sstevel 	sgfru_soft_state_t *softsp;
16303831d35Sstevel 	int instance;
16403831d35Sstevel 	int error;
16503831d35Sstevel 	static fn_t f = "sgfru_attach";
16603831d35Sstevel 
16703831d35Sstevel 	switch (cmd) {
16803831d35Sstevel 	case DDI_ATTACH:
16903831d35Sstevel 		instance = ddi_get_instance(dip);
17003831d35Sstevel 
17103831d35Sstevel 		error = ddi_soft_state_zalloc(sgfru_statep, instance);
17203831d35Sstevel 		if (error != DDI_SUCCESS) {
17303831d35Sstevel 			cmn_err(CE_WARN, "sgfru:%s: cannot allocate fru state "
17403831d35Sstevel 			    "for inst %d.", f, instance);
17503831d35Sstevel 			return (DDI_FAILURE);
17603831d35Sstevel 		}
17703831d35Sstevel 		softsp = ddi_get_soft_state(sgfru_statep, instance);
17803831d35Sstevel 		if (softsp == NULL) {
17903831d35Sstevel 			ddi_soft_state_free(sgfru_statep, instance);
18003831d35Sstevel 			cmn_err(CE_WARN, "sgfru:%s: could not get state "
18103831d35Sstevel 			    "structure for inst %d.", f, instance);
18203831d35Sstevel 			return (DDI_FAILURE);
18303831d35Sstevel 		}
18403831d35Sstevel 		softsp->fru_dip = dip;
18503831d35Sstevel 		softsp->fru_pdip = ddi_get_parent(softsp->fru_dip);
18603831d35Sstevel 		softsp->instance = instance;
18703831d35Sstevel 
18803831d35Sstevel 		error = ddi_create_minor_node(dip, SGFRU_DRV_NAME, S_IFCHR,
189*d1d6926fSToomas Soome 		    instance, DDI_PSEUDO, 0);
19003831d35Sstevel 		if (error == DDI_FAILURE) {
19103831d35Sstevel 			ddi_soft_state_free(sgfru_statep, instance);
19203831d35Sstevel 			return (DDI_FAILURE);
19303831d35Sstevel 		}
19403831d35Sstevel 
19503831d35Sstevel 		ddi_report_dev(dip);
19603831d35Sstevel 
19703831d35Sstevel 		return (DDI_SUCCESS);
19803831d35Sstevel 
19903831d35Sstevel 	case DDI_RESUME:
20003831d35Sstevel 		return (DDI_SUCCESS);
20103831d35Sstevel 
20203831d35Sstevel 	default:
20303831d35Sstevel 		return (DDI_FAILURE);
20403831d35Sstevel 	}
20503831d35Sstevel }
20603831d35Sstevel 
20703831d35Sstevel static int
sgfru_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)20803831d35Sstevel sgfru_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
20903831d35Sstevel {
21003831d35Sstevel 	int instance;
21103831d35Sstevel 	sgfru_soft_state_t *softsp;
21203831d35Sstevel 	static fn_t f = "sgfru_detach";
21303831d35Sstevel 
21403831d35Sstevel 	instance = ddi_get_instance(dip);
21503831d35Sstevel 
21603831d35Sstevel 	softsp = ddi_get_soft_state(sgfru_statep, instance);
21703831d35Sstevel 	if (softsp == NULL) {
21803831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: could not get state "
21903831d35Sstevel 		    "structure for inst %d.", f, instance);
22003831d35Sstevel 		return (DDI_FAILURE);
22103831d35Sstevel 	}
22203831d35Sstevel 
22303831d35Sstevel 	switch (cmd) {
22403831d35Sstevel 	case DDI_DETACH:
22503831d35Sstevel 		ddi_soft_state_free(sgfru_statep, instance);
22603831d35Sstevel 		ddi_remove_minor_node(dip, NULL);
22703831d35Sstevel 		return (DDI_SUCCESS);
22803831d35Sstevel 
22903831d35Sstevel 	case DDI_SUSPEND:
23003831d35Sstevel 		return (DDI_SUCCESS);
23103831d35Sstevel 
23203831d35Sstevel 	default:
23303831d35Sstevel 		return (DDI_FAILURE);
23403831d35Sstevel 	}
23503831d35Sstevel }
23603831d35Sstevel 
23703831d35Sstevel /*ARGSUSED*/
23803831d35Sstevel static int
sgfru_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)23903831d35Sstevel sgfru_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
24003831d35Sstevel {
24103831d35Sstevel 	int error = 0;
24203831d35Sstevel 	int instance = getminor(*dev_p);
24303831d35Sstevel 	sgfru_soft_state_t *softsp;
24403831d35Sstevel 	static fn_t f = "sgfru_open";
24503831d35Sstevel 
24603831d35Sstevel 	if ((error = drv_priv(cred_p)) != 0) {
24703831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: inst %d drv_priv failed",
24803831d35Sstevel 		    f, instance);
24903831d35Sstevel 		return (error);
25003831d35Sstevel 	}
25103831d35Sstevel 	softsp = (sgfru_soft_state_t *)ddi_get_soft_state(sgfru_statep,
25203831d35Sstevel 	    instance);
25303831d35Sstevel 	if (softsp == (sgfru_soft_state_t *)NULL) {
25403831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: inst %d ddi_get_soft_state failed",
25503831d35Sstevel 		    f, instance);
25603831d35Sstevel 		return (ENXIO);
25703831d35Sstevel 	}
25803831d35Sstevel 	return (error);
25903831d35Sstevel }
26003831d35Sstevel 
26103831d35Sstevel /*ARGSUSED*/
26203831d35Sstevel static int
sgfru_close(dev_t dev,int flag,int otyp,cred_t * cred_p)26303831d35Sstevel sgfru_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
26403831d35Sstevel {
26503831d35Sstevel 	int instance = getminor(dev);
26603831d35Sstevel 	sgfru_soft_state_t *softsp = (sgfru_soft_state_t *)
26703831d35Sstevel 	    ddi_get_soft_state(sgfru_statep, instance);
26803831d35Sstevel 
26903831d35Sstevel 	if (softsp == (sgfru_soft_state_t *)NULL)
27003831d35Sstevel 		return (ENXIO);
27103831d35Sstevel 	return (DDI_SUCCESS);
27203831d35Sstevel }
27303831d35Sstevel 
27403831d35Sstevel /*
27503831d35Sstevel  * This function disperses the ioctls from the serengeti libpiclfruhier plugin
27603831d35Sstevel  * and the serengeti libpiclfruaccess library to the appropriate sub-functions.
27703831d35Sstevel  */
27803831d35Sstevel /*ARGSUSED*/
27903831d35Sstevel static int
sgfru_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)28003831d35Sstevel sgfru_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
28103831d35Sstevel     int *rval_p)
28203831d35Sstevel {
28303831d35Sstevel 	sgfru_soft_state_t *softsp;
28403831d35Sstevel 	int instance = getminor(dev);
28503831d35Sstevel 	sgfru_init_arg_t init_arg;
28603831d35Sstevel 	int32_t ret = 0;
28703831d35Sstevel 	static fn_t f = "sgfru_ioctl";
28803831d35Sstevel 
28903831d35Sstevel 
29003831d35Sstevel 	softsp = ddi_get_soft_state(sgfru_statep, instance);
29103831d35Sstevel 	if (softsp == NULL) {
29203831d35Sstevel 		return (ENXIO);
29303831d35Sstevel 	}
29403831d35Sstevel 	PR_STATE("sgfru:%s: dev %lx cmd %d, instance %d\n",
29503831d35Sstevel 	    f, dev, cmd, instance);
29603831d35Sstevel 
29703831d35Sstevel 	init_arg.dev = dev;
29803831d35Sstevel 	init_arg.cmd = cmd;
29903831d35Sstevel 	init_arg.mode = mode;
30003831d35Sstevel 	init_arg.argp = arg;
30103831d35Sstevel 
30203831d35Sstevel 	switch (cmd) {
30303831d35Sstevel 
30403831d35Sstevel 	case SGFRU_GETSECTIONS:
30503831d35Sstevel 		ret = sgfru_getsections(&init_arg);
30603831d35Sstevel 		break;
30703831d35Sstevel 
30803831d35Sstevel 	case SGFRU_GETSEGMENTS:
30903831d35Sstevel 		ret = sgfru_getsegments(&init_arg);
31003831d35Sstevel 		break;
31103831d35Sstevel 
31203831d35Sstevel 	case SGFRU_ADDSEGMENT:
31303831d35Sstevel 		ret = sgfru_addsegment(&init_arg);
31403831d35Sstevel 		break;
31503831d35Sstevel 
31603831d35Sstevel 	case SGFRU_READRAWSEGMENT:
31703831d35Sstevel 		ret = sgfru_readsegment(&init_arg);
31803831d35Sstevel 		break;
31903831d35Sstevel 
32003831d35Sstevel 	case SGFRU_WRITERAWSEGMENT:
32103831d35Sstevel 		ret = sgfru_writesegment(&init_arg);
32203831d35Sstevel 		break;
32303831d35Sstevel 
32403831d35Sstevel 	case SGFRU_GETPACKETS:
32503831d35Sstevel 		ret = sgfru_getpackets(&init_arg);
32603831d35Sstevel 		break;
32703831d35Sstevel 
32803831d35Sstevel 	case SGFRU_APPENDPACKET:
32903831d35Sstevel 		ret = sgfru_appendpacket(&init_arg);
33003831d35Sstevel 		break;
33103831d35Sstevel 
33203831d35Sstevel 	case SGFRU_GETPAYLOAD:
33303831d35Sstevel 		ret = sgfru_getpayload(&init_arg);
33403831d35Sstevel 		break;
33503831d35Sstevel 
33603831d35Sstevel 	case SGFRU_UPDATEPAYLOAD:
33703831d35Sstevel 		ret = sgfru_updatepayload(&init_arg);
33803831d35Sstevel 		break;
33903831d35Sstevel 
34003831d35Sstevel 	case SGFRU_GETNUMSECTIONS:
34103831d35Sstevel 	case SGFRU_GETNUMSEGMENTS:
34203831d35Sstevel 	case SGFRU_GETNUMPACKETS:
34303831d35Sstevel 		ret = sgfru_getnum(&init_arg);
34403831d35Sstevel 		break;
34503831d35Sstevel 
34603831d35Sstevel 	case SGFRU_DELETESEGMENT:
34703831d35Sstevel 	case SGFRU_DELETEPACKET:
34803831d35Sstevel 		ret = sgfru_delete(&init_arg);
34903831d35Sstevel 		break;
35003831d35Sstevel 
35103831d35Sstevel 	case SGFRU_GETCHILDLIST:
35203831d35Sstevel 		ret = sgfru_getchildlist(&init_arg);
35303831d35Sstevel 		break;
35403831d35Sstevel 
35503831d35Sstevel 	case SGFRU_GETCHILDHANDLES:
35603831d35Sstevel 		ret = sgfru_getchildhandles(&init_arg);
35703831d35Sstevel 		break;
35803831d35Sstevel 
35903831d35Sstevel 	case SGFRU_GETNODEINFO:
36003831d35Sstevel 		ret = sgfru_getnodeinfo(&init_arg);
36103831d35Sstevel 		break;
36203831d35Sstevel 
36303831d35Sstevel 	default:
36403831d35Sstevel 		ret = EINVAL;
36503831d35Sstevel 		break;
36603831d35Sstevel 	}
36703831d35Sstevel 
36803831d35Sstevel 	return (ret);
36903831d35Sstevel }
37003831d35Sstevel 
37103831d35Sstevel /*
37203831d35Sstevel  * Used for private SGFRU_GETCHILDLIST ioctl.
37303831d35Sstevel  */
37403831d35Sstevel static int
sgfru_getchildlist(const sgfru_init_arg_t * iargp)37503831d35Sstevel sgfru_getchildlist(const sgfru_init_arg_t *iargp)
37603831d35Sstevel {
37703831d35Sstevel 	int32_t ret;
37803831d35Sstevel 	caddr_t datap;
37903831d35Sstevel 	size_t ssize, size;
38003831d35Sstevel 	frup_info_t clist;
38103831d35Sstevel 	fru_cnt_t max_cnt;
38203831d35Sstevel 	node_t *clistp;
38303831d35Sstevel 	static fn_t f = "sgfru_getchildlist";
38403831d35Sstevel 
38503831d35Sstevel 	/* copyin child_info_t aka frup_info_t */
38603831d35Sstevel 	if (sgfru_copyin_frup(iargp, &clist) != 0) {
38703831d35Sstevel 		return (EFAULT);
38803831d35Sstevel 	}
38903831d35Sstevel 
39003831d35Sstevel 	/* check on kmem_alloc space requirements */
39103831d35Sstevel 	max_cnt = clist.fru_cnt;
39203831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
39303831d35Sstevel 		return (EINVAL);
39403831d35Sstevel 	}
39503831d35Sstevel 
39603831d35Sstevel 	/* allocate buffer for unpadded fru_info_t + node_t's */
39703831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * NODE_SIZE));
39803831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
39903831d35Sstevel 	PR_NODE("sgfru:%s: FRU_INFO_SIZE %lu NODE_SIZE %lu size %lu\n",
40003831d35Sstevel 	    f, FRU_INFO_SIZE, NODE_SIZE, size);
40103831d35Sstevel 	PR_NODE("sgfru:%s: handle %lx cnt %d buffer 0x%p\n", f,
40203831d35Sstevel 	    clist.fru_hdl, clist.fru_cnt, clist.frus);
40303831d35Sstevel 
40403831d35Sstevel 	/* call mailbox */
40503831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &clist.fru_info))
40603831d35Sstevel 	    != 0) {
40703831d35Sstevel 		kmem_free(datap, size);
40803831d35Sstevel 		return (ret);
40903831d35Sstevel 	}
41003831d35Sstevel 
41103831d35Sstevel 	/* allocate buffer for padded node_t's */
41203831d35Sstevel 	ssize = (size_t)(max_cnt * sizeof (node_t));
41303831d35Sstevel 	clistp = (node_t *)kmem_zalloc(ssize, KM_SLEEP);
41403831d35Sstevel 
41503831d35Sstevel 	/* translate unpadded to padded fru_info_t + node_t's */
41603831d35Sstevel 	if ((ret = sgfru_node_pad(datap, max_cnt, &clist.fru_info, clistp))
41703831d35Sstevel 	    != 0) {
41803831d35Sstevel 		kmem_free(datap, size);
41903831d35Sstevel 		kmem_free(clistp, ssize);
42003831d35Sstevel 		return (ret);
42103831d35Sstevel 	}
42203831d35Sstevel 	/* free node_t buffer */
42303831d35Sstevel 	kmem_free(datap, size);
42403831d35Sstevel 
42503831d35Sstevel 	/* copy out fru_info_t */
42603831d35Sstevel 	if (sgfru_copyout_fru(iargp, &clist.fru_info) != 0) {
42703831d35Sstevel 		kmem_free(clistp, ssize);
42803831d35Sstevel 		return (EFAULT);
42903831d35Sstevel 	}
43003831d35Sstevel 	/* copyout node_t's */
43103831d35Sstevel 	if (sgfru_copyout_nodes(iargp, &clist, clistp) != 0) {
43203831d35Sstevel 		kmem_free(clistp, ssize);
43303831d35Sstevel 		return (EFAULT);
43403831d35Sstevel 	}
43503831d35Sstevel 	/* free node_t buffer */
43603831d35Sstevel 	kmem_free(clistp, ssize);
43703831d35Sstevel 
43803831d35Sstevel 	return (ret);
43903831d35Sstevel }
44003831d35Sstevel 
44103831d35Sstevel /*
44203831d35Sstevel  * Used for private SGFRU_GETCHILDHANDLES ioctl.
44303831d35Sstevel  */
44403831d35Sstevel static int
sgfru_getchildhandles(const sgfru_init_arg_t * iargp)44503831d35Sstevel sgfru_getchildhandles(const sgfru_init_arg_t *iargp)
44603831d35Sstevel {
44703831d35Sstevel 	int32_t ret;
44803831d35Sstevel 	size_t size;
44903831d35Sstevel 	caddr_t datap, tdatap;
45003831d35Sstevel 	frup_info_t hdls;
45103831d35Sstevel 	fru_info_t hinfo;
45203831d35Sstevel 	fru_cnt_t max_cnt;
45303831d35Sstevel 	static fn_t f = "sgfru_getchildhandles";
45403831d35Sstevel 
45503831d35Sstevel 	/* copyin handles_t aka frup_info_t */
45603831d35Sstevel 	if (sgfru_copyin_frup(iargp, &hdls) != 0) {
45703831d35Sstevel 		return (EFAULT);
45803831d35Sstevel 	}
45903831d35Sstevel 	PR_HANDLE("sgfru:%s: handle %lx\n", f, hdls.fru_hdl);
46003831d35Sstevel 
46103831d35Sstevel 	/* check on kmem_alloc space requirements */
46203831d35Sstevel 	max_cnt = hdls.fru_cnt;
46303831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) {
46403831d35Sstevel 		return (EINVAL);
46503831d35Sstevel 	}
46603831d35Sstevel 
46703831d35Sstevel 	/* allocate buffer for child fru_hdl_t's */
46803831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * FRU_HDL_SIZE));
46903831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
47003831d35Sstevel 
47103831d35Sstevel 	/* call mailbox */
47203831d35Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &hdls.fru_info);
47303831d35Sstevel 	if (ret != 0) {
47403831d35Sstevel 		kmem_free(datap, size);
47503831d35Sstevel 		return (ret);
47603831d35Sstevel 	}
47703831d35Sstevel 
47803831d35Sstevel 	/* translate unpadded to fru_info_t */
47903831d35Sstevel 	tdatap = sgfru_fru_pad(datap, &hinfo);
48003831d35Sstevel 
48103831d35Sstevel 	/* copyout actual fru_cnt */
48203831d35Sstevel 	if (sgfru_copyout_fru(iargp, &hinfo) != 0) {
48303831d35Sstevel 		kmem_free(datap, size);
48403831d35Sstevel 		return (EFAULT);
48503831d35Sstevel 	}
48603831d35Sstevel 	PR_HANDLE("sgfru:%s: count %x\n", f, hinfo.cnt);
48703831d35Sstevel 
48803831d35Sstevel 	/* copyout fru_hdl_t's */
48903831d35Sstevel 	if (sgfru_copyout_handles(iargp, &hdls, (fru_hdl_t *)tdatap) != 0) {
49003831d35Sstevel 		kmem_free(datap, size);
49103831d35Sstevel 		return (EFAULT);
49203831d35Sstevel 	}
49303831d35Sstevel 
49403831d35Sstevel 	/* free datap buffer */
49503831d35Sstevel 	kmem_free(datap, size);
49603831d35Sstevel 
49703831d35Sstevel 	return (ret);
49803831d35Sstevel }
49903831d35Sstevel 
50003831d35Sstevel /*
50103831d35Sstevel  * Used for private SGFRU_GETNODEINFO ioctl.
50203831d35Sstevel  */
50303831d35Sstevel static int
sgfru_getnodeinfo(const sgfru_init_arg_t * iargp)50403831d35Sstevel sgfru_getnodeinfo(const sgfru_init_arg_t *iargp)
50503831d35Sstevel {
50603831d35Sstevel 	int32_t ret;
50703831d35Sstevel 	caddr_t datap;
50803831d35Sstevel 	size_t size;
50903831d35Sstevel 	frup_info_t nodeinfo;
51003831d35Sstevel 	node_t node;
51103831d35Sstevel 	static fn_t f = "sgfru_getnodeinfo";
51203831d35Sstevel 
51303831d35Sstevel 	/* copyin node_info_t aka frup_info_t */
51403831d35Sstevel 	if (sgfru_copyin_frup(iargp, &nodeinfo) != 0) {
51503831d35Sstevel 		return (EFAULT);
51603831d35Sstevel 	}
51703831d35Sstevel 
51803831d35Sstevel 	/* allocate unpadded buffer for node_t */
51903831d35Sstevel 	size = (size_t)(NODE_SIZE);
52003831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
52103831d35Sstevel 
52203831d35Sstevel 	PR_NODE("sgfru:%s: handle %lx size 0x%lx\n", f, nodeinfo.fru_hdl, size);
52303831d35Sstevel 	/* call mailbox */
52403831d35Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &nodeinfo.fru_info);
52503831d35Sstevel 	if (ret != 0) {
52603831d35Sstevel 		kmem_free(datap, size);
52703831d35Sstevel 		return (ret);
52803831d35Sstevel 	}
52903831d35Sstevel 
53003831d35Sstevel 	/* translate unpadded to padded node_t */
53103831d35Sstevel 	if ((ret = sgfru_node_pad(datap, 0, NULL, &node))
53203831d35Sstevel 	    != 0) {
53303831d35Sstevel 		kmem_free(datap, size);
53403831d35Sstevel 		return (ret);
53503831d35Sstevel 	}
53603831d35Sstevel 
53703831d35Sstevel 	/* free node_t buffer */
53803831d35Sstevel 	kmem_free(datap, size);
53903831d35Sstevel 
54003831d35Sstevel 	/* copyout node_t */
54103831d35Sstevel 	if (sgfru_copyout_nodes(iargp, &nodeinfo, &node) != 0) {
54203831d35Sstevel 		return (EFAULT);
54303831d35Sstevel 	}
54403831d35Sstevel 	PR_NODE("sgfru:%s: handle %lx nodename %s has_children %d class %d\n",
54503831d35Sstevel 	    f, node.handle, node.nodename, node.has_children, node.class);
54603831d35Sstevel 
54703831d35Sstevel 	return (ret);
54803831d35Sstevel }
54903831d35Sstevel 
55003831d35Sstevel /*
55103831d35Sstevel  * Used for fru_get_sections().
55203831d35Sstevel  */
55303831d35Sstevel static int
sgfru_getsections(const sgfru_init_arg_t * iargp)55403831d35Sstevel sgfru_getsections(const sgfru_init_arg_t *iargp)
55503831d35Sstevel {
55603831d35Sstevel 	int32_t ret;
55703831d35Sstevel 	caddr_t datap;
55803831d35Sstevel 	size_t ssize, size;
55903831d35Sstevel 	frup_info_t sects;
56003831d35Sstevel 	fru_cnt_t max_cnt;
56103831d35Sstevel 	section_t *sectp;
56203831d35Sstevel 
56303831d35Sstevel 	/* copyin sections_t aka frup_info_t */
56403831d35Sstevel 	if (sgfru_copyin_frup(iargp, &sects) != 0) {
56503831d35Sstevel 		return (EFAULT);
56603831d35Sstevel 	}
56703831d35Sstevel 	/* check on kmem_alloc space requirements */
56803831d35Sstevel 	max_cnt = sects.fru_cnt;
56903831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SECTIONS)) {
57003831d35Sstevel 		return (EINVAL);
57103831d35Sstevel 	}
57203831d35Sstevel 
57303831d35Sstevel 	/* allocate buffer for unpadded fru_info_t + section_t's */
57403831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SECTION_SIZE));
57503831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
57603831d35Sstevel 
57703831d35Sstevel 	/* call mailbox */
57803831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &sects.fru_info))
57903831d35Sstevel 	    != 0) {
58003831d35Sstevel 		kmem_free(datap, size);
58103831d35Sstevel 		return (ret);
58203831d35Sstevel 	}
58303831d35Sstevel 
58403831d35Sstevel 	/* allocate buffer for padded section_t's */
58503831d35Sstevel 	ssize = (size_t)(max_cnt * sizeof (section_t));
58603831d35Sstevel 	sectp = (section_t *)kmem_zalloc(ssize, KM_SLEEP);
58703831d35Sstevel 
58803831d35Sstevel 	/* translate unpadded to padded fru_info_t + section_t's */
58903831d35Sstevel 	if ((ret = sgfru_section_pad(datap, max_cnt, &sects.fru_info, sectp))
59003831d35Sstevel 	    != 0) {
59103831d35Sstevel 		kmem_free(datap, size);
59203831d35Sstevel 		kmem_free(sectp, ssize);
59303831d35Sstevel 		return (ret);
59403831d35Sstevel 	}
59503831d35Sstevel 	/* free section_t buffer */
59603831d35Sstevel 	kmem_free(datap, size);
59703831d35Sstevel 
59803831d35Sstevel 	/* copy out fru_info_t */
59903831d35Sstevel 	if (sgfru_copyout_fru(iargp, &sects.fru_info) != 0) {
60003831d35Sstevel 		kmem_free(sectp, ssize);
60103831d35Sstevel 		return (EFAULT);
60203831d35Sstevel 	}
60303831d35Sstevel 	/* copyout section_t's */
60403831d35Sstevel 	if (sgfru_copyout_sections(iargp, &sects, sectp) != 0) {
60503831d35Sstevel 		kmem_free(sectp, ssize);
60603831d35Sstevel 		return (EFAULT);
60703831d35Sstevel 	}
60803831d35Sstevel 	/* free section_t buffer */
60903831d35Sstevel 	kmem_free(sectp, ssize);
61003831d35Sstevel 
61103831d35Sstevel 	return (ret);
61203831d35Sstevel }
61303831d35Sstevel 
61403831d35Sstevel /*
61503831d35Sstevel  * Used for fru_get_segments().
61603831d35Sstevel  */
61703831d35Sstevel static int
sgfru_getsegments(const sgfru_init_arg_t * iargp)61803831d35Sstevel sgfru_getsegments(const sgfru_init_arg_t *iargp)
61903831d35Sstevel {
62003831d35Sstevel 	int32_t ret;
62103831d35Sstevel 	caddr_t datap;
62203831d35Sstevel 	size_t ssize, size;
62303831d35Sstevel 	frup_info_t segs;
62403831d35Sstevel 	fru_cnt_t max_cnt;
62503831d35Sstevel 	segment_t *segp;
62603831d35Sstevel 
62703831d35Sstevel 	/* copyin frup_info_t */
62803831d35Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
62903831d35Sstevel 		return (EFAULT);
63003831d35Sstevel 	}
63103831d35Sstevel 	/* check on kmem_alloc space requirements */
63203831d35Sstevel 	max_cnt = segs.fru_cnt;
63303831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTS)) {
63403831d35Sstevel 		return (EINVAL);
63503831d35Sstevel 	}
63603831d35Sstevel 
63703831d35Sstevel 	/* allocate unpadded buffer for fru_info_t + segment_t's */
63803831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * SEGMENT_SIZE));
63903831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
64003831d35Sstevel 
64103831d35Sstevel 	/* call mailbox */
64203831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
64303831d35Sstevel 		kmem_free(datap, size);
64403831d35Sstevel 		return (ret);
64503831d35Sstevel 	}
64603831d35Sstevel 
64703831d35Sstevel 	/* allocate buffer for padded segment_t's */
64803831d35Sstevel 	ssize = (size_t)(max_cnt * sizeof (segment_t));
64903831d35Sstevel 	segp = (segment_t *)kmem_zalloc(ssize, KM_SLEEP);
65003831d35Sstevel 
65103831d35Sstevel 	/* translate unpadded to padded fru_info_t + segment_t's */
65203831d35Sstevel 	if ((ret = sgfru_segment_pad(datap, max_cnt, &segs.fru_info, segp))
65303831d35Sstevel 	    != 0) {
65403831d35Sstevel 		kmem_free(datap, size);
65503831d35Sstevel 		kmem_free(segp, ssize);
65603831d35Sstevel 		return (ret);
65703831d35Sstevel 	}
65803831d35Sstevel 	/* free segment_t buffer */
65903831d35Sstevel 	kmem_free(datap, size);
66003831d35Sstevel 
66103831d35Sstevel 	/* copy out fru_info_t */
66203831d35Sstevel 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
66303831d35Sstevel 		kmem_free(segp, ssize);
66403831d35Sstevel 		return (EFAULT);
66503831d35Sstevel 	}
66603831d35Sstevel 	/* copyout segment_t's */
66703831d35Sstevel 	if (sgfru_copyout_segments(iargp, &segs, segp) != 0) {
66803831d35Sstevel 		kmem_free(segp, ssize);
66903831d35Sstevel 		return (EFAULT);
67003831d35Sstevel 	}
67103831d35Sstevel 	/* free segment_t buffer */
67203831d35Sstevel 	kmem_free(segp, ssize);
67303831d35Sstevel 
67403831d35Sstevel 	return (ret);
67503831d35Sstevel }
67603831d35Sstevel 
67703831d35Sstevel static int
sgfru_addsegment(const sgfru_init_arg_t * iargp)67803831d35Sstevel sgfru_addsegment(const sgfru_init_arg_t *iargp)
67903831d35Sstevel {
68003831d35Sstevel 	int32_t ret;
68103831d35Sstevel 	caddr_t datap;
68203831d35Sstevel 	size_t size;
68303831d35Sstevel 	frup_info_t seg;
68403831d35Sstevel 	segment_t segment;
68503831d35Sstevel 	fru_hdl_t *hdlp;
68603831d35Sstevel 	static fn_t f = "sgfru_addsegment";
68703831d35Sstevel 
68803831d35Sstevel 	/* copyin frup_info_t */
68903831d35Sstevel 	if (sgfru_copyin_frup(iargp, &seg) != 0) {
69003831d35Sstevel 		return (EFAULT);
69103831d35Sstevel 	}
69203831d35Sstevel 	/* copyin segment_t */
69303831d35Sstevel 	if (sgfru_copyin_segment(iargp, &seg, &segment) != 0) {
69403831d35Sstevel 		return (EFAULT);
69503831d35Sstevel 	}
69603831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
69719397407SSherry Moore 	    f, seg.fru_hdl, seg.fru_cnt);
69803831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, "
69919397407SSherry Moore 	    "offset 0x%x, length 0x%x\n", f, segment.handle, segment.name,
70019397407SSherry Moore 	    segment.descriptor, segment.offset, segment.length);
70103831d35Sstevel 
70203831d35Sstevel 	/* allocate buffer for unpadded section_hdl_t + segment_t */
70303831d35Sstevel 	size = (size_t)(SECTION_HDL_SIZE + SEGMENT_SIZE);
70403831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
70503831d35Sstevel 	/* translate padded to unpadded section_hdl_t + segment_t */
70603831d35Sstevel 	sgfru_segment_unpad(&seg.fru_info, &segment, datap);
70703831d35Sstevel 
70803831d35Sstevel 	/* call mailbox */
70903831d35Sstevel 	ret = sgfru_mbox(iargp->cmd, datap, size, &seg.fru_info);
71003831d35Sstevel 	if (ret != 0) {
71103831d35Sstevel 		kmem_free(datap, size);
71203831d35Sstevel 		return (ret);
71303831d35Sstevel 	}
71403831d35Sstevel 
71503831d35Sstevel 	/* copyout updated section_hdl_t */
71603831d35Sstevel 	hdlp = (fru_hdl_t *)(datap + sizeof (fru_hdl_t));
71703831d35Sstevel 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
71803831d35Sstevel 		kmem_free(datap, size);
71903831d35Sstevel 		return (EFAULT);
72003831d35Sstevel 	}
72103831d35Sstevel 	/* copyout new segment_hdl_t */
72203831d35Sstevel 	if (sgfru_copyout_handle(iargp, seg.frus, --hdlp) != 0) {
72303831d35Sstevel 		kmem_free(datap, size);
72403831d35Sstevel 		return (EFAULT);
72503831d35Sstevel 	}
72603831d35Sstevel 	/* free segment_t buffer */
72703831d35Sstevel 	kmem_free(datap, size);
72803831d35Sstevel 
72903831d35Sstevel 	return (ret);
73003831d35Sstevel }
73103831d35Sstevel 
73203831d35Sstevel /*
73303831d35Sstevel  * Used for fru_read_segment().
73403831d35Sstevel  */
73503831d35Sstevel static int
sgfru_readsegment(const sgfru_init_arg_t * iargp)73603831d35Sstevel sgfru_readsegment(const sgfru_init_arg_t *iargp)
73703831d35Sstevel {
73803831d35Sstevel 	int32_t ret;
73903831d35Sstevel 	caddr_t datap, tdatap;
74003831d35Sstevel 	size_t size;
74103831d35Sstevel 	frup_info_t segs;
74203831d35Sstevel 	fru_info_t sinfo;
74303831d35Sstevel 	fru_cnt_t max_cnt;
74403831d35Sstevel 	static fn_t f = "sgfru_readsegment";
74503831d35Sstevel 
74603831d35Sstevel 	/* copyin one segments_t aka frup_info_t */
74703831d35Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
74803831d35Sstevel 		return (EFAULT);
74903831d35Sstevel 	}
75003831d35Sstevel 	/* check on kmem_alloc space requirements */
75103831d35Sstevel 	max_cnt = segs.fru_cnt;
75203831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
75303831d35Sstevel 		return (EINVAL);
75403831d35Sstevel 	}
75503831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
75619397407SSherry Moore 	    f, segs.fru_hdl, segs.fru_cnt);
75703831d35Sstevel 
75803831d35Sstevel 	/* allocate unpadded buffer for raw data */
75903831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
76003831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
76103831d35Sstevel 
76203831d35Sstevel 	/* call mailbox */
76303831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
76403831d35Sstevel 		kmem_free(datap, size);
76503831d35Sstevel 		return (ret);
76603831d35Sstevel 	}
76703831d35Sstevel 
76803831d35Sstevel 	/* translate unpadded to padded fru_info_t */
76903831d35Sstevel 	tdatap = sgfru_fru_pad(datap, &sinfo);
77003831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
77119397407SSherry Moore 	    f, sinfo.hdl, sinfo.cnt);
77203831d35Sstevel 
77303831d35Sstevel 	/* copyout actual fru_cnt */
77403831d35Sstevel 	if (sgfru_copyout_fru(iargp, &sinfo) != 0) {
77503831d35Sstevel 		kmem_free(datap, size);
77603831d35Sstevel 		return (EFAULT);
77703831d35Sstevel 	}
77803831d35Sstevel 	/* copyout raw segment data */
77903831d35Sstevel 	if (sgfru_copyout_buffer(iargp, &segs, tdatap) != 0) {
78003831d35Sstevel 		kmem_free(datap, size);
78103831d35Sstevel 		return (EFAULT);
78203831d35Sstevel 	}
78303831d35Sstevel 	/* free buffer */
78403831d35Sstevel 	kmem_free(datap, size);
78503831d35Sstevel 
78603831d35Sstevel 	return (ret);
78703831d35Sstevel }
78803831d35Sstevel 
78903831d35Sstevel /*
79003831d35Sstevel  * Used for fru_write_segment().
79103831d35Sstevel  */
79203831d35Sstevel static int
sgfru_writesegment(const sgfru_init_arg_t * iargp)79303831d35Sstevel sgfru_writesegment(const sgfru_init_arg_t *iargp)
79403831d35Sstevel {
79503831d35Sstevel 	int32_t ret;
79603831d35Sstevel 	caddr_t datap, tdatap;
79703831d35Sstevel 	size_t size;
79803831d35Sstevel 	frup_info_t segs;
79903831d35Sstevel 	fru_cnt_t max_cnt;
80003831d35Sstevel 	static fn_t f = "sgfru_writesegment";
80103831d35Sstevel 
80203831d35Sstevel 	/* copyin frup_info_t */
80303831d35Sstevel 	if (sgfru_copyin_frup(iargp, &segs) != 0) {
80403831d35Sstevel 		return (EFAULT);
80503831d35Sstevel 	}
80603831d35Sstevel 	/* check on kmem_alloc space requirements */
80703831d35Sstevel 	max_cnt = segs.fru_cnt;
80803831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) {
80903831d35Sstevel 		return (EINVAL);
81003831d35Sstevel 	}
81103831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
81219397407SSherry Moore 	    f, segs.fru_hdl, segs.fru_cnt);
81303831d35Sstevel 
81403831d35Sstevel 	/* allocate unpadded buffer for fru_info_t + raw data */
81503831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
81603831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
81703831d35Sstevel 
81803831d35Sstevel 	/* translate padded to unpadded fru_info_t */
81903831d35Sstevel 	tdatap = sgfru_fru_unpad(&segs.fru_info, datap);
82003831d35Sstevel 
82103831d35Sstevel 	/* copyin raw segment data */
82203831d35Sstevel 	if (sgfru_copyin_buffer(iargp, segs.frus, max_cnt, tdatap) != 0) {
82303831d35Sstevel 		kmem_free(datap, size);
82403831d35Sstevel 		return (EFAULT);
82503831d35Sstevel 	}
82603831d35Sstevel 
82703831d35Sstevel 	/* call mailbox */
82803831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) {
82903831d35Sstevel 		kmem_free(datap, size);
83003831d35Sstevel 		return (ret);
83103831d35Sstevel 	}
83203831d35Sstevel 	/* free buffer */
83303831d35Sstevel 	kmem_free(datap, size);
83403831d35Sstevel 
83503831d35Sstevel 	PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
83619397407SSherry Moore 	    f, segs.fru_hdl, segs.fru_cnt);
83703831d35Sstevel 	/* copyout updated segment handle and actual fru_cnt */
83803831d35Sstevel 	if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) {
83903831d35Sstevel 		return (EFAULT);
84003831d35Sstevel 	}
84103831d35Sstevel 
84203831d35Sstevel 	return (ret);
84303831d35Sstevel }
84403831d35Sstevel 
84503831d35Sstevel /*
84603831d35Sstevel  * Used for fru_get_packets().
84703831d35Sstevel  */
84803831d35Sstevel static int
sgfru_getpackets(const sgfru_init_arg_t * iargp)84903831d35Sstevel sgfru_getpackets(const sgfru_init_arg_t *iargp)
85003831d35Sstevel {
85103831d35Sstevel 	int32_t ret;
85203831d35Sstevel 	caddr_t datap;
85303831d35Sstevel 	size_t ssize, size;
85403831d35Sstevel 	frup_info_t packs;
85503831d35Sstevel 	fru_cnt_t max_cnt;
85603831d35Sstevel 	packet_t *packp;
85703831d35Sstevel 
85803831d35Sstevel 	/* copyin packets_t aka frup_info_t */
85903831d35Sstevel 	if (sgfru_copyin_frup(iargp, &packs) != 0) {
86003831d35Sstevel 		return (EFAULT);
86103831d35Sstevel 	}
86203831d35Sstevel 	/* check on kmem_alloc space requirements */
86303831d35Sstevel 	max_cnt = packs.fru_cnt;
86403831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PACKETS)) {
86503831d35Sstevel 		return (EINVAL);
86603831d35Sstevel 	}
86703831d35Sstevel 
86803831d35Sstevel 	/* allocate buffer for unpadded fru_info_t + packet_t's */
86903831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + (max_cnt * PACKET_SIZE));
87003831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
87103831d35Sstevel 
87203831d35Sstevel 	/* call mailbox */
87303831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &packs.fru_info))
87403831d35Sstevel 	    != 0) {
87503831d35Sstevel 		kmem_free(datap, size);
87603831d35Sstevel 		return (ret);
87703831d35Sstevel 	}
87803831d35Sstevel 
87903831d35Sstevel 	/* allocate buffer for padded packet_t's */
88003831d35Sstevel 	ssize = (size_t)(max_cnt * sizeof (packet_t));
88103831d35Sstevel 	packp = (packet_t *)kmem_zalloc(ssize, KM_SLEEP);
88203831d35Sstevel 
88303831d35Sstevel 	/* translate unpadded to padded fru_info_t + packet_t's */
88403831d35Sstevel 	if ((ret = sgfru_packet_pad(datap, max_cnt, &packs.fru_info, packp))
88503831d35Sstevel 	    != 0) {
88603831d35Sstevel 		kmem_free(datap, size);
88703831d35Sstevel 		kmem_free(packp, ssize);
88803831d35Sstevel 		return (ret);
88903831d35Sstevel 	}
89003831d35Sstevel 	/* free packet_t buffer */
89103831d35Sstevel 	kmem_free(datap, size);
89203831d35Sstevel 
89303831d35Sstevel 	/* copy out fru_info_t */
89403831d35Sstevel 	if (sgfru_copyout_fru(iargp, &packs.fru_info) != 0) {
89503831d35Sstevel 		kmem_free(packp, ssize);
89603831d35Sstevel 		return (EFAULT);
89703831d35Sstevel 	}
89803831d35Sstevel 	/* copyout packet_t's */
89903831d35Sstevel 	if (sgfru_copyout_packets(iargp, &packs, packp) != 0) {
90003831d35Sstevel 		kmem_free(packp, ssize);
90103831d35Sstevel 		return (EFAULT);
90203831d35Sstevel 	}
90303831d35Sstevel 	/* free packet_t buffer */
90403831d35Sstevel 	kmem_free(packp, ssize);
90503831d35Sstevel 
90603831d35Sstevel 	return (ret);
90703831d35Sstevel }
90803831d35Sstevel 
90903831d35Sstevel /*
91003831d35Sstevel  * Used for fru_append_packet().
91103831d35Sstevel  */
91203831d35Sstevel static int
sgfru_appendpacket(const sgfru_init_arg_t * iargp)91303831d35Sstevel sgfru_appendpacket(const sgfru_init_arg_t *iargp)
91403831d35Sstevel {
91503831d35Sstevel 	int32_t ret = 0;
91603831d35Sstevel 	caddr_t datap, tdatap;
91703831d35Sstevel 	size_t size;
91803831d35Sstevel 	append_info_t append;
91903831d35Sstevel 	fru_cnt_t max_cnt;
92003831d35Sstevel 	fru_hdl_t *hdlp;
92103831d35Sstevel 	caddr_t addr;
92203831d35Sstevel 
92303831d35Sstevel 	/* copyin append_info_t */
92403831d35Sstevel 	if (sgfru_copyin_append(iargp, &append) != 0) {
92503831d35Sstevel 		return (EFAULT);
92603831d35Sstevel 	}
92703831d35Sstevel 	/* check on kmem_alloc space requirements */
92803831d35Sstevel 	max_cnt = append.payload_cnt;
92903831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
93003831d35Sstevel 		return (EINVAL);
93103831d35Sstevel 	}
93203831d35Sstevel 
93303831d35Sstevel 	/* allocate buffer for unpadded fru_info_t + packet_t + payload */
93403831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + PACKET_SIZE + max_cnt);
93503831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
93603831d35Sstevel 	/* translate padded to unpadded fru_info_t plus packet_t */
93703831d35Sstevel 	tdatap = sgfru_packet_unpad(&append.payload.fru_info, &append.packet,
93803831d35Sstevel 	    datap);
93903831d35Sstevel 
94003831d35Sstevel 	/* copyin payload to the end of the unpadded buffer */
94103831d35Sstevel 	if (sgfru_copyin_buffer(iargp, append.payload_data, append.payload_cnt,
94203831d35Sstevel 	    tdatap) != 0) {
94303831d35Sstevel 		kmem_free(datap, size);
94403831d35Sstevel 		return (EFAULT);
94503831d35Sstevel 	}
94603831d35Sstevel 
94703831d35Sstevel 	/* call mailbox */
94803831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size,
94903831d35Sstevel 	    &append.payload.fru_info)) != 0) {
95003831d35Sstevel 		kmem_free(datap, size);
95103831d35Sstevel 		return (ret);
95203831d35Sstevel 	}
95303831d35Sstevel 
95403831d35Sstevel 	/* copyout new packet_hdl_t */
95503831d35Sstevel 	hdlp = (fru_hdl_t *)datap;
95603831d35Sstevel 	if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) {
95703831d35Sstevel 		kmem_free(datap, size);
95803831d35Sstevel 		return (EFAULT);
95903831d35Sstevel 	}
96003831d35Sstevel 	/* copyout updated segment_hdl_t */
96103831d35Sstevel 	addr = (caddr_t)(iargp->argp + sizeof (packet_t));
96203831d35Sstevel 	if (sgfru_copyout_handle(iargp, addr, ++hdlp) != 0) {
96303831d35Sstevel 		kmem_free(datap, size);
96403831d35Sstevel 		return (EFAULT);
96503831d35Sstevel 	}
96603831d35Sstevel 
96703831d35Sstevel 	/* free buffer */
96803831d35Sstevel 	kmem_free(datap, size);
96903831d35Sstevel 
97003831d35Sstevel 	return (ret);
97103831d35Sstevel }
97203831d35Sstevel 
97303831d35Sstevel /*
97403831d35Sstevel  * Used for fru_get_payload().
97503831d35Sstevel  */
97603831d35Sstevel static int
sgfru_getpayload(const sgfru_init_arg_t * iargp)97703831d35Sstevel sgfru_getpayload(const sgfru_init_arg_t *iargp)
97803831d35Sstevel {
97903831d35Sstevel 	int32_t ret;
98003831d35Sstevel 	caddr_t datap, tdatap;
98103831d35Sstevel 	size_t size;
98203831d35Sstevel 	frup_info_t payld;
98303831d35Sstevel 	fru_info_t pinfo;
98403831d35Sstevel 	fru_cnt_t max_cnt;
98503831d35Sstevel 	static fn_t f = "sgfru_getpayload";
98603831d35Sstevel 
98703831d35Sstevel 	/* copyin payload_t aka frup_info_t */
98803831d35Sstevel 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
98903831d35Sstevel 		return (EFAULT);
99003831d35Sstevel 	}
99103831d35Sstevel 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
99219397407SSherry Moore 	    f, payld.fru_hdl, payld.fru_cnt);
99303831d35Sstevel 
99403831d35Sstevel 	/* check on kmem_alloc space requirements */
99503831d35Sstevel 	max_cnt = payld.fru_cnt;
99603831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
99703831d35Sstevel 		return (EINVAL);
99803831d35Sstevel 	}
99903831d35Sstevel 
100003831d35Sstevel 	/* allocate buffer for fru_info_t + payload */
100103831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
100203831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
100303831d35Sstevel 
100403831d35Sstevel 	/* call mailbox */
100503831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
100603831d35Sstevel 	    != 0) {
100703831d35Sstevel 		kmem_free(datap, size);
100803831d35Sstevel 		return (ret);
100903831d35Sstevel 	}
101003831d35Sstevel 
101103831d35Sstevel 	/* translate unpadded to padded fru_info_t */
101203831d35Sstevel 	tdatap = sgfru_fru_pad(datap, &pinfo);
101303831d35Sstevel 	PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
101419397407SSherry Moore 	    f, pinfo.hdl, pinfo.cnt);
101503831d35Sstevel 
101603831d35Sstevel 	/* copyout actual fru_cnt */
101703831d35Sstevel 	if (sgfru_copyout_fru(iargp, &pinfo) != 0) {
101803831d35Sstevel 		kmem_free(datap, size);
101903831d35Sstevel 		return (EFAULT);
102003831d35Sstevel 	}
102103831d35Sstevel 	/* copyout raw packet data, aka the payload */
102203831d35Sstevel 	if (sgfru_copyout_buffer(iargp, &payld, tdatap) != 0) {
102303831d35Sstevel 		kmem_free(datap, size);
102403831d35Sstevel 		return (EFAULT);
102503831d35Sstevel 	}
102603831d35Sstevel 
102703831d35Sstevel 	/* free buffer */
102803831d35Sstevel 	kmem_free(datap, size);
102903831d35Sstevel 
103003831d35Sstevel 	return (ret);
103103831d35Sstevel }
103203831d35Sstevel 
103303831d35Sstevel /*
103403831d35Sstevel  * Used for fru_update_payload().
103503831d35Sstevel  */
103603831d35Sstevel static int
sgfru_updatepayload(const sgfru_init_arg_t * iargp)103703831d35Sstevel sgfru_updatepayload(const sgfru_init_arg_t *iargp)
103803831d35Sstevel {
103903831d35Sstevel 	int32_t ret;
104003831d35Sstevel 	caddr_t datap, tdatap;
104103831d35Sstevel 	size_t size;
104203831d35Sstevel 	frup_info_t payld;
104303831d35Sstevel 	fru_cnt_t max_cnt;
104403831d35Sstevel 	static fn_t f = "sgfru_updatepayload";
104503831d35Sstevel 
104603831d35Sstevel 	/* copyin frup_info_t */
104703831d35Sstevel 	if (sgfru_copyin_frup(iargp, &payld) != 0) {
104803831d35Sstevel 		return (EFAULT);
104903831d35Sstevel 	}
105003831d35Sstevel 	/* check on kmem_alloc space requirements */
105103831d35Sstevel 	max_cnt = payld.fru_cnt;
105203831d35Sstevel 	if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) {
105303831d35Sstevel 		return (EINVAL);
105403831d35Sstevel 	}
105503831d35Sstevel 
105603831d35Sstevel 	/* allocate buffer for fru_info_t + payload */
105703831d35Sstevel 	size = (size_t)(FRU_INFO_SIZE + max_cnt);
105803831d35Sstevel 	datap = kmem_zalloc(size, KM_SLEEP);
105903831d35Sstevel 
106003831d35Sstevel 	/* translate padded to unpadded fru_info_t */
106103831d35Sstevel 	tdatap = sgfru_fru_unpad(&payld.fru_info, datap);
106203831d35Sstevel 
106303831d35Sstevel 	/* copyin payload */
106403831d35Sstevel 	if (sgfru_copyin_buffer(iargp, payld.frus, max_cnt, tdatap) != 0) {
106503831d35Sstevel 		kmem_free(datap, size);
106603831d35Sstevel 		return (EFAULT);
106703831d35Sstevel 	}
106803831d35Sstevel 	PR_PAYLOAD("sgfru_updatepayload: handle %lx, actual cnt %d\n",
106919397407SSherry Moore 	    payld.fru_hdl, payld.fru_cnt);
107003831d35Sstevel 
107103831d35Sstevel 	/* call mailbox */
107203831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info))
107303831d35Sstevel 	    != 0) {
107403831d35Sstevel 		kmem_free(datap, size);
107503831d35Sstevel 		return (ret);
107603831d35Sstevel 	}
107703831d35Sstevel 
107803831d35Sstevel 	/* free buffer */
107903831d35Sstevel 	kmem_free(datap, size);
108003831d35Sstevel 
108103831d35Sstevel 	/* copyout new packet_hdl_t and actual count */
108203831d35Sstevel 	if (sgfru_copyout_fru(iargp, &payld.fru_info) != 0) {
108303831d35Sstevel 		return (EFAULT);
108403831d35Sstevel 	}
108503831d35Sstevel 	PR_PAYLOAD("sgfru:%s: new handle %lx, cnt %d\n",
108619397407SSherry Moore 	    f, payld.fru_hdl, payld.fru_cnt);
108703831d35Sstevel 
108803831d35Sstevel 	return (ret);
108903831d35Sstevel }
109003831d35Sstevel 
109103831d35Sstevel /*
109203831d35Sstevel  * Used for fru_get_num_[sections|segments|packets]().
109303831d35Sstevel  */
109403831d35Sstevel static int
sgfru_getnum(const sgfru_init_arg_t * iargp)109503831d35Sstevel sgfru_getnum(const sgfru_init_arg_t *iargp)
109603831d35Sstevel {
109703831d35Sstevel 	int32_t ret;
109803831d35Sstevel 	caddr_t datap;
109903831d35Sstevel 	size_t size;
110003831d35Sstevel 	fru_info_t fru_info;
110103831d35Sstevel 
110203831d35Sstevel 	/* copyin fru_info_t */
110303831d35Sstevel 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
110403831d35Sstevel 		return (EFAULT);
110503831d35Sstevel 	}
110603831d35Sstevel 
110703831d35Sstevel 	size = sizeof (fru_cnt_t);
110803831d35Sstevel 	datap = (caddr_t)&fru_info.cnt;
110903831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
111003831d35Sstevel 		return (ret);
111103831d35Sstevel 	}
111203831d35Sstevel 
111303831d35Sstevel 	/* copyout fru_info_t */
111403831d35Sstevel 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
111503831d35Sstevel 		return (EFAULT);
111603831d35Sstevel 	}
111703831d35Sstevel 	return (ret);
111803831d35Sstevel }
111903831d35Sstevel 
112003831d35Sstevel /*
112103831d35Sstevel  * Used for fru_delete_[segment|packet].
112203831d35Sstevel  */
112303831d35Sstevel static int
sgfru_delete(const sgfru_init_arg_t * iargp)112403831d35Sstevel sgfru_delete(const sgfru_init_arg_t *iargp)
112503831d35Sstevel {
112603831d35Sstevel 	int32_t ret;
112703831d35Sstevel 	caddr_t datap;
112803831d35Sstevel 	size_t size;
112903831d35Sstevel 	fru_info_t fru_info;
113003831d35Sstevel 	static fn_t f = "sgfru_delete";
113103831d35Sstevel 
113203831d35Sstevel 	/* copyin fru_info_t */
113303831d35Sstevel 	if (sgfru_copyin_fru(iargp, &fru_info) != 0) {
113403831d35Sstevel 		return (EFAULT);
113503831d35Sstevel 	}
113603831d35Sstevel 	PR_SEGMENT("sgfru:%s: delete handle %lx\n", f, fru_info.hdl);
113703831d35Sstevel 
113803831d35Sstevel 	size = sizeof (fru_hdl_t);
113903831d35Sstevel 	datap = (caddr_t)&fru_info.hdl;
114003831d35Sstevel 	if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) {
114103831d35Sstevel 		return (ret);
114203831d35Sstevel 	}
114303831d35Sstevel 
114403831d35Sstevel 	PR_SEGMENT("sgfru:%s: new parent handle %lx\n", f, fru_info.hdl);
114503831d35Sstevel 	/* copyout fru_info_t */
114603831d35Sstevel 	if (sgfru_copyout_fru(iargp, &fru_info) != 0) {
114703831d35Sstevel 		return (EFAULT);
114803831d35Sstevel 	}
114903831d35Sstevel 	return (ret);
115003831d35Sstevel }
115103831d35Sstevel 
115203831d35Sstevel /*
115303831d35Sstevel  * Calls the sgsbbc mailbox with data, returns data and status info.
115403831d35Sstevel  */
115503831d35Sstevel static int
sgfru_mbox(const int cmd,char * datap,const size_t size,fru_info_t * fru)115603831d35Sstevel sgfru_mbox(const int cmd, char *datap, const size_t size, fru_info_t *fru)
115703831d35Sstevel {
115803831d35Sstevel 	sbbc_msg_t request, *reqp = &request;
115903831d35Sstevel 	sbbc_msg_t response, *resp = &response;
116003831d35Sstevel 	fru_hdl_t hdls[2] = {0, 0};
116103831d35Sstevel 	fru_hdl_t hdl = fru->hdl;
116203831d35Sstevel 	int rv = 0;
116303831d35Sstevel 	static fn_t f = "sgfru_mbox";
116403831d35Sstevel 
116503831d35Sstevel 	bzero((caddr_t)&request, sizeof (sbbc_msg_t));
116603831d35Sstevel 	reqp->msg_type.type = SGFRU_MBOX;
116703831d35Sstevel 	bzero((caddr_t)&response, sizeof (sbbc_msg_t));
116803831d35Sstevel 	resp->msg_type.type = SGFRU_MBOX;
116903831d35Sstevel 	PR_MBOX("sgfru:%s: cmd 0x%x, size %lu\n", f, cmd, size);
117003831d35Sstevel 
117103831d35Sstevel 	switch (cmd) {
117203831d35Sstevel 
117303831d35Sstevel 	case SGFRU_GETCHILDLIST:
117403831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
117503831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
117603831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
117703831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST;
117803831d35Sstevel 		resp->msg_len = size;
117903831d35Sstevel 		resp->msg_buf = datap;
118003831d35Sstevel 		break;
118103831d35Sstevel 
118203831d35Sstevel 	case SGFRU_GETCHILDHANDLES:
118303831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
118403831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
118503831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
118603831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES;
118703831d35Sstevel 		resp->msg_len = size;
118803831d35Sstevel 		resp->msg_buf = datap;
118903831d35Sstevel 		break;
119003831d35Sstevel 
119103831d35Sstevel 	case SGFRU_GETNODEINFO:
119203831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
119303831d35Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
119403831d35Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
119503831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO;
119603831d35Sstevel 		resp->msg_len = size;
119703831d35Sstevel 		resp->msg_buf = datap;
119803831d35Sstevel 		break;
119903831d35Sstevel 
120003831d35Sstevel 	case SGFRU_GETNUMSECTIONS:
120103831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
120203831d35Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
120303831d35Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
120403831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS;
120503831d35Sstevel 		resp->msg_len = size;
120603831d35Sstevel 		resp->msg_buf = datap;
120703831d35Sstevel 		break;
120803831d35Sstevel 
120903831d35Sstevel 	case SGFRU_GETNUMSEGMENTS:
121003831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
121103831d35Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
121203831d35Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
121303831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS;
121403831d35Sstevel 		resp->msg_len = size;
121503831d35Sstevel 		resp->msg_buf = datap;
121603831d35Sstevel 		break;
121703831d35Sstevel 
121803831d35Sstevel 	case SGFRU_GETNUMPACKETS:
121903831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
122003831d35Sstevel 		reqp->msg_len = sizeof (fru_hdl_t);
122103831d35Sstevel 		reqp->msg_buf = (caddr_t)&hdl;
122203831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS;
122303831d35Sstevel 		resp->msg_len = size;
122403831d35Sstevel 		resp->msg_buf = datap;
122503831d35Sstevel 		break;
122603831d35Sstevel 
122703831d35Sstevel 	case SGFRU_GETSECTIONS:
122803831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
122903831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
123003831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
123103831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS;
123203831d35Sstevel 		resp->msg_len = size;
123303831d35Sstevel 		resp->msg_buf = datap;
123403831d35Sstevel 		break;
123503831d35Sstevel 
123603831d35Sstevel 	case SGFRU_GETSEGMENTS:
123703831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
123803831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
123903831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
124003831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS;
124103831d35Sstevel 		resp->msg_len = size;
124203831d35Sstevel 		resp->msg_buf = datap;
124303831d35Sstevel 		break;
124403831d35Sstevel 
124503831d35Sstevel 	case SGFRU_GETPACKETS:
124603831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
124703831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
124803831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
124903831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS;
125003831d35Sstevel 		resp->msg_len = size;
125103831d35Sstevel 		resp->msg_buf = datap;
125203831d35Sstevel 		break;
125303831d35Sstevel 
125403831d35Sstevel 	case SGFRU_ADDSEGMENT:
125503831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
125603831d35Sstevel 		reqp->msg_len = size;
125703831d35Sstevel 		reqp->msg_buf = datap;
125803831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT;
125903831d35Sstevel 		resp->msg_len = sizeof (hdls);
126003831d35Sstevel 		resp->msg_buf = (caddr_t)&hdls;
126103831d35Sstevel 		break;
126203831d35Sstevel 
126303831d35Sstevel 	case SGFRU_APPENDPACKET:
126403831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
126503831d35Sstevel 		reqp->msg_len = size;
126603831d35Sstevel 		reqp->msg_buf = (caddr_t)datap;
126703831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET;
126803831d35Sstevel 		resp->msg_len = sizeof (hdls);
126903831d35Sstevel 		resp->msg_buf = (caddr_t)&hdls;
127003831d35Sstevel 		break;
127103831d35Sstevel 
127203831d35Sstevel 	case SGFRU_DELETESEGMENT:
127303831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
127403831d35Sstevel 		reqp->msg_len = size;
127503831d35Sstevel 		reqp->msg_buf = (caddr_t)datap;
127603831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT;
127703831d35Sstevel 		resp->msg_len = sizeof (fru_hdl_t);
127803831d35Sstevel 		resp->msg_buf = (caddr_t)&hdl;
127903831d35Sstevel 		break;
128003831d35Sstevel 
128103831d35Sstevel 	case SGFRU_READRAWSEGMENT:
128203831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_READRAWSEGMENT;
128303831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
128403831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
128503831d35Sstevel 		resp->msg_type.sub_type = SGFRU_READRAWSEGMENT;
128603831d35Sstevel 		resp->msg_len = size;
128703831d35Sstevel 		resp->msg_buf = datap;
128803831d35Sstevel 		break;
128903831d35Sstevel 
129003831d35Sstevel 	case SGFRU_WRITERAWSEGMENT:
129103831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_WRITERAWSEGMENT;
129203831d35Sstevel 		reqp->msg_len = size;
129303831d35Sstevel 		reqp->msg_buf = datap;
129403831d35Sstevel 		resp->msg_type.sub_type = SGFRU_WRITERAWSEGMENT;
129503831d35Sstevel 		resp->msg_len = sizeof (fru_info_t);
129603831d35Sstevel 		resp->msg_buf = (caddr_t)fru;
129703831d35Sstevel 		break;
129803831d35Sstevel 
129903831d35Sstevel 	case SGFRU_DELETEPACKET:
130003831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
130103831d35Sstevel 		reqp->msg_len = size;
130203831d35Sstevel 		reqp->msg_buf = (caddr_t)datap;
130303831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET;
130403831d35Sstevel 		resp->msg_len = sizeof (fru_hdl_t);
130503831d35Sstevel 		resp->msg_buf = (caddr_t)&hdl;
130603831d35Sstevel 		break;
130703831d35Sstevel 
130803831d35Sstevel 	case SGFRU_GETPAYLOAD:
130903831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
131003831d35Sstevel 		reqp->msg_len = sizeof (fru_info_t);
131103831d35Sstevel 		reqp->msg_buf = (caddr_t)fru;
131203831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD;
131303831d35Sstevel 		resp->msg_len = size;
131403831d35Sstevel 		resp->msg_buf = datap;
131503831d35Sstevel 		break;
131603831d35Sstevel 
131703831d35Sstevel 	case SGFRU_UPDATEPAYLOAD:
131803831d35Sstevel 		reqp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
131903831d35Sstevel 		reqp->msg_len = size;
132003831d35Sstevel 		reqp->msg_buf = datap;
132103831d35Sstevel 		resp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD;
132203831d35Sstevel 		resp->msg_len = sizeof (fru_info_t);
132303831d35Sstevel 		resp->msg_buf = (caddr_t)fru;
132403831d35Sstevel 		break;
132503831d35Sstevel 
132603831d35Sstevel 	default:
132703831d35Sstevel 		return (EINVAL);
132803831d35Sstevel 	}
132903831d35Sstevel 
133003831d35Sstevel 	rv = sbbc_mbox_request_response(reqp, resp, sgfru_mbox_wait);
133103831d35Sstevel 	PR_MBOX("sgfru:%s: rv %d, msg_status %d\n", f, rv, resp->msg_status);
133203831d35Sstevel 
133303831d35Sstevel 	if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
133403831d35Sstevel 
133503831d35Sstevel 		/* errors from sgsbbc */
133603831d35Sstevel 		if (resp->msg_status > 0) {
133703831d35Sstevel 			return (resp->msg_status);
133803831d35Sstevel 		}
133903831d35Sstevel 
134003831d35Sstevel 		/* errors from SCAPP */
134103831d35Sstevel 		switch (resp->msg_status) {
134203831d35Sstevel 
134303831d35Sstevel 		case SG_MBOX_STATUS_COMMAND_FAILURE:
134403831d35Sstevel 			/* internal SCAPP error */
134503831d35Sstevel 			return (EINTR);
134603831d35Sstevel 
134703831d35Sstevel 		case SG_MBOX_STATUS_HARDWARE_FAILURE:
134803831d35Sstevel 			/* seprom read/write errors */
134903831d35Sstevel 			return (EIO);
135003831d35Sstevel 
135103831d35Sstevel 		case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
135203831d35Sstevel 			/* illegal ioctl parameter */
135303831d35Sstevel 			return (EINVAL);
135403831d35Sstevel 
135503831d35Sstevel 		case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
135603831d35Sstevel 			/* board access denied */
135703831d35Sstevel 			return (EACCES);
135803831d35Sstevel 
135903831d35Sstevel 		case SG_MBOX_STATUS_STALE_CONTENTS:
136003831d35Sstevel 			/* stale contents */
136103831d35Sstevel 			return (ESTALE);
136203831d35Sstevel 
136303831d35Sstevel 		case SG_MBOX_STATUS_STALE_OBJECT:
136403831d35Sstevel 			/* stale handle */
136503831d35Sstevel 			return (ENOENT);
136603831d35Sstevel 
136703831d35Sstevel 		case SG_MBOX_STATUS_NO_SEPROM_SPACE:
136803831d35Sstevel 			/* seprom lacks space */
136903831d35Sstevel 			return (ENOSPC);
137003831d35Sstevel 
137103831d35Sstevel 		case SG_MBOX_STATUS_NO_MEMORY:
137203831d35Sstevel 			/* user prog. lacks space */
137303831d35Sstevel 			return (ENOMEM);
137403831d35Sstevel 
137503831d35Sstevel 		case SG_MBOX_STATUS_NOT_SUPPORTED:
137603831d35Sstevel 			/* unsupported operation */
137703831d35Sstevel 			return (ENOTSUP);
137803831d35Sstevel 
137903831d35Sstevel 		default:
138003831d35Sstevel 			return (EIO);
138103831d35Sstevel 		}
138203831d35Sstevel 	}
138303831d35Sstevel 
138403831d35Sstevel 	switch (cmd) {
138503831d35Sstevel 
138603831d35Sstevel 	/*
138703831d35Sstevel 	 * These two calls get back two handles, a new handle for the
138803831d35Sstevel 	 * added segment or packet, and an updated parent handle.
138903831d35Sstevel 	 */
139003831d35Sstevel 	case SGFRU_ADDSEGMENT:
139103831d35Sstevel 	case SGFRU_APPENDPACKET:
139203831d35Sstevel 		bcopy(hdls, datap, sizeof (hdls));
139303831d35Sstevel 		break;
139403831d35Sstevel 
139503831d35Sstevel 	/* These two calls get an updated parent handle. */
139603831d35Sstevel 	case SGFRU_DELETESEGMENT:
139703831d35Sstevel 	case SGFRU_DELETEPACKET:
139803831d35Sstevel 		fru->hdl = hdl;
139903831d35Sstevel 		break;
140003831d35Sstevel 
140103831d35Sstevel 	default:
140203831d35Sstevel 		break;
140303831d35Sstevel 	}
140403831d35Sstevel 
140503831d35Sstevel 	return (0);
140603831d35Sstevel }
140703831d35Sstevel 
140803831d35Sstevel /*
140903831d35Sstevel  * Used to copy in one frup_info_t from user.
141003831d35Sstevel  */
141103831d35Sstevel static int
sgfru_copyin_frup(const sgfru_init_arg_t * argp,frup_info_t * frup)141203831d35Sstevel sgfru_copyin_frup(const sgfru_init_arg_t *argp, frup_info_t *frup)
141303831d35Sstevel {
141403831d35Sstevel 	static fn_t f = "sgfru_copyin_frup";
141503831d35Sstevel 
141603831d35Sstevel 	bzero((caddr_t)frup, sizeof (frup_info_t));
141703831d35Sstevel #ifdef _MULTI_DATAMODEL
141803831d35Sstevel 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
141903831d35Sstevel 		frup32_info_t frup32;
142003831d35Sstevel 
142103831d35Sstevel 		bzero((caddr_t)&frup32, sizeof (frup32_info_t));
142203831d35Sstevel 		if (ddi_copyin((void *)argp->argp, (void *)&frup32,
142303831d35Sstevel 		    sizeof (frup32_info_t), argp->mode) != DDI_SUCCESS) {
142403831d35Sstevel 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
142503831d35Sstevel 			    "frup32_t struct", f);
142603831d35Sstevel 			return (EFAULT);
142703831d35Sstevel 		}
142803831d35Sstevel 		frup->fru_hdl = frup32.fru_hdl;
142903831d35Sstevel 		frup->fru_cnt = frup32.fru_cnt;
143003831d35Sstevel 		frup->frus = (void *)(uintptr_t)frup32.frus;
143103831d35Sstevel 		PR_STATE("sgfru:%s: frus %p %x hdl %lx cnt %d\n",
143203831d35Sstevel 		    f, frup->frus, frup32.frus, frup->fru_hdl, frup->fru_cnt);
143303831d35Sstevel 
143403831d35Sstevel 	} else
143503831d35Sstevel #endif /* _MULTI_DATAMODEL */
143603831d35Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)frup,
143703831d35Sstevel 	    sizeof (frup_info_t), argp->mode) != DDI_SUCCESS) {
143803831d35Sstevel 		cmn_err(CE_WARN,
143903831d35Sstevel 		    "sgfru:%s: failed to copyin frup_info_t struct", f);
144003831d35Sstevel 		return (EFAULT);
144103831d35Sstevel 	}
144203831d35Sstevel 	return (0);
144303831d35Sstevel }
144403831d35Sstevel 
144503831d35Sstevel /*
144603831d35Sstevel  * Used to copy in one fru_info_t from user.
144703831d35Sstevel  */
144803831d35Sstevel static int
sgfru_copyin_fru(const sgfru_init_arg_t * argp,fru_info_t * fru)144903831d35Sstevel sgfru_copyin_fru(const sgfru_init_arg_t *argp, fru_info_t *fru)
145003831d35Sstevel {
145103831d35Sstevel 	static fn_t f = "sgfru_copyin_fru";
145203831d35Sstevel 
145303831d35Sstevel 	bzero((caddr_t)fru, sizeof (fru_info_t));
145403831d35Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)fru,
145503831d35Sstevel 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
145603831d35Sstevel 		cmn_err(CE_WARN,
145703831d35Sstevel 		    "sgfru:%s: failed to copyin fru_info_t struct", f);
145803831d35Sstevel 		return (EFAULT);
145903831d35Sstevel 	}
146003831d35Sstevel 	return (0);
146103831d35Sstevel }
146203831d35Sstevel 
146303831d35Sstevel /*
146403831d35Sstevel  * Used to copy in segment_t from user.
146503831d35Sstevel  */
146603831d35Sstevel static int
sgfru_copyin_segment(const sgfru_init_arg_t * argp,const frup_info_t * frup,segment_t * segp)146703831d35Sstevel sgfru_copyin_segment(const sgfru_init_arg_t *argp, const frup_info_t *frup,
146803831d35Sstevel     segment_t *segp)
146903831d35Sstevel {
147003831d35Sstevel 	static fn_t f = "sgfru_copyin_segment";
147103831d35Sstevel 
147203831d35Sstevel 	bzero((caddr_t)segp, sizeof (segment_t));
147303831d35Sstevel 	if (ddi_copyin((void *)frup->frus, (void *)segp,
147403831d35Sstevel 	    sizeof (segment_t), argp->mode) != DDI_SUCCESS) {
147503831d35Sstevel 		cmn_err(CE_WARN,
147603831d35Sstevel 		    "sgfru:%s: failed to copyin segment_t struct", f);
147703831d35Sstevel 		return (EFAULT);
147803831d35Sstevel 	}
147903831d35Sstevel 	return (0);
148003831d35Sstevel }
148103831d35Sstevel 
148203831d35Sstevel /*
148303831d35Sstevel  * Used to copy in segment handle, packet and payload data from user.
148403831d35Sstevel  */
148503831d35Sstevel static int
sgfru_copyin_append(const sgfru_init_arg_t * argp,append_info_t * app)148603831d35Sstevel sgfru_copyin_append(const sgfru_init_arg_t *argp, append_info_t *app)
148703831d35Sstevel {
148803831d35Sstevel 	static fn_t f = "sgfru_copyin_append";
148903831d35Sstevel 
149003831d35Sstevel 	bzero((caddr_t)app, sizeof (append_info_t));
149103831d35Sstevel #ifdef _MULTI_DATAMODEL
149203831d35Sstevel 	if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) {
149303831d35Sstevel 		append32_info_t app32;
149403831d35Sstevel 
149503831d35Sstevel 		bzero((caddr_t)&app32, sizeof (append32_info_t));
149603831d35Sstevel 		if (ddi_copyin((void *)argp->argp, (void *)&app32,
149703831d35Sstevel 		    sizeof (append32_info_t), argp->mode) != DDI_SUCCESS) {
149803831d35Sstevel 			cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin "
149903831d35Sstevel 			    "append32_info_t struct", f);
150003831d35Sstevel 			return (EFAULT);
150103831d35Sstevel 		}
150203831d35Sstevel 		app->packet = app32.packet;
150303831d35Sstevel 		app->payload_hdl = app32.payload_hdl;
150403831d35Sstevel 		app->payload_cnt = app32.payload_cnt;
150503831d35Sstevel 		app->payload_data = (void *)(uintptr_t)app32.payload_data;
150603831d35Sstevel 		PR_PAYLOAD("sgfru:%s:: data %p hdl %lx cnt %d\n",
150703831d35Sstevel 		    f, app->payload_data, app->payload_hdl, app->payload_cnt);
150803831d35Sstevel 
150903831d35Sstevel 	} else
151003831d35Sstevel #endif /* _MULTI_DATAMODEL */
151103831d35Sstevel 	if (ddi_copyin((void *)argp->argp, (void *)app,
151203831d35Sstevel 	    sizeof (append_info_t), argp->mode) != DDI_SUCCESS) {
151303831d35Sstevel 		cmn_err(CE_WARN,
151403831d35Sstevel 		    "sgfru:%s: failed to copyin append_info_t struct", f);
151503831d35Sstevel 		return (EFAULT);
151603831d35Sstevel 	}
151703831d35Sstevel 	PR_PAYLOAD("sgfru:%s: hdl %lx, cnt %d pkt hdl %lx "
151819397407SSherry Moore 	    "tag %lx\n", f, app->payload_hdl, app->payload_cnt,
151919397407SSherry Moore 	    app->packet.handle, app->packet.tag);
152003831d35Sstevel 	return (0);
152103831d35Sstevel }
152203831d35Sstevel 
152303831d35Sstevel /*
152403831d35Sstevel  * Used to copy in raw segment and payload data from user.
152503831d35Sstevel  */
152603831d35Sstevel static int
sgfru_copyin_buffer(const sgfru_init_arg_t * argp,const caddr_t data,const int cnt,char * buffer)152703831d35Sstevel sgfru_copyin_buffer(const sgfru_init_arg_t *argp, const caddr_t data,
1528*d1d6926fSToomas Soome     const int cnt, char *buffer)
152903831d35Sstevel {
153003831d35Sstevel 	static fn_t f = "sgfru_copyin_buffer";
153103831d35Sstevel 
153203831d35Sstevel 	if (ddi_copyin((void *)data, (void *)buffer, cnt, argp->mode)
153303831d35Sstevel 	    != DDI_SUCCESS) {
153403831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyin buffer", f);
153503831d35Sstevel 		return (EFAULT);
153603831d35Sstevel 	}
153703831d35Sstevel 	return (0);
153803831d35Sstevel }
153903831d35Sstevel 
154003831d35Sstevel /*
154103831d35Sstevel  * Used to copy out one fru_info_t to user.
154203831d35Sstevel  */
154303831d35Sstevel static int
sgfru_copyout_fru(const sgfru_init_arg_t * argp,const fru_info_t * frup)154403831d35Sstevel sgfru_copyout_fru(const sgfru_init_arg_t *argp, const fru_info_t *frup)
154503831d35Sstevel {
154603831d35Sstevel 	static fn_t f = "sgfru_copyout_fru";
154703831d35Sstevel 
154803831d35Sstevel 	if (ddi_copyout((void *)frup, (void *)argp->argp,
154903831d35Sstevel 	    sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) {
155003831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout fru", f);
155103831d35Sstevel 		return (EFAULT);
155203831d35Sstevel 	}
155303831d35Sstevel 	return (0);
155403831d35Sstevel }
155503831d35Sstevel 
155603831d35Sstevel /*
155703831d35Sstevel  * Used to copy out one fru_hdl_t to user.
155803831d35Sstevel  */
155903831d35Sstevel static int
sgfru_copyout_handle(const sgfru_init_arg_t * argp,const void * addr,const fru_hdl_t * hdlp)156003831d35Sstevel sgfru_copyout_handle(const sgfru_init_arg_t *argp, const void *addr,
156103831d35Sstevel     const fru_hdl_t *hdlp)
156203831d35Sstevel {
156303831d35Sstevel 	static fn_t f = "sgfru_copyout_handle";
156403831d35Sstevel 
156503831d35Sstevel 	if (ddi_copyout((void *)hdlp, (void *)addr, sizeof (fru_hdl_t),
156603831d35Sstevel 	    argp->mode) != DDI_SUCCESS) {
156703831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handle", f);
156803831d35Sstevel 		return (EFAULT);
156903831d35Sstevel 	}
157003831d35Sstevel 	return (0);
157103831d35Sstevel }
157203831d35Sstevel 
157303831d35Sstevel /*
157403831d35Sstevel  * Used to copy out an array of fru_hdl_t's to user.
157503831d35Sstevel  */
157603831d35Sstevel static int
sgfru_copyout_handles(const sgfru_init_arg_t * argp,const frup_info_t * frup,const fru_hdl_t * hdlp)157703831d35Sstevel sgfru_copyout_handles(const sgfru_init_arg_t *argp, const frup_info_t *frup,
157803831d35Sstevel     const fru_hdl_t *hdlp)
157903831d35Sstevel {
158003831d35Sstevel 	static fn_t f = "sgfru_copyout_handles";
158103831d35Sstevel 
158203831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (fru_hdl_t));
158303831d35Sstevel 	/* copyout fru_hdl_t's */
158403831d35Sstevel 	if (ddi_copyout((void *)hdlp, (void *)frup->frus, size, argp->mode)
158503831d35Sstevel 	    != DDI_SUCCESS) {
158603831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout handles", f);
158703831d35Sstevel 		return (EFAULT);
158803831d35Sstevel 	}
158903831d35Sstevel 	return (0);
159003831d35Sstevel }
159103831d35Sstevel 
159203831d35Sstevel /*
159303831d35Sstevel  * Used to copy out one or more node_t's to user.
159403831d35Sstevel  */
159503831d35Sstevel static int
sgfru_copyout_nodes(const sgfru_init_arg_t * argp,const frup_info_t * frup,const node_t * nodep)159603831d35Sstevel sgfru_copyout_nodes(const sgfru_init_arg_t *argp, const frup_info_t *frup,
159703831d35Sstevel     const node_t *nodep)
159803831d35Sstevel {
159903831d35Sstevel 	static fn_t f = "sgfru_copyout_nodes";
160003831d35Sstevel 
160103831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (node_t));
160203831d35Sstevel 	/* copyout node_t's */
160303831d35Sstevel 	if (ddi_copyout((void *)nodep, (void *)frup->frus, size, argp->mode)
160403831d35Sstevel 	    != DDI_SUCCESS) {
160503831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout nodes", f);
160603831d35Sstevel 		return (EFAULT);
160703831d35Sstevel 	}
160803831d35Sstevel 	return (0);
160903831d35Sstevel }
161003831d35Sstevel 
161103831d35Sstevel /*
161203831d35Sstevel  * Used to copy out section_t's to user.
161303831d35Sstevel  */
161403831d35Sstevel static int
sgfru_copyout_sections(const sgfru_init_arg_t * argp,const frup_info_t * frup,const section_t * sectp)161503831d35Sstevel sgfru_copyout_sections(const sgfru_init_arg_t *argp, const frup_info_t *frup,
161603831d35Sstevel     const section_t *sectp)
161703831d35Sstevel {
161803831d35Sstevel 	static fn_t f = "sgfru_copyout_sections";
161903831d35Sstevel 
162003831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (section_t));
162103831d35Sstevel 	/* copyout section_t's */
162203831d35Sstevel 	if (ddi_copyout((void *)sectp, (void *)frup->frus, size, argp->mode)
162303831d35Sstevel 	    != DDI_SUCCESS) {
162403831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout sections", f);
162503831d35Sstevel 		return (EFAULT);
162603831d35Sstevel 	}
162703831d35Sstevel 	return (0);
162803831d35Sstevel }
162903831d35Sstevel 
163003831d35Sstevel /*
163103831d35Sstevel  * Used to copy out segment_t's to user.
163203831d35Sstevel  */
163303831d35Sstevel static int
sgfru_copyout_segments(const sgfru_init_arg_t * argp,const frup_info_t * frup,const segment_t * segp)163403831d35Sstevel sgfru_copyout_segments(const sgfru_init_arg_t *argp, const frup_info_t *frup,
163503831d35Sstevel     const segment_t *segp)
163603831d35Sstevel {
163703831d35Sstevel 	static fn_t f = "sgfru_copyout_segments";
163803831d35Sstevel 
163903831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (segment_t));
164003831d35Sstevel 	/* copyout segment_t's */
164103831d35Sstevel 	if (ddi_copyout((void *)segp, (void *)frup->frus, size, argp->mode)
164203831d35Sstevel 	    != DDI_SUCCESS) {
164303831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout segments", f);
164403831d35Sstevel 		return (EFAULT);
164503831d35Sstevel 	}
164603831d35Sstevel 	return (0);
164703831d35Sstevel }
164803831d35Sstevel 
164903831d35Sstevel /*
165003831d35Sstevel  * Used to copy out packet_t's to user.
165103831d35Sstevel  */
165203831d35Sstevel static int
sgfru_copyout_packets(const sgfru_init_arg_t * argp,const frup_info_t * frup,const packet_t * packp)165303831d35Sstevel sgfru_copyout_packets(const sgfru_init_arg_t *argp, const frup_info_t *frup,
165403831d35Sstevel     const packet_t *packp)
165503831d35Sstevel {
165603831d35Sstevel 	static fn_t f = "sgfru_copyout_packets";
165703831d35Sstevel 
165803831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt * sizeof (packet_t));
165903831d35Sstevel 	/* copyout packet_t's */
166003831d35Sstevel 	if (ddi_copyout((void *)packp, (void *)frup->frus, size, argp->mode)
166103831d35Sstevel 	    != DDI_SUCCESS) {
166203831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout packets", f);
166303831d35Sstevel 		return (EFAULT);
166403831d35Sstevel 	}
166503831d35Sstevel 	return (0);
166603831d35Sstevel }
166703831d35Sstevel 
166803831d35Sstevel /*
166903831d35Sstevel  * Used to copy out raw segment and payload data to user.
167003831d35Sstevel  */
167103831d35Sstevel static int
sgfru_copyout_buffer(const sgfru_init_arg_t * argp,const frup_info_t * frup,const char * buffer)167203831d35Sstevel sgfru_copyout_buffer(const sgfru_init_arg_t *argp, const frup_info_t *frup,
167303831d35Sstevel     const char *buffer)
167403831d35Sstevel {
167503831d35Sstevel 	static fn_t f = "sgfru_copyout_buffer";
167603831d35Sstevel 
167703831d35Sstevel 	size_t size = (size_t)(frup->fru_cnt);
167803831d35Sstevel 	/* copyout packet_t */
167903831d35Sstevel 	if (ddi_copyout((void *)buffer, (void *)frup->frus, size, argp->mode)
168003831d35Sstevel 	    != DDI_SUCCESS) {
168103831d35Sstevel 		cmn_err(CE_WARN, "sgfru:%s: failed to copyout buffer", f);
168203831d35Sstevel 		return (EFAULT);
168303831d35Sstevel 	}
168403831d35Sstevel 	return (0);
168503831d35Sstevel }
168603831d35Sstevel 
168703831d35Sstevel /*
168803831d35Sstevel  * Used to pad a Java (SCAPP) fru_info_t, in preparation for sending it to
168903831d35Sstevel  * C (Solaris).  Assumes one fru_info_t.
169003831d35Sstevel  */
169103831d35Sstevel static caddr_t
sgfru_fru_pad(const caddr_t datap,fru_info_t * fru)169203831d35Sstevel sgfru_fru_pad(const caddr_t datap, fru_info_t *fru)
169303831d35Sstevel {
169403831d35Sstevel 	caddr_t tdatap = datap;
169503831d35Sstevel 
169603831d35Sstevel 	bcopy(tdatap, (caddr_t)&fru->hdl, FRU_HDL_SIZE);
169703831d35Sstevel 	tdatap += FRU_HDL_SIZE;
169803831d35Sstevel 	bcopy(tdatap, (caddr_t)&fru->cnt, FRU_CNT_SIZE);
169903831d35Sstevel 	tdatap += FRU_CNT_SIZE;
170003831d35Sstevel 	return (tdatap);
170103831d35Sstevel }
170203831d35Sstevel 
170303831d35Sstevel /*
170403831d35Sstevel  * Used to pad a Java (SCAPP) node_t, in preparation for sending it to
170503831d35Sstevel  * C (Solaris).  Assumes a fru_info_t and one or more node_t's.
170603831d35Sstevel  */
170703831d35Sstevel static int
sgfru_node_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,node_t * nodep)170803831d35Sstevel sgfru_node_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
170903831d35Sstevel     node_t *nodep)
171003831d35Sstevel {
171103831d35Sstevel 	caddr_t tdatap = datap;
171203831d35Sstevel 	node_t *np;
171303831d35Sstevel 	int i, cnt = 1;
171403831d35Sstevel 
171503831d35Sstevel 	if (fru != NULL) {
171603831d35Sstevel 		tdatap = sgfru_fru_pad(datap, fru);
171703831d35Sstevel 		if (max_cnt < fru->cnt) {
171803831d35Sstevel 			return (ENOMEM);
171903831d35Sstevel 		} else {
172003831d35Sstevel 			cnt = fru->cnt;
172103831d35Sstevel 		}
172203831d35Sstevel 	}
172303831d35Sstevel 	for (i = 0, np = nodep; i < cnt; i++, np++) {
172403831d35Sstevel 		bcopy(tdatap, (caddr_t)&np->handle, FRU_HDL_SIZE);
172503831d35Sstevel 		tdatap += FRU_HDL_SIZE;
172603831d35Sstevel 		bcopy(tdatap, (caddr_t)&np->nodename, NODENAME_SIZE);
172703831d35Sstevel 		tdatap += NODENAME_SIZE;
172803831d35Sstevel 		bcopy(tdatap, (caddr_t)&np->has_children, HASCHILDREN_SIZE);
172903831d35Sstevel 		tdatap += HASCHILDREN_SIZE;
173003831d35Sstevel 		bcopy(tdatap, (caddr_t)&np->class, CLASS_SIZE);
173103831d35Sstevel 		tdatap += CLASS_SIZE;
173203831d35Sstevel 		if (np->class == LOCATION_CLASS) {
173303831d35Sstevel 			bcopy(tdatap, (caddr_t)&np->location_slot, SLOT_SIZE);
173403831d35Sstevel 			tdatap += SLOT_SIZE;
173503831d35Sstevel 			bcopy(tdatap, (caddr_t)&np->location_label, LABEL_SIZE);
173603831d35Sstevel 			tdatap += LABEL_SIZE;
173703831d35Sstevel 		}
173803831d35Sstevel 	}
173903831d35Sstevel 	return (0);
174003831d35Sstevel }
174103831d35Sstevel 
174203831d35Sstevel /*
174303831d35Sstevel  * Used to pad a Java (SCAPP) section, in preparation for sending it to
174403831d35Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple section_t's.
174503831d35Sstevel  */
174603831d35Sstevel static int
sgfru_section_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,section_t * sectp)174703831d35Sstevel sgfru_section_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
174803831d35Sstevel     section_t *sectp)
174903831d35Sstevel {
175003831d35Sstevel 	caddr_t tdatap = datap;
175103831d35Sstevel 	section_t *sp;
175203831d35Sstevel 	int i;
175303831d35Sstevel 
175403831d35Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
175503831d35Sstevel 	if (max_cnt < fru->cnt)
175603831d35Sstevel 		return (ENOMEM);
175703831d35Sstevel 	for (i = 0, sp = sectp; i < fru->cnt; i++, sp++) {
175803831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
175903831d35Sstevel 		tdatap += FRU_HDL_SIZE;
176003831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
176103831d35Sstevel 		tdatap += OFFSET_SIZE;
176203831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
176303831d35Sstevel 		tdatap += LENGTH_SIZE;
176403831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->protected, PROTECTED_SIZE);
176503831d35Sstevel 		tdatap += PROTECTED_SIZE;
176603831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->version, VERSION_SIZE);
176703831d35Sstevel 		tdatap += VERSION_SIZE;
176803831d35Sstevel 	}
176903831d35Sstevel 	return (0);
177003831d35Sstevel }
177103831d35Sstevel 
177203831d35Sstevel /*
177303831d35Sstevel  * Used to pad a Java (SCAPP) segment, in preparation for sending it to
177403831d35Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple segment_t's.
177503831d35Sstevel  */
177603831d35Sstevel static int
sgfru_segment_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,segment_t * segp)177703831d35Sstevel sgfru_segment_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
177803831d35Sstevel     segment_t *segp)
177903831d35Sstevel {
178003831d35Sstevel 	caddr_t tdatap = datap;
178103831d35Sstevel 	segment_t *sp;
178203831d35Sstevel 	int i;
178303831d35Sstevel 
178403831d35Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
178503831d35Sstevel 	if (max_cnt < fru->cnt)
178603831d35Sstevel 		return (ENOMEM);
178703831d35Sstevel 	for (i = 0, sp = segp; i < fru->cnt; i++, sp++) {
178803831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE);
178903831d35Sstevel 		tdatap += FRU_HDL_SIZE;
179003831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->name, NAME_SIZE);
179103831d35Sstevel 		tdatap += NAME_SIZE;
179203831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->descriptor, DESCRIPTOR_SIZE);
179303831d35Sstevel 		tdatap += DESCRIPTOR_SIZE;
179403831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE);
179503831d35Sstevel 		tdatap += OFFSET_SIZE;
179603831d35Sstevel 		bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE);
179703831d35Sstevel 		tdatap += LENGTH_SIZE;
179803831d35Sstevel 	}
179903831d35Sstevel 	return (0);
180003831d35Sstevel }
180103831d35Sstevel 
180203831d35Sstevel /*
180303831d35Sstevel  * Used to pad a Java (SCAPP) packet, in preparation for sending it to
180403831d35Sstevel  * C (Solaris).  Assumes a fru_info_t and multiple packet_t's.
180503831d35Sstevel  */
180603831d35Sstevel static int
sgfru_packet_pad(const caddr_t datap,const int max_cnt,fru_info_t * fru,packet_t * packp)180703831d35Sstevel sgfru_packet_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru,
180803831d35Sstevel     packet_t *packp)
180903831d35Sstevel {
181003831d35Sstevel 	caddr_t tdatap = datap;
181103831d35Sstevel 	packet_t *pp;
181203831d35Sstevel 	int i;
181303831d35Sstevel 
181403831d35Sstevel 	tdatap = sgfru_fru_pad(datap, fru);
181503831d35Sstevel 	if (max_cnt < fru->cnt)
181603831d35Sstevel 		return (ENOMEM);
181703831d35Sstevel 	for (i = 0, pp = packp; i < fru->cnt; i++, pp++) {
181803831d35Sstevel 		bcopy(tdatap, (caddr_t)&pp->handle, FRU_HDL_SIZE);
181903831d35Sstevel 		tdatap += FRU_HDL_SIZE;
182003831d35Sstevel 		bcopy(tdatap, (caddr_t)&pp->tag, TAG_SIZE);
182103831d35Sstevel 		tdatap += TAG_SIZE;
182203831d35Sstevel 	}
182303831d35Sstevel 	return (0);
182403831d35Sstevel }
182503831d35Sstevel 
182603831d35Sstevel /*
182703831d35Sstevel  * Used to unpad a C (Solaris) fru_info_t, in preparation for sending it to
182803831d35Sstevel  * Java (SCAPP).  Assumes a fru_info_t.
182903831d35Sstevel  */
183003831d35Sstevel static caddr_t
sgfru_fru_unpad(const fru_info_t * fru,caddr_t datap)183103831d35Sstevel sgfru_fru_unpad(const fru_info_t *fru, caddr_t datap)
183203831d35Sstevel {
183303831d35Sstevel 	caddr_t tdatap = datap;
183403831d35Sstevel 
183503831d35Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
183603831d35Sstevel 	tdatap += FRU_HDL_SIZE;
183703831d35Sstevel 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
183803831d35Sstevel 	tdatap += FRU_CNT_SIZE;
183903831d35Sstevel 	return (tdatap);
184003831d35Sstevel }
184103831d35Sstevel 
184203831d35Sstevel /*
184303831d35Sstevel  * Used to unpad a C (Solaris) segment, in preparation for sending it to
184403831d35Sstevel  * Java (SCAPP). Assumes a section_hdl_t and one segment_t.
184503831d35Sstevel  */
184603831d35Sstevel static void
sgfru_segment_unpad(const fru_info_t * fru,const segment_t * segp,caddr_t datap)184703831d35Sstevel sgfru_segment_unpad(const fru_info_t *fru, const segment_t *segp,
184803831d35Sstevel     caddr_t datap)
184903831d35Sstevel {
185003831d35Sstevel 	caddr_t tdatap = datap;
185103831d35Sstevel 
185203831d35Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
185303831d35Sstevel 	tdatap += FRU_HDL_SIZE;
185403831d35Sstevel 	bcopy((caddr_t)&segp->handle, tdatap, FRU_HDL_SIZE);
185503831d35Sstevel 	tdatap += FRU_HDL_SIZE;
185603831d35Sstevel 	bcopy((caddr_t)&segp->name, tdatap, NAME_SIZE);
185703831d35Sstevel 	tdatap += NAME_SIZE;
185803831d35Sstevel 	bcopy((caddr_t)&segp->descriptor, tdatap, DESCRIPTOR_SIZE);
185903831d35Sstevel 	tdatap += DESCRIPTOR_SIZE;
186003831d35Sstevel 	bcopy((caddr_t)&segp->offset, tdatap, OFFSET_SIZE);
186103831d35Sstevel 	tdatap += OFFSET_SIZE;
186203831d35Sstevel 	bcopy((caddr_t)&segp->length, tdatap, LENGTH_SIZE);
186303831d35Sstevel }
186403831d35Sstevel 
186503831d35Sstevel /*
186603831d35Sstevel  * Used to unpad a C (Solaris) packet, in preparation for sending it to
186703831d35Sstevel  * Java (SCAPP).  Assumes a fru_info_t and one packet_t.
186803831d35Sstevel  */
186903831d35Sstevel static caddr_t
sgfru_packet_unpad(const fru_info_t * fru,const packet_t * packp,caddr_t datap)187003831d35Sstevel sgfru_packet_unpad(const fru_info_t *fru, const packet_t *packp, caddr_t datap)
187103831d35Sstevel {
187203831d35Sstevel 	caddr_t tdatap = datap;
187303831d35Sstevel 
187403831d35Sstevel 	bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE);
187503831d35Sstevel 	tdatap += FRU_HDL_SIZE;
187603831d35Sstevel 	bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE);
187703831d35Sstevel 	tdatap += FRU_CNT_SIZE;
187803831d35Sstevel 	bcopy((caddr_t)&packp->handle, tdatap, FRU_HDL_SIZE);
187903831d35Sstevel 	tdatap += FRU_HDL_SIZE;
188003831d35Sstevel 	bcopy((caddr_t)&packp->tag, tdatap, TAG_SIZE);
188103831d35Sstevel 	tdatap += TAG_SIZE;
188203831d35Sstevel 	return (tdatap);
188303831d35Sstevel }
1884