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