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 /*
23*19397407SSherry 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 */
105*19397407SSherry Moore nulldev, /* power */
106*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
10703831d35Sstevel };
10803831d35Sstevel
10903831d35Sstevel /*
11003831d35Sstevel * Loadable module support. This is located in sgfru.c so as to
111*19397407SSherry 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 */
117*19397407SSherry 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,
18903831d35Sstevel instance, DDI_PSEUDO, NULL);
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, §s) != 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, §s.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, §s.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, §s.fru_info) != 0) {
60003831d35Sstevel kmem_free(sectp, ssize);
60103831d35Sstevel return (EFAULT);
60203831d35Sstevel }
60303831d35Sstevel /* copyout section_t's */
60403831d35Sstevel if (sgfru_copyout_sections(iargp, §s, 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",
69703831d35Sstevel f, seg.fru_hdl, seg.fru_cnt);
69803831d35Sstevel PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, "
69903831d35Sstevel "offset 0x%x, length 0x%x\n", f, segment.handle, segment.name,
70003831d35Sstevel 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",
75603831d35Sstevel 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",
77103831d35Sstevel 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",
81203831d35Sstevel 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",
83603831d35Sstevel 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",
99203831d35Sstevel 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",
101403831d35Sstevel 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",
106903831d35Sstevel 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",
108603831d35Sstevel 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 "
151803831d35Sstevel "tag %lx\n", f, app->payload_hdl, app->payload_cnt,
151903831d35Sstevel 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,
152803831d35Sstevel 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