xref: /illumos-gate/usr/src/uts/sun4u/io/rmcadm.c (revision 725953abcc30bcf6f15d7b8a313ab0749275d95f)
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/stat.h>
2903831d35Sstevel #include <sys/conf.h>
3003831d35Sstevel #include <sys/modctl.h>
3103831d35Sstevel #include <sys/ddi.h>
3203831d35Sstevel #include <sys/rmc_comm_dp.h>
3303831d35Sstevel #include <sys/rmc_comm_dp_boot.h>
3403831d35Sstevel #include <sys/rmc_comm_drvintf.h>
3503831d35Sstevel #include <sys/cyclic.h>
3603831d35Sstevel #include <sys/rmc_comm.h>
3703831d35Sstevel #include <sys/machsystm.h>
3803831d35Sstevel #include <sys/file.h>
3903831d35Sstevel #include <sys/rmcadm.h>
4003831d35Sstevel 
4103831d35Sstevel /*
4203831d35Sstevel  * functions local to this driver.
4303831d35Sstevel  */
4403831d35Sstevel static int	rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
4503831d35Sstevel     void **resultp);
4603831d35Sstevel static int	rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
4703831d35Sstevel static int	rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
4803831d35Sstevel static int	rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
4903831d35Sstevel static int	rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
5003831d35Sstevel static int	rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5103831d35Sstevel     cred_t *cred_p, int *rval_p);
5203831d35Sstevel 
5303831d35Sstevel /*
5403831d35Sstevel  * Driver entry points
5503831d35Sstevel  */
5603831d35Sstevel static struct cb_ops rmcadm_cb_ops = {
5703831d35Sstevel 	rmcadm_open,	/* open */
5803831d35Sstevel 	rmcadm_close,	/* close */
5903831d35Sstevel 	nodev,		/* strategy() */
6003831d35Sstevel 	nodev,		/* print() */
6103831d35Sstevel 	nodev,		/* dump() */
6203831d35Sstevel 	nodev,		/* read() */
6303831d35Sstevel 	nodev,		/* write() */
6403831d35Sstevel 	rmcadm_ioctl,	/* ioctl() */
6503831d35Sstevel 	nodev,		/* devmap() */
6603831d35Sstevel 	nodev,		/* mmap() */
6703831d35Sstevel 	ddi_segmap,	/* segmap() */
6803831d35Sstevel 	nochpoll,	/* poll() */
6903831d35Sstevel 	ddi_prop_op,    /* prop_op() */
7003831d35Sstevel 	NULL,		/* cb_str */
7103831d35Sstevel 	D_NEW | D_MP	/* cb_flag */
7203831d35Sstevel };
7303831d35Sstevel 
7403831d35Sstevel 
7503831d35Sstevel static struct dev_ops rmcadm_ops = {
7603831d35Sstevel 	DEVO_REV,
7703831d35Sstevel 	0,			/* ref count */
7803831d35Sstevel 	rmcadm_getinfo,		/* getinfo() */
7903831d35Sstevel 	nulldev,		/* identify() */
8003831d35Sstevel 	nulldev,		/* probe() */
8103831d35Sstevel 	rmcadm_attach,		/* attach() */
8203831d35Sstevel 	rmcadm_detach,		/* detach */
8303831d35Sstevel 	nodev,			/* reset */
8403831d35Sstevel 	&rmcadm_cb_ops,		/* pointer to cb_ops structure */
8503831d35Sstevel 	(struct bus_ops *)NULL,
8619397407SSherry Moore 	nulldev,		/* power() */
8719397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
8803831d35Sstevel };
8903831d35Sstevel 
9003831d35Sstevel /*
9103831d35Sstevel  * Loadable module support.
9203831d35Sstevel  */
9303831d35Sstevel extern struct mod_ops mod_driverops;
9403831d35Sstevel 
9503831d35Sstevel static struct modldrv modldrv = {
9603831d35Sstevel 	&mod_driverops,			/* Type of module. This is a driver */
9719397407SSherry Moore 	"rmcadm control driver",	/* Name of the module */
9803831d35Sstevel 	&rmcadm_ops			/* pointer to the dev_ops structure */
9903831d35Sstevel };
10003831d35Sstevel 
10103831d35Sstevel static struct modlinkage modlinkage = {
10203831d35Sstevel 	MODREV_1,
10303831d35Sstevel 	&modldrv,
10403831d35Sstevel 	NULL
10503831d35Sstevel };
10603831d35Sstevel 
10703831d35Sstevel static dev_info_t		*rmcadm_dip = NULL;
10803831d35Sstevel 
10903831d35Sstevel extern void pmugpio_reset();
11003831d35Sstevel 
11103831d35Sstevel /*
11203831d35Sstevel  * Utilities...
11303831d35Sstevel  */
11403831d35Sstevel 
11503831d35Sstevel /*
11603831d35Sstevel  * to return the errno from the rmc_comm error status
11703831d35Sstevel  */
11803831d35Sstevel int
rmcadm_get_errno(int status)11903831d35Sstevel rmcadm_get_errno(int status)
12003831d35Sstevel {
12103831d35Sstevel 	int retval = EIO;
12203831d35Sstevel 
12303831d35Sstevel 	/* errors from RMC */
12403831d35Sstevel 	switch (status) {
12503831d35Sstevel 		case RCENOSOFTSTATE:
12603831d35Sstevel 			/* invalid/NULL soft state structure */
12703831d35Sstevel 			retval = EIO;
12803831d35Sstevel 			break;
12903831d35Sstevel 		case RCENODATALINK:
13003831d35Sstevel 			/* data protocol not available (down) */
13103831d35Sstevel 			retval = EIO;
13203831d35Sstevel 			break;
13303831d35Sstevel 		case RCENOMEM:
13403831d35Sstevel 			/* memory problems */
13503831d35Sstevel 			retval = ENOMEM;
13603831d35Sstevel 			break;
13703831d35Sstevel 		case RCECANTRESEND:
13803831d35Sstevel 			/* resend failed */
13903831d35Sstevel 			retval = EIO;
14003831d35Sstevel 			break;
14103831d35Sstevel 		case RCEMAXRETRIES:
14203831d35Sstevel 			/* reply not received - retries exceeded */
14303831d35Sstevel 			retval = EINTR;
14403831d35Sstevel 			break;
14503831d35Sstevel 		case RCETIMEOUT:
14603831d35Sstevel 			/* reply not received - command has timed out */
14703831d35Sstevel 			retval = EINTR;
14803831d35Sstevel 			break;
14903831d35Sstevel 		case RCEINVCMD:
15003831d35Sstevel 			/* data protocol cmd not supported */
15103831d35Sstevel 			retval = ENOTSUP;
15203831d35Sstevel 			break;
15303831d35Sstevel 		case RCEINVARG:
15403831d35Sstevel 			/* invalid argument(s) */
15503831d35Sstevel 			retval = ENOTSUP;
15603831d35Sstevel 			break;
15703831d35Sstevel 		case RCEGENERIC:
15803831d35Sstevel 			/* generic error */
15903831d35Sstevel 			retval = EIO;
16003831d35Sstevel 			break;
16103831d35Sstevel 		default:
16203831d35Sstevel 			retval = EIO;
16303831d35Sstevel 			break;
16403831d35Sstevel 	}
16503831d35Sstevel 	return (retval);
16603831d35Sstevel }
16703831d35Sstevel 
16803831d35Sstevel int
_init(void)16903831d35Sstevel _init(void)
17003831d35Sstevel {
17103831d35Sstevel 	int	error = 0;
17203831d35Sstevel 
17303831d35Sstevel 	error = mod_install(&modlinkage);
17403831d35Sstevel 	return (error);
17503831d35Sstevel }
17603831d35Sstevel 
17703831d35Sstevel 
17803831d35Sstevel int
_info(struct modinfo * modinfop)17903831d35Sstevel _info(struct modinfo *modinfop)
18003831d35Sstevel {
18103831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
18203831d35Sstevel }
18303831d35Sstevel 
18403831d35Sstevel 
18503831d35Sstevel int
_fini(void)18603831d35Sstevel _fini(void)
18703831d35Sstevel {
18803831d35Sstevel 	int	error = 0;
18903831d35Sstevel 
19003831d35Sstevel 	error = mod_remove(&modlinkage);
19103831d35Sstevel 	if (error)
19203831d35Sstevel 		return (error);
19303831d35Sstevel 	return (error);
19403831d35Sstevel }
19503831d35Sstevel 
19603831d35Sstevel 
19703831d35Sstevel /* ARGSUSED */
19803831d35Sstevel static int
rmcadm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)19903831d35Sstevel rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
20003831d35Sstevel {
20103831d35Sstevel 	minor_t m = getminor((dev_t)arg);
20203831d35Sstevel 
20303831d35Sstevel 	switch (cmd) {
20403831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
20503831d35Sstevel 		if ((m != 0) || (rmcadm_dip == NULL)) {
20603831d35Sstevel 			*resultp = NULL;
20703831d35Sstevel 			return (DDI_FAILURE);
20803831d35Sstevel 		}
20903831d35Sstevel 		*resultp = rmcadm_dip;
21003831d35Sstevel 		return (DDI_SUCCESS);
21103831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
21203831d35Sstevel 		*resultp = (void *)(uintptr_t)m;
21303831d35Sstevel 		return (DDI_SUCCESS);
21403831d35Sstevel 	default:
21503831d35Sstevel 		return (DDI_FAILURE);
21603831d35Sstevel 	}
21703831d35Sstevel }
21803831d35Sstevel 
21903831d35Sstevel 
22003831d35Sstevel static int
rmcadm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)22103831d35Sstevel rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
22203831d35Sstevel {
22303831d35Sstevel 	int			instance;
22403831d35Sstevel 	int			err;
22503831d35Sstevel 
22603831d35Sstevel 	switch (cmd) {
22703831d35Sstevel 	case DDI_ATTACH:
22803831d35Sstevel 		/*
22903831d35Sstevel 		 * only allow one instance
23003831d35Sstevel 		 */
23103831d35Sstevel 		instance = ddi_get_instance(dip);
23203831d35Sstevel 		if (instance != 0)
23303831d35Sstevel 			return (DDI_FAILURE);
23403831d35Sstevel 
23503831d35Sstevel 		err = ddi_create_minor_node(dip, "rmcadm", S_IFCHR,
236*725953abSToomas Soome 		    instance, DDI_PSEUDO, 0);
23703831d35Sstevel 		if (err != DDI_SUCCESS)
23803831d35Sstevel 			return (DDI_FAILURE);
23903831d35Sstevel 
24003831d35Sstevel 		/*
24103831d35Sstevel 		 * Register with rmc_comm to prevent it being detached
24203831d35Sstevel 		 */
24303831d35Sstevel 		err = rmc_comm_register();
24403831d35Sstevel 		if (err != DDI_SUCCESS) {
24503831d35Sstevel 			ddi_remove_minor_node(dip, NULL);
24603831d35Sstevel 			return (DDI_FAILURE);
24703831d35Sstevel 		}
24803831d35Sstevel 
24903831d35Sstevel 		/* Remember the dev info */
25003831d35Sstevel 		rmcadm_dip = dip;
25103831d35Sstevel 
25203831d35Sstevel 		ddi_report_dev(dip);
25303831d35Sstevel 		return (DDI_SUCCESS);
25403831d35Sstevel 	case DDI_RESUME:
25503831d35Sstevel 		return (DDI_SUCCESS);
25603831d35Sstevel 	default:
25703831d35Sstevel 		return (DDI_FAILURE);
25803831d35Sstevel 	}
25903831d35Sstevel }
26003831d35Sstevel 
26103831d35Sstevel 
26203831d35Sstevel static int
rmcadm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)26303831d35Sstevel rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
26403831d35Sstevel {
26503831d35Sstevel 	int	instance;
26603831d35Sstevel 
26703831d35Sstevel 	switch (cmd) {
26803831d35Sstevel 	case DDI_DETACH:
26903831d35Sstevel 		instance = ddi_get_instance(dip);
27003831d35Sstevel 		if (instance != 0)
27103831d35Sstevel 			return (DDI_FAILURE);
27203831d35Sstevel 
27303831d35Sstevel 		rmcadm_dip = NULL;
27403831d35Sstevel 		ddi_remove_minor_node(dip, NULL);
27503831d35Sstevel 		rmc_comm_unregister();
27603831d35Sstevel 		return (DDI_SUCCESS);
27703831d35Sstevel 	case DDI_SUSPEND:
27803831d35Sstevel 		return (DDI_SUCCESS);
27903831d35Sstevel 	default:
28003831d35Sstevel 		return (DDI_FAILURE);
28103831d35Sstevel 	}
28203831d35Sstevel }
28303831d35Sstevel 
28403831d35Sstevel /*ARGSUSED*/
28503831d35Sstevel static int
rmcadm_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)28603831d35Sstevel rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
28703831d35Sstevel {
28803831d35Sstevel 	int error = 0;
28903831d35Sstevel 	int instance = getminor(*dev_p);
29003831d35Sstevel 
29103831d35Sstevel 	if (instance != 0)
29203831d35Sstevel 		return (ENXIO);
29303831d35Sstevel 
29403831d35Sstevel 	if ((error = drv_priv(cred_p)) != 0) {
29503831d35Sstevel 		cmn_err(CE_WARN, "rmcadm: inst %d drv_priv failed",
29603831d35Sstevel 		    instance);
29703831d35Sstevel 		return (error);
29803831d35Sstevel 	}
29903831d35Sstevel 	return (error);
30003831d35Sstevel }
30103831d35Sstevel 
30203831d35Sstevel /*ARGSUSED*/
30303831d35Sstevel static int
rmcadm_close(dev_t dev,int flag,int otyp,cred_t * cred_p)30403831d35Sstevel rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
30503831d35Sstevel {
30603831d35Sstevel 	return (DDI_SUCCESS);
30703831d35Sstevel }
30803831d35Sstevel 
30903831d35Sstevel /*ARGSUSED*/
31003831d35Sstevel static int
rmcadm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)31103831d35Sstevel rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
31203831d35Sstevel     int *rval_p)
31303831d35Sstevel {
31403831d35Sstevel 	int				instance = getminor(dev);
31503831d35Sstevel 	int				retval = 0;
31603831d35Sstevel 	rmcadm_request_response_t	rr;
31703831d35Sstevel 	rmcadm_send_srecord_bp_t	ssbp;
31803831d35Sstevel 	rmc_comm_msg_t			rmc_req, *rmc_reqp = &rmc_req;
31903831d35Sstevel 	rmc_comm_msg_t			rmc_resp, *rmc_respp = &rmc_resp;
32003831d35Sstevel 	caddr_t				user_req_buf;
32103831d35Sstevel 	caddr_t				user_data_buf;
32203831d35Sstevel 	caddr_t				user_resp_buf;
32303831d35Sstevel 
32403831d35Sstevel 	if (instance != 0)
32503831d35Sstevel 		return (ENXIO);
32603831d35Sstevel 
32703831d35Sstevel 	switch (cmd) {
32803831d35Sstevel 
32903831d35Sstevel 	case RMCADM_REQUEST_RESPONSE:
33003831d35Sstevel 	case RMCADM_REQUEST_RESPONSE_BP:
33103831d35Sstevel 
33203831d35Sstevel 		/*
33303831d35Sstevel 		 * first copy in the request_response structure
33403831d35Sstevel 		 */
33503831d35Sstevel #ifdef _MULTI_DATAMODEL
33603831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
33703831d35Sstevel 		case DDI_MODEL_ILP32:
33803831d35Sstevel 		{
33903831d35Sstevel 			/*
34003831d35Sstevel 			 * For use when a 32 bit app makes a call into a
34103831d35Sstevel 			 * 64 bit ioctl
34203831d35Sstevel 			 */
34303831d35Sstevel 			rmcadm_request_response32_t	rr32;
34403831d35Sstevel 
34503831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr32,
34603831d35Sstevel 			    sizeof (rr32), mode)) {
34703831d35Sstevel 				return (EFAULT);
34803831d35Sstevel 			}
34903831d35Sstevel 			rr.req.msg_type = rr32.req.msg_type;
35003831d35Sstevel 			rr.req.msg_len = rr32.req.msg_len;
35103831d35Sstevel 			rr.req.msg_bytes = rr32.req.msg_bytes;
35203831d35Sstevel 			rr.req.msg_buf = (caddr_t)(uintptr_t)rr32.req.msg_buf;
35303831d35Sstevel 			rr.resp.msg_type = rr32.resp.msg_type;
35403831d35Sstevel 			rr.resp.msg_len = rr32.resp.msg_len;
35503831d35Sstevel 			rr.resp.msg_bytes = rr32.resp.msg_bytes;
35603831d35Sstevel 			rr.resp.msg_buf = (caddr_t)(uintptr_t)rr32.resp.msg_buf;
35703831d35Sstevel 			rr.wait_time = rr32.wait_time;
35803831d35Sstevel 			break;
35903831d35Sstevel 		}
36003831d35Sstevel 		case DDI_MODEL_NONE:
36103831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
36203831d35Sstevel 			    sizeof (rr), mode)) {
36303831d35Sstevel 				return (EFAULT);
36403831d35Sstevel 			}
36503831d35Sstevel 			break;
36603831d35Sstevel 		}
36703831d35Sstevel #else /* ! _MULTI_DATAMODEL */
36803831d35Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
36903831d35Sstevel 		    sizeof (rr), mode) != 0) {
37003831d35Sstevel 			return (EFAULT);
37103831d35Sstevel 		}
37203831d35Sstevel #endif /* _MULTI_DATAMODEL */
37303831d35Sstevel 
37403831d35Sstevel 		/*
37503831d35Sstevel 		 * save the user request buffer pointer
37603831d35Sstevel 		 */
37703831d35Sstevel 		user_req_buf = rr.req.msg_buf;
37803831d35Sstevel 
37903831d35Sstevel 		if (user_req_buf != NULL) {
38003831d35Sstevel 			/*
38103831d35Sstevel 			 * copy in the request data
38203831d35Sstevel 			 */
38303831d35Sstevel 			rr.req.msg_buf = kmem_alloc(rr.req.msg_len, KM_SLEEP);
38403831d35Sstevel 
38503831d35Sstevel 			if (ddi_copyin(user_req_buf, rr.req.msg_buf,
38603831d35Sstevel 			    rr.req.msg_len, mode) != 0) {
38703831d35Sstevel 
38803831d35Sstevel 				kmem_free(rr.req.msg_buf, rr.req.msg_len);
38903831d35Sstevel 				rr.req.msg_buf = user_req_buf;
39003831d35Sstevel 				return (EFAULT);
39103831d35Sstevel 			}
39203831d35Sstevel 		} else {
39303831d35Sstevel 			if (rr.req.msg_len > 0)
39403831d35Sstevel 				/*
39503831d35Sstevel 				 * msg_len should be 0 if buffer is NULL!
39603831d35Sstevel 				 */
39703831d35Sstevel 				return (EINVAL);
39803831d35Sstevel 		}
39903831d35Sstevel 
40003831d35Sstevel 		/*
40103831d35Sstevel 		 * save the user request buffer pointer
40203831d35Sstevel 		 */
40303831d35Sstevel 		user_resp_buf = rr.resp.msg_buf;
40403831d35Sstevel 		if (user_resp_buf != NULL) {
40503831d35Sstevel 			rr.resp.msg_buf = kmem_alloc(rr.resp.msg_len, KM_SLEEP);
40603831d35Sstevel 		}
40703831d35Sstevel 
40803831d35Sstevel 		/*
40903831d35Sstevel 		 * send the request (or BP request) via the rmc_comm driver
41003831d35Sstevel 		 */
41103831d35Sstevel 		rmc_reqp->msg_type = rr.req.msg_type;
41203831d35Sstevel 		rmc_reqp->msg_buf = rr.req.msg_buf;
41303831d35Sstevel 		rmc_reqp->msg_len = rr.req.msg_len;
41403831d35Sstevel 		rmc_reqp->msg_bytes = rr.req.msg_bytes;
41503831d35Sstevel 
41603831d35Sstevel 		if (cmd == RMCADM_REQUEST_RESPONSE) {
41703831d35Sstevel 
41803831d35Sstevel 			/*
41903831d35Sstevel 			 * check if response is expected. If so, fill in
42003831d35Sstevel 			 * the response data structure
42103831d35Sstevel 			 */
42203831d35Sstevel 			if (rr.resp.msg_type != DP_NULL_MSG) {
42303831d35Sstevel 
42403831d35Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
42503831d35Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
42603831d35Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
42703831d35Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
42803831d35Sstevel 
42903831d35Sstevel 			} else {
43003831d35Sstevel 
43103831d35Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
43203831d35Sstevel 			}
43303831d35Sstevel 
43403831d35Sstevel 			rr.status = rmc_comm_request_response(
43503831d35Sstevel 			    rmc_reqp, rmc_respp, rr.wait_time);
43603831d35Sstevel 
43703831d35Sstevel 		} else { /* RMCADM_REQUEST_RESPONSE_BP */
43803831d35Sstevel 
43903831d35Sstevel 			/*
44003831d35Sstevel 			 * check if a BP message is expected back. If so,
44103831d35Sstevel 			 * fill in the response data structure
44203831d35Sstevel 			 */
44303831d35Sstevel 			if (rr.resp.msg_buf != NULL) {
44403831d35Sstevel 
44503831d35Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
44603831d35Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
44703831d35Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
44803831d35Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
44903831d35Sstevel 
45003831d35Sstevel 			} else {
45103831d35Sstevel 
45203831d35Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
45303831d35Sstevel 			}
45403831d35Sstevel 
45503831d35Sstevel 			rr.status = rmc_comm_request_response_bp(
45603831d35Sstevel 			    rmc_reqp, rmc_respp, rr.wait_time);
45703831d35Sstevel 		}
45803831d35Sstevel 
45903831d35Sstevel 		/*
46003831d35Sstevel 		 * if a response was expected, copy back the (actual) number
46103831d35Sstevel 		 * of bytes of the response returned by the
46203831d35Sstevel 		 * rmc_comm_request_response function (msg_bytes field)
46303831d35Sstevel 		 */
46403831d35Sstevel 		if (rmc_respp != NULL) {
46503831d35Sstevel 			rr.resp.msg_bytes = rmc_respp->msg_bytes;
46603831d35Sstevel 		}
46703831d35Sstevel 
46803831d35Sstevel 		if (rr.status != RCNOERR) {
46903831d35Sstevel 
47003831d35Sstevel 			retval = rmcadm_get_errno(rr.status);
47103831d35Sstevel 
47203831d35Sstevel 		} else if (user_resp_buf != NULL) {
47303831d35Sstevel 			/*
47403831d35Sstevel 			 * copy out the user response buffer
47503831d35Sstevel 			 */
47603831d35Sstevel 			if (ddi_copyout(rr.resp.msg_buf, user_resp_buf,
47703831d35Sstevel 			    rr.resp.msg_bytes, mode) != 0) {
47803831d35Sstevel 				retval = EFAULT;
47903831d35Sstevel 			}
48003831d35Sstevel 		}
48103831d35Sstevel 
48203831d35Sstevel 		/*
48303831d35Sstevel 		 * now copy out the updated request_response structure
48403831d35Sstevel 		 */
48503831d35Sstevel 		if (rr.req.msg_buf)
48603831d35Sstevel 			kmem_free(rr.req.msg_buf, rr.req.msg_len);
48703831d35Sstevel 		if (rr.resp.msg_buf)
48803831d35Sstevel 			kmem_free(rr.resp.msg_buf, rr.resp.msg_len);
48903831d35Sstevel 
49003831d35Sstevel 		rr.req.msg_buf = user_req_buf;
49103831d35Sstevel 		rr.resp.msg_buf = user_resp_buf;
49203831d35Sstevel 
49303831d35Sstevel #ifdef _MULTI_DATAMODEL
49403831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
49503831d35Sstevel 		case DDI_MODEL_ILP32:
49603831d35Sstevel 		{
49703831d35Sstevel 			/*
49803831d35Sstevel 			 * For use when a 32 bit app makes a call into a
49903831d35Sstevel 			 * 64 bit ioctl
50003831d35Sstevel 			 */
50103831d35Sstevel 			rmcadm_request_response32_t	rr32;
50203831d35Sstevel 
50303831d35Sstevel 			rr32.req.msg_type = rr.req.msg_type;
50403831d35Sstevel 			rr32.req.msg_len = rr.req.msg_len;
50503831d35Sstevel 			rr32.req.msg_bytes = rr.req.msg_bytes;
50603831d35Sstevel 			rr32.req.msg_buf = (caddr32_t)(uintptr_t)rr.req.msg_buf;
50703831d35Sstevel 			rr32.resp.msg_type = rr.resp.msg_type;
50803831d35Sstevel 			rr32.resp.msg_len = rr.resp.msg_len;
50903831d35Sstevel 			rr32.resp.msg_bytes = rr.resp.msg_bytes;
51003831d35Sstevel 			rr32.resp.msg_buf =
51103831d35Sstevel 			    (caddr32_t)(uintptr_t)rr.resp.msg_buf;
51203831d35Sstevel 			rr32.wait_time = rr.wait_time;
51303831d35Sstevel 			rr32.status = rr.status;
51403831d35Sstevel 			if (ddi_copyout((caddr_t)&rr32, (caddr_t)arg,
51503831d35Sstevel 			    sizeof (rr32), mode)) {
51603831d35Sstevel 				return (EFAULT);
51703831d35Sstevel 			}
51803831d35Sstevel 			break;
51903831d35Sstevel 		}
52003831d35Sstevel 		case DDI_MODEL_NONE:
52103831d35Sstevel 			if (ddi_copyout((caddr_t)&rr, (caddr_t)arg,
52203831d35Sstevel 			    sizeof (rr), mode))
52303831d35Sstevel 				return (EFAULT);
52403831d35Sstevel 			break;
52503831d35Sstevel 		}
52603831d35Sstevel #else /* ! _MULTI_DATAMODEL */
52703831d35Sstevel 		if (ddi_copyout((caddr_t)&rr, (caddr_t)arg, sizeof (rr),
52803831d35Sstevel 		    mode) != 0)
52903831d35Sstevel 			return (EFAULT);
53003831d35Sstevel #endif /* _MULTI_DATAMODEL */
53103831d35Sstevel 		break;
53203831d35Sstevel 
53303831d35Sstevel 
53403831d35Sstevel 	case RMCADM_SEND_SRECORD_BP:
53503831d35Sstevel 
53603831d35Sstevel 		/*
53703831d35Sstevel 		 * first copy in the request_response structure
53803831d35Sstevel 		 */
53903831d35Sstevel #ifdef _MULTI_DATAMODEL
54003831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
54103831d35Sstevel 		case DDI_MODEL_ILP32:
54203831d35Sstevel 		{
54303831d35Sstevel 			/*
54403831d35Sstevel 			 * For use when a 32 bit app makes a call into a
54503831d35Sstevel 			 * 64 bit ioctl
54603831d35Sstevel 			 */
54703831d35Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
54803831d35Sstevel 
54903831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp32,
55003831d35Sstevel 			    sizeof (ssbp32), mode)) {
55103831d35Sstevel 				return (EFAULT);
55203831d35Sstevel 			}
55303831d35Sstevel 			ssbp.data_len = ssbp32.data_len;
55403831d35Sstevel 			ssbp.data_buf = (caddr_t)(uintptr_t)ssbp32.data_buf;
55503831d35Sstevel 			ssbp.resp_bp.msg_type = ssbp32.resp_bp.msg_type;
55603831d35Sstevel 			ssbp.resp_bp.msg_len = ssbp32.resp_bp.msg_len;
55703831d35Sstevel 			ssbp.resp_bp.msg_bytes = ssbp32.resp_bp.msg_bytes;
55803831d35Sstevel 			ssbp.resp_bp.msg_buf =
55903831d35Sstevel 			    (caddr_t)(uintptr_t)ssbp32.resp_bp.msg_buf;
56003831d35Sstevel 			ssbp.wait_time = ssbp32.wait_time;
56103831d35Sstevel 			break;
56203831d35Sstevel 		}
56303831d35Sstevel 		case DDI_MODEL_NONE:
56403831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
56503831d35Sstevel 			    sizeof (ssbp), mode))
56603831d35Sstevel 				return (EFAULT);
56703831d35Sstevel 			break;
56803831d35Sstevel 		}
56903831d35Sstevel #else /* ! _MULTI_DATAMODEL */
57003831d35Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
57103831d35Sstevel 		    sizeof (ssbp), mode) != 0)
57203831d35Sstevel 			return (EFAULT);
57303831d35Sstevel #endif /* _MULTI_DATAMODEL */
57403831d35Sstevel 
57503831d35Sstevel 		/*
57603831d35Sstevel 		 * save the user data buffer pointer
57703831d35Sstevel 		 */
57803831d35Sstevel 		user_data_buf = ssbp.data_buf;
57903831d35Sstevel 
58003831d35Sstevel 		if (user_data_buf != NULL) {
58103831d35Sstevel 			/*
58203831d35Sstevel 			 * copy in the srecord data
58303831d35Sstevel 			 */
58403831d35Sstevel 			ssbp.data_buf = kmem_alloc(ssbp.data_len, KM_SLEEP);
58503831d35Sstevel 
58603831d35Sstevel 			if (ddi_copyin(user_data_buf, ssbp.data_buf,
58703831d35Sstevel 			    ssbp.data_len, mode) != 0) {
58803831d35Sstevel 
58903831d35Sstevel 				kmem_free(ssbp.data_buf, ssbp.data_len);
59003831d35Sstevel 				ssbp.data_buf = user_data_buf;
59103831d35Sstevel 				return (EFAULT);
59203831d35Sstevel 			}
59303831d35Sstevel 		} else {
59403831d35Sstevel 			return (EINVAL);	/* request can't be NULL! */
59503831d35Sstevel 		}
59603831d35Sstevel 
59703831d35Sstevel 		/*
59803831d35Sstevel 		 * save the user request buffer pointer
59903831d35Sstevel 		 */
60003831d35Sstevel 		user_resp_buf = ssbp.resp_bp.msg_buf;
60103831d35Sstevel 		if (user_resp_buf != NULL) {
60203831d35Sstevel 			ssbp.resp_bp.msg_buf =
60303831d35Sstevel 			    kmem_alloc(ssbp.resp_bp.msg_len, KM_SLEEP);
60403831d35Sstevel 		} else {
60503831d35Sstevel 
60603831d35Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
60703831d35Sstevel 			return (EINVAL);
60803831d35Sstevel 		}
60903831d35Sstevel 
61003831d35Sstevel 		/*
61103831d35Sstevel 		 * send the srecord via the rmc_comm driver and get the reply
61203831d35Sstevel 		 * back (BP message)
61303831d35Sstevel 		 */
61403831d35Sstevel 
61503831d35Sstevel 		rmc_respp->msg_type = ssbp.resp_bp.msg_type;
61603831d35Sstevel 		rmc_respp->msg_buf = ssbp.resp_bp.msg_buf;
61703831d35Sstevel 		rmc_respp->msg_len = ssbp.resp_bp.msg_len;
61803831d35Sstevel 		rmc_respp->msg_bytes = ssbp.resp_bp.msg_bytes;
61903831d35Sstevel 
62003831d35Sstevel 		ssbp.status = rmc_comm_send_srecord_bp(ssbp.data_buf,
62103831d35Sstevel 		    ssbp.data_len, rmc_respp, ssbp.wait_time);
62203831d35Sstevel 
62303831d35Sstevel 		/*
62403831d35Sstevel 		 * copy back the actual size of the returned message
62503831d35Sstevel 		 */
62603831d35Sstevel 		ssbp.resp_bp.msg_bytes = rmc_respp->msg_bytes;
62703831d35Sstevel 
62803831d35Sstevel 		if (ssbp.status != RCNOERR) {
62903831d35Sstevel 			retval = rmcadm_get_errno(ssbp.status);
63003831d35Sstevel 
63103831d35Sstevel 		} else if (user_resp_buf != NULL) {
63203831d35Sstevel 			/*
63303831d35Sstevel 			 * copy out the user BP response buffer
63403831d35Sstevel 			 */
63503831d35Sstevel 			if (ddi_copyout(ssbp.resp_bp.msg_buf, user_resp_buf,
63603831d35Sstevel 			    ssbp.resp_bp.msg_bytes, mode) != 0) {
63703831d35Sstevel 				retval = EFAULT;
63803831d35Sstevel 			}
63903831d35Sstevel 		}
64003831d35Sstevel 
64103831d35Sstevel 		/*
64203831d35Sstevel 		 * now copy out the updated request_response structure
64303831d35Sstevel 		 */
64403831d35Sstevel 		if (ssbp.data_buf)
64503831d35Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
64603831d35Sstevel 		if (ssbp.resp_bp.msg_buf)
64703831d35Sstevel 			kmem_free(ssbp.resp_bp.msg_buf, ssbp.resp_bp.msg_len);
64803831d35Sstevel 
64903831d35Sstevel 		ssbp.data_buf = user_data_buf;
65003831d35Sstevel 		ssbp.resp_bp.msg_buf = user_resp_buf;
65103831d35Sstevel 
65203831d35Sstevel #ifdef _MULTI_DATAMODEL
65303831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
65403831d35Sstevel 		case DDI_MODEL_ILP32:
65503831d35Sstevel 		{
65603831d35Sstevel 			/*
65703831d35Sstevel 			 * For use when a 32 bit app makes a call into a
65803831d35Sstevel 			 * 64 bit ioctl
65903831d35Sstevel 			 */
66003831d35Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
66103831d35Sstevel 
66203831d35Sstevel 			ssbp32.data_len = ssbp.data_len;
66303831d35Sstevel 			ssbp32.data_buf = (caddr32_t)(uintptr_t)ssbp.data_buf;
66403831d35Sstevel 			ssbp32.resp_bp.msg_type = ssbp.resp_bp.msg_type;
66503831d35Sstevel 			ssbp32.resp_bp.msg_len = ssbp.resp_bp.msg_len;
66603831d35Sstevel 			ssbp32.resp_bp.msg_bytes = ssbp.resp_bp.msg_bytes;
66703831d35Sstevel 			ssbp32.resp_bp.msg_buf =
66803831d35Sstevel 			    (caddr32_t)(uintptr_t)ssbp.resp_bp.msg_buf;
66903831d35Sstevel 			ssbp32.wait_time = ssbp.wait_time;
67003831d35Sstevel 
67103831d35Sstevel 			if (ddi_copyout((caddr_t)&ssbp32, (caddr_t)arg,
67203831d35Sstevel 			    sizeof (ssbp32), mode)) {
67303831d35Sstevel 				return (EFAULT);
67403831d35Sstevel 			}
67503831d35Sstevel 			break;
67603831d35Sstevel 		}
67703831d35Sstevel 		case DDI_MODEL_NONE:
67803831d35Sstevel 			if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg,
67903831d35Sstevel 			    sizeof (ssbp), mode))
68003831d35Sstevel 				return (EFAULT);
68103831d35Sstevel 			break;
68203831d35Sstevel 		}
68303831d35Sstevel #else /* ! _MULTI_DATAMODEL */
68403831d35Sstevel 		if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg, sizeof (ssbp),
68503831d35Sstevel 		    mode) != 0)
68603831d35Sstevel 			return (EFAULT);
68703831d35Sstevel #endif /* _MULTI_DATAMODEL */
68803831d35Sstevel 		break;
68903831d35Sstevel 
69003831d35Sstevel 
69103831d35Sstevel 	case RMCADM_RESET_SP:
69203831d35Sstevel 		pmugpio_reset();
69303831d35Sstevel 		retval = 0;
69403831d35Sstevel 		break;
69503831d35Sstevel 	default:
69603831d35Sstevel 		retval = ENOTSUP;
69703831d35Sstevel 		break;
69803831d35Sstevel 	}
69903831d35Sstevel 	return (retval);
70003831d35Sstevel }
701