xref: /onnv-gate/usr/src/uts/sun4u/io/rmcadm.c (revision 7656:2621e50fdf4a)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel #include <sys/stat.h>
291708Sstevel #include <sys/conf.h>
301708Sstevel #include <sys/modctl.h>
311708Sstevel #include <sys/ddi.h>
321708Sstevel #include <sys/rmc_comm_dp.h>
331708Sstevel #include <sys/rmc_comm_dp_boot.h>
341708Sstevel #include <sys/rmc_comm_drvintf.h>
351708Sstevel #include <sys/cyclic.h>
361708Sstevel #include <sys/rmc_comm.h>
371708Sstevel #include <sys/machsystm.h>
381708Sstevel #include <sys/file.h>
391708Sstevel #include <sys/rmcadm.h>
401708Sstevel 
411708Sstevel /*
421708Sstevel  * functions local to this driver.
431708Sstevel  */
441708Sstevel static int	rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
451708Sstevel     void **resultp);
461708Sstevel static int	rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
471708Sstevel static int	rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
481708Sstevel static int	rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
491708Sstevel static int	rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
501708Sstevel static int	rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
511708Sstevel     cred_t *cred_p, int *rval_p);
521708Sstevel 
531708Sstevel /*
541708Sstevel  * Driver entry points
551708Sstevel  */
561708Sstevel static struct cb_ops rmcadm_cb_ops = {
571708Sstevel 	rmcadm_open,	/* open */
581708Sstevel 	rmcadm_close,	/* close */
591708Sstevel 	nodev,		/* strategy() */
601708Sstevel 	nodev,		/* print() */
611708Sstevel 	nodev,		/* dump() */
621708Sstevel 	nodev,		/* read() */
631708Sstevel 	nodev,		/* write() */
641708Sstevel 	rmcadm_ioctl,	/* ioctl() */
651708Sstevel 	nodev,		/* devmap() */
661708Sstevel 	nodev,		/* mmap() */
671708Sstevel 	ddi_segmap,	/* segmap() */
681708Sstevel 	nochpoll,	/* poll() */
691708Sstevel 	ddi_prop_op,    /* prop_op() */
701708Sstevel 	NULL,		/* cb_str */
711708Sstevel 	D_NEW | D_MP	/* cb_flag */
721708Sstevel };
731708Sstevel 
741708Sstevel 
751708Sstevel static struct dev_ops rmcadm_ops = {
761708Sstevel 	DEVO_REV,
771708Sstevel 	0,			/* ref count */
781708Sstevel 	rmcadm_getinfo,		/* getinfo() */
791708Sstevel 	nulldev,		/* identify() */
801708Sstevel 	nulldev,		/* probe() */
811708Sstevel 	rmcadm_attach,		/* attach() */
821708Sstevel 	rmcadm_detach,		/* detach */
831708Sstevel 	nodev,			/* reset */
841708Sstevel 	&rmcadm_cb_ops,		/* pointer to cb_ops structure */
851708Sstevel 	(struct bus_ops *)NULL,
86*7656SSherry.Moore@Sun.COM 	nulldev,		/* power() */
87*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
881708Sstevel };
891708Sstevel 
901708Sstevel /*
911708Sstevel  * Loadable module support.
921708Sstevel  */
931708Sstevel extern struct mod_ops mod_driverops;
941708Sstevel 
951708Sstevel static struct modldrv modldrv = {
961708Sstevel 	&mod_driverops,			/* Type of module. This is a driver */
97*7656SSherry.Moore@Sun.COM 	"rmcadm control driver",	/* Name of the module */
981708Sstevel 	&rmcadm_ops			/* pointer to the dev_ops structure */
991708Sstevel };
1001708Sstevel 
1011708Sstevel static struct modlinkage modlinkage = {
1021708Sstevel 	MODREV_1,
1031708Sstevel 	&modldrv,
1041708Sstevel 	NULL
1051708Sstevel };
1061708Sstevel 
1071708Sstevel static dev_info_t		*rmcadm_dip = NULL;
1081708Sstevel 
1091708Sstevel extern void pmugpio_reset();
1101708Sstevel 
1111708Sstevel /*
1121708Sstevel  * Utilities...
1131708Sstevel  */
1141708Sstevel 
1151708Sstevel /*
1161708Sstevel  * to return the errno from the rmc_comm error status
1171708Sstevel  */
1181708Sstevel int
rmcadm_get_errno(int status)1191708Sstevel rmcadm_get_errno(int status)
1201708Sstevel {
1211708Sstevel 	int retval = EIO;
1221708Sstevel 
1231708Sstevel 	/* errors from RMC */
1241708Sstevel 	switch (status) {
1251708Sstevel 		case RCENOSOFTSTATE:
1261708Sstevel 			/* invalid/NULL soft state structure */
1271708Sstevel 			retval = EIO;
1281708Sstevel 			break;
1291708Sstevel 		case RCENODATALINK:
1301708Sstevel 			/* data protocol not available (down) */
1311708Sstevel 			retval = EIO;
1321708Sstevel 			break;
1331708Sstevel 		case RCENOMEM:
1341708Sstevel 			/* memory problems */
1351708Sstevel 			retval = ENOMEM;
1361708Sstevel 			break;
1371708Sstevel 		case RCECANTRESEND:
1381708Sstevel 			/* resend failed */
1391708Sstevel 			retval = EIO;
1401708Sstevel 			break;
1411708Sstevel 		case RCEMAXRETRIES:
1421708Sstevel 			/* reply not received - retries exceeded */
1431708Sstevel 			retval = EINTR;
1441708Sstevel 			break;
1451708Sstevel 		case RCETIMEOUT:
1461708Sstevel 			/* reply not received - command has timed out */
1471708Sstevel 			retval = EINTR;
1481708Sstevel 			break;
1491708Sstevel 		case RCEINVCMD:
1501708Sstevel 			/* data protocol cmd not supported */
1511708Sstevel 			retval = ENOTSUP;
1521708Sstevel 			break;
1531708Sstevel 		case RCEINVARG:
1541708Sstevel 			/* invalid argument(s) */
1551708Sstevel 			retval = ENOTSUP;
1561708Sstevel 			break;
1571708Sstevel 		case RCEGENERIC:
1581708Sstevel 			/* generic error */
1591708Sstevel 			retval = EIO;
1601708Sstevel 			break;
1611708Sstevel 		default:
1621708Sstevel 			retval = EIO;
1631708Sstevel 			break;
1641708Sstevel 	}
1651708Sstevel 	return (retval);
1661708Sstevel }
1671708Sstevel 
1681708Sstevel int
_init(void)1691708Sstevel _init(void)
1701708Sstevel {
1711708Sstevel 	int	error = 0;
1721708Sstevel 
1731708Sstevel 	error = mod_install(&modlinkage);
1741708Sstevel 	return (error);
1751708Sstevel }
1761708Sstevel 
1771708Sstevel 
1781708Sstevel int
_info(struct modinfo * modinfop)1791708Sstevel _info(struct modinfo *modinfop)
1801708Sstevel {
1811708Sstevel 	return (mod_info(&modlinkage, modinfop));
1821708Sstevel }
1831708Sstevel 
1841708Sstevel 
1851708Sstevel int
_fini(void)1861708Sstevel _fini(void)
1871708Sstevel {
1881708Sstevel 	int	error = 0;
1891708Sstevel 
1901708Sstevel 	error = mod_remove(&modlinkage);
1911708Sstevel 	if (error)
1921708Sstevel 		return (error);
1931708Sstevel 	return (error);
1941708Sstevel }
1951708Sstevel 
1961708Sstevel 
1971708Sstevel /* ARGSUSED */
1981708Sstevel static int
rmcadm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)1991708Sstevel rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
2001708Sstevel {
2011708Sstevel 	minor_t m = getminor((dev_t)arg);
2021708Sstevel 
2031708Sstevel 	switch (cmd) {
2041708Sstevel 	case DDI_INFO_DEVT2DEVINFO:
2051708Sstevel 		if ((m != 0) || (rmcadm_dip == NULL)) {
2061708Sstevel 			*resultp = NULL;
2071708Sstevel 			return (DDI_FAILURE);
2081708Sstevel 		}
2091708Sstevel 		*resultp = rmcadm_dip;
2101708Sstevel 		return (DDI_SUCCESS);
2111708Sstevel 	case DDI_INFO_DEVT2INSTANCE:
2121708Sstevel 		*resultp = (void *)(uintptr_t)m;
2131708Sstevel 		return (DDI_SUCCESS);
2141708Sstevel 	default:
2151708Sstevel 		return (DDI_FAILURE);
2161708Sstevel 	}
2171708Sstevel }
2181708Sstevel 
2191708Sstevel 
2201708Sstevel static int
rmcadm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2211708Sstevel rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2221708Sstevel {
2231708Sstevel 	int			instance;
2241708Sstevel 	int			err;
2251708Sstevel 
2261708Sstevel 	switch (cmd) {
2271708Sstevel 	case DDI_ATTACH:
2281708Sstevel 		/*
2291708Sstevel 		 * only allow one instance
2301708Sstevel 		 */
2311708Sstevel 		instance = ddi_get_instance(dip);
2321708Sstevel 		if (instance != 0)
2331708Sstevel 			return (DDI_FAILURE);
2341708Sstevel 
2351708Sstevel 		err = ddi_create_minor_node(dip, "rmcadm", S_IFCHR,
236*7656SSherry.Moore@Sun.COM 		    instance, DDI_PSEUDO, NULL);
2371708Sstevel 		if (err != DDI_SUCCESS)
2381708Sstevel 			return (DDI_FAILURE);
2391708Sstevel 
2401708Sstevel 		/*
2411708Sstevel 		 * Register with rmc_comm to prevent it being detached
2421708Sstevel 		 */
2431708Sstevel 		err = rmc_comm_register();
2441708Sstevel 		if (err != DDI_SUCCESS) {
2451708Sstevel 			ddi_remove_minor_node(dip, NULL);
2461708Sstevel 			return (DDI_FAILURE);
2471708Sstevel 		}
2481708Sstevel 
2491708Sstevel 		/* Remember the dev info */
2501708Sstevel 		rmcadm_dip = dip;
2511708Sstevel 
2521708Sstevel 		ddi_report_dev(dip);
2531708Sstevel 		return (DDI_SUCCESS);
2541708Sstevel 	case DDI_RESUME:
2551708Sstevel 		return (DDI_SUCCESS);
2561708Sstevel 	default:
2571708Sstevel 		return (DDI_FAILURE);
2581708Sstevel 	}
2591708Sstevel }
2601708Sstevel 
2611708Sstevel 
2621708Sstevel static int
rmcadm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2631708Sstevel rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2641708Sstevel {
2651708Sstevel 	int	instance;
2661708Sstevel 
2671708Sstevel 	switch (cmd) {
2681708Sstevel 	case DDI_DETACH:
2691708Sstevel 		instance = ddi_get_instance(dip);
2701708Sstevel 		if (instance != 0)
2711708Sstevel 			return (DDI_FAILURE);
2721708Sstevel 
2731708Sstevel 		rmcadm_dip = NULL;
2741708Sstevel 		ddi_remove_minor_node(dip, NULL);
2751708Sstevel 		rmc_comm_unregister();
2761708Sstevel 		return (DDI_SUCCESS);
2771708Sstevel 	case DDI_SUSPEND:
2781708Sstevel 		return (DDI_SUCCESS);
2791708Sstevel 	default:
2801708Sstevel 		return (DDI_FAILURE);
2811708Sstevel 	}
2821708Sstevel }
2831708Sstevel 
2841708Sstevel /*ARGSUSED*/
2851708Sstevel static int
rmcadm_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)2861708Sstevel rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
2871708Sstevel {
2881708Sstevel 	int error = 0;
2891708Sstevel 	int instance = getminor(*dev_p);
2901708Sstevel 
2911708Sstevel 	if (instance != 0)
2921708Sstevel 		return (ENXIO);
2931708Sstevel 
2941708Sstevel 	if ((error = drv_priv(cred_p)) != 0) {
2951708Sstevel 		cmn_err(CE_WARN, "rmcadm: inst %d drv_priv failed",
2961708Sstevel 		    instance);
2971708Sstevel 		return (error);
2981708Sstevel 	}
2991708Sstevel 	return (error);
3001708Sstevel }
3011708Sstevel 
3021708Sstevel /*ARGSUSED*/
3031708Sstevel static int
rmcadm_close(dev_t dev,int flag,int otyp,cred_t * cred_p)3041708Sstevel rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
3051708Sstevel {
3061708Sstevel 	return (DDI_SUCCESS);
3071708Sstevel }
3081708Sstevel 
3091708Sstevel /*ARGSUSED*/
3101708Sstevel static int
rmcadm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)3111708Sstevel rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
3121708Sstevel     int *rval_p)
3131708Sstevel {
3141708Sstevel 	int				instance = getminor(dev);
3151708Sstevel 	int				retval = 0;
3161708Sstevel 	rmcadm_request_response_t	rr;
3171708Sstevel 	rmcadm_send_srecord_bp_t	ssbp;
3181708Sstevel 	rmc_comm_msg_t			rmc_req, *rmc_reqp = &rmc_req;
3191708Sstevel 	rmc_comm_msg_t			rmc_resp, *rmc_respp = &rmc_resp;
3201708Sstevel 	caddr_t				user_req_buf;
3211708Sstevel 	caddr_t				user_data_buf;
3221708Sstevel 	caddr_t				user_resp_buf;
3231708Sstevel 
3241708Sstevel 	if (instance != 0)
3251708Sstevel 		return (ENXIO);
3261708Sstevel 
3271708Sstevel 	switch (cmd) {
3281708Sstevel 
3291708Sstevel 	case RMCADM_REQUEST_RESPONSE:
3301708Sstevel 	case RMCADM_REQUEST_RESPONSE_BP:
3311708Sstevel 
3321708Sstevel 		/*
3331708Sstevel 		 * first copy in the request_response structure
3341708Sstevel 		 */
3351708Sstevel #ifdef _MULTI_DATAMODEL
3361708Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
3371708Sstevel 		case DDI_MODEL_ILP32:
3381708Sstevel 		{
3391708Sstevel 			/*
3401708Sstevel 			 * For use when a 32 bit app makes a call into a
3411708Sstevel 			 * 64 bit ioctl
3421708Sstevel 			 */
3431708Sstevel 			rmcadm_request_response32_t	rr32;
3441708Sstevel 
3451708Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr32,
3461708Sstevel 			    sizeof (rr32), mode)) {
3471708Sstevel 				return (EFAULT);
3481708Sstevel 			}
3491708Sstevel 			rr.req.msg_type = rr32.req.msg_type;
3501708Sstevel 			rr.req.msg_len = rr32.req.msg_len;
3511708Sstevel 			rr.req.msg_bytes = rr32.req.msg_bytes;
3521708Sstevel 			rr.req.msg_buf = (caddr_t)(uintptr_t)rr32.req.msg_buf;
3531708Sstevel 			rr.resp.msg_type = rr32.resp.msg_type;
3541708Sstevel 			rr.resp.msg_len = rr32.resp.msg_len;
3551708Sstevel 			rr.resp.msg_bytes = rr32.resp.msg_bytes;
3561708Sstevel 			rr.resp.msg_buf = (caddr_t)(uintptr_t)rr32.resp.msg_buf;
3571708Sstevel 			rr.wait_time = rr32.wait_time;
3581708Sstevel 			break;
3591708Sstevel 		}
3601708Sstevel 		case DDI_MODEL_NONE:
3611708Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
3621708Sstevel 			    sizeof (rr), mode)) {
3631708Sstevel 				return (EFAULT);
3641708Sstevel 			}
3651708Sstevel 			break;
3661708Sstevel 		}
3671708Sstevel #else /* ! _MULTI_DATAMODEL */
3681708Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
3691708Sstevel 		    sizeof (rr), mode) != 0) {
3701708Sstevel 			return (EFAULT);
3711708Sstevel 		}
3721708Sstevel #endif /* _MULTI_DATAMODEL */
3731708Sstevel 
3741708Sstevel 		/*
3751708Sstevel 		 * save the user request buffer pointer
3761708Sstevel 		 */
3771708Sstevel 		user_req_buf = rr.req.msg_buf;
3781708Sstevel 
3791708Sstevel 		if (user_req_buf != NULL) {
3801708Sstevel 			/*
3811708Sstevel 			 * copy in the request data
3821708Sstevel 			 */
3831708Sstevel 			rr.req.msg_buf = kmem_alloc(rr.req.msg_len, KM_SLEEP);
3841708Sstevel 
3851708Sstevel 			if (ddi_copyin(user_req_buf, rr.req.msg_buf,
3861708Sstevel 			    rr.req.msg_len, mode) != 0) {
3871708Sstevel 
3881708Sstevel 				kmem_free(rr.req.msg_buf, rr.req.msg_len);
3891708Sstevel 				rr.req.msg_buf = user_req_buf;
3901708Sstevel 				return (EFAULT);
3911708Sstevel 			}
3921708Sstevel 		} else {
3931708Sstevel 			if (rr.req.msg_len > 0)
3941708Sstevel 				/*
3951708Sstevel 				 * msg_len should be 0 if buffer is NULL!
3961708Sstevel 				 */
3971708Sstevel 				return (EINVAL);
3981708Sstevel 		}
3991708Sstevel 
4001708Sstevel 		/*
4011708Sstevel 		 * save the user request buffer pointer
4021708Sstevel 		 */
4031708Sstevel 		user_resp_buf = rr.resp.msg_buf;
4041708Sstevel 		if (user_resp_buf != NULL) {
4051708Sstevel 			rr.resp.msg_buf = kmem_alloc(rr.resp.msg_len, KM_SLEEP);
4061708Sstevel 		}
4071708Sstevel 
4081708Sstevel 		/*
4091708Sstevel 		 * send the request (or BP request) via the rmc_comm driver
4101708Sstevel 		 */
4111708Sstevel 		rmc_reqp->msg_type = rr.req.msg_type;
4121708Sstevel 		rmc_reqp->msg_buf = rr.req.msg_buf;
4131708Sstevel 		rmc_reqp->msg_len = rr.req.msg_len;
4141708Sstevel 		rmc_reqp->msg_bytes = rr.req.msg_bytes;
4151708Sstevel 
4161708Sstevel 		if (cmd == RMCADM_REQUEST_RESPONSE) {
4171708Sstevel 
4181708Sstevel 			/*
4191708Sstevel 			 * check if response is expected. If so, fill in
4201708Sstevel 			 * the response data structure
4211708Sstevel 			 */
4221708Sstevel 			if (rr.resp.msg_type != DP_NULL_MSG) {
4231708Sstevel 
4241708Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
4251708Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
4261708Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
4271708Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
4281708Sstevel 
4291708Sstevel 			} else {
4301708Sstevel 
4311708Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
4321708Sstevel 			}
4331708Sstevel 
4341708Sstevel 			rr.status = rmc_comm_request_response(
435*7656SSherry.Moore@Sun.COM 			    rmc_reqp, rmc_respp, rr.wait_time);
4361708Sstevel 
4371708Sstevel 		} else { /* RMCADM_REQUEST_RESPONSE_BP */
4381708Sstevel 
4391708Sstevel 			/*
4401708Sstevel 			 * check if a BP message is expected back. If so,
4411708Sstevel 			 * fill in the response data structure
4421708Sstevel 			 */
4431708Sstevel 			if (rr.resp.msg_buf != NULL) {
4441708Sstevel 
4451708Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
4461708Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
4471708Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
4481708Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
4491708Sstevel 
4501708Sstevel 			} else {
4511708Sstevel 
4521708Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
4531708Sstevel 			}
4541708Sstevel 
4551708Sstevel 			rr.status = rmc_comm_request_response_bp(
456*7656SSherry.Moore@Sun.COM 			    rmc_reqp, rmc_respp, rr.wait_time);
4571708Sstevel 		}
4581708Sstevel 
4591708Sstevel 		/*
4601708Sstevel 		 * if a response was expected, copy back the (actual) number
4611708Sstevel 		 * of bytes of the response returned by the
4621708Sstevel 		 * rmc_comm_request_response function (msg_bytes field)
4631708Sstevel 		 */
4641708Sstevel 		if (rmc_respp != NULL) {
4651708Sstevel 			rr.resp.msg_bytes = rmc_respp->msg_bytes;
4661708Sstevel 		}
4671708Sstevel 
4681708Sstevel 		if (rr.status != RCNOERR) {
4691708Sstevel 
4701708Sstevel 			retval = rmcadm_get_errno(rr.status);
4711708Sstevel 
4721708Sstevel 		} else if (user_resp_buf != NULL) {
4731708Sstevel 			/*
4741708Sstevel 			 * copy out the user response buffer
4751708Sstevel 			 */
4761708Sstevel 			if (ddi_copyout(rr.resp.msg_buf, user_resp_buf,
4771708Sstevel 			    rr.resp.msg_bytes, mode) != 0) {
4781708Sstevel 				retval = EFAULT;
4791708Sstevel 			}
4801708Sstevel 		}
4811708Sstevel 
4821708Sstevel 		/*
4831708Sstevel 		 * now copy out the updated request_response structure
4841708Sstevel 		 */
4851708Sstevel 		if (rr.req.msg_buf)
4861708Sstevel 			kmem_free(rr.req.msg_buf, rr.req.msg_len);
4871708Sstevel 		if (rr.resp.msg_buf)
4881708Sstevel 			kmem_free(rr.resp.msg_buf, rr.resp.msg_len);
4891708Sstevel 
4901708Sstevel 		rr.req.msg_buf = user_req_buf;
4911708Sstevel 		rr.resp.msg_buf = user_resp_buf;
4921708Sstevel 
4931708Sstevel #ifdef _MULTI_DATAMODEL
4941708Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
4951708Sstevel 		case DDI_MODEL_ILP32:
4961708Sstevel 		{
4971708Sstevel 			/*
4981708Sstevel 			 * For use when a 32 bit app makes a call into a
4991708Sstevel 			 * 64 bit ioctl
5001708Sstevel 			 */
5011708Sstevel 			rmcadm_request_response32_t	rr32;
5021708Sstevel 
5031708Sstevel 			rr32.req.msg_type = rr.req.msg_type;
5041708Sstevel 			rr32.req.msg_len = rr.req.msg_len;
5051708Sstevel 			rr32.req.msg_bytes = rr.req.msg_bytes;
5061708Sstevel 			rr32.req.msg_buf = (caddr32_t)(uintptr_t)rr.req.msg_buf;
5071708Sstevel 			rr32.resp.msg_type = rr.resp.msg_type;
5081708Sstevel 			rr32.resp.msg_len = rr.resp.msg_len;
5091708Sstevel 			rr32.resp.msg_bytes = rr.resp.msg_bytes;
5101708Sstevel 			rr32.resp.msg_buf =
5111708Sstevel 			    (caddr32_t)(uintptr_t)rr.resp.msg_buf;
5121708Sstevel 			rr32.wait_time = rr.wait_time;
5131708Sstevel 			rr32.status = rr.status;
5141708Sstevel 			if (ddi_copyout((caddr_t)&rr32, (caddr_t)arg,
5151708Sstevel 			    sizeof (rr32), mode)) {
5161708Sstevel 				return (EFAULT);
5171708Sstevel 			}
5181708Sstevel 			break;
5191708Sstevel 		}
5201708Sstevel 		case DDI_MODEL_NONE:
5211708Sstevel 			if (ddi_copyout((caddr_t)&rr, (caddr_t)arg,
5221708Sstevel 			    sizeof (rr), mode))
5231708Sstevel 				return (EFAULT);
5241708Sstevel 			break;
5251708Sstevel 		}
5261708Sstevel #else /* ! _MULTI_DATAMODEL */
5271708Sstevel 		if (ddi_copyout((caddr_t)&rr, (caddr_t)arg, sizeof (rr),
5281708Sstevel 		    mode) != 0)
5291708Sstevel 			return (EFAULT);
5301708Sstevel #endif /* _MULTI_DATAMODEL */
5311708Sstevel 		break;
5321708Sstevel 
5331708Sstevel 
5341708Sstevel 	case RMCADM_SEND_SRECORD_BP:
5351708Sstevel 
5361708Sstevel 		/*
5371708Sstevel 		 * first copy in the request_response structure
5381708Sstevel 		 */
5391708Sstevel #ifdef _MULTI_DATAMODEL
5401708Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
5411708Sstevel 		case DDI_MODEL_ILP32:
5421708Sstevel 		{
5431708Sstevel 			/*
5441708Sstevel 			 * For use when a 32 bit app makes a call into a
5451708Sstevel 			 * 64 bit ioctl
5461708Sstevel 			 */
5471708Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
5481708Sstevel 
5491708Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp32,
5501708Sstevel 			    sizeof (ssbp32), mode)) {
5511708Sstevel 				return (EFAULT);
5521708Sstevel 			}
5531708Sstevel 			ssbp.data_len = ssbp32.data_len;
5541708Sstevel 			ssbp.data_buf = (caddr_t)(uintptr_t)ssbp32.data_buf;
5551708Sstevel 			ssbp.resp_bp.msg_type = ssbp32.resp_bp.msg_type;
5561708Sstevel 			ssbp.resp_bp.msg_len = ssbp32.resp_bp.msg_len;
5571708Sstevel 			ssbp.resp_bp.msg_bytes = ssbp32.resp_bp.msg_bytes;
5581708Sstevel 			ssbp.resp_bp.msg_buf =
5591708Sstevel 			    (caddr_t)(uintptr_t)ssbp32.resp_bp.msg_buf;
5601708Sstevel 			ssbp.wait_time = ssbp32.wait_time;
5611708Sstevel 			break;
5621708Sstevel 		}
5631708Sstevel 		case DDI_MODEL_NONE:
5641708Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
5651708Sstevel 			    sizeof (ssbp), mode))
5661708Sstevel 				return (EFAULT);
5671708Sstevel 			break;
5681708Sstevel 		}
5691708Sstevel #else /* ! _MULTI_DATAMODEL */
5701708Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
5711708Sstevel 		    sizeof (ssbp), mode) != 0)
5721708Sstevel 			return (EFAULT);
5731708Sstevel #endif /* _MULTI_DATAMODEL */
5741708Sstevel 
5751708Sstevel 		/*
5761708Sstevel 		 * save the user data buffer pointer
5771708Sstevel 		 */
5781708Sstevel 		user_data_buf = ssbp.data_buf;
5791708Sstevel 
5801708Sstevel 		if (user_data_buf != NULL) {
5811708Sstevel 			/*
5821708Sstevel 			 * copy in the srecord data
5831708Sstevel 			 */
5841708Sstevel 			ssbp.data_buf = kmem_alloc(ssbp.data_len, KM_SLEEP);
5851708Sstevel 
5861708Sstevel 			if (ddi_copyin(user_data_buf, ssbp.data_buf,
5871708Sstevel 			    ssbp.data_len, mode) != 0) {
5881708Sstevel 
5891708Sstevel 				kmem_free(ssbp.data_buf, ssbp.data_len);
5901708Sstevel 				ssbp.data_buf = user_data_buf;
5911708Sstevel 				return (EFAULT);
5921708Sstevel 			}
5931708Sstevel 		} else {
5941708Sstevel 			return (EINVAL);	/* request can't be NULL! */
5951708Sstevel 		}
5961708Sstevel 
5971708Sstevel 		/*
5981708Sstevel 		 * save the user request buffer pointer
5991708Sstevel 		 */
6001708Sstevel 		user_resp_buf = ssbp.resp_bp.msg_buf;
6011708Sstevel 		if (user_resp_buf != NULL) {
6021708Sstevel 			ssbp.resp_bp.msg_buf =
6031708Sstevel 			    kmem_alloc(ssbp.resp_bp.msg_len, KM_SLEEP);
6041708Sstevel 		} else {
6051708Sstevel 
6061708Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
6071708Sstevel 			return (EINVAL);
6081708Sstevel 		}
6091708Sstevel 
6101708Sstevel 		/*
6111708Sstevel 		 * send the srecord via the rmc_comm driver and get the reply
6121708Sstevel 		 * back (BP message)
6131708Sstevel 		 */
6141708Sstevel 
6151708Sstevel 		rmc_respp->msg_type = ssbp.resp_bp.msg_type;
6161708Sstevel 		rmc_respp->msg_buf = ssbp.resp_bp.msg_buf;
6171708Sstevel 		rmc_respp->msg_len = ssbp.resp_bp.msg_len;
6181708Sstevel 		rmc_respp->msg_bytes = ssbp.resp_bp.msg_bytes;
6191708Sstevel 
6201708Sstevel 		ssbp.status = rmc_comm_send_srecord_bp(ssbp.data_buf,
6211708Sstevel 		    ssbp.data_len, rmc_respp, ssbp.wait_time);
6221708Sstevel 
6231708Sstevel 		/*
6241708Sstevel 		 * copy back the actual size of the returned message
6251708Sstevel 		 */
6261708Sstevel 		ssbp.resp_bp.msg_bytes = rmc_respp->msg_bytes;
6271708Sstevel 
6281708Sstevel 		if (ssbp.status != RCNOERR) {
6291708Sstevel 			retval = rmcadm_get_errno(ssbp.status);
6301708Sstevel 
6311708Sstevel 		} else if (user_resp_buf != NULL) {
6321708Sstevel 			/*
6331708Sstevel 			 * copy out the user BP response buffer
6341708Sstevel 			 */
6351708Sstevel 			if (ddi_copyout(ssbp.resp_bp.msg_buf, user_resp_buf,
6361708Sstevel 			    ssbp.resp_bp.msg_bytes, mode) != 0) {
6371708Sstevel 				retval = EFAULT;
6381708Sstevel 			}
6391708Sstevel 		}
6401708Sstevel 
6411708Sstevel 		/*
6421708Sstevel 		 * now copy out the updated request_response structure
6431708Sstevel 		 */
6441708Sstevel 		if (ssbp.data_buf)
6451708Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
6461708Sstevel 		if (ssbp.resp_bp.msg_buf)
6471708Sstevel 			kmem_free(ssbp.resp_bp.msg_buf, ssbp.resp_bp.msg_len);
6481708Sstevel 
6491708Sstevel 		ssbp.data_buf = user_data_buf;
6501708Sstevel 		ssbp.resp_bp.msg_buf = user_resp_buf;
6511708Sstevel 
6521708Sstevel #ifdef _MULTI_DATAMODEL
6531708Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
6541708Sstevel 		case DDI_MODEL_ILP32:
6551708Sstevel 		{
6561708Sstevel 			/*
6571708Sstevel 			 * For use when a 32 bit app makes a call into a
6581708Sstevel 			 * 64 bit ioctl
6591708Sstevel 			 */
6601708Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
6611708Sstevel 
6621708Sstevel 			ssbp32.data_len = ssbp.data_len;
6631708Sstevel 			ssbp32.data_buf = (caddr32_t)(uintptr_t)ssbp.data_buf;
6641708Sstevel 			ssbp32.resp_bp.msg_type = ssbp.resp_bp.msg_type;
6651708Sstevel 			ssbp32.resp_bp.msg_len = ssbp.resp_bp.msg_len;
6661708Sstevel 			ssbp32.resp_bp.msg_bytes = ssbp.resp_bp.msg_bytes;
6671708Sstevel 			ssbp32.resp_bp.msg_buf =
6681708Sstevel 			    (caddr32_t)(uintptr_t)ssbp.resp_bp.msg_buf;
6691708Sstevel 			ssbp32.wait_time = ssbp.wait_time;
6701708Sstevel 
6711708Sstevel 			if (ddi_copyout((caddr_t)&ssbp32, (caddr_t)arg,
6721708Sstevel 			    sizeof (ssbp32), mode)) {
6731708Sstevel 				return (EFAULT);
6741708Sstevel 			}
6751708Sstevel 			break;
6761708Sstevel 		}
6771708Sstevel 		case DDI_MODEL_NONE:
6781708Sstevel 			if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg,
6791708Sstevel 			    sizeof (ssbp), mode))
6801708Sstevel 				return (EFAULT);
6811708Sstevel 			break;
6821708Sstevel 		}
6831708Sstevel #else /* ! _MULTI_DATAMODEL */
6841708Sstevel 		if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg, sizeof (ssbp),
6851708Sstevel 		    mode) != 0)
6861708Sstevel 			return (EFAULT);
6871708Sstevel #endif /* _MULTI_DATAMODEL */
6881708Sstevel 		break;
6891708Sstevel 
6901708Sstevel 
6911708Sstevel 	case RMCADM_RESET_SP:
6921708Sstevel 		pmugpio_reset();
6931708Sstevel 		retval = 0;
6941708Sstevel 		break;
6951708Sstevel 	default:
6961708Sstevel 		retval = ENOTSUP;
6971708Sstevel 		break;
6981708Sstevel 	}
6991708Sstevel 	return (retval);
7001708Sstevel }
701