xref: /onnv-gate/usr/src/uts/sun4u/starcat/io/cvc.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
57656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
67656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
21*11311SSurya.Prakki@Sun.COM 
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel /*
291708Sstevel  * MT STREAMS Virtual Console Device Driver
301708Sstevel  */
311708Sstevel 
321708Sstevel #include <sys/types.h>
331708Sstevel #include <sys/open.h>
341708Sstevel #include <sys/param.h>
351708Sstevel #include <sys/systm.h>
361708Sstevel #include <sys/signal.h>
371708Sstevel #include <sys/cred.h>
381708Sstevel #include <sys/user.h>
391708Sstevel #include <sys/proc.h>
401708Sstevel #include <sys/disp.h>
411708Sstevel #include <sys/vnode.h>
421708Sstevel #include <sys/uio.h>
431708Sstevel #include <sys/buf.h>
441708Sstevel #include <sys/file.h>
451708Sstevel #include <sys/kmem.h>
461708Sstevel #include <sys/stat.h>
471708Sstevel #include <sys/stream.h>
481708Sstevel #include <sys/stropts.h>
491708Sstevel #include <sys/strsubr.h>
501708Sstevel #include <sys/strsun.h>
511708Sstevel #include <sys/tty.h>
521708Sstevel #include <sys/ptyvar.h>
531708Sstevel #include <sys/poll.h>
541708Sstevel #include <sys/debug.h>
551708Sstevel #include <sys/conf.h>
561708Sstevel #include <sys/ddi.h>
571708Sstevel #include <sys/sunddi.h>
581708Sstevel #include <sys/errno.h>
591708Sstevel #include <sys/modctl.h>
601708Sstevel 
611708Sstevel #include <sys/sc_cvc.h>
621708Sstevel #include <sys/sc_cvcio.h>
631708Sstevel #include <sys/iosramio.h>
641708Sstevel 
651708Sstevel static int	cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
661708Sstevel static int	cvc_attach(dev_info_t *, ddi_attach_cmd_t);
671708Sstevel static int	cvc_detach(dev_info_t *, ddi_detach_cmd_t);
681708Sstevel static int	cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
691708Sstevel static int	cvc_close(queue_t *, int, cred_t *);
701708Sstevel static int	cvc_wput(queue_t *, mblk_t *);
711708Sstevel static int	cvc_wsrv(queue_t *);
721708Sstevel static void	cvc_ioctl(queue_t *, mblk_t *);
731708Sstevel static void	cvc_reioctl(void *);
741708Sstevel static void	cvc_input_daemon(void);
751708Sstevel static void	cvc_send_to_iosram(mblk_t **chainpp);
761708Sstevel static void	cvc_flush_queue(void *);
771708Sstevel static void	cvc_iosram_ops(uint8_t);
781708Sstevel static void	cvc_getstr(char *cp);
791708Sstevel static void	cvc_win_resize(int clear_flag);
801708Sstevel 
811708Sstevel #define	ESUCCESS 0
821708Sstevel #ifndef	TRUE
831708Sstevel #define	TRUE	1
841708Sstevel #define	FALSE	0
851708Sstevel #endif
861708Sstevel 
871708Sstevel /*
881708Sstevel  * Private copy of devinfo pointer; cvc_info uses it.
891708Sstevel  */
901708Sstevel static dev_info_t	*cvcdip;
911708Sstevel 
921708Sstevel /*
931708Sstevel  * This structure reflects the layout of data in CONI and CONO.  If you are
941708Sstevel  * going to add fields that don't get written into those chunks, be sure to
951708Sstevel  * place them _after_ the buffer field.
961708Sstevel  */
971708Sstevel typedef struct cvc_buf {
981708Sstevel 	ushort_t	count;
991708Sstevel 	uchar_t		buffer[MAX_XFER_COUTPUT];
1001708Sstevel } cvc_buf_t;
1011708Sstevel 
1021708Sstevel typedef struct cvc_s {
1031708Sstevel 	bufcall_id_t	cvc_wbufcid;
1041708Sstevel 	tty_common_t	cvc_tty;
1051708Sstevel } cvc_t;
1061708Sstevel 
1071708Sstevel cvc_t	cvc_common_tty;
1081708Sstevel 
1091708Sstevel static struct module_info cvcm_info = {
1101708Sstevel 	1313,		/* mi_idnum Bad luck number  ;-) */
1111708Sstevel 	"cvc",		/* mi_idname */
1121708Sstevel 	0,		/* mi_minpsz */
1131708Sstevel 	INFPSZ,		/* mi_maxpsz */
1141708Sstevel 	2048,		/* mi_hiwat */
1151708Sstevel 	2048		/* mi_lowat */
1161708Sstevel };
1171708Sstevel 
1181708Sstevel static struct qinit cvcrinit = {
1191708Sstevel 	NULL,		/* qi_putp */
1201708Sstevel 	NULL,		/* qi_srvp */
1211708Sstevel 	cvc_open,	/* qi_qopen */
1221708Sstevel 	cvc_close,	/* qi_qclose */
1231708Sstevel 	NULL,		/* qi_qadmin */
1241708Sstevel 	&cvcm_info,	/* qi_minfo */
1251708Sstevel 	NULL		/* qi_mstat */
1261708Sstevel };
1271708Sstevel 
1281708Sstevel static struct qinit cvcwinit = {
1291708Sstevel 	cvc_wput,	/* qi_putp */
1301708Sstevel 	cvc_wsrv,	/* qi_srvp */
1311708Sstevel 	cvc_open,	/* qi_qopen */
1321708Sstevel 	cvc_close,	/* qi_qclose */
1331708Sstevel 	NULL,		/* qi_qadmin */
1341708Sstevel 	&cvcm_info,	/* qi_minfo */
1351708Sstevel 	NULL		/* qi_mstat */
1361708Sstevel };
1371708Sstevel 
1381708Sstevel struct streamtab	cvcinfo = {
1391708Sstevel 	&cvcrinit,	/* st_rdinit */
1401708Sstevel 	&cvcwinit,	/* st_wrinit */
1411708Sstevel 	NULL,		/* st_muxrinit */
1421708Sstevel 	NULL		/* st_muxwrinit */
1431708Sstevel };
1441708Sstevel 
1451708Sstevel static krwlock_t	cvclock;	/* lock protecting everything here */
1461708Sstevel static queue_t		*cvcinput_q;	/* queue for console input */
1471708Sstevel static queue_t		*cvcoutput_q;	/* queue for console output */
1481708Sstevel static int		cvc_instance = -1;
1491708Sstevel static int		cvc_stopped = 0;
1501708Sstevel static int		cvc_suspended = 0;
1511708Sstevel 
1521708Sstevel kthread_id_t		cvc_input_daemon_thread; /* just to aid debugging */
1531708Sstevel static kmutex_t		cvcmutex;	/* protects input */
1541708Sstevel static kmutex_t		cvc_iosram_input_mutex; /* protects IOSRAM inp buff */
1551708Sstevel static int		input_ok = 0;	/* true when stream is valid */
1561708Sstevel 
1571708Sstevel static int		via_iosram = 0; /* toggle switch */
1581708Sstevel static timeout_id_t	cvc_timeout_id = (timeout_id_t)-1;
1591708Sstevel static int		input_daemon_started = 0;
1601708Sstevel 
1611708Sstevel /* debugging functions */
1621708Sstevel #ifdef DEBUG
1631708Sstevel uint32_t cvc_dbg_flags = 0x0;
1641708Sstevel static void cvc_dbg(uint32_t flag, char *fmt,
1651708Sstevel 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
1661708Sstevel #endif
1671708Sstevel 
1681708Sstevel /*
1691708Sstevel  * Module linkage information for the kernel.
1701708Sstevel  */
1711708Sstevel 
1721708Sstevel DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
1737656SSherry.Moore@Sun.COM 		    nodev, cvc_info, (D_NEW|D_MTPERQ|D_MP), &cvcinfo,
1747656SSherry.Moore@Sun.COM 		    ddi_quiesce_not_supported);
1751708Sstevel 
1761708Sstevel extern int nodev(), nulldev();
1771708Sstevel extern struct mod_ops mod_driverops;
1781708Sstevel 
1791708Sstevel static struct modldrv modldrv = {
1801708Sstevel 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
1817656SSherry.Moore@Sun.COM 	"CVC driver 'cvc'",
1821708Sstevel 	&cvcops,	/* driver ops */
1831708Sstevel };
1841708Sstevel 
1851708Sstevel static struct modlinkage modlinkage = {
1861708Sstevel 	MODREV_1,
1871708Sstevel 	&modldrv,
1881708Sstevel 	NULL
1891708Sstevel };
1901708Sstevel 
1911708Sstevel int
_init()1921708Sstevel _init()
1931708Sstevel {
1941708Sstevel 	int	status;
1951708Sstevel 
1961708Sstevel 	status = mod_install(&modlinkage);
1971708Sstevel 	if (status == 0) {
1981708Sstevel 		mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
1991708Sstevel 	}
2001708Sstevel 	return (status);
2011708Sstevel }
2021708Sstevel 
2031708Sstevel int
_fini()2041708Sstevel _fini()
2051708Sstevel {
2061708Sstevel 	return (EBUSY);
2071708Sstevel }
2081708Sstevel 
2091708Sstevel int
_info(struct modinfo * modinfop)2101708Sstevel _info(struct modinfo *modinfop)
2111708Sstevel {
2121708Sstevel 	return (mod_info(&modlinkage, modinfop));
2131708Sstevel }
2141708Sstevel 
2151708Sstevel /*
2161708Sstevel  * DDI glue routines.
2171708Sstevel  */
2181708Sstevel 
2191708Sstevel /* ARGSUSED */
2201708Sstevel static int
cvc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2211708Sstevel cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2221708Sstevel {
2231708Sstevel 	static char	been_here = 0;
2241708Sstevel 
2251708Sstevel 	if (cmd == DDI_RESUME) {
2261708Sstevel 		cvc_suspended = 0;
2271708Sstevel 		if (cvcinput_q != NULL) {
2281708Sstevel 			qenable(WR(cvcinput_q));
2291708Sstevel 		}
2301708Sstevel 		return (DDI_SUCCESS);
2311708Sstevel 	}
2321708Sstevel 
2331708Sstevel 	mutex_enter(&cvcmutex);
2341708Sstevel 	if (!been_here) {
2351708Sstevel 		been_here = 1;
2361708Sstevel 		mutex_init(&cvc_iosram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
2371708Sstevel 		rw_init(&cvclock, NULL, RW_DRIVER, NULL);
2381708Sstevel 		cvc_instance = ddi_get_instance(devi);
2391708Sstevel 	} else {
2401708Sstevel #if defined(DEBUG)
2411708Sstevel 		cmn_err(CE_NOTE,
2427656SSherry.Moore@Sun.COM 		    "cvc_attach: called multiple times!! (instance = %d)",
2437656SSherry.Moore@Sun.COM 		    ddi_get_instance(devi));
2441708Sstevel #endif /* DEBUG */
2451708Sstevel 		mutex_exit(&cvcmutex);
2461708Sstevel 		return (DDI_SUCCESS);
2471708Sstevel 	}
2481708Sstevel 	mutex_exit(&cvcmutex);
2491708Sstevel 
2501708Sstevel 	if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
2511708Sstevel 	    0, NULL, NULL) == DDI_FAILURE) {
2521708Sstevel 		ddi_remove_minor_node(devi, NULL);
2531708Sstevel 		return (-1);
2541708Sstevel 	}
2551708Sstevel 	cvcdip = devi;
2561708Sstevel 	cvcinput_q = NULL;
2571708Sstevel 	cvcoutput_q = NULL;
2581708Sstevel 
2591708Sstevel 	CVC_DBG0(CVC_DBG_ATTACH, "Attached");
2601708Sstevel 
2611708Sstevel 	return (DDI_SUCCESS);
2621708Sstevel }
2631708Sstevel 
2641708Sstevel static int
cvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2651708Sstevel cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2661708Sstevel {
2671708Sstevel 	if (cmd == DDI_SUSPEND) {
2681708Sstevel 		cvc_suspended = 1;
2691708Sstevel 	} else {
2701708Sstevel 		if (cmd != DDI_DETACH) {
2711708Sstevel 			return (DDI_FAILURE);
2721708Sstevel 		}
2731708Sstevel 		/*
2741708Sstevel 		 * XXX this doesn't even begin to address the detach
2751708Sstevel 		 * issues - it doesn't terminate the outstanding thread,
2761708Sstevel 		 * it doesn't clean up mutexes, kill the timeout routine
2771708Sstevel 		 * etc.
2781708Sstevel 		 */
2791708Sstevel 		if (cvc_instance == ddi_get_instance(dip)) {
2801708Sstevel 			ddi_remove_minor_node(dip, NULL);
2811708Sstevel 		}
2821708Sstevel 	}
2831708Sstevel 
2841708Sstevel 	CVC_DBG0(CVC_DBG_DETACH, "Detached");
2851708Sstevel 
2861708Sstevel 	return (DDI_SUCCESS);
2871708Sstevel }
2881708Sstevel 
2891708Sstevel /* ARGSUSED */
2901708Sstevel static int
cvc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2911708Sstevel cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2921708Sstevel {
2931708Sstevel 	register int error;
2941708Sstevel 
2951708Sstevel 	switch (infocmd) {
2961708Sstevel 	case DDI_INFO_DEVT2DEVINFO:
2971708Sstevel 		if (cvcdip == NULL) {
2981708Sstevel 			error = DDI_FAILURE;
2991708Sstevel 		} else {
3001708Sstevel 			*result = (void *)cvcdip;
3011708Sstevel 			error = DDI_SUCCESS;
3021708Sstevel 		}
3031708Sstevel 		break;
3041708Sstevel 	case DDI_INFO_DEVT2INSTANCE:
3051708Sstevel 		*result = (void *)0;
3061708Sstevel 		error = DDI_SUCCESS;
3071708Sstevel 		break;
3081708Sstevel 	default:
3091708Sstevel 		error = DDI_FAILURE;
3101708Sstevel 	}
3111708Sstevel 	return (error);
3121708Sstevel }
3131708Sstevel 
3141708Sstevel /* ARGSUSED */
3151708Sstevel static int
cvc_open(register queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)3161708Sstevel cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
3171708Sstevel {
3181708Sstevel 	register int		unit = getminor(*devp);
3191708Sstevel 	register int		err = DDI_SUCCESS;
3201708Sstevel 	tty_common_t		*tty;
3211708Sstevel 	cvc_t			*cp;
3221708Sstevel 
3231708Sstevel 	if (unit != 0)
3241708Sstevel 		return (ENXIO);
3251708Sstevel 
3261708Sstevel 	if (q->q_ptr)
3271708Sstevel 		return (0);
3281708Sstevel 
3291708Sstevel 	cp = (cvc_t *)&cvc_common_tty;
3301708Sstevel 	bzero((caddr_t)cp, sizeof (cvc_t));
3311708Sstevel 	cp->cvc_wbufcid = 0;
3321708Sstevel 	tty = &cp->cvc_tty;
3331708Sstevel 	tty->t_readq = q;
3341708Sstevel 	tty->t_writeq = WR(q);
3351708Sstevel 	WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
3361708Sstevel 	cvcinput_q = RD(q);		/* save for cvc_redir */
3371708Sstevel 	qprocson(q);
3381708Sstevel 	mutex_enter(&cvcmutex);
3391708Sstevel 	input_ok = 1;
3401708Sstevel 
3411708Sstevel 	/*
3421708Sstevel 	 * Start the thread that handles input polling if it hasn't been started
3431708Sstevel 	 * previously.
3441708Sstevel 	 */
3451708Sstevel 	if (!input_daemon_started) {
3461708Sstevel 		input_daemon_started = 1;
3471708Sstevel 		mutex_exit(&cvcmutex);
3481708Sstevel 
3491708Sstevel 		cvc_input_daemon_thread = thread_create(NULL, 0,
3501708Sstevel 		    cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
3511708Sstevel 		CVC_DBG0(CVC_DBG_IOSRAM_RD, "Started input daemon");
3521708Sstevel 	} else {
3531708Sstevel 		mutex_exit(&cvcmutex);
3541708Sstevel 	}
3551708Sstevel 
3561708Sstevel 	/*
3571708Sstevel 	 * Set the console window size.
3581708Sstevel 	 */
3591708Sstevel 	mutex_enter(&cvc_iosram_input_mutex);
3601708Sstevel 	cvc_win_resize(FALSE);
3611708Sstevel 	mutex_exit(&cvc_iosram_input_mutex);
3621708Sstevel 
3631708Sstevel 	CVC_DBG0(CVC_DBG_OPEN, "Plumbed successfully");
3641708Sstevel 
3651708Sstevel 	return (err);
3661708Sstevel }
3671708Sstevel 
3681708Sstevel /* ARGSUSED */
3691708Sstevel static int
cvc_close(queue_t * q,int flag,cred_t * crp)3701708Sstevel cvc_close(queue_t *q, int flag, cred_t *crp)
3711708Sstevel {
3721708Sstevel 	register int		err = DDI_SUCCESS;
3731708Sstevel 	register cvc_t		*cp;
3741708Sstevel 
3751708Sstevel 	mutex_enter(&cvcmutex);
3761708Sstevel 	input_ok = 0;
3771708Sstevel 	mutex_exit(&cvcmutex);
3781708Sstevel 
3791708Sstevel 	cp = q->q_ptr;
3801708Sstevel 	if (cp->cvc_wbufcid != 0) {
3811708Sstevel 		unbufcall(cp->cvc_wbufcid);
3821708Sstevel 	}
3831708Sstevel 	ttycommon_close(&cp->cvc_tty);
3841708Sstevel 	WR(q)->q_ptr = q->q_ptr = NULL;
3851708Sstevel 	cvcinput_q = NULL;
3861708Sstevel 	bzero((caddr_t)cp, sizeof (cvc_t));
3871708Sstevel 	qprocsoff(q);
3881708Sstevel 
3891708Sstevel 	CVC_DBG0(CVC_DBG_CLOSE, "Un-plumbed successfully");
3901708Sstevel 
3911708Sstevel 	return (err);
3921708Sstevel }
3931708Sstevel 
3941708Sstevel 
3951708Sstevel /*
3961708Sstevel  * cvc_wput()
3971708Sstevel  *	cn driver does a strwrite of console output data to rconsvp which has
3981708Sstevel  *	been set by consconfig. The data enters the cvc stream at the streamhead
3991708Sstevel  *	and flows thru ttycompat and ldterm which have been pushed on the
4001708Sstevel  *	stream.  Console output data gets sent out either to cvcredir, if the
4011708Sstevel  *	network path is available and selected, or to IOSRAM otherwise.  Data is
4021708Sstevel  *	sent to cvcredir via its read queue (cvcoutput_q, which gets set in
4031708Sstevel  *	cvc_register()).  If the IOSRAM path is selected, or if previous mblks
4041708Sstevel  *	are currently queued up for processing, the new mblk will be queued
4051708Sstevel  *	and handled later on by cvc_wsrv.
4061708Sstevel  */
4071708Sstevel static int
cvc_wput(queue_t * q,mblk_t * mp)4081708Sstevel cvc_wput(queue_t *q, mblk_t *mp)
4091708Sstevel {
4101708Sstevel 	int		error = 0;
4111708Sstevel 
4121708Sstevel 	rw_enter(&cvclock, RW_READER);
4131708Sstevel 
4141708Sstevel 	CVC_DBG2(CVC_DBG_WPUT, "mp 0x%x db_type 0x%x",
4157656SSherry.Moore@Sun.COM 	    mp, mp->b_datap->db_type);
4161708Sstevel 
4171708Sstevel 	switch (mp->b_datap->db_type) {
4181708Sstevel 
4191708Sstevel 		case M_IOCTL:
4201708Sstevel 		case M_CTL: {
4211708Sstevel 			struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
4221708Sstevel 
4231708Sstevel 			switch (iocp->ioc_cmd) {
4241708Sstevel 				/*
4251708Sstevel 				 * These ioctls are only supposed to be
4261708Sstevel 				 * processed after everything else that is
4271708Sstevel 				 * already queued awaiting processing, so throw
4281708Sstevel 				 * them on the queue and let cvc_wsrv handle
4291708Sstevel 				 * them.
4301708Sstevel 				 */
4311708Sstevel 				case TCSETSW:
4321708Sstevel 				case TCSETSF:
4331708Sstevel 				case TCSETAW:
4341708Sstevel 				case TCSETAF:
4351708Sstevel 				case TCSBRK:
436*11311SSurya.Prakki@Sun.COM 					(void) putq(q, mp);
4371708Sstevel 					break;
4381708Sstevel 
4391708Sstevel 				default:
4401708Sstevel 					cvc_ioctl(q, mp);
4411708Sstevel 			}
4421708Sstevel 			break;
4431708Sstevel 		}
4441708Sstevel 
4451708Sstevel 		case M_FLUSH:
4461708Sstevel 			if (*mp->b_rptr & FLUSHW) {
4471708Sstevel 				/*
4481708Sstevel 				 * Flush our write queue.
4491708Sstevel 				 */
4501708Sstevel 				flushq(q, FLUSHDATA);
4511708Sstevel 				*mp->b_rptr &= ~FLUSHW;
4521708Sstevel 			}
4531708Sstevel 			if (*mp->b_rptr & FLUSHR) {
4541708Sstevel 				flushq(RD(q), FLUSHDATA);
4551708Sstevel 				qreply(q, mp);
4561708Sstevel 			} else
4571708Sstevel 				freemsg(mp);
4581708Sstevel 			break;
4591708Sstevel 
4601708Sstevel 		case M_STOP:
4611708Sstevel 			cvc_stopped = 1;
4621708Sstevel 			freemsg(mp);
4631708Sstevel 			break;
4641708Sstevel 
4651708Sstevel 		case M_START:
4661708Sstevel 			cvc_stopped = 0;
4671708Sstevel 			freemsg(mp);
4681708Sstevel 			qenable(q);  /* Start up delayed messages */
4691708Sstevel 			break;
4701708Sstevel 
4711708Sstevel 		case M_READ:
4721708Sstevel 			/*
4731708Sstevel 			 * ldterm handles this (VMIN/VTIME processing).
4741708Sstevel 			 */
4751708Sstevel 			freemsg(mp);
4761708Sstevel 			break;
4771708Sstevel 
4781708Sstevel 		default:
4791708Sstevel 			cmn_err(CE_WARN, "cvc_wput: unexpected mblk type - mp ="
480*11311SSurya.Prakki@Sun.COM 			    " 0x%p, type = 0x%x", (void *)mp,
481*11311SSurya.Prakki@Sun.COM 			    mp->b_datap->db_type);
4821708Sstevel 			freemsg(mp);
4831708Sstevel 			break;
4841708Sstevel 
4851708Sstevel 		case M_DATA:
4861708Sstevel 			/*
4871708Sstevel 			 * If there are other mblks queued up for transmission,
4881708Sstevel 			 * or we're using IOSRAM either because cvcredir hasn't
4891708Sstevel 			 * registered yet or because we were configured that
4901708Sstevel 			 * way, or cvc has been stopped or suspended, place this
4911708Sstevel 			 * mblk on the input queue for future processing.
4921708Sstevel 			 * Otherwise, hand it off to cvcredir for transmission
4931708Sstevel 			 * via the network.
4941708Sstevel 			 */
4951708Sstevel 			if (q->q_first != NULL || cvcoutput_q == NULL ||
4961708Sstevel 			    via_iosram || cvc_stopped == 1 ||
4971708Sstevel 			    cvc_suspended == 1) {
4981708Sstevel 				(void) putq(q, mp);
4991708Sstevel 			} else {
5001708Sstevel 				/*
5011708Sstevel 				 * XXX - should canputnext be called here?
5021708Sstevel 				 * Starfire's cvc doesn't do that, and it
5031708Sstevel 				 * appears to work anyway.
5041708Sstevel 				 */
5051708Sstevel 				(void) putnext(cvcoutput_q, mp);
5061708Sstevel 			}
5071708Sstevel 			break;
5081708Sstevel 
5091708Sstevel 	}
5101708Sstevel 	rw_exit(&cvclock);
5111708Sstevel 	return (error);
5121708Sstevel }
5131708Sstevel 
5141708Sstevel /*
5151708Sstevel  * cvc_wsrv()
5161708Sstevel  *	cvc_wsrv handles mblks that have been queued by cvc_wput either because
5171708Sstevel  *	the IOSRAM path was selected or the queue contained preceding mblks.  To
5181708Sstevel  *	optimize processing (particularly if the IOSRAM path is selected), all
5191708Sstevel  *	mblks are pulled off of the queue and chained together.  Then, if there
5201708Sstevel  *	are any mblks on the chain, they are either forwarded to cvcredir or
5211708Sstevel  *	sent for IOSRAM processing as appropriate given current circumstances.
5221708Sstevel  *	IOSRAM processing may not be able to handle all of the data in the
5231708Sstevel  *	chain, in which case the remaining data is placed back on the queue and
5241708Sstevel  *	a timeout routine is registered to reschedule cvc_wsrv in the future.
5251708Sstevel  *	Automatic scheduling of the queue is disabled (noenable(q)) while
5261708Sstevel  *	cvc_wsrv is running to avoid superfluous calls.
5271708Sstevel  */
5281708Sstevel static int
cvc_wsrv(queue_t * q)5291708Sstevel cvc_wsrv(queue_t *q)
5301708Sstevel {
5311708Sstevel 	mblk_t *total_mp = NULL;
5321708Sstevel 	mblk_t *mp;
5331708Sstevel 
5341708Sstevel 	if (cvc_stopped == 1 || cvc_suspended == 1) {
5351708Sstevel 		return (0);
5361708Sstevel 	}
5371708Sstevel 
5381708Sstevel 	rw_enter(&cvclock, RW_READER);
5391708Sstevel 	noenable(q);
5401708Sstevel 
5411708Sstevel 	/*
5421708Sstevel 	 * If there's already a timeout registered for scheduling this routine
5431708Sstevel 	 * in the future, it's a safe bet that we don't want to run right now.
5441708Sstevel 	 */
5451708Sstevel 	if (cvc_timeout_id != (timeout_id_t)-1) {
5461708Sstevel 		enableok(q);
5471708Sstevel 		rw_exit(&cvclock);
5481708Sstevel 		return (0);
5491708Sstevel 	}
5501708Sstevel 
5511708Sstevel 	/*
5521708Sstevel 	 * Start by linking all of the queued M_DATA mblks into a single chain
5531708Sstevel 	 * so we can flush as much as possible to IOSRAM (if we choose that
5541708Sstevel 	 * route).
5551708Sstevel 	 */
5561708Sstevel 	while ((mp = getq(q)) != NULL) {
5571708Sstevel 		/*
5581708Sstevel 		 * Technically, certain IOCTLs are supposed to be processed only
5591708Sstevel 		 * after all preceding data has completely "drained".  In an
5601708Sstevel 		 * attempt to support that, we delay processing of those IOCTLs
5611708Sstevel 		 * until this point.  It is still possible that an IOCTL will be
5621708Sstevel 		 * processed before all preceding data is drained, for instance
5631708Sstevel 		 * in the case where not all of the preceding data would fit
5641708Sstevel 		 * into IOSRAM and we have to place it back on the queue.
5651708Sstevel 		 * However, since none of these IOCTLs really appear to have any
5661708Sstevel 		 * relevance for cvc, and we weren't supporting delayed
5671708Sstevel 		 * processing at _all_ previously, this partial implementation
5681708Sstevel 		 * should suffice.  (Fully implementing the delayed IOCTL
5691708Sstevel 		 * processing would be unjustifiably difficult given the nature
5701708Sstevel 		 * of the underlying IOSRAM console protocol.)
5711708Sstevel 		 */
5721708Sstevel 		if (mp->b_datap->db_type == M_IOCTL) {
5731708Sstevel 			cvc_ioctl(q, mp);
5741708Sstevel 			continue;
5751708Sstevel 		}
5761708Sstevel 
5771708Sstevel 		/*
5781708Sstevel 		 * We know that only M_IOCTL and M_DATA blocks are placed on our
5791708Sstevel 		 * queue.  Since this block isn't an M_IOCTL, it must be M_DATA.
5801708Sstevel 		 */
5811708Sstevel 		if (total_mp != NULL) {
5821708Sstevel 			linkb(total_mp, mp);
5831708Sstevel 		} else {
5841708Sstevel 			total_mp = mp;
5851708Sstevel 		}
5861708Sstevel 	}
5871708Sstevel 
5881708Sstevel 	/*
5891708Sstevel 	 * Do we actually have anything to do?
5901708Sstevel 	 */
5911708Sstevel 	if (total_mp == NULL) {
5921708Sstevel 		enableok(q);
5931708Sstevel 		rw_exit(&cvclock);
5941708Sstevel 		return (0);
5951708Sstevel 	}
5961708Sstevel 
5971708Sstevel 	/*
5981708Sstevel 	 * Yes, we do, so send the data to either cvcredir or IOSRAM as
5991708Sstevel 	 * appropriate.  In the latter case, we might not be able to transmit
6001708Sstevel 	 * everything right now, so re-queue the remainder.
6011708Sstevel 	 */
6021708Sstevel 	if (cvcoutput_q != NULL && !via_iosram) {
6031708Sstevel 		CVC_DBG0(CVC_DBG_NETWORK_WR, "Sending to cvcredir.");
6041708Sstevel 		/*
6051708Sstevel 		 * XXX - should canputnext be called here?  Starfire's cvc
6061708Sstevel 		 * doesn't do that, and it appears to work anyway.
6071708Sstevel 		 */
6081708Sstevel 		(void) putnext(cvcoutput_q, total_mp);
6091708Sstevel 	} else {
6101708Sstevel 		CVC_DBG0(CVC_DBG_IOSRAM_WR, "Send to IOSRAM.");
6111708Sstevel 		cvc_send_to_iosram(&total_mp);
6121708Sstevel 		if (total_mp != NULL) {
6131708Sstevel 			(void) putbq(q, total_mp);
6141708Sstevel 		}
6151708Sstevel 	}
6161708Sstevel 
6171708Sstevel 	/*
6181708Sstevel 	 * If there is still data queued at this point, make sure the queue
6191708Sstevel 	 * gets scheduled again after an appropriate delay (which has been
6201708Sstevel 	 * somewhat arbitrarily selected as half of the SC's input polling
6211708Sstevel 	 * frequency).
6221708Sstevel 	 */
6231708Sstevel 	enableok(q);
6241708Sstevel 	if (q->q_first != NULL) {
6251708Sstevel 		if (cvc_timeout_id == (timeout_id_t)-1) {
6261708Sstevel 			cvc_timeout_id = timeout(cvc_flush_queue,
6271708Sstevel 			    NULL, drv_usectohz(CVC_IOSRAM_POLL_USECS / 2));
6281708Sstevel 		}
6291708Sstevel 	}
6301708Sstevel 	rw_exit(&cvclock);
6311708Sstevel 	return (0);
6321708Sstevel }
6331708Sstevel 
6341708Sstevel 
6351708Sstevel /*
6361708Sstevel  * cvc_ioctl()
6371708Sstevel  *	handle normal console ioctls.
6381708Sstevel  */
6391708Sstevel static void
cvc_ioctl(register queue_t * q,register mblk_t * mp)6401708Sstevel cvc_ioctl(register queue_t *q, register mblk_t *mp)
6411708Sstevel {
6421708Sstevel 	register cvc_t			*cp = q->q_ptr;
6431708Sstevel 	int				datasize;
6441708Sstevel 	int				error = 0;
6451708Sstevel 
6461708Sstevel 	/*
6471708Sstevel 	 * Let ttycommon_ioctl take the first shot at processing the ioctl.  If
6481708Sstevel 	 * it fails because it can't allocate memory, schedule processing of the
6491708Sstevel 	 * ioctl later when a proper buffer is available.  The mblk that
6501708Sstevel 	 * couldn't be processed will have been stored in the tty structure by
6511708Sstevel 	 * ttycommon_ioctl.
6521708Sstevel 	 */
6531708Sstevel 	datasize = ttycommon_ioctl(&cp->cvc_tty, q, mp, &error);
6541708Sstevel 	if (datasize != 0) {
6551708Sstevel 		if (cp->cvc_wbufcid) {
6561708Sstevel 			unbufcall(cp->cvc_wbufcid);
6571708Sstevel 		}
6581708Sstevel 		cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
6591708Sstevel 		return;
6601708Sstevel 	}
6611708Sstevel 
6621708Sstevel 	/*
6631708Sstevel 	 * ttycommon_ioctl didn't do anything, but there's nothing we really
6641708Sstevel 	 * support either with the exception of TCSBRK, which is supported
6651708Sstevel 	 * only to appear a bit more like a serial device for software that
6661708Sstevel 	 * expects TCSBRK to work.
6671708Sstevel 	 */
6681708Sstevel 	if (error != 0) {
6691708Sstevel 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
6701708Sstevel 
6711708Sstevel 		if (iocp->ioc_cmd == TCSBRK) {
6721708Sstevel 			miocack(q, mp, 0, 0);
6731708Sstevel 		} else {
6741708Sstevel 			miocnak(q, mp, 0, EINVAL);
6751708Sstevel 		}
6761708Sstevel 	} else {
6771708Sstevel 		qreply(q, mp);
6781708Sstevel 	}
6791708Sstevel }
6801708Sstevel 
6811708Sstevel 
6821708Sstevel /*
6831708Sstevel  * cvc_redir()
6841708Sstevel  *	called from cvcredir:cvcr_wput() to handle console input
6851708Sstevel  *	data. This routine puts the cvcredir write (downstream) data
6861708Sstevel  *	onto the cvc read (upstream) queues.
6871708Sstevel  */
6881708Sstevel int
cvc_redir(mblk_t * mp)6891708Sstevel cvc_redir(mblk_t *mp)
6901708Sstevel {
6911708Sstevel 	register struct iocblk	*iocp;
6921708Sstevel 	int			rv = 1;
6931708Sstevel 
6941708Sstevel 	/*
6951708Sstevel 	 * This function shouldn't be called if cvcredir hasn't registered yet.
6961708Sstevel 	 */
6971708Sstevel 	if (cvcinput_q == NULL) {
6981708Sstevel 		/*
6991708Sstevel 		 * Need to let caller know that it may be necessary for them to
7001708Sstevel 		 * free the message buffer, so return 0.
7011708Sstevel 		 */
7021708Sstevel 		CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled");
7031708Sstevel 		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
7041708Sstevel 		return (0);
7051708Sstevel 	}
7061708Sstevel 
7071708Sstevel 	CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type);
7081708Sstevel 	if (mp->b_datap->db_type == M_DATA) {
7091708Sstevel 		/*
7101708Sstevel 		 * XXX - should canputnext be called here?  Starfire's cvc
7111708Sstevel 		 * doesn't do that, and it appears to work anyway.
7121708Sstevel 		 */
7131708Sstevel 		CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp);
7141708Sstevel 		(void) putnext(cvcinput_q, mp);
7151708Sstevel 	} else if (mp->b_datap->db_type == M_IOCTL) {
7161708Sstevel 		/*
7171708Sstevel 		 * The cvcredir driver filters out ioctl mblks we wouldn't
7181708Sstevel 		 * understand, so we don't have to check for every conceivable
7191708Sstevel 		 * ioc_cmd.  However, additional ioctls may be supported (again)
7201708Sstevel 		 * some day, so the code is structured to check the value even
7211708Sstevel 		 * though there's only one that is currently supported.
7221708Sstevel 		 */
7231708Sstevel 		iocp = (struct iocblk *)mp->b_rptr;
7241708Sstevel 		if (iocp->ioc_cmd == CVC_DISCONNECT) {
7251708Sstevel 			(void) putnextctl(cvcinput_q, M_HANGUP);
7261708Sstevel 		}
7271708Sstevel 	} else {
7281708Sstevel 		/*
7291708Sstevel 		 * Since we don't know what this mblk is, we're not going to
7301708Sstevel 		 * process it.
7311708Sstevel 		 */
7321708Sstevel 		CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d",
7331708Sstevel 		    mp->b_datap->db_type);
7341708Sstevel 		rv = 0;
7351708Sstevel 	}
7361708Sstevel 
7371708Sstevel 	return (rv);
7381708Sstevel }
7391708Sstevel 
7401708Sstevel 
7411708Sstevel /*
7421708Sstevel  * cvc_register()
7431708Sstevel  *	called from cvcredir to register it's queues.  cvc
7441708Sstevel  *	receives data from cn via the streamhead and sends it to cvcredir
7451708Sstevel  *	via pointers to cvcredir's queues.
7461708Sstevel  */
7471708Sstevel int
cvc_register(queue_t * q)7481708Sstevel cvc_register(queue_t *q)
7491708Sstevel {
7501708Sstevel 	int error = -1;
7511708Sstevel 
7521708Sstevel 	if (cvcinput_q == NULL)
7531708Sstevel 		cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
7541708Sstevel 	rw_enter(&cvclock, RW_WRITER);
7551708Sstevel 	if (cvcoutput_q == NULL) {
7561708Sstevel 		cvcoutput_q = RD(q);  /* Make sure its the upstream q */
7571708Sstevel 		qprocson(cvcoutput_q);	/* must be done within cvclock */
7581708Sstevel 		error = 0;
7591708Sstevel 	} else {
7601708Sstevel 		/*
7611708Sstevel 		 * cmn_err will call us, so release lock.
7621708Sstevel 		 */
7631708Sstevel 		rw_exit(&cvclock);
7641708Sstevel 		if (cvcoutput_q == q)
7651708Sstevel 			cmn_err(CE_WARN, "cvc_register: duplicate q!");
7661708Sstevel 		else
7671708Sstevel 			cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p",
768*11311SSurya.Prakki@Sun.COM 			    (void *)q);
7691708Sstevel 		return (error);
7701708Sstevel 	}
7711708Sstevel 	rw_exit(&cvclock);
7721708Sstevel 	return (error);
7731708Sstevel }
7741708Sstevel 
7751708Sstevel 
7761708Sstevel /*
7771708Sstevel  * cvc_unregister()
7781708Sstevel  *	called from cvcredir to clear pointers to its queues.
7791708Sstevel  *	cvcredir no longer wants to send or receive data.
7801708Sstevel  */
7811708Sstevel void
cvc_unregister(queue_t * q)7821708Sstevel cvc_unregister(queue_t *q)
7831708Sstevel {
7841708Sstevel 	rw_enter(&cvclock, RW_WRITER);
7851708Sstevel 	if (q == cvcoutput_q) {
7861708Sstevel 		qprocsoff(cvcoutput_q);	/* must be done within cvclock */
7871708Sstevel 		cvcoutput_q = NULL;
7881708Sstevel 	} else {
7891708Sstevel 		rw_exit(&cvclock);
790*11311SSurya.Prakki@Sun.COM 		cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered",
791*11311SSurya.Prakki@Sun.COM 		    (void *)q);
7921708Sstevel 		return;
7931708Sstevel 	}
7941708Sstevel 	rw_exit(&cvclock);
7951708Sstevel }
7961708Sstevel 
7971708Sstevel 
7981708Sstevel /*
7991708Sstevel  * cvc_reioctl()
8001708Sstevel  *	Retry an "ioctl", now that "bufcall" claims we may be able
8011708Sstevel  *	to allocate the buffer we need.
8021708Sstevel  */
8031708Sstevel static void
cvc_reioctl(void * unit)8041708Sstevel cvc_reioctl(void *unit)
8051708Sstevel {
8061708Sstevel 	register queue_t	*q;
8071708Sstevel 	register mblk_t		*mp;
8081708Sstevel 	register cvc_t		*cp = (cvc_t *)unit;
8091708Sstevel 
8101708Sstevel 	/*
8111708Sstevel 	 * The bufcall is no longer pending.
8121708Sstevel 	 */
8131708Sstevel 	if (!cp->cvc_wbufcid) {
8141708Sstevel 		return;
8151708Sstevel 	}
8161708Sstevel 	cp->cvc_wbufcid = 0;
8171708Sstevel 	if ((q = cp->cvc_tty.t_writeq) == NULL) {
8181708Sstevel 		return;
8191708Sstevel 	}
8201708Sstevel 	if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
8211708Sstevel 		/* not pending any more */
8221708Sstevel 		cp->cvc_tty.t_iocpending = NULL;
8231708Sstevel 		cvc_ioctl(q, mp);
8241708Sstevel 	}
8251708Sstevel }
8261708Sstevel 
8271708Sstevel 
8281708Sstevel /*
8291708Sstevel  * cvc_iosram_ops()
8301708Sstevel  *	Process commands sent to cvc from netcon_server via IOSRAM
8311708Sstevel  */
8321708Sstevel static void
cvc_iosram_ops(uint8_t op)8331708Sstevel cvc_iosram_ops(uint8_t op)
8341708Sstevel {
8351708Sstevel 	int		rval = ESUCCESS;
8361708Sstevel 	static uint8_t	stale_op = 0;
8371708Sstevel 
8381708Sstevel 	ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex));
8391708Sstevel 
8401708Sstevel 	CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op);
8411708Sstevel 
8421708Sstevel 	/*
8431708Sstevel 	 * If this is a repeated notice of a command that was previously
8441708Sstevel 	 * processed but couldn't be cleared due to EAGAIN (tunnel switch in
8451708Sstevel 	 * progress), just clear the data_valid flag and return.
8461708Sstevel 	 */
8471708Sstevel 	if (op == stale_op) {
8481708Sstevel 		if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
8491708Sstevel 		    IOSRAM_INT_NONE) == 0) {
8501708Sstevel 			stale_op = 0;
8511708Sstevel 		}
8521708Sstevel 		return;
8531708Sstevel 	}
8541708Sstevel 	stale_op = 0;
8551708Sstevel 
8561708Sstevel 	switch (op) {
8571708Sstevel 		case CVC_IOSRAM_BREAK:		/* A console break (L1-A) */
8581708Sstevel 			abort_sequence_enter((char *)NULL);
8591708Sstevel 			break;
8601708Sstevel 
8611708Sstevel 		case CVC_IOSRAM_DISCONNECT:	/* Break connection, hang up */
8621708Sstevel 			if (cvcinput_q)
8631708Sstevel 				(void) putnextctl(cvcinput_q, M_HANGUP);
8641708Sstevel 			break;
8651708Sstevel 
8661708Sstevel 		case CVC_IOSRAM_VIA_NET:	/* console via network */
8671708Sstevel 			via_iosram = 0;
8681708Sstevel 			break;
8691708Sstevel 
8701708Sstevel 		case CVC_IOSRAM_VIA_IOSRAM:	/* console via iosram */
8711708Sstevel 			via_iosram = 1;
8721708Sstevel 			/*
8731708Sstevel 			 * Tell cvcd to close any network connection it has.
8741708Sstevel 			 */
8751708Sstevel 			rw_enter(&cvclock, RW_READER);
8761708Sstevel 			if (cvcoutput_q != NULL) {
8771708Sstevel 				(void) putnextctl(cvcoutput_q, M_HANGUP);
8781708Sstevel 			}
8791708Sstevel 			rw_exit(&cvclock);
8801708Sstevel 			break;
8811708Sstevel 
8821708Sstevel 		case CVC_IOSRAM_WIN_RESIZE:	/* console window size data */
8831708Sstevel 			/*
8841708Sstevel 			 * In the case of window resizing, we don't want to
8851708Sstevel 			 * record a stale_op value because we should always use
8861708Sstevel 			 * the most recent winsize info, which could change
8871708Sstevel 			 * between the time that we fail to clear the flag and
8881708Sstevel 			 * the next time we try to process the command.  So,
8891708Sstevel 			 * we'll just let cvc_win_resize clear the data_valid
8901708Sstevel 			 * flag itself (hence the TRUE parameter) and not worry
8911708Sstevel 			 * about whether or not it succeeds.
8921708Sstevel 			 */
8931708Sstevel 			cvc_win_resize(TRUE);
8941708Sstevel 			return;
8951708Sstevel 			/* NOTREACHED */
8961708Sstevel 
8971708Sstevel 		default:
8981708Sstevel 			cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op);
8991708Sstevel 			break;
9001708Sstevel 	}
9011708Sstevel 
9021708Sstevel 	/*
9031708Sstevel 	 * Clear CONC's data_valid flag to indicate that the chunk is available
9041708Sstevel 	 * for further communications.  If the flag can't be cleared due to an
9051708Sstevel 	 * error, record the op value so we'll know to ignore it when we see it
9061708Sstevel 	 * on the next poll.
9071708Sstevel 	 */
9081708Sstevel 	rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
9091708Sstevel 	    IOSRAM_INT_NONE);
9101708Sstevel 	if (rval != 0) {
9111708Sstevel 		stale_op = op;
9121708Sstevel 		if (rval != EAGAIN) {
9131708Sstevel 			cmn_err(CE_WARN,
9141708Sstevel 			    "cvc_iosram_ops: set flag for cntlbuf ret %d",
9151708Sstevel 			    rval);
9161708Sstevel 		}
9171708Sstevel 	}
9181708Sstevel }
9191708Sstevel 
9201708Sstevel 
9211708Sstevel /*
9221708Sstevel  * cvc_send_to_iosram()
9231708Sstevel  *	Flush as much data as possible to the CONO chunk.  If successful, free
9241708Sstevel  *	any mblks that were completely transmitted, update the b_rptr field in
9251708Sstevel  *	the first remaining mblk if it was partially transmitted, and update the
9261708Sstevel  *	caller's pointer to the new head of the mblk chain.  Since the software
9271708Sstevel  *	that will be pulling this data out of IOSRAM (dxs on the SC) is just
9281708Sstevel  *	polling at some frequency, we avoid attempts to flush data to IOSRAM any
9291708Sstevel  *	faster than a large divisor of that polling frequency.
9301708Sstevel  *
9311708Sstevel  *	Note that "cvc_buf_t out" is only declared "static" to keep it from
9321708Sstevel  *	being allocated on the stack.  Allocating 1K+ structures on the stack
9331708Sstevel  *	seems rather antisocial.
9341708Sstevel  */
9351708Sstevel static void
cvc_send_to_iosram(mblk_t ** chainpp)9361708Sstevel cvc_send_to_iosram(mblk_t **chainpp)
9371708Sstevel {
9381708Sstevel 	int			rval;
9391708Sstevel 	uint8_t			dvalid;
9401708Sstevel 	uchar_t			*cp;
9411708Sstevel 	mblk_t			*mp;
9421708Sstevel 	mblk_t			*last_empty_mp;
9431708Sstevel 	static clock_t		last_flush = (clock_t)-1;
9441708Sstevel 	static cvc_buf_t	out;   /* see note above about static */
9451708Sstevel 
9461708Sstevel 	ASSERT(chainpp != NULL);
9471708Sstevel 
9481708Sstevel 	/*
9491708Sstevel 	 * We _do_ have something to do, right?
9501708Sstevel 	 */
9511708Sstevel 	if (*chainpp == NULL) {
9521708Sstevel 		return;
9531708Sstevel 	}
9541708Sstevel 
9551708Sstevel 	/*
9561708Sstevel 	 * We can actually increase throughput by throttling back on attempts to
9571708Sstevel 	 * flush data to IOSRAM, since trying to write every little bit of data
9581708Sstevel 	 * as it shows up will actually generate more delays waiting for the SC
9591708Sstevel 	 * to pick up each of those bits.  Instead, we'll avoid attempting to
9601708Sstevel 	 * write data to IOSRAM any faster than half of the polling frequency we
9611708Sstevel 	 * expect the SC to be using.
9621708Sstevel 	 */
9631708Sstevel 	if (ddi_get_lbolt() - last_flush <
9641708Sstevel 	    drv_usectohz(CVC_IOSRAM_POLL_USECS / 2)) {
9651708Sstevel 		return;
9661708Sstevel 	}
9671708Sstevel 
9681708Sstevel 	/*
9691708Sstevel 	 * If IOSRAM is inaccessible or the CONO chunk still holds data that
9701708Sstevel 	 * hasn't been picked up by the SC, there's nothing we can do right now.
9711708Sstevel 	 */
9721708Sstevel 	rval = iosram_get_flag(IOSRAM_KEY_CONO, &dvalid, NULL);
9731708Sstevel 	if ((rval != 0) || (dvalid == IOSRAM_DATA_VALID)) {
9741708Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
9751708Sstevel 			cmn_err(CE_WARN, "cvc_send_to_iosram: get_flag ret %d",
9761708Sstevel 			    rval);
9771708Sstevel 		}
9781708Sstevel 		return;
9791708Sstevel 	}
9801708Sstevel 
9811708Sstevel 	/*
9821708Sstevel 	 * Copy up to MAX_XFER_COUTPUT chars from the mblk chain into a buffer.
9831708Sstevel 	 * Don't change any of the mblks just yet, since we can't be certain
9841708Sstevel 	 * that we'll be successful in writing data to the CONO chunk.
9851708Sstevel 	 */
9861708Sstevel 	out.count = 0;
9871708Sstevel 	mp = *chainpp;
9881708Sstevel 	cp = mp->b_rptr;
9891708Sstevel 	last_empty_mp = NULL;
9901708Sstevel 	while ((mp != NULL) && (out.count < MAX_XFER_COUTPUT)) {
9911708Sstevel 		/*
9921708Sstevel 		 * Process as many of the characters in the current mblk as
9931708Sstevel 		 * possible.
9941708Sstevel 		 */
9951708Sstevel 		while ((cp != mp->b_wptr) && (out.count < MAX_XFER_COUTPUT)) {
9961708Sstevel 			out.buffer[out.count++] = *cp++;
9971708Sstevel 		}
9981708Sstevel 
9991708Sstevel 		/*
10001708Sstevel 		 * Did we process that entire mblk?  If so, move on to the next
10011708Sstevel 		 * one.  If not, we're done filling the buffer even if there's
10021708Sstevel 		 * space left, because apparently there wasn't room to process
10031708Sstevel 		 * the next character.
10041708Sstevel 		 */
10051708Sstevel 		if (cp != mp->b_wptr) {
10061708Sstevel 			break;
10071708Sstevel 		}
10081708Sstevel 
10091708Sstevel 		/*
10101708Sstevel 		 * When this loop terminates, last_empty_mp will point to the
10111708Sstevel 		 * last mblk that was completely processed, mp will point to the
10121708Sstevel 		 * following mblk (or NULL if no more mblks exist), and cp will
10131708Sstevel 		 * point to the first untransmitted character in the mblk
10141708Sstevel 		 * pointed to by mp.  We'll need this data to update the mblk
10151708Sstevel 		 * chain if all of the data is successfully transmitted.
10161708Sstevel 		 */
10171708Sstevel 		last_empty_mp = mp;
10181708Sstevel 		mp = mp->b_cont;
10191708Sstevel 		cp = (mp != NULL) ? mp->b_rptr : NULL;
10201708Sstevel 	}
10211708Sstevel 
10221708Sstevel 	/*
10231708Sstevel 	 * If we succeeded in preparing some data, try to transmit it through
10241708Sstevel 	 * IOSRAM.  First write the count and the data, which can be done in a
10251708Sstevel 	 * single operation thanks to the buffer structure we use, then set the
10261708Sstevel 	 * data_valid flag if the first step succeeded.
10271708Sstevel 	 */
10281708Sstevel 	if (out.count != 0) {
10291708Sstevel 		rval = iosram_wr(IOSRAM_KEY_CONO, COUNT_OFFSET,
10301708Sstevel 		    CONSBUF_COUNT_SIZE + out.count, (caddr_t)&out);
10311708Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
10321708Sstevel 			cmn_err(CE_WARN, "cvc_putc: write ret %d", rval);
10331708Sstevel 		}
10341708Sstevel 
10351708Sstevel 		/* if the data write succeeded, set the data_valid flag */
10361708Sstevel 		if (rval == 0) {
10371708Sstevel 			rval = iosram_set_flag(IOSRAM_KEY_CONO,
10381708Sstevel 			    IOSRAM_DATA_VALID, IOSRAM_INT_NONE);
10391708Sstevel 			if ((rval != 0) && (rval != EAGAIN)) {
10401708Sstevel 				cmn_err(CE_WARN,
10411708Sstevel 				    "cvc_putc: set flags for outbuf ret %d",
10421708Sstevel 				    rval);
10431708Sstevel 			}
10441708Sstevel 		}
10451708Sstevel 
10461708Sstevel 		/*
10471708Sstevel 		 * If we successfully transmitted any data, modify the caller's
10481708Sstevel 		 * mblk chain to remove the data that was transmitted, freeing
10491708Sstevel 		 * all mblks that were completely processed.
10501708Sstevel 		 */
10511708Sstevel 		if (rval == 0) {
10521708Sstevel 			last_flush = ddi_get_lbolt();
10531708Sstevel 
10541708Sstevel 			/*
10551708Sstevel 			 * If any data is left over, update the b_rptr field of
10561708Sstevel 			 * the first remaining mblk in case some of its data was
10571708Sstevel 			 * processed.
10581708Sstevel 			 */
10591708Sstevel 			if (mp != NULL) {
10601708Sstevel 				mp->b_rptr = cp;
10611708Sstevel 			}
10621708Sstevel 
10631708Sstevel 			/*
10641708Sstevel 			 * If any mblks have been emptied, unlink them from the
10651708Sstevel 			 * residual chain, free them, and update the caller's
10661708Sstevel 			 * mblk pointer.
10671708Sstevel 			 */
10681708Sstevel 			if (last_empty_mp != NULL) {
10691708Sstevel 				last_empty_mp->b_cont = NULL;
10701708Sstevel 				freemsg(*chainpp);
10711708Sstevel 				*chainpp = mp;
10721708Sstevel 			}
10731708Sstevel 		}
10741708Sstevel 	}
10751708Sstevel }
10761708Sstevel 
10771708Sstevel 
10781708Sstevel /*
10791708Sstevel  * cvc_flush_queue()
10801708Sstevel  *	Tell the STREAMS subsystem to schedule cvc_wsrv to process the queue we
10811708Sstevel  *	use to gather console output.
10821708Sstevel  */
10831708Sstevel /* ARGSUSED */
10841708Sstevel static void
cvc_flush_queue(void * notused)10851708Sstevel cvc_flush_queue(void *notused)
10861708Sstevel {
10871708Sstevel 	rw_enter(&cvclock, RW_WRITER);
10881708Sstevel 	if (cvcinput_q != NULL) {
10891708Sstevel 		qenable(WR(cvcinput_q));
10901708Sstevel 	}
10911708Sstevel 
10921708Sstevel 	cvc_timeout_id = (timeout_id_t)-1;
10931708Sstevel 	rw_exit(&cvclock);
10941708Sstevel }
10951708Sstevel 
10961708Sstevel 
10971708Sstevel /*
10981708Sstevel  * cvc_getstr()
10991708Sstevel  *	Poll IOSRAM for console input while available.
11001708Sstevel  */
11011708Sstevel static void
cvc_getstr(char * cp)11021708Sstevel cvc_getstr(char *cp)
11031708Sstevel {
11041708Sstevel 	short		count;
11051708Sstevel 	uint8_t		command = 0;
11061708Sstevel 	int		rval = ESUCCESS;
11071708Sstevel 	uint8_t		dvalid = IOSRAM_DATA_INVALID;
11081708Sstevel 	uint8_t		intrpending = 0;
11091708Sstevel 
11101708Sstevel 	mutex_enter(&cvc_iosram_input_mutex);
11111708Sstevel 	while (dvalid == IOSRAM_DATA_INVALID) {
11121708Sstevel 		/*
11131708Sstevel 		 * Check the CONC data_valid flag to see if a control message is
11141708Sstevel 		 * available.
11151708Sstevel 		 */
11161708Sstevel 		rval = iosram_get_flag(IOSRAM_KEY_CONC, &dvalid, &intrpending);
11171708Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
11181708Sstevel 			cmn_err(CE_WARN,
11191708Sstevel 			    "cvc_getstr: get flag for cntl ret %d", rval);
11201708Sstevel 		}
11211708Sstevel 
11221708Sstevel 		/*
11231708Sstevel 		 * If a control message is available, try to read and process
11241708Sstevel 		 * it.
11251708Sstevel 		 */
11261708Sstevel 		if ((dvalid == IOSRAM_DATA_VALID) && (rval == 0)) {
11271708Sstevel 			/* read the control reg offset */
11281708Sstevel 			rval = iosram_rd(IOSRAM_KEY_CONC,
11291708Sstevel 			    CVC_CTL_OFFSET(command), CVC_CTL_SIZE(command),
11301708Sstevel 			    (caddr_t)&command);
11311708Sstevel 			if ((rval != 0) && (rval != EAGAIN)) {
11321708Sstevel 				cmn_err(CE_WARN,
11331708Sstevel 				    "cvc_getstr: read for command ret %d",
11341708Sstevel 				    rval);
11351708Sstevel 			}
11361708Sstevel 
11371708Sstevel 			/* process the cntl msg and clear the data_valid flag */
11381708Sstevel 			if (rval == 0) {
11391708Sstevel 				cvc_iosram_ops(command);
11401708Sstevel 			}
11411708Sstevel 		}
11421708Sstevel 
11431708Sstevel 		/*
11441708Sstevel 		 * Check the CONI data_valid flag to see if console input data
11451708Sstevel 		 * is available.
11461708Sstevel 		 */
11471708Sstevel 		rval = iosram_get_flag(IOSRAM_KEY_CONI, &dvalid, &intrpending);
11481708Sstevel 		if ((rval != 0) && (rval != EAGAIN)) {
11497656SSherry.Moore@Sun.COM 			cmn_err(CE_WARN,
11507656SSherry.Moore@Sun.COM 			    "cvc_getstr: get flag for inbuf ret %d",
11511708Sstevel 			    rval);
11521708Sstevel 		}
11531708Sstevel 		if ((rval != 0) || (dvalid != IOSRAM_DATA_VALID)) {
11541708Sstevel 			goto retry;
11551708Sstevel 		}
11561708Sstevel 
11571708Sstevel 		/*
11581708Sstevel 		 * Try to read the count.
11591708Sstevel 		 */
11601708Sstevel 		rval = iosram_rd(IOSRAM_KEY_CONI, COUNT_OFFSET,
11611708Sstevel 		    CONSBUF_COUNT_SIZE, (caddr_t)&count);
11621708Sstevel 		if (rval != 0) {
11631708Sstevel 			if (rval != EAGAIN) {
11641708Sstevel 				cmn_err(CE_WARN,
11651708Sstevel 				    "cvc_getstr: read for count ret %d", rval);
11661708Sstevel 			}
11671708Sstevel 			goto retry;
11681708Sstevel 		}
11691708Sstevel 
11701708Sstevel 		/*
11711708Sstevel 		 * If there is data to be read, try to read it.
11721708Sstevel 		 */
11731708Sstevel 		if (count != 0) {
11741708Sstevel 			rval = iosram_rd(IOSRAM_KEY_CONI, DATA_OFFSET, count,
11751708Sstevel 			    (caddr_t)cp);
11761708Sstevel 			if (rval != 0) {
11771708Sstevel 				if (rval != EAGAIN) {
11781708Sstevel 					cmn_err(CE_WARN,
11791708Sstevel 					    "cvc_getstr: read for count ret %d",
11801708Sstevel 					    rval);
11811708Sstevel 				}
11821708Sstevel 				goto retry;
11831708Sstevel 			}
11841708Sstevel 			cp[count] = '\0';
11851708Sstevel 		}
11861708Sstevel 
11871708Sstevel 		/*
11881708Sstevel 		 * Try to clear the data_valid flag to indicate that whatever
11891708Sstevel 		 * was in CONI was read successfully.  If successful, and some
11901708Sstevel 		 * data was read, break out of the loop to return to the caller.
11911708Sstevel 		 */
11921708Sstevel 		rval = iosram_set_flag(IOSRAM_KEY_CONI, IOSRAM_DATA_INVALID,
11931708Sstevel 		    IOSRAM_INT_NONE);
11941708Sstevel 		if (rval != 0) {
11951708Sstevel 			if (rval != EAGAIN) {
11961708Sstevel 				cmn_err(CE_WARN,
11971708Sstevel 				    "cvc_getstr: set flag for inbuf ret %d",
11981708Sstevel 				    rval);
11991708Sstevel 			}
12001708Sstevel 		} else if (count != 0) {
12011708Sstevel 			CVC_DBG1(CVC_DBG_IOSRAM_RD, "Read 0x%x", count);
12021708Sstevel 			break;
12031708Sstevel 		}
12041708Sstevel 
12051708Sstevel 		/*
12061708Sstevel 		 * Use a smaller delay between checks of IOSRAM for input
12071708Sstevel 		 * when cvcd/cvcredir are not running or "via_iosram" has
12081708Sstevel 		 * been set.
12091708Sstevel 		 * We don't go away completely when i/o is going through the
12101708Sstevel 		 * network via cvcd since a command may be sent via IOSRAM
12111708Sstevel 		 * to switch if the network is down or hung.
12121708Sstevel 		 */
12131708Sstevel retry:
12141708Sstevel 		if ((cvcoutput_q == NULL) || (via_iosram))
12151708Sstevel 			delay(drv_usectohz(CVC_IOSRAM_POLL_USECS));
12161708Sstevel 		else
12171708Sstevel 			delay(drv_usectohz(CVC_IOSRAM_POLL_USECS * 10));
12181708Sstevel 
12191708Sstevel 	}
12201708Sstevel 
12211708Sstevel 	mutex_exit(&cvc_iosram_input_mutex);
12221708Sstevel }
12231708Sstevel 
12241708Sstevel 
12251708Sstevel /*
12261708Sstevel  * cvc_input_daemon()
12271708Sstevel  *	this function runs as a separate kernel thread and polls IOSRAM for
12281708Sstevel  *	input, and possibly put it on read stream for the console.
12291708Sstevel  *	There are two poll rates (implemented in cvc_getstr):
12301708Sstevel  *		 100 000 uS (10 Hz) - no cvcd communications || via_iosram
12311708Sstevel  *		1000 000 uS ( 1 Hz) - cvcd communications
12321708Sstevel  * 	This continues to run even if there are network console communications
12331708Sstevel  *	in order to handle out-of-band signaling.
12341708Sstevel  */
12351708Sstevel /* ARGSUSED */
12361708Sstevel static void
cvc_input_daemon(void)12371708Sstevel cvc_input_daemon(void)
12381708Sstevel {
12391708Sstevel 	char		linebuf[MAX_XFER_CINPUT + 1];
12401708Sstevel 	char		*cp;
12411708Sstevel 	mblk_t		*mbp;
12421708Sstevel 	int		c;
12431708Sstevel 	int		dropped_read = 0;
12441708Sstevel 
12451708Sstevel 	for (;;) {
12461708Sstevel 		cvc_getstr(linebuf);
12471708Sstevel 
12481708Sstevel 		mbp = allocb(strlen(linebuf), BPRI_MED);
12491708Sstevel 		if (mbp == NULL) {	/* drop it & go on if no buffer */
12501708Sstevel 			if (!dropped_read) {
12511708Sstevel 				cmn_err(CE_WARN, "cvc_input_daemon: "
12521708Sstevel 				    "dropping IOSRAM reads");
12531708Sstevel 			}
12541708Sstevel 			dropped_read++;
12551708Sstevel 			continue;
12561708Sstevel 		}
12571708Sstevel 
12581708Sstevel 		if (dropped_read) {
12591708Sstevel 			cmn_err(CE_WARN,
12601708Sstevel 			    "cvc_input_daemon: dropped %d IOSRAM reads",
12611708Sstevel 			    dropped_read);
12621708Sstevel 			dropped_read = 0;
12631708Sstevel 		}
12641708Sstevel 
12651708Sstevel 		for (cp = linebuf; *cp != '\0'; cp++) {
12661708Sstevel 			c = (int)*cp;
12671708Sstevel 			if (c == '\r')
12681708Sstevel 				c = '\n';
12691708Sstevel 			c &= 0177;
12701708Sstevel 			*mbp->b_wptr = (char)c;
12711708Sstevel 			mbp->b_wptr++;
12721708Sstevel 		}
12731708Sstevel 		mutex_enter(&cvcmutex);
12741708Sstevel 		if (input_ok) {
12751708Sstevel 			if (cvcinput_q == NULL) {
12761708Sstevel 				cmn_err(CE_WARN,
12771708Sstevel 				    "cvc_input_daemon: cvcinput_q is NULL!");
12781708Sstevel 			} else {
12791708Sstevel 				/*
12801708Sstevel 				 * XXX - should canputnext be called here?
12811708Sstevel 				 * Starfire's cvc doesn't do that, and it
12821708Sstevel 				 * appears to work anyway.
12831708Sstevel 				 */
12841708Sstevel 				(void) putnext(cvcinput_q, mbp);
12851708Sstevel 			}
12861708Sstevel 		} else {
12871708Sstevel 			freemsg(mbp);
12881708Sstevel 		}
12891708Sstevel 		mutex_exit(&cvcmutex);
12901708Sstevel 	}
12911708Sstevel 
12921708Sstevel 	/* NOTREACHED */
12931708Sstevel }
12941708Sstevel 
12951708Sstevel /*
12961708Sstevel  * cvc_win_resize()
12971708Sstevel  *	cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set
12981708Sstevel  *	the console window size accordingly.  If indicated by the caller, CONC's
12991708Sstevel  *	data_valid flag will also be cleared.  The flag isn't cleared in all
13001708Sstevel  *	cases because we need to process winsize data at startup without waiting
13011708Sstevel  *	for a command.
13021708Sstevel  */
13031708Sstevel static void
cvc_win_resize(int clear_flag)13041708Sstevel cvc_win_resize(int clear_flag)
13051708Sstevel {
13061708Sstevel 	int		rval;
13071708Sstevel 	uint16_t	rows;
13081708Sstevel 	uint16_t	cols;
13091708Sstevel 	uint16_t	xpixels;
13101708Sstevel 	uint16_t	ypixels;
13111708Sstevel 	tty_common_t	*tty;
13121708Sstevel 	cvc_t		*cp;
13131708Sstevel 	struct winsize	ws;
13141708Sstevel 
13151708Sstevel 	/*
13161708Sstevel 	 * Start by reading the new window size out of the CONC chunk and, if
13171708Sstevel 	 * requested, clearing CONC's data_valid flag.  If any of that fails,
13181708Sstevel 	 * return immediately.  (Note that the rather bulky condition in the
13191708Sstevel 	 * two "if" statements takes advantage of C's short-circuit logic
13201708Sstevel 	 * evaluation)
13211708Sstevel 	 */
13221708Sstevel 	if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows),
13231708Sstevel 	    CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) ||
13241708Sstevel 	    ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols),
13251708Sstevel 	    CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) ||
13261708Sstevel 	    ((rval = iosram_rd(IOSRAM_KEY_CONC,
13271708Sstevel 	    CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels),
13281708Sstevel 	    (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC,
13291708Sstevel 	    CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels),
13301708Sstevel 	    (caddr_t)&ypixels)) != 0)) {
13311708Sstevel 		if (rval != EAGAIN) {
13321708Sstevel 			cmn_err(CE_WARN,
13331708Sstevel 			    "cvc_win_resize: read for ctlbuf ret %d", rval);
13341708Sstevel 		}
13351708Sstevel 		return;
13361708Sstevel 	}
13371708Sstevel 
13381708Sstevel 	if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC,
13391708Sstevel 	    IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) {
13401708Sstevel 		if (rval != EAGAIN) {
13411708Sstevel 			cmn_err(CE_WARN,
13421708Sstevel 			    "cvc_win_resize: set_flag for ctlbuf ret %d", rval);
13431708Sstevel 		}
13441708Sstevel 		return;
13451708Sstevel 	}
13461708Sstevel 
13471708Sstevel 	/*
13481708Sstevel 	 * Copy the parameters from IOSRAM to a winsize struct.
13491708Sstevel 	 */
13501708Sstevel 	ws.ws_row = rows;
13511708Sstevel 	ws.ws_col = cols;
13521708Sstevel 	ws.ws_xpixel = xpixels;
13531708Sstevel 	ws.ws_ypixel = ypixels;
13541708Sstevel 
13551708Sstevel 	/*
13561708Sstevel 	 * This code was taken from Starfire, and it appears to work correctly.
13571708Sstevel 	 * However, since the original developer felt it necessary to add the
13581708Sstevel 	 * following comment, it's probably worth preserving:
13591708Sstevel 	 *
13601708Sstevel 	 * XXX I hope this is safe...
13611708Sstevel 	 */
13621708Sstevel 	cp = cvcinput_q->q_ptr;
13631708Sstevel 	tty = &cp->cvc_tty;
13641708Sstevel 	mutex_enter(&tty->t_excl);
13651708Sstevel 	if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws,
13661708Sstevel 	    sizeof (struct winsize))) {
13671708Sstevel 		tty->t_size = ws;
13681708Sstevel 		mutex_exit(&tty->t_excl);
13691708Sstevel 		(void) putnextctl1(cvcinput_q, M_PCSIG,
13701708Sstevel 			SIGWINCH);
13711708Sstevel 	} else {
13721708Sstevel 		mutex_exit(&tty->t_excl);
13731708Sstevel 	}
13741708Sstevel }
13751708Sstevel 
13761708Sstevel #ifdef DEBUG
13771708Sstevel 
13781708Sstevel void
cvc_dbg(uint32_t flag,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)13791708Sstevel cvc_dbg(uint32_t flag, char *fmt,
13801708Sstevel 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
13811708Sstevel {
13821708Sstevel 	char *s = NULL;
13831708Sstevel 	char buf[256];
13841708Sstevel 
13851708Sstevel 	if (cvc_dbg_flags && ((cvc_dbg_flags & flag) == flag)) {
13861708Sstevel 		switch (flag) {
13871708Sstevel 		case CVC_DBG_ATTACH:
13881708Sstevel 			s = "attach";
13891708Sstevel 			break;
13901708Sstevel 		case CVC_DBG_DETACH:
13911708Sstevel 			s = "detach";
13921708Sstevel 			break;
13931708Sstevel 		case CVC_DBG_OPEN:
13941708Sstevel 			s = "open";
13951708Sstevel 			break;
13961708Sstevel 		case CVC_DBG_CLOSE:
13971708Sstevel 			s = "close";
13981708Sstevel 			break;
13991708Sstevel 		case CVC_DBG_IOCTL:
14001708Sstevel 			s = "ioctl";
14011708Sstevel 			break;
14021708Sstevel 		case CVC_DBG_REDIR:
14031708Sstevel 			s = "redir";
14041708Sstevel 			break;
14051708Sstevel 		case CVC_DBG_WPUT:
14061708Sstevel 			s = "wput";
14071708Sstevel 			break;
14081708Sstevel 		case CVC_DBG_WSRV:
14091708Sstevel 			s = "wsrv";
14101708Sstevel 			break;
14111708Sstevel 		case CVC_DBG_IOSRAM_WR:
14121708Sstevel 			s = "iosram_wr";
14131708Sstevel 			break;
14141708Sstevel 		case CVC_DBG_IOSRAM_RD:
14151708Sstevel 			s = "iosram_rd";
14161708Sstevel 			break;
14171708Sstevel 		case CVC_DBG_NETWORK_WR:
14181708Sstevel 			s = "network_wr";
14191708Sstevel 			break;
14201708Sstevel 		case CVC_DBG_NETWORK_RD:
14211708Sstevel 			s = "network_rd";
14221708Sstevel 			break;
14231708Sstevel 		case CVC_DBG_IOSRAM_CNTL:
14241708Sstevel 			s = "iosram_cntlmsg";
14251708Sstevel 			break;
14261708Sstevel 		default:
14271708Sstevel 			s = "Unknown debug flag";
14281708Sstevel 			break;
14291708Sstevel 		}
14301708Sstevel 
1431*11311SSurya.Prakki@Sun.COM 		(void) sprintf(buf, "!%s_%s(%d): %s", ddi_driver_name(cvcdip),
1432*11311SSurya.Prakki@Sun.COM 		    s, cvc_instance, fmt);
14331708Sstevel 		cmn_err(CE_NOTE, buf, a1, a2, a3, a4, a5);
14341708Sstevel 	}
14351708Sstevel }
14361708Sstevel 
14371708Sstevel #endif /* DEBUG */
1438