xref: /titanic_51/usr/src/uts/sun4u/starfire/cvc/cvc.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
519397407SSherry Moore  * Common Development and Distribution License (the "License").
619397407SSherry Moore  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*07d06da5SSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * MT STREAMS Virtual Console Device Driver
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/processor.h>
357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
367c478bd9Sstevel@tonic-gate #include <sys/open.h>
377c478bd9Sstevel@tonic-gate #include <sys/param.h>
387c478bd9Sstevel@tonic-gate #include <sys/systm.h>
397c478bd9Sstevel@tonic-gate #include <sys/signal.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/user.h>
427c478bd9Sstevel@tonic-gate #include <sys/proc.h>
437c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
447c478bd9Sstevel@tonic-gate #include <sys/uio.h>
457c478bd9Sstevel@tonic-gate #include <sys/buf.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
487c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
497c478bd9Sstevel@tonic-gate #include <sys/stat.h>
507c478bd9Sstevel@tonic-gate #include <sys/stream.h>
517c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
527c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
537c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
547c478bd9Sstevel@tonic-gate #include <sys/tty.h>
557c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h>
567c478bd9Sstevel@tonic-gate #include <sys/poll.h>
577c478bd9Sstevel@tonic-gate #include <sys/debug.h>
587c478bd9Sstevel@tonic-gate #include <sys/conf.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include <sys/starfire.h>
617c478bd9Sstevel@tonic-gate #include <sys/mman.h>
627c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
657c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
667c478bd9Sstevel@tonic-gate #include <sys/errno.h>
677c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
687c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
697c478bd9Sstevel@tonic-gate #include <sys/cvc.h>
707c478bd9Sstevel@tonic-gate #include <sys/cpu_sgn.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate extern void	prom_printf(char *fmt, ...);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static int	cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
757c478bd9Sstevel@tonic-gate static int	cvc_attach(dev_info_t *, ddi_attach_cmd_t);
767c478bd9Sstevel@tonic-gate static int	cvc_detach(dev_info_t *, ddi_detach_cmd_t);
777c478bd9Sstevel@tonic-gate static int	cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
787c478bd9Sstevel@tonic-gate static int	cvc_close(queue_t *, int, cred_t *);
797c478bd9Sstevel@tonic-gate static int	cvc_wput(queue_t *, mblk_t *);
807c478bd9Sstevel@tonic-gate static int	cvc_wsrv(queue_t *);
817c478bd9Sstevel@tonic-gate static void	cvc_ioctl(queue_t *, mblk_t *);
827c478bd9Sstevel@tonic-gate static void	cvc_ack(mblk_t *, mblk_t *, uint_t);
837c478bd9Sstevel@tonic-gate static void	cvc_reioctl(void *);
847c478bd9Sstevel@tonic-gate static void	cvc_input_daemon(void);
857c478bd9Sstevel@tonic-gate static void	cvc_putc(register int);
867c478bd9Sstevel@tonic-gate static void	cvc_flush_buf(void *);
877c478bd9Sstevel@tonic-gate static void	cvc_bbsram_ops(volatile uchar_t *);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static caddr_t	cvc_iobuf_mapin(processorid_t);
907c478bd9Sstevel@tonic-gate static void	cvc_iobuf_mapout(processorid_t);
917c478bd9Sstevel@tonic-gate 	void	cvc_assign_iocpu(processorid_t);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Private copy of devinfo pointer; cvc_info uses it.
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate static dev_info_t	*cvcdip;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * This buffer is used to manage mapping in the I/O buffer that CVC
1007c478bd9Sstevel@tonic-gate  * uses when communicating with the SSP Client (netcon_server) via bbsram.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static caddr_t	cvc_iobufp[NCPU];
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate typedef struct cvc_s {
1057c478bd9Sstevel@tonic-gate 	bufcall_id_t	cvc_wbufcid;
1067c478bd9Sstevel@tonic-gate 	tty_common_t	cvc_tty;
1077c478bd9Sstevel@tonic-gate } cvc_t;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate cvc_t	cvc_common_tty;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static struct module_info cvcm_info = {
1127c478bd9Sstevel@tonic-gate 	1313,		/* mi_idnum Bad luck number  ;-) */
1137c478bd9Sstevel@tonic-gate 	"cvc",		/* mi_idname */
1147c478bd9Sstevel@tonic-gate 	0,		/* mi_minpsz */
1157c478bd9Sstevel@tonic-gate 	INFPSZ,		/* mi_maxpsz */
1167c478bd9Sstevel@tonic-gate 	2048,		/* mi_hiwat */
1177c478bd9Sstevel@tonic-gate 	2048		/* mi_lowat */
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static struct qinit cvcrinit = {
1217c478bd9Sstevel@tonic-gate 	NULL,		/* qi_putp */
1227c478bd9Sstevel@tonic-gate 	NULL,		/* qi_srvp */
1237c478bd9Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
1247c478bd9Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
1257c478bd9Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
1267c478bd9Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
1277c478bd9Sstevel@tonic-gate 	NULL		/* qi_mstat */
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static struct qinit cvcwinit = {
1317c478bd9Sstevel@tonic-gate 	cvc_wput,	/* qi_putp */
1327c478bd9Sstevel@tonic-gate 	cvc_wsrv,	/* qi_srvp */
1337c478bd9Sstevel@tonic-gate 	cvc_open,	/* qi_qopen */
1347c478bd9Sstevel@tonic-gate 	cvc_close,	/* qi_qclose */
1357c478bd9Sstevel@tonic-gate 	NULL,		/* qi_qadmin */
1367c478bd9Sstevel@tonic-gate 	&cvcm_info,	/* qi_minfo */
1377c478bd9Sstevel@tonic-gate 	NULL		/* qi_mstat */
1387c478bd9Sstevel@tonic-gate };
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate struct streamtab	cvcinfo = {
1417c478bd9Sstevel@tonic-gate 	&cvcrinit,	/* st_rdinit */
1427c478bd9Sstevel@tonic-gate 	&cvcwinit,	/* st_wrinit */
1437c478bd9Sstevel@tonic-gate 	NULL,		/* st_muxrinit */
1447c478bd9Sstevel@tonic-gate 	NULL		/* st_muxwrinit */
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate #define	TIMEOUT_DELAY		100000
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate #define	BBSRAM_INPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
1507c478bd9Sstevel@tonic-gate 					+ BBSRAM_INPUT_COUNT_OFF))
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate #define	BBSRAM_OUTPUT_BUF	((volatile char *)(cvc_iobufp[cvc_iocpu] \
1537c478bd9Sstevel@tonic-gate 					+ BBSRAM_OUTPUT_COUNT_OFF))
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate #define	BBSRAM_INPUT_COUNT	(*((volatile short *)BBSRAM_INPUT_BUF))
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate #define	BBSRAM_OUTPUT_COUNT	(*((volatile short *)BBSRAM_OUTPUT_BUF))
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate #define	CVC_OUT_MAXSPIN	1024
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */
1627c478bd9Sstevel@tonic-gate #define	BBSRAM_CONTROL_REG	((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \
1637c478bd9Sstevel@tonic-gate 					+ CVC_IN_SIZE + CVC_OUT_SIZE))
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static krwlock_t	cvclock;	/* lock protecting everything here */
1667c478bd9Sstevel@tonic-gate static queue_t		*cvcinput_q;	/* queue for console input */
1677c478bd9Sstevel@tonic-gate static queue_t		*cvcoutput_q;	/* queue for console output */
1687c478bd9Sstevel@tonic-gate static int		cvc_instance = -1;
1697c478bd9Sstevel@tonic-gate static int		cvc_stopped = 0;
1707c478bd9Sstevel@tonic-gate static int		cvc_suspended = 0;
1717c478bd9Sstevel@tonic-gate static int		cvc_hangup_ok = 0;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate static kthread_id_t	cvc_input_daemon_thread;
1747c478bd9Sstevel@tonic-gate static kmutex_t		cvcmutex;	/* protects input */
1757c478bd9Sstevel@tonic-gate static kmutex_t		cvc_buf_mutex;	/* protects internal output buffer */
1767c478bd9Sstevel@tonic-gate static kmutex_t		cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */
1777c478bd9Sstevel@tonic-gate static int		input_ok = 0;	/* true when stream is valid */
1787c478bd9Sstevel@tonic-gate static int		stop_bbsram = 1; /* true when BBSRAM is not usable */
1797c478bd9Sstevel@tonic-gate static int		stop_timeout = 0;
1807c478bd9Sstevel@tonic-gate static uchar_t		cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */
1817c478bd9Sstevel@tonic-gate static ushort_t		cvc_output_count = 0;
1827c478bd9Sstevel@tonic-gate static int		via_bbsram = 0; /* toggle switch */
1837c478bd9Sstevel@tonic-gate static timeout_id_t	cvc_timeout_id = (timeout_id_t)-1;
1847c478bd9Sstevel@tonic-gate static processorid_t	cvc_iocpu = -1;	/* cpu id of cpu zero */
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
19119397407SSherry Moore 		    nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo,
19219397407SSherry Moore 		    ddi_quiesce_not_supported);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1957c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
19619397407SSherry Moore 	"CVC driver 'cvc'",
1977c478bd9Sstevel@tonic-gate 	&cvcops,	/* driver ops */
1987c478bd9Sstevel@tonic-gate };
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2017c478bd9Sstevel@tonic-gate 	MODREV_1,
2027c478bd9Sstevel@tonic-gate 	&modldrv,
2037c478bd9Sstevel@tonic-gate 	NULL
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate int
2077c478bd9Sstevel@tonic-gate _init(void)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	int	status;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	status = mod_install(&modlinkage);
2127c478bd9Sstevel@tonic-gate 	if (status == 0) {
2137c478bd9Sstevel@tonic-gate 		mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	return (status);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate int
2197c478bd9Sstevel@tonic-gate _fini(void)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	return (EBUSY);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate int
2257c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * DDI glue routines.
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /* ARGSUSED */
2357c478bd9Sstevel@tonic-gate static int
2367c478bd9Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate 	static char	been_here = 0;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (cmd == DDI_RESUME) {
2417c478bd9Sstevel@tonic-gate 		cvc_suspended = 0;
2427c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
2467c478bd9Sstevel@tonic-gate 	if (!been_here) {
2477c478bd9Sstevel@tonic-gate 		been_here = 1;
2487c478bd9Sstevel@tonic-gate 		mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL);
2497c478bd9Sstevel@tonic-gate 		mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
2507c478bd9Sstevel@tonic-gate 		rw_init(&cvclock, NULL, RW_DRIVER, NULL);
2517c478bd9Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
2527c478bd9Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
2537c478bd9Sstevel@tonic-gate 		    drv_usectohz(TIMEOUT_DELAY));
2547c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
2557c478bd9Sstevel@tonic-gate 		cvc_instance = ddi_get_instance(devi);
2567c478bd9Sstevel@tonic-gate 	} else {
2577c478bd9Sstevel@tonic-gate #if defined(DEBUG)
2587c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
2597c478bd9Sstevel@tonic-gate 		    "cvc_attach: called multiple times!! (instance = %d)",
2607c478bd9Sstevel@tonic-gate 		    ddi_get_instance(devi));
2617c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2627c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
2677c478bd9Sstevel@tonic-gate 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2687c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
2697c478bd9Sstevel@tonic-gate 		return (-1);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	cvcdip = devi;
2727c478bd9Sstevel@tonic-gate 	cvcinput_q = NULL;
2737c478bd9Sstevel@tonic-gate 	cvcoutput_q = NULL;
2747c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate static int
2787c478bd9Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	if (cmd == DDI_SUSPEND) {
2817c478bd9Sstevel@tonic-gate 		cvc_suspended = 1;
2827c478bd9Sstevel@tonic-gate 	} else {
2837c478bd9Sstevel@tonic-gate 		if (cmd != DDI_DETACH) {
2847c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		/*
2877c478bd9Sstevel@tonic-gate 		 * XXX this doesn't even begin to address the detach
2887c478bd9Sstevel@tonic-gate 		 * issues - it doesn't terminate the outstanding thread,
2897c478bd9Sstevel@tonic-gate 		 * it doesn't clean up mutexes, kill the timeout routine
2907c478bd9Sstevel@tonic-gate 		 * etc.
2917c478bd9Sstevel@tonic-gate 		 */
2927c478bd9Sstevel@tonic-gate 		if (cvc_instance == ddi_get_instance(dip)) {
2937c478bd9Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /* ARGSUSED */
3007c478bd9Sstevel@tonic-gate static int
3017c478bd9Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	register int error;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	switch (infocmd) {
3067c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3077c478bd9Sstevel@tonic-gate 		if (cvcdip == NULL) {
3087c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
3097c478bd9Sstevel@tonic-gate 		} else {
3107c478bd9Sstevel@tonic-gate 			*result = (void *)cvcdip;
3117c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 		break;
3147c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3157c478bd9Sstevel@tonic-gate 		*result = (void *)0;
3167c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
3177c478bd9Sstevel@tonic-gate 		break;
3187c478bd9Sstevel@tonic-gate 	default:
3197c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	return (error);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /* ARGSUSED */
3257c478bd9Sstevel@tonic-gate static int
3267c478bd9Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	register int		unit = getminor(*devp);
3297c478bd9Sstevel@tonic-gate 	register int		err = 0;
3307c478bd9Sstevel@tonic-gate 	tty_common_t		*tty;
3317c478bd9Sstevel@tonic-gate 	cvc_t			*cp;
3327c478bd9Sstevel@tonic-gate 	static int		input_daemon_started;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (unit != 0)
3357c478bd9Sstevel@tonic-gate 		return (ENXIO);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (q->q_ptr)
3387c478bd9Sstevel@tonic-gate 		return (0);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	cp = (cvc_t *)&cvc_common_tty;
3417c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
3427c478bd9Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
3437c478bd9Sstevel@tonic-gate 	tty = &cp->cvc_tty;
3447c478bd9Sstevel@tonic-gate 	tty->t_readq = q;
3457c478bd9Sstevel@tonic-gate 	tty->t_writeq = WR(q);
3467c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
3477c478bd9Sstevel@tonic-gate 	cvcinput_q = RD(q);		/* save for cvc_redir */
3487c478bd9Sstevel@tonic-gate 	qprocson(q);
3497c478bd9Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
3507c478bd9Sstevel@tonic-gate 	input_ok = 1;
3517c478bd9Sstevel@tonic-gate 	if (!input_daemon_started) {
3527c478bd9Sstevel@tonic-gate 		extern struct cpu	*SIGBCPU;	/* bugid4141050 */
3537c478bd9Sstevel@tonic-gate 		extern cpu_sgnblk_t	*cpu_sgnblkp[];
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		input_daemon_started = 1;
3567c478bd9Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL);
3597c478bd9Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		cvc_input_daemon_thread = thread_create(NULL, 0,
3627c478bd9Sstevel@tonic-gate 		    cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
3637c478bd9Sstevel@tonic-gate 	} else {
3647c478bd9Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate #ifdef lint
3677c478bd9Sstevel@tonic-gate 	cvc_input_daemon_thread = cvc_input_daemon_thread;
3687c478bd9Sstevel@tonic-gate #endif
3697c478bd9Sstevel@tonic-gate 	return (err);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /* ARGSUSED */
3737c478bd9Sstevel@tonic-gate static int
3747c478bd9Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	register int		err = 0;
3777c478bd9Sstevel@tonic-gate 	register cvc_t		*cp;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	mutex_enter(&cvcmutex);
3807c478bd9Sstevel@tonic-gate 	input_ok = 0;
3817c478bd9Sstevel@tonic-gate 	mutex_exit(&cvcmutex);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	cp = q->q_ptr;
3847c478bd9Sstevel@tonic-gate 	if (cp->cvc_wbufcid != 0) {
3857c478bd9Sstevel@tonic-gate 		unbufcall(cp->cvc_wbufcid);
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	ttycommon_close(&cp->cvc_tty);
3887c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr = NULL;
3897c478bd9Sstevel@tonic-gate 	cvcinput_q = NULL;
3907c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cp, sizeof (cvc_t));
3917c478bd9Sstevel@tonic-gate 	qprocsoff(q);
3927c478bd9Sstevel@tonic-gate 	return (err);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate  * cvc_wput()
3987c478bd9Sstevel@tonic-gate  *	cn driver does a strwrite of console output data to rconsvp which
3997c478bd9Sstevel@tonic-gate  *	has been set by consconfig. The data enters the cvc stream at the
4007c478bd9Sstevel@tonic-gate  *	streamhead and flows thru ttycompat and ldterm which have been
4017c478bd9Sstevel@tonic-gate  *	pushed on the stream.  Console output data gets sent out either
4027c478bd9Sstevel@tonic-gate  *	by cvcredir (if there is a cvcd running) or bbsram (if there
4037c478bd9Sstevel@tonic-gate  *	isn't).
4047c478bd9Sstevel@tonic-gate  *	Data is sent to the cvcredir via it's read q which is cvcoutput_q
4057c478bd9Sstevel@tonic-gate  *	and was set in cvc_register().
4067c478bd9Sstevel@tonic-gate  */
4077c478bd9Sstevel@tonic-gate static int
4087c478bd9Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	int		error = 0;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
4137c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 		case M_IOCTL:
4167c478bd9Sstevel@tonic-gate 		case M_CTL:
4177c478bd9Sstevel@tonic-gate 			cvc_ioctl(q, mp);
4187c478bd9Sstevel@tonic-gate 			break;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 		case M_FLUSH:
4217c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW) {
4227c478bd9Sstevel@tonic-gate 				/*
4237c478bd9Sstevel@tonic-gate 				 * Flush our write queue.
4247c478bd9Sstevel@tonic-gate 				 */
4257c478bd9Sstevel@tonic-gate 				flushq(q, FLUSHDATA);
4267c478bd9Sstevel@tonic-gate 				*mp->b_rptr &= ~FLUSHW;
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR) {
4297c478bd9Sstevel@tonic-gate 				flushq(RD(q), FLUSHDATA);
4307c478bd9Sstevel@tonic-gate 				qreply(q, mp);
4317c478bd9Sstevel@tonic-gate 			} else
4327c478bd9Sstevel@tonic-gate 				freemsg(mp);
4337c478bd9Sstevel@tonic-gate 			break;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		case M_STOP:
4367c478bd9Sstevel@tonic-gate 			cvc_stopped = 1;
4377c478bd9Sstevel@tonic-gate 			freemsg(mp);
4387c478bd9Sstevel@tonic-gate 			break;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		case M_START:
4417c478bd9Sstevel@tonic-gate 			cvc_stopped = 0;
4427c478bd9Sstevel@tonic-gate 			freemsg(mp);
4437c478bd9Sstevel@tonic-gate 			qenable(q);  /* Start up delayed messages */
4447c478bd9Sstevel@tonic-gate 			break;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		case M_READ:
4477c478bd9Sstevel@tonic-gate 			/*
4487c478bd9Sstevel@tonic-gate 			 * ldterm handles this (VMIN/VTIME processing).
4497c478bd9Sstevel@tonic-gate 			 */
4507c478bd9Sstevel@tonic-gate 			freemsg(mp);
4517c478bd9Sstevel@tonic-gate 			break;
4527c478bd9Sstevel@tonic-gate 		default:
453*07d06da5SSurya Prakki 			cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%p",
454*07d06da5SSurya Prakki 			    (void *)mp);
4557c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_wput: type = 0x%x",
4567c478bd9Sstevel@tonic-gate 			    mp->b_datap->db_type);
4577c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
4587c478bd9Sstevel@tonic-gate #ifdef lint
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate #endif
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 		case M_DATA:
4637c478bd9Sstevel@tonic-gate 			if (cvc_stopped == 1 || cvc_suspended == 1) {
4647c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
4657c478bd9Sstevel@tonic-gate 				break;
4667c478bd9Sstevel@tonic-gate 			}
4677c478bd9Sstevel@tonic-gate 			if (cvcoutput_q != NULL && !via_bbsram) {
4687c478bd9Sstevel@tonic-gate 				/*
4697c478bd9Sstevel@tonic-gate 				 * Send it up past cvcredir module.
4707c478bd9Sstevel@tonic-gate 				 */
4717c478bd9Sstevel@tonic-gate 				putnext(cvcoutput_q, mp);
4727c478bd9Sstevel@tonic-gate 			} else {
4737c478bd9Sstevel@tonic-gate 				char	*msgp, c;
4747c478bd9Sstevel@tonic-gate 				mblk_t	*mp2 = mp;
4757c478bd9Sstevel@tonic-gate 				int count;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 				while (mp2 != NULL) {
4787c478bd9Sstevel@tonic-gate 					count = mp2->b_wptr - mp2->b_rptr;
4797c478bd9Sstevel@tonic-gate 					msgp = (char *)mp2->b_rptr;
4807c478bd9Sstevel@tonic-gate 					while (count > 0) {
4817c478bd9Sstevel@tonic-gate 						count--;
4827c478bd9Sstevel@tonic-gate 						if ((c = *msgp++) != '\0') {
4837c478bd9Sstevel@tonic-gate 							/* don't print NULs */
4847c478bd9Sstevel@tonic-gate 							cvc_putc(c);
4857c478bd9Sstevel@tonic-gate 						}
4867c478bd9Sstevel@tonic-gate 					}
4877c478bd9Sstevel@tonic-gate 					mp2 = mp2->b_cont;
4887c478bd9Sstevel@tonic-gate 				}
4897c478bd9Sstevel@tonic-gate 				freemsg(mp);
4907c478bd9Sstevel@tonic-gate 			}
4917c478bd9Sstevel@tonic-gate 			break;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 	rw_exit(&cvclock);
4957c478bd9Sstevel@tonic-gate 	return (error);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate static int cvc_wsrv_count = 0;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate static int
5017c478bd9Sstevel@tonic-gate cvc_wsrv(queue_t *q)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	cvc_wsrv_count++;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (cvc_stopped == 1 || cvc_suspended == 1) {
5087c478bd9Sstevel@tonic-gate 		return (0);
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	rw_enter(&cvclock, RW_READER);
5127c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
5137c478bd9Sstevel@tonic-gate 		if (cvcoutput_q != NULL && !via_bbsram) {
5147c478bd9Sstevel@tonic-gate 			/*
5157c478bd9Sstevel@tonic-gate 			 * Send it up past cvcredir module.
5167c478bd9Sstevel@tonic-gate 			 */
5177c478bd9Sstevel@tonic-gate 			putnext(cvcoutput_q, mp);
5187c478bd9Sstevel@tonic-gate 		} else {
5197c478bd9Sstevel@tonic-gate 			char    *msgp, c;
5207c478bd9Sstevel@tonic-gate 			mblk_t  *mp2 = mp;
5217c478bd9Sstevel@tonic-gate 			int count;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			while (mp2 != NULL) {
5247c478bd9Sstevel@tonic-gate 				count = mp2->b_wptr - mp2->b_rptr;
5257c478bd9Sstevel@tonic-gate 				msgp = (char *)mp2->b_rptr;
5267c478bd9Sstevel@tonic-gate 				while (count > 0) {
5277c478bd9Sstevel@tonic-gate 					count--;
5287c478bd9Sstevel@tonic-gate 					if ((c = *msgp++) != '\0') {
5297c478bd9Sstevel@tonic-gate 						/* don't print NULs */
5307c478bd9Sstevel@tonic-gate 						cvc_putc(c);
5317c478bd9Sstevel@tonic-gate 					}
5327c478bd9Sstevel@tonic-gate 				}
5337c478bd9Sstevel@tonic-gate 				mp2 = mp2->b_cont;
5347c478bd9Sstevel@tonic-gate 			}
5357c478bd9Sstevel@tonic-gate 			freemsg(mp);
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 	rw_exit(&cvclock);
5397c478bd9Sstevel@tonic-gate 	return (0);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate  * cvc_ioctl()
5457c478bd9Sstevel@tonic-gate  *	handle normal console ioctls.
5467c478bd9Sstevel@tonic-gate  */
5477c478bd9Sstevel@tonic-gate static void
5487c478bd9Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	register struct iocblk		*iocp;
5517c478bd9Sstevel@tonic-gate 	register tty_common_t		*tty;
5527c478bd9Sstevel@tonic-gate 	register cvc_t			*cp;
5537c478bd9Sstevel@tonic-gate 	int				datasize;
5547c478bd9Sstevel@tonic-gate 	int				error = 0;
5557c478bd9Sstevel@tonic-gate 	mblk_t				*tmp;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	cp = q->q_ptr;
5587c478bd9Sstevel@tonic-gate 	tty = &cp->cvc_tty;
5597c478bd9Sstevel@tonic-gate 	if (tty->t_iocpending != NULL) {
5607c478bd9Sstevel@tonic-gate 		freemsg(tty->t_iocpending);
5617c478bd9Sstevel@tonic-gate 		tty->t_iocpending = NULL;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 	datasize = ttycommon_ioctl(tty, q, mp, &error);
5647c478bd9Sstevel@tonic-gate 	if (datasize != 0) {
5657c478bd9Sstevel@tonic-gate 		if (cp->cvc_wbufcid)
5667c478bd9Sstevel@tonic-gate 			unbufcall(cp->cvc_wbufcid);
5677c478bd9Sstevel@tonic-gate 		cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
5687c478bd9Sstevel@tonic-gate 		return;
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 	if (error < 0) {
5717c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
5727c478bd9Sstevel@tonic-gate 		/*
5737c478bd9Sstevel@tonic-gate 		 * "ttycommon_ioctl" didn't do anything; we process it here.
5747c478bd9Sstevel@tonic-gate 		 */
5757c478bd9Sstevel@tonic-gate 		error = 0;
5767c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		/*
5797c478bd9Sstevel@tonic-gate 		 *  Set modem bit ioctls.  These are NOPs for us, since we
5807c478bd9Sstevel@tonic-gate 		 * dont control any hardware.
5817c478bd9Sstevel@tonic-gate 		 */
5827c478bd9Sstevel@tonic-gate 		case TCSBRK:
5837c478bd9Sstevel@tonic-gate 		case TIOCSBRK:
5847c478bd9Sstevel@tonic-gate 		case TIOCCBRK:
5857c478bd9Sstevel@tonic-gate 		case TIOCMSET:
5867c478bd9Sstevel@tonic-gate 		case TIOCMBIS:
5877c478bd9Sstevel@tonic-gate 		case TIOCMBIC:
5887c478bd9Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT) {
5897c478bd9Sstevel@tonic-gate 				mioc2ack(mp, NULL, 0, 0);
5907c478bd9Sstevel@tonic-gate 			} else {
5917c478bd9Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (int), NULL);
5927c478bd9Sstevel@tonic-gate 			}
5937c478bd9Sstevel@tonic-gate 			/* qreply done below */
5947c478bd9Sstevel@tonic-gate 			break;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 *  Get modem bits, we return 0 in mblk.
5987c478bd9Sstevel@tonic-gate 		 */
5997c478bd9Sstevel@tonic-gate 		case TIOCMGET:
6007c478bd9Sstevel@tonic-gate 			tmp = allocb(sizeof (int), BPRI_MED);
6017c478bd9Sstevel@tonic-gate 			if (tmp == NULL) {
6027c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
6037c478bd9Sstevel@tonic-gate 				return;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 			*(int *)tmp->b_rptr = 0;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT)
6087c478bd9Sstevel@tonic-gate 				mioc2ack(mp, tmp, sizeof (int), 0);
6097c478bd9Sstevel@tonic-gate 			else
6107c478bd9Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (int), NULL, tmp);
6117c478bd9Sstevel@tonic-gate 			/* qreply done below */
6127c478bd9Sstevel@tonic-gate 			break;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 		default:
6157c478bd9Sstevel@tonic-gate 			/*
6167c478bd9Sstevel@tonic-gate 			 * If we don't understand it, it's an error. NAK it.
6177c478bd9Sstevel@tonic-gate 			 */
6187c478bd9Sstevel@tonic-gate 			error = EINVAL;
6197c478bd9Sstevel@tonic-gate 			break;
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	if (error != 0) {
6237c478bd9Sstevel@tonic-gate 		iocp->ioc_error = error;
6247c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 	qreply(q, mp);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate  * cvc_redir()
6337c478bd9Sstevel@tonic-gate  *	called from cvcredir:cvcr_wput() to handle console input
6347c478bd9Sstevel@tonic-gate  *	data. This routine puts the cvcredir write (downstream) data
6357c478bd9Sstevel@tonic-gate  *	onto the cvc read (upstream) queues.  Note that if `mp' is
6367c478bd9Sstevel@tonic-gate  *	an M_IOCTL, then it may be reused by the caller to send back
6377c478bd9Sstevel@tonic-gate  *	an M_IOCACK or M_IOCNAK.
6387c478bd9Sstevel@tonic-gate  */
6397c478bd9Sstevel@tonic-gate int
6407c478bd9Sstevel@tonic-gate cvc_redir(mblk_t *mp)
6417c478bd9Sstevel@tonic-gate {
6427c478bd9Sstevel@tonic-gate 	register struct iocblk	*iocp;
6437c478bd9Sstevel@tonic-gate 	register tty_common_t	*tty;
6447c478bd9Sstevel@tonic-gate 	register cvc_t		*cp;
6457c478bd9Sstevel@tonic-gate 	struct winsize		*ws;
6467c478bd9Sstevel@tonic-gate 	int			error;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (cvcinput_q == NULL) {
6497c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
6507c478bd9Sstevel@tonic-gate 		return (EINVAL);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_IOCTL) {
6547c478bd9Sstevel@tonic-gate 		putnext(cvcinput_q, mp);
6557c478bd9Sstevel@tonic-gate 		return (0);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
6597c478bd9Sstevel@tonic-gate 	if (iocp->ioc_cmd == TIOCSWINSZ) {
6607c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct winsize));
6617c478bd9Sstevel@tonic-gate 		if (error != 0)
6627c478bd9Sstevel@tonic-gate 			return (error);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		ws = (struct winsize *)mp->b_cont->b_rptr;
6657c478bd9Sstevel@tonic-gate 		cp = cvcinput_q->q_ptr;
6667c478bd9Sstevel@tonic-gate 		tty = &cp->cvc_tty;
6677c478bd9Sstevel@tonic-gate 		mutex_enter(&tty->t_excl);
6687c478bd9Sstevel@tonic-gate 		if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) {
6697c478bd9Sstevel@tonic-gate 			tty->t_size = *ws;
6707c478bd9Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
6717c478bd9Sstevel@tonic-gate 			(void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH);
6727c478bd9Sstevel@tonic-gate 		} else
6737c478bd9Sstevel@tonic-gate 			mutex_exit(&tty->t_excl);
6747c478bd9Sstevel@tonic-gate 	} else {
6757c478bd9Sstevel@tonic-gate 		/*
6767c478bd9Sstevel@tonic-gate 		 * It must be a CVC_DISCONNECT, send hangup.
6777c478bd9Sstevel@tonic-gate 		 */
6787c478bd9Sstevel@tonic-gate 		ASSERT(iocp->ioc_cmd == CVC_DISCONNECT);
6797c478bd9Sstevel@tonic-gate 		if (cvc_hangup_ok)
6807c478bd9Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	return (0);
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate  * cvc_register()
6897c478bd9Sstevel@tonic-gate  *	called from cvcredir to register it's queues.  cvc
6907c478bd9Sstevel@tonic-gate  *	receives data from cn via the streamhead and sends it to cvcredir
6917c478bd9Sstevel@tonic-gate  *	via pointers to cvcredir's queues.
6927c478bd9Sstevel@tonic-gate  */
6937c478bd9Sstevel@tonic-gate int
6947c478bd9Sstevel@tonic-gate cvc_register(queue_t *q)
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	int error = -1;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	if (cvcinput_q == NULL)
6997c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
7007c478bd9Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
7017c478bd9Sstevel@tonic-gate 	if (cvcoutput_q == NULL) {
7027c478bd9Sstevel@tonic-gate 		cvcoutput_q = RD(q);  /* Make sure its the upstream q */
7037c478bd9Sstevel@tonic-gate 		qprocson(cvcoutput_q);	/* must be done within cvclock */
7047c478bd9Sstevel@tonic-gate 		error = 0;
7057c478bd9Sstevel@tonic-gate 	} else {
7067c478bd9Sstevel@tonic-gate 		/*
7077c478bd9Sstevel@tonic-gate 		 * cmn_err will call us, so release lock.
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
7107c478bd9Sstevel@tonic-gate 		if (cvcoutput_q == q)
7117c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "cvc_register: duplicate q!");
7127c478bd9Sstevel@tonic-gate 		else
71304580fdfSmathue 			cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p",
714*07d06da5SSurya Prakki 			    (void *)q);
7157c478bd9Sstevel@tonic-gate 		return (error);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	/*
7197c478bd9Sstevel@tonic-gate 	 * Unless "via_bbsram" is set, i/o will be going through cvcd, so
7207c478bd9Sstevel@tonic-gate 	 * stop flushing output to BBSRAM.
7217c478bd9Sstevel@tonic-gate 	 */
7227c478bd9Sstevel@tonic-gate 	if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) {
7237c478bd9Sstevel@tonic-gate 		stop_timeout = 1;
7247c478bd9Sstevel@tonic-gate 		(void) untimeout(cvc_timeout_id);
7257c478bd9Sstevel@tonic-gate 		cvc_timeout_id = (timeout_id_t)-1;
7267c478bd9Sstevel@tonic-gate 		cvc_hangup_ok = 1;
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	rw_exit(&cvclock);
7297c478bd9Sstevel@tonic-gate 	return (error);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate  * cvc_unregister()
7357c478bd9Sstevel@tonic-gate  *	called from cvcredir to clear pointers to its queues.
7367c478bd9Sstevel@tonic-gate  *	cvcredir no longer wants to send or receive data.
7377c478bd9Sstevel@tonic-gate  */
7387c478bd9Sstevel@tonic-gate void
7397c478bd9Sstevel@tonic-gate cvc_unregister(queue_t *q)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate 	rw_enter(&cvclock, RW_WRITER);
7427c478bd9Sstevel@tonic-gate 	if (q == cvcoutput_q) {
7437c478bd9Sstevel@tonic-gate 		qprocsoff(cvcoutput_q);	/* must be done within cvclock */
7447c478bd9Sstevel@tonic-gate 		cvcoutput_q = NULL;
7457c478bd9Sstevel@tonic-gate 	} else {
7467c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
747*07d06da5SSurya Prakki 		cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered",
748*07d06da5SSurya Prakki 		    (void *)q);
7497c478bd9Sstevel@tonic-gate 		return;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/*
7537c478bd9Sstevel@tonic-gate 	 * i/o will not be going through cvcd, start flushing output to
7547c478bd9Sstevel@tonic-gate 	 * BBSRAM
7557c478bd9Sstevel@tonic-gate 	 */
7567c478bd9Sstevel@tonic-gate 	if (cvc_timeout_id == (timeout_id_t)-1) {
7577c478bd9Sstevel@tonic-gate 		stop_timeout = 0;
7587c478bd9Sstevel@tonic-gate 		cvc_timeout_id = timeout(cvc_flush_buf, NULL,
7597c478bd9Sstevel@tonic-gate 		    drv_usectohz(TIMEOUT_DELAY));
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	rw_exit(&cvclock);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate  * cvc_reioctl()
7667c478bd9Sstevel@tonic-gate  *	Retry an "ioctl", now that "bufcall" claims we may be able
7677c478bd9Sstevel@tonic-gate  *	to allocate the buffer we need.
7687c478bd9Sstevel@tonic-gate  */
7697c478bd9Sstevel@tonic-gate static void
7707c478bd9Sstevel@tonic-gate cvc_reioctl(void *unit)
7717c478bd9Sstevel@tonic-gate {
7727c478bd9Sstevel@tonic-gate 	register queue_t	*q;
7737c478bd9Sstevel@tonic-gate 	register mblk_t		*mp;
7747c478bd9Sstevel@tonic-gate 	register cvc_t		*cp = (cvc_t *)unit;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	/*
7777c478bd9Sstevel@tonic-gate 	 * The bufcall is no longer pending.
7787c478bd9Sstevel@tonic-gate 	 */
7797c478bd9Sstevel@tonic-gate 	if (!cp->cvc_wbufcid) {
7807c478bd9Sstevel@tonic-gate 		return;
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 	cp->cvc_wbufcid = 0;
7837c478bd9Sstevel@tonic-gate 	if ((q = cp->cvc_tty.t_writeq) == NULL) {
7847c478bd9Sstevel@tonic-gate 		return;
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 	if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
7877c478bd9Sstevel@tonic-gate 		/* not pending any more */
7887c478bd9Sstevel@tonic-gate 		cp->cvc_tty.t_iocpending = NULL;
7897c478bd9Sstevel@tonic-gate 		cvc_ioctl(q, mp);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate /*
7957c478bd9Sstevel@tonic-gate  * cvc_bbsram_ops()
7967c478bd9Sstevel@tonic-gate  *	Process commands sent to cvc from netcon_server via BBSRAM
7977c478bd9Sstevel@tonic-gate  */
7987c478bd9Sstevel@tonic-gate static void
7997c478bd9Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	uchar_t	 op;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	if ((op = *op_reg) == 0)
8047c478bd9Sstevel@tonic-gate 		return;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex));
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	switch (op) {
8097c478bd9Sstevel@tonic-gate 	case CVC_BBSRAM_BREAK:		/* A console break (L1-A) */
8107c478bd9Sstevel@tonic-gate 		abort_sequence_enter((char *)NULL);
8117c478bd9Sstevel@tonic-gate 		break;
8127c478bd9Sstevel@tonic-gate 	case CVC_BBSRAM_DISCONNECT:	/* Break connection, hang up */
8137c478bd9Sstevel@tonic-gate 		if (cvcinput_q && cvc_hangup_ok)
8147c478bd9Sstevel@tonic-gate 			(void) putnextctl(cvcinput_q, M_HANGUP);
8157c478bd9Sstevel@tonic-gate 		break;
8167c478bd9Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_NET:	/* console via network */
8177c478bd9Sstevel@tonic-gate 		via_bbsram = 0;
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * stop periodic flushing of output to BBSRAM
8207c478bd9Sstevel@tonic-gate 		 * only if cvcredir/cvcd are present
8217c478bd9Sstevel@tonic-gate 		 */
8227c478bd9Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
8237c478bd9Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
8247c478bd9Sstevel@tonic-gate 			stop_timeout = 1;
8257c478bd9Sstevel@tonic-gate 			if (cvc_timeout_id != (timeout_id_t)-1) {
8267c478bd9Sstevel@tonic-gate 				(void) untimeout(cvc_timeout_id);
8277c478bd9Sstevel@tonic-gate 				cvc_timeout_id = (timeout_id_t)-1;
8287c478bd9Sstevel@tonic-gate 			}
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
8317c478bd9Sstevel@tonic-gate 		break;
8327c478bd9Sstevel@tonic-gate 	case CVC_BBSRAM_VIA_BBSRAM:	/* console via bbsram */
8337c478bd9Sstevel@tonic-gate 		via_bbsram = 1;
8347c478bd9Sstevel@tonic-gate 		/* start periodic flushing of ouput to BBSRAM */
8357c478bd9Sstevel@tonic-gate 		rw_enter(&cvclock, RW_WRITER);
8367c478bd9Sstevel@tonic-gate 		if (cvc_timeout_id == (timeout_id_t)-1) {
8377c478bd9Sstevel@tonic-gate 			stop_timeout = 0;
8387c478bd9Sstevel@tonic-gate 			cvc_timeout_id = timeout(cvc_flush_buf,
8397c478bd9Sstevel@tonic-gate 			    NULL, drv_usectohz(TIMEOUT_DELAY));
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
8427c478bd9Sstevel@tonic-gate 		break;
8437c478bd9Sstevel@tonic-gate 	case CVC_BBSRAM_CLOSE_NET:
8447c478bd9Sstevel@tonic-gate 		/*
8457c478bd9Sstevel@tonic-gate 		 * Send a hangup control message upstream to cvcd
8467c478bd9Sstevel@tonic-gate 		 * thru cvcredir.  This is an attempt to close
8477c478bd9Sstevel@tonic-gate 		 * out any existing network connection(if any).
8487c478bd9Sstevel@tonic-gate 		 * cvcoutput_q should point to the cvcredir's read
8497c478bd9Sstevel@tonic-gate 		 * queue.
8507c478bd9Sstevel@tonic-gate 		 */
8517c478bd9Sstevel@tonic-gate 		rw_enter(&cvclock, RW_READER);
8527c478bd9Sstevel@tonic-gate 		if (cvcoutput_q != NULL) {
8537c478bd9Sstevel@tonic-gate 			(void) putnextctl(cvcoutput_q, M_HANGUP);
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 		rw_exit(&cvclock);
8567c478bd9Sstevel@tonic-gate 		break;
8577c478bd9Sstevel@tonic-gate 	default:
8587c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n",
8597c478bd9Sstevel@tonic-gate 		    (unsigned int)op);
8607c478bd9Sstevel@tonic-gate 		break;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 	*op_reg = 0;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate /*
8677c478bd9Sstevel@tonic-gate  * cvc_putc()
8687c478bd9Sstevel@tonic-gate  *	Put a single character out to BBSRAM if space available.
8697c478bd9Sstevel@tonic-gate  */
8707c478bd9Sstevel@tonic-gate static void
8717c478bd9Sstevel@tonic-gate cvc_putc(register int c)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate 	static int	output_lost = 0;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	if (c == '\n')
8767c478bd9Sstevel@tonic-gate 		cvc_putc('\r');
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
8797c478bd9Sstevel@tonic-gate 	/*
8807c478bd9Sstevel@tonic-gate 	 * Just exit if the buffer is already full.
8817c478bd9Sstevel@tonic-gate 	 * It will be up to cvc_flush_buf() to flush the buffer.
8827c478bd9Sstevel@tonic-gate 	 */
8837c478bd9Sstevel@tonic-gate 	if (cvc_output_count == MAX_XFER_OUTPUT) {
8847c478bd9Sstevel@tonic-gate 		output_lost = 1;
8857c478bd9Sstevel@tonic-gate 		mutex_exit(&cvc_buf_mutex);
8867c478bd9Sstevel@tonic-gate 		return;
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 	if (output_lost)
8897c478bd9Sstevel@tonic-gate 		prom_printf("WARNING: overflow of cvc output buffer, "
8907c478bd9Sstevel@tonic-gate 		    "output lost!");
8917c478bd9Sstevel@tonic-gate 	output_lost = 0;
8927c478bd9Sstevel@tonic-gate 	cvc_output_buffer[cvc_output_count] = (unsigned char)c;
8937c478bd9Sstevel@tonic-gate 	cvc_output_count++;
8947c478bd9Sstevel@tonic-gate 	if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) {
8957c478bd9Sstevel@tonic-gate 		/* flush cvc's internal output buffer to BBSRAM */
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		/*
8987c478bd9Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
8997c478bd9Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP
9007c478bd9Sstevel@tonic-gate 		 */
9017c478bd9Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
9027c478bd9Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
9037c478bd9Sstevel@tonic-gate 			if (stop_bbsram) {
9047c478bd9Sstevel@tonic-gate 				mutex_exit(&cvc_buf_mutex);
9057c478bd9Sstevel@tonic-gate 				return;
9067c478bd9Sstevel@tonic-gate 			}
9077c478bd9Sstevel@tonic-gate 			DELAY(1000);
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
9107c478bd9Sstevel@tonic-gate 		    (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count),
9117c478bd9Sstevel@tonic-gate 		    cvc_output_count);
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
9147c478bd9Sstevel@tonic-gate 		cvc_output_count = 0;
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate /*
9217c478bd9Sstevel@tonic-gate  * cvc_flush_buf()
9227c478bd9Sstevel@tonic-gate  *	Flush cvc's internal output buffer to BBSRAM at regular intervals.
9237c478bd9Sstevel@tonic-gate  *	This should only be done if cvcd is not running or the user (via the cvc
9247c478bd9Sstevel@tonic-gate  *	application on the SSP) has requested that i/o go through BBSRAM.
9257c478bd9Sstevel@tonic-gate  */
9267c478bd9Sstevel@tonic-gate /* ARGSUSED */
9277c478bd9Sstevel@tonic-gate static void
9287c478bd9Sstevel@tonic-gate cvc_flush_buf(void *notused)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate 	if (stop_timeout)
9317c478bd9Sstevel@tonic-gate 		return;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
9347c478bd9Sstevel@tonic-gate 	if (cvc_output_count != 0) {
9357c478bd9Sstevel@tonic-gate 		/*
9367c478bd9Sstevel@tonic-gate 		 * Wait for the BBSRAM output buffer to be emptied.
9377c478bd9Sstevel@tonic-gate 		 * This may hang if netcon_server isn't running on the SSP.
9387c478bd9Sstevel@tonic-gate 		 */
9397c478bd9Sstevel@tonic-gate 		int maxspin = CVC_OUT_MAXSPIN;
9407c478bd9Sstevel@tonic-gate 		while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) {
9417c478bd9Sstevel@tonic-gate 			if (stop_bbsram)
9427c478bd9Sstevel@tonic-gate 				goto exit;
9437c478bd9Sstevel@tonic-gate 			DELAY(1000);
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)cvc_output_buffer,
9477c478bd9Sstevel@tonic-gate 		    (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count,
9487c478bd9Sstevel@tonic-gate 		    cvc_output_count);
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 		BBSRAM_OUTPUT_COUNT = cvc_output_count;
9517c478bd9Sstevel@tonic-gate 		cvc_output_count = 0;
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate exit:
9547c478bd9Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
9557c478bd9Sstevel@tonic-gate 	/* rw_enter(&cvclock, RW_WRITER); */
9567c478bd9Sstevel@tonic-gate 	cvc_timeout_id = timeout(cvc_flush_buf, NULL,
9577c478bd9Sstevel@tonic-gate 	    drv_usectohz(TIMEOUT_DELAY));
9587c478bd9Sstevel@tonic-gate 	/* rw_exit(&cvclock); */
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate /*
9637c478bd9Sstevel@tonic-gate  * cvc_getstr()
9647c478bd9Sstevel@tonic-gate  *	Poll BBSRAM for console input while available.
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate static void
9677c478bd9Sstevel@tonic-gate cvc_getstr(char *cp)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	short		count;
9707c478bd9Sstevel@tonic-gate 	volatile char	*lp;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
9737c478bd9Sstevel@tonic-gate 	/* Poll BBSRAM for input */
9747c478bd9Sstevel@tonic-gate 	do {
9757c478bd9Sstevel@tonic-gate 		if (stop_bbsram) {
9767c478bd9Sstevel@tonic-gate 			*cp = '\0';	/* set string to zero-length */
9777c478bd9Sstevel@tonic-gate 			mutex_exit(&cvc_bbsram_input_mutex);
9787c478bd9Sstevel@tonic-gate 			return;
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 		/*
9817c478bd9Sstevel@tonic-gate 		 * Use a smaller delay between checks of BBSRAM for input
9827c478bd9Sstevel@tonic-gate 		 * when cvcd/cvcredir are not running or "via_bbsram" has
9837c478bd9Sstevel@tonic-gate 		 * been set.
9847c478bd9Sstevel@tonic-gate 		 * We don't go away completely when i/o is going through the
9857c478bd9Sstevel@tonic-gate 		 * network via cvcd since a command may be sent via BBSRAM
9867c478bd9Sstevel@tonic-gate 		 * to switch if the network is down or hung.
9877c478bd9Sstevel@tonic-gate 		 */
9887c478bd9Sstevel@tonic-gate 		if ((cvcoutput_q == NULL) || (via_bbsram))
9897c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(100000));
9907c478bd9Sstevel@tonic-gate 		else
9917c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(1000000));
9927c478bd9Sstevel@tonic-gate 		cvc_bbsram_ops(BBSRAM_CONTROL_REG);
9937c478bd9Sstevel@tonic-gate 		count = BBSRAM_INPUT_COUNT;
9947c478bd9Sstevel@tonic-gate 	} while (count == 0);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	lp = BBSRAM_INPUT_BUF - count;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	while (count--) {
9997c478bd9Sstevel@tonic-gate 		*cp++ = *lp++;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	*cp = '\0';
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	BBSRAM_INPUT_COUNT = 0;
10047c478bd9Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate  * cvc_input_daemon()
10107c478bd9Sstevel@tonic-gate  *	this function runs as a separate kernel thread and polls BBSRAM for
10117c478bd9Sstevel@tonic-gate  *	input, and possibly put it on read stream for the console.
10127c478bd9Sstevel@tonic-gate  *	There are two poll rates (implemented in cvc_getstr):
10137c478bd9Sstevel@tonic-gate  *		 100 000 uS (10 Hz) - no cvcd communications || via_bbsram
10147c478bd9Sstevel@tonic-gate  *		1000 000 uS ( 1 Hz) - cvcd communications
10157c478bd9Sstevel@tonic-gate  * 	This continues to run even if there are network console communications
10167c478bd9Sstevel@tonic-gate  *	in order to handle out-of-band signaling.
10177c478bd9Sstevel@tonic-gate  */
10187c478bd9Sstevel@tonic-gate static void
10197c478bd9Sstevel@tonic-gate cvc_input_daemon(void)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	char		linebuf[MAX_XFER_INPUT];
10227c478bd9Sstevel@tonic-gate 	char		*cp;
10237c478bd9Sstevel@tonic-gate 	mblk_t		*mbp;
10247c478bd9Sstevel@tonic-gate 	int		c;
10257c478bd9Sstevel@tonic-gate 	int		dropped_read = 0;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	for (;;) {
10287c478bd9Sstevel@tonic-gate 		cvc_getstr(linebuf);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		mbp = allocb(strlen(linebuf), BPRI_MED);
10317c478bd9Sstevel@tonic-gate 		if (mbp == NULL) {	/* drop it & go on if no buffer */
10327c478bd9Sstevel@tonic-gate 			if (!dropped_read) {
10337c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
10347c478bd9Sstevel@tonic-gate 				    "cvc_input_daemon: "
10357c478bd9Sstevel@tonic-gate 				    "dropping BBSRAM reads\n");
10367c478bd9Sstevel@tonic-gate 			}
10377c478bd9Sstevel@tonic-gate 			dropped_read++;
10387c478bd9Sstevel@tonic-gate 			continue;
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 		if (dropped_read) {
10417c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
10427c478bd9Sstevel@tonic-gate 			    "cvc_input_daemon: dropped %d BBSRAM reads\n",
10437c478bd9Sstevel@tonic-gate 			    dropped_read);
10447c478bd9Sstevel@tonic-gate 			dropped_read = 0;
10457c478bd9Sstevel@tonic-gate 		}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 		for (cp = linebuf; *cp != '\0'; cp++) {
10487c478bd9Sstevel@tonic-gate 			c = (int)*cp;
10497c478bd9Sstevel@tonic-gate 			if (c == '\r')
10507c478bd9Sstevel@tonic-gate 				c = '\n';
10517c478bd9Sstevel@tonic-gate 			c &= 0177;
10527c478bd9Sstevel@tonic-gate 			*mbp->b_wptr = (char)c;
10537c478bd9Sstevel@tonic-gate 			mbp->b_wptr++;
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 		mutex_enter(&cvcmutex);
10567c478bd9Sstevel@tonic-gate 		if (input_ok) {
10577c478bd9Sstevel@tonic-gate 			if (cvcinput_q == NULL) {
10587c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
10597c478bd9Sstevel@tonic-gate 				    "cvc_input_daemon: cvcinput_q is NULL!");
10607c478bd9Sstevel@tonic-gate 			} else {
10617c478bd9Sstevel@tonic-gate 				putnext(cvcinput_q, mbp);
10627c478bd9Sstevel@tonic-gate 			}
10637c478bd9Sstevel@tonic-gate 		} else {
10647c478bd9Sstevel@tonic-gate 			freemsg(mbp);
10657c478bd9Sstevel@tonic-gate 		}
10667c478bd9Sstevel@tonic-gate 		mutex_exit(&cvcmutex);
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate  * cvc_bbsram_stop()
10757c478bd9Sstevel@tonic-gate  *	Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when
10767c478bd9Sstevel@tonic-gate  *	mapping in BBSRAM to a virtual address.
10777c478bd9Sstevel@tonic-gate  */
10787c478bd9Sstevel@tonic-gate static void
10797c478bd9Sstevel@tonic-gate cvc_bbsram_stop(void)
10807c478bd9Sstevel@tonic-gate {
10817c478bd9Sstevel@tonic-gate 	stop_bbsram = 1;
10827c478bd9Sstevel@tonic-gate 	mutex_enter(&cvc_bbsram_input_mutex);
10837c478bd9Sstevel@tonic-gate 	mutex_enter(&cvc_buf_mutex);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate  * cvc_bbsram_start()
10897c478bd9Sstevel@tonic-gate  *	Allow accesses to BBSRAM, used by cvc_assign_iocpu() after
10907c478bd9Sstevel@tonic-gate  *	BBSRAM has been mapped to a virtual address.
10917c478bd9Sstevel@tonic-gate  */
10927c478bd9Sstevel@tonic-gate static void
10937c478bd9Sstevel@tonic-gate cvc_bbsram_start(void)
10947c478bd9Sstevel@tonic-gate {
10957c478bd9Sstevel@tonic-gate 	stop_bbsram = 0;
10967c478bd9Sstevel@tonic-gate 	mutex_exit(&cvc_buf_mutex);
10977c478bd9Sstevel@tonic-gate 	mutex_exit(&cvc_bbsram_input_mutex);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate /*
11027c478bd9Sstevel@tonic-gate  * cvc_assign_iocpu()
11037c478bd9Sstevel@tonic-gate  *	Map in BBSRAM to a virtual address
11047c478bd9Sstevel@tonic-gate  *	This called by the kernel with the cpu id of cpu zero.
11057c478bd9Sstevel@tonic-gate  */
11067c478bd9Sstevel@tonic-gate void
11077c478bd9Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu)
11087c478bd9Sstevel@tonic-gate {
11097c478bd9Sstevel@tonic-gate 	processorid_t	oldcpu = cvc_iocpu;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if (newcpu == oldcpu)
11127c478bd9Sstevel@tonic-gate 		return;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu);
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	cvc_bbsram_stop();
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	cvc_iocpu = newcpu;
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	cvc_bbsram_start();
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	if (oldcpu != -1)
11237c478bd9Sstevel@tonic-gate 		cvc_iobuf_mapout(oldcpu);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate /*
11287c478bd9Sstevel@tonic-gate  * cvc_iobuf_mapin()
11297c478bd9Sstevel@tonic-gate  *	Map in the cvc bbsram i/o buffer into kernel space.
11307c478bd9Sstevel@tonic-gate  */
11317c478bd9Sstevel@tonic-gate static caddr_t
11327c478bd9Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id)
11337c478bd9Sstevel@tonic-gate {
11347c478bd9Sstevel@tonic-gate 	caddr_t	cvaddr;
11357c478bd9Sstevel@tonic-gate 	uint64_t cvc_iobuf_physaddr;
11367c478bd9Sstevel@tonic-gate 	pfn_t pfn;
11377c478bd9Sstevel@tonic-gate 	uint_t num_pages;
11387c478bd9Sstevel@tonic-gate 	extern cpu_sgnblk_t *cpu_sgnblkp[];
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	ASSERT(cpu_sgnblkp[cpu_id] != NULL);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	/*
11437c478bd9Sstevel@tonic-gate 	 * First construct the physical base address of the bbsram
11447c478bd9Sstevel@tonic-gate 	 * in Starfire PSI space associated with this cpu in question.
11457c478bd9Sstevel@tonic-gate 	 */
11467c478bd9Sstevel@tonic-gate 	cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/*
11497c478bd9Sstevel@tonic-gate 	 * Next add the cvc i/o buffer offset obtained from the
11507c478bd9Sstevel@tonic-gate 	 * sigblock to get cvc iobuf physical address
11517c478bd9Sstevel@tonic-gate 	 */
11527c478bd9Sstevel@tonic-gate 	cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	/* Get the page frame number */
11557c478bd9Sstevel@tonic-gate 	pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	/* Calculate how many pages we need to map in */
11587c478bd9Sstevel@tonic-gate 	num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr
11597c478bd9Sstevel@tonic-gate 	    & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t)));
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	/*
11627c478bd9Sstevel@tonic-gate 	 * Map in the cvc iobuf
11637c478bd9Sstevel@tonic-gate 	 */
11647c478bd9Sstevel@tonic-gate 	cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn,
11677c478bd9Sstevel@tonic-gate 	    PROT_READ | PROT_WRITE, HAT_LOAD_LOCK);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr
11707c478bd9Sstevel@tonic-gate 	    & MMU_PAGEOFFSET)));
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate /*
11757c478bd9Sstevel@tonic-gate  * cvc_iobuf_mapout()
11767c478bd9Sstevel@tonic-gate  *	Map out the cvc iobuf from kernel space
11777c478bd9Sstevel@tonic-gate  */
11787c478bd9Sstevel@tonic-gate static void
11797c478bd9Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate 	caddr_t	cvaddr;
11827c478bd9Sstevel@tonic-gate 	size_t	num_pages;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if ((cvaddr = cvc_iobufp[cpu_id]) == 0) {
11857c478bd9Sstevel@tonic-gate 		/* already unmapped - return */
11867c478bd9Sstevel@tonic-gate 		return;
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/* Calculate how many pages we need to map out */
11907c478bd9Sstevel@tonic-gate 	num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) +
11917c478bd9Sstevel@tonic-gate 	    sizeof (sigb_cvc_t)));
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	/* Get cvaddr to the start of the page boundary */
11947c478bd9Sstevel@tonic-gate 	cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK));
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK);
11977c478bd9Sstevel@tonic-gate 	vmem_free(heap_arena, cvaddr, ptob(num_pages));
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	cvc_iobufp[cpu_id] = NULL;
12007c478bd9Sstevel@tonic-gate }
1201