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
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,
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
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