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