xref: /titanic_41/usr/src/uts/sun4u/starcat/io/cvc.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * 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.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
21*07d06da5SSurya Prakki 
2203831d35Sstevel /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel /*
2903831d35Sstevel  * MT STREAMS Virtual Console Device Driver
3003831d35Sstevel  */
3103831d35Sstevel 
3203831d35Sstevel #include <sys/types.h>
3303831d35Sstevel #include <sys/open.h>
3403831d35Sstevel #include <sys/param.h>
3503831d35Sstevel #include <sys/systm.h>
3603831d35Sstevel #include <sys/signal.h>
3703831d35Sstevel #include <sys/cred.h>
3803831d35Sstevel #include <sys/user.h>
3903831d35Sstevel #include <sys/proc.h>
4003831d35Sstevel #include <sys/disp.h>
4103831d35Sstevel #include <sys/vnode.h>
4203831d35Sstevel #include <sys/uio.h>
4303831d35Sstevel #include <sys/buf.h>
4403831d35Sstevel #include <sys/file.h>
4503831d35Sstevel #include <sys/kmem.h>
4603831d35Sstevel #include <sys/stat.h>
4703831d35Sstevel #include <sys/stream.h>
4803831d35Sstevel #include <sys/stropts.h>
4903831d35Sstevel #include <sys/strsubr.h>
5003831d35Sstevel #include <sys/strsun.h>
5103831d35Sstevel #include <sys/tty.h>
5203831d35Sstevel #include <sys/ptyvar.h>
5303831d35Sstevel #include <sys/poll.h>
5403831d35Sstevel #include <sys/debug.h>
5503831d35Sstevel #include <sys/conf.h>
5603831d35Sstevel #include <sys/ddi.h>
5703831d35Sstevel #include <sys/sunddi.h>
5803831d35Sstevel #include <sys/errno.h>
5903831d35Sstevel #include <sys/modctl.h>
6003831d35Sstevel 
6103831d35Sstevel #include <sys/sc_cvc.h>
6203831d35Sstevel #include <sys/sc_cvcio.h>
6303831d35Sstevel #include <sys/iosramio.h>
6403831d35Sstevel 
6503831d35Sstevel static int	cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
6603831d35Sstevel static int	cvc_attach(dev_info_t *, ddi_attach_cmd_t);
6703831d35Sstevel static int	cvc_detach(dev_info_t *, ddi_detach_cmd_t);
6803831d35Sstevel static int	cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
6903831d35Sstevel static int	cvc_close(queue_t *, int, cred_t *);
7003831d35Sstevel static int	cvc_wput(queue_t *, mblk_t *);
7103831d35Sstevel static int	cvc_wsrv(queue_t *);
7203831d35Sstevel static void	cvc_ioctl(queue_t *, mblk_t *);
7303831d35Sstevel static void	cvc_reioctl(void *);
7403831d35Sstevel static void	cvc_input_daemon(void);
7503831d35Sstevel static void	cvc_send_to_iosram(mblk_t **chainpp);
7603831d35Sstevel static void	cvc_flush_queue(void *);
7703831d35Sstevel static void	cvc_iosram_ops(uint8_t);
7803831d35Sstevel static void	cvc_getstr(char *cp);
7903831d35Sstevel static void	cvc_win_resize(int clear_flag);
8003831d35Sstevel 
8103831d35Sstevel #define	ESUCCESS 0
8203831d35Sstevel #ifndef	TRUE
8303831d35Sstevel #define	TRUE	1
8403831d35Sstevel #define	FALSE	0
8503831d35Sstevel #endif
8603831d35Sstevel 
8703831d35Sstevel /*
8803831d35Sstevel  * Private copy of devinfo pointer; cvc_info uses it.
8903831d35Sstevel  */
9003831d35Sstevel static dev_info_t	*cvcdip;
9103831d35Sstevel 
9203831d35Sstevel /*
9303831d35Sstevel  * This structure reflects the layout of data in CONI and CONO.  If you are
9403831d35Sstevel  * going to add fields that don't get written into those chunks, be sure to
9503831d35Sstevel  * place them _after_ the buffer field.
9603831d35Sstevel  */
9703831d35Sstevel typedef struct cvc_buf {
9803831d35Sstevel 	ushort_t	count;
9903831d35Sstevel 	uchar_t		buffer[MAX_XFER_COUTPUT];
10003831d35Sstevel } cvc_buf_t;
10103831d35Sstevel 
10203831d35Sstevel typedef struct cvc_s {
10303831d35Sstevel 	bufcall_id_t	cvc_wbufcid;
10403831d35Sstevel 	tty_common_t	cvc_tty;
10503831d35Sstevel } cvc_t;
10603831d35Sstevel 
10703831d35Sstevel cvc_t	cvc_common_tty;
10803831d35Sstevel 
10903831d35Sstevel static struct module_info cvcm_info = {
11003831d35Sstevel 	1313,		/* mi_idnum Bad luck number  ;-) */
11103831d35Sstevel 	"cvc",		/* mi_idname */
11203831d35Sstevel 	0,		/* mi_minpsz */
11303831d35Sstevel 	INFPSZ,		/* mi_maxpsz */
11403831d35Sstevel 	2048,		/* mi_hiwat */
11503831d35Sstevel 	2048		/* mi_lowat */
11603831d35Sstevel };
11703831d35Sstevel 
11803831d35Sstevel static struct qinit cvcrinit = {
11903831d35Sstevel 	NULL,		/* qi_putp */
12003831d35Sstevel 	NULL,		/* qi_srvp */
12103831d35Sstevel 	cvc_open,	/* qi_qopen */
12203831d35Sstevel 	cvc_close,	/* qi_qclose */
12303831d35Sstevel 	NULL,		/* qi_qadmin */
12403831d35Sstevel 	&cvcm_info,	/* qi_minfo */
12503831d35Sstevel 	NULL		/* qi_mstat */
12603831d35Sstevel };
12703831d35Sstevel 
12803831d35Sstevel static struct qinit cvcwinit = {
12903831d35Sstevel 	cvc_wput,	/* qi_putp */
13003831d35Sstevel 	cvc_wsrv,	/* qi_srvp */
13103831d35Sstevel 	cvc_open,	/* qi_qopen */
13203831d35Sstevel 	cvc_close,	/* qi_qclose */
13303831d35Sstevel 	NULL,		/* qi_qadmin */
13403831d35Sstevel 	&cvcm_info,	/* qi_minfo */
13503831d35Sstevel 	NULL		/* qi_mstat */
13603831d35Sstevel };
13703831d35Sstevel 
13803831d35Sstevel struct streamtab	cvcinfo = {
13903831d35Sstevel 	&cvcrinit,	/* st_rdinit */
14003831d35Sstevel 	&cvcwinit,	/* st_wrinit */
14103831d35Sstevel 	NULL,		/* st_muxrinit */
14203831d35Sstevel 	NULL		/* st_muxwrinit */
14303831d35Sstevel };
14403831d35Sstevel 
14503831d35Sstevel static krwlock_t	cvclock;	/* lock protecting everything here */
14603831d35Sstevel static queue_t		*cvcinput_q;	/* queue for console input */
14703831d35Sstevel static queue_t		*cvcoutput_q;	/* queue for console output */
14803831d35Sstevel static int		cvc_instance = -1;
14903831d35Sstevel static int		cvc_stopped = 0;
15003831d35Sstevel static int		cvc_suspended = 0;
15103831d35Sstevel 
15203831d35Sstevel kthread_id_t		cvc_input_daemon_thread; /* just to aid debugging */
15303831d35Sstevel static kmutex_t		cvcmutex;	/* protects input */
15403831d35Sstevel static kmutex_t		cvc_iosram_input_mutex; /* protects IOSRAM inp buff */
15503831d35Sstevel static int		input_ok = 0;	/* true when stream is valid */
15603831d35Sstevel 
15703831d35Sstevel static int		via_iosram = 0; /* toggle switch */
15803831d35Sstevel static timeout_id_t	cvc_timeout_id = (timeout_id_t)-1;
15903831d35Sstevel static int		input_daemon_started = 0;
16003831d35Sstevel 
16103831d35Sstevel /* debugging functions */
16203831d35Sstevel #ifdef DEBUG
16303831d35Sstevel uint32_t cvc_dbg_flags = 0x0;
16403831d35Sstevel static void cvc_dbg(uint32_t flag, char *fmt,
16503831d35Sstevel 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
16603831d35Sstevel #endif
16703831d35Sstevel 
16803831d35Sstevel /*
16903831d35Sstevel  * Module linkage information for the kernel.
17003831d35Sstevel  */
17103831d35Sstevel 
17203831d35Sstevel DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
17319397407SSherry Moore 		    nodev, cvc_info, (D_NEW|D_MTPERQ|D_MP), &cvcinfo,
17419397407SSherry Moore 		    ddi_quiesce_not_supported);
17503831d35Sstevel 
17603831d35Sstevel extern int nodev(), nulldev();
17703831d35Sstevel extern struct mod_ops mod_driverops;
17803831d35Sstevel 
17903831d35Sstevel static struct modldrv modldrv = {
18003831d35Sstevel 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
18119397407SSherry Moore 	"CVC driver 'cvc'",
18203831d35Sstevel 	&cvcops,	/* driver ops */
18303831d35Sstevel };
18403831d35Sstevel 
18503831d35Sstevel static struct modlinkage modlinkage = {
18603831d35Sstevel 	MODREV_1,
18703831d35Sstevel 	&modldrv,
18803831d35Sstevel 	NULL
18903831d35Sstevel };
19003831d35Sstevel 
19103831d35Sstevel int
_init()19203831d35Sstevel _init()
19303831d35Sstevel {
19403831d35Sstevel 	int	status;
19503831d35Sstevel 
19603831d35Sstevel 	status = mod_install(&modlinkage);
19703831d35Sstevel 	if (status == 0) {
19803831d35Sstevel 		mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
19903831d35Sstevel 	}
20003831d35Sstevel 	return (status);
20103831d35Sstevel }
20203831d35Sstevel 
20303831d35Sstevel int
_fini()20403831d35Sstevel _fini()
20503831d35Sstevel {
20603831d35Sstevel 	return (EBUSY);
20703831d35Sstevel }
20803831d35Sstevel 
20903831d35Sstevel int
_info(struct modinfo * modinfop)21003831d35Sstevel _info(struct modinfo *modinfop)
21103831d35Sstevel {
21203831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
21303831d35Sstevel }
21403831d35Sstevel 
21503831d35Sstevel /*
21603831d35Sstevel  * DDI glue routines.
21703831d35Sstevel  */
21803831d35Sstevel 
21903831d35Sstevel /* ARGSUSED */
22003831d35Sstevel static int
cvc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)22103831d35Sstevel cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
22203831d35Sstevel {
22303831d35Sstevel 	static char	been_here = 0;
22403831d35Sstevel 
22503831d35Sstevel 	if (cmd == DDI_RESUME) {
22603831d35Sstevel 		cvc_suspended = 0;
22703831d35Sstevel 		if (cvcinput_q != NULL) {
22803831d35Sstevel 			qenable(WR(cvcinput_q));
22903831d35Sstevel 		}
23003831d35Sstevel 		return (DDI_SUCCESS);
23103831d35Sstevel 	}
23203831d35Sstevel 
23303831d35Sstevel 	mutex_enter(&cvcmutex);
23403831d35Sstevel 	if (!been_here) {
23503831d35Sstevel 		been_here = 1;
23603831d35Sstevel 		mutex_init(&cvc_iosram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
23703831d35Sstevel 		rw_init(&cvclock, NULL, RW_DRIVER, NULL);
23803831d35Sstevel 		cvc_instance = ddi_get_instance(devi);
23903831d35Sstevel 	} else {
24003831d35Sstevel #if defined(DEBUG)
24103831d35Sstevel 		cmn_err(CE_NOTE,
24203831d35Sstevel 		    "cvc_attach: called multiple times!! (instance = %d)",
24303831d35Sstevel 		    ddi_get_instance(devi));
24403831d35Sstevel #endif /* DEBUG */
24503831d35Sstevel 		mutex_exit(&cvcmutex);
24603831d35Sstevel 		return (DDI_SUCCESS);
24703831d35Sstevel 	}
24803831d35Sstevel 	mutex_exit(&cvcmutex);
24903831d35Sstevel 
25003831d35Sstevel 	if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
25103831d35Sstevel 	    0, NULL, NULL) == DDI_FAILURE) {
25203831d35Sstevel 		ddi_remove_minor_node(devi, NULL);
25303831d35Sstevel 		return (-1);
25403831d35Sstevel 	}
25503831d35Sstevel 	cvcdip = devi;
25603831d35Sstevel 	cvcinput_q = NULL;
25703831d35Sstevel 	cvcoutput_q = NULL;
25803831d35Sstevel 
25903831d35Sstevel 	CVC_DBG0(CVC_DBG_ATTACH, "Attached");
26003831d35Sstevel 
26103831d35Sstevel 	return (DDI_SUCCESS);
26203831d35Sstevel }
26303831d35Sstevel 
26403831d35Sstevel static int
cvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)26503831d35Sstevel cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
26603831d35Sstevel {
26703831d35Sstevel 	if (cmd == DDI_SUSPEND) {
26803831d35Sstevel 		cvc_suspended = 1;
26903831d35Sstevel 	} else {
27003831d35Sstevel 		if (cmd != DDI_DETACH) {
27103831d35Sstevel 			return (DDI_FAILURE);
27203831d35Sstevel 		}
27303831d35Sstevel 		/*
27403831d35Sstevel 		 * XXX this doesn't even begin to address the detach
27503831d35Sstevel 		 * issues - it doesn't terminate the outstanding thread,
27603831d35Sstevel 		 * it doesn't clean up mutexes, kill the timeout routine
27703831d35Sstevel 		 * etc.
27803831d35Sstevel 		 */
27903831d35Sstevel 		if (cvc_instance == ddi_get_instance(dip)) {
28003831d35Sstevel 			ddi_remove_minor_node(dip, NULL);
28103831d35Sstevel 		}
28203831d35Sstevel 	}
28303831d35Sstevel 
28403831d35Sstevel 	CVC_DBG0(CVC_DBG_DETACH, "Detached");
28503831d35Sstevel 
28603831d35Sstevel 	return (DDI_SUCCESS);
28703831d35Sstevel }
28803831d35Sstevel 
28903831d35Sstevel /* ARGSUSED */
29003831d35Sstevel static int
cvc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)29103831d35Sstevel cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
29203831d35Sstevel {
29303831d35Sstevel 	register int error;
29403831d35Sstevel 
29503831d35Sstevel 	switch (infocmd) {
29603831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
29703831d35Sstevel 		if (cvcdip == NULL) {
29803831d35Sstevel 			error = DDI_FAILURE;
29903831d35Sstevel 		} else {
30003831d35Sstevel 			*result = (void *)cvcdip;
30103831d35Sstevel 			error = DDI_SUCCESS;
30203831d35Sstevel 		}
30303831d35Sstevel 		break;
30403831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
30503831d35Sstevel 		*result = (void *)0;
30603831d35Sstevel 		error = DDI_SUCCESS;
30703831d35Sstevel 		break;
30803831d35Sstevel 	default:
30903831d35Sstevel 		error = DDI_FAILURE;
31003831d35Sstevel 	}
31103831d35Sstevel 	return (error);
31203831d35Sstevel }
31303831d35Sstevel 
31403831d35Sstevel /* ARGSUSED */
31503831d35Sstevel static int
cvc_open(register queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)31603831d35Sstevel cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
31703831d35Sstevel {
31803831d35Sstevel 	register int		unit = getminor(*devp);
31903831d35Sstevel 	register int		err = DDI_SUCCESS;
32003831d35Sstevel 	tty_common_t		*tty;
32103831d35Sstevel 	cvc_t			*cp;
32203831d35Sstevel 
32303831d35Sstevel 	if (unit != 0)
32403831d35Sstevel 		return (ENXIO);
32503831d35Sstevel 
32603831d35Sstevel 	if (q->q_ptr)
32703831d35Sstevel 		return (0);
32803831d35Sstevel 
32903831d35Sstevel 	cp = (cvc_t *)&cvc_common_tty;
33003831d35Sstevel 	bzero((caddr_t)cp, sizeof (cvc_t));
33103831d35Sstevel 	cp->cvc_wbufcid = 0;
33203831d35Sstevel 	tty = &cp->cvc_tty;
33303831d35Sstevel 	tty->t_readq = q;
33403831d35Sstevel 	tty->t_writeq = WR(q);
33503831d35Sstevel 	WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
33603831d35Sstevel 	cvcinput_q = RD(q);		/* save for cvc_redir */
33703831d35Sstevel 	qprocson(q);
33803831d35Sstevel 	mutex_enter(&cvcmutex);
33903831d35Sstevel 	input_ok = 1;
34003831d35Sstevel 
34103831d35Sstevel 	/*
34203831d35Sstevel 	 * Start the thread that handles input polling if it hasn't been started
34303831d35Sstevel 	 * previously.
34403831d35Sstevel 	 */
34503831d35Sstevel 	if (!input_daemon_started) {
34603831d35Sstevel 		input_daemon_started = 1;
34703831d35Sstevel 		mutex_exit(&cvcmutex);
34803831d35Sstevel 
34903831d35Sstevel 		cvc_input_daemon_thread = thread_create(NULL, 0,
35003831d35Sstevel 		    cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
35103831d35Sstevel 		CVC_DBG0(CVC_DBG_IOSRAM_RD, "Started input daemon");
35203831d35Sstevel 	} else {
35303831d35Sstevel 		mutex_exit(&cvcmutex);
35403831d35Sstevel 	}
35503831d35Sstevel 
35603831d35Sstevel 	/*
35703831d35Sstevel 	 * Set the console window size.
35803831d35Sstevel 	 */
35903831d35Sstevel 	mutex_enter(&cvc_iosram_input_mutex);
36003831d35Sstevel 	cvc_win_resize(FALSE);
36103831d35Sstevel 	mutex_exit(&cvc_iosram_input_mutex);
36203831d35Sstevel 
36303831d35Sstevel 	CVC_DBG0(CVC_DBG_OPEN, "Plumbed successfully");
36403831d35Sstevel 
36503831d35Sstevel 	return (err);
36603831d35Sstevel }
36703831d35Sstevel 
36803831d35Sstevel /* ARGSUSED */
36903831d35Sstevel static int
cvc_close(queue_t * q,int flag,cred_t * crp)37003831d35Sstevel cvc_close(queue_t *q, int flag, cred_t *crp)
37103831d35Sstevel {
37203831d35Sstevel 	register int		err = DDI_SUCCESS;
37303831d35Sstevel 	register cvc_t		*cp;
37403831d35Sstevel 
37503831d35Sstevel 	mutex_enter(&cvcmutex);
37603831d35Sstevel 	input_ok = 0;
37703831d35Sstevel 	mutex_exit(&cvcmutex);
37803831d35Sstevel 
37903831d35Sstevel 	cp = q->q_ptr;
38003831d35Sstevel 	if (cp->cvc_wbufcid != 0) {
38103831d35Sstevel 		unbufcall(cp->cvc_wbufcid);
38203831d35Sstevel 	}
38303831d35Sstevel 	ttycommon_close(&cp->cvc_tty);
38403831d35Sstevel 	WR(q)->q_ptr = q->q_ptr = NULL;
38503831d35Sstevel 	cvcinput_q = NULL;
38603831d35Sstevel 	bzero((caddr_t)cp, sizeof (cvc_t));
38703831d35Sstevel 	qprocsoff(q);
38803831d35Sstevel 
38903831d35Sstevel 	CVC_DBG0(CVC_DBG_CLOSE, "Un-plumbed successfully");
39003831d35Sstevel 
39103831d35Sstevel 	return (err);
39203831d35Sstevel }
39303831d35Sstevel 
39403831d35Sstevel 
39503831d35Sstevel /*
39603831d35Sstevel  * cvc_wput()
39703831d35Sstevel  *	cn driver does a strwrite of console output data to rconsvp which has
39803831d35Sstevel  *	been set by consconfig. The data enters the cvc stream at the streamhead
39903831d35Sstevel  *	and flows thru ttycompat and ldterm which have been pushed on the
40003831d35Sstevel  *	stream.  Console output data gets sent out either to cvcredir, if the
40103831d35Sstevel  *	network path is available and selected, or to IOSRAM otherwise.  Data is
40203831d35Sstevel  *	sent to cvcredir via its read queue (cvcoutput_q, which gets set in
40303831d35Sstevel  *	cvc_register()).  If the IOSRAM path is selected, or if previous mblks
40403831d35Sstevel  *	are currently queued up for processing, the new mblk will be queued
40503831d35Sstevel  *	and handled later on by cvc_wsrv.
40603831d35Sstevel  */
40703831d35Sstevel static int
cvc_wput(queue_t * q,mblk_t * mp)40803831d35Sstevel cvc_wput(queue_t *q, mblk_t *mp)
40903831d35Sstevel {
41003831d35Sstevel 	int		error = 0;
41103831d35Sstevel 
41203831d35Sstevel 	rw_enter(&cvclock, RW_READER);
41303831d35Sstevel 
41403831d35Sstevel 	CVC_DBG2(CVC_DBG_WPUT, "mp 0x%x db_type 0x%x",
41503831d35Sstevel 	    mp, mp->b_datap->db_type);
41603831d35Sstevel 
41703831d35Sstevel 	switch (mp->b_datap->db_type) {
41803831d35Sstevel 
41903831d35Sstevel 		case M_IOCTL:
42003831d35Sstevel 		case M_CTL: {
42103831d35Sstevel 			struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
42203831d35Sstevel 
42303831d35Sstevel 			switch (iocp->ioc_cmd) {
42403831d35Sstevel 				/*
42503831d35Sstevel 				 * These ioctls are only supposed to be
42603831d35Sstevel 				 * processed after everything else that is
42703831d35Sstevel 				 * already queued awaiting processing, so throw
42803831d35Sstevel 				 * them on the queue and let cvc_wsrv handle
42903831d35Sstevel 				 * them.
43003831d35Sstevel 				 */
43103831d35Sstevel 				case TCSETSW:
43203831d35Sstevel 				case TCSETSF:
43303831d35Sstevel 				case TCSETAW:
43403831d35Sstevel 				case TCSETAF:
43503831d35Sstevel 				case TCSBRK:
436*07d06da5SSurya Prakki 					(void) putq(q, mp);
43703831d35Sstevel 					break;
43803831d35Sstevel 
43903831d35Sstevel 				default:
44003831d35Sstevel 					cvc_ioctl(q, mp);
44103831d35Sstevel 			}
44203831d35Sstevel 			break;
44303831d35Sstevel 		}
44403831d35Sstevel 
44503831d35Sstevel 		case M_FLUSH:
44603831d35Sstevel 			if (*mp->b_rptr & FLUSHW) {
44703831d35Sstevel 				/*
44803831d35Sstevel 				 * Flush our write queue.
44903831d35Sstevel 				 */
45003831d35Sstevel 				flushq(q, FLUSHDATA);
45103831d35Sstevel 				*mp->b_rptr &= ~FLUSHW;
45203831d35Sstevel 			}
45303831d35Sstevel 			if (*mp->b_rptr & FLUSHR) {
45403831d35Sstevel 				flushq(RD(q), FLUSHDATA);
45503831d35Sstevel 				qreply(q, mp);
45603831d35Sstevel 			} else
45703831d35Sstevel 				freemsg(mp);
45803831d35Sstevel 			break;
45903831d35Sstevel 
46003831d35Sstevel 		case M_STOP:
46103831d35Sstevel 			cvc_stopped = 1;
46203831d35Sstevel 			freemsg(mp);
46303831d35Sstevel 			break;
46403831d35Sstevel 
46503831d35Sstevel 		case M_START:
46603831d35Sstevel 			cvc_stopped = 0;
46703831d35Sstevel 			freemsg(mp);
46803831d35Sstevel 			qenable(q);  /* Start up delayed messages */
46903831d35Sstevel 			break;
47003831d35Sstevel 
47103831d35Sstevel 		case M_READ:
47203831d35Sstevel 			/*
47303831d35Sstevel 			 * ldterm handles this (VMIN/VTIME processing).
47403831d35Sstevel 			 */
47503831d35Sstevel 			freemsg(mp);
47603831d35Sstevel 			break;
47703831d35Sstevel 
47803831d35Sstevel 		default:
47903831d35Sstevel 			cmn_err(CE_WARN, "cvc_wput: unexpected mblk type - mp ="
480*07d06da5SSurya Prakki 			    " 0x%p, type = 0x%x", (void *)mp,
481*07d06da5SSurya Prakki 			    mp->b_datap->db_type);
48203831d35Sstevel 			freemsg(mp);
48303831d35Sstevel 			break;
48403831d35Sstevel 
48503831d35Sstevel 		case M_DATA:
48603831d35Sstevel 			/*
48703831d35Sstevel 			 * If there are other mblks queued up for transmission,
48803831d35Sstevel 			 * or we're using IOSRAM either because cvcredir hasn't
48903831d35Sstevel 			 * registered yet or because we were configured that
49003831d35Sstevel 			 * way, or cvc has been stopped or suspended, place this
49103831d35Sstevel 			 * mblk on the input queue for future processing.
49203831d35Sstevel 			 * Otherwise, hand it off to cvcredir for transmission
49303831d35Sstevel 			 * via the network.
49403831d35Sstevel 			 */
49503831d35Sstevel 			if (q->q_first != NULL || cvcoutput_q == NULL ||
49603831d35Sstevel 			    via_iosram || cvc_stopped == 1 ||
49703831d35Sstevel 			    cvc_suspended == 1) {
49803831d35Sstevel 				(void) putq(q, mp);
49903831d35Sstevel 			} else {
50003831d35Sstevel 				/*
50103831d35Sstevel 				 * XXX - should canputnext be called here?
50203831d35Sstevel 				 * Starfire's cvc doesn't do that, and it
50303831d35Sstevel 				 * appears to work anyway.
50403831d35Sstevel 				 */
50503831d35Sstevel 				(void) putnext(cvcoutput_q, mp);
50603831d35Sstevel 			}
50703831d35Sstevel 			break;
50803831d35Sstevel 
50903831d35Sstevel 	}
51003831d35Sstevel 	rw_exit(&cvclock);
51103831d35Sstevel 	return (error);
51203831d35Sstevel }
51303831d35Sstevel 
51403831d35Sstevel /*
51503831d35Sstevel  * cvc_wsrv()
51603831d35Sstevel  *	cvc_wsrv handles mblks that have been queued by cvc_wput either because
51703831d35Sstevel  *	the IOSRAM path was selected or the queue contained preceding mblks.  To
51803831d35Sstevel  *	optimize processing (particularly if the IOSRAM path is selected), all
51903831d35Sstevel  *	mblks are pulled off of the queue and chained together.  Then, if there
52003831d35Sstevel  *	are any mblks on the chain, they are either forwarded to cvcredir or
52103831d35Sstevel  *	sent for IOSRAM processing as appropriate given current circumstances.
52203831d35Sstevel  *	IOSRAM processing may not be able to handle all of the data in the
52303831d35Sstevel  *	chain, in which case the remaining data is placed back on the queue and
52403831d35Sstevel  *	a timeout routine is registered to reschedule cvc_wsrv in the future.
52503831d35Sstevel  *	Automatic scheduling of the queue is disabled (noenable(q)) while
52603831d35Sstevel  *	cvc_wsrv is running to avoid superfluous calls.
52703831d35Sstevel  */
52803831d35Sstevel static int
cvc_wsrv(queue_t * q)52903831d35Sstevel cvc_wsrv(queue_t *q)
53003831d35Sstevel {
53103831d35Sstevel 	mblk_t *total_mp = NULL;
53203831d35Sstevel 	mblk_t *mp;
53303831d35Sstevel 
53403831d35Sstevel 	if (cvc_stopped == 1 || cvc_suspended == 1) {
53503831d35Sstevel 		return (0);
53603831d35Sstevel 	}
53703831d35Sstevel 
53803831d35Sstevel 	rw_enter(&cvclock, RW_READER);
53903831d35Sstevel 	noenable(q);
54003831d35Sstevel 
54103831d35Sstevel 	/*
54203831d35Sstevel 	 * If there's already a timeout registered for scheduling this routine
54303831d35Sstevel 	 * in the future, it's a safe bet that we don't want to run right now.
54403831d35Sstevel 	 */
54503831d35Sstevel 	if (cvc_timeout_id != (timeout_id_t)-1) {
54603831d35Sstevel 		enableok(q);
54703831d35Sstevel 		rw_exit(&cvclock);
54803831d35Sstevel 		return (0);
54903831d35Sstevel 	}
55003831d35Sstevel 
55103831d35Sstevel 	/*
55203831d35Sstevel 	 * Start by linking all of the queued M_DATA mblks into a single chain
55303831d35Sstevel 	 * so we can flush as much as possible to IOSRAM (if we choose that
55403831d35Sstevel 	 * route).
55503831d35Sstevel 	 */
55603831d35Sstevel 	while ((mp = getq(q)) != NULL) {
55703831d35Sstevel 		/*
55803831d35Sstevel 		 * Technically, certain IOCTLs are supposed to be processed only
55903831d35Sstevel 		 * after all preceding data has completely "drained".  In an
56003831d35Sstevel 		 * attempt to support that, we delay processing of those IOCTLs
56103831d35Sstevel 		 * until this point.  It is still possible that an IOCTL will be
56203831d35Sstevel 		 * processed before all preceding data is drained, for instance
56303831d35Sstevel 		 * in the case where not all of the preceding data would fit
56403831d35Sstevel 		 * into IOSRAM and we have to place it back on the queue.
56503831d35Sstevel 		 * However, since none of these IOCTLs really appear to have any
56603831d35Sstevel 		 * relevance for cvc, and we weren't supporting delayed
56703831d35Sstevel 		 * processing at _all_ previously, this partial implementation
56803831d35Sstevel 		 * should suffice.  (Fully implementing the delayed IOCTL
56903831d35Sstevel 		 * processing would be unjustifiably difficult given the nature
57003831d35Sstevel 		 * of the underlying IOSRAM console protocol.)
57103831d35Sstevel 		 */
57203831d35Sstevel 		if (mp->b_datap->db_type == M_IOCTL) {
57303831d35Sstevel 			cvc_ioctl(q, mp);
57403831d35Sstevel 			continue;
57503831d35Sstevel 		}
57603831d35Sstevel 
57703831d35Sstevel 		/*
57803831d35Sstevel 		 * We know that only M_IOCTL and M_DATA blocks are placed on our
57903831d35Sstevel 		 * queue.  Since this block isn't an M_IOCTL, it must be M_DATA.
58003831d35Sstevel 		 */
58103831d35Sstevel 		if (total_mp != NULL) {
58203831d35Sstevel 			linkb(total_mp, mp);
58303831d35Sstevel 		} else {
58403831d35Sstevel 			total_mp = mp;
58503831d35Sstevel 		}
58603831d35Sstevel 	}
58703831d35Sstevel 
58803831d35Sstevel 	/*
58903831d35Sstevel 	 * Do we actually have anything to do?
59003831d35Sstevel 	 */
59103831d35Sstevel 	if (total_mp == NULL) {
59203831d35Sstevel 		enableok(q);
59303831d35Sstevel 		rw_exit(&cvclock);
59403831d35Sstevel 		return (0);
59503831d35Sstevel 	}
59603831d35Sstevel 
59703831d35Sstevel 	/*
59803831d35Sstevel 	 * Yes, we do, so send the data to either cvcredir or IOSRAM as
59903831d35Sstevel 	 * appropriate.  In the latter case, we might not be able to transmit
60003831d35Sstevel 	 * everything right now, so re-queue the remainder.
60103831d35Sstevel 	 */
60203831d35Sstevel 	if (cvcoutput_q != NULL && !via_iosram) {
60303831d35Sstevel 		CVC_DBG0(CVC_DBG_NETWORK_WR, "Sending to cvcredir.");
60403831d35Sstevel 		/*
60503831d35Sstevel 		 * XXX - should canputnext be called here?  Starfire's cvc
60603831d35Sstevel 		 * doesn't do that, and it appears to work anyway.
60703831d35Sstevel 		 */
60803831d35Sstevel 		(void) putnext(cvcoutput_q, total_mp);
60903831d35Sstevel 	} else {
61003831d35Sstevel 		CVC_DBG0(CVC_DBG_IOSRAM_WR, "Send to IOSRAM.");
61103831d35Sstevel 		cvc_send_to_iosram(&total_mp);
61203831d35Sstevel 		if (total_mp != NULL) {
61303831d35Sstevel 			(void) putbq(q, total_mp);
61403831d35Sstevel 		}
61503831d35Sstevel 	}
61603831d35Sstevel 
61703831d35Sstevel 	/*
61803831d35Sstevel 	 * If there is still data queued at this point, make sure the queue
61903831d35Sstevel 	 * gets scheduled again after an appropriate delay (which has been
62003831d35Sstevel 	 * somewhat arbitrarily selected as half of the SC's input polling
62103831d35Sstevel 	 * frequency).
62203831d35Sstevel 	 */
62303831d35Sstevel 	enableok(q);
62403831d35Sstevel 	if (q->q_first != NULL) {
62503831d35Sstevel 		if (cvc_timeout_id == (timeout_id_t)-1) {
62603831d35Sstevel 			cvc_timeout_id = timeout(cvc_flush_queue,
62703831d35Sstevel 			    NULL, drv_usectohz(CVC_IOSRAM_POLL_USECS / 2));
62803831d35Sstevel 		}
62903831d35Sstevel 	}
63003831d35Sstevel 	rw_exit(&cvclock);
63103831d35Sstevel 	return (0);
63203831d35Sstevel }
63303831d35Sstevel 
63403831d35Sstevel 
63503831d35Sstevel /*
63603831d35Sstevel  * cvc_ioctl()
63703831d35Sstevel  *	handle normal console ioctls.
63803831d35Sstevel  */
63903831d35Sstevel static void
cvc_ioctl(register queue_t * q,register mblk_t * mp)64003831d35Sstevel cvc_ioctl(register queue_t *q, register mblk_t *mp)
64103831d35Sstevel {
64203831d35Sstevel 	register cvc_t			*cp = q->q_ptr;
64303831d35Sstevel 	int				datasize;
64403831d35Sstevel 	int				error = 0;
64503831d35Sstevel 
64603831d35Sstevel 	/*
64703831d35Sstevel 	 * Let ttycommon_ioctl take the first shot at processing the ioctl.  If
64803831d35Sstevel 	 * it fails because it can't allocate memory, schedule processing of the
64903831d35Sstevel 	 * ioctl later when a proper buffer is available.  The mblk that
65003831d35Sstevel 	 * couldn't be processed will have been stored in the tty structure by
65103831d35Sstevel 	 * ttycommon_ioctl.
65203831d35Sstevel 	 */
65303831d35Sstevel 	datasize = ttycommon_ioctl(&cp->cvc_tty, q, mp, &error);
65403831d35Sstevel 	if (datasize != 0) {
65503831d35Sstevel 		if (cp->cvc_wbufcid) {
65603831d35Sstevel 			unbufcall(cp->cvc_wbufcid);
65703831d35Sstevel 		}
65803831d35Sstevel 		cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
65903831d35Sstevel 		return;
66003831d35Sstevel 	}
66103831d35Sstevel 
66203831d35Sstevel 	/*
66303831d35Sstevel 	 * ttycommon_ioctl didn't do anything, but there's nothing we really
66403831d35Sstevel 	 * support either with the exception of TCSBRK, which is supported
66503831d35Sstevel 	 * only to appear a bit more like a serial device for software that
66603831d35Sstevel 	 * expects TCSBRK to work.
66703831d35Sstevel 	 */
66803831d35Sstevel 	if (error != 0) {
66903831d35Sstevel 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
67003831d35Sstevel 
67103831d35Sstevel 		if (iocp->ioc_cmd == TCSBRK) {
67203831d35Sstevel 			miocack(q, mp, 0, 0);
67303831d35Sstevel 		} else {
67403831d35Sstevel 			miocnak(q, mp, 0, EINVAL);
67503831d35Sstevel 		}
67603831d35Sstevel 	} else {
67703831d35Sstevel 		qreply(q, mp);
67803831d35Sstevel 	}
67903831d35Sstevel }
68003831d35Sstevel 
68103831d35Sstevel 
68203831d35Sstevel /*
68303831d35Sstevel  * cvc_redir()
68403831d35Sstevel  *	called from cvcredir:cvcr_wput() to handle console input
68503831d35Sstevel  *	data. This routine puts the cvcredir write (downstream) data
68603831d35Sstevel  *	onto the cvc read (upstream) queues.
68703831d35Sstevel  */
68803831d35Sstevel int
cvc_redir(mblk_t * mp)68903831d35Sstevel cvc_redir(mblk_t *mp)
69003831d35Sstevel {
69103831d35Sstevel 	register struct iocblk	*iocp;
69203831d35Sstevel 	int			rv = 1;
69303831d35Sstevel 
69403831d35Sstevel 	/*
69503831d35Sstevel 	 * This function shouldn't be called if cvcredir hasn't registered yet.
69603831d35Sstevel 	 */
69703831d35Sstevel 	if (cvcinput_q == NULL) {
69803831d35Sstevel 		/*
69903831d35Sstevel 		 * Need to let caller know that it may be necessary for them to
70003831d35Sstevel 		 * free the message buffer, so return 0.
70103831d35Sstevel 		 */
70203831d35Sstevel 		CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled");
70303831d35Sstevel 		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
70403831d35Sstevel 		return (0);
70503831d35Sstevel 	}
70603831d35Sstevel 
70703831d35Sstevel 	CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type);
70803831d35Sstevel 	if (mp->b_datap->db_type == M_DATA) {
70903831d35Sstevel 		/*
71003831d35Sstevel 		 * XXX - should canputnext be called here?  Starfire's cvc
71103831d35Sstevel 		 * doesn't do that, and it appears to work anyway.
71203831d35Sstevel 		 */
71303831d35Sstevel 		CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp);
71403831d35Sstevel 		(void) putnext(cvcinput_q, mp);
71503831d35Sstevel 	} else if (mp->b_datap->db_type == M_IOCTL) {
71603831d35Sstevel 		/*
71703831d35Sstevel 		 * The cvcredir driver filters out ioctl mblks we wouldn't
71803831d35Sstevel 		 * understand, so we don't have to check for every conceivable
71903831d35Sstevel 		 * ioc_cmd.  However, additional ioctls may be supported (again)
72003831d35Sstevel 		 * some day, so the code is structured to check the value even
72103831d35Sstevel 		 * though there's only one that is currently supported.
72203831d35Sstevel 		 */
72303831d35Sstevel 		iocp = (struct iocblk *)mp->b_rptr;
72403831d35Sstevel 		if (iocp->ioc_cmd == CVC_DISCONNECT) {
72503831d35Sstevel 			(void) putnextctl(cvcinput_q, M_HANGUP);
72603831d35Sstevel 		}
72703831d35Sstevel 	} else {
72803831d35Sstevel 		/*
72903831d35Sstevel 		 * Since we don't know what this mblk is, we're not going to
73003831d35Sstevel 		 * process it.
73103831d35Sstevel 		 */
73203831d35Sstevel 		CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d",
73303831d35Sstevel 		    mp->b_datap->db_type);
73403831d35Sstevel 		rv = 0;
73503831d35Sstevel 	}
73603831d35Sstevel 
73703831d35Sstevel 	return (rv);
73803831d35Sstevel }
73903831d35Sstevel 
74003831d35Sstevel 
74103831d35Sstevel /*
74203831d35Sstevel  * cvc_register()
74303831d35Sstevel  *	called from cvcredir to register it's queues.  cvc
74403831d35Sstevel  *	receives data from cn via the streamhead and sends it to cvcredir
74503831d35Sstevel  *	via pointers to cvcredir's queues.
74603831d35Sstevel  */
74703831d35Sstevel int
cvc_register(queue_t * q)74803831d35Sstevel cvc_register(queue_t *q)
74903831d35Sstevel {
75003831d35Sstevel 	int error = -1;
75103831d35Sstevel 
75203831d35Sstevel 	if (cvcinput_q == NULL)
75303831d35Sstevel 		cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
75403831d35Sstevel 	rw_enter(&cvclock, RW_WRITER);
75503831d35Sstevel 	if (cvcoutput_q == NULL) {
75603831d35Sstevel 		cvcoutput_q = RD(q);  /* Make sure its the upstream q */
75703831d35Sstevel 		qprocson(cvcoutput_q);	/* must be done within cvclock */
75803831d35Sstevel 		error = 0;
75903831d35Sstevel 	} else {
76003831d35Sstevel 		/*
76103831d35Sstevel 		 * cmn_err will call us, so release lock.
76203831d35Sstevel 		 */
76303831d35Sstevel 		rw_exit(&cvclock);
76403831d35Sstevel 		if (cvcoutput_q == q)
76503831d35Sstevel 			cmn_err(CE_WARN, "cvc_register: duplicate q!");
76603831d35Sstevel 		else
76703831d35Sstevel 			cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p",
768*07d06da5SSurya Prakki 			    (void *)q);
76903831d35Sstevel 		return (error);
77003831d35Sstevel 	}
77103831d35Sstevel 	rw_exit(&cvclock);
77203831d35Sstevel 	return (error);
77303831d35Sstevel }
77403831d35Sstevel 
77503831d35Sstevel 
77603831d35Sstevel /*
77703831d35Sstevel  * cvc_unregister()
77803831d35Sstevel  *	called from cvcredir to clear pointers to its queues.
77903831d35Sstevel  *	cvcredir no longer wants to send or receive data.
78003831d35Sstevel  */
78103831d35Sstevel void
cvc_unregister(queue_t * q)78203831d35Sstevel cvc_unregister(queue_t *q)
78303831d35Sstevel {
78403831d35Sstevel 	rw_enter(&cvclock, RW_WRITER);
78503831d35Sstevel 	if (q == cvcoutput_q) {
78603831d35Sstevel 		qprocsoff(cvcoutput_q);	/* must be done within cvclock */
78703831d35Sstevel 		cvcoutput_q = NULL;
78803831d35Sstevel 	} else {
78903831d35Sstevel 		rw_exit(&cvclock);
790*07d06da5SSurya Prakki 		cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered",
791*07d06da5SSurya Prakki 		    (void *)q);
79203831d35Sstevel 		return;
79303831d35Sstevel 	}
79403831d35Sstevel 	rw_exit(&cvclock);
79503831d35Sstevel }
79603831d35Sstevel 
79703831d35Sstevel 
79803831d35Sstevel /*
79903831d35Sstevel  * cvc_reioctl()
80003831d35Sstevel  *	Retry an "ioctl", now that "bufcall" claims we may be able
80103831d35Sstevel  *	to allocate the buffer we need.
80203831d35Sstevel  */
80303831d35Sstevel static void
cvc_reioctl(void * unit)80403831d35Sstevel cvc_reioctl(void *unit)
80503831d35Sstevel {
80603831d35Sstevel 	register queue_t	*q;
80703831d35Sstevel 	register mblk_t		*mp;
80803831d35Sstevel 	register cvc_t		*cp = (cvc_t *)unit;
80903831d35Sstevel 
81003831d35Sstevel 	/*
81103831d35Sstevel 	 * The bufcall is no longer pending.
81203831d35Sstevel 	 */
81303831d35Sstevel 	if (!cp->cvc_wbufcid) {
81403831d35Sstevel 		return;
81503831d35Sstevel 	}
81603831d35Sstevel 	cp->cvc_wbufcid = 0;
81703831d35Sstevel 	if ((q = cp->cvc_tty.t_writeq) == NULL) {
81803831d35Sstevel 		return;
81903831d35Sstevel 	}
82003831d35Sstevel 	if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
82103831d35Sstevel 		/* not pending any more */
82203831d35Sstevel 		cp->cvc_tty.t_iocpending = NULL;
82303831d35Sstevel 		cvc_ioctl(q, mp);
82403831d35Sstevel 	}
82503831d35Sstevel }
82603831d35Sstevel 
82703831d35Sstevel 
82803831d35Sstevel /*
82903831d35Sstevel  * cvc_iosram_ops()
83003831d35Sstevel  *	Process commands sent to cvc from netcon_server via IOSRAM
83103831d35Sstevel  */
83203831d35Sstevel static void
cvc_iosram_ops(uint8_t op)83303831d35Sstevel cvc_iosram_ops(uint8_t op)
83403831d35Sstevel {
83503831d35Sstevel 	int		rval = ESUCCESS;
83603831d35Sstevel 	static uint8_t	stale_op = 0;
83703831d35Sstevel 
83803831d35Sstevel 	ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex));
83903831d35Sstevel 
84003831d35Sstevel 	CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op);
84103831d35Sstevel 
84203831d35Sstevel 	/*
84303831d35Sstevel 	 * If this is a repeated notice of a command that was previously
84403831d35Sstevel 	 * processed but couldn't be cleared due to EAGAIN (tunnel switch in
84503831d35Sstevel 	 * progress), just clear the data_valid flag and return.
84603831d35Sstevel 	 */
84703831d35Sstevel 	if (op == stale_op) {
84803831d35Sstevel 		if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
84903831d35Sstevel 		    IOSRAM_INT_NONE) == 0) {
85003831d35Sstevel 			stale_op = 0;
85103831d35Sstevel 		}
85203831d35Sstevel 		return;
85303831d35Sstevel 	}
85403831d35Sstevel 	stale_op = 0;
85503831d35Sstevel 
85603831d35Sstevel 	switch (op) {
85703831d35Sstevel 		case CVC_IOSRAM_BREAK:		/* A console break (L1-A) */
85803831d35Sstevel 			abort_sequence_enter((char *)NULL);
85903831d35Sstevel 			break;
86003831d35Sstevel 
86103831d35Sstevel 		case CVC_IOSRAM_DISCONNECT:	/* Break connection, hang up */
86203831d35Sstevel 			if (cvcinput_q)
86303831d35Sstevel 				(void) putnextctl(cvcinput_q, M_HANGUP);
86403831d35Sstevel 			break;
86503831d35Sstevel 
86603831d35Sstevel 		case CVC_IOSRAM_VIA_NET:	/* console via network */
86703831d35Sstevel 			via_iosram = 0;
86803831d35Sstevel 			break;
86903831d35Sstevel 
87003831d35Sstevel 		case CVC_IOSRAM_VIA_IOSRAM:	/* console via iosram */
87103831d35Sstevel 			via_iosram = 1;
87203831d35Sstevel 			/*
87303831d35Sstevel 			 * Tell cvcd to close any network connection it has.
87403831d35Sstevel 			 */
87503831d35Sstevel 			rw_enter(&cvclock, RW_READER);
87603831d35Sstevel 			if (cvcoutput_q != NULL) {
87703831d35Sstevel 				(void) putnextctl(cvcoutput_q, M_HANGUP);
87803831d35Sstevel 			}
87903831d35Sstevel 			rw_exit(&cvclock);
88003831d35Sstevel 			break;
88103831d35Sstevel 
88203831d35Sstevel 		case CVC_IOSRAM_WIN_RESIZE:	/* console window size data */
88303831d35Sstevel 			/*
88403831d35Sstevel 			 * In the case of window resizing, we don't want to
88503831d35Sstevel 			 * record a stale_op value because we should always use
88603831d35Sstevel 			 * the most recent winsize info, which could change
88703831d35Sstevel 			 * between the time that we fail to clear the flag and
88803831d35Sstevel 			 * the next time we try to process the command.  So,
88903831d35Sstevel 			 * we'll just let cvc_win_resize clear the data_valid
89003831d35Sstevel 			 * flag itself (hence the TRUE parameter) and not worry
89103831d35Sstevel 			 * about whether or not it succeeds.
89203831d35Sstevel 			 */
89303831d35Sstevel 			cvc_win_resize(TRUE);
89403831d35Sstevel 			return;
89503831d35Sstevel 			/* NOTREACHED */
89603831d35Sstevel 
89703831d35Sstevel 		default:
89803831d35Sstevel 			cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op);
89903831d35Sstevel 			break;
90003831d35Sstevel 	}
90103831d35Sstevel 
90203831d35Sstevel 	/*
90303831d35Sstevel 	 * Clear CONC's data_valid flag to indicate that the chunk is available
90403831d35Sstevel 	 * for further communications.  If the flag can't be cleared due to an
90503831d35Sstevel 	 * error, record the op value so we'll know to ignore it when we see it
90603831d35Sstevel 	 * on the next poll.
90703831d35Sstevel 	 */
90803831d35Sstevel 	rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
90903831d35Sstevel 	    IOSRAM_INT_NONE);
91003831d35Sstevel 	if (rval != 0) {
91103831d35Sstevel 		stale_op = op;
91203831d35Sstevel 		if (rval != EAGAIN) {
91303831d35Sstevel 			cmn_err(CE_WARN,
91403831d35Sstevel 			    "cvc_iosram_ops: set flag for cntlbuf ret %d",
91503831d35Sstevel 			    rval);
91603831d35Sstevel 		}
91703831d35Sstevel 	}
91803831d35Sstevel }
91903831d35Sstevel 
92003831d35Sstevel 
92103831d35Sstevel /*
92203831d35Sstevel  * cvc_send_to_iosram()
92303831d35Sstevel  *	Flush as much data as possible to the CONO chunk.  If successful, free
92403831d35Sstevel  *	any mblks that were completely transmitted, update the b_rptr field in
92503831d35Sstevel  *	the first remaining mblk if it was partially transmitted, and update the
92603831d35Sstevel  *	caller's pointer to the new head of the mblk chain.  Since the software
92703831d35Sstevel  *	that will be pulling this data out of IOSRAM (dxs on the SC) is just
92803831d35Sstevel  *	polling at some frequency, we avoid attempts to flush data to IOSRAM any
92903831d35Sstevel  *	faster than a large divisor of that polling frequency.
93003831d35Sstevel  *
93103831d35Sstevel  *	Note that "cvc_buf_t out" is only declared "static" to keep it from
93203831d35Sstevel  *	being allocated on the stack.  Allocating 1K+ structures on the stack
93303831d35Sstevel  *	seems rather antisocial.
93403831d35Sstevel  */
93503831d35Sstevel static void
cvc_send_to_iosram(mblk_t ** chainpp)93603831d35Sstevel cvc_send_to_iosram(mblk_t **chainpp)
93703831d35Sstevel {
93803831d35Sstevel 	int			rval;
93903831d35Sstevel 	uint8_t			dvalid;
94003831d35Sstevel 	uchar_t			*cp;
94103831d35Sstevel 	mblk_t			*mp;
94203831d35Sstevel 	mblk_t			*last_empty_mp;
94303831d35Sstevel 	static clock_t		last_flush = (clock_t)-1;
94403831d35Sstevel 	static cvc_buf_t	out;   /* see note above about static */
94503831d35Sstevel 
94603831d35Sstevel 	ASSERT(chainpp != NULL);
94703831d35Sstevel 
94803831d35Sstevel 	/*
94903831d35Sstevel 	 * We _do_ have something to do, right?
95003831d35Sstevel 	 */
95103831d35Sstevel 	if (*chainpp == NULL) {
95203831d35Sstevel 		return;
95303831d35Sstevel 	}
95403831d35Sstevel 
95503831d35Sstevel 	/*
95603831d35Sstevel 	 * We can actually increase throughput by throttling back on attempts to
95703831d35Sstevel 	 * flush data to IOSRAM, since trying to write every little bit of data
95803831d35Sstevel 	 * as it shows up will actually generate more delays waiting for the SC
95903831d35Sstevel 	 * to pick up each of those bits.  Instead, we'll avoid attempting to
96003831d35Sstevel 	 * write data to IOSRAM any faster than half of the polling frequency we
96103831d35Sstevel 	 * expect the SC to be using.
96203831d35Sstevel 	 */
96303831d35Sstevel 	if (ddi_get_lbolt() - last_flush <
96403831d35Sstevel 	    drv_usectohz(CVC_IOSRAM_POLL_USECS / 2)) {
96503831d35Sstevel 		return;
96603831d35Sstevel 	}
96703831d35Sstevel 
96803831d35Sstevel 	/*
96903831d35Sstevel 	 * If IOSRAM is inaccessible or the CONO chunk still holds data that
97003831d35Sstevel 	 * hasn't been picked up by the SC, there's nothing we can do right now.
97103831d35Sstevel 	 */
97203831d35Sstevel 	rval = iosram_get_flag(IOSRAM_KEY_CONO, &dvalid, NULL);
97303831d35Sstevel 	if ((rval != 0) || (dvalid == IOSRAM_DATA_VALID)) {
97403831d35Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
97503831d35Sstevel 			cmn_err(CE_WARN, "cvc_send_to_iosram: get_flag ret %d",
97603831d35Sstevel 			    rval);
97703831d35Sstevel 		}
97803831d35Sstevel 		return;
97903831d35Sstevel 	}
98003831d35Sstevel 
98103831d35Sstevel 	/*
98203831d35Sstevel 	 * Copy up to MAX_XFER_COUTPUT chars from the mblk chain into a buffer.
98303831d35Sstevel 	 * Don't change any of the mblks just yet, since we can't be certain
98403831d35Sstevel 	 * that we'll be successful in writing data to the CONO chunk.
98503831d35Sstevel 	 */
98603831d35Sstevel 	out.count = 0;
98703831d35Sstevel 	mp = *chainpp;
98803831d35Sstevel 	cp = mp->b_rptr;
98903831d35Sstevel 	last_empty_mp = NULL;
99003831d35Sstevel 	while ((mp != NULL) && (out.count < MAX_XFER_COUTPUT)) {
99103831d35Sstevel 		/*
99203831d35Sstevel 		 * Process as many of the characters in the current mblk as
99303831d35Sstevel 		 * possible.
99403831d35Sstevel 		 */
99503831d35Sstevel 		while ((cp != mp->b_wptr) && (out.count < MAX_XFER_COUTPUT)) {
99603831d35Sstevel 			out.buffer[out.count++] = *cp++;
99703831d35Sstevel 		}
99803831d35Sstevel 
99903831d35Sstevel 		/*
100003831d35Sstevel 		 * Did we process that entire mblk?  If so, move on to the next
100103831d35Sstevel 		 * one.  If not, we're done filling the buffer even if there's
100203831d35Sstevel 		 * space left, because apparently there wasn't room to process
100303831d35Sstevel 		 * the next character.
100403831d35Sstevel 		 */
100503831d35Sstevel 		if (cp != mp->b_wptr) {
100603831d35Sstevel 			break;
100703831d35Sstevel 		}
100803831d35Sstevel 
100903831d35Sstevel 		/*
101003831d35Sstevel 		 * When this loop terminates, last_empty_mp will point to the
101103831d35Sstevel 		 * last mblk that was completely processed, mp will point to the
101203831d35Sstevel 		 * following mblk (or NULL if no more mblks exist), and cp will
101303831d35Sstevel 		 * point to the first untransmitted character in the mblk
101403831d35Sstevel 		 * pointed to by mp.  We'll need this data to update the mblk
101503831d35Sstevel 		 * chain if all of the data is successfully transmitted.
101603831d35Sstevel 		 */
101703831d35Sstevel 		last_empty_mp = mp;
101803831d35Sstevel 		mp = mp->b_cont;
101903831d35Sstevel 		cp = (mp != NULL) ? mp->b_rptr : NULL;
102003831d35Sstevel 	}
102103831d35Sstevel 
102203831d35Sstevel 	/*
102303831d35Sstevel 	 * If we succeeded in preparing some data, try to transmit it through
102403831d35Sstevel 	 * IOSRAM.  First write the count and the data, which can be done in a
102503831d35Sstevel 	 * single operation thanks to the buffer structure we use, then set the
102603831d35Sstevel 	 * data_valid flag if the first step succeeded.
102703831d35Sstevel 	 */
102803831d35Sstevel 	if (out.count != 0) {
102903831d35Sstevel 		rval = iosram_wr(IOSRAM_KEY_CONO, COUNT_OFFSET,
103003831d35Sstevel 		    CONSBUF_COUNT_SIZE + out.count, (caddr_t)&out);
103103831d35Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
103203831d35Sstevel 			cmn_err(CE_WARN, "cvc_putc: write ret %d", rval);
103303831d35Sstevel 		}
103403831d35Sstevel 
103503831d35Sstevel 		/* if the data write succeeded, set the data_valid flag */
103603831d35Sstevel 		if (rval == 0) {
103703831d35Sstevel 			rval = iosram_set_flag(IOSRAM_KEY_CONO,
103803831d35Sstevel 			    IOSRAM_DATA_VALID, IOSRAM_INT_NONE);
103903831d35Sstevel 			if ((rval != 0) && (rval != EAGAIN)) {
104003831d35Sstevel 				cmn_err(CE_WARN,
104103831d35Sstevel 				    "cvc_putc: set flags for outbuf ret %d",
104203831d35Sstevel 				    rval);
104303831d35Sstevel 			}
104403831d35Sstevel 		}
104503831d35Sstevel 
104603831d35Sstevel 		/*
104703831d35Sstevel 		 * If we successfully transmitted any data, modify the caller's
104803831d35Sstevel 		 * mblk chain to remove the data that was transmitted, freeing
104903831d35Sstevel 		 * all mblks that were completely processed.
105003831d35Sstevel 		 */
105103831d35Sstevel 		if (rval == 0) {
105203831d35Sstevel 			last_flush = ddi_get_lbolt();
105303831d35Sstevel 
105403831d35Sstevel 			/*
105503831d35Sstevel 			 * If any data is left over, update the b_rptr field of
105603831d35Sstevel 			 * the first remaining mblk in case some of its data was
105703831d35Sstevel 			 * processed.
105803831d35Sstevel 			 */
105903831d35Sstevel 			if (mp != NULL) {
106003831d35Sstevel 				mp->b_rptr = cp;
106103831d35Sstevel 			}
106203831d35Sstevel 
106303831d35Sstevel 			/*
106403831d35Sstevel 			 * If any mblks have been emptied, unlink them from the
106503831d35Sstevel 			 * residual chain, free them, and update the caller's
106603831d35Sstevel 			 * mblk pointer.
106703831d35Sstevel 			 */
106803831d35Sstevel 			if (last_empty_mp != NULL) {
106903831d35Sstevel 				last_empty_mp->b_cont = NULL;
107003831d35Sstevel 				freemsg(*chainpp);
107103831d35Sstevel 				*chainpp = mp;
107203831d35Sstevel 			}
107303831d35Sstevel 		}
107403831d35Sstevel 	}
107503831d35Sstevel }
107603831d35Sstevel 
107703831d35Sstevel 
107803831d35Sstevel /*
107903831d35Sstevel  * cvc_flush_queue()
108003831d35Sstevel  *	Tell the STREAMS subsystem to schedule cvc_wsrv to process the queue we
108103831d35Sstevel  *	use to gather console output.
108203831d35Sstevel  */
108303831d35Sstevel /* ARGSUSED */
108403831d35Sstevel static void
cvc_flush_queue(void * notused)108503831d35Sstevel cvc_flush_queue(void *notused)
108603831d35Sstevel {
108703831d35Sstevel 	rw_enter(&cvclock, RW_WRITER);
108803831d35Sstevel 	if (cvcinput_q != NULL) {
108903831d35Sstevel 		qenable(WR(cvcinput_q));
109003831d35Sstevel 	}
109103831d35Sstevel 
109203831d35Sstevel 	cvc_timeout_id = (timeout_id_t)-1;
109303831d35Sstevel 	rw_exit(&cvclock);
109403831d35Sstevel }
109503831d35Sstevel 
109603831d35Sstevel 
109703831d35Sstevel /*
109803831d35Sstevel  * cvc_getstr()
109903831d35Sstevel  *	Poll IOSRAM for console input while available.
110003831d35Sstevel  */
110103831d35Sstevel static void
cvc_getstr(char * cp)110203831d35Sstevel cvc_getstr(char *cp)
110303831d35Sstevel {
110403831d35Sstevel 	short		count;
110503831d35Sstevel 	uint8_t		command = 0;
110603831d35Sstevel 	int		rval = ESUCCESS;
110703831d35Sstevel 	uint8_t		dvalid = IOSRAM_DATA_INVALID;
110803831d35Sstevel 	uint8_t		intrpending = 0;
110903831d35Sstevel 
111003831d35Sstevel 	mutex_enter(&cvc_iosram_input_mutex);
111103831d35Sstevel 	while (dvalid == IOSRAM_DATA_INVALID) {
111203831d35Sstevel 		/*
111303831d35Sstevel 		 * Check the CONC data_valid flag to see if a control message is
111403831d35Sstevel 		 * available.
111503831d35Sstevel 		 */
111603831d35Sstevel 		rval = iosram_get_flag(IOSRAM_KEY_CONC, &dvalid, &intrpending);
111703831d35Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
111803831d35Sstevel 			cmn_err(CE_WARN,
111903831d35Sstevel 			    "cvc_getstr: get flag for cntl ret %d", rval);
112003831d35Sstevel 		}
112103831d35Sstevel 
112203831d35Sstevel 		/*
112303831d35Sstevel 		 * If a control message is available, try to read and process
112403831d35Sstevel 		 * it.
112503831d35Sstevel 		 */
112603831d35Sstevel 		if ((dvalid == IOSRAM_DATA_VALID) && (rval == 0)) {
112703831d35Sstevel 			/* read the control reg offset */
112803831d35Sstevel 			rval = iosram_rd(IOSRAM_KEY_CONC,
112903831d35Sstevel 			    CVC_CTL_OFFSET(command), CVC_CTL_SIZE(command),
113003831d35Sstevel 			    (caddr_t)&command);
113103831d35Sstevel 			if ((rval != 0) && (rval != EAGAIN)) {
113203831d35Sstevel 				cmn_err(CE_WARN,
113303831d35Sstevel 				    "cvc_getstr: read for command ret %d",
113403831d35Sstevel 				    rval);
113503831d35Sstevel 			}
113603831d35Sstevel 
113703831d35Sstevel 			/* process the cntl msg and clear the data_valid flag */
113803831d35Sstevel 			if (rval == 0) {
113903831d35Sstevel 				cvc_iosram_ops(command);
114003831d35Sstevel 			}
114103831d35Sstevel 		}
114203831d35Sstevel 
114303831d35Sstevel 		/*
114403831d35Sstevel 		 * Check the CONI data_valid flag to see if console input data
114503831d35Sstevel 		 * is available.
114603831d35Sstevel 		 */
114703831d35Sstevel 		rval = iosram_get_flag(IOSRAM_KEY_CONI, &dvalid, &intrpending);
114803831d35Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
114919397407SSherry Moore 			cmn_err(CE_WARN,
115019397407SSherry Moore 			    "cvc_getstr: get flag for inbuf ret %d",
115103831d35Sstevel 			    rval);
115203831d35Sstevel 		}
115303831d35Sstevel 		if ((rval != 0) || (dvalid != IOSRAM_DATA_VALID)) {
115403831d35Sstevel 			goto retry;
115503831d35Sstevel 		}
115603831d35Sstevel 
115703831d35Sstevel 		/*
115803831d35Sstevel 		 * Try to read the count.
115903831d35Sstevel 		 */
116003831d35Sstevel 		rval = iosram_rd(IOSRAM_KEY_CONI, COUNT_OFFSET,
116103831d35Sstevel 		    CONSBUF_COUNT_SIZE, (caddr_t)&count);
116203831d35Sstevel 		if (rval != 0) {
116303831d35Sstevel 			if (rval != EAGAIN) {
116403831d35Sstevel 				cmn_err(CE_WARN,
116503831d35Sstevel 				    "cvc_getstr: read for count ret %d", rval);
116603831d35Sstevel 			}
116703831d35Sstevel 			goto retry;
116803831d35Sstevel 		}
116903831d35Sstevel 
117003831d35Sstevel 		/*
117103831d35Sstevel 		 * If there is data to be read, try to read it.
117203831d35Sstevel 		 */
117303831d35Sstevel 		if (count != 0) {
117403831d35Sstevel 			rval = iosram_rd(IOSRAM_KEY_CONI, DATA_OFFSET, count,
117503831d35Sstevel 			    (caddr_t)cp);
117603831d35Sstevel 			if (rval != 0) {
117703831d35Sstevel 				if (rval != EAGAIN) {
117803831d35Sstevel 					cmn_err(CE_WARN,
117903831d35Sstevel 					    "cvc_getstr: read for count ret %d",
118003831d35Sstevel 					    rval);
118103831d35Sstevel 				}
118203831d35Sstevel 				goto retry;
118303831d35Sstevel 			}
118403831d35Sstevel 			cp[count] = '\0';
118503831d35Sstevel 		}
118603831d35Sstevel 
118703831d35Sstevel 		/*
118803831d35Sstevel 		 * Try to clear the data_valid flag to indicate that whatever
118903831d35Sstevel 		 * was in CONI was read successfully.  If successful, and some
119003831d35Sstevel 		 * data was read, break out of the loop to return to the caller.
119103831d35Sstevel 		 */
119203831d35Sstevel 		rval = iosram_set_flag(IOSRAM_KEY_CONI, IOSRAM_DATA_INVALID,
119303831d35Sstevel 		    IOSRAM_INT_NONE);
119403831d35Sstevel 		if (rval != 0) {
119503831d35Sstevel 			if (rval != EAGAIN) {
119603831d35Sstevel 				cmn_err(CE_WARN,
119703831d35Sstevel 				    "cvc_getstr: set flag for inbuf ret %d",
119803831d35Sstevel 				    rval);
119903831d35Sstevel 			}
120003831d35Sstevel 		} else if (count != 0) {
120103831d35Sstevel 			CVC_DBG1(CVC_DBG_IOSRAM_RD, "Read 0x%x", count);
120203831d35Sstevel 			break;
120303831d35Sstevel 		}
120403831d35Sstevel 
120503831d35Sstevel 		/*
120603831d35Sstevel 		 * Use a smaller delay between checks of IOSRAM for input
120703831d35Sstevel 		 * when cvcd/cvcredir are not running or "via_iosram" has
120803831d35Sstevel 		 * been set.
120903831d35Sstevel 		 * We don't go away completely when i/o is going through the
121003831d35Sstevel 		 * network via cvcd since a command may be sent via IOSRAM
121103831d35Sstevel 		 * to switch if the network is down or hung.
121203831d35Sstevel 		 */
121303831d35Sstevel retry:
121403831d35Sstevel 		if ((cvcoutput_q == NULL) || (via_iosram))
121503831d35Sstevel 			delay(drv_usectohz(CVC_IOSRAM_POLL_USECS));
121603831d35Sstevel 		else
121703831d35Sstevel 			delay(drv_usectohz(CVC_IOSRAM_POLL_USECS * 10));
121803831d35Sstevel 
121903831d35Sstevel 	}
122003831d35Sstevel 
122103831d35Sstevel 	mutex_exit(&cvc_iosram_input_mutex);
122203831d35Sstevel }
122303831d35Sstevel 
122403831d35Sstevel 
122503831d35Sstevel /*
122603831d35Sstevel  * cvc_input_daemon()
122703831d35Sstevel  *	this function runs as a separate kernel thread and polls IOSRAM for
122803831d35Sstevel  *	input, and possibly put it on read stream for the console.
122903831d35Sstevel  *	There are two poll rates (implemented in cvc_getstr):
123003831d35Sstevel  *		 100 000 uS (10 Hz) - no cvcd communications || via_iosram
123103831d35Sstevel  *		1000 000 uS ( 1 Hz) - cvcd communications
123203831d35Sstevel  * 	This continues to run even if there are network console communications
123303831d35Sstevel  *	in order to handle out-of-band signaling.
123403831d35Sstevel  */
123503831d35Sstevel /* ARGSUSED */
123603831d35Sstevel static void
cvc_input_daemon(void)123703831d35Sstevel cvc_input_daemon(void)
123803831d35Sstevel {
123903831d35Sstevel 	char		linebuf[MAX_XFER_CINPUT + 1];
124003831d35Sstevel 	char		*cp;
124103831d35Sstevel 	mblk_t		*mbp;
124203831d35Sstevel 	int		c;
124303831d35Sstevel 	int		dropped_read = 0;
124403831d35Sstevel 
124503831d35Sstevel 	for (;;) {
124603831d35Sstevel 		cvc_getstr(linebuf);
124703831d35Sstevel 
124803831d35Sstevel 		mbp = allocb(strlen(linebuf), BPRI_MED);
124903831d35Sstevel 		if (mbp == NULL) {	/* drop it & go on if no buffer */
125003831d35Sstevel 			if (!dropped_read) {
125103831d35Sstevel 				cmn_err(CE_WARN, "cvc_input_daemon: "
125203831d35Sstevel 				    "dropping IOSRAM reads");
125303831d35Sstevel 			}
125403831d35Sstevel 			dropped_read++;
125503831d35Sstevel 			continue;
125603831d35Sstevel 		}
125703831d35Sstevel 
125803831d35Sstevel 		if (dropped_read) {
125903831d35Sstevel 			cmn_err(CE_WARN,
126003831d35Sstevel 			    "cvc_input_daemon: dropped %d IOSRAM reads",
126103831d35Sstevel 			    dropped_read);
126203831d35Sstevel 			dropped_read = 0;
126303831d35Sstevel 		}
126403831d35Sstevel 
126503831d35Sstevel 		for (cp = linebuf; *cp != '\0'; cp++) {
126603831d35Sstevel 			c = (int)*cp;
126703831d35Sstevel 			if (c == '\r')
126803831d35Sstevel 				c = '\n';
126903831d35Sstevel 			c &= 0177;
127003831d35Sstevel 			*mbp->b_wptr = (char)c;
127103831d35Sstevel 			mbp->b_wptr++;
127203831d35Sstevel 		}
127303831d35Sstevel 		mutex_enter(&cvcmutex);
127403831d35Sstevel 		if (input_ok) {
127503831d35Sstevel 			if (cvcinput_q == NULL) {
127603831d35Sstevel 				cmn_err(CE_WARN,
127703831d35Sstevel 				    "cvc_input_daemon: cvcinput_q is NULL!");
127803831d35Sstevel 			} else {
127903831d35Sstevel 				/*
128003831d35Sstevel 				 * XXX - should canputnext be called here?
128103831d35Sstevel 				 * Starfire's cvc doesn't do that, and it
128203831d35Sstevel 				 * appears to work anyway.
128303831d35Sstevel 				 */
128403831d35Sstevel 				(void) putnext(cvcinput_q, mbp);
128503831d35Sstevel 			}
128603831d35Sstevel 		} else {
128703831d35Sstevel 			freemsg(mbp);
128803831d35Sstevel 		}
128903831d35Sstevel 		mutex_exit(&cvcmutex);
129003831d35Sstevel 	}
129103831d35Sstevel 
129203831d35Sstevel 	/* NOTREACHED */
129303831d35Sstevel }
129403831d35Sstevel 
129503831d35Sstevel /*
129603831d35Sstevel  * cvc_win_resize()
129703831d35Sstevel  *	cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set
129803831d35Sstevel  *	the console window size accordingly.  If indicated by the caller, CONC's
129903831d35Sstevel  *	data_valid flag will also be cleared.  The flag isn't cleared in all
130003831d35Sstevel  *	cases because we need to process winsize data at startup without waiting
130103831d35Sstevel  *	for a command.
130203831d35Sstevel  */
130303831d35Sstevel static void
cvc_win_resize(int clear_flag)130403831d35Sstevel cvc_win_resize(int clear_flag)
130503831d35Sstevel {
130603831d35Sstevel 	int		rval;
130703831d35Sstevel 	uint16_t	rows;
130803831d35Sstevel 	uint16_t	cols;
130903831d35Sstevel 	uint16_t	xpixels;
131003831d35Sstevel 	uint16_t	ypixels;
131103831d35Sstevel 	tty_common_t	*tty;
131203831d35Sstevel 	cvc_t		*cp;
131303831d35Sstevel 	struct winsize	ws;
131403831d35Sstevel 
131503831d35Sstevel 	/*
131603831d35Sstevel 	 * Start by reading the new window size out of the CONC chunk and, if
131703831d35Sstevel 	 * requested, clearing CONC's data_valid flag.  If any of that fails,
131803831d35Sstevel 	 * return immediately.  (Note that the rather bulky condition in the
131903831d35Sstevel 	 * two "if" statements takes advantage of C's short-circuit logic
132003831d35Sstevel 	 * evaluation)
132103831d35Sstevel 	 */
132203831d35Sstevel 	if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows),
132303831d35Sstevel 	    CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) ||
132403831d35Sstevel 	    ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols),
132503831d35Sstevel 	    CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) ||
132603831d35Sstevel 	    ((rval = iosram_rd(IOSRAM_KEY_CONC,
132703831d35Sstevel 	    CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels),
132803831d35Sstevel 	    (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC,
132903831d35Sstevel 	    CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels),
133003831d35Sstevel 	    (caddr_t)&ypixels)) != 0)) {
133103831d35Sstevel 		if (rval != EAGAIN) {
133203831d35Sstevel 			cmn_err(CE_WARN,
133303831d35Sstevel 			    "cvc_win_resize: read for ctlbuf ret %d", rval);
133403831d35Sstevel 		}
133503831d35Sstevel 		return;
133603831d35Sstevel 	}
133703831d35Sstevel 
133803831d35Sstevel 	if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC,
133903831d35Sstevel 	    IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) {
134003831d35Sstevel 		if (rval != EAGAIN) {
134103831d35Sstevel 			cmn_err(CE_WARN,
134203831d35Sstevel 			    "cvc_win_resize: set_flag for ctlbuf ret %d", rval);
134303831d35Sstevel 		}
134403831d35Sstevel 		return;
134503831d35Sstevel 	}
134603831d35Sstevel 
134703831d35Sstevel 	/*
134803831d35Sstevel 	 * Copy the parameters from IOSRAM to a winsize struct.
134903831d35Sstevel 	 */
135003831d35Sstevel 	ws.ws_row = rows;
135103831d35Sstevel 	ws.ws_col = cols;
135203831d35Sstevel 	ws.ws_xpixel = xpixels;
135303831d35Sstevel 	ws.ws_ypixel = ypixels;
135403831d35Sstevel 
135503831d35Sstevel 	/*
135603831d35Sstevel 	 * This code was taken from Starfire, and it appears to work correctly.
135703831d35Sstevel 	 * However, since the original developer felt it necessary to add the
135803831d35Sstevel 	 * following comment, it's probably worth preserving:
135903831d35Sstevel 	 *
136003831d35Sstevel 	 * XXX I hope this is safe...
136103831d35Sstevel 	 */
136203831d35Sstevel 	cp = cvcinput_q->q_ptr;
136303831d35Sstevel 	tty = &cp->cvc_tty;
136403831d35Sstevel 	mutex_enter(&tty->t_excl);
136503831d35Sstevel 	if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws,
136603831d35Sstevel 	    sizeof (struct winsize))) {
136703831d35Sstevel 		tty->t_size = ws;
136803831d35Sstevel 		mutex_exit(&tty->t_excl);
136903831d35Sstevel 		(void) putnextctl1(cvcinput_q, M_PCSIG,
137003831d35Sstevel 			SIGWINCH);
137103831d35Sstevel 	} else {
137203831d35Sstevel 		mutex_exit(&tty->t_excl);
137303831d35Sstevel 	}
137403831d35Sstevel }
137503831d35Sstevel 
137603831d35Sstevel #ifdef DEBUG
137703831d35Sstevel 
137803831d35Sstevel void
cvc_dbg(uint32_t flag,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)137903831d35Sstevel cvc_dbg(uint32_t flag, char *fmt,
138003831d35Sstevel 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
138103831d35Sstevel {
138203831d35Sstevel 	char *s = NULL;
138303831d35Sstevel 	char buf[256];
138403831d35Sstevel 
138503831d35Sstevel 	if (cvc_dbg_flags && ((cvc_dbg_flags & flag) == flag)) {
138603831d35Sstevel 		switch (flag) {
138703831d35Sstevel 		case CVC_DBG_ATTACH:
138803831d35Sstevel 			s = "attach";
138903831d35Sstevel 			break;
139003831d35Sstevel 		case CVC_DBG_DETACH:
139103831d35Sstevel 			s = "detach";
139203831d35Sstevel 			break;
139303831d35Sstevel 		case CVC_DBG_OPEN:
139403831d35Sstevel 			s = "open";
139503831d35Sstevel 			break;
139603831d35Sstevel 		case CVC_DBG_CLOSE:
139703831d35Sstevel 			s = "close";
139803831d35Sstevel 			break;
139903831d35Sstevel 		case CVC_DBG_IOCTL:
140003831d35Sstevel 			s = "ioctl";
140103831d35Sstevel 			break;
140203831d35Sstevel 		case CVC_DBG_REDIR:
140303831d35Sstevel 			s = "redir";
140403831d35Sstevel 			break;
140503831d35Sstevel 		case CVC_DBG_WPUT:
140603831d35Sstevel 			s = "wput";
140703831d35Sstevel 			break;
140803831d35Sstevel 		case CVC_DBG_WSRV:
140903831d35Sstevel 			s = "wsrv";
141003831d35Sstevel 			break;
141103831d35Sstevel 		case CVC_DBG_IOSRAM_WR:
141203831d35Sstevel 			s = "iosram_wr";
141303831d35Sstevel 			break;
141403831d35Sstevel 		case CVC_DBG_IOSRAM_RD:
141503831d35Sstevel 			s = "iosram_rd";
141603831d35Sstevel 			break;
141703831d35Sstevel 		case CVC_DBG_NETWORK_WR:
141803831d35Sstevel 			s = "network_wr";
141903831d35Sstevel 			break;
142003831d35Sstevel 		case CVC_DBG_NETWORK_RD:
142103831d35Sstevel 			s = "network_rd";
142203831d35Sstevel 			break;
142303831d35Sstevel 		case CVC_DBG_IOSRAM_CNTL:
142403831d35Sstevel 			s = "iosram_cntlmsg";
142503831d35Sstevel 			break;
142603831d35Sstevel 		default:
142703831d35Sstevel 			s = "Unknown debug flag";
142803831d35Sstevel 			break;
142903831d35Sstevel 		}
143003831d35Sstevel 
1431*07d06da5SSurya Prakki 		(void) sprintf(buf, "!%s_%s(%d): %s", ddi_driver_name(cvcdip),
1432*07d06da5SSurya Prakki 		    s, cvc_instance, fmt);
143303831d35Sstevel 		cmn_err(CE_NOTE, buf, a1, a2, a3, a4, a5);
143403831d35Sstevel 	}
143503831d35Sstevel }
143603831d35Sstevel 
143703831d35Sstevel #endif /* DEBUG */
1438