xref: /onnv-gate/usr/src/uts/sun4u/starfire/cvc/cvc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * MT STREAMS Virtual Console Device Driver
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/sysmacros.h>
35*0Sstevel@tonic-gate #include <sys/processor.h>
36*0Sstevel@tonic-gate #include <sys/cpuvar.h>
37*0Sstevel@tonic-gate #include <sys/open.h>
38*0Sstevel@tonic-gate #include <sys/param.h>
39*0Sstevel@tonic-gate #include <sys/systm.h>
40*0Sstevel@tonic-gate #include <sys/signal.h>
41*0Sstevel@tonic-gate #include <sys/cred.h>
42*0Sstevel@tonic-gate #include <sys/user.h>
43*0Sstevel@tonic-gate #include <sys/proc.h>
44*0Sstevel@tonic-gate #include <sys/vnode.h>
45*0Sstevel@tonic-gate #include <sys/uio.h>
46*0Sstevel@tonic-gate #include <sys/buf.h>
47*0Sstevel@tonic-gate #include <sys/file.h>
48*0Sstevel@tonic-gate #include <sys/kmem.h>
49*0Sstevel@tonic-gate #include <sys/vmem.h>
50*0Sstevel@tonic-gate #include <sys/stat.h>
51*0Sstevel@tonic-gate #include <sys/stream.h>
52*0Sstevel@tonic-gate #include <sys/stropts.h>
53*0Sstevel@tonic-gate #include <sys/strsubr.h>
54*0Sstevel@tonic-gate #include <sys/strsun.h>
55*0Sstevel@tonic-gate #include <sys/tty.h>
56*0Sstevel@tonic-gate #include <sys/ptyvar.h>
57*0Sstevel@tonic-gate #include <sys/poll.h>
58*0Sstevel@tonic-gate #include <sys/debug.h>
59*0Sstevel@tonic-gate #include <sys/conf.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #include <sys/starfire.h>
62*0Sstevel@tonic-gate #include <sys/mman.h>
63*0Sstevel@tonic-gate #include <vm/seg_kmem.h>
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #include <sys/ddi.h>
66*0Sstevel@tonic-gate #include <sys/sunddi.h>
67*0Sstevel@tonic-gate #include <sys/errno.h>
68*0Sstevel@tonic-gate #include <sys/modctl.h>
69*0Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
70*0Sstevel@tonic-gate #include <sys/cvc.h>
71*0Sstevel@tonic-gate #include <sys/cpu_sgn.h>
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate extern void	prom_printf(char *fmt, ...);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static int	cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
76*0Sstevel@tonic-gate static int	cvc_attach(dev_info_t *, ddi_attach_cmd_t);
77*0Sstevel@tonic-gate static int	cvc_detach(dev_info_t *, ddi_detach_cmd_t);
78*0Sstevel@tonic-gate static int	cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
79*0Sstevel@tonic-gate static int	cvc_close(queue_t *, int, cred_t *);
80*0Sstevel@tonic-gate static int	cvc_wput(queue_t *, mblk_t *);
81*0Sstevel@tonic-gate static int	cvc_wsrv(queue_t *);
82*0Sstevel@tonic-gate static void	cvc_ioctl(queue_t *, mblk_t *);
83*0Sstevel@tonic-gate static void	cvc_ack(mblk_t *, mblk_t *, uint_t);
84*0Sstevel@tonic-gate static void	cvc_reioctl(void *);
85*0Sstevel@tonic-gate static void	cvc_input_daemon(void);
86*0Sstevel@tonic-gate static void	cvc_putc(register int);
87*0Sstevel@tonic-gate static void	cvc_flush_buf(void *);
88*0Sstevel@tonic-gate static void	cvc_bbsram_ops(volatile uchar_t *);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate static caddr_t	cvc_iobuf_mapin(processorid_t);
91*0Sstevel@tonic-gate static void	cvc_iobuf_mapout(processorid_t);
92*0Sstevel@tonic-gate 	void	cvc_assign_iocpu(processorid_t);
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate  * Private copy of devinfo pointer; cvc_info uses it.
96*0Sstevel@tonic-gate  */
97*0Sstevel@tonic-gate static dev_info_t	*cvcdip;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * This buffer is used to manage mapping in the I/O buffer that CVC
101*0Sstevel@tonic-gate  * uses when communicating with the SSP Client (netcon_server) via bbsram.
102*0Sstevel@tonic-gate  */
103*0Sstevel@tonic-gate static caddr_t	cvc_iobufp[NCPU];
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate typedef struct cvc_s {
106*0Sstevel@tonic-gate 	bufcall_id_t	cvc_wbufcid;
107*0Sstevel@tonic-gate 	tty_common_t	cvc_tty;
108*0Sstevel@tonic-gate } cvc_t;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate cvc_t	cvc_common_tty;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate static struct module_info cvcm_info = {
113*0Sstevel@tonic-gate 	1313,		/* mi_idnum Bad luck number  ;-) */
114*0Sstevel@tonic-gate 	"cvc",		/* mi_idname */
115*0Sstevel@tonic-gate 	0,		/* mi_minpsz */
116*0Sstevel@tonic-gate 	INFPSZ,		/* mi_maxpsz */
117*0Sstevel@tonic-gate 	2048,		/* mi_hiwat */
118*0Sstevel@tonic-gate 	2048		/* mi_lowat */
119*0Sstevel@tonic-gate };
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate static struct qinit cvcrinit = {
122*0Sstevel@tonic-gate 	NULL,		/* qi_putp */
123*0Sstevel@tonic-gate 	NULL,		/* qi_srvp */
124*0Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
125*0Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
126*0Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
127*0Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
128*0Sstevel@tonic-gate 	NULL		/* qi_mstat */
129*0Sstevel@tonic-gate };
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate static struct qinit cvcwinit = {
132*0Sstevel@tonic-gate 	cvc_wput,	/* qi_putp */
133*0Sstevel@tonic-gate 	cvc_wsrv,	/* qi_srvp */
134*0Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
135*0Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
136*0Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
137*0Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
138*0Sstevel@tonic-gate 	NULL		/* qi_mstat */
139*0Sstevel@tonic-gate };
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate struct streamtab	cvcinfo = {
142*0Sstevel@tonic-gate 	&cvcrinit,	/* st_rdinit */
143*0Sstevel@tonic-gate 	&cvcwinit,	/* st_wrinit */
144*0Sstevel@tonic-gate 	NULL,		/* st_muxrinit */
145*0Sstevel@tonic-gate 	NULL		/* st_muxwrinit */
146*0Sstevel@tonic-gate };
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate #define	TIMEOUT_DELAY		100000
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate #define	BBSRAM_INPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
151*0Sstevel@tonic-gate 					+ BBSRAM_INPUT_COUNT_OFF))
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate #define	BBSRAM_OUTPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
154*0Sstevel@tonic-gate 					+ BBSRAM_OUTPUT_COUNT_OFF))
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate #define	BBSRAM_INPUT_COUNT	(*((volatile short *)BBSRAM_INPUT_BUF))
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate #define	BBSRAM_OUTPUT_COUNT	(*((volatile short *)BBSRAM_OUTPUT_BUF))
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate #define	CVC_OUT_MAXSPIN	1024
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */
163*0Sstevel@tonic-gate #define	BBSRAM_CONTROL_REG	((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \
164*0Sstevel@tonic-gate 					+ CVC_IN_SIZE + CVC_OUT_SIZE))
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate static krwlock_t	cvclock;	/* lock protecting everything here */
167*0Sstevel@tonic-gate static queue_t		*cvcinput_q;	/* queue for console input */
168*0Sstevel@tonic-gate static queue_t		*cvcoutput_q;	/* queue for console output */
169*0Sstevel@tonic-gate static int		cvc_instance = -1;
170*0Sstevel@tonic-gate static int		cvc_stopped = 0;
171*0Sstevel@tonic-gate static int		cvc_suspended = 0;
172*0Sstevel@tonic-gate static int		cvc_hangup_ok = 0;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate static kthread_id_t	cvc_input_daemon_thread;
175*0Sstevel@tonic-gate static kmutex_t		cvcmutex;	/* protects input */
176*0Sstevel@tonic-gate static kmutex_t		cvc_buf_mutex;	/* protects internal output buffer */
177*0Sstevel@tonic-gate static kmutex_t		cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */
178*0Sstevel@tonic-gate static int		input_ok = 0;	/* true when stream is valid */
179*0Sstevel@tonic-gate static int		stop_bbsram = 1; /* true when BBSRAM is not usable */
180*0Sstevel@tonic-gate static int		stop_timeout = 0;
181*0Sstevel@tonic-gate static uchar_t		cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */
182*0Sstevel@tonic-gate static ushort_t		cvc_output_count = 0;
183*0Sstevel@tonic-gate static int		via_bbsram = 0; /* toggle switch */
184*0Sstevel@tonic-gate static timeout_id_t	cvc_timeout_id = (timeout_id_t)-1;
185*0Sstevel@tonic-gate static processorid_t	cvc_iocpu = -1;	/* cpu id of cpu zero */
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate /*
188*0Sstevel@tonic-gate  * Module linkage information for the kernel.
189*0Sstevel@tonic-gate  */
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
192*0Sstevel@tonic-gate 			nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo);
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate static struct modldrv modldrv = {
195*0Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
196*0Sstevel@tonic-gate 	"CVC driver 'cvc' v%I%",
197*0Sstevel@tonic-gate 	&cvcops,	/* driver ops */
198*0Sstevel@tonic-gate };
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
201*0Sstevel@tonic-gate 	MODREV_1,
202*0Sstevel@tonic-gate 	&modldrv,
203*0Sstevel@tonic-gate 	NULL
204*0Sstevel@tonic-gate };
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate int
207*0Sstevel@tonic-gate _init(void)
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	int	status;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	status = mod_install(&modlinkage);
212*0Sstevel@tonic-gate 	if (status == 0) {
213*0Sstevel@tonic-gate 		mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 	return (status);
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate int
219*0Sstevel@tonic-gate _fini(void)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate 	return (EBUSY);
222*0Sstevel@tonic-gate }
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate int
225*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  * DDI glue routines.
232*0Sstevel@tonic-gate  */
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate /* ARGSUSED */
235*0Sstevel@tonic-gate static int
236*0Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate 	static char	been_here = 0;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if (cmd == DDI_RESUME) {
241*0Sstevel@tonic-gate 		cvc_suspended = 0;
242*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
246*0Sstevel@tonic-gate 	if (!been_here) {
247*0Sstevel@tonic-gate 		been_here = 1;
248*0Sstevel@tonic-gate 		mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL);
249*0Sstevel@tonic-gate 		mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
250*0Sstevel@tonic-gate 		rw_init(&cvclock, NULL, RW_DRIVER, NULL);
251*0Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
252*0Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
253*0Sstevel@tonic-gate 			drv_usectohz(TIMEOUT_DELAY));
254*0Sstevel@tonic-gate 		rw_exit(&cvclock);
255*0Sstevel@tonic-gate 		cvc_instance = ddi_get_instance(devi);
256*0Sstevel@tonic-gate 	} else {
257*0Sstevel@tonic-gate #if defined(DEBUG)
258*0Sstevel@tonic-gate 		cmn_err(CE_NOTE,
259*0Sstevel@tonic-gate 			"cvc_attach: called multiple times!! (instance = %d)",
260*0Sstevel@tonic-gate 			ddi_get_instance(devi));
261*0Sstevel@tonic-gate #endif /* DEBUG */
262*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
267*0Sstevel@tonic-gate 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
268*0Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
269*0Sstevel@tonic-gate 		return (-1);
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 	cvcdip = devi;
272*0Sstevel@tonic-gate 	cvcinput_q = NULL;
273*0Sstevel@tonic-gate 	cvcoutput_q = NULL;
274*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate static int
278*0Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	if (cmd == DDI_SUSPEND) {
281*0Sstevel@tonic-gate 		cvc_suspended = 1;
282*0Sstevel@tonic-gate 	} else {
283*0Sstevel@tonic-gate 		if (cmd != DDI_DETACH) {
284*0Sstevel@tonic-gate 			return (DDI_FAILURE);
285*0Sstevel@tonic-gate 		}
286*0Sstevel@tonic-gate 		/*
287*0Sstevel@tonic-gate 		 * XXX this doesn't even begin to address the detach
288*0Sstevel@tonic-gate 		 * issues - it doesn't terminate the outstanding thread,
289*0Sstevel@tonic-gate 		 * it doesn't clean up mutexes, kill the timeout routine
290*0Sstevel@tonic-gate 		 * etc.
291*0Sstevel@tonic-gate 		 */
292*0Sstevel@tonic-gate 		if (cvc_instance == ddi_get_instance(dip)) {
293*0Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 	}
296*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate /* ARGSUSED */
300*0Sstevel@tonic-gate static int
301*0Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
302*0Sstevel@tonic-gate {
303*0Sstevel@tonic-gate 	register int error;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	switch (infocmd) {
306*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
307*0Sstevel@tonic-gate 		if (cvcdip == NULL) {
308*0Sstevel@tonic-gate 			error = DDI_FAILURE;
309*0Sstevel@tonic-gate 		} else {
310*0Sstevel@tonic-gate 			*result = (void *)cvcdip;
311*0Sstevel@tonic-gate 			error = DDI_SUCCESS;
312*0Sstevel@tonic-gate 		}
313*0Sstevel@tonic-gate 		break;
314*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
315*0Sstevel@tonic-gate 		*result = (void *)0;
316*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
317*0Sstevel@tonic-gate 		break;
318*0Sstevel@tonic-gate 	default:
319*0Sstevel@tonic-gate 		error = DDI_FAILURE;
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 	return (error);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate /* ARGSUSED */
325*0Sstevel@tonic-gate static int
326*0Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	register int		unit = getminor(*devp);
329*0Sstevel@tonic-gate 	register int		err = 0;
330*0Sstevel@tonic-gate 	tty_common_t		*tty;
331*0Sstevel@tonic-gate 	cvc_t			*cp;
332*0Sstevel@tonic-gate 	static int		input_daemon_started;
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	if (unit != 0)
335*0Sstevel@tonic-gate 		return (ENXIO);
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	if (q->q_ptr)
338*0Sstevel@tonic-gate 		return (0);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	cp = (cvc_t *)&cvc_common_tty;
341*0Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
342*0Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
343*0Sstevel@tonic-gate 	tty = &cp->cvc_tty;
344*0Sstevel@tonic-gate 	tty->t_readq = q;
345*0Sstevel@tonic-gate 	tty->t_writeq = WR(q);
346*0Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
347*0Sstevel@tonic-gate 	cvcinput_q = RD(q);		/* save for cvc_redir */
348*0Sstevel@tonic-gate 	qprocson(q);
349*0Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
350*0Sstevel@tonic-gate 	input_ok = 1;
351*0Sstevel@tonic-gate 	if (!input_daemon_started) {
352*0Sstevel@tonic-gate 		extern struct cpu	*SIGBCPU;	/* bugid4141050 */
353*0Sstevel@tonic-gate 		extern cpu_sgnblk_t	*cpu_sgnblkp[];
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 		input_daemon_started = 1;
356*0Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 		ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL);
359*0Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 		cvc_input_daemon_thread = thread_create(NULL, 0,
362*0Sstevel@tonic-gate 		    cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
363*0Sstevel@tonic-gate 	} else {
364*0Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate #ifdef lint
367*0Sstevel@tonic-gate 	cvc_input_daemon_thread = cvc_input_daemon_thread;
368*0Sstevel@tonic-gate #endif
369*0Sstevel@tonic-gate 	return (err);
370*0Sstevel@tonic-gate }
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate /* ARGSUSED */
373*0Sstevel@tonic-gate static int
374*0Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp)
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate 	register int		err = 0;
377*0Sstevel@tonic-gate 	register cvc_t		*cp;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
380*0Sstevel@tonic-gate 	input_ok = 0;
381*0Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	cp = q->q_ptr;
384*0Sstevel@tonic-gate 	if (cp->cvc_wbufcid != 0) {
385*0Sstevel@tonic-gate 		unbufcall(cp->cvc_wbufcid);
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 	ttycommon_close(&cp->cvc_tty);
388*0Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = NULL;
389*0Sstevel@tonic-gate 	cvcinput_q = NULL;
390*0Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
391*0Sstevel@tonic-gate 	qprocsoff(q);
392*0Sstevel@tonic-gate 	return (err);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate /*
397*0Sstevel@tonic-gate  * cvc_wput()
398*0Sstevel@tonic-gate  *	cn driver does a strwrite of console output data to rconsvp which
399*0Sstevel@tonic-gate  *	has been set by consconfig. The data enters the cvc stream at the
400*0Sstevel@tonic-gate  *	streamhead and flows thru ttycompat and ldterm which have been
401*0Sstevel@tonic-gate  *	pushed on the stream.  Console output data gets sent out either
402*0Sstevel@tonic-gate  *	by cvcredir (if there is a cvcd running) or bbsram (if there
403*0Sstevel@tonic-gate  *	isn't).
404*0Sstevel@tonic-gate  *	Data is sent to the cvcredir via it's read q which is cvcoutput_q
405*0Sstevel@tonic-gate  *	and was set in cvc_register().
406*0Sstevel@tonic-gate  */
407*0Sstevel@tonic-gate static int
408*0Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp)
409*0Sstevel@tonic-gate {
410*0Sstevel@tonic-gate 	int		error = 0;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
413*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 		case M_IOCTL:
416*0Sstevel@tonic-gate 		case M_CTL:
417*0Sstevel@tonic-gate 			cvc_ioctl(q, mp);
418*0Sstevel@tonic-gate 			break;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 		case M_FLUSH:
421*0Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW) {
422*0Sstevel@tonic-gate 				/*
423*0Sstevel@tonic-gate 				 * Flush our write queue.
424*0Sstevel@tonic-gate 				 */
425*0Sstevel@tonic-gate 				flushq(q, FLUSHDATA);
426*0Sstevel@tonic-gate 				*mp->b_rptr &= ~FLUSHW;
427*0Sstevel@tonic-gate 			}
428*0Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR) {
429*0Sstevel@tonic-gate 				flushq(RD(q), FLUSHDATA);
430*0Sstevel@tonic-gate 				qreply(q, mp);
431*0Sstevel@tonic-gate 			} else
432*0Sstevel@tonic-gate 				freemsg(mp);
433*0Sstevel@tonic-gate 			break;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		case M_STOP:
436*0Sstevel@tonic-gate 			cvc_stopped = 1;
437*0Sstevel@tonic-gate 			freemsg(mp);
438*0Sstevel@tonic-gate 			break;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 		case M_START:
441*0Sstevel@tonic-gate 			cvc_stopped = 0;
442*0Sstevel@tonic-gate 			freemsg(mp);
443*0Sstevel@tonic-gate 			qenable(q);  /* Start up delayed messages */
444*0Sstevel@tonic-gate 			break;
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 		case M_READ:
447*0Sstevel@tonic-gate 			/*
448*0Sstevel@tonic-gate 			 * ldterm handles this (VMIN/VTIME processing).
449*0Sstevel@tonic-gate 			 */
450*0Sstevel@tonic-gate 			freemsg(mp);
451*0Sstevel@tonic-gate 			break;
452*0Sstevel@tonic-gate 		default:
453*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%x", mp);
454*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_wput: type = 0x%x",
455*0Sstevel@tonic-gate 				mp->b_datap->db_type);
456*0Sstevel@tonic-gate 			/* FALLTHROUGH */
457*0Sstevel@tonic-gate #ifdef lint
458*0Sstevel@tonic-gate 			break;
459*0Sstevel@tonic-gate #endif
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 		case M_DATA:
462*0Sstevel@tonic-gate 			if (cvc_stopped == 1 || cvc_suspended == 1) {
463*0Sstevel@tonic-gate 				(void) putq(q, mp);
464*0Sstevel@tonic-gate 				break;
465*0Sstevel@tonic-gate 			}
466*0Sstevel@tonic-gate 			if (cvcoutput_q != NULL && !via_bbsram) {
467*0Sstevel@tonic-gate 				/*
468*0Sstevel@tonic-gate 				 * Send it up past cvcredir module.
469*0Sstevel@tonic-gate 				 */
470*0Sstevel@tonic-gate 				putnext(cvcoutput_q, mp);
471*0Sstevel@tonic-gate 			} else {
472*0Sstevel@tonic-gate 				char	*msgp, c;
473*0Sstevel@tonic-gate 				mblk_t	*mp2 = mp;
474*0Sstevel@tonic-gate 				int count;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 				while (mp2 != NULL) {
477*0Sstevel@tonic-gate 					count = mp2->b_wptr - mp2->b_rptr;
478*0Sstevel@tonic-gate 					msgp = (char *)mp2->b_rptr;
479*0Sstevel@tonic-gate 					while (count > 0) {
480*0Sstevel@tonic-gate 						count--;
481*0Sstevel@tonic-gate 						if ((c = *msgp++) != '\0') {
482*0Sstevel@tonic-gate 							/* don't print NULs */
483*0Sstevel@tonic-gate 							cvc_putc(c);
484*0Sstevel@tonic-gate 						}
485*0Sstevel@tonic-gate 					}
486*0Sstevel@tonic-gate 					mp2 = mp2->b_cont;
487*0Sstevel@tonic-gate 				}
488*0Sstevel@tonic-gate 				freemsg(mp);
489*0Sstevel@tonic-gate 			}
490*0Sstevel@tonic-gate 			break;
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate 	rw_exit(&cvclock);
494*0Sstevel@tonic-gate 	return (error);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate static int cvc_wsrv_count = 0;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate static int
500*0Sstevel@tonic-gate cvc_wsrv(queue_t *q)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	register mblk_t *mp;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	cvc_wsrv_count++;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	if (cvc_stopped == 1 || cvc_suspended == 1) {
507*0Sstevel@tonic-gate 		return (0);
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
511*0Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
512*0Sstevel@tonic-gate 		if (cvcoutput_q != NULL && !via_bbsram) {
513*0Sstevel@tonic-gate 			/*
514*0Sstevel@tonic-gate 			 * Send it up past cvcredir module.
515*0Sstevel@tonic-gate 			 */
516*0Sstevel@tonic-gate 			putnext(cvcoutput_q, mp);
517*0Sstevel@tonic-gate 		} else {
518*0Sstevel@tonic-gate 			char    *msgp, c;
519*0Sstevel@tonic-gate 			mblk_t  *mp2 = mp;
520*0Sstevel@tonic-gate 			int count;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 			while (mp2 != NULL) {
523*0Sstevel@tonic-gate 				count = mp2->b_wptr - mp2->b_rptr;
524*0Sstevel@tonic-gate 				msgp = (char *)mp2->b_rptr;
525*0Sstevel@tonic-gate 				while (count > 0) {
526*0Sstevel@tonic-gate 					count--;
527*0Sstevel@tonic-gate 					if ((c = *msgp++) != '\0') {
528*0Sstevel@tonic-gate 						/* don't print NULs */
529*0Sstevel@tonic-gate 						cvc_putc(c);
530*0Sstevel@tonic-gate 					}
531*0Sstevel@tonic-gate 				}
532*0Sstevel@tonic-gate 				mp2 = mp2->b_cont;
533*0Sstevel@tonic-gate 			}
534*0Sstevel@tonic-gate 			freemsg(mp);
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 	rw_exit(&cvclock);
538*0Sstevel@tonic-gate 	return (0);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate  * cvc_ioctl()
544*0Sstevel@tonic-gate  *	handle normal console ioctls.
545*0Sstevel@tonic-gate  */
546*0Sstevel@tonic-gate static void
547*0Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp)
548*0Sstevel@tonic-gate {
549*0Sstevel@tonic-gate 	register struct iocblk		*iocp;
550*0Sstevel@tonic-gate 	register tty_common_t		*tty;
551*0Sstevel@tonic-gate 	register cvc_t			*cp;
552*0Sstevel@tonic-gate 	int				datasize;
553*0Sstevel@tonic-gate 	int				error = 0;
554*0Sstevel@tonic-gate 	mblk_t				*tmp;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	cp = q->q_ptr;
557*0Sstevel@tonic-gate 	tty = &cp->cvc_tty;
558*0Sstevel@tonic-gate 	if (tty->t_iocpending != NULL) {
559*0Sstevel@tonic-gate 		freemsg(tty->t_iocpending);
560*0Sstevel@tonic-gate 		tty->t_iocpending = NULL;
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 	datasize = ttycommon_ioctl(tty, q, mp, &error);
563*0Sstevel@tonic-gate 	if (datasize != 0) {
564*0Sstevel@tonic-gate 		if (cp->cvc_wbufcid)
565*0Sstevel@tonic-gate 			unbufcall(cp->cvc_wbufcid);
566*0Sstevel@tonic-gate 		cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
567*0Sstevel@tonic-gate 		return;
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 	if (error < 0) {
570*0Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
571*0Sstevel@tonic-gate 		/*
572*0Sstevel@tonic-gate 		 * "ttycommon_ioctl" didn't do anything; we process it here.
573*0Sstevel@tonic-gate 		 */
574*0Sstevel@tonic-gate 		error = 0;
575*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 		/*
578*0Sstevel@tonic-gate 		 *  Set modem bit ioctls.  These are NOPs for us, since we
579*0Sstevel@tonic-gate 		 * dont control any hardware.
580*0Sstevel@tonic-gate 		 */
581*0Sstevel@tonic-gate 		case TCSBRK:
582*0Sstevel@tonic-gate 		case TIOCSBRK:
583*0Sstevel@tonic-gate 		case TIOCCBRK:
584*0Sstevel@tonic-gate 		case TIOCMSET:
585*0Sstevel@tonic-gate 		case TIOCMBIS:
586*0Sstevel@tonic-gate 		case TIOCMBIC:
587*0Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT) {
588*0Sstevel@tonic-gate 				mioc2ack(mp, NULL, 0, 0);
589*0Sstevel@tonic-gate 			} else {
590*0Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (int), NULL);
591*0Sstevel@tonic-gate 			}
592*0Sstevel@tonic-gate 			/* qreply done below */
593*0Sstevel@tonic-gate 			break;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 		/*
596*0Sstevel@tonic-gate 		 *  Get modem bits, we return 0 in mblk.
597*0Sstevel@tonic-gate 		 */
598*0Sstevel@tonic-gate 		case TIOCMGET:
599*0Sstevel@tonic-gate 			tmp = allocb(sizeof (int), BPRI_MED);
600*0Sstevel@tonic-gate 			if (tmp == NULL) {
601*0Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
602*0Sstevel@tonic-gate 				return;
603*0Sstevel@tonic-gate 			}
604*0Sstevel@tonic-gate 			*(int *)tmp->b_rptr = 0;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT)
607*0Sstevel@tonic-gate 				mioc2ack(mp, tmp, sizeof (int), 0);
608*0Sstevel@tonic-gate 			else
609*0Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (int), NULL, tmp);
610*0Sstevel@tonic-gate 			/* qreply done below */
611*0Sstevel@tonic-gate 			break;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 		default:
614*0Sstevel@tonic-gate 			/*
615*0Sstevel@tonic-gate 			 * If we don't understand it, it's an error. NAK it.
616*0Sstevel@tonic-gate 			 */
617*0Sstevel@tonic-gate 			error = EINVAL;
618*0Sstevel@tonic-gate 			break;
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate 	if (error != 0) {
622*0Sstevel@tonic-gate 		iocp->ioc_error = error;
623*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
624*0Sstevel@tonic-gate 	}
625*0Sstevel@tonic-gate 	qreply(q, mp);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate }
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate /*
631*0Sstevel@tonic-gate  * cvc_redir()
632*0Sstevel@tonic-gate  *	called from cvcredir:cvcr_wput() to handle console input
633*0Sstevel@tonic-gate  *	data. This routine puts the cvcredir write (downstream) data
634*0Sstevel@tonic-gate  *	onto the cvc read (upstream) queues.  Note that if `mp' is
635*0Sstevel@tonic-gate  *	an M_IOCTL, then it may be reused by the caller to send back
636*0Sstevel@tonic-gate  *	an M_IOCACK or M_IOCNAK.
637*0Sstevel@tonic-gate  */
638*0Sstevel@tonic-gate int
639*0Sstevel@tonic-gate cvc_redir(mblk_t *mp)
640*0Sstevel@tonic-gate {
641*0Sstevel@tonic-gate 	register struct iocblk	*iocp;
642*0Sstevel@tonic-gate 	register tty_common_t	*tty;
643*0Sstevel@tonic-gate 	register cvc_t		*cp;
644*0Sstevel@tonic-gate 	struct winsize		*ws;
645*0Sstevel@tonic-gate 	int			error;
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	if (cvcinput_q == NULL) {
648*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
649*0Sstevel@tonic-gate 		return (EINVAL);
650*0Sstevel@tonic-gate 	}
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_IOCTL) {
653*0Sstevel@tonic-gate 		putnext(cvcinput_q, mp);
654*0Sstevel@tonic-gate 		return (0);
655*0Sstevel@tonic-gate 	}
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
658*0Sstevel@tonic-gate 	if (iocp->ioc_cmd == TIOCSWINSZ) {
659*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct winsize));
660*0Sstevel@tonic-gate 		if (error != 0)
661*0Sstevel@tonic-gate 			return (error);
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 		ws = (struct winsize *)mp->b_cont->b_rptr;
664*0Sstevel@tonic-gate 		cp = cvcinput_q->q_ptr;
665*0Sstevel@tonic-gate 		tty = &cp->cvc_tty;
666*0Sstevel@tonic-gate 		mutex_enter(&tty->t_excl);
667*0Sstevel@tonic-gate 		if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) {
668*0Sstevel@tonic-gate 			tty->t_size = *ws;
669*0Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
670*0Sstevel@tonic-gate 			(void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH);
671*0Sstevel@tonic-gate 		} else
672*0Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
673*0Sstevel@tonic-gate 	} else {
674*0Sstevel@tonic-gate 		/*
675*0Sstevel@tonic-gate 		 * It must be a CVC_DISCONNECT, send hangup.
676*0Sstevel@tonic-gate 		 */
677*0Sstevel@tonic-gate 		ASSERT(iocp->ioc_cmd == CVC_DISCONNECT);
678*0Sstevel@tonic-gate 		if (cvc_hangup_ok)
679*0Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
680*0Sstevel@tonic-gate 	}
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	return (0);
683*0Sstevel@tonic-gate }
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate /*
687*0Sstevel@tonic-gate  * cvc_register()
688*0Sstevel@tonic-gate  *	called from cvcredir to register it's queues.  cvc
689*0Sstevel@tonic-gate  *	receives data from cn via the streamhead and sends it to cvcredir
690*0Sstevel@tonic-gate  *	via pointers to cvcredir's queues.
691*0Sstevel@tonic-gate  */
692*0Sstevel@tonic-gate int
693*0Sstevel@tonic-gate cvc_register(queue_t *q)
694*0Sstevel@tonic-gate {
695*0Sstevel@tonic-gate 	int error = -1;
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	if (cvcinput_q == NULL)
698*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
699*0Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
700*0Sstevel@tonic-gate 	if (cvcoutput_q == NULL) {
701*0Sstevel@tonic-gate 		cvcoutput_q = RD(q);  /* Make sure its the upstream q */
702*0Sstevel@tonic-gate 		qprocson(cvcoutput_q);	/* must be done within cvclock */
703*0Sstevel@tonic-gate 		error = 0;
704*0Sstevel@tonic-gate 	} else {
705*0Sstevel@tonic-gate 		/*
706*0Sstevel@tonic-gate 		 * cmn_err will call us, so release lock.
707*0Sstevel@tonic-gate 		 */
708*0Sstevel@tonic-gate 		rw_exit(&cvclock);
709*0Sstevel@tonic-gate 		if (cvcoutput_q == q)
710*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_register: duplicate q!");
711*0Sstevel@tonic-gate 		else
712*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_register: nondup q = 0x%x",
713*0Sstevel@tonic-gate 				q);
714*0Sstevel@tonic-gate 		return (error);
715*0Sstevel@tonic-gate 	}
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	/*
718*0Sstevel@tonic-gate 	 * Unless "via_bbsram" is set, i/o will be going through cvcd, so
719*0Sstevel@tonic-gate 	 * stop flushing output to BBSRAM.
720*0Sstevel@tonic-gate 	 */
721*0Sstevel@tonic-gate 	if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) {
722*0Sstevel@tonic-gate 		stop_timeout = 1;
723*0Sstevel@tonic-gate 		(void) untimeout(cvc_timeout_id);
724*0Sstevel@tonic-gate 		cvc_timeout_id = (timeout_id_t)-1;
725*0Sstevel@tonic-gate 		cvc_hangup_ok = 1;
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 	rw_exit(&cvclock);
728*0Sstevel@tonic-gate 	return (error);
729*0Sstevel@tonic-gate }
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate /*
733*0Sstevel@tonic-gate  * cvc_unregister()
734*0Sstevel@tonic-gate  *	called from cvcredir to clear pointers to its queues.
735*0Sstevel@tonic-gate  *	cvcredir no longer wants to send or receive data.
736*0Sstevel@tonic-gate  */
737*0Sstevel@tonic-gate void
738*0Sstevel@tonic-gate cvc_unregister(queue_t *q)
739*0Sstevel@tonic-gate {
740*0Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
741*0Sstevel@tonic-gate 	if (q == cvcoutput_q) {
742*0Sstevel@tonic-gate 		qprocsoff(cvcoutput_q);	/* must be done within cvclock */
743*0Sstevel@tonic-gate 		cvcoutput_q = NULL;
744*0Sstevel@tonic-gate 	} else {
745*0Sstevel@tonic-gate 		rw_exit(&cvclock);
746*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_unregister: q = 0x%x not registered", q);
747*0Sstevel@tonic-gate 		return;
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	/*
751*0Sstevel@tonic-gate 	 * i/o will not be going through cvcd, start flushing output to
752*0Sstevel@tonic-gate 	 * BBSRAM
753*0Sstevel@tonic-gate 	 */
754*0Sstevel@tonic-gate 	if (cvc_timeout_id == (timeout_id_t)-1) {
755*0Sstevel@tonic-gate 		stop_timeout = 0;
756*0Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
757*0Sstevel@tonic-gate 			drv_usectohz(TIMEOUT_DELAY));
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 	rw_exit(&cvclock);
760*0Sstevel@tonic-gate }
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate /*
763*0Sstevel@tonic-gate  * cvc_reioctl()
764*0Sstevel@tonic-gate  *	Retry an "ioctl", now that "bufcall" claims we may be able
765*0Sstevel@tonic-gate  *	to allocate the buffer we need.
766*0Sstevel@tonic-gate  */
767*0Sstevel@tonic-gate static void
768*0Sstevel@tonic-gate cvc_reioctl(void *unit)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	register queue_t	*q;
771*0Sstevel@tonic-gate 	register mblk_t		*mp;
772*0Sstevel@tonic-gate 	register cvc_t		*cp = (cvc_t *)unit;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	/*
775*0Sstevel@tonic-gate 	 * The bufcall is no longer pending.
776*0Sstevel@tonic-gate 	 */
777*0Sstevel@tonic-gate 	if (!cp->cvc_wbufcid) {
778*0Sstevel@tonic-gate 		return;
779*0Sstevel@tonic-gate 	}
780*0Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
781*0Sstevel@tonic-gate 	if ((q = cp->cvc_tty.t_writeq) == NULL) {
782*0Sstevel@tonic-gate 		return;
783*0Sstevel@tonic-gate 	}
784*0Sstevel@tonic-gate 	if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
785*0Sstevel@tonic-gate 		/* not pending any more */
786*0Sstevel@tonic-gate 		cp->cvc_tty.t_iocpending = NULL;
787*0Sstevel@tonic-gate 		cvc_ioctl(q, mp);
788*0Sstevel@tonic-gate 	}
789*0Sstevel@tonic-gate }
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate /*
793*0Sstevel@tonic-gate  * cvc_bbsram_ops()
794*0Sstevel@tonic-gate  *	Process commands sent to cvc from netcon_server via BBSRAM
795*0Sstevel@tonic-gate  */
796*0Sstevel@tonic-gate static void
797*0Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg)
798*0Sstevel@tonic-gate {
799*0Sstevel@tonic-gate 	uchar_t	 op;
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	if ((op = *op_reg) == 0)
802*0Sstevel@tonic-gate 		return;
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex));
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	switch (op) {
807*0Sstevel@tonic-gate 	case CVC_BBSRAM_BREAK:		/* A console break (L1-A) */
808*0Sstevel@tonic-gate 		abort_sequence_enter((char *)NULL);
809*0Sstevel@tonic-gate 		break;
810*0Sstevel@tonic-gate 	case CVC_BBSRAM_DISCONNECT:	/* Break connection, hang up */
811*0Sstevel@tonic-gate 		if (cvcinput_q && cvc_hangup_ok)
812*0Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
813*0Sstevel@tonic-gate 		break;
814*0Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_NET:	/* console via network */
815*0Sstevel@tonic-gate 		via_bbsram = 0;
816*0Sstevel@tonic-gate 		/*
817*0Sstevel@tonic-gate 		 * stop periodic flushing of output to BBSRAM
818*0Sstevel@tonic-gate 		 * only if cvcredir/cvcd are present
819*0Sstevel@tonic-gate 		 */
820*0Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
821*0Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
822*0Sstevel@tonic-gate 			stop_timeout = 1;
823*0Sstevel@tonic-gate 			if (cvc_timeout_id != (timeout_id_t)-1) {
824*0Sstevel@tonic-gate 				(void) untimeout(cvc_timeout_id);
825*0Sstevel@tonic-gate 				cvc_timeout_id = (timeout_id_t)-1;
826*0Sstevel@tonic-gate 			}
827*0Sstevel@tonic-gate 		}
828*0Sstevel@tonic-gate 		rw_exit(&cvclock);
829*0Sstevel@tonic-gate 		break;
830*0Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_BBSRAM:	/* console via bbsram */
831*0Sstevel@tonic-gate 		via_bbsram = 1;
832*0Sstevel@tonic-gate 		/* start periodic flushing of ouput to BBSRAM */
833*0Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
834*0Sstevel@tonic-gate 		if (cvc_timeout_id == (timeout_id_t)-1) {
835*0Sstevel@tonic-gate 			stop_timeout = 0;
836*0Sstevel@tonic-gate 			cvc_timeout_id = timeout(cvc_flush_buf,
837*0Sstevel@tonic-gate 			    NULL, drv_usectohz(TIMEOUT_DELAY));
838*0Sstevel@tonic-gate 		}
839*0Sstevel@tonic-gate 		rw_exit(&cvclock);
840*0Sstevel@tonic-gate 		break;
841*0Sstevel@tonic-gate 	case CVC_BBSRAM_CLOSE_NET:
842*0Sstevel@tonic-gate 		/*
843*0Sstevel@tonic-gate 		 * Send a hangup control message upstream to cvcd
844*0Sstevel@tonic-gate 		 * thru cvcredir.  This is an attempt to close
845*0Sstevel@tonic-gate 		 * out any existing network connection(if any).
846*0Sstevel@tonic-gate 		 * cvcoutput_q should point to the cvcredir's read
847*0Sstevel@tonic-gate 		 * queue.
848*0Sstevel@tonic-gate 		 */
849*0Sstevel@tonic-gate 		rw_enter(&cvclock, RW_READER);
850*0Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
851*0Sstevel@tonic-gate 			(void) putnextctl(cvcoutput_q, M_HANGUP);
852*0Sstevel@tonic-gate 		}
853*0Sstevel@tonic-gate 		rw_exit(&cvclock);
854*0Sstevel@tonic-gate 		break;
855*0Sstevel@tonic-gate 	default:
856*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n",
857*0Sstevel@tonic-gate 			(unsigned int)op);
858*0Sstevel@tonic-gate 		break;
859*0Sstevel@tonic-gate 	}
860*0Sstevel@tonic-gate 	*op_reg = 0;
861*0Sstevel@tonic-gate }
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate /*
865*0Sstevel@tonic-gate  * cvc_putc()
866*0Sstevel@tonic-gate  *	Put a single character out to BBSRAM if space available.
867*0Sstevel@tonic-gate  */
868*0Sstevel@tonic-gate static void
869*0Sstevel@tonic-gate cvc_putc(register int c)
870*0Sstevel@tonic-gate {
871*0Sstevel@tonic-gate 	static int	output_lost = 0;
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 	if (c == '\n')
874*0Sstevel@tonic-gate 		cvc_putc('\r');
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
877*0Sstevel@tonic-gate 	/*
878*0Sstevel@tonic-gate 	 * Just exit if the buffer is already full.
879*0Sstevel@tonic-gate 	 * It will be up to cvc_flush_buf() to flush the buffer.
880*0Sstevel@tonic-gate 	 */
881*0Sstevel@tonic-gate 	if (cvc_output_count == MAX_XFER_OUTPUT) {
882*0Sstevel@tonic-gate 		output_lost = 1;
883*0Sstevel@tonic-gate 		mutex_exit(&cvc_buf_mutex);
884*0Sstevel@tonic-gate 		return;
885*0Sstevel@tonic-gate 	}
886*0Sstevel@tonic-gate 	if (output_lost)
887*0Sstevel@tonic-gate 		prom_printf("WARNING: overflow of cvc output buffer, "
888*0Sstevel@tonic-gate 		    "output lost!");
889*0Sstevel@tonic-gate 	output_lost = 0;
890*0Sstevel@tonic-gate 	cvc_output_buffer[cvc_output_count] = (unsigned char)c;
891*0Sstevel@tonic-gate 	cvc_output_count++;
892*0Sstevel@tonic-gate 	if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) {
893*0Sstevel@tonic-gate 		/* flush cvc's internal output buffer to BBSRAM */
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 		/*
896*0Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
897*0Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP
898*0Sstevel@tonic-gate 		 */
899*0Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
900*0Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
901*0Sstevel@tonic-gate 			if (stop_bbsram) {
902*0Sstevel@tonic-gate 				mutex_exit(&cvc_buf_mutex);
903*0Sstevel@tonic-gate 				return;
904*0Sstevel@tonic-gate 			}
905*0Sstevel@tonic-gate 			DELAY(1000);
906*0Sstevel@tonic-gate 		}
907*0Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
908*0Sstevel@tonic-gate 			(caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count),
909*0Sstevel@tonic-gate 			cvc_output_count);
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
912*0Sstevel@tonic-gate 		cvc_output_count = 0;
913*0Sstevel@tonic-gate 	}
914*0Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
915*0Sstevel@tonic-gate }
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate /*
919*0Sstevel@tonic-gate  * cvc_flush_buf()
920*0Sstevel@tonic-gate  *	Flush cvc's internal output buffer to BBSRAM at regular intervals.
921*0Sstevel@tonic-gate  *	This should only be done if cvcd is not running or the user (via the cvc
922*0Sstevel@tonic-gate  *	application on the SSP) has requested that i/o go through BBSRAM.
923*0Sstevel@tonic-gate  */
924*0Sstevel@tonic-gate /* ARGSUSED */
925*0Sstevel@tonic-gate static void
926*0Sstevel@tonic-gate cvc_flush_buf(void *notused)
927*0Sstevel@tonic-gate {
928*0Sstevel@tonic-gate 	if (stop_timeout)
929*0Sstevel@tonic-gate 		return;
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
932*0Sstevel@tonic-gate 	if (cvc_output_count != 0) {
933*0Sstevel@tonic-gate 		/*
934*0Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
935*0Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP.
936*0Sstevel@tonic-gate 		 */
937*0Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
938*0Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
939*0Sstevel@tonic-gate 			if (stop_bbsram)
940*0Sstevel@tonic-gate 				goto exit;
941*0Sstevel@tonic-gate 			DELAY(1000);
942*0Sstevel@tonic-gate 		}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
945*0Sstevel@tonic-gate 			(caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count,
946*0Sstevel@tonic-gate 			cvc_output_count);
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
949*0Sstevel@tonic-gate 		cvc_output_count = 0;
950*0Sstevel@tonic-gate 	}
951*0Sstevel@tonic-gate exit:
952*0Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
953*0Sstevel@tonic-gate 	/* rw_enter(&cvclock, RW_WRITER); */
954*0Sstevel@tonic-gate 	cvc_timeout_id = timeout(cvc_flush_buf, NULL,
955*0Sstevel@tonic-gate 		drv_usectohz(TIMEOUT_DELAY));
956*0Sstevel@tonic-gate 	/* rw_exit(&cvclock); */
957*0Sstevel@tonic-gate }
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate /*
961*0Sstevel@tonic-gate  * cvc_getstr()
962*0Sstevel@tonic-gate  *	Poll BBSRAM for console input while available.
963*0Sstevel@tonic-gate  */
964*0Sstevel@tonic-gate static void
965*0Sstevel@tonic-gate cvc_getstr(char *cp)
966*0Sstevel@tonic-gate {
967*0Sstevel@tonic-gate 	short		count;
968*0Sstevel@tonic-gate 	volatile char	*lp;
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
971*0Sstevel@tonic-gate 	/* Poll BBSRAM for input */
972*0Sstevel@tonic-gate 	do {
973*0Sstevel@tonic-gate 		if (stop_bbsram) {
974*0Sstevel@tonic-gate 			*cp = '\0';	/* set string to zero-length */
975*0Sstevel@tonic-gate 			mutex_exit(&cvc_bbsram_input_mutex);
976*0Sstevel@tonic-gate 			return;
977*0Sstevel@tonic-gate 		}
978*0Sstevel@tonic-gate 		/*
979*0Sstevel@tonic-gate 		 * Use a smaller delay between checks of BBSRAM for input
980*0Sstevel@tonic-gate 		 * when cvcd/cvcredir are not running or "via_bbsram" has
981*0Sstevel@tonic-gate 		 * been set.
982*0Sstevel@tonic-gate 		 * We don't go away completely when i/o is going through the
983*0Sstevel@tonic-gate 		 * network via cvcd since a command may be sent via BBSRAM
984*0Sstevel@tonic-gate 		 * to switch if the network is down or hung.
985*0Sstevel@tonic-gate 		 */
986*0Sstevel@tonic-gate 		if ((cvcoutput_q == NULL) || (via_bbsram))
987*0Sstevel@tonic-gate 			delay(drv_usectohz(100000));
988*0Sstevel@tonic-gate 		else
989*0Sstevel@tonic-gate 			delay(drv_usectohz(1000000));
990*0Sstevel@tonic-gate 		cvc_bbsram_ops(BBSRAM_CONTROL_REG);
991*0Sstevel@tonic-gate 		count = BBSRAM_INPUT_COUNT;
992*0Sstevel@tonic-gate 	} while (count == 0);
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	lp = BBSRAM_INPUT_BUF - count;
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	while (count--) {
997*0Sstevel@tonic-gate 		*cp++ = *lp++;
998*0Sstevel@tonic-gate 	}
999*0Sstevel@tonic-gate 	*cp = '\0';
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 	BBSRAM_INPUT_COUNT = 0;
1002*0Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
1003*0Sstevel@tonic-gate }
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate /*
1007*0Sstevel@tonic-gate  * cvc_input_daemon()
1008*0Sstevel@tonic-gate  *	this function runs as a separate kernel thread and polls BBSRAM for
1009*0Sstevel@tonic-gate  *	input, and possibly put it on read stream for the console.
1010*0Sstevel@tonic-gate  *	There are two poll rates (implemented in cvc_getstr):
1011*0Sstevel@tonic-gate  *		 100 000 uS (10 Hz) - no cvcd communications || via_bbsram
1012*0Sstevel@tonic-gate  *		1000 000 uS ( 1 Hz) - cvcd communications
1013*0Sstevel@tonic-gate  * 	This continues to run even if there are network console communications
1014*0Sstevel@tonic-gate  *	in order to handle out-of-band signaling.
1015*0Sstevel@tonic-gate  */
1016*0Sstevel@tonic-gate static void
1017*0Sstevel@tonic-gate cvc_input_daemon(void)
1018*0Sstevel@tonic-gate {
1019*0Sstevel@tonic-gate 	char		linebuf[MAX_XFER_INPUT];
1020*0Sstevel@tonic-gate 	char		*cp;
1021*0Sstevel@tonic-gate 	mblk_t		*mbp;
1022*0Sstevel@tonic-gate 	int		c;
1023*0Sstevel@tonic-gate 	int		dropped_read = 0;
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	for (;;) {
1026*0Sstevel@tonic-gate 		cvc_getstr(linebuf);
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 		mbp = allocb(strlen(linebuf), BPRI_MED);
1029*0Sstevel@tonic-gate 		if (mbp == NULL) {	/* drop it & go on if no buffer */
1030*0Sstevel@tonic-gate 			if (!dropped_read) {
1031*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
1032*0Sstevel@tonic-gate 				    "cvc_input_daemon: "
1033*0Sstevel@tonic-gate 				    "dropping BBSRAM reads\n");
1034*0Sstevel@tonic-gate 			}
1035*0Sstevel@tonic-gate 			dropped_read++;
1036*0Sstevel@tonic-gate 			continue;
1037*0Sstevel@tonic-gate 		}
1038*0Sstevel@tonic-gate 		if (dropped_read) {
1039*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
1040*0Sstevel@tonic-gate 			    "cvc_input_daemon: dropped %d BBSRAM reads\n",
1041*0Sstevel@tonic-gate 			    dropped_read);
1042*0Sstevel@tonic-gate 			dropped_read = 0;
1043*0Sstevel@tonic-gate 		}
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 		for (cp = linebuf; *cp != '\0'; cp++) {
1046*0Sstevel@tonic-gate 			c = (int)*cp;
1047*0Sstevel@tonic-gate 			if (c == '\r')
1048*0Sstevel@tonic-gate 				c = '\n';
1049*0Sstevel@tonic-gate 			c &= 0177;
1050*0Sstevel@tonic-gate 			*mbp->b_wptr = (char)c;
1051*0Sstevel@tonic-gate 			mbp->b_wptr++;
1052*0Sstevel@tonic-gate 		}
1053*0Sstevel@tonic-gate 		mutex_enter(&cvcmutex);
1054*0Sstevel@tonic-gate 		if (input_ok) {
1055*0Sstevel@tonic-gate 			if (cvcinput_q == NULL) {
1056*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
1057*0Sstevel@tonic-gate 				    "cvc_input_daemon: cvcinput_q is NULL!");
1058*0Sstevel@tonic-gate 			} else {
1059*0Sstevel@tonic-gate 				putnext(cvcinput_q, mbp);
1060*0Sstevel@tonic-gate 			}
1061*0Sstevel@tonic-gate 		} else {
1062*0Sstevel@tonic-gate 			freemsg(mbp);
1063*0Sstevel@tonic-gate 		}
1064*0Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	/* NOTREACHED */
1068*0Sstevel@tonic-gate }
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate /*
1072*0Sstevel@tonic-gate  * cvc_bbsram_stop()
1073*0Sstevel@tonic-gate  *	Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when
1074*0Sstevel@tonic-gate  *	mapping in BBSRAM to a virtual address.
1075*0Sstevel@tonic-gate  */
1076*0Sstevel@tonic-gate static void
1077*0Sstevel@tonic-gate cvc_bbsram_stop(void)
1078*0Sstevel@tonic-gate {
1079*0Sstevel@tonic-gate 	stop_bbsram = 1;
1080*0Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
1081*0Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
1082*0Sstevel@tonic-gate }
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate /*
1086*0Sstevel@tonic-gate  * cvc_bbsram_start()
1087*0Sstevel@tonic-gate  *	Allow accesses to BBSRAM, used by cvc_assign_iocpu() after
1088*0Sstevel@tonic-gate  *	BBSRAM has been mapped to a virtual address.
1089*0Sstevel@tonic-gate  */
1090*0Sstevel@tonic-gate static void
1091*0Sstevel@tonic-gate cvc_bbsram_start(void)
1092*0Sstevel@tonic-gate {
1093*0Sstevel@tonic-gate 	stop_bbsram = 0;
1094*0Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
1095*0Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
1096*0Sstevel@tonic-gate }
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate /*
1100*0Sstevel@tonic-gate  * cvc_assign_iocpu()
1101*0Sstevel@tonic-gate  *	Map in BBSRAM to a virtual address
1102*0Sstevel@tonic-gate  *	This called by the kernel with the cpu id of cpu zero.
1103*0Sstevel@tonic-gate  */
1104*0Sstevel@tonic-gate void
1105*0Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu)
1106*0Sstevel@tonic-gate {
1107*0Sstevel@tonic-gate 	processorid_t	oldcpu = cvc_iocpu;
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	if (newcpu == oldcpu)
1110*0Sstevel@tonic-gate 		return;
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu);
1113*0Sstevel@tonic-gate 
1114*0Sstevel@tonic-gate 	cvc_bbsram_stop();
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 	cvc_iocpu = newcpu;
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 	cvc_bbsram_start();
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 	if (oldcpu != -1)
1121*0Sstevel@tonic-gate 		cvc_iobuf_mapout(oldcpu);
1122*0Sstevel@tonic-gate }
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate /*
1126*0Sstevel@tonic-gate  * cvc_iobuf_mapin()
1127*0Sstevel@tonic-gate  *	Map in the cvc bbsram i/o buffer into kernel space.
1128*0Sstevel@tonic-gate  */
1129*0Sstevel@tonic-gate static caddr_t
1130*0Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id)
1131*0Sstevel@tonic-gate {
1132*0Sstevel@tonic-gate 	caddr_t	cvaddr;
1133*0Sstevel@tonic-gate 	uint64_t cvc_iobuf_physaddr;
1134*0Sstevel@tonic-gate 	pfn_t pfn;
1135*0Sstevel@tonic-gate 	uint_t num_pages;
1136*0Sstevel@tonic-gate 	extern cpu_sgnblk_t *cpu_sgnblkp[];
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	ASSERT(cpu_sgnblkp[cpu_id] != NULL);
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 	/*
1141*0Sstevel@tonic-gate 	 * First construct the physical base address of the bbsram
1142*0Sstevel@tonic-gate 	 * in Starfire PSI space associated with this cpu in question.
1143*0Sstevel@tonic-gate 	 */
1144*0Sstevel@tonic-gate 	cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE;
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	/*
1147*0Sstevel@tonic-gate 	 * Next add the cvc i/o buffer offset obtained from the
1148*0Sstevel@tonic-gate 	 * sigblock to get cvc iobuf physical address
1149*0Sstevel@tonic-gate 	 */
1150*0Sstevel@tonic-gate 	cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off;
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	/* Get the page frame number */
1153*0Sstevel@tonic-gate 	pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT);
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 	/* Calculate how many pages we need to map in */
1156*0Sstevel@tonic-gate 	num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr
1157*0Sstevel@tonic-gate 		& MMU_PAGEOFFSET) + sizeof (sigb_cvc_t)));
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 	/*
1160*0Sstevel@tonic-gate 	 * Map in the cvc iobuf
1161*0Sstevel@tonic-gate 	 */
1162*0Sstevel@tonic-gate 	cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP);
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate 	hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn,
1165*0Sstevel@tonic-gate 	    PROT_READ | PROT_WRITE, HAT_LOAD_LOCK);
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr
1168*0Sstevel@tonic-gate 		& MMU_PAGEOFFSET)));
1169*0Sstevel@tonic-gate }
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate /*
1173*0Sstevel@tonic-gate  * cvc_iobuf_mapout()
1174*0Sstevel@tonic-gate  *	Map out the cvc iobuf from kernel space
1175*0Sstevel@tonic-gate  */
1176*0Sstevel@tonic-gate static void
1177*0Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id)
1178*0Sstevel@tonic-gate {
1179*0Sstevel@tonic-gate 	caddr_t	cvaddr;
1180*0Sstevel@tonic-gate 	size_t	num_pages;
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate 	if ((cvaddr = cvc_iobufp[cpu_id]) == 0) {
1183*0Sstevel@tonic-gate 		/* already unmapped - return */
1184*0Sstevel@tonic-gate 		return;
1185*0Sstevel@tonic-gate 	}
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	/* Calculate how many pages we need to map out */
1188*0Sstevel@tonic-gate 	num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) +
1189*0Sstevel@tonic-gate 		sizeof (sigb_cvc_t)));
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	/* Get cvaddr to the start of the page boundary */
1192*0Sstevel@tonic-gate 	cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK));
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 	hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK);
1195*0Sstevel@tonic-gate 	vmem_free(heap_arena, cvaddr, ptob(num_pages));
1196*0Sstevel@tonic-gate 
1197*0Sstevel@tonic-gate 	cvc_iobufp[cpu_id] = NULL;
1198*0Sstevel@tonic-gate }
1199