xref: /onnv-gate/usr/src/uts/sun4u/starfire/cvc/cvc.c (revision 11311:639e7bc0b42f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
67656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*11311SSurya.Prakki@Sun.COM 
220Sstevel@tonic-gate /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * MT STREAMS Virtual Console Device Driver
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/processor.h>
350Sstevel@tonic-gate #include <sys/cpuvar.h>
360Sstevel@tonic-gate #include <sys/open.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/systm.h>
390Sstevel@tonic-gate #include <sys/signal.h>
400Sstevel@tonic-gate #include <sys/cred.h>
410Sstevel@tonic-gate #include <sys/user.h>
420Sstevel@tonic-gate #include <sys/proc.h>
430Sstevel@tonic-gate #include <sys/vnode.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <sys/buf.h>
460Sstevel@tonic-gate #include <sys/file.h>
470Sstevel@tonic-gate #include <sys/kmem.h>
480Sstevel@tonic-gate #include <sys/vmem.h>
490Sstevel@tonic-gate #include <sys/stat.h>
500Sstevel@tonic-gate #include <sys/stream.h>
510Sstevel@tonic-gate #include <sys/stropts.h>
520Sstevel@tonic-gate #include <sys/strsubr.h>
530Sstevel@tonic-gate #include <sys/strsun.h>
540Sstevel@tonic-gate #include <sys/tty.h>
550Sstevel@tonic-gate #include <sys/ptyvar.h>
560Sstevel@tonic-gate #include <sys/poll.h>
570Sstevel@tonic-gate #include <sys/debug.h>
580Sstevel@tonic-gate #include <sys/conf.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #include <sys/starfire.h>
610Sstevel@tonic-gate #include <sys/mman.h>
620Sstevel@tonic-gate #include <vm/seg_kmem.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #include <sys/ddi.h>
650Sstevel@tonic-gate #include <sys/sunddi.h>
660Sstevel@tonic-gate #include <sys/errno.h>
670Sstevel@tonic-gate #include <sys/modctl.h>
680Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
690Sstevel@tonic-gate #include <sys/cvc.h>
700Sstevel@tonic-gate #include <sys/cpu_sgn.h>
710Sstevel@tonic-gate 
720Sstevel@tonic-gate extern void	prom_printf(char *fmt, ...);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static int	cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
750Sstevel@tonic-gate static int	cvc_attach(dev_info_t *, ddi_attach_cmd_t);
760Sstevel@tonic-gate static int	cvc_detach(dev_info_t *, ddi_detach_cmd_t);
770Sstevel@tonic-gate static int	cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
780Sstevel@tonic-gate static int	cvc_close(queue_t *, int, cred_t *);
790Sstevel@tonic-gate static int	cvc_wput(queue_t *, mblk_t *);
800Sstevel@tonic-gate static int	cvc_wsrv(queue_t *);
810Sstevel@tonic-gate static void	cvc_ioctl(queue_t *, mblk_t *);
820Sstevel@tonic-gate static void	cvc_ack(mblk_t *, mblk_t *, uint_t);
830Sstevel@tonic-gate static void	cvc_reioctl(void *);
840Sstevel@tonic-gate static void	cvc_input_daemon(void);
850Sstevel@tonic-gate static void	cvc_putc(register int);
860Sstevel@tonic-gate static void	cvc_flush_buf(void *);
870Sstevel@tonic-gate static void	cvc_bbsram_ops(volatile uchar_t *);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static caddr_t	cvc_iobuf_mapin(processorid_t);
900Sstevel@tonic-gate static void	cvc_iobuf_mapout(processorid_t);
910Sstevel@tonic-gate 	void	cvc_assign_iocpu(processorid_t);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * Private copy of devinfo pointer; cvc_info uses it.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate static dev_info_t	*cvcdip;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * This buffer is used to manage mapping in the I/O buffer that CVC
1000Sstevel@tonic-gate  * uses when communicating with the SSP Client (netcon_server) via bbsram.
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate static caddr_t	cvc_iobufp[NCPU];
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate typedef struct cvc_s {
1050Sstevel@tonic-gate 	bufcall_id_t	cvc_wbufcid;
1060Sstevel@tonic-gate 	tty_common_t	cvc_tty;
1070Sstevel@tonic-gate } cvc_t;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate cvc_t	cvc_common_tty;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate static struct module_info cvcm_info = {
1120Sstevel@tonic-gate 	1313,		/* mi_idnum Bad luck number  ;-) */
1130Sstevel@tonic-gate 	"cvc",		/* mi_idname */
1140Sstevel@tonic-gate 	0,		/* mi_minpsz */
1150Sstevel@tonic-gate 	INFPSZ,		/* mi_maxpsz */
1160Sstevel@tonic-gate 	2048,		/* mi_hiwat */
1170Sstevel@tonic-gate 	2048		/* mi_lowat */
1180Sstevel@tonic-gate };
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static struct qinit cvcrinit = {
1210Sstevel@tonic-gate 	NULL,		/* qi_putp */
1220Sstevel@tonic-gate 	NULL,		/* qi_srvp */
1230Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
1240Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
1250Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
1260Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
1270Sstevel@tonic-gate 	NULL		/* qi_mstat */
1280Sstevel@tonic-gate };
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static struct qinit cvcwinit = {
1310Sstevel@tonic-gate 	cvc_wput,	/* qi_putp */
1320Sstevel@tonic-gate 	cvc_wsrv,	/* qi_srvp */
1330Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
1340Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
1350Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
1360Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
1370Sstevel@tonic-gate 	NULL		/* qi_mstat */
1380Sstevel@tonic-gate };
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate struct streamtab	cvcinfo = {
1410Sstevel@tonic-gate 	&cvcrinit,	/* st_rdinit */
1420Sstevel@tonic-gate 	&cvcwinit,	/* st_wrinit */
1430Sstevel@tonic-gate 	NULL,		/* st_muxrinit */
1440Sstevel@tonic-gate 	NULL		/* st_muxwrinit */
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate #define	TIMEOUT_DELAY		100000
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate #define	BBSRAM_INPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
1500Sstevel@tonic-gate 					+ BBSRAM_INPUT_COUNT_OFF))
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate #define	BBSRAM_OUTPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
1530Sstevel@tonic-gate 					+ BBSRAM_OUTPUT_COUNT_OFF))
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate #define	BBSRAM_INPUT_COUNT	(*((volatile short *)BBSRAM_INPUT_BUF))
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate #define	BBSRAM_OUTPUT_COUNT	(*((volatile short *)BBSRAM_OUTPUT_BUF))
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate #define	CVC_OUT_MAXSPIN	1024
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */
1620Sstevel@tonic-gate #define	BBSRAM_CONTROL_REG	((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \
1630Sstevel@tonic-gate 					+ CVC_IN_SIZE + CVC_OUT_SIZE))
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static krwlock_t	cvclock;	/* lock protecting everything here */
1660Sstevel@tonic-gate static queue_t		*cvcinput_q;	/* queue for console input */
1670Sstevel@tonic-gate static queue_t		*cvcoutput_q;	/* queue for console output */
1680Sstevel@tonic-gate static int		cvc_instance = -1;
1690Sstevel@tonic-gate static int		cvc_stopped = 0;
1700Sstevel@tonic-gate static int		cvc_suspended = 0;
1710Sstevel@tonic-gate static int		cvc_hangup_ok = 0;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate static kthread_id_t	cvc_input_daemon_thread;
1740Sstevel@tonic-gate static kmutex_t		cvcmutex;	/* protects input */
1750Sstevel@tonic-gate static kmutex_t		cvc_buf_mutex;	/* protects internal output buffer */
1760Sstevel@tonic-gate static kmutex_t		cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */
1770Sstevel@tonic-gate static int		input_ok = 0;	/* true when stream is valid */
1780Sstevel@tonic-gate static int		stop_bbsram = 1; /* true when BBSRAM is not usable */
1790Sstevel@tonic-gate static int		stop_timeout = 0;
1800Sstevel@tonic-gate static uchar_t		cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */
1810Sstevel@tonic-gate static ushort_t		cvc_output_count = 0;
1820Sstevel@tonic-gate static int		via_bbsram = 0; /* toggle switch */
1830Sstevel@tonic-gate static timeout_id_t	cvc_timeout_id = (timeout_id_t)-1;
1840Sstevel@tonic-gate static processorid_t	cvc_iocpu = -1;	/* cpu id of cpu zero */
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  * Module linkage information for the kernel.
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
1917656SSherry.Moore@Sun.COM 		    nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo,
1927656SSherry.Moore@Sun.COM 		    ddi_quiesce_not_supported);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate static struct modldrv modldrv = {
1950Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
1967656SSherry.Moore@Sun.COM 	"CVC driver 'cvc'",
1970Sstevel@tonic-gate 	&cvcops,	/* driver ops */
1980Sstevel@tonic-gate };
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate static struct modlinkage modlinkage = {
2010Sstevel@tonic-gate 	MODREV_1,
2020Sstevel@tonic-gate 	&modldrv,
2030Sstevel@tonic-gate 	NULL
2040Sstevel@tonic-gate };
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate int
_init(void)2070Sstevel@tonic-gate _init(void)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	int	status;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	status = mod_install(&modlinkage);
2120Sstevel@tonic-gate 	if (status == 0) {
2130Sstevel@tonic-gate 		mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 	return (status);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate int
_fini(void)2190Sstevel@tonic-gate _fini(void)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	return (EBUSY);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2250Sstevel@tonic-gate _info(struct modinfo *modinfop)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * DDI glue routines.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /* ARGSUSED */
2350Sstevel@tonic-gate static int
cvc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2360Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	static char	been_here = 0;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if (cmd == DDI_RESUME) {
2410Sstevel@tonic-gate 		cvc_suspended = 0;
2420Sstevel@tonic-gate 		return (DDI_SUCCESS);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
2460Sstevel@tonic-gate 	if (!been_here) {
2470Sstevel@tonic-gate 		been_here = 1;
2480Sstevel@tonic-gate 		mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL);
2490Sstevel@tonic-gate 		mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
2500Sstevel@tonic-gate 		rw_init(&cvclock, NULL, RW_DRIVER, NULL);
2510Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
2520Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
2537656SSherry.Moore@Sun.COM 		    drv_usectohz(TIMEOUT_DELAY));
2540Sstevel@tonic-gate 		rw_exit(&cvclock);
2550Sstevel@tonic-gate 		cvc_instance = ddi_get_instance(devi);
2560Sstevel@tonic-gate 	} else {
2570Sstevel@tonic-gate #if defined(DEBUG)
2580Sstevel@tonic-gate 		cmn_err(CE_NOTE,
2597656SSherry.Moore@Sun.COM 		    "cvc_attach: called multiple times!! (instance = %d)",
2607656SSherry.Moore@Sun.COM 		    ddi_get_instance(devi));
2610Sstevel@tonic-gate #endif /* DEBUG */
2620Sstevel@tonic-gate 		return (DDI_SUCCESS);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
2670Sstevel@tonic-gate 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2680Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
2690Sstevel@tonic-gate 		return (-1);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 	cvcdip = devi;
2720Sstevel@tonic-gate 	cvcinput_q = NULL;
2730Sstevel@tonic-gate 	cvcoutput_q = NULL;
2740Sstevel@tonic-gate 	return (DDI_SUCCESS);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate static int
cvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2780Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	if (cmd == DDI_SUSPEND) {
2810Sstevel@tonic-gate 		cvc_suspended = 1;
2820Sstevel@tonic-gate 	} else {
2830Sstevel@tonic-gate 		if (cmd != DDI_DETACH) {
2840Sstevel@tonic-gate 			return (DDI_FAILURE);
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 		/*
2870Sstevel@tonic-gate 		 * XXX this doesn't even begin to address the detach
2880Sstevel@tonic-gate 		 * issues - it doesn't terminate the outstanding thread,
2890Sstevel@tonic-gate 		 * it doesn't clean up mutexes, kill the timeout routine
2900Sstevel@tonic-gate 		 * etc.
2910Sstevel@tonic-gate 		 */
2920Sstevel@tonic-gate 		if (cvc_instance == ddi_get_instance(dip)) {
2930Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 	return (DDI_SUCCESS);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate /* ARGSUSED */
3000Sstevel@tonic-gate static int
cvc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3010Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	register int error;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	switch (infocmd) {
3060Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3070Sstevel@tonic-gate 		if (cvcdip == NULL) {
3080Sstevel@tonic-gate 			error = DDI_FAILURE;
3090Sstevel@tonic-gate 		} else {
3100Sstevel@tonic-gate 			*result = (void *)cvcdip;
3110Sstevel@tonic-gate 			error = DDI_SUCCESS;
3120Sstevel@tonic-gate 		}
3130Sstevel@tonic-gate 		break;
3140Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3150Sstevel@tonic-gate 		*result = (void *)0;
3160Sstevel@tonic-gate 		error = DDI_SUCCESS;
3170Sstevel@tonic-gate 		break;
3180Sstevel@tonic-gate 	default:
3190Sstevel@tonic-gate 		error = DDI_FAILURE;
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	return (error);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /* ARGSUSED */
3250Sstevel@tonic-gate static int
cvc_open(register queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)3260Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	register int		unit = getminor(*devp);
3290Sstevel@tonic-gate 	register int		err = 0;
3300Sstevel@tonic-gate 	tty_common_t		*tty;
3310Sstevel@tonic-gate 	cvc_t			*cp;
3320Sstevel@tonic-gate 	static int		input_daemon_started;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (unit != 0)
3350Sstevel@tonic-gate 		return (ENXIO);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (q->q_ptr)
3380Sstevel@tonic-gate 		return (0);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	cp = (cvc_t *)&cvc_common_tty;
3410Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
3420Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
3430Sstevel@tonic-gate 	tty = &cp->cvc_tty;
3440Sstevel@tonic-gate 	tty->t_readq = q;
3450Sstevel@tonic-gate 	tty->t_writeq = WR(q);
3460Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
3470Sstevel@tonic-gate 	cvcinput_q = RD(q);		/* save for cvc_redir */
3480Sstevel@tonic-gate 	qprocson(q);
3490Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
3500Sstevel@tonic-gate 	input_ok = 1;
3510Sstevel@tonic-gate 	if (!input_daemon_started) {
3520Sstevel@tonic-gate 		extern struct cpu	*SIGBCPU;	/* bugid4141050 */
3530Sstevel@tonic-gate 		extern cpu_sgnblk_t	*cpu_sgnblkp[];
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		input_daemon_started = 1;
3560Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL);
3590Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		cvc_input_daemon_thread = thread_create(NULL, 0,
3620Sstevel@tonic-gate 		    cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
3630Sstevel@tonic-gate 	} else {
3640Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate #ifdef lint
3670Sstevel@tonic-gate 	cvc_input_daemon_thread = cvc_input_daemon_thread;
3680Sstevel@tonic-gate #endif
3690Sstevel@tonic-gate 	return (err);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /* ARGSUSED */
3730Sstevel@tonic-gate static int
cvc_close(queue_t * q,int flag,cred_t * crp)3740Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	register int		err = 0;
3770Sstevel@tonic-gate 	register cvc_t		*cp;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
3800Sstevel@tonic-gate 	input_ok = 0;
3810Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	cp = q->q_ptr;
3840Sstevel@tonic-gate 	if (cp->cvc_wbufcid != 0) {
3850Sstevel@tonic-gate 		unbufcall(cp->cvc_wbufcid);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 	ttycommon_close(&cp->cvc_tty);
3880Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = NULL;
3890Sstevel@tonic-gate 	cvcinput_q = NULL;
3900Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
3910Sstevel@tonic-gate 	qprocsoff(q);
3920Sstevel@tonic-gate 	return (err);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate  * cvc_wput()
3980Sstevel@tonic-gate  *	cn driver does a strwrite of console output data to rconsvp which
3990Sstevel@tonic-gate  *	has been set by consconfig. The data enters the cvc stream at the
4000Sstevel@tonic-gate  *	streamhead and flows thru ttycompat and ldterm which have been
4010Sstevel@tonic-gate  *	pushed on the stream.  Console output data gets sent out either
4020Sstevel@tonic-gate  *	by cvcredir (if there is a cvcd running) or bbsram (if there
4030Sstevel@tonic-gate  *	isn't).
4040Sstevel@tonic-gate  *	Data is sent to the cvcredir via it's read q which is cvcoutput_q
4050Sstevel@tonic-gate  *	and was set in cvc_register().
4060Sstevel@tonic-gate  */
4070Sstevel@tonic-gate static int
cvc_wput(register queue_t * q,register mblk_t * mp)4080Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	int		error = 0;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
4130Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		case M_IOCTL:
4160Sstevel@tonic-gate 		case M_CTL:
4170Sstevel@tonic-gate 			cvc_ioctl(q, mp);
4180Sstevel@tonic-gate 			break;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		case M_FLUSH:
4210Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW) {
4220Sstevel@tonic-gate 				/*
4230Sstevel@tonic-gate 				 * Flush our write queue.
4240Sstevel@tonic-gate 				 */
4250Sstevel@tonic-gate 				flushq(q, FLUSHDATA);
4260Sstevel@tonic-gate 				*mp->b_rptr &= ~FLUSHW;
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR) {
4290Sstevel@tonic-gate 				flushq(RD(q), FLUSHDATA);
4300Sstevel@tonic-gate 				qreply(q, mp);
4310Sstevel@tonic-gate 			} else
4320Sstevel@tonic-gate 				freemsg(mp);
4330Sstevel@tonic-gate 			break;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		case M_STOP:
4360Sstevel@tonic-gate 			cvc_stopped = 1;
4370Sstevel@tonic-gate 			freemsg(mp);
4380Sstevel@tonic-gate 			break;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 		case M_START:
4410Sstevel@tonic-gate 			cvc_stopped = 0;
4420Sstevel@tonic-gate 			freemsg(mp);
4430Sstevel@tonic-gate 			qenable(q);  /* Start up delayed messages */
4440Sstevel@tonic-gate 			break;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 		case M_READ:
4470Sstevel@tonic-gate 			/*
4480Sstevel@tonic-gate 			 * ldterm handles this (VMIN/VTIME processing).
4490Sstevel@tonic-gate 			 */
4500Sstevel@tonic-gate 			freemsg(mp);
4510Sstevel@tonic-gate 			break;
4520Sstevel@tonic-gate 		default:
453*11311SSurya.Prakki@Sun.COM 			cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%p",
454*11311SSurya.Prakki@Sun.COM 			    (void *)mp);
4550Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_wput: type = 0x%x",
4567656SSherry.Moore@Sun.COM 			    mp->b_datap->db_type);
4570Sstevel@tonic-gate 			/* FALLTHROUGH */
4580Sstevel@tonic-gate #ifdef lint
4590Sstevel@tonic-gate 			break;
4600Sstevel@tonic-gate #endif
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		case M_DATA:
4630Sstevel@tonic-gate 			if (cvc_stopped == 1 || cvc_suspended == 1) {
4640Sstevel@tonic-gate 				(void) putq(q, mp);
4650Sstevel@tonic-gate 				break;
4660Sstevel@tonic-gate 			}
4670Sstevel@tonic-gate 			if (cvcoutput_q != NULL && !via_bbsram) {
4680Sstevel@tonic-gate 				/*
4690Sstevel@tonic-gate 				 * Send it up past cvcredir module.
4700Sstevel@tonic-gate 				 */
4710Sstevel@tonic-gate 				putnext(cvcoutput_q, mp);
4720Sstevel@tonic-gate 			} else {
4730Sstevel@tonic-gate 				char	*msgp, c;
4740Sstevel@tonic-gate 				mblk_t	*mp2 = mp;
4750Sstevel@tonic-gate 				int count;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 				while (mp2 != NULL) {
4780Sstevel@tonic-gate 					count = mp2->b_wptr - mp2->b_rptr;
4790Sstevel@tonic-gate 					msgp = (char *)mp2->b_rptr;
4800Sstevel@tonic-gate 					while (count > 0) {
4810Sstevel@tonic-gate 						count--;
4820Sstevel@tonic-gate 						if ((c = *msgp++) != '\0') {
4830Sstevel@tonic-gate 							/* don't print NULs */
4840Sstevel@tonic-gate 							cvc_putc(c);
4850Sstevel@tonic-gate 						}
4860Sstevel@tonic-gate 					}
4870Sstevel@tonic-gate 					mp2 = mp2->b_cont;
4880Sstevel@tonic-gate 				}
4890Sstevel@tonic-gate 				freemsg(mp);
4900Sstevel@tonic-gate 			}
4910Sstevel@tonic-gate 			break;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	}
4940Sstevel@tonic-gate 	rw_exit(&cvclock);
4950Sstevel@tonic-gate 	return (error);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate static int cvc_wsrv_count = 0;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate static int
cvc_wsrv(queue_t * q)5010Sstevel@tonic-gate cvc_wsrv(queue_t *q)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	register mblk_t *mp;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	cvc_wsrv_count++;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (cvc_stopped == 1 || cvc_suspended == 1) {
5080Sstevel@tonic-gate 		return (0);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
5120Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
5130Sstevel@tonic-gate 		if (cvcoutput_q != NULL && !via_bbsram) {
5140Sstevel@tonic-gate 			/*
5150Sstevel@tonic-gate 			 * Send it up past cvcredir module.
5160Sstevel@tonic-gate 			 */
5170Sstevel@tonic-gate 			putnext(cvcoutput_q, mp);
5180Sstevel@tonic-gate 		} else {
5190Sstevel@tonic-gate 			char    *msgp, c;
5200Sstevel@tonic-gate 			mblk_t  *mp2 = mp;
5210Sstevel@tonic-gate 			int count;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 			while (mp2 != NULL) {
5240Sstevel@tonic-gate 				count = mp2->b_wptr - mp2->b_rptr;
5250Sstevel@tonic-gate 				msgp = (char *)mp2->b_rptr;
5260Sstevel@tonic-gate 				while (count > 0) {
5270Sstevel@tonic-gate 					count--;
5280Sstevel@tonic-gate 					if ((c = *msgp++) != '\0') {
5290Sstevel@tonic-gate 						/* don't print NULs */
5300Sstevel@tonic-gate 						cvc_putc(c);
5310Sstevel@tonic-gate 					}
5320Sstevel@tonic-gate 				}
5330Sstevel@tonic-gate 				mp2 = mp2->b_cont;
5340Sstevel@tonic-gate 			}
5350Sstevel@tonic-gate 			freemsg(mp);
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 	rw_exit(&cvclock);
5390Sstevel@tonic-gate 	return (0);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * cvc_ioctl()
5450Sstevel@tonic-gate  *	handle normal console ioctls.
5460Sstevel@tonic-gate  */
5470Sstevel@tonic-gate static void
cvc_ioctl(register queue_t * q,register mblk_t * mp)5480Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate 	register struct iocblk		*iocp;
5510Sstevel@tonic-gate 	register tty_common_t		*tty;
5520Sstevel@tonic-gate 	register cvc_t			*cp;
5530Sstevel@tonic-gate 	int				datasize;
5540Sstevel@tonic-gate 	int				error = 0;
5550Sstevel@tonic-gate 	mblk_t				*tmp;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	cp = q->q_ptr;
5580Sstevel@tonic-gate 	tty = &cp->cvc_tty;
5590Sstevel@tonic-gate 	if (tty->t_iocpending != NULL) {
5600Sstevel@tonic-gate 		freemsg(tty->t_iocpending);
5610Sstevel@tonic-gate 		tty->t_iocpending = NULL;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 	datasize = ttycommon_ioctl(tty, q, mp, &error);
5640Sstevel@tonic-gate 	if (datasize != 0) {
5650Sstevel@tonic-gate 		if (cp->cvc_wbufcid)
5660Sstevel@tonic-gate 			unbufcall(cp->cvc_wbufcid);
5670Sstevel@tonic-gate 		cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
5680Sstevel@tonic-gate 		return;
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 	if (error < 0) {
5710Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
5720Sstevel@tonic-gate 		/*
5730Sstevel@tonic-gate 		 * "ttycommon_ioctl" didn't do anything; we process it here.
5740Sstevel@tonic-gate 		 */
5750Sstevel@tonic-gate 		error = 0;
5760Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		/*
5790Sstevel@tonic-gate 		 *  Set modem bit ioctls.  These are NOPs for us, since we
5800Sstevel@tonic-gate 		 * dont control any hardware.
5810Sstevel@tonic-gate 		 */
5820Sstevel@tonic-gate 		case TCSBRK:
5830Sstevel@tonic-gate 		case TIOCSBRK:
5840Sstevel@tonic-gate 		case TIOCCBRK:
5850Sstevel@tonic-gate 		case TIOCMSET:
5860Sstevel@tonic-gate 		case TIOCMBIS:
5870Sstevel@tonic-gate 		case TIOCMBIC:
5880Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT) {
5890Sstevel@tonic-gate 				mioc2ack(mp, NULL, 0, 0);
5900Sstevel@tonic-gate 			} else {
5910Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (int), NULL);
5920Sstevel@tonic-gate 			}
5930Sstevel@tonic-gate 			/* qreply done below */
5940Sstevel@tonic-gate 			break;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 		/*
5970Sstevel@tonic-gate 		 *  Get modem bits, we return 0 in mblk.
5980Sstevel@tonic-gate 		 */
5990Sstevel@tonic-gate 		case TIOCMGET:
6000Sstevel@tonic-gate 			tmp = allocb(sizeof (int), BPRI_MED);
6010Sstevel@tonic-gate 			if (tmp == NULL) {
6020Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
6030Sstevel@tonic-gate 				return;
6040Sstevel@tonic-gate 			}
6050Sstevel@tonic-gate 			*(int *)tmp->b_rptr = 0;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT)
6080Sstevel@tonic-gate 				mioc2ack(mp, tmp, sizeof (int), 0);
6090Sstevel@tonic-gate 			else
6100Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (int), NULL, tmp);
6110Sstevel@tonic-gate 			/* qreply done below */
6120Sstevel@tonic-gate 			break;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		default:
6150Sstevel@tonic-gate 			/*
6160Sstevel@tonic-gate 			 * If we don't understand it, it's an error. NAK it.
6170Sstevel@tonic-gate 			 */
6180Sstevel@tonic-gate 			error = EINVAL;
6190Sstevel@tonic-gate 			break;
6200Sstevel@tonic-gate 		}
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 	if (error != 0) {
6230Sstevel@tonic-gate 		iocp->ioc_error = error;
6240Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
6250Sstevel@tonic-gate 	}
6260Sstevel@tonic-gate 	qreply(q, mp);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate /*
6320Sstevel@tonic-gate  * cvc_redir()
6330Sstevel@tonic-gate  *	called from cvcredir:cvcr_wput() to handle console input
6340Sstevel@tonic-gate  *	data. This routine puts the cvcredir write (downstream) data
6350Sstevel@tonic-gate  *	onto the cvc read (upstream) queues.  Note that if `mp' is
6360Sstevel@tonic-gate  *	an M_IOCTL, then it may be reused by the caller to send back
6370Sstevel@tonic-gate  *	an M_IOCACK or M_IOCNAK.
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate int
cvc_redir(mblk_t * mp)6400Sstevel@tonic-gate cvc_redir(mblk_t *mp)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	register struct iocblk	*iocp;
6430Sstevel@tonic-gate 	register tty_common_t	*tty;
6440Sstevel@tonic-gate 	register cvc_t		*cp;
6450Sstevel@tonic-gate 	struct winsize		*ws;
6460Sstevel@tonic-gate 	int			error;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	if (cvcinput_q == NULL) {
6490Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
6500Sstevel@tonic-gate 		return (EINVAL);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_IOCTL) {
6540Sstevel@tonic-gate 		putnext(cvcinput_q, mp);
6550Sstevel@tonic-gate 		return (0);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
6590Sstevel@tonic-gate 	if (iocp->ioc_cmd == TIOCSWINSZ) {
6600Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct winsize));
6610Sstevel@tonic-gate 		if (error != 0)
6620Sstevel@tonic-gate 			return (error);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		ws = (struct winsize *)mp->b_cont->b_rptr;
6650Sstevel@tonic-gate 		cp = cvcinput_q->q_ptr;
6660Sstevel@tonic-gate 		tty = &cp->cvc_tty;
6670Sstevel@tonic-gate 		mutex_enter(&tty->t_excl);
6680Sstevel@tonic-gate 		if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) {
6690Sstevel@tonic-gate 			tty->t_size = *ws;
6700Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
6710Sstevel@tonic-gate 			(void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH);
6720Sstevel@tonic-gate 		} else
6730Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
6740Sstevel@tonic-gate 	} else {
6750Sstevel@tonic-gate 		/*
6760Sstevel@tonic-gate 		 * It must be a CVC_DISCONNECT, send hangup.
6770Sstevel@tonic-gate 		 */
6780Sstevel@tonic-gate 		ASSERT(iocp->ioc_cmd == CVC_DISCONNECT);
6790Sstevel@tonic-gate 		if (cvc_hangup_ok)
6800Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	return (0);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate  * cvc_register()
6890Sstevel@tonic-gate  *	called from cvcredir to register it's queues.  cvc
6900Sstevel@tonic-gate  *	receives data from cn via the streamhead and sends it to cvcredir
6910Sstevel@tonic-gate  *	via pointers to cvcredir's queues.
6920Sstevel@tonic-gate  */
6930Sstevel@tonic-gate int
cvc_register(queue_t * q)6940Sstevel@tonic-gate cvc_register(queue_t *q)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	int error = -1;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if (cvcinput_q == NULL)
6990Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
7000Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
7010Sstevel@tonic-gate 	if (cvcoutput_q == NULL) {
7020Sstevel@tonic-gate 		cvcoutput_q = RD(q);  /* Make sure its the upstream q */
7030Sstevel@tonic-gate 		qprocson(cvcoutput_q);	/* must be done within cvclock */
7040Sstevel@tonic-gate 		error = 0;
7050Sstevel@tonic-gate 	} else {
7060Sstevel@tonic-gate 		/*
7070Sstevel@tonic-gate 		 * cmn_err will call us, so release lock.
7080Sstevel@tonic-gate 		 */
7090Sstevel@tonic-gate 		rw_exit(&cvclock);
7100Sstevel@tonic-gate 		if (cvcoutput_q == q)
7110Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_register: duplicate q!");
7120Sstevel@tonic-gate 		else
713930Smathue 			cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p",
714*11311SSurya.Prakki@Sun.COM 			    (void *)q);
7150Sstevel@tonic-gate 		return (error);
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	/*
7190Sstevel@tonic-gate 	 * Unless "via_bbsram" is set, i/o will be going through cvcd, so
7200Sstevel@tonic-gate 	 * stop flushing output to BBSRAM.
7210Sstevel@tonic-gate 	 */
7220Sstevel@tonic-gate 	if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) {
7230Sstevel@tonic-gate 		stop_timeout = 1;
7240Sstevel@tonic-gate 		(void) untimeout(cvc_timeout_id);
7250Sstevel@tonic-gate 		cvc_timeout_id = (timeout_id_t)-1;
7260Sstevel@tonic-gate 		cvc_hangup_ok = 1;
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 	rw_exit(&cvclock);
7290Sstevel@tonic-gate 	return (error);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate /*
7340Sstevel@tonic-gate  * cvc_unregister()
7350Sstevel@tonic-gate  *	called from cvcredir to clear pointers to its queues.
7360Sstevel@tonic-gate  *	cvcredir no longer wants to send or receive data.
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate void
cvc_unregister(queue_t * q)7390Sstevel@tonic-gate cvc_unregister(queue_t *q)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
7420Sstevel@tonic-gate 	if (q == cvcoutput_q) {
7430Sstevel@tonic-gate 		qprocsoff(cvcoutput_q);	/* must be done within cvclock */
7440Sstevel@tonic-gate 		cvcoutput_q = NULL;
7450Sstevel@tonic-gate 	} else {
7460Sstevel@tonic-gate 		rw_exit(&cvclock);
747*11311SSurya.Prakki@Sun.COM 		cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered",
748*11311SSurya.Prakki@Sun.COM 		    (void *)q);
7490Sstevel@tonic-gate 		return;
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * i/o will not be going through cvcd, start flushing output to
7540Sstevel@tonic-gate 	 * BBSRAM
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 	if (cvc_timeout_id == (timeout_id_t)-1) {
7570Sstevel@tonic-gate 		stop_timeout = 0;
7580Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
7597656SSherry.Moore@Sun.COM 		    drv_usectohz(TIMEOUT_DELAY));
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 	rw_exit(&cvclock);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate /*
7650Sstevel@tonic-gate  * cvc_reioctl()
7660Sstevel@tonic-gate  *	Retry an "ioctl", now that "bufcall" claims we may be able
7670Sstevel@tonic-gate  *	to allocate the buffer we need.
7680Sstevel@tonic-gate  */
7690Sstevel@tonic-gate static void
cvc_reioctl(void * unit)7700Sstevel@tonic-gate cvc_reioctl(void *unit)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	register queue_t	*q;
7730Sstevel@tonic-gate 	register mblk_t		*mp;
7740Sstevel@tonic-gate 	register cvc_t		*cp = (cvc_t *)unit;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * The bufcall is no longer pending.
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	if (!cp->cvc_wbufcid) {
7800Sstevel@tonic-gate 		return;
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
7830Sstevel@tonic-gate 	if ((q = cp->cvc_tty.t_writeq) == NULL) {
7840Sstevel@tonic-gate 		return;
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
7870Sstevel@tonic-gate 		/* not pending any more */
7880Sstevel@tonic-gate 		cp->cvc_tty.t_iocpending = NULL;
7890Sstevel@tonic-gate 		cvc_ioctl(q, mp);
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate /*
7950Sstevel@tonic-gate  * cvc_bbsram_ops()
7960Sstevel@tonic-gate  *	Process commands sent to cvc from netcon_server via BBSRAM
7970Sstevel@tonic-gate  */
7980Sstevel@tonic-gate static void
cvc_bbsram_ops(volatile unsigned char * op_reg)7990Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg)
8000Sstevel@tonic-gate {
8010Sstevel@tonic-gate 	uchar_t	 op;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	if ((op = *op_reg) == 0)
8040Sstevel@tonic-gate 		return;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex));
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	switch (op) {
8090Sstevel@tonic-gate 	case CVC_BBSRAM_BREAK:		/* A console break (L1-A) */
8100Sstevel@tonic-gate 		abort_sequence_enter((char *)NULL);
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 	case CVC_BBSRAM_DISCONNECT:	/* Break connection, hang up */
8130Sstevel@tonic-gate 		if (cvcinput_q && cvc_hangup_ok)
8140Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
8150Sstevel@tonic-gate 		break;
8160Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_NET:	/* console via network */
8170Sstevel@tonic-gate 		via_bbsram = 0;
8180Sstevel@tonic-gate 		/*
8190Sstevel@tonic-gate 		 * stop periodic flushing of output to BBSRAM
8200Sstevel@tonic-gate 		 * only if cvcredir/cvcd are present
8210Sstevel@tonic-gate 		 */
8220Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
8230Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
8240Sstevel@tonic-gate 			stop_timeout = 1;
8250Sstevel@tonic-gate 			if (cvc_timeout_id != (timeout_id_t)-1) {
8260Sstevel@tonic-gate 				(void) untimeout(cvc_timeout_id);
8270Sstevel@tonic-gate 				cvc_timeout_id = (timeout_id_t)-1;
8280Sstevel@tonic-gate 			}
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		rw_exit(&cvclock);
8310Sstevel@tonic-gate 		break;
8320Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_BBSRAM:	/* console via bbsram */
8330Sstevel@tonic-gate 		via_bbsram = 1;
8340Sstevel@tonic-gate 		/* start periodic flushing of ouput to BBSRAM */
8350Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
8360Sstevel@tonic-gate 		if (cvc_timeout_id == (timeout_id_t)-1) {
8370Sstevel@tonic-gate 			stop_timeout = 0;
8380Sstevel@tonic-gate 			cvc_timeout_id = timeout(cvc_flush_buf,
8390Sstevel@tonic-gate 			    NULL, drv_usectohz(TIMEOUT_DELAY));
8400Sstevel@tonic-gate 		}
8410Sstevel@tonic-gate 		rw_exit(&cvclock);
8420Sstevel@tonic-gate 		break;
8430Sstevel@tonic-gate 	case CVC_BBSRAM_CLOSE_NET:
8440Sstevel@tonic-gate 		/*
8450Sstevel@tonic-gate 		 * Send a hangup control message upstream to cvcd
8460Sstevel@tonic-gate 		 * thru cvcredir.  This is an attempt to close
8470Sstevel@tonic-gate 		 * out any existing network connection(if any).
8480Sstevel@tonic-gate 		 * cvcoutput_q should point to the cvcredir's read
8490Sstevel@tonic-gate 		 * queue.
8500Sstevel@tonic-gate 		 */
8510Sstevel@tonic-gate 		rw_enter(&cvclock, RW_READER);
8520Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
8530Sstevel@tonic-gate 			(void) putnextctl(cvcoutput_q, M_HANGUP);
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 		rw_exit(&cvclock);
8560Sstevel@tonic-gate 		break;
8570Sstevel@tonic-gate 	default:
8580Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n",
8597656SSherry.Moore@Sun.COM 		    (unsigned int)op);
8600Sstevel@tonic-gate 		break;
8610Sstevel@tonic-gate 	}
8620Sstevel@tonic-gate 	*op_reg = 0;
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate  * cvc_putc()
8680Sstevel@tonic-gate  *	Put a single character out to BBSRAM if space available.
8690Sstevel@tonic-gate  */
8700Sstevel@tonic-gate static void
cvc_putc(register int c)8710Sstevel@tonic-gate cvc_putc(register int c)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate 	static int	output_lost = 0;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	if (c == '\n')
8760Sstevel@tonic-gate 		cvc_putc('\r');
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
8790Sstevel@tonic-gate 	/*
8800Sstevel@tonic-gate 	 * Just exit if the buffer is already full.
8810Sstevel@tonic-gate 	 * It will be up to cvc_flush_buf() to flush the buffer.
8820Sstevel@tonic-gate 	 */
8830Sstevel@tonic-gate 	if (cvc_output_count == MAX_XFER_OUTPUT) {
8840Sstevel@tonic-gate 		output_lost = 1;
8850Sstevel@tonic-gate 		mutex_exit(&cvc_buf_mutex);
8860Sstevel@tonic-gate 		return;
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 	if (output_lost)
8890Sstevel@tonic-gate 		prom_printf("WARNING: overflow of cvc output buffer, "
8900Sstevel@tonic-gate 		    "output lost!");
8910Sstevel@tonic-gate 	output_lost = 0;
8920Sstevel@tonic-gate 	cvc_output_buffer[cvc_output_count] = (unsigned char)c;
8930Sstevel@tonic-gate 	cvc_output_count++;
8940Sstevel@tonic-gate 	if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) {
8950Sstevel@tonic-gate 		/* flush cvc's internal output buffer to BBSRAM */
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		/*
8980Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
8990Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP
9000Sstevel@tonic-gate 		 */
9010Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
9020Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
9030Sstevel@tonic-gate 			if (stop_bbsram) {
9040Sstevel@tonic-gate 				mutex_exit(&cvc_buf_mutex);
9050Sstevel@tonic-gate 				return;
9060Sstevel@tonic-gate 			}
9070Sstevel@tonic-gate 			DELAY(1000);
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
9107656SSherry.Moore@Sun.COM 		    (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count),
9117656SSherry.Moore@Sun.COM 		    cvc_output_count);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
9140Sstevel@tonic-gate 		cvc_output_count = 0;
9150Sstevel@tonic-gate 	}
9160Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate /*
9210Sstevel@tonic-gate  * cvc_flush_buf()
9220Sstevel@tonic-gate  *	Flush cvc's internal output buffer to BBSRAM at regular intervals.
9230Sstevel@tonic-gate  *	This should only be done if cvcd is not running or the user (via the cvc
9240Sstevel@tonic-gate  *	application on the SSP) has requested that i/o go through BBSRAM.
9250Sstevel@tonic-gate  */
9260Sstevel@tonic-gate /* ARGSUSED */
9270Sstevel@tonic-gate static void
cvc_flush_buf(void * notused)9280Sstevel@tonic-gate cvc_flush_buf(void *notused)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	if (stop_timeout)
9310Sstevel@tonic-gate 		return;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
9340Sstevel@tonic-gate 	if (cvc_output_count != 0) {
9350Sstevel@tonic-gate 		/*
9360Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
9370Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP.
9380Sstevel@tonic-gate 		 */
9390Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
9400Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
9410Sstevel@tonic-gate 			if (stop_bbsram)
9420Sstevel@tonic-gate 				goto exit;
9430Sstevel@tonic-gate 			DELAY(1000);
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
9477656SSherry.Moore@Sun.COM 		    (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count,
9487656SSherry.Moore@Sun.COM 		    cvc_output_count);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
9510Sstevel@tonic-gate 		cvc_output_count = 0;
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate exit:
9540Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
9550Sstevel@tonic-gate 	/* rw_enter(&cvclock, RW_WRITER); */
9560Sstevel@tonic-gate 	cvc_timeout_id = timeout(cvc_flush_buf, NULL,
9577656SSherry.Moore@Sun.COM 	    drv_usectohz(TIMEOUT_DELAY));
9580Sstevel@tonic-gate 	/* rw_exit(&cvclock); */
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate /*
9630Sstevel@tonic-gate  * cvc_getstr()
9640Sstevel@tonic-gate  *	Poll BBSRAM for console input while available.
9650Sstevel@tonic-gate  */
9660Sstevel@tonic-gate static void
cvc_getstr(char * cp)9670Sstevel@tonic-gate cvc_getstr(char *cp)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate 	short		count;
9700Sstevel@tonic-gate 	volatile char	*lp;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
9730Sstevel@tonic-gate 	/* Poll BBSRAM for input */
9740Sstevel@tonic-gate 	do {
9750Sstevel@tonic-gate 		if (stop_bbsram) {
9760Sstevel@tonic-gate 			*cp = '\0';	/* set string to zero-length */
9770Sstevel@tonic-gate 			mutex_exit(&cvc_bbsram_input_mutex);
9780Sstevel@tonic-gate 			return;
9790Sstevel@tonic-gate 		}
9800Sstevel@tonic-gate 		/*
9810Sstevel@tonic-gate 		 * Use a smaller delay between checks of BBSRAM for input
9820Sstevel@tonic-gate 		 * when cvcd/cvcredir are not running or "via_bbsram" has
9830Sstevel@tonic-gate 		 * been set.
9840Sstevel@tonic-gate 		 * We don't go away completely when i/o is going through the
9850Sstevel@tonic-gate 		 * network via cvcd since a command may be sent via BBSRAM
9860Sstevel@tonic-gate 		 * to switch if the network is down or hung.
9870Sstevel@tonic-gate 		 */
9880Sstevel@tonic-gate 		if ((cvcoutput_q == NULL) || (via_bbsram))
9890Sstevel@tonic-gate 			delay(drv_usectohz(100000));
9900Sstevel@tonic-gate 		else
9910Sstevel@tonic-gate 			delay(drv_usectohz(1000000));
9920Sstevel@tonic-gate 		cvc_bbsram_ops(BBSRAM_CONTROL_REG);
9930Sstevel@tonic-gate 		count = BBSRAM_INPUT_COUNT;
9940Sstevel@tonic-gate 	} while (count == 0);
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	lp = BBSRAM_INPUT_BUF - count;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	while (count--) {
9990Sstevel@tonic-gate 		*cp++ = *lp++;
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 	*cp = '\0';
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	BBSRAM_INPUT_COUNT = 0;
10040Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate /*
10090Sstevel@tonic-gate  * cvc_input_daemon()
10100Sstevel@tonic-gate  *	this function runs as a separate kernel thread and polls BBSRAM for
10110Sstevel@tonic-gate  *	input, and possibly put it on read stream for the console.
10120Sstevel@tonic-gate  *	There are two poll rates (implemented in cvc_getstr):
10130Sstevel@tonic-gate  *		 100 000 uS (10 Hz) - no cvcd communications || via_bbsram
10140Sstevel@tonic-gate  *		1000 000 uS ( 1 Hz) - cvcd communications
10150Sstevel@tonic-gate  * 	This continues to run even if there are network console communications
10160Sstevel@tonic-gate  *	in order to handle out-of-band signaling.
10170Sstevel@tonic-gate  */
10180Sstevel@tonic-gate static void
cvc_input_daemon(void)10190Sstevel@tonic-gate cvc_input_daemon(void)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	char		linebuf[MAX_XFER_INPUT];
10220Sstevel@tonic-gate 	char		*cp;
10230Sstevel@tonic-gate 	mblk_t		*mbp;
10240Sstevel@tonic-gate 	int		c;
10250Sstevel@tonic-gate 	int		dropped_read = 0;
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	for (;;) {
10280Sstevel@tonic-gate 		cvc_getstr(linebuf);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		mbp = allocb(strlen(linebuf), BPRI_MED);
10310Sstevel@tonic-gate 		if (mbp == NULL) {	/* drop it & go on if no buffer */
10320Sstevel@tonic-gate 			if (!dropped_read) {
10330Sstevel@tonic-gate 				cmn_err(CE_WARN,
10340Sstevel@tonic-gate 				    "cvc_input_daemon: "
10350Sstevel@tonic-gate 				    "dropping BBSRAM reads\n");
10360Sstevel@tonic-gate 			}
10370Sstevel@tonic-gate 			dropped_read++;
10380Sstevel@tonic-gate 			continue;
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 		if (dropped_read) {
10410Sstevel@tonic-gate 			cmn_err(CE_WARN,
10420Sstevel@tonic-gate 			    "cvc_input_daemon: dropped %d BBSRAM reads\n",
10430Sstevel@tonic-gate 			    dropped_read);
10440Sstevel@tonic-gate 			dropped_read = 0;
10450Sstevel@tonic-gate 		}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		for (cp = linebuf; *cp != '\0'; cp++) {
10480Sstevel@tonic-gate 			c = (int)*cp;
10490Sstevel@tonic-gate 			if (c == '\r')
10500Sstevel@tonic-gate 				c = '\n';
10510Sstevel@tonic-gate 			c &= 0177;
10520Sstevel@tonic-gate 			*mbp->b_wptr = (char)c;
10530Sstevel@tonic-gate 			mbp->b_wptr++;
10540Sstevel@tonic-gate 		}
10550Sstevel@tonic-gate 		mutex_enter(&cvcmutex);
10560Sstevel@tonic-gate 		if (input_ok) {
10570Sstevel@tonic-gate 			if (cvcinput_q == NULL) {
10580Sstevel@tonic-gate 				cmn_err(CE_WARN,
10590Sstevel@tonic-gate 				    "cvc_input_daemon: cvcinput_q is NULL!");
10600Sstevel@tonic-gate 			} else {
10610Sstevel@tonic-gate 				putnext(cvcinput_q, mbp);
10620Sstevel@tonic-gate 			}
10630Sstevel@tonic-gate 		} else {
10640Sstevel@tonic-gate 			freemsg(mbp);
10650Sstevel@tonic-gate 		}
10660Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
10670Sstevel@tonic-gate 	}
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	/* NOTREACHED */
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate  * cvc_bbsram_stop()
10750Sstevel@tonic-gate  *	Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when
10760Sstevel@tonic-gate  *	mapping in BBSRAM to a virtual address.
10770Sstevel@tonic-gate  */
10780Sstevel@tonic-gate static void
cvc_bbsram_stop(void)10790Sstevel@tonic-gate cvc_bbsram_stop(void)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate 	stop_bbsram = 1;
10820Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
10830Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate /*
10880Sstevel@tonic-gate  * cvc_bbsram_start()
10890Sstevel@tonic-gate  *	Allow accesses to BBSRAM, used by cvc_assign_iocpu() after
10900Sstevel@tonic-gate  *	BBSRAM has been mapped to a virtual address.
10910Sstevel@tonic-gate  */
10920Sstevel@tonic-gate static void
cvc_bbsram_start(void)10930Sstevel@tonic-gate cvc_bbsram_start(void)
10940Sstevel@tonic-gate {
10950Sstevel@tonic-gate 	stop_bbsram = 0;
10960Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
10970Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate /*
11020Sstevel@tonic-gate  * cvc_assign_iocpu()
11030Sstevel@tonic-gate  *	Map in BBSRAM to a virtual address
11040Sstevel@tonic-gate  *	This called by the kernel with the cpu id of cpu zero.
11050Sstevel@tonic-gate  */
11060Sstevel@tonic-gate void
cvc_assign_iocpu(processorid_t newcpu)11070Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu)
11080Sstevel@tonic-gate {
11090Sstevel@tonic-gate 	processorid_t	oldcpu = cvc_iocpu;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	if (newcpu == oldcpu)
11120Sstevel@tonic-gate 		return;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu);
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	cvc_bbsram_stop();
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	cvc_iocpu = newcpu;
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	cvc_bbsram_start();
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	if (oldcpu != -1)
11230Sstevel@tonic-gate 		cvc_iobuf_mapout(oldcpu);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate /*
11280Sstevel@tonic-gate  * cvc_iobuf_mapin()
11290Sstevel@tonic-gate  *	Map in the cvc bbsram i/o buffer into kernel space.
11300Sstevel@tonic-gate  */
11310Sstevel@tonic-gate static caddr_t
cvc_iobuf_mapin(processorid_t cpu_id)11320Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id)
11330Sstevel@tonic-gate {
11340Sstevel@tonic-gate 	caddr_t	cvaddr;
11350Sstevel@tonic-gate 	uint64_t cvc_iobuf_physaddr;
11360Sstevel@tonic-gate 	pfn_t pfn;
11370Sstevel@tonic-gate 	uint_t num_pages;
11380Sstevel@tonic-gate 	extern cpu_sgnblk_t *cpu_sgnblkp[];
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	ASSERT(cpu_sgnblkp[cpu_id] != NULL);
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	/*
11430Sstevel@tonic-gate 	 * First construct the physical base address of the bbsram
11440Sstevel@tonic-gate 	 * in Starfire PSI space associated with this cpu in question.
11450Sstevel@tonic-gate 	 */
11460Sstevel@tonic-gate 	cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE;
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	/*
11490Sstevel@tonic-gate 	 * Next add the cvc i/o buffer offset obtained from the
11500Sstevel@tonic-gate 	 * sigblock to get cvc iobuf physical address
11510Sstevel@tonic-gate 	 */
11520Sstevel@tonic-gate 	cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off;
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	/* Get the page frame number */
11550Sstevel@tonic-gate 	pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT);
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	/* Calculate how many pages we need to map in */
11580Sstevel@tonic-gate 	num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr
11597656SSherry.Moore@Sun.COM 	    & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t)));
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	/*
11620Sstevel@tonic-gate 	 * Map in the cvc iobuf
11630Sstevel@tonic-gate 	 */
11640Sstevel@tonic-gate 	cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn,
11670Sstevel@tonic-gate 	    PROT_READ | PROT_WRITE, HAT_LOAD_LOCK);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr
11707656SSherry.Moore@Sun.COM 	    & MMU_PAGEOFFSET)));
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate /*
11750Sstevel@tonic-gate  * cvc_iobuf_mapout()
11760Sstevel@tonic-gate  *	Map out the cvc iobuf from kernel space
11770Sstevel@tonic-gate  */
11780Sstevel@tonic-gate static void
cvc_iobuf_mapout(processorid_t cpu_id)11790Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id)
11800Sstevel@tonic-gate {
11810Sstevel@tonic-gate 	caddr_t	cvaddr;
11820Sstevel@tonic-gate 	size_t	num_pages;
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	if ((cvaddr = cvc_iobufp[cpu_id]) == 0) {
11850Sstevel@tonic-gate 		/* already unmapped - return */
11860Sstevel@tonic-gate 		return;
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	/* Calculate how many pages we need to map out */
11900Sstevel@tonic-gate 	num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) +
11917656SSherry.Moore@Sun.COM 	    sizeof (sigb_cvc_t)));
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* Get cvaddr to the start of the page boundary */
11940Sstevel@tonic-gate 	cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK));
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK);
11970Sstevel@tonic-gate 	vmem_free(heap_arena, cvaddr, ptob(num_pages));
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	cvc_iobufp[cpu_id] = NULL;
12000Sstevel@tonic-gate }
1201