xref: /illumos-gate/usr/src/uts/sun4u/io/rmcadm.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
1*03831d35Sstevel /*
2*03831d35Sstevel  * CDDL HEADER START
3*03831d35Sstevel  *
4*03831d35Sstevel  * The contents of this file are subject to the terms of the
5*03831d35Sstevel  * Common Development and Distribution License (the "License").
6*03831d35Sstevel  * You may not use this file except in compliance with the License.
7*03831d35Sstevel  *
8*03831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*03831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
10*03831d35Sstevel  * See the License for the specific language governing permissions
11*03831d35Sstevel  * and limitations under the License.
12*03831d35Sstevel  *
13*03831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
14*03831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*03831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
16*03831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
17*03831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
18*03831d35Sstevel  *
19*03831d35Sstevel  * CDDL HEADER END
20*03831d35Sstevel  */
21*03831d35Sstevel 
22*03831d35Sstevel /*
23*03831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  */
26*03831d35Sstevel 
27*03831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*03831d35Sstevel 
29*03831d35Sstevel #include <sys/stat.h>
30*03831d35Sstevel #include <sys/conf.h>
31*03831d35Sstevel #include <sys/modctl.h>
32*03831d35Sstevel #include <sys/ddi.h>
33*03831d35Sstevel #include <sys/rmc_comm_dp.h>
34*03831d35Sstevel #include <sys/rmc_comm_dp_boot.h>
35*03831d35Sstevel #include <sys/rmc_comm_drvintf.h>
36*03831d35Sstevel #include <sys/cyclic.h>
37*03831d35Sstevel #include <sys/rmc_comm.h>
38*03831d35Sstevel #include <sys/machsystm.h>
39*03831d35Sstevel #include <sys/file.h>
40*03831d35Sstevel #include <sys/rmcadm.h>
41*03831d35Sstevel 
42*03831d35Sstevel /*
43*03831d35Sstevel  * functions local to this driver.
44*03831d35Sstevel  */
45*03831d35Sstevel static int	rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
46*03831d35Sstevel     void **resultp);
47*03831d35Sstevel static int	rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
48*03831d35Sstevel static int	rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
49*03831d35Sstevel static int	rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
50*03831d35Sstevel static int	rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
51*03831d35Sstevel static int	rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
52*03831d35Sstevel     cred_t *cred_p, int *rval_p);
53*03831d35Sstevel 
54*03831d35Sstevel /*
55*03831d35Sstevel  * Driver entry points
56*03831d35Sstevel  */
57*03831d35Sstevel static struct cb_ops rmcadm_cb_ops = {
58*03831d35Sstevel 	rmcadm_open,	/* open */
59*03831d35Sstevel 	rmcadm_close,	/* close */
60*03831d35Sstevel 	nodev,		/* strategy() */
61*03831d35Sstevel 	nodev,		/* print() */
62*03831d35Sstevel 	nodev,		/* dump() */
63*03831d35Sstevel 	nodev,		/* read() */
64*03831d35Sstevel 	nodev,		/* write() */
65*03831d35Sstevel 	rmcadm_ioctl,	/* ioctl() */
66*03831d35Sstevel 	nodev,		/* devmap() */
67*03831d35Sstevel 	nodev,		/* mmap() */
68*03831d35Sstevel 	ddi_segmap,	/* segmap() */
69*03831d35Sstevel 	nochpoll,	/* poll() */
70*03831d35Sstevel 	ddi_prop_op,    /* prop_op() */
71*03831d35Sstevel 	NULL,		/* cb_str */
72*03831d35Sstevel 	D_NEW | D_MP	/* cb_flag */
73*03831d35Sstevel };
74*03831d35Sstevel 
75*03831d35Sstevel 
76*03831d35Sstevel static struct dev_ops rmcadm_ops = {
77*03831d35Sstevel 	DEVO_REV,
78*03831d35Sstevel 	0,			/* ref count */
79*03831d35Sstevel 	rmcadm_getinfo,		/* getinfo() */
80*03831d35Sstevel 	nulldev,		/* identify() */
81*03831d35Sstevel 	nulldev,		/* probe() */
82*03831d35Sstevel 	rmcadm_attach,		/* attach() */
83*03831d35Sstevel 	rmcadm_detach,		/* detach */
84*03831d35Sstevel 	nodev,			/* reset */
85*03831d35Sstevel 	&rmcadm_cb_ops,		/* pointer to cb_ops structure */
86*03831d35Sstevel 	(struct bus_ops *)NULL,
87*03831d35Sstevel 	nulldev			/* power() */
88*03831d35Sstevel };
89*03831d35Sstevel 
90*03831d35Sstevel /*
91*03831d35Sstevel  * Loadable module support.
92*03831d35Sstevel  */
93*03831d35Sstevel extern struct mod_ops mod_driverops;
94*03831d35Sstevel 
95*03831d35Sstevel static struct modldrv modldrv = {
96*03831d35Sstevel 	&mod_driverops,			/* Type of module. This is a driver */
97*03831d35Sstevel 	"rmcadm control driver v%I%",	/* Name of the module */
98*03831d35Sstevel 	&rmcadm_ops			/* pointer to the dev_ops structure */
99*03831d35Sstevel };
100*03831d35Sstevel 
101*03831d35Sstevel static struct modlinkage modlinkage = {
102*03831d35Sstevel 	MODREV_1,
103*03831d35Sstevel 	&modldrv,
104*03831d35Sstevel 	NULL
105*03831d35Sstevel };
106*03831d35Sstevel 
107*03831d35Sstevel static dev_info_t		*rmcadm_dip = NULL;
108*03831d35Sstevel 
109*03831d35Sstevel extern void pmugpio_reset();
110*03831d35Sstevel 
111*03831d35Sstevel /*
112*03831d35Sstevel  * Utilities...
113*03831d35Sstevel  */
114*03831d35Sstevel 
115*03831d35Sstevel /*
116*03831d35Sstevel  * to return the errno from the rmc_comm error status
117*03831d35Sstevel  */
118*03831d35Sstevel int
119*03831d35Sstevel rmcadm_get_errno(int status)
120*03831d35Sstevel {
121*03831d35Sstevel 	int retval = EIO;
122*03831d35Sstevel 
123*03831d35Sstevel 	/* errors from RMC */
124*03831d35Sstevel 	switch (status) {
125*03831d35Sstevel 		case RCENOSOFTSTATE:
126*03831d35Sstevel 			/* invalid/NULL soft state structure */
127*03831d35Sstevel 			retval = EIO;
128*03831d35Sstevel 			break;
129*03831d35Sstevel 		case RCENODATALINK:
130*03831d35Sstevel 			/* data protocol not available (down) */
131*03831d35Sstevel 			retval = EIO;
132*03831d35Sstevel 			break;
133*03831d35Sstevel 		case RCENOMEM:
134*03831d35Sstevel 			/* memory problems */
135*03831d35Sstevel 			retval = ENOMEM;
136*03831d35Sstevel 			break;
137*03831d35Sstevel 		case RCECANTRESEND:
138*03831d35Sstevel 			/* resend failed */
139*03831d35Sstevel 			retval = EIO;
140*03831d35Sstevel 			break;
141*03831d35Sstevel 		case RCEMAXRETRIES:
142*03831d35Sstevel 			/* reply not received - retries exceeded */
143*03831d35Sstevel 			retval = EINTR;
144*03831d35Sstevel 			break;
145*03831d35Sstevel 		case RCETIMEOUT:
146*03831d35Sstevel 			/* reply not received - command has timed out */
147*03831d35Sstevel 			retval = EINTR;
148*03831d35Sstevel 			break;
149*03831d35Sstevel 		case RCEINVCMD:
150*03831d35Sstevel 			/* data protocol cmd not supported */
151*03831d35Sstevel 			retval = ENOTSUP;
152*03831d35Sstevel 			break;
153*03831d35Sstevel 		case RCEINVARG:
154*03831d35Sstevel 			/* invalid argument(s) */
155*03831d35Sstevel 			retval = ENOTSUP;
156*03831d35Sstevel 			break;
157*03831d35Sstevel 		case RCEGENERIC:
158*03831d35Sstevel 			/* generic error */
159*03831d35Sstevel 			retval = EIO;
160*03831d35Sstevel 			break;
161*03831d35Sstevel 		default:
162*03831d35Sstevel 			retval = EIO;
163*03831d35Sstevel 			break;
164*03831d35Sstevel 	}
165*03831d35Sstevel 	return (retval);
166*03831d35Sstevel }
167*03831d35Sstevel 
168*03831d35Sstevel int
169*03831d35Sstevel _init(void)
170*03831d35Sstevel {
171*03831d35Sstevel 	int	error = 0;
172*03831d35Sstevel 
173*03831d35Sstevel 	error = mod_install(&modlinkage);
174*03831d35Sstevel 	return (error);
175*03831d35Sstevel }
176*03831d35Sstevel 
177*03831d35Sstevel 
178*03831d35Sstevel int
179*03831d35Sstevel _info(struct modinfo *modinfop)
180*03831d35Sstevel {
181*03831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
182*03831d35Sstevel }
183*03831d35Sstevel 
184*03831d35Sstevel 
185*03831d35Sstevel int
186*03831d35Sstevel _fini(void)
187*03831d35Sstevel {
188*03831d35Sstevel 	int	error = 0;
189*03831d35Sstevel 
190*03831d35Sstevel 	error = mod_remove(&modlinkage);
191*03831d35Sstevel 	if (error)
192*03831d35Sstevel 		return (error);
193*03831d35Sstevel 	return (error);
194*03831d35Sstevel }
195*03831d35Sstevel 
196*03831d35Sstevel 
197*03831d35Sstevel /* ARGSUSED */
198*03831d35Sstevel static int
199*03831d35Sstevel rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
200*03831d35Sstevel {
201*03831d35Sstevel 	minor_t m = getminor((dev_t)arg);
202*03831d35Sstevel 
203*03831d35Sstevel 	switch (cmd) {
204*03831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
205*03831d35Sstevel 		if ((m != 0) || (rmcadm_dip == NULL)) {
206*03831d35Sstevel 			*resultp = NULL;
207*03831d35Sstevel 			return (DDI_FAILURE);
208*03831d35Sstevel 		}
209*03831d35Sstevel 		*resultp = rmcadm_dip;
210*03831d35Sstevel 		return (DDI_SUCCESS);
211*03831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
212*03831d35Sstevel 		*resultp = (void *)(uintptr_t)m;
213*03831d35Sstevel 		return (DDI_SUCCESS);
214*03831d35Sstevel 	default:
215*03831d35Sstevel 		return (DDI_FAILURE);
216*03831d35Sstevel 	}
217*03831d35Sstevel }
218*03831d35Sstevel 
219*03831d35Sstevel 
220*03831d35Sstevel static int
221*03831d35Sstevel rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
222*03831d35Sstevel {
223*03831d35Sstevel 	int			instance;
224*03831d35Sstevel 	int			err;
225*03831d35Sstevel 
226*03831d35Sstevel 	switch (cmd) {
227*03831d35Sstevel 	case DDI_ATTACH:
228*03831d35Sstevel 		/*
229*03831d35Sstevel 		 * only allow one instance
230*03831d35Sstevel 		 */
231*03831d35Sstevel 		instance = ddi_get_instance(dip);
232*03831d35Sstevel 		if (instance != 0)
233*03831d35Sstevel 			return (DDI_FAILURE);
234*03831d35Sstevel 
235*03831d35Sstevel 		err = ddi_create_minor_node(dip, "rmcadm", S_IFCHR,
236*03831d35Sstevel 			instance, DDI_PSEUDO, NULL);
237*03831d35Sstevel 		if (err != DDI_SUCCESS)
238*03831d35Sstevel 			return (DDI_FAILURE);
239*03831d35Sstevel 
240*03831d35Sstevel 		/*
241*03831d35Sstevel 		 * Register with rmc_comm to prevent it being detached
242*03831d35Sstevel 		 */
243*03831d35Sstevel 		err = rmc_comm_register();
244*03831d35Sstevel 		if (err != DDI_SUCCESS) {
245*03831d35Sstevel 			ddi_remove_minor_node(dip, NULL);
246*03831d35Sstevel 			return (DDI_FAILURE);
247*03831d35Sstevel 		}
248*03831d35Sstevel 
249*03831d35Sstevel 		/* Remember the dev info */
250*03831d35Sstevel 		rmcadm_dip = dip;
251*03831d35Sstevel 
252*03831d35Sstevel 		ddi_report_dev(dip);
253*03831d35Sstevel 		return (DDI_SUCCESS);
254*03831d35Sstevel 	case DDI_RESUME:
255*03831d35Sstevel 		return (DDI_SUCCESS);
256*03831d35Sstevel 	default:
257*03831d35Sstevel 		return (DDI_FAILURE);
258*03831d35Sstevel 	}
259*03831d35Sstevel }
260*03831d35Sstevel 
261*03831d35Sstevel 
262*03831d35Sstevel static int
263*03831d35Sstevel rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
264*03831d35Sstevel {
265*03831d35Sstevel 	int	instance;
266*03831d35Sstevel 
267*03831d35Sstevel 	switch (cmd) {
268*03831d35Sstevel 	case DDI_DETACH:
269*03831d35Sstevel 		instance = ddi_get_instance(dip);
270*03831d35Sstevel 		if (instance != 0)
271*03831d35Sstevel 			return (DDI_FAILURE);
272*03831d35Sstevel 
273*03831d35Sstevel 		rmcadm_dip = NULL;
274*03831d35Sstevel 		ddi_remove_minor_node(dip, NULL);
275*03831d35Sstevel 		rmc_comm_unregister();
276*03831d35Sstevel 		return (DDI_SUCCESS);
277*03831d35Sstevel 	case DDI_SUSPEND:
278*03831d35Sstevel 		return (DDI_SUCCESS);
279*03831d35Sstevel 	default:
280*03831d35Sstevel 		return (DDI_FAILURE);
281*03831d35Sstevel 	}
282*03831d35Sstevel }
283*03831d35Sstevel 
284*03831d35Sstevel /*ARGSUSED*/
285*03831d35Sstevel static int
286*03831d35Sstevel rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
287*03831d35Sstevel {
288*03831d35Sstevel 	int error = 0;
289*03831d35Sstevel 	int instance = getminor(*dev_p);
290*03831d35Sstevel 
291*03831d35Sstevel 	if (instance != 0)
292*03831d35Sstevel 		return (ENXIO);
293*03831d35Sstevel 
294*03831d35Sstevel 	if ((error = drv_priv(cred_p)) != 0) {
295*03831d35Sstevel 		cmn_err(CE_WARN, "rmcadm: inst %d drv_priv failed",
296*03831d35Sstevel 		    instance);
297*03831d35Sstevel 		return (error);
298*03831d35Sstevel 	}
299*03831d35Sstevel 	return (error);
300*03831d35Sstevel }
301*03831d35Sstevel 
302*03831d35Sstevel /*ARGSUSED*/
303*03831d35Sstevel static int
304*03831d35Sstevel rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
305*03831d35Sstevel {
306*03831d35Sstevel 	return (DDI_SUCCESS);
307*03831d35Sstevel }
308*03831d35Sstevel 
309*03831d35Sstevel /*ARGSUSED*/
310*03831d35Sstevel static int
311*03831d35Sstevel rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
312*03831d35Sstevel     int *rval_p)
313*03831d35Sstevel {
314*03831d35Sstevel 	int				instance = getminor(dev);
315*03831d35Sstevel 	int				retval = 0;
316*03831d35Sstevel 	rmcadm_request_response_t	rr;
317*03831d35Sstevel 	rmcadm_send_srecord_bp_t	ssbp;
318*03831d35Sstevel 	rmc_comm_msg_t			rmc_req, *rmc_reqp = &rmc_req;
319*03831d35Sstevel 	rmc_comm_msg_t			rmc_resp, *rmc_respp = &rmc_resp;
320*03831d35Sstevel 	caddr_t				user_req_buf;
321*03831d35Sstevel 	caddr_t				user_data_buf;
322*03831d35Sstevel 	caddr_t				user_resp_buf;
323*03831d35Sstevel 
324*03831d35Sstevel 	if (instance != 0)
325*03831d35Sstevel 		return (ENXIO);
326*03831d35Sstevel 
327*03831d35Sstevel 	switch (cmd) {
328*03831d35Sstevel 
329*03831d35Sstevel 	case RMCADM_REQUEST_RESPONSE:
330*03831d35Sstevel 	case RMCADM_REQUEST_RESPONSE_BP:
331*03831d35Sstevel 
332*03831d35Sstevel 		/*
333*03831d35Sstevel 		 * first copy in the request_response structure
334*03831d35Sstevel 		 */
335*03831d35Sstevel #ifdef _MULTI_DATAMODEL
336*03831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
337*03831d35Sstevel 		case DDI_MODEL_ILP32:
338*03831d35Sstevel 		{
339*03831d35Sstevel 			/*
340*03831d35Sstevel 			 * For use when a 32 bit app makes a call into a
341*03831d35Sstevel 			 * 64 bit ioctl
342*03831d35Sstevel 			 */
343*03831d35Sstevel 			rmcadm_request_response32_t	rr32;
344*03831d35Sstevel 
345*03831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr32,
346*03831d35Sstevel 			    sizeof (rr32), mode)) {
347*03831d35Sstevel 				return (EFAULT);
348*03831d35Sstevel 			}
349*03831d35Sstevel 			rr.req.msg_type = rr32.req.msg_type;
350*03831d35Sstevel 			rr.req.msg_len = rr32.req.msg_len;
351*03831d35Sstevel 			rr.req.msg_bytes = rr32.req.msg_bytes;
352*03831d35Sstevel 			rr.req.msg_buf = (caddr_t)(uintptr_t)rr32.req.msg_buf;
353*03831d35Sstevel 			rr.resp.msg_type = rr32.resp.msg_type;
354*03831d35Sstevel 			rr.resp.msg_len = rr32.resp.msg_len;
355*03831d35Sstevel 			rr.resp.msg_bytes = rr32.resp.msg_bytes;
356*03831d35Sstevel 			rr.resp.msg_buf = (caddr_t)(uintptr_t)rr32.resp.msg_buf;
357*03831d35Sstevel 			rr.wait_time = rr32.wait_time;
358*03831d35Sstevel 			break;
359*03831d35Sstevel 		}
360*03831d35Sstevel 		case DDI_MODEL_NONE:
361*03831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
362*03831d35Sstevel 			    sizeof (rr), mode)) {
363*03831d35Sstevel 				return (EFAULT);
364*03831d35Sstevel 			}
365*03831d35Sstevel 			break;
366*03831d35Sstevel 		}
367*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */
368*03831d35Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&rr,
369*03831d35Sstevel 		    sizeof (rr), mode) != 0) {
370*03831d35Sstevel 			return (EFAULT);
371*03831d35Sstevel 		}
372*03831d35Sstevel #endif /* _MULTI_DATAMODEL */
373*03831d35Sstevel 
374*03831d35Sstevel 		/*
375*03831d35Sstevel 		 * save the user request buffer pointer
376*03831d35Sstevel 		 */
377*03831d35Sstevel 		user_req_buf = rr.req.msg_buf;
378*03831d35Sstevel 
379*03831d35Sstevel 		if (user_req_buf != NULL) {
380*03831d35Sstevel 			/*
381*03831d35Sstevel 			 * copy in the request data
382*03831d35Sstevel 			 */
383*03831d35Sstevel 			rr.req.msg_buf = kmem_alloc(rr.req.msg_len, KM_SLEEP);
384*03831d35Sstevel 
385*03831d35Sstevel 			if (ddi_copyin(user_req_buf, rr.req.msg_buf,
386*03831d35Sstevel 			    rr.req.msg_len, mode) != 0) {
387*03831d35Sstevel 
388*03831d35Sstevel 				kmem_free(rr.req.msg_buf, rr.req.msg_len);
389*03831d35Sstevel 				rr.req.msg_buf = user_req_buf;
390*03831d35Sstevel 				return (EFAULT);
391*03831d35Sstevel 			}
392*03831d35Sstevel 		} else {
393*03831d35Sstevel 			if (rr.req.msg_len > 0)
394*03831d35Sstevel 				/*
395*03831d35Sstevel 				 * msg_len should be 0 if buffer is NULL!
396*03831d35Sstevel 				 */
397*03831d35Sstevel 				return (EINVAL);
398*03831d35Sstevel 		}
399*03831d35Sstevel 
400*03831d35Sstevel 		/*
401*03831d35Sstevel 		 * save the user request buffer pointer
402*03831d35Sstevel 		 */
403*03831d35Sstevel 		user_resp_buf = rr.resp.msg_buf;
404*03831d35Sstevel 		if (user_resp_buf != NULL) {
405*03831d35Sstevel 			rr.resp.msg_buf = kmem_alloc(rr.resp.msg_len, KM_SLEEP);
406*03831d35Sstevel 		}
407*03831d35Sstevel 
408*03831d35Sstevel 		/*
409*03831d35Sstevel 		 * send the request (or BP request) via the rmc_comm driver
410*03831d35Sstevel 		 */
411*03831d35Sstevel 		rmc_reqp->msg_type = rr.req.msg_type;
412*03831d35Sstevel 		rmc_reqp->msg_buf = rr.req.msg_buf;
413*03831d35Sstevel 		rmc_reqp->msg_len = rr.req.msg_len;
414*03831d35Sstevel 		rmc_reqp->msg_bytes = rr.req.msg_bytes;
415*03831d35Sstevel 
416*03831d35Sstevel 		if (cmd == RMCADM_REQUEST_RESPONSE) {
417*03831d35Sstevel 
418*03831d35Sstevel 			/*
419*03831d35Sstevel 			 * check if response is expected. If so, fill in
420*03831d35Sstevel 			 * the response data structure
421*03831d35Sstevel 			 */
422*03831d35Sstevel 			if (rr.resp.msg_type != DP_NULL_MSG) {
423*03831d35Sstevel 
424*03831d35Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
425*03831d35Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
426*03831d35Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
427*03831d35Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
428*03831d35Sstevel 
429*03831d35Sstevel 			} else {
430*03831d35Sstevel 
431*03831d35Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
432*03831d35Sstevel 			}
433*03831d35Sstevel 
434*03831d35Sstevel 			rr.status = rmc_comm_request_response(
435*03831d35Sstevel 				    rmc_reqp, rmc_respp, rr.wait_time);
436*03831d35Sstevel 
437*03831d35Sstevel 		} else { /* RMCADM_REQUEST_RESPONSE_BP */
438*03831d35Sstevel 
439*03831d35Sstevel 			/*
440*03831d35Sstevel 			 * check if a BP message is expected back. If so,
441*03831d35Sstevel 			 * fill in the response data structure
442*03831d35Sstevel 			 */
443*03831d35Sstevel 			if (rr.resp.msg_buf != NULL) {
444*03831d35Sstevel 
445*03831d35Sstevel 				rmc_respp->msg_type = rr.resp.msg_type;
446*03831d35Sstevel 				rmc_respp->msg_buf = rr.resp.msg_buf;
447*03831d35Sstevel 				rmc_respp->msg_len = rr.resp.msg_len;
448*03831d35Sstevel 				rmc_respp->msg_bytes = rr.resp.msg_bytes;
449*03831d35Sstevel 
450*03831d35Sstevel 			} else {
451*03831d35Sstevel 
452*03831d35Sstevel 				rmc_respp = (rmc_comm_msg_t *)NULL;
453*03831d35Sstevel 			}
454*03831d35Sstevel 
455*03831d35Sstevel 			rr.status = rmc_comm_request_response_bp(
456*03831d35Sstevel 				    rmc_reqp, rmc_respp, rr.wait_time);
457*03831d35Sstevel 		}
458*03831d35Sstevel 
459*03831d35Sstevel 		/*
460*03831d35Sstevel 		 * if a response was expected, copy back the (actual) number
461*03831d35Sstevel 		 * of bytes of the response returned by the
462*03831d35Sstevel 		 * rmc_comm_request_response function (msg_bytes field)
463*03831d35Sstevel 		 */
464*03831d35Sstevel 		if (rmc_respp != NULL) {
465*03831d35Sstevel 			rr.resp.msg_bytes = rmc_respp->msg_bytes;
466*03831d35Sstevel 		}
467*03831d35Sstevel 
468*03831d35Sstevel 		if (rr.status != RCNOERR) {
469*03831d35Sstevel 
470*03831d35Sstevel 			retval = rmcadm_get_errno(rr.status);
471*03831d35Sstevel 
472*03831d35Sstevel 		} else if (user_resp_buf != NULL) {
473*03831d35Sstevel 			/*
474*03831d35Sstevel 			 * copy out the user response buffer
475*03831d35Sstevel 			 */
476*03831d35Sstevel 			if (ddi_copyout(rr.resp.msg_buf, user_resp_buf,
477*03831d35Sstevel 			    rr.resp.msg_bytes, mode) != 0) {
478*03831d35Sstevel 				retval = EFAULT;
479*03831d35Sstevel 			}
480*03831d35Sstevel 		}
481*03831d35Sstevel 
482*03831d35Sstevel 		/*
483*03831d35Sstevel 		 * now copy out the updated request_response structure
484*03831d35Sstevel 		 */
485*03831d35Sstevel 		if (rr.req.msg_buf)
486*03831d35Sstevel 			kmem_free(rr.req.msg_buf, rr.req.msg_len);
487*03831d35Sstevel 		if (rr.resp.msg_buf)
488*03831d35Sstevel 			kmem_free(rr.resp.msg_buf, rr.resp.msg_len);
489*03831d35Sstevel 
490*03831d35Sstevel 		rr.req.msg_buf = user_req_buf;
491*03831d35Sstevel 		rr.resp.msg_buf = user_resp_buf;
492*03831d35Sstevel 
493*03831d35Sstevel #ifdef _MULTI_DATAMODEL
494*03831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
495*03831d35Sstevel 		case DDI_MODEL_ILP32:
496*03831d35Sstevel 		{
497*03831d35Sstevel 			/*
498*03831d35Sstevel 			 * For use when a 32 bit app makes a call into a
499*03831d35Sstevel 			 * 64 bit ioctl
500*03831d35Sstevel 			 */
501*03831d35Sstevel 			rmcadm_request_response32_t	rr32;
502*03831d35Sstevel 
503*03831d35Sstevel 			rr32.req.msg_type = rr.req.msg_type;
504*03831d35Sstevel 			rr32.req.msg_len = rr.req.msg_len;
505*03831d35Sstevel 			rr32.req.msg_bytes = rr.req.msg_bytes;
506*03831d35Sstevel 			rr32.req.msg_buf = (caddr32_t)(uintptr_t)rr.req.msg_buf;
507*03831d35Sstevel 			rr32.resp.msg_type = rr.resp.msg_type;
508*03831d35Sstevel 			rr32.resp.msg_len = rr.resp.msg_len;
509*03831d35Sstevel 			rr32.resp.msg_bytes = rr.resp.msg_bytes;
510*03831d35Sstevel 			rr32.resp.msg_buf =
511*03831d35Sstevel 			    (caddr32_t)(uintptr_t)rr.resp.msg_buf;
512*03831d35Sstevel 			rr32.wait_time = rr.wait_time;
513*03831d35Sstevel 			rr32.status = rr.status;
514*03831d35Sstevel 			if (ddi_copyout((caddr_t)&rr32, (caddr_t)arg,
515*03831d35Sstevel 			    sizeof (rr32), mode)) {
516*03831d35Sstevel 				return (EFAULT);
517*03831d35Sstevel 			}
518*03831d35Sstevel 			break;
519*03831d35Sstevel 		}
520*03831d35Sstevel 		case DDI_MODEL_NONE:
521*03831d35Sstevel 			if (ddi_copyout((caddr_t)&rr, (caddr_t)arg,
522*03831d35Sstevel 			    sizeof (rr), mode))
523*03831d35Sstevel 				return (EFAULT);
524*03831d35Sstevel 			break;
525*03831d35Sstevel 		}
526*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */
527*03831d35Sstevel 		if (ddi_copyout((caddr_t)&rr, (caddr_t)arg, sizeof (rr),
528*03831d35Sstevel 		    mode) != 0)
529*03831d35Sstevel 			return (EFAULT);
530*03831d35Sstevel #endif /* _MULTI_DATAMODEL */
531*03831d35Sstevel 		break;
532*03831d35Sstevel 
533*03831d35Sstevel 
534*03831d35Sstevel 	case RMCADM_SEND_SRECORD_BP:
535*03831d35Sstevel 
536*03831d35Sstevel 		/*
537*03831d35Sstevel 		 * first copy in the request_response structure
538*03831d35Sstevel 		 */
539*03831d35Sstevel #ifdef _MULTI_DATAMODEL
540*03831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
541*03831d35Sstevel 		case DDI_MODEL_ILP32:
542*03831d35Sstevel 		{
543*03831d35Sstevel 			/*
544*03831d35Sstevel 			 * For use when a 32 bit app makes a call into a
545*03831d35Sstevel 			 * 64 bit ioctl
546*03831d35Sstevel 			 */
547*03831d35Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
548*03831d35Sstevel 
549*03831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp32,
550*03831d35Sstevel 			    sizeof (ssbp32), mode)) {
551*03831d35Sstevel 				return (EFAULT);
552*03831d35Sstevel 			}
553*03831d35Sstevel 			ssbp.data_len = ssbp32.data_len;
554*03831d35Sstevel 			ssbp.data_buf = (caddr_t)(uintptr_t)ssbp32.data_buf;
555*03831d35Sstevel 			ssbp.resp_bp.msg_type = ssbp32.resp_bp.msg_type;
556*03831d35Sstevel 			ssbp.resp_bp.msg_len = ssbp32.resp_bp.msg_len;
557*03831d35Sstevel 			ssbp.resp_bp.msg_bytes = ssbp32.resp_bp.msg_bytes;
558*03831d35Sstevel 			ssbp.resp_bp.msg_buf =
559*03831d35Sstevel 			    (caddr_t)(uintptr_t)ssbp32.resp_bp.msg_buf;
560*03831d35Sstevel 			ssbp.wait_time = ssbp32.wait_time;
561*03831d35Sstevel 			break;
562*03831d35Sstevel 		}
563*03831d35Sstevel 		case DDI_MODEL_NONE:
564*03831d35Sstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
565*03831d35Sstevel 			    sizeof (ssbp), mode))
566*03831d35Sstevel 				return (EFAULT);
567*03831d35Sstevel 			break;
568*03831d35Sstevel 		}
569*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */
570*03831d35Sstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp,
571*03831d35Sstevel 		    sizeof (ssbp), mode) != 0)
572*03831d35Sstevel 			return (EFAULT);
573*03831d35Sstevel #endif /* _MULTI_DATAMODEL */
574*03831d35Sstevel 
575*03831d35Sstevel 		/*
576*03831d35Sstevel 		 * save the user data buffer pointer
577*03831d35Sstevel 		 */
578*03831d35Sstevel 		user_data_buf = ssbp.data_buf;
579*03831d35Sstevel 
580*03831d35Sstevel 		if (user_data_buf != NULL) {
581*03831d35Sstevel 			/*
582*03831d35Sstevel 			 * copy in the srecord data
583*03831d35Sstevel 			 */
584*03831d35Sstevel 			ssbp.data_buf = kmem_alloc(ssbp.data_len, KM_SLEEP);
585*03831d35Sstevel 
586*03831d35Sstevel 			if (ddi_copyin(user_data_buf, ssbp.data_buf,
587*03831d35Sstevel 			    ssbp.data_len, mode) != 0) {
588*03831d35Sstevel 
589*03831d35Sstevel 				kmem_free(ssbp.data_buf, ssbp.data_len);
590*03831d35Sstevel 				ssbp.data_buf = user_data_buf;
591*03831d35Sstevel 				return (EFAULT);
592*03831d35Sstevel 			}
593*03831d35Sstevel 		} else {
594*03831d35Sstevel 			return (EINVAL);	/* request can't be NULL! */
595*03831d35Sstevel 		}
596*03831d35Sstevel 
597*03831d35Sstevel 		/*
598*03831d35Sstevel 		 * save the user request buffer pointer
599*03831d35Sstevel 		 */
600*03831d35Sstevel 		user_resp_buf = ssbp.resp_bp.msg_buf;
601*03831d35Sstevel 		if (user_resp_buf != NULL) {
602*03831d35Sstevel 			ssbp.resp_bp.msg_buf =
603*03831d35Sstevel 			    kmem_alloc(ssbp.resp_bp.msg_len, KM_SLEEP);
604*03831d35Sstevel 		} else {
605*03831d35Sstevel 
606*03831d35Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
607*03831d35Sstevel 			return (EINVAL);
608*03831d35Sstevel 		}
609*03831d35Sstevel 
610*03831d35Sstevel 		/*
611*03831d35Sstevel 		 * send the srecord via the rmc_comm driver and get the reply
612*03831d35Sstevel 		 * back (BP message)
613*03831d35Sstevel 		 */
614*03831d35Sstevel 
615*03831d35Sstevel 		rmc_respp->msg_type = ssbp.resp_bp.msg_type;
616*03831d35Sstevel 		rmc_respp->msg_buf = ssbp.resp_bp.msg_buf;
617*03831d35Sstevel 		rmc_respp->msg_len = ssbp.resp_bp.msg_len;
618*03831d35Sstevel 		rmc_respp->msg_bytes = ssbp.resp_bp.msg_bytes;
619*03831d35Sstevel 
620*03831d35Sstevel 		ssbp.status = rmc_comm_send_srecord_bp(ssbp.data_buf,
621*03831d35Sstevel 		    ssbp.data_len, rmc_respp, ssbp.wait_time);
622*03831d35Sstevel 
623*03831d35Sstevel 		/*
624*03831d35Sstevel 		 * copy back the actual size of the returned message
625*03831d35Sstevel 		 */
626*03831d35Sstevel 		ssbp.resp_bp.msg_bytes = rmc_respp->msg_bytes;
627*03831d35Sstevel 
628*03831d35Sstevel 		if (ssbp.status != RCNOERR) {
629*03831d35Sstevel 			retval = rmcadm_get_errno(ssbp.status);
630*03831d35Sstevel 
631*03831d35Sstevel 		} else if (user_resp_buf != NULL) {
632*03831d35Sstevel 			/*
633*03831d35Sstevel 			 * copy out the user BP response buffer
634*03831d35Sstevel 			 */
635*03831d35Sstevel 			if (ddi_copyout(ssbp.resp_bp.msg_buf, user_resp_buf,
636*03831d35Sstevel 			    ssbp.resp_bp.msg_bytes, mode) != 0) {
637*03831d35Sstevel 				retval = EFAULT;
638*03831d35Sstevel 			}
639*03831d35Sstevel 		}
640*03831d35Sstevel 
641*03831d35Sstevel 		/*
642*03831d35Sstevel 		 * now copy out the updated request_response structure
643*03831d35Sstevel 		 */
644*03831d35Sstevel 		if (ssbp.data_buf)
645*03831d35Sstevel 			kmem_free(ssbp.data_buf, ssbp.data_len);
646*03831d35Sstevel 		if (ssbp.resp_bp.msg_buf)
647*03831d35Sstevel 			kmem_free(ssbp.resp_bp.msg_buf, ssbp.resp_bp.msg_len);
648*03831d35Sstevel 
649*03831d35Sstevel 		ssbp.data_buf = user_data_buf;
650*03831d35Sstevel 		ssbp.resp_bp.msg_buf = user_resp_buf;
651*03831d35Sstevel 
652*03831d35Sstevel #ifdef _MULTI_DATAMODEL
653*03831d35Sstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
654*03831d35Sstevel 		case DDI_MODEL_ILP32:
655*03831d35Sstevel 		{
656*03831d35Sstevel 			/*
657*03831d35Sstevel 			 * For use when a 32 bit app makes a call into a
658*03831d35Sstevel 			 * 64 bit ioctl
659*03831d35Sstevel 			 */
660*03831d35Sstevel 			rmcadm_send_srecord_bp32_t	ssbp32;
661*03831d35Sstevel 
662*03831d35Sstevel 			ssbp32.data_len = ssbp.data_len;
663*03831d35Sstevel 			ssbp32.data_buf = (caddr32_t)(uintptr_t)ssbp.data_buf;
664*03831d35Sstevel 			ssbp32.resp_bp.msg_type = ssbp.resp_bp.msg_type;
665*03831d35Sstevel 			ssbp32.resp_bp.msg_len = ssbp.resp_bp.msg_len;
666*03831d35Sstevel 			ssbp32.resp_bp.msg_bytes = ssbp.resp_bp.msg_bytes;
667*03831d35Sstevel 			ssbp32.resp_bp.msg_buf =
668*03831d35Sstevel 			    (caddr32_t)(uintptr_t)ssbp.resp_bp.msg_buf;
669*03831d35Sstevel 			ssbp32.wait_time = ssbp.wait_time;
670*03831d35Sstevel 
671*03831d35Sstevel 			if (ddi_copyout((caddr_t)&ssbp32, (caddr_t)arg,
672*03831d35Sstevel 			    sizeof (ssbp32), mode)) {
673*03831d35Sstevel 				return (EFAULT);
674*03831d35Sstevel 			}
675*03831d35Sstevel 			break;
676*03831d35Sstevel 		}
677*03831d35Sstevel 		case DDI_MODEL_NONE:
678*03831d35Sstevel 			if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg,
679*03831d35Sstevel 			    sizeof (ssbp), mode))
680*03831d35Sstevel 				return (EFAULT);
681*03831d35Sstevel 			break;
682*03831d35Sstevel 		}
683*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */
684*03831d35Sstevel 		if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg, sizeof (ssbp),
685*03831d35Sstevel 		    mode) != 0)
686*03831d35Sstevel 			return (EFAULT);
687*03831d35Sstevel #endif /* _MULTI_DATAMODEL */
688*03831d35Sstevel 		break;
689*03831d35Sstevel 
690*03831d35Sstevel 
691*03831d35Sstevel 	case RMCADM_RESET_SP:
692*03831d35Sstevel 		pmugpio_reset();
693*03831d35Sstevel 		retval = 0;
694*03831d35Sstevel 		break;
695*03831d35Sstevel 	default:
696*03831d35Sstevel 		retval = ENOTSUP;
697*03831d35Sstevel 		break;
698*03831d35Sstevel 	}
699*03831d35Sstevel 	return (retval);
700*03831d35Sstevel }
701