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/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, 86*19397407SSherry Moore nulldev, /* power() */ 87*19397407SSherry 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 */ 97*19397407SSherry 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 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 16903831d35Sstevel _init(void) 17003831d35Sstevel { 17103831d35Sstevel int error = 0; 17203831d35Sstevel 17303831d35Sstevel error = mod_install(&modlinkage); 17403831d35Sstevel return (error); 17503831d35Sstevel } 17603831d35Sstevel 17703831d35Sstevel 17803831d35Sstevel int 17903831d35Sstevel _info(struct modinfo *modinfop) 18003831d35Sstevel { 18103831d35Sstevel return (mod_info(&modlinkage, modinfop)); 18203831d35Sstevel } 18303831d35Sstevel 18403831d35Sstevel 18503831d35Sstevel int 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 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 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, 23603831d35Sstevel instance, DDI_PSEUDO, NULL); 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 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 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 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 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