xref: /titanic_41/usr/src/uts/sun/io/zs_async.c (revision d3d50737e566cade9a08d73d2af95105ac7cd960)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*d3d50737SRafael Vanoni  * Common Development and Distribution License (the "License").
6*d3d50737SRafael Vanoni  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	Asynchronous protocol handler for Z8530 chips
287c478bd9Sstevel@tonic-gate  *	Handles normal UNIX support for terminals & modems
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <sys/signal.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/termios.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/stream.h>
407c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
417c478bd9Sstevel@tonic-gate #include <sys/tty.h>
427c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h>
437c478bd9Sstevel@tonic-gate #include <sys/cred.h>
447c478bd9Sstevel@tonic-gate #include <sys/user.h>
457c478bd9Sstevel@tonic-gate #include <sys/proc.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/uio.h>
487c478bd9Sstevel@tonic-gate #include <sys/buf.h>
497c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
517c478bd9Sstevel@tonic-gate #include <sys/strtty.h>
527c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
537c478bd9Sstevel@tonic-gate #include <sys/zsdev.h>
547c478bd9Sstevel@tonic-gate #include <sys/ser_async.h>
557c478bd9Sstevel@tonic-gate #include <sys/debug.h>
567c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
577c478bd9Sstevel@tonic-gate #include <sys/conf.h>
587c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
597c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
607c478bd9Sstevel@tonic-gate #include <sys/promif.h>
617c478bd9Sstevel@tonic-gate #include <sys/policy.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * PPS (Pulse Per Second) support.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate extern void ddi_hardpps(struct timeval *, int);
677c478bd9Sstevel@tonic-gate static struct ppsclockev ppsclockev;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #ifdef PPSCLOCKLED
707c478bd9Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */
717c478bd9Sstevel@tonic-gate #define	LED_ON
727c478bd9Sstevel@tonic-gate #define	LED_OFF
737c478bd9Sstevel@tonic-gate #else
747c478bd9Sstevel@tonic-gate #define	LED_ON
757c478bd9Sstevel@tonic-gate #define	LED_OFF
767c478bd9Sstevel@tonic-gate #endif
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	ZSA_RCV_SIZE	64
797c478bd9Sstevel@tonic-gate #define	ZA_KICK_RCV_COUNT	3
807c478bd9Sstevel@tonic-gate #define	ZSA_GRACE_MIN_FLOW_CONTROL	5
817c478bd9Sstevel@tonic-gate #define	ZSA_GRACE_MAX_FLOW_CONTROL	20
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate int zsasoftdtr = 0;	/* if nonzero, softcarrier raises dtr at attach */
847c478bd9Sstevel@tonic-gate int zsb134_weird = 0;	/* if set, old weird B134 behavior */
857c478bd9Sstevel@tonic-gate int g_zsticks = 0;	/* if set, becomes the global zsticks value */
867c478bd9Sstevel@tonic-gate int g_nocluster = 0;	/* if set, disables clustering of received data */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate unsigned int zsa_rstandby = ZSA_MIN_RSTANDBY;
897c478bd9Sstevel@tonic-gate unsigned int zsa_rdone = ZSA_RDONE_MIN;
907c478bd9Sstevel@tonic-gate unsigned int zsa_grace_flow_control = ZSA_GRACE_MIN_FLOW_CONTROL;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	NSPEED	18	/* max # of speeds */
947c478bd9Sstevel@tonic-gate ushort_t zs_speeds[NSPEED] = {
957c478bd9Sstevel@tonic-gate 	0,
967c478bd9Sstevel@tonic-gate 	ZSPEED(50),	/* 1 */
977c478bd9Sstevel@tonic-gate 	ZSPEED(75),	/* 2 */
987c478bd9Sstevel@tonic-gate 	ZSPEED(110),	/* 3 */
997c478bd9Sstevel@tonic-gate #ifdef lint
1007c478bd9Sstevel@tonic-gate 	ZSPEED(134),	/* 4 */
1017c478bd9Sstevel@tonic-gate #else
1027c478bd9Sstevel@tonic-gate 	ZSPEED(269/2),			/* XXX - This is sleazy */
1037c478bd9Sstevel@tonic-gate #endif
1047c478bd9Sstevel@tonic-gate 	ZSPEED(150),	/* 5 */
1057c478bd9Sstevel@tonic-gate 	ZSPEED(200),	/* 6 */
1067c478bd9Sstevel@tonic-gate 	ZSPEED(300),	/* 7 */
1077c478bd9Sstevel@tonic-gate 	ZSPEED(600),	/* 8 */
1087c478bd9Sstevel@tonic-gate 	ZSPEED(1200),	/* 9 */
1097c478bd9Sstevel@tonic-gate 	ZSPEED(1800),	/* 10 */
1107c478bd9Sstevel@tonic-gate 	ZSPEED(2400),	/* 11 */
1117c478bd9Sstevel@tonic-gate 	ZSPEED(4800),	/* 12 */
1127c478bd9Sstevel@tonic-gate 	ZSPEED(9600),	/* 13 */
1137c478bd9Sstevel@tonic-gate 	ZSPEED(19200),	/* 14 */
1147c478bd9Sstevel@tonic-gate 	ZSPEED(38400),	/* 15 */
1157c478bd9Sstevel@tonic-gate 	ZSPEED(57680),	/* 16 */
1167c478bd9Sstevel@tonic-gate 	ZSPEED(76800)	/* 17 */
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate ushort_t zsticks[NSPEED] = {
1207c478bd9Sstevel@tonic-gate 	3,		/* 0 */
1217c478bd9Sstevel@tonic-gate 	3,		/* 1 */
1227c478bd9Sstevel@tonic-gate 	3,		/* 2 */
1237c478bd9Sstevel@tonic-gate 	3,		/* 3 */
1247c478bd9Sstevel@tonic-gate 	3,		/* 4 */
1257c478bd9Sstevel@tonic-gate 	3,		/* 5 */
1267c478bd9Sstevel@tonic-gate 	3,		/* 6 */
1277c478bd9Sstevel@tonic-gate 	3,		/* 7 */
1287c478bd9Sstevel@tonic-gate 	3,		/* 8 */
1297c478bd9Sstevel@tonic-gate 	3,		/* 9 */
1307c478bd9Sstevel@tonic-gate 	3,		/* 10 */
1317c478bd9Sstevel@tonic-gate 	3,		/* 11 */
1327c478bd9Sstevel@tonic-gate 	3,		/* 12 */
1337c478bd9Sstevel@tonic-gate 	3,		/* 13 */
1347c478bd9Sstevel@tonic-gate 	2,		/* 14 */
1357c478bd9Sstevel@tonic-gate 	1,		/* 15 */
1367c478bd9Sstevel@tonic-gate 	1,		/* 16 */
1377c478bd9Sstevel@tonic-gate 	1		/* 17 */
1387c478bd9Sstevel@tonic-gate };
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #define	ztdelay(nsp)	(zsdelay[(nsp)]*(hz/100))
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate ushort_t zsdelay[NSPEED] = {
1437c478bd9Sstevel@tonic-gate 	0,
1447c478bd9Sstevel@tonic-gate 	ZDELAY(50),	/* 1 */
1457c478bd9Sstevel@tonic-gate 	ZDELAY(75),	/* 2 */
1467c478bd9Sstevel@tonic-gate 	ZDELAY(110),    /* 3 */
1477c478bd9Sstevel@tonic-gate #ifdef lint
1487c478bd9Sstevel@tonic-gate 	ZDELAY(134),    /* 4 */
1497c478bd9Sstevel@tonic-gate #else
1507c478bd9Sstevel@tonic-gate 	ZDELAY(269/2),
1517c478bd9Sstevel@tonic-gate #endif
1527c478bd9Sstevel@tonic-gate 	ZDELAY(150),    /* 5 */
1537c478bd9Sstevel@tonic-gate 	ZDELAY(200),    /* 6 */
1547c478bd9Sstevel@tonic-gate 	ZDELAY(300),    /* 7 */
1557c478bd9Sstevel@tonic-gate 	ZDELAY(600),    /* 8 */
1567c478bd9Sstevel@tonic-gate 	ZDELAY(1200),   /* 9 */
1577c478bd9Sstevel@tonic-gate 	ZDELAY(1800),   /* 10 */
1587c478bd9Sstevel@tonic-gate 	ZDELAY(2400),   /* 11 */
1597c478bd9Sstevel@tonic-gate 	ZDELAY(4800),   /* 12 */
1607c478bd9Sstevel@tonic-gate 	ZDELAY(9600),   /* 13 */
1617c478bd9Sstevel@tonic-gate 	ZDELAY(19200),  /* 14 */
1627c478bd9Sstevel@tonic-gate 	ZDELAY(38400),  /* 15 */
1637c478bd9Sstevel@tonic-gate 	ZDELAY(57600),  /* 16 */
1647c478bd9Sstevel@tonic-gate 	ZDELAY(76800)	/* 17 */
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate ushort_t zslowat[NSPEED] = {
1687c478bd9Sstevel@tonic-gate 	3,		/* 0 */
1697c478bd9Sstevel@tonic-gate 	3,		/* 1 */
1707c478bd9Sstevel@tonic-gate 	3,		/* 2 */
1717c478bd9Sstevel@tonic-gate 	3,		/* 3 */
1727c478bd9Sstevel@tonic-gate 	3,		/* 4 */
1737c478bd9Sstevel@tonic-gate 	3,		/* 5 */
1747c478bd9Sstevel@tonic-gate 	3,		/* 6 */
1757c478bd9Sstevel@tonic-gate 	2,		/* 7 */
1767c478bd9Sstevel@tonic-gate 	2,		/* 8 */
1777c478bd9Sstevel@tonic-gate 	2,		/* 9 */
1787c478bd9Sstevel@tonic-gate 	2,		/* 10 */
1797c478bd9Sstevel@tonic-gate 	1,		/* 11 */
1807c478bd9Sstevel@tonic-gate 	1,		/* 12 */
1817c478bd9Sstevel@tonic-gate 	1,		/* 13 */
1827c478bd9Sstevel@tonic-gate 	1,		/* 14 */
1837c478bd9Sstevel@tonic-gate 	1,		/* 15 */
1847c478bd9Sstevel@tonic-gate 	1,		/* 16 */
1857c478bd9Sstevel@tonic-gate 	1		/* 17 */
1867c478bd9Sstevel@tonic-gate };
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate ushort_t zshiwat[NSPEED] = {
1897c478bd9Sstevel@tonic-gate 	0,		/* 0 */
1907c478bd9Sstevel@tonic-gate 	1,		/* 1 */
1917c478bd9Sstevel@tonic-gate 	1,		/* 2 */
1927c478bd9Sstevel@tonic-gate 	1,		/* 3 */
1937c478bd9Sstevel@tonic-gate 	1,		/* 4 */
1947c478bd9Sstevel@tonic-gate 	1,		/* 5 */
1957c478bd9Sstevel@tonic-gate 	1,		/* 6 */
1967c478bd9Sstevel@tonic-gate 	1,		/* 7 */
1977c478bd9Sstevel@tonic-gate 	1,		/* 8 */
1987c478bd9Sstevel@tonic-gate 	1,		/* 9 */
1997c478bd9Sstevel@tonic-gate 	1,		/* 10 */
2007c478bd9Sstevel@tonic-gate 	1,		/* 11 */
2017c478bd9Sstevel@tonic-gate 	1,		/* 12 */
2027c478bd9Sstevel@tonic-gate 	3,		/* 13 */
2037c478bd9Sstevel@tonic-gate 	3,		/* 14 */
2047c478bd9Sstevel@tonic-gate 	4,		/* 15 */
2057c478bd9Sstevel@tonic-gate 	4,		/* 16 */
2067c478bd9Sstevel@tonic-gate 	4		/* 17 */
2077c478bd9Sstevel@tonic-gate };
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate #define	SLAVIO_BUG	/* this workaround required to fix bug 1102778 */
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate #define	SPEED(cflag) \
2127c478bd9Sstevel@tonic-gate 	((cflag) & CBAUDEXT) ? \
2137c478bd9Sstevel@tonic-gate 		(((cflag) & 0x1) + CBAUD + 1) : ((cflag) & CBAUD)
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * Special macros to handle STREAMS operations.
2177c478bd9Sstevel@tonic-gate  * These are required to address memory leakage problems.
2187c478bd9Sstevel@tonic-gate  * WARNING : the macro do NOT call ZSSETSOFT
2197c478bd9Sstevel@tonic-gate  */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
2237c478bd9Sstevel@tonic-gate  */
2247c478bd9Sstevel@tonic-gate #define	ZSA_GETBLOCK(zs, allocbcount) \
2257c478bd9Sstevel@tonic-gate { \
2267c478bd9Sstevel@tonic-gate 	register int n = zsa_rstandby; \
2277c478bd9Sstevel@tonic-gate 	while (--n >= 0 && allocbcount > 0) { \
2287c478bd9Sstevel@tonic-gate 		if (!za->za_rstandby[n]) { \
2297c478bd9Sstevel@tonic-gate 			if ((za->za_rstandby[n] = allocb(ZSA_RCV_SIZE, \
2307c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL) { \
2317c478bd9Sstevel@tonic-gate 				if (za->za_bufcid == 0) { \
2327c478bd9Sstevel@tonic-gate 					za->za_bufcid = bufcall(ZSA_RCV_SIZE, \
2337c478bd9Sstevel@tonic-gate 					    BPRI_MED, \
2347c478bd9Sstevel@tonic-gate 					    zsa_callback, zs); \
2357c478bd9Sstevel@tonic-gate 					break; \
2367c478bd9Sstevel@tonic-gate 				} \
2377c478bd9Sstevel@tonic-gate 			} \
2387c478bd9Sstevel@tonic-gate 			allocbcount--; \
2397c478bd9Sstevel@tonic-gate 		} \
2407c478bd9Sstevel@tonic-gate 	} \
2417c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
2427c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi); \
2437c478bd9Sstevel@tonic-gate 		if (!(zs->zs_wreg[5] & ZSWR5_RTS)) { \
2447c478bd9Sstevel@tonic-gate 			register int usedcnt = 0; \
2457c478bd9Sstevel@tonic-gate 			for (n = 0; n < zsa_rstandby; n++) \
2467c478bd9Sstevel@tonic-gate 				if (!za->za_rstandby[n]) \
2477c478bd9Sstevel@tonic-gate 					usedcnt++; \
2487c478bd9Sstevel@tonic-gate 			if ((ushort_t)usedcnt <= \
2497c478bd9Sstevel@tonic-gate 			    zslowat[SPEED(za->za_ttycommon.t_cflag)]) \
2507c478bd9Sstevel@tonic-gate 				SCC_BIS(5, ZSWR5_RTS); \
2517c478bd9Sstevel@tonic-gate 		} \
2527c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi); \
2537c478bd9Sstevel@tonic-gate 	} \
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate #define	ZSA_ALLOCB(mp) \
2607c478bd9Sstevel@tonic-gate { \
2617c478bd9Sstevel@tonic-gate 	register int n = zsa_rstandby; \
2627c478bd9Sstevel@tonic-gate 	while (--n >= 0) { \
2637c478bd9Sstevel@tonic-gate 		if ((mp = za->za_rstandby[n]) != NULL) { \
2647c478bd9Sstevel@tonic-gate 			za->za_rstandby[n] = NULL; \
2657c478bd9Sstevel@tonic-gate 			break; \
2667c478bd9Sstevel@tonic-gate 		} \
2677c478bd9Sstevel@tonic-gate 	} \
2687c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
2697c478bd9Sstevel@tonic-gate 		if (!mp) { \
2707c478bd9Sstevel@tonic-gate 			if (zs->zs_wreg[5] & ZSWR5_RTS) \
2717c478bd9Sstevel@tonic-gate 				SCC_BIC(5, ZSWR5_RTS); \
2727c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "zs%d: message lost\n", \
2737c478bd9Sstevel@tonic-gate 				UNIT(za->za_dev)); \
2747c478bd9Sstevel@tonic-gate 		} else if (zs->zs_wreg[5] & ZSWR5_RTS) { \
2757c478bd9Sstevel@tonic-gate 			register int usedcnt = 0; \
2767c478bd9Sstevel@tonic-gate 			for (n = 0; n < zsa_rstandby; n++) \
2777c478bd9Sstevel@tonic-gate 				if (!za->za_rstandby[n]) \
2787c478bd9Sstevel@tonic-gate 					usedcnt++; \
2797c478bd9Sstevel@tonic-gate 			if ((ushort_t)usedcnt >= (zsa_rstandby - \
2807c478bd9Sstevel@tonic-gate 			    zshiwat[SPEED(za->za_ttycommon.t_cflag)])) \
2817c478bd9Sstevel@tonic-gate 				SCC_BIC(5, ZSWR5_RTS); \
2827c478bd9Sstevel@tonic-gate 		} \
2837c478bd9Sstevel@tonic-gate 	} \
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate  * Should get the spin (zs_excl_hi) mutex.
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate #define	ZSA_QREPLY(q, mp) \
2907c478bd9Sstevel@tonic-gate { \
2917c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi); \
2927c478bd9Sstevel@tonic-gate 	ZSA_PUTQ(mp); \
2937c478bd9Sstevel@tonic-gate 	ZSSETSOFT(zs); \
2947c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi); \
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate #define	ZSA_PUTQ(mp) \
3017c478bd9Sstevel@tonic-gate { \
3027c478bd9Sstevel@tonic-gate 	register int wptr, rptr; \
3037c478bd9Sstevel@tonic-gate 	wptr = za->za_rdone_wptr; \
3047c478bd9Sstevel@tonic-gate 	rptr = za->za_rdone_rptr; \
3057c478bd9Sstevel@tonic-gate 	za->za_rdone[wptr] = mp; \
3067c478bd9Sstevel@tonic-gate 	if ((wptr)+1 == zsa_rdone) { \
3077c478bd9Sstevel@tonic-gate 		za->za_rdone_wptr = wptr = 0; \
3087c478bd9Sstevel@tonic-gate 	} else \
3097c478bd9Sstevel@tonic-gate 		za->za_rdone_wptr = ++wptr; \
3107c478bd9Sstevel@tonic-gate 	if (wptr == rptr) { \
3117c478bd9Sstevel@tonic-gate 		SCC_BIC(1, ZSWR1_INIT); \
3127c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "zs%d disabled: input buffer overflow", \
3137c478bd9Sstevel@tonic-gate 			UNIT(za->za_dev)); \
3147c478bd9Sstevel@tonic-gate 	} \
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate #define	ZSA_KICK_RCV \
3217c478bd9Sstevel@tonic-gate { \
3227c478bd9Sstevel@tonic-gate 	register mblk_t *mp = za->za_rcvblk; \
3237c478bd9Sstevel@tonic-gate 	if (mp) { \
3247c478bd9Sstevel@tonic-gate 		if (zs->zs_rd_cur) {	/* M_DATA */ \
3257c478bd9Sstevel@tonic-gate 			mp->b_wptr = zs->zs_rd_cur; \
3267c478bd9Sstevel@tonic-gate 			zs->zs_rd_cur = NULL; \
3277c478bd9Sstevel@tonic-gate 			zs->zs_rd_lim = NULL; \
3287c478bd9Sstevel@tonic-gate 		} \
3297c478bd9Sstevel@tonic-gate 		za->za_rcvblk = NULL; \
3307c478bd9Sstevel@tonic-gate 		ZSA_PUTQ(mp); \
3317c478bd9Sstevel@tonic-gate 		ZSSETSOFT(zs); \
3327c478bd9Sstevel@tonic-gate 	} \
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate #define	ZSA_SEEQ(mp) \
3367c478bd9Sstevel@tonic-gate { \
3377c478bd9Sstevel@tonic-gate 		if (za->za_rdone_rptr != za->za_rdone_wptr) { \
3387c478bd9Sstevel@tonic-gate 			mp = za->za_rdone[za->za_rdone_rptr]; \
3397c478bd9Sstevel@tonic-gate 		} else { \
3407c478bd9Sstevel@tonic-gate 			mp = NULL; \
3417c478bd9Sstevel@tonic-gate 		} \
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate #define	ZSA_GETQ(mp) \
3497c478bd9Sstevel@tonic-gate { \
3507c478bd9Sstevel@tonic-gate 	if (za->za_rdone_rptr != za->za_rdone_wptr) { \
3517c478bd9Sstevel@tonic-gate 		mp = za->za_rdone[za->za_rdone_rptr]; \
3527c478bd9Sstevel@tonic-gate 		za->za_rdone[za->za_rdone_rptr++] = NULL; \
3537c478bd9Sstevel@tonic-gate 		if (za->za_rdone_rptr == zsa_rdone) \
3547c478bd9Sstevel@tonic-gate 			za->za_rdone_rptr = 0; \
3557c478bd9Sstevel@tonic-gate 	} else { \
3567c478bd9Sstevel@tonic-gate 		mp = NULL; \
3577c478bd9Sstevel@tonic-gate 	} \
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate #define	ZSA_FLUSHQ \
3647c478bd9Sstevel@tonic-gate { \
3657c478bd9Sstevel@tonic-gate 	register mblk_t *tmp; \
3667c478bd9Sstevel@tonic-gate 	for (;;) { \
3677c478bd9Sstevel@tonic-gate 		ZSA_GETQ(tmp); \
3687c478bd9Sstevel@tonic-gate 		if (!(tmp)) \
3697c478bd9Sstevel@tonic-gate 			break; \
3707c478bd9Sstevel@tonic-gate 		freemsg(tmp); \
3717c478bd9Sstevel@tonic-gate 	} \
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate  * Logging definitions
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate extern	char	zs_h_log[];
3847c478bd9Sstevel@tonic-gate extern	int	zs_h_log_n;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate #define	zsa_h_log_clear
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate #define	zsa_h_log_add(c) \
3897c478bd9Sstevel@tonic-gate { \
3907c478bd9Sstevel@tonic-gate 	if (zs_h_log_n >= ZS_H_LOG_MAX) \
3917c478bd9Sstevel@tonic-gate 		zs_h_log_n = 0; \
3927c478bd9Sstevel@tonic-gate 	zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \
3937c478bd9Sstevel@tonic-gate 	zs_h_log[zs_h_log_n++] = c; \
3947c478bd9Sstevel@tonic-gate 	zs_h_log[zs_h_log_n] = '\0'; \
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate #else /* ZS_DEBUG_ALL */
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate #define	ZSA_H_LOG_MAX	0x4000
4007c478bd9Sstevel@tonic-gate char zsa_h_log[40][ZSA_H_LOG_MAX +10];
4017c478bd9Sstevel@tonic-gate int zsa_h_log_n[40];
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate #define	zsa_h_log_add(c) \
4047c478bd9Sstevel@tonic-gate { \
4057c478bd9Sstevel@tonic-gate 	if (zsa_h_log_n[zs->zs_unit] >= ZSA_H_LOG_MAX) \
4067c478bd9Sstevel@tonic-gate 		zsa_h_log_n[zs->zs_unit] = 0; \
4077c478bd9Sstevel@tonic-gate 	zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]++] = c; \
4087c478bd9Sstevel@tonic-gate 	zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]] = '\0'; \
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate #define	zsa_h_log_clear \
4127c478bd9Sstevel@tonic-gate { \
4137c478bd9Sstevel@tonic-gate 	register char *p; \
4147c478bd9Sstevel@tonic-gate 	for (p = &zsa_h_log[zs->zs_unit][ZSA_H_LOG_MAX]; \
4157c478bd9Sstevel@tonic-gate 		p >= &zsa_h_log[zs->zs_unit][0]; /* null */) \
4167c478bd9Sstevel@tonic-gate 		*p-- = '\0'; \
4177c478bd9Sstevel@tonic-gate 	zsa_h_log_n[zs->zs_unit] = 0; \
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate #endif /* ZS_DEBUG_ALL */
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate #define	ZSA_R0_LOG(r0) \
4237c478bd9Sstevel@tonic-gate { \
4247c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_RX_READY) zsa_h_log_add('R'); \
4257c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_TIMER) zsa_h_log_add('Z'); \
4267c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_TX_READY) zsa_h_log_add('T'); \
4277c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_CD) zsa_h_log_add('D'); \
4287c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_SYNC) zsa_h_log_add('S'); \
4297c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_CTS) zsa_h_log_add('C'); \
4307c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_TXUNDER) zsa_h_log_add('U'); \
4317c478bd9Sstevel@tonic-gate 	if (r0 & ZSRR0_BREAK) zsa_h_log_add('B'); \
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate #else /* ZSA_DEBUG */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate #define	zsa_h_log_clear
4377c478bd9Sstevel@tonic-gate #define	zsa_h_log_add(c)
4387c478bd9Sstevel@tonic-gate #define	 ZSA_R0_LOG(r0)
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate #endif /* ZSA_DEBUG */
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate static int zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
4457c478bd9Sstevel@tonic-gate static int zsa_close(queue_t *q, int flag);
4467c478bd9Sstevel@tonic-gate static void zsa_wput(queue_t *q, mblk_t *mp);
4477c478bd9Sstevel@tonic-gate static void zsa_rsrv(queue_t *q);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate static struct module_info asyncm_info = {
4507c478bd9Sstevel@tonic-gate 	0,
4517c478bd9Sstevel@tonic-gate 	"zs",
4527c478bd9Sstevel@tonic-gate 	0,
4537c478bd9Sstevel@tonic-gate 	INFPSZ,
4547c478bd9Sstevel@tonic-gate 	2048,
4557c478bd9Sstevel@tonic-gate 	128
4567c478bd9Sstevel@tonic-gate };
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate static struct qinit async_rinit = {
4597c478bd9Sstevel@tonic-gate 	putq,
4607c478bd9Sstevel@tonic-gate 	(int (*)())zsa_rsrv,
4617c478bd9Sstevel@tonic-gate 	zsa_open,
4627c478bd9Sstevel@tonic-gate 	zsa_close,
4637c478bd9Sstevel@tonic-gate 	NULL,
4647c478bd9Sstevel@tonic-gate 	&asyncm_info,
4657c478bd9Sstevel@tonic-gate 	NULL
4667c478bd9Sstevel@tonic-gate };
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate static struct qinit async_winit = {
4697c478bd9Sstevel@tonic-gate 	(int (*)())zsa_wput,
4707c478bd9Sstevel@tonic-gate 	NULL,
4717c478bd9Sstevel@tonic-gate 	NULL,
4727c478bd9Sstevel@tonic-gate 	NULL,
4737c478bd9Sstevel@tonic-gate 	NULL,
4747c478bd9Sstevel@tonic-gate 	&asyncm_info,
4757c478bd9Sstevel@tonic-gate 	NULL
4767c478bd9Sstevel@tonic-gate };
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate struct streamtab asynctab = {
4797c478bd9Sstevel@tonic-gate 	&async_rinit,
4807c478bd9Sstevel@tonic-gate 	&async_winit,
4817c478bd9Sstevel@tonic-gate 	NULL,
4827c478bd9Sstevel@tonic-gate 	NULL,
4837c478bd9Sstevel@tonic-gate };
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * The async interrupt entry points.
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate static void	zsa_txint(struct zscom *zs);
4897c478bd9Sstevel@tonic-gate static void	zsa_xsint(struct zscom *zs);
4907c478bd9Sstevel@tonic-gate static void	zsa_rxint(struct zscom *zs);
4917c478bd9Sstevel@tonic-gate static void	zsa_srint(struct zscom *zs);
4927c478bd9Sstevel@tonic-gate static int	zsa_softint(struct zscom *zs);
4937c478bd9Sstevel@tonic-gate static int	zsa_suspend(struct zscom *zs);
4947c478bd9Sstevel@tonic-gate static int	zsa_resume(struct zscom *zs);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate static void
zsa_null(struct zscom * zs)4977c478bd9Sstevel@tonic-gate zsa_null(struct zscom *zs)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	/* LINTED */
5007c478bd9Sstevel@tonic-gate 	register short	c;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXINT);
5037c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
5047c478bd9Sstevel@tonic-gate 	c = SCC_READDATA();
5057c478bd9Sstevel@tonic-gate 	ZSDELAY();
5067c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5107c478bd9Sstevel@tonic-gate static int
zsa_null_int(struct zscom * zs)5117c478bd9Sstevel@tonic-gate zsa_null_int(struct zscom *zs)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	return (0);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate struct zsops zsops_null_async = {
5177c478bd9Sstevel@tonic-gate 	zsa_null,
5187c478bd9Sstevel@tonic-gate 	zsa_null,
5197c478bd9Sstevel@tonic-gate 	zsa_null,
5207c478bd9Sstevel@tonic-gate 	zsa_null,
5217c478bd9Sstevel@tonic-gate 	zsa_null_int,
5227c478bd9Sstevel@tonic-gate 	zsa_null_int,
5237c478bd9Sstevel@tonic-gate 	zsa_null_int
5247c478bd9Sstevel@tonic-gate };
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate struct zsops zsops_async = {
5277c478bd9Sstevel@tonic-gate 	zsa_txint,
5287c478bd9Sstevel@tonic-gate 	zsa_xsint,
5297c478bd9Sstevel@tonic-gate 	zsa_rxint,
5307c478bd9Sstevel@tonic-gate 	zsa_srint,
5317c478bd9Sstevel@tonic-gate 	zsa_softint,
5327c478bd9Sstevel@tonic-gate 	zsa_suspend,
5337c478bd9Sstevel@tonic-gate 	zsa_resume
5347c478bd9Sstevel@tonic-gate };
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate static int	dmtozs(int bits);
5377c478bd9Sstevel@tonic-gate static int	zstodm(int bits);
5387c478bd9Sstevel@tonic-gate static void	zsa_restart(void *);
5397c478bd9Sstevel@tonic-gate static void	zsa_reioctl(void *);
5407c478bd9Sstevel@tonic-gate static void	zsa_ioctl(struct asyncline *za, queue_t *q, mblk_t *mp);
5417c478bd9Sstevel@tonic-gate static void	zsa_program(struct asyncline *za, int setibaud);
5427c478bd9Sstevel@tonic-gate static void	zsa_start(struct zscom *zs);
5437c478bd9Sstevel@tonic-gate static void 	zsa_kick_rcv(void *);
5447c478bd9Sstevel@tonic-gate static void 	zsa_callback(void *);
5457c478bd9Sstevel@tonic-gate static void	zsa_set_za_rcv_flags_mask(struct asyncline *za);
5467c478bd9Sstevel@tonic-gate int		zsgetspeed(dev_t dev);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /* ARGSUSED */
5517c478bd9Sstevel@tonic-gate int
zsc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5527c478bd9Sstevel@tonic-gate zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
5537c478bd9Sstevel@tonic-gate     void **result)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	register dev_t dev = (dev_t)arg;
5567c478bd9Sstevel@tonic-gate 	register int unit, error;
5577c478bd9Sstevel@tonic-gate 	register struct zscom *zs;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if ((unit = UNIT(dev)) >= nzs)
5607c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	switch (infocmd) {
5637c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
5647c478bd9Sstevel@tonic-gate 		zs = &zscom[unit];
5657c478bd9Sstevel@tonic-gate 		*result = zs->zs_dip;
5667c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
5677c478bd9Sstevel@tonic-gate 		break;
5687c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
569360e6f5eSmathue 		*result = (void *)(uintptr_t)(unit / 2);
5707c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
5717c478bd9Sstevel@tonic-gate 		break;
5727c478bd9Sstevel@tonic-gate 	default:
5737c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 	return (error);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * The Asynchronous Driver.
5807c478bd9Sstevel@tonic-gate  */
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate  * Determine if the zsminor device is in use as either a stdin or stdout
5847c478bd9Sstevel@tonic-gate  * device, so we can be careful about how we initialize the DUART, if
5857c478bd9Sstevel@tonic-gate  * it is, in fact, in use.
5867c478bd9Sstevel@tonic-gate  *
5877c478bd9Sstevel@tonic-gate  * Since this is expensive, we do it once and store away the answers,
5887c478bd9Sstevel@tonic-gate  * since this gets called a number of times per phyical zs device.
5897c478bd9Sstevel@tonic-gate  * Perhaps, this should be in a loadable module, so it can get thrown
5907c478bd9Sstevel@tonic-gate  * away after all the zs devices are attached?
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /*
5947c478bd9Sstevel@tonic-gate  * To determine if a given unit is being used by the PROM,
5957c478bd9Sstevel@tonic-gate  * we need to map stdin/stdout devices as known to the PROM
5967c478bd9Sstevel@tonic-gate  * to zs internal minor device numbers:
5977c478bd9Sstevel@tonic-gate  *
5987c478bd9Sstevel@tonic-gate  * PROM (real device)	zs minor	device
5997c478bd9Sstevel@tonic-gate  *
6007c478bd9Sstevel@tonic-gate  * "zs", 0, "a"		 0		ttya
6017c478bd9Sstevel@tonic-gate  * "zs", 0, "b"		 1		ttyb
6027c478bd9Sstevel@tonic-gate  * "zs", 1, "a"		 2		keyboard
6037c478bd9Sstevel@tonic-gate  * "zs", 1, "b"		 3		mouse
6047c478bd9Sstevel@tonic-gate  * "zs", 2, "a"		 4		ttyc
6057c478bd9Sstevel@tonic-gate  * "zs", 2, "b"		 5		ttyd
6067c478bd9Sstevel@tonic-gate  *
6077c478bd9Sstevel@tonic-gate  * The following value mapping lines assume that insource
6087c478bd9Sstevel@tonic-gate  * and outsink map as "screen, a, b, c, d, ...", and that
6097c478bd9Sstevel@tonic-gate  * zs minors are "a, b, kbd, mouse, c, d, ...".
6107c478bd9Sstevel@tonic-gate  */
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate static int zsa_inuse;		/* Strictly for debugging */
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate int
zsa_channel_is_active_in_rom(dev_info_t * dev,int zsminor)6157c478bd9Sstevel@tonic-gate zsa_channel_is_active_in_rom(dev_info_t *dev, int zsminor)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	char pathname[OBP_MAXPATHLEN];
6187c478bd9Sstevel@tonic-gate 	char default_pathname[OBP_MAXPATHLEN];
6197c478bd9Sstevel@tonic-gate 	char *stdioname;
6207c478bd9Sstevel@tonic-gate 	char minordata[3];
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	/*
6237c478bd9Sstevel@tonic-gate 	 * Basically, get my name and compare it to stdio devnames
6247c478bd9Sstevel@tonic-gate 	 * and if we get a match, then the device is in use as either
6257c478bd9Sstevel@tonic-gate 	 * stdin or stdout device (console tip line or keyboard device).
6267c478bd9Sstevel@tonic-gate 	 *
6277c478bd9Sstevel@tonic-gate 	 * We get two forms of the pathname, one complete with the
6287c478bd9Sstevel@tonic-gate 	 * the channel number, and if the channel is 'a', then
6297c478bd9Sstevel@tonic-gate 	 * we also deal with the user's ability to default to
6307c478bd9Sstevel@tonic-gate 	 * channel 'a', by omitting the channel number option.
6317c478bd9Sstevel@tonic-gate 	 * We then compare these pathnames to both the stdin and
6327c478bd9Sstevel@tonic-gate 	 * stdout pathnames. If any of these match, then the channel
6337c478bd9Sstevel@tonic-gate 	 * is in use.
6347c478bd9Sstevel@tonic-gate 	 */
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dev, pathname);	/* device pathname */
6377c478bd9Sstevel@tonic-gate 	default_pathname[0] = (char)0;	/* default pathname if channel 'a' */
6387c478bd9Sstevel@tonic-gate 	if ((zsminor & 1) == 0)
6397c478bd9Sstevel@tonic-gate 		(void) strcpy(default_pathname, pathname);
6407c478bd9Sstevel@tonic-gate 	minordata[0] = ':';
6417c478bd9Sstevel@tonic-gate 	minordata[1] = (char)('a' + (zsminor & 1));
6427c478bd9Sstevel@tonic-gate 	minordata[2] = (char)0;
6437c478bd9Sstevel@tonic-gate 	(void) strcat(pathname, minordata);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	stdioname = prom_stdinpath();
6467c478bd9Sstevel@tonic-gate 	if (strcmp(pathname, stdioname) == 0) {
6477c478bd9Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
6487c478bd9Sstevel@tonic-gate 		return (1);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	if (strcmp(default_pathname, stdioname) == 0) {
6517c478bd9Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
6527c478bd9Sstevel@tonic-gate 		return (1);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	stdioname = prom_stdoutpath();
6567c478bd9Sstevel@tonic-gate 	if (strcmp(pathname, stdioname) == 0) {
6577c478bd9Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
6587c478bd9Sstevel@tonic-gate 		return (1);
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 	if (strcmp(default_pathname, stdioname) == 0) {
6617c478bd9Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
6627c478bd9Sstevel@tonic-gate 		return (1);
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	return (0);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate /*
6697c478bd9Sstevel@tonic-gate  * Initialize zs
6707c478bd9Sstevel@tonic-gate  */
6717c478bd9Sstevel@tonic-gate void
zsa_init(struct zscom * zs)6727c478bd9Sstevel@tonic-gate zsa_init(struct zscom *zs)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate 	/*
6757c478bd9Sstevel@tonic-gate 	 * This routine is called near the end of the zs module's attach
6767c478bd9Sstevel@tonic-gate 	 * process. It initializes the TTY protocol-private data for this
6777c478bd9Sstevel@tonic-gate 	 * channel that needs to be in place before interrupts are enabled.
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
6807c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	/*
6837c478bd9Sstevel@tonic-gate 	 * Raise modem control lines on serial ports associated
6847c478bd9Sstevel@tonic-gate 	 * with the console and (optionally) softcarrier lines.
6857c478bd9Sstevel@tonic-gate 	 * Drop modem control lines on all others so that modems
6867c478bd9Sstevel@tonic-gate 	 * will not answer and portselectors will skip these
6877c478bd9Sstevel@tonic-gate 	 * lines until they are opened by a getty.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	if (zsa_channel_is_active_in_rom(zs->zs_dip, zs->zs_unit))
6907c478bd9Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_ON, DMSET);	/* raise dtr */
6917c478bd9Sstevel@tonic-gate 	else if (zsasoftdtr && (zssoftCAR[zs->zs_unit]))
6927c478bd9Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_ON, DMSET);	/* raise dtr */
6937c478bd9Sstevel@tonic-gate 	else
6947c478bd9Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_OFF, DMSET);	/* drop dtr */
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (zsa_rstandby > ZSA_MAX_RSTANDBY)
6977c478bd9Sstevel@tonic-gate 		zsa_rstandby = ZSA_MAX_RSTANDBY;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	if (zsa_rdone > ZSA_RDONE_MAX)
7007c478bd9Sstevel@tonic-gate 		zsa_rdone = ZSA_RDONE_MAX;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if (zsa_grace_flow_control > ZSA_GRACE_MAX_FLOW_CONTROL)
7037c478bd9Sstevel@tonic-gate 		zsa_grace_flow_control = ZSA_GRACE_MAX_FLOW_CONTROL;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
7067c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate  * Open routine.
7127c478bd9Sstevel@tonic-gate  */
7137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7147c478bd9Sstevel@tonic-gate static int
zsa_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)7157c478bd9Sstevel@tonic-gate zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
7167c478bd9Sstevel@tonic-gate {
7177c478bd9Sstevel@tonic-gate 	register struct zscom *zs;
7187c478bd9Sstevel@tonic-gate 	register struct asyncline *za;
7197c478bd9Sstevel@tonic-gate 	register int	speed, unit;
7207c478bd9Sstevel@tonic-gate 	struct termios *termiosp;
7217c478bd9Sstevel@tonic-gate 	int len;
7227c478bd9Sstevel@tonic-gate 	register int allocbcount = zsa_rstandby;
7237c478bd9Sstevel@tonic-gate 	boolean_t set_zsoptinit = B_FALSE;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	unit = UNIT(*dev);
7267c478bd9Sstevel@tonic-gate 	if (unit >= nzs)
7277c478bd9Sstevel@tonic-gate 		return (ENXIO);		/* unit not configured */
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	/* zscom is allocated by zsattach, and thus cannot be NULL here */
7307c478bd9Sstevel@tonic-gate 	zs = &zscom[unit];
7317c478bd9Sstevel@tonic-gate 	if (zs->zs_ops == NULL) {
7327c478bd9Sstevel@tonic-gate 		return (ENXIO);	 /* device not found by autoconfig */
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_ocexcl);
7367c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
7377c478bd9Sstevel@tonic-gate again:
7387c478bd9Sstevel@tonic-gate 	if ((zs->zs_ops != &zsops_null) &&
7397c478bd9Sstevel@tonic-gate 	    (zs->zs_ops != &zsops_async)) {
7407c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
7417c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
7427c478bd9Sstevel@tonic-gate 		return (EBUSY);	 /* another protocol got here first */
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (zs->zs_suspended) {
7487c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
7497c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
7507c478bd9Sstevel@tonic-gate 		(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
7517c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_ocexcl);
7527c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/* Mark device as busy (for power management) */
7567c478bd9Sstevel@tonic-gate 	(void) pm_busy_component(zs->zs_dip, unit%2+1);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (zs->zs_ops == &zsops_null) {
7597c478bd9Sstevel@tonic-gate 		bzero(za, sizeof (zs->zs_priv_str));
7607c478bd9Sstevel@tonic-gate 		za->za_common = zs;
7617c478bd9Sstevel@tonic-gate 		if (zssoftCAR[zs->zs_unit])
7627c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_flags |= TS_SOFTCAR;
7637c478bd9Sstevel@tonic-gate 		zsopinit(zs, &zsops_async);
7647c478bd9Sstevel@tonic-gate 		set_zsoptinit = B_TRUE;
7657c478bd9Sstevel@tonic-gate 		za->za_rdone_wptr = 0;
7667c478bd9Sstevel@tonic-gate 		za->za_rdone_rptr = 0;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	zs->zs_priv = (caddr_t)za;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/*
7727c478bd9Sstevel@tonic-gate 	 * Block waiting for carrier to come up,
7737c478bd9Sstevel@tonic-gate 	 * unless this is a no-delay open.
7747c478bd9Sstevel@tonic-gate 	 */
7757c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
7767c478bd9Sstevel@tonic-gate 	if (!(za->za_flags & ZAS_ISOPEN)) {
7777c478bd9Sstevel@tonic-gate 		/*
7787c478bd9Sstevel@tonic-gate 		 * Get the default termios settings (cflag).
7797c478bd9Sstevel@tonic-gate 		 * These are stored as a property in the
7807c478bd9Sstevel@tonic-gate 		 * "options" node.
7817c478bd9Sstevel@tonic-gate 		 */
7827c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
7837c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
7847c478bd9Sstevel@tonic-gate 		    ddi_root_node(), 0, "ttymodes",
7857c478bd9Sstevel@tonic-gate 		    (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
7867c478bd9Sstevel@tonic-gate 		    len == sizeof (struct termios)) {
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag = termiosp->c_cflag;
7897c478bd9Sstevel@tonic-gate 			kmem_free(termiosp, len);
7907c478bd9Sstevel@tonic-gate 		} else {
7917c478bd9Sstevel@tonic-gate 			/*
7927c478bd9Sstevel@tonic-gate 			 * Gack! Whine about it.
7937c478bd9Sstevel@tonic-gate 			 */
7947c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
7957c478bd9Sstevel@tonic-gate 			    "zs: Couldn't get ttymodes property!");
7967c478bd9Sstevel@tonic-gate 		}
7977c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
7987c478bd9Sstevel@tonic-gate 		if ((*dev == rconsdev) || (*dev == kbddev) ||
7997c478bd9Sstevel@tonic-gate 		    (*dev == stdindev)) {
8007c478bd9Sstevel@tonic-gate 			speed = zsgetspeed(*dev);
8017c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag &= ~(CBAUD);
8027c478bd9Sstevel@tonic-gate 			if (speed > CBAUD) {
8037c478bd9Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |= CBAUDEXT;
8047c478bd9Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |=
8057c478bd9Sstevel@tonic-gate 				    ((speed - CBAUD - 1) & CBAUD);
8067c478bd9Sstevel@tonic-gate 			} else {
8077c478bd9Sstevel@tonic-gate 				za->za_ttycommon.t_cflag &= ~CBAUDEXT;
8087c478bd9Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |= (speed & CBAUD);
8097c478bd9Sstevel@tonic-gate 			}
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 		za->za_overrun = 0;
8127c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_iflag = 0;
8137c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
8147c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_row = 0;
8157c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_col = 0;
8167c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_xpixel = 0;
8177c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_ypixel = 0;
8187c478bd9Sstevel@tonic-gate 		za->za_dev = *dev;
8197c478bd9Sstevel@tonic-gate 		za->za_wbufcid = 0;
8207c478bd9Sstevel@tonic-gate 		zsa_program(za, za->za_ttycommon.t_cflag & (CIBAUDEXT|CIBAUD));
8217c478bd9Sstevel@tonic-gate 		zsa_set_za_rcv_flags_mask(za);
8227c478bd9Sstevel@tonic-gate 	} else if ((za->za_ttycommon.t_flags & TS_XCLUDE) &&
8237c478bd9Sstevel@tonic-gate 	    secpolicy_excl_open(cr) != 0) {
8247c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
8257c478bd9Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
8267c478bd9Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
8277c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
8287c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
8297c478bd9Sstevel@tonic-gate 		return (EBUSY);
8307c478bd9Sstevel@tonic-gate 	} else if ((*dev & OUTLINE) && !(za->za_flags & ZAS_OUT)) {
8317c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
8327c478bd9Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
8337c478bd9Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
8347c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
8357c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
8367c478bd9Sstevel@tonic-gate 		return (EBUSY);
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	if (*dev & OUTLINE)
8407c478bd9Sstevel@tonic-gate 		za->za_flags |= ZAS_OUT;
8417c478bd9Sstevel@tonic-gate 	(void) zsmctl(zs, ZS_ON, DMSET);
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	/*
8447c478bd9Sstevel@tonic-gate 	 * Check carrier.
8457c478bd9Sstevel@tonic-gate 	 */
8467c478bd9Sstevel@tonic-gate 	if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
8477c478bd9Sstevel@tonic-gate 	    (zsmctl(zs, 0, DMGET) & ZSRR0_CD))
8487c478bd9Sstevel@tonic-gate 		za->za_flags |= ZAS_CARR_ON;
8497c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	/*
8527c478bd9Sstevel@tonic-gate 	 * If FNDELAY and FNONBLOCK are clear, block until carrier up.
8537c478bd9Sstevel@tonic-gate 	 * Quit on interrupt.
8547c478bd9Sstevel@tonic-gate 	 */
8557c478bd9Sstevel@tonic-gate 	if (!(flag & (FNDELAY|FNONBLOCK)) &&
8567c478bd9Sstevel@tonic-gate 	    !(za->za_ttycommon.t_cflag & CLOCAL)) {
8577c478bd9Sstevel@tonic-gate 		if (!(za->za_flags & (ZAS_CARR_ON|ZAS_OUT)) ||
8587c478bd9Sstevel@tonic-gate 		    ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE))) {
8597c478bd9Sstevel@tonic-gate 			za->za_flags |= ZAS_WOPEN;
8607c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
8617c478bd9Sstevel@tonic-gate 			if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_ocexcl) == 0) {
8627c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl);
8637c478bd9Sstevel@tonic-gate 				if (zs->zs_suspended) {
8647c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_excl);
8657c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_ocexcl);
8667c478bd9Sstevel@tonic-gate 					(void) ddi_dev_is_needed(zs->zs_dip,
8677c478bd9Sstevel@tonic-gate 					    0, 1);
8687c478bd9Sstevel@tonic-gate 					mutex_enter(zs->zs_ocexcl);
8697c478bd9Sstevel@tonic-gate 					mutex_enter(zs->zs_excl);
8707c478bd9Sstevel@tonic-gate 				}
8717c478bd9Sstevel@tonic-gate 				za->za_flags &= ~ZAS_WOPEN;
8727c478bd9Sstevel@tonic-gate 				if (set_zsoptinit && !(za->za_flags & ISOPEN))
8737c478bd9Sstevel@tonic-gate 					zsopinit(zs, &zsops_null);
8747c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
8757c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_ocexcl);
8767c478bd9Sstevel@tonic-gate 				return (EINTR);
8777c478bd9Sstevel@tonic-gate 			}
8787c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
8797c478bd9Sstevel@tonic-gate 			za->za_flags &= ~ZAS_WOPEN;
8807c478bd9Sstevel@tonic-gate 			if ((zs->zs_ops == &zsops_null) ||
8817c478bd9Sstevel@tonic-gate 			    (zs->zs_ops == &zsops_async))
8827c478bd9Sstevel@tonic-gate 				goto again;
8837c478bd9Sstevel@tonic-gate 			else {
8847c478bd9Sstevel@tonic-gate 				if (set_zsoptinit && !(za->za_flags & ISOPEN))
8857c478bd9Sstevel@tonic-gate 					zsopinit(zs, &zsops_null);
8867c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
8877c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_ocexcl);
8887c478bd9Sstevel@tonic-gate 				return (EBUSY);
8897c478bd9Sstevel@tonic-gate 			}
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 	} else if ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE)) {
8927c478bd9Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
8937c478bd9Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
8947c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
8957c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
8967c478bd9Sstevel@tonic-gate 		return (EBUSY);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	za->za_ttycommon.t_readq = rq;
9007c478bd9Sstevel@tonic-gate 	za->za_ttycommon.t_writeq = WR(rq);
9017c478bd9Sstevel@tonic-gate 	rq->q_ptr = WR(rq)->q_ptr = (caddr_t)za;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	za->za_flags |= ZAS_ISOPEN;
9047c478bd9Sstevel@tonic-gate 	ZSA_GETBLOCK(zs, allocbcount);
9057c478bd9Sstevel@tonic-gate 	qprocson(rq);
9067c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
9077c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_ocexcl);
9087c478bd9Sstevel@tonic-gate 	return (0);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate static void
zs_progress_check(void * arg)9127c478bd9Sstevel@tonic-gate zs_progress_check(void *arg)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate 	struct asyncline *za = arg;
9157c478bd9Sstevel@tonic-gate 	struct zscom *zs = za->za_common;
9167c478bd9Sstevel@tonic-gate 	mblk_t *bp;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	/*
9197c478bd9Sstevel@tonic-gate 	 * We define "progress" as either waiting on a timed break or delay, or
9207c478bd9Sstevel@tonic-gate 	 * having had at least one transmitter interrupt.  If none of these are
9217c478bd9Sstevel@tonic-gate 	 * true, then just terminate the output and wake up that close thread.
9227c478bd9Sstevel@tonic-gate 	 */
9237c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
9247c478bd9Sstevel@tonic-gate 	if (!(zs->zs_flags & ZS_PROGRESS) &&
9257c478bd9Sstevel@tonic-gate 	    !(za->za_flags & (ZAS_BREAK|ZAS_DELAY))) {
9267c478bd9Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BUSY;
9277c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
9287c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
9297c478bd9Sstevel@tonic-gate 		zs->zs_wr_cur = NULL;
9307c478bd9Sstevel@tonic-gate 		zs->zs_wr_lim = NULL;
9317c478bd9Sstevel@tonic-gate 		bp = za->za_xmitblk;
9327c478bd9Sstevel@tonic-gate 		za->za_xmitblk = NULL;
9337c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
9347c478bd9Sstevel@tonic-gate 		zs->zs_timer = 0;
9357c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
9367c478bd9Sstevel@tonic-gate 		if (bp != NULL)
9377c478bd9Sstevel@tonic-gate 			freeb(bp);
9387c478bd9Sstevel@tonic-gate 		/*
9397c478bd9Sstevel@tonic-gate 		 * Since this timer is running, we know that we're in exit(2).
9407c478bd9Sstevel@tonic-gate 		 * That means that the user can't possibly be waiting on any
9417c478bd9Sstevel@tonic-gate 		 * valid ioctl(2) completion anymore, and we should just flush
9427c478bd9Sstevel@tonic-gate 		 * everything.
9437c478bd9Sstevel@tonic-gate 		 */
9447c478bd9Sstevel@tonic-gate 		flushq(za->za_ttycommon.t_writeq, FLUSHALL);
9457c478bd9Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
9467c478bd9Sstevel@tonic-gate 	} else {
9477c478bd9Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_PROGRESS;
9487c478bd9Sstevel@tonic-gate 		zs->zs_timer = timeout(zs_progress_check, za,
9497c478bd9Sstevel@tonic-gate 		    drv_usectohz(zs_drain_check));
9507c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate /*
9557c478bd9Sstevel@tonic-gate  * Close routine.
9567c478bd9Sstevel@tonic-gate  *
9577c478bd9Sstevel@tonic-gate  * Important locking note: the zs_ocexcl lock is not held at all in this
9587c478bd9Sstevel@tonic-gate  * routine.  This is intentional.  That lock is used to coordinate multiple
9597c478bd9Sstevel@tonic-gate  * simultaneous opens on a stream, and there's no such thing as multiple
9607c478bd9Sstevel@tonic-gate  * simultaneous closes on a stream.
9617c478bd9Sstevel@tonic-gate  */
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9647c478bd9Sstevel@tonic-gate static int
zsa_close(queue_t * q,int flag)9657c478bd9Sstevel@tonic-gate zsa_close(queue_t *q, int flag)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate 	struct asyncline *za;
9687c478bd9Sstevel@tonic-gate 	struct zscom *zs;
9697c478bd9Sstevel@tonic-gate 	int i;
9707c478bd9Sstevel@tonic-gate 	mblk_t *bp;
9717c478bd9Sstevel@tonic-gate 	timeout_id_t za_zsa_restart_id, za_kick_rcv_id;
9727c478bd9Sstevel@tonic-gate 	bufcall_id_t za_bufcid, za_wbufcid;
9737c478bd9Sstevel@tonic-gate 	int	 tmp;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	za = q->q_ptr;
9767c478bd9Sstevel@tonic-gate 	ASSERT(za != NULL);
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	zs = za->za_common;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
9817c478bd9Sstevel@tonic-gate 	zs->zs_flags |= ZS_CLOSING;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/*
9847c478bd9Sstevel@tonic-gate 	 * There are two flavors of break -- timed (M_BREAK or TCSBRK) and
9857c478bd9Sstevel@tonic-gate 	 * untimed (TIOCSBRK).  For the timed case, these are enqueued on our
9867c478bd9Sstevel@tonic-gate 	 * write queue and there's a timer running, so we don't have to worry
9877c478bd9Sstevel@tonic-gate 	 * about them.  For the untimed case, though, the user obviously made a
9887c478bd9Sstevel@tonic-gate 	 * mistake, because these are handled immediately.  We'll terminate the
9897c478bd9Sstevel@tonic-gate 	 * break now and honor his implicit request by discarding the rest of
9907c478bd9Sstevel@tonic-gate 	 * the data.
9917c478bd9Sstevel@tonic-gate 	 */
9927c478bd9Sstevel@tonic-gate 	if (!(za->za_flags & ZAS_BREAK) && (zs->zs_wreg[5] & ZSWR5_BREAK))
9937c478bd9Sstevel@tonic-gate 		goto nodrain;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	/*
9967c478bd9Sstevel@tonic-gate 	 * If the user told us not to delay the close ("non-blocking"), then
9977c478bd9Sstevel@tonic-gate 	 * don't bother trying to drain.
9987c478bd9Sstevel@tonic-gate 	 *
9997c478bd9Sstevel@tonic-gate 	 * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever
10007c478bd9Sstevel@tonic-gate 	 * getting an M_START (since these messages aren't enqueued), and the
10017c478bd9Sstevel@tonic-gate 	 * only other way to clear the stop condition is by loss of DCD, which
10027c478bd9Sstevel@tonic-gate 	 * would discard the queue data.  Thus, we drop the output data if
10037c478bd9Sstevel@tonic-gate 	 * ASYNC_STOPPED is set.
10047c478bd9Sstevel@tonic-gate 	 */
10057c478bd9Sstevel@tonic-gate 	if ((flag & (FNDELAY|FNONBLOCK)) || (za->za_flags & ZAS_STOPPED))
10067c478bd9Sstevel@tonic-gate 		goto nodrain;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	/*
10097c478bd9Sstevel@tonic-gate 	 * If there's any pending output, then we have to try to drain it.
10107c478bd9Sstevel@tonic-gate 	 * There are two main cases to be handled:
10117c478bd9Sstevel@tonic-gate 	 *	- called by close(2): need to drain until done or until
10127c478bd9Sstevel@tonic-gate 	 *	  a signal is received.  No timeout.
10137c478bd9Sstevel@tonic-gate 	 *	- called by exit(2): need to drain while making progress
10147c478bd9Sstevel@tonic-gate 	 *	  or until a timeout occurs.  No signals.
10157c478bd9Sstevel@tonic-gate 	 *
10167c478bd9Sstevel@tonic-gate 	 * If we can't rely on receiving a signal to get us out of a hung
10177c478bd9Sstevel@tonic-gate 	 * session, then we have to use a timer.  In this case, we set a timer
10187c478bd9Sstevel@tonic-gate 	 * to check for progress in sending the output data -- all that we ask
10197c478bd9Sstevel@tonic-gate 	 * (at each interval) is that there's been some progress made.  Since
10207c478bd9Sstevel@tonic-gate 	 * the interrupt routine grabs buffers from the write queue, we can't
10217c478bd9Sstevel@tonic-gate 	 * trust changes in zs_wr_cur.  Instead, we use a progress flag.
10227c478bd9Sstevel@tonic-gate 	 *
10237c478bd9Sstevel@tonic-gate 	 * Note that loss of carrier will cause the output queue to be flushed,
10247c478bd9Sstevel@tonic-gate 	 * and we'll wake up again and finish normally.
10257c478bd9Sstevel@tonic-gate 	 */
10267c478bd9Sstevel@tonic-gate 	if (!ddi_can_receive_sig() && zs_drain_check != 0) {
10277c478bd9Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_PROGRESS;
10287c478bd9Sstevel@tonic-gate 		zs->zs_timer = timeout(zs_progress_check, za,
10297c478bd9Sstevel@tonic-gate 		    drv_usectohz(zs_drain_check));
10307c478bd9Sstevel@tonic-gate 	}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	while (zs->zs_wr_cur != NULL ||
10337c478bd9Sstevel@tonic-gate 	    za->za_ttycommon.t_writeq->q_first != NULL ||
10347c478bd9Sstevel@tonic-gate 	    (za->za_flags & (ZAS_BUSY|ZAS_DELAY|ZAS_BREAK))) {
10357c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_excl) == 0)
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	if (zs->zs_timer != 0) {
10407c478bd9Sstevel@tonic-gate 		(void) untimeout(zs->zs_timer);
10417c478bd9Sstevel@tonic-gate 		zs->zs_timer = 0;
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate nodrain:
10457c478bd9Sstevel@tonic-gate 	/*
10467c478bd9Sstevel@tonic-gate 	 * If break is in progress, stop it.
10477c478bd9Sstevel@tonic-gate 	 */
10487c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
10497c478bd9Sstevel@tonic-gate 	if (zs->zs_wreg[5] & ZSWR5_BREAK) {
10507c478bd9Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
10517c478bd9Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BREAK;
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	za_wbufcid = za->za_wbufcid;
10557c478bd9Sstevel@tonic-gate 	za_bufcid = za->za_bufcid;
10567c478bd9Sstevel@tonic-gate 	za_zsa_restart_id = za->za_zsa_restart_id;
10577c478bd9Sstevel@tonic-gate 	za_kick_rcv_id = za->za_kick_rcv_id;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	za->za_wbufcid = za->za_bufcid = 0;
10607c478bd9Sstevel@tonic-gate 	za->za_zsa_restart_id = za->za_kick_rcv_id = 0;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	/*
10637c478bd9Sstevel@tonic-gate 	 * If line has HUPCL set or is incompletely opened,
10647c478bd9Sstevel@tonic-gate 	 * and it is not the console or the keyboard,
10657c478bd9Sstevel@tonic-gate 	 * fix up the modem lines.
10667c478bd9Sstevel@tonic-gate 	 */
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	zsopinit(zs, &zsops_null_async);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	/*
10717c478bd9Sstevel@tonic-gate 	 * Nobody, zsh or zs can now open this port until
10727c478bd9Sstevel@tonic-gate 	 * zsopinit(zs, &zsops_null);
10737c478bd9Sstevel@tonic-gate 	 *
10747c478bd9Sstevel@tonic-gate 	 */
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	if ((za->za_dev != rconsdev) && (za->za_dev != kbddev) &&
10777c478bd9Sstevel@tonic-gate 	    (za->za_dev != stdindev) &&
10787c478bd9Sstevel@tonic-gate 	    (((za->za_flags & (ZAS_WOPEN|ZAS_ISOPEN)) != ZAS_ISOPEN) ||
10797c478bd9Sstevel@tonic-gate 	    (za->za_ttycommon.t_cflag & HUPCL))) {
10807c478bd9Sstevel@tonic-gate 		/*
10817c478bd9Sstevel@tonic-gate 		 * If DTR is being held high by softcarrier,
10827c478bd9Sstevel@tonic-gate 		 * set up the ZS_ON set; if not, hang up.
10837c478bd9Sstevel@tonic-gate 		 */
10847c478bd9Sstevel@tonic-gate 		if (zsasoftdtr && (za->za_ttycommon.t_flags & TS_SOFTCAR))
10857c478bd9Sstevel@tonic-gate 			(void) zsmctl(zs, ZS_ON, DMSET);
10867c478bd9Sstevel@tonic-gate 		else
10877c478bd9Sstevel@tonic-gate 			(void) zsmctl(zs, ZS_OFF, DMSET);
10887c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
10897c478bd9Sstevel@tonic-gate 		/*
10907c478bd9Sstevel@tonic-gate 		 * Don't let an interrupt in the middle of close
10917c478bd9Sstevel@tonic-gate 		 * bounce us back to the top; just continue
10927c478bd9Sstevel@tonic-gate 		 * closing as if nothing had happened.
10937c478bd9Sstevel@tonic-gate 		 */
1094*d3d50737SRafael Vanoni 		tmp = cv_reltimedwait_sig(&zs->zs_flags_cv, zs->zs_excl,
1095*d3d50737SRafael Vanoni 		    drv_usectohz(10000), TR_CLOCK_TICK);
10967c478bd9Sstevel@tonic-gate 		if (zs->zs_suspended) {
10977c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
10987c478bd9Sstevel@tonic-gate 			(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
10997c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
11007c478bd9Sstevel@tonic-gate 		}
11017c478bd9Sstevel@tonic-gate 		if (tmp == 0)
11027c478bd9Sstevel@tonic-gate 			goto out;
11037c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	/*
11077c478bd9Sstevel@tonic-gate 	 * If nobody's now using it, turn off receiver interrupts.
11087c478bd9Sstevel@tonic-gate 	 */
11097c478bd9Sstevel@tonic-gate 	if ((za->za_flags & (ZAS_ISOPEN|ZAS_WOPEN)) == 0)
11107c478bd9Sstevel@tonic-gate 		SCC_BIC(1, ZSWR1_RIE);
11117c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate out:
11147c478bd9Sstevel@tonic-gate 	/*
11157c478bd9Sstevel@tonic-gate 	 * Clear out device state.
11167c478bd9Sstevel@tonic-gate 	 */
11177c478bd9Sstevel@tonic-gate 	ttycommon_close(&za->za_ttycommon);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	za->za_ttycommon.t_readq = NULL;
11207c478bd9Sstevel@tonic-gate 	za->za_ttycommon.t_writeq = NULL;
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
11237c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
11247c478bd9Sstevel@tonic-gate 	zs->zs_wr_cur = NULL;
11257c478bd9Sstevel@tonic-gate 	zs->zs_wr_lim = NULL;
11267c478bd9Sstevel@tonic-gate 	bp = za->za_xmitblk;
11277c478bd9Sstevel@tonic-gate 	za->za_xmitblk = NULL;
11287c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
11297c478bd9Sstevel@tonic-gate 	if (bp)
11307c478bd9Sstevel@tonic-gate 		freemsg(bp);
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
11337c478bd9Sstevel@tonic-gate 	zs->zs_rd_cur = NULL;
11347c478bd9Sstevel@tonic-gate 	zs->zs_rd_lim = NULL;
11357c478bd9Sstevel@tonic-gate 	bp = za->za_rcvblk;
11367c478bd9Sstevel@tonic-gate 	za->za_rcvblk = NULL;
11377c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
11387c478bd9Sstevel@tonic-gate 	if (bp)
11397c478bd9Sstevel@tonic-gate 		freemsg(bp);
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	for (i = 0; i < zsa_rstandby; i++) {
11427c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
11437c478bd9Sstevel@tonic-gate 		bp = za->za_rstandby[i];
11447c478bd9Sstevel@tonic-gate 		za->za_rstandby[i] = NULL;
11457c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
11467c478bd9Sstevel@tonic-gate 		if (bp)
11477c478bd9Sstevel@tonic-gate 			freemsg(bp);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (za->za_soft_active || za->za_kick_active) {
11517c478bd9Sstevel@tonic-gate 		zs->zs_flags |= ZS_CLOSED;
11527c478bd9Sstevel@tonic-gate 		while (za->za_soft_active || za->za_kick_active)
11537c478bd9Sstevel@tonic-gate 			cv_wait(&zs->zs_flags_cv, zs->zs_excl);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 	if (zs->zs_suspended) {
11567c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
11577c478bd9Sstevel@tonic-gate 		(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
11587c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
11597c478bd9Sstevel@tonic-gate 	}
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	ZSA_FLUSHQ;
11627c478bd9Sstevel@tonic-gate 	bzero(za, sizeof (struct asyncline));
11637c478bd9Sstevel@tonic-gate 	qprocsoff(q);
11647c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/*
11677c478bd9Sstevel@tonic-gate 	 * Cancel outstanding "bufcall" request.
11687c478bd9Sstevel@tonic-gate 	 */
11697c478bd9Sstevel@tonic-gate 	if (za_wbufcid)
11707c478bd9Sstevel@tonic-gate 		unbufcall(za_wbufcid);
11717c478bd9Sstevel@tonic-gate 	if (za_bufcid)
11727c478bd9Sstevel@tonic-gate 		unbufcall(za_bufcid);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	/*
11757c478bd9Sstevel@tonic-gate 	 * Cancel outstanding timeout.
11767c478bd9Sstevel@tonic-gate 	 */
11777c478bd9Sstevel@tonic-gate 	if (za_zsa_restart_id)
11787c478bd9Sstevel@tonic-gate 		(void) untimeout(za_zsa_restart_id);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	if (za_kick_rcv_id)
11817c478bd9Sstevel@tonic-gate 		(void) untimeout(za_kick_rcv_id);
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
11847c478bd9Sstevel@tonic-gate 	zsopinit(zs, &zsops_null);
11857c478bd9Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	/* Mark device as available for power management */
11887c478bd9Sstevel@tonic-gate 	(void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1);
11897c478bd9Sstevel@tonic-gate 	return (0);
11907c478bd9Sstevel@tonic-gate }
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate /*
11937c478bd9Sstevel@tonic-gate  * Put procedure for write queue.
11947c478bd9Sstevel@tonic-gate  * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
11957c478bd9Sstevel@tonic-gate  * set the flow control character for M_STOPI and M_STARTI messages;
11967c478bd9Sstevel@tonic-gate  * queue up M_BREAK, M_DELAY, and M_DATA messages for processing
11977c478bd9Sstevel@tonic-gate  * by the start routine, and then call the start routine; discard
11987c478bd9Sstevel@tonic-gate  * everything else. Note that this driver does not incorporate any
11997c478bd9Sstevel@tonic-gate  * mechanism to negotiate to handle the canonicalization process.
12007c478bd9Sstevel@tonic-gate  * It expects that these functions are handled in upper module(s),
12017c478bd9Sstevel@tonic-gate  * as we do in ldterm.
12027c478bd9Sstevel@tonic-gate  */
12037c478bd9Sstevel@tonic-gate static void
zsa_wput(queue_t * q,mblk_t * mp)12047c478bd9Sstevel@tonic-gate zsa_wput(queue_t *q, mblk_t *mp)
12057c478bd9Sstevel@tonic-gate {
12067c478bd9Sstevel@tonic-gate 	register struct asyncline	*za;
12077c478bd9Sstevel@tonic-gate 	register struct zscom		*zs;
12087c478bd9Sstevel@tonic-gate 	register struct copyresp	*resp;
12097c478bd9Sstevel@tonic-gate 	register mblk_t			*bp = NULL;
12107c478bd9Sstevel@tonic-gate 	int				error;
12117c478bd9Sstevel@tonic-gate 	struct iocblk			*iocp;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	za = (struct asyncline *)q->q_ptr;
12147c478bd9Sstevel@tonic-gate 	zs = za->za_common;
12157c478bd9Sstevel@tonic-gate 	if (zs->zs_flags & ZS_NEEDSOFT) {
12167c478bd9Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_NEEDSOFT;
12177c478bd9Sstevel@tonic-gate 		(void) zsa_softint(zs);
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	case M_STOP:
12237c478bd9Sstevel@tonic-gate 		/*
12247c478bd9Sstevel@tonic-gate 		 * Since we don't do real DMA, we can just let the
12257c478bd9Sstevel@tonic-gate 		 * chip coast to a stop after applying the brakes.
12267c478bd9Sstevel@tonic-gate 		 */
12277c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
12287c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
12297c478bd9Sstevel@tonic-gate 		za->za_flags |= ZAS_STOPPED;
12307c478bd9Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
12317c478bd9Sstevel@tonic-gate 			za->za_flags &= ~ZAS_BUSY;
12327c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
12337c478bd9Sstevel@tonic-gate 			bp = za->za_xmitblk;
12347c478bd9Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
12357c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
12367c478bd9Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
12377c478bd9Sstevel@tonic-gate 			za->za_xmitblk = NULL;
12387c478bd9Sstevel@tonic-gate 		}
12397c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
12407c478bd9Sstevel@tonic-gate 		if (bp)
12417c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
12427c478bd9Sstevel@tonic-gate 		freemsg(mp);
12437c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
12447c478bd9Sstevel@tonic-gate 		break;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	case M_START:
12477c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
12487c478bd9Sstevel@tonic-gate 		if (za->za_flags & ZAS_STOPPED) {
12497c478bd9Sstevel@tonic-gate 			za->za_flags &= ~ZAS_STOPPED;
12507c478bd9Sstevel@tonic-gate 			/*
12517c478bd9Sstevel@tonic-gate 			 * If an output operation is in progress,
12527c478bd9Sstevel@tonic-gate 			 * resume it. Otherwise, prod the start
12537c478bd9Sstevel@tonic-gate 			 * routine.
12547c478bd9Sstevel@tonic-gate 			 */
12557c478bd9Sstevel@tonic-gate 			zsa_start(zs);
12567c478bd9Sstevel@tonic-gate 		}
12577c478bd9Sstevel@tonic-gate 		freemsg(mp);
12587c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
12597c478bd9Sstevel@tonic-gate 		break;
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	case M_IOCTL:
12627c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
12637c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 		case TIOCGPPS:
12687c478bd9Sstevel@tonic-gate 			/*
12697c478bd9Sstevel@tonic-gate 			 * Get PPS state.
12707c478bd9Sstevel@tonic-gate 			 */
12717c478bd9Sstevel@tonic-gate 			if (mp->b_cont != NULL)
12727c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 			mp->b_cont = allocb(sizeof (int), BPRI_HI);
12757c478bd9Sstevel@tonic-gate 			if (mp->b_cont == NULL) {
12767c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
12777c478bd9Sstevel@tonic-gate 				iocp->ioc_error = ENOMEM;
12787c478bd9Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
12797c478bd9Sstevel@tonic-gate 				break;
12807c478bd9Sstevel@tonic-gate 			}
12817c478bd9Sstevel@tonic-gate 			if (za->za_pps)
12827c478bd9Sstevel@tonic-gate 				*(int *)mp->b_cont->b_wptr = 1;
12837c478bd9Sstevel@tonic-gate 			else
12847c478bd9Sstevel@tonic-gate 				*(int *)mp->b_cont->b_wptr = 0;
12857c478bd9Sstevel@tonic-gate 			mp->b_cont->b_wptr += sizeof (int);
12867c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
12877c478bd9Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
12887c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
12897c478bd9Sstevel@tonic-gate 			break;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 		case TIOCSPPS:
12927c478bd9Sstevel@tonic-gate 			/*
12937c478bd9Sstevel@tonic-gate 			 * Set PPS state.
12947c478bd9Sstevel@tonic-gate 			 */
12957c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
12967c478bd9Sstevel@tonic-gate 			if (error != 0) {
12977c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
12987c478bd9Sstevel@tonic-gate 				iocp->ioc_error = error;
12997c478bd9Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
13007c478bd9Sstevel@tonic-gate 				break;
13017c478bd9Sstevel@tonic-gate 			}
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 			za->za_pps = (*(int *)mp->b_cont->b_rptr != 0);
13047c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
13057c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
13067c478bd9Sstevel@tonic-gate 			break;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		case TIOCGPPSEV:
13097c478bd9Sstevel@tonic-gate 		{
13107c478bd9Sstevel@tonic-gate 			/*
13117c478bd9Sstevel@tonic-gate 			 * Get PPS event data.
13127c478bd9Sstevel@tonic-gate 			 */
13137c478bd9Sstevel@tonic-gate 			void *buf;
13147c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13157c478bd9Sstevel@tonic-gate 			struct ppsclockev32 p32;
13167c478bd9Sstevel@tonic-gate #endif
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 			if (mp->b_cont != NULL) {
13197c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
13207c478bd9Sstevel@tonic-gate 				mp->b_cont = NULL;
13217c478bd9Sstevel@tonic-gate 			}
13227c478bd9Sstevel@tonic-gate 			if (za->za_pps == NULL) {
13237c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
13247c478bd9Sstevel@tonic-gate 				iocp->ioc_error = ENXIO;
13257c478bd9Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
13267c478bd9Sstevel@tonic-gate 				break;
13277c478bd9Sstevel@tonic-gate 			}
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13307c478bd9Sstevel@tonic-gate 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
13317c478bd9Sstevel@tonic-gate 				TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv);
13327c478bd9Sstevel@tonic-gate 				p32.serial = ppsclockev.serial;
13337c478bd9Sstevel@tonic-gate 				buf = &p32;
13347c478bd9Sstevel@tonic-gate 				iocp->ioc_count = sizeof (struct ppsclockev32);
13357c478bd9Sstevel@tonic-gate 			} else
13367c478bd9Sstevel@tonic-gate #endif
13377c478bd9Sstevel@tonic-gate 			{
13387c478bd9Sstevel@tonic-gate 				buf = &ppsclockev;
13397c478bd9Sstevel@tonic-gate 				iocp->ioc_count = sizeof (struct ppsclockev);
13407c478bd9Sstevel@tonic-gate 			}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 			if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) {
13437c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
13447c478bd9Sstevel@tonic-gate 				iocp->ioc_error = ENOMEM;
13457c478bd9Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
13467c478bd9Sstevel@tonic-gate 				break;
13477c478bd9Sstevel@tonic-gate 			}
13487c478bd9Sstevel@tonic-gate 			mp->b_cont = bp;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 			bcopy(buf, bp->b_wptr, iocp->ioc_count);
13517c478bd9Sstevel@tonic-gate 			bp->b_wptr += iocp->ioc_count;
13527c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
13537c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
13547c478bd9Sstevel@tonic-gate 			break;
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 		case TCSETSW:
13587c478bd9Sstevel@tonic-gate 		case TCSETSF:
13597c478bd9Sstevel@tonic-gate 		case TCSETAW:
13607c478bd9Sstevel@tonic-gate 		case TCSETAF:
13617c478bd9Sstevel@tonic-gate 		case TCSBRK:
13627c478bd9Sstevel@tonic-gate 			/*
13637c478bd9Sstevel@tonic-gate 			 * The changes do not take effect until all
13647c478bd9Sstevel@tonic-gate 			 * output queued before them is drained.
13657c478bd9Sstevel@tonic-gate 			 * Put this message on the queue, so that
13667c478bd9Sstevel@tonic-gate 			 * "zsa_start" will see it when it's done
13677c478bd9Sstevel@tonic-gate 			 * with the output before it. Poke the
13687c478bd9Sstevel@tonic-gate 			 * start routine, just in case.
13697c478bd9Sstevel@tonic-gate 			 */
13707c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
13717c478bd9Sstevel@tonic-gate 			zsa_start(zs);
13727c478bd9Sstevel@tonic-gate 			break;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 		default:
13757c478bd9Sstevel@tonic-gate 			/*
13767c478bd9Sstevel@tonic-gate 			 * Do it now.
13777c478bd9Sstevel@tonic-gate 			 */
13787c478bd9Sstevel@tonic-gate 			zsa_ioctl(za, q, mp);
13797c478bd9Sstevel@tonic-gate 			break;
13807c478bd9Sstevel@tonic-gate 		}
13817c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
13827c478bd9Sstevel@tonic-gate 		break;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	case M_IOCDATA:
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
13887c478bd9Sstevel@tonic-gate 		resp = (struct copyresp *)mp->b_rptr;
13897c478bd9Sstevel@tonic-gate 		if (resp->cp_rval) {
13907c478bd9Sstevel@tonic-gate 			/*
13917c478bd9Sstevel@tonic-gate 			 * Just free message on failure.
13927c478bd9Sstevel@tonic-gate 			 */
13937c478bd9Sstevel@tonic-gate 			freemsg(mp);
13947c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
13957c478bd9Sstevel@tonic-gate 			break;
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 		switch (resp->cp_cmd) {
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 		case TIOCMSET:
14007c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
14017c478bd9Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14027c478bd9Sstevel@tonic-gate 			    DMSET);
14037c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
14047c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
14057c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
14067c478bd9Sstevel@tonic-gate 			break;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 		case TIOCMBIS:
14097c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
14107c478bd9Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14117c478bd9Sstevel@tonic-gate 			    DMBIS);
14127c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
14137c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
14147c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
14157c478bd9Sstevel@tonic-gate 			break;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 		case TIOCMBIC:
14187c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
14197c478bd9Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14207c478bd9Sstevel@tonic-gate 			    DMBIC);
14217c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
14227c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
14237c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
14247c478bd9Sstevel@tonic-gate 			break;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 		case TIOCMGET:
14277c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
14287c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
14297c478bd9Sstevel@tonic-gate 			break;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		default:
14327c478bd9Sstevel@tonic-gate 			freemsg(mp);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 		}
14357c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
14367c478bd9Sstevel@tonic-gate 		break;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	case M_FLUSH:
14407c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
14417c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 			/*
14447c478bd9Sstevel@tonic-gate 			 * Abort any output in progress.
14457c478bd9Sstevel@tonic-gate 			 */
14467c478bd9Sstevel@tonic-gate 			if (za->za_flags & ZAS_BUSY) {
14477c478bd9Sstevel@tonic-gate 				za->za_flags &= ~ZAS_BUSY;
14487c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
14497c478bd9Sstevel@tonic-gate 				za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
14507c478bd9Sstevel@tonic-gate 				zs->zs_wr_cur = NULL;
14517c478bd9Sstevel@tonic-gate 				zs->zs_wr_lim = NULL;
14527c478bd9Sstevel@tonic-gate 				bp = za->za_xmitblk;
14537c478bd9Sstevel@tonic-gate 				za->za_xmitblk = NULL;
14547c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
14557c478bd9Sstevel@tonic-gate 				if (bp)
14567c478bd9Sstevel@tonic-gate 					freemsg(bp);
14577c478bd9Sstevel@tonic-gate 			}
14587c478bd9Sstevel@tonic-gate 			/*
14597c478bd9Sstevel@tonic-gate 			 * Flush our write queue.
14607c478bd9Sstevel@tonic-gate 			 */
14617c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);	/* XXX doesn't flush M_DELAY */
14627c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;	/* it has been flushed */
14637c478bd9Sstevel@tonic-gate 		}
14647c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
14657c478bd9Sstevel@tonic-gate 			/*
14667c478bd9Sstevel@tonic-gate 			 * Flush any data in the temporary receive buffer
14677c478bd9Sstevel@tonic-gate 			 */
14687c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
14697c478bd9Sstevel@tonic-gate 			if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
14707c478bd9Sstevel@tonic-gate 			    (SCC_READ0() & ZSRR0_CD)) {
14717c478bd9Sstevel@tonic-gate 				ZSA_KICK_RCV;
14727c478bd9Sstevel@tonic-gate 			} else {
14737c478bd9Sstevel@tonic-gate 				ZSA_KICK_RCV;
14747c478bd9Sstevel@tonic-gate 				if (!(SCC_READ0() & ZSRR0_RX_READY)) {
14757c478bd9Sstevel@tonic-gate 					/*
14767c478bd9Sstevel@tonic-gate 					 * settle time for 1 character shift
14777c478bd9Sstevel@tonic-gate 					 */
14787c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_excl_hi);
14797c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_excl);
1480*d3d50737SRafael Vanoni 					delay(ztdelay(SPEED(
1481*d3d50737SRafael Vanoni 					    za->za_ttycommon.t_cflag))/3 + 1);
14827c478bd9Sstevel@tonic-gate 					mutex_enter(zs->zs_excl);
14837c478bd9Sstevel@tonic-gate 					mutex_enter(zs->zs_excl_hi);
14847c478bd9Sstevel@tonic-gate 					if (!(SCC_READ0() & ZSRR0_CD))
14857c478bd9Sstevel@tonic-gate 						ZSA_KICK_RCV;
14867c478bd9Sstevel@tonic-gate 				}
14877c478bd9Sstevel@tonic-gate 				while ((SCC_READ0() &
1488*d3d50737SRafael Vanoni 				    (ZSRR0_CD | ZSRR0_RX_READY)) ==
1489*d3d50737SRafael Vanoni 				    ZSRR0_RX_READY) {
14907c478bd9Sstevel@tonic-gate 					/*
14917c478bd9Sstevel@tonic-gate 					 * Empty Receiver
14927c478bd9Sstevel@tonic-gate 					 */
14937c478bd9Sstevel@tonic-gate 					(void) SCC_READDATA();
14947c478bd9Sstevel@tonic-gate 				}
14957c478bd9Sstevel@tonic-gate 			}
14967c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
14977c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
14987c478bd9Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
14997c478bd9Sstevel@tonic-gate 			/*
15007c478bd9Sstevel@tonic-gate 			 * give the read queues a crack at it
15017c478bd9Sstevel@tonic-gate 			 */
15027c478bd9Sstevel@tonic-gate 		} else
15037c478bd9Sstevel@tonic-gate 			freemsg(mp);
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 		/*
15067c478bd9Sstevel@tonic-gate 		 * We must make sure we process messages that survive the
15077c478bd9Sstevel@tonic-gate 		 * write-side flush. Without this call, the close protocol
15087c478bd9Sstevel@tonic-gate 		 * with ldterm can hang forever.  (ldterm will have sent us a
15097c478bd9Sstevel@tonic-gate 		 * TCSBRK ioctl that it expects a response to.)
15107c478bd9Sstevel@tonic-gate 		 */
15117c478bd9Sstevel@tonic-gate 		zsa_start(zs);
15127c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
15137c478bd9Sstevel@tonic-gate 		break;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	case M_BREAK:
15167c478bd9Sstevel@tonic-gate 	case M_DELAY:
15177c478bd9Sstevel@tonic-gate 	case M_DATA:
15187c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
15197c478bd9Sstevel@tonic-gate 		/*
15207c478bd9Sstevel@tonic-gate 		 * Queue the message up to be transmitted,
15217c478bd9Sstevel@tonic-gate 		 * and poke the start routine.
15227c478bd9Sstevel@tonic-gate 		 */
15237c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
15247c478bd9Sstevel@tonic-gate 		zsa_start(zs);
15257c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
15267c478bd9Sstevel@tonic-gate 		break;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	case M_STOPI:
15297c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
15307c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
15317c478bd9Sstevel@tonic-gate 		za->za_flowc = za->za_ttycommon.t_stopc;
15327c478bd9Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
15337c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
15347c478bd9Sstevel@tonic-gate 			bp = za->za_xmitblk;
15357c478bd9Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
15367c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
15377c478bd9Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
15387c478bd9Sstevel@tonic-gate 			za->za_xmitblk = NULL;
15397c478bd9Sstevel@tonic-gate 		}
15407c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
15417c478bd9Sstevel@tonic-gate 		if (bp)
15427c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
15437c478bd9Sstevel@tonic-gate 		else
15447c478bd9Sstevel@tonic-gate 			zsa_start(zs);		/* poke the start routine */
15457c478bd9Sstevel@tonic-gate 		freemsg(mp);
15467c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
15477c478bd9Sstevel@tonic-gate 		break;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	case M_STARTI:
15507c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
15517c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
15527c478bd9Sstevel@tonic-gate 		za->za_flowc = za->za_ttycommon.t_startc;
15537c478bd9Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
15547c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
15557c478bd9Sstevel@tonic-gate 			bp = za->za_xmitblk;
15567c478bd9Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
15577c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
15587c478bd9Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
15597c478bd9Sstevel@tonic-gate 			za->za_xmitblk = NULL;
15607c478bd9Sstevel@tonic-gate 		}
15617c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
15627c478bd9Sstevel@tonic-gate 		if (bp)
15637c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
15647c478bd9Sstevel@tonic-gate 		else
15657c478bd9Sstevel@tonic-gate 			zsa_start(zs);		/* poke the start routine */
15667c478bd9Sstevel@tonic-gate 		freemsg(mp);
15677c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
15687c478bd9Sstevel@tonic-gate 		break;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	case M_CTL:
15717c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) >= sizeof (struct iocblk) &&
15727c478bd9Sstevel@tonic-gate 		    ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) {
15737c478bd9Sstevel@tonic-gate 			((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX;
15747c478bd9Sstevel@tonic-gate 			qreply(q, mp);
15757c478bd9Sstevel@tonic-gate 		} else {
15767c478bd9Sstevel@tonic-gate 			/*
15777c478bd9Sstevel@tonic-gate 			 * These MC_SERVICE type messages are used by upper
15787c478bd9Sstevel@tonic-gate 			 * modules to tell this driver to send input up
15797c478bd9Sstevel@tonic-gate 			 * immediately, or that it can wait for normal
15807c478bd9Sstevel@tonic-gate 			 * processing that may or may not be done. Sun
15817c478bd9Sstevel@tonic-gate 			 * requires these for the mouse module.
15827c478bd9Sstevel@tonic-gate 			 */
15837c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
15847c478bd9Sstevel@tonic-gate 			switch (*mp->b_rptr) {
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 			case MC_SERVICEIMM:
15877c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
15887c478bd9Sstevel@tonic-gate 				za->za_flags |= ZAS_SERVICEIMM;
15897c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
15907c478bd9Sstevel@tonic-gate 				break;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 			case MC_SERVICEDEF:
15937c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
15947c478bd9Sstevel@tonic-gate 				za->za_flags &= ~ZAS_SERVICEIMM;
15957c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
15967c478bd9Sstevel@tonic-gate 				break;
15977c478bd9Sstevel@tonic-gate 			}
15987c478bd9Sstevel@tonic-gate 			freemsg(mp);
15997c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
16007c478bd9Sstevel@tonic-gate 		}
16017c478bd9Sstevel@tonic-gate 		break;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	default:
16047c478bd9Sstevel@tonic-gate 		/*
16057c478bd9Sstevel@tonic-gate 		 * "No, I don't want a subscription to Chain Store Age,
16067c478bd9Sstevel@tonic-gate 		 * thank you anyway."
16077c478bd9Sstevel@tonic-gate 		 */
16087c478bd9Sstevel@tonic-gate 		freemsg(mp);
16097c478bd9Sstevel@tonic-gate 		break;
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate  * zs read service procedure
16157c478bd9Sstevel@tonic-gate  */
16167c478bd9Sstevel@tonic-gate static void
zsa_rsrv(queue_t * q)16177c478bd9Sstevel@tonic-gate zsa_rsrv(queue_t *q)
16187c478bd9Sstevel@tonic-gate {
16197c478bd9Sstevel@tonic-gate 	struct asyncline	*za;
16207c478bd9Sstevel@tonic-gate 	struct zscom		*zs;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	if (((za = (struct asyncline *)q->q_ptr) != NULL) &&
16237c478bd9Sstevel@tonic-gate 	    (za->za_ttycommon.t_cflag & CRTSXOFF)) {
16247c478bd9Sstevel@tonic-gate 		zs = za->za_common;
16257c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
16267c478bd9Sstevel@tonic-gate 		ZSSETSOFT(zs);
16277c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
16287c478bd9Sstevel@tonic-gate 	}
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate  * Transmitter interrupt service routine.
16337c478bd9Sstevel@tonic-gate  * If there's more data to transmit in the current pseudo-DMA block,
16347c478bd9Sstevel@tonic-gate  * and the transmitter is ready, send the next character if output
16357c478bd9Sstevel@tonic-gate  * is not stopped or draining.
16367c478bd9Sstevel@tonic-gate  * Otherwise, queue up a soft interrupt.
16377c478bd9Sstevel@tonic-gate  */
16387c478bd9Sstevel@tonic-gate static void
zsa_txint(struct zscom * zs)16397c478bd9Sstevel@tonic-gate zsa_txint(struct zscom *zs)
16407c478bd9Sstevel@tonic-gate {
16417c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
16427c478bd9Sstevel@tonic-gate 	register uchar_t *wr_cur;
16437c478bd9Sstevel@tonic-gate 	register uchar_t s0;
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	s0 = SCC_READ0();
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	if ((wr_cur = zs->zs_wr_cur) != NULL) {
16487c478bd9Sstevel@tonic-gate 		if (wr_cur < zs->zs_wr_lim) {
16497c478bd9Sstevel@tonic-gate 			if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
16507c478bd9Sstevel@tonic-gate 			    !(s0 & ZSRR0_CTS)) {
16517c478bd9Sstevel@tonic-gate 				SCC_WRITE0(ZSWR0_RESET_TXINT);
16527c478bd9Sstevel@tonic-gate 				za->za_rcv_flags_mask |= DO_RETRANSMIT;
16537c478bd9Sstevel@tonic-gate 				return;
16547c478bd9Sstevel@tonic-gate 			}
16557c478bd9Sstevel@tonic-gate 			SCC_WRITEDATA(*wr_cur++);
16567c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
16577c478bd9Sstevel@tonic-gate 			za->za_wr++;
16587c478bd9Sstevel@tonic-gate #endif
16597c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = wr_cur;
16607c478bd9Sstevel@tonic-gate 			zs->zs_flags |= ZS_PROGRESS;
16617c478bd9Sstevel@tonic-gate 			return;
16627c478bd9Sstevel@tonic-gate 		} else {
16637c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
16647c478bd9Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
16657c478bd9Sstevel@tonic-gate 			/*
16667c478bd9Sstevel@tonic-gate 			 * Use the rcv_flags_mask as it is set and
16677c478bd9Sstevel@tonic-gate 			 * test while holding the zs_excl_hi mutex
16687c478bd9Sstevel@tonic-gate 			 */
16697c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_TRANSMIT;
16707c478bd9Sstevel@tonic-gate 			SCC_WRITE0(ZSWR0_RESET_TXINT);
16717c478bd9Sstevel@tonic-gate 			ZSSETSOFT(zs);
16727c478bd9Sstevel@tonic-gate 			return;
16737c478bd9Sstevel@tonic-gate 		}
16747c478bd9Sstevel@tonic-gate 	}
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	if (za->za_flowc != '\0' && (!(za->za_flags & ZAS_DRAINING))) {
16777c478bd9Sstevel@tonic-gate 		if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
16787c478bd9Sstevel@tonic-gate 		    !(s0 & ZSRR0_CTS)) {
16797c478bd9Sstevel@tonic-gate 			SCC_WRITE0(ZSWR0_RESET_TXINT);
16807c478bd9Sstevel@tonic-gate 			return;
16817c478bd9Sstevel@tonic-gate 		}
16827c478bd9Sstevel@tonic-gate 		SCC_WRITEDATA(za->za_flowc);
16837c478bd9Sstevel@tonic-gate 		za->za_flowc = '\0';
16847c478bd9Sstevel@tonic-gate 		return;
16857c478bd9Sstevel@tonic-gate 	}
16867c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXINT);
16877c478bd9Sstevel@tonic-gate 	/*
16887c478bd9Sstevel@tonic-gate 	 * Set DO_TRANSMIT bit so that the soft interrupt can
16897c478bd9Sstevel@tonic-gate 	 * test it and unset the ZAS_BUSY in za_flags while holding
16907c478bd9Sstevel@tonic-gate 	 * the mutex zs_excl and zs_excl_hi
16917c478bd9Sstevel@tonic-gate 	 */
16927c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask |= DO_TRANSMIT;
16937c478bd9Sstevel@tonic-gate 	ZSSETSOFT(zs);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate  * External/Status interrupt.
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate static void
zsa_xsint(struct zscom * zs)17007c478bd9Sstevel@tonic-gate zsa_xsint(struct zscom *zs)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
17037c478bd9Sstevel@tonic-gate 	register uchar_t s0, x0;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	s0 = SCC_READ0();
17067c478bd9Sstevel@tonic-gate 	ZSA_R0_LOG(s0);
17077c478bd9Sstevel@tonic-gate 	x0 = s0 ^ za->za_rr0;
17087c478bd9Sstevel@tonic-gate 	za->za_rr0 = s0;
17097c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	/*
17127c478bd9Sstevel@tonic-gate 	 * PPS (Pulse Per Second) support.
17137c478bd9Sstevel@tonic-gate 	 */
17147c478bd9Sstevel@tonic-gate 	if (za->za_pps && (x0 & ZSRR0_CD) && (s0 & ZSRR0_CD)) {
17157c478bd9Sstevel@tonic-gate 		/*
17167c478bd9Sstevel@tonic-gate 		 * This code captures a timestamp at the designated
17177c478bd9Sstevel@tonic-gate 		 * transition of the PPS signal (CD asserted).  The
17187c478bd9Sstevel@tonic-gate 		 * code provides a pointer to the timestamp, as well
17197c478bd9Sstevel@tonic-gate 		 * as the hardware counter value at the capture.
17207c478bd9Sstevel@tonic-gate 		 *
17217c478bd9Sstevel@tonic-gate 		 * Note: the kernel has nano based time values while
17227c478bd9Sstevel@tonic-gate 		 * NTP requires micro based, an in-line fast algorithm
17237c478bd9Sstevel@tonic-gate 		 * to convert nsec to usec is used here -- see hrt2ts()
17247c478bd9Sstevel@tonic-gate 		 * in common/os/timers.c for a full description.
17257c478bd9Sstevel@tonic-gate 		 */
17267c478bd9Sstevel@tonic-gate 		struct timeval *tvp = &ppsclockev.tv;
17277c478bd9Sstevel@tonic-gate 		timespec_t ts;
17287c478bd9Sstevel@tonic-gate 		int nsec, usec;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 		LED_OFF;
17317c478bd9Sstevel@tonic-gate 		gethrestime(&ts);
17327c478bd9Sstevel@tonic-gate 		LED_ON;
17337c478bd9Sstevel@tonic-gate 		nsec = ts.tv_nsec;
17347c478bd9Sstevel@tonic-gate 		usec = nsec + (nsec >> 2);
17357c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 1);
17367c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 2);
17377c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 4);
17387c478bd9Sstevel@tonic-gate 		usec = nsec - (usec >> 3);
17397c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 2);
17407c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 3);
17417c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 4);
17427c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 1);
17437c478bd9Sstevel@tonic-gate 		usec = nsec + (usec >> 6);
17447c478bd9Sstevel@tonic-gate 		tvp->tv_usec = usec >> 10;
17457c478bd9Sstevel@tonic-gate 		tvp->tv_sec = ts.tv_sec;
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 		++ppsclockev.serial;
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 		/*
17507c478bd9Sstevel@tonic-gate 		 * Because the kernel keeps a high-resolution time, pass the
17517c478bd9Sstevel@tonic-gate 		 * current highres timestamp in tvp and zero in usec.
17527c478bd9Sstevel@tonic-gate 		 */
17537c478bd9Sstevel@tonic-gate 		ddi_hardpps(tvp, 0);
17547c478bd9Sstevel@tonic-gate 	}
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	ZSA_KICK_RCV;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) == 0) {
17597c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
17607c478bd9Sstevel@tonic-gate 		/*
17617c478bd9Sstevel@tonic-gate 		 * ZSRR0_BREAK turned off.  This means that the break sequence
17627c478bd9Sstevel@tonic-gate 		 * has completed (i.e., the stop bit finally arrived).
17637c478bd9Sstevel@tonic-gate 		 */
17647c478bd9Sstevel@tonic-gate 		if ((s0 & ZSRR0_RX_READY) == 0) {
17657c478bd9Sstevel@tonic-gate 			/*
17667c478bd9Sstevel@tonic-gate 			 * SLAVIO will generate a separate STATUS change
17677c478bd9Sstevel@tonic-gate 			 * interrupt when the break sequence completes.
17687c478bd9Sstevel@tonic-gate 			 * SCC will combine both, taking the higher priority
17697c478bd9Sstevel@tonic-gate 			 * one, the receive.  Should still see the ext/stat.
17707c478bd9Sstevel@tonic-gate 			 * bit in REG3 on SCC.  If no ext/stat, it must be
17717c478bd9Sstevel@tonic-gate 			 * a SLAVIO.
17727c478bd9Sstevel@tonic-gate 			 */
17737c478bd9Sstevel@tonic-gate 			za->za_breakoff = 1;
17747c478bd9Sstevel@tonic-gate 		} else {
17757c478bd9Sstevel@tonic-gate 			/*
17767c478bd9Sstevel@tonic-gate 			 * The NUL character in the receiver is part of the
17777c478bd9Sstevel@tonic-gate 			 * break sequence; it is discarded.
17787c478bd9Sstevel@tonic-gate 			 */
17797c478bd9Sstevel@tonic-gate 			(void) SCC_READDATA(); /* swallow null */
17807c478bd9Sstevel@tonic-gate 		}
17817c478bd9Sstevel@tonic-gate #else /* SLAVIO_BUG */
17827c478bd9Sstevel@tonic-gate 		/*
17837c478bd9Sstevel@tonic-gate 		 * ZSRR0_BREAK turned off.  This means that the break sequence
17847c478bd9Sstevel@tonic-gate 		 * has completed (i.e., the stop bit finally arrived).  The NUL
17857c478bd9Sstevel@tonic-gate 		 * character in the receiver is part of the break sequence;
17867c478bd9Sstevel@tonic-gate 		 * it is discarded.
17877c478bd9Sstevel@tonic-gate 		 */
17887c478bd9Sstevel@tonic-gate 		(void) SCC_READDATA(); /* swallow null */
17897c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
17907c478bd9Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_ERRORS);
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 		/*
17937c478bd9Sstevel@tonic-gate 		 * Note: this will cause an abort if a break occurs on
17947c478bd9Sstevel@tonic-gate 		 * the "keyboard device", regardless of whether the
17957c478bd9Sstevel@tonic-gate 		 * "keyboard device" is a real keyboard or just a
17967c478bd9Sstevel@tonic-gate 		 * terminal on a serial line. This permits you to
17977c478bd9Sstevel@tonic-gate 		 * abort a workstation by unplugging the keyboard,
17987c478bd9Sstevel@tonic-gate 		 * even if the normal abort key sequence isn't working.
17997c478bd9Sstevel@tonic-gate 		 */
18007c478bd9Sstevel@tonic-gate 		if ((za->za_dev == kbddev) ||
18017c478bd9Sstevel@tonic-gate 		    ((za->za_dev == rconsdev) || (za->za_dev == stdindev)) &&
18027c478bd9Sstevel@tonic-gate 		    (abort_enable != KIOCABORTALTERNATE)) {
18037c478bd9Sstevel@tonic-gate 			abort_sequence_enter((char *)NULL);
18047c478bd9Sstevel@tonic-gate 			/*
18057c478bd9Sstevel@tonic-gate 			 * We just broke into the monitor or debugger,
18067c478bd9Sstevel@tonic-gate 			 * ignore the break in this case so whatever
18077c478bd9Sstevel@tonic-gate 			 * random program that was running doesn't get
18087c478bd9Sstevel@tonic-gate 			 * a SIGINT.
18097c478bd9Sstevel@tonic-gate 			 */
18107c478bd9Sstevel@tonic-gate 			return;
18117c478bd9Sstevel@tonic-gate 		}
18127c478bd9Sstevel@tonic-gate 		za->za_break = 1;
18137c478bd9Sstevel@tonic-gate 	}
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	/*
18167c478bd9Sstevel@tonic-gate 	 * If hardware flow control is enabled, (re)start output
18177c478bd9Sstevel@tonic-gate 	 * when CTS is reasserted.
18187c478bd9Sstevel@tonic-gate 	 */
18197c478bd9Sstevel@tonic-gate 	if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
18207c478bd9Sstevel@tonic-gate 	    (x0 & ZSRR0_CTS) && (s0 & ZSRR0_CTS) &&
18217c478bd9Sstevel@tonic-gate 	    (za->za_rcv_flags_mask & DO_RETRANSMIT))
18227c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_TRANSMIT;
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	za->za_ext = 1;
18257c478bd9Sstevel@tonic-gate 	ZSSETSOFT(zs);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate /*
18297c478bd9Sstevel@tonic-gate  * Receive Interrupt
18307c478bd9Sstevel@tonic-gate  */
18317c478bd9Sstevel@tonic-gate static void
zsa_rxint(struct zscom * zs)18327c478bd9Sstevel@tonic-gate zsa_rxint(struct zscom *zs)
18337c478bd9Sstevel@tonic-gate {
18347c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
18357c478bd9Sstevel@tonic-gate 	register uchar_t c;
18367c478bd9Sstevel@tonic-gate 	register uchar_t *rd_cur = zs->zs_rd_cur;
18377c478bd9Sstevel@tonic-gate 	register uchar_t *rd_lim = zs->zs_rd_lim;
18387c478bd9Sstevel@tonic-gate 	register mblk_t	*bp;
18397c478bd9Sstevel@tonic-gate 	register uint_t	fm = za->za_rcv_flags_mask;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
18437c478bd9Sstevel@tonic-gate 	za->za_rd++;
18447c478bd9Sstevel@tonic-gate #endif
18457c478bd9Sstevel@tonic-gate 	c = (fm >> 16) & (SCC_READDATA());
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	/*
18487c478bd9Sstevel@tonic-gate 	 * Check for character break sequence
18497c478bd9Sstevel@tonic-gate 	 */
18507c478bd9Sstevel@tonic-gate 	if ((abort_enable == KIOCABORTALTERNATE) && (za->za_dev == rconsdev)) {
18517c478bd9Sstevel@tonic-gate 		if (abort_charseq_recognize(c))
18527c478bd9Sstevel@tonic-gate 			abort_sequence_enter((char *)NULL);
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	if (!rd_cur) {
18567c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
18577c478bd9Sstevel@tonic-gate 		/*
18587c478bd9Sstevel@tonic-gate 		 * SLAVIO generates FE for the start of break and
18597c478bd9Sstevel@tonic-gate 		 * during break when parity is set.  End of break is
18607c478bd9Sstevel@tonic-gate 		 * detected when the first character is received.
18617c478bd9Sstevel@tonic-gate 		 * This character is always garbage and is thrown away.
18627c478bd9Sstevel@tonic-gate 		 */
18637c478bd9Sstevel@tonic-gate 		if (za->za_slav_break) {
18647c478bd9Sstevel@tonic-gate 			za->za_slav_break = 0;
18657c478bd9Sstevel@tonic-gate 			za->za_rr0 |= ZSRR0_BREAK;
18667c478bd9Sstevel@tonic-gate 			zsa_xsint(zs);
18677c478bd9Sstevel@tonic-gate 			return;
18687c478bd9Sstevel@tonic-gate 		}
18697c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 		if (c == 0 && (za->za_rr0 & ZSRR0_BREAK)) {
18727c478bd9Sstevel@tonic-gate 			/*
18737c478bd9Sstevel@tonic-gate 			 * A break sequence was under way, and a NUL character
18747c478bd9Sstevel@tonic-gate 			 * was received. Discard the NUL character, as it is
18757c478bd9Sstevel@tonic-gate 			 * part of the break sequence; if ZSRR0_BREAK turned
18767c478bd9Sstevel@tonic-gate 			 * off, indicating that the break sequence has com-
18777c478bd9Sstevel@tonic-gate 			 * pleted, call "zsa_xsint" to properly handle the
18787c478bd9Sstevel@tonic-gate 			 * error. It would appear that External/Status
18797c478bd9Sstevel@tonic-gate 			 * interrupts get lost occasionally, so this ensures
18807c478bd9Sstevel@tonic-gate 			 * that one is delivered.
18817c478bd9Sstevel@tonic-gate 			 */
18827c478bd9Sstevel@tonic-gate 			c = SCC_READ0();
18837c478bd9Sstevel@tonic-gate 			if (!(c & ZSRR0_BREAK))
18847c478bd9Sstevel@tonic-gate 				zsa_xsint(zs);
18857c478bd9Sstevel@tonic-gate 			return;
18867c478bd9Sstevel@tonic-gate 		}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
18897c478bd9Sstevel@tonic-gate 		if (c == 0 && za->za_breakoff) {
18907c478bd9Sstevel@tonic-gate 			/*
18917c478bd9Sstevel@tonic-gate 			 * A break sequence completed, but SLAVIO generates
18927c478bd9Sstevel@tonic-gate 			 * the NULL character interrupt late, so we throw the
18937c478bd9Sstevel@tonic-gate 			 * NULL away now.
18947c478bd9Sstevel@tonic-gate 			 */
18957c478bd9Sstevel@tonic-gate 			return;
18967c478bd9Sstevel@tonic-gate 		}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 		/*
18997c478bd9Sstevel@tonic-gate 		 * make sure it gets cleared.
19007c478bd9Sstevel@tonic-gate 		 */
19017c478bd9Sstevel@tonic-gate 		za->za_breakoff = 0;
19027c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 		ZSA_KICK_RCV;	/* We can have M_BREAK msg */
19057c478bd9Sstevel@tonic-gate 		ZSA_ALLOCB(bp);
19067c478bd9Sstevel@tonic-gate 		if (!bp) {
19077c478bd9Sstevel@tonic-gate 			za->za_sw_overrun++;
19087c478bd9Sstevel@tonic-gate 			ZSSETSOFT(zs);
19097c478bd9Sstevel@tonic-gate 			return;
19107c478bd9Sstevel@tonic-gate 		}
19117c478bd9Sstevel@tonic-gate 		za->za_rcvblk = bp;
19127c478bd9Sstevel@tonic-gate 		zs->zs_rd_cur = rd_cur = bp->b_wptr;
19137c478bd9Sstevel@tonic-gate 		zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
19147c478bd9Sstevel@tonic-gate 		if (za->za_kick_rcv_id == 0)
19157c478bd9Sstevel@tonic-gate 			ZSSETSOFT(zs);
19167c478bd9Sstevel@tonic-gate 	}
19177c478bd9Sstevel@tonic-gate 	if (c == 0377 && (fm & DO_ESC)) {
19187c478bd9Sstevel@tonic-gate 		if (rd_lim < rd_cur + 2) {
19197c478bd9Sstevel@tonic-gate 			ZSA_ALLOCB(bp);
19207c478bd9Sstevel@tonic-gate 			ZSA_KICK_RCV;
19217c478bd9Sstevel@tonic-gate 			if (!bp) {
19227c478bd9Sstevel@tonic-gate 				za->za_sw_overrun++;
19237c478bd9Sstevel@tonic-gate 				return;
19247c478bd9Sstevel@tonic-gate 			}
19257c478bd9Sstevel@tonic-gate 			za->za_rcvblk = bp;
19267c478bd9Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur = bp->b_wptr;
19277c478bd9Sstevel@tonic-gate 			zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
19287c478bd9Sstevel@tonic-gate 		}
19297c478bd9Sstevel@tonic-gate 		*rd_cur++ = c;
19307c478bd9Sstevel@tonic-gate 	}
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	*rd_cur++ = c;
19347c478bd9Sstevel@tonic-gate 	zs->zs_rd_cur = rd_cur;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	if (rd_cur == rd_lim) {
19377c478bd9Sstevel@tonic-gate 		ZSA_KICK_RCV;
19387c478bd9Sstevel@tonic-gate 	} else if ((fm & DO_STOPC) && (c == (fm & 0xff))) {
19397c478bd9Sstevel@tonic-gate 		za->za_do_kick_rcv_in_softint = 1;
19407c478bd9Sstevel@tonic-gate 		ZSSETSOFT(zs);
19417c478bd9Sstevel@tonic-gate 	}
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	if ((za->za_flags & ZAS_SERVICEIMM) || g_nocluster) {
19447c478bd9Sstevel@tonic-gate 		/*
19457c478bd9Sstevel@tonic-gate 		 * Send the data up immediately
19467c478bd9Sstevel@tonic-gate 		 */
19477c478bd9Sstevel@tonic-gate 		ZSA_KICK_RCV;
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate }
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate /*
19527c478bd9Sstevel@tonic-gate  * Special receive condition interrupt handler.
19537c478bd9Sstevel@tonic-gate  */
19547c478bd9Sstevel@tonic-gate static void
zsa_srint(struct zscom * zs)19557c478bd9Sstevel@tonic-gate zsa_srint(struct zscom *zs)
19567c478bd9Sstevel@tonic-gate {
19577c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
19587c478bd9Sstevel@tonic-gate 	register short s1;
19597c478bd9Sstevel@tonic-gate 	register uchar_t c;
19607c478bd9Sstevel@tonic-gate 	register uchar_t c1;
19617c478bd9Sstevel@tonic-gate 	register mblk_t *bp = za->za_rcvblk;
19627c478bd9Sstevel@tonic-gate 	register uchar_t *rd_cur = zs->zs_rd_cur;
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	SCC_READ(1, s1);
19657c478bd9Sstevel@tonic-gate 	if (s1 & (ZSRR1_FE | ZSRR1_PE | ZSRR1_DO)) {
19667c478bd9Sstevel@tonic-gate 		c = SCC_READDATA();	/* swallow bad character */
19677c478bd9Sstevel@tonic-gate 	}
19687c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
19697c478bd9Sstevel@tonic-gate 	/*
19707c478bd9Sstevel@tonic-gate 	 * SLAVIO does not handle breaks properly when parity is enabled.
19717c478bd9Sstevel@tonic-gate 	 *
19727c478bd9Sstevel@tonic-gate 	 * In general, if a null character is received when a framing
19737c478bd9Sstevel@tonic-gate 	 * error occurs then it is a break condition and not a real
19747c478bd9Sstevel@tonic-gate 	 * framing error. The null character must be limited to the
19757c478bd9Sstevel@tonic-gate 	 * number of bits including the parity bit. For example, a 6
19767c478bd9Sstevel@tonic-gate 	 * bit character with parity would be null if the lower 7 bits
19777c478bd9Sstevel@tonic-gate 	 * read from the receive fifo were 0. (The higher order bits are
19787c478bd9Sstevel@tonic-gate 	 * padded with 1 and/or the stop bits.) The only exception to this
19797c478bd9Sstevel@tonic-gate 	 * general rule would be an 8 bit null character with parity being
19807c478bd9Sstevel@tonic-gate 	 * a 1 in the parity bit and a framing error. This exception
19817c478bd9Sstevel@tonic-gate 	 * can be determined by examining the parity error bit in RREG 1.
19827c478bd9Sstevel@tonic-gate 	 *
19837c478bd9Sstevel@tonic-gate 	 * A null character, even parity, 8 bits, no parity error,
19847c478bd9Sstevel@tonic-gate 	 * (0 0000 0000) with framing error is a break condition.
19857c478bd9Sstevel@tonic-gate 	 *
19867c478bd9Sstevel@tonic-gate 	 * A null character, even parity, 8 bits, parity error,
19877c478bd9Sstevel@tonic-gate 	 * (1 0000 0000) with framing error is a framing error.
19887c478bd9Sstevel@tonic-gate 	 *
19897c478bd9Sstevel@tonic-gate 	 * A null character, odd parity, 8 bits, parity error
19907c478bd9Sstevel@tonic-gate 	 * (0 0000 0000) with framing error is a break condition.
19917c478bd9Sstevel@tonic-gate 	 *
19927c478bd9Sstevel@tonic-gate 	 * A null character, odd parity, 8 bits, no parity error,
19937c478bd9Sstevel@tonic-gate 	 * (1 0000 0000) with framing error is a framing error.
19947c478bd9Sstevel@tonic-gate 	 */
19957c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARENB) {
19967c478bd9Sstevel@tonic-gate 		switch (za->za_ttycommon.t_cflag & CSIZE) {
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 		case CS5:
19997c478bd9Sstevel@tonic-gate 			c1 = c & 0x3f;
20007c478bd9Sstevel@tonic-gate 			break;
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 		case CS6:
20037c478bd9Sstevel@tonic-gate 			c1 = c & 0x7f;
20047c478bd9Sstevel@tonic-gate 			break;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 		case CS7:
20077c478bd9Sstevel@tonic-gate 			c1 = c & 0xff;
20087c478bd9Sstevel@tonic-gate 			break;
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 		case CS8:
20117c478bd9Sstevel@tonic-gate 			if ((za->za_ttycommon.t_cflag & PARODD) &&
20127c478bd9Sstevel@tonic-gate 			    !(s1 & ZSRR1_PE))
20137c478bd9Sstevel@tonic-gate 				c1 = 0xff;
20147c478bd9Sstevel@tonic-gate 			else if (!(za->za_ttycommon.t_cflag & PARODD) &&
20157c478bd9Sstevel@tonic-gate 			    (s1 & ZSRR1_PE))
20167c478bd9Sstevel@tonic-gate 				c1 = 0xff;
20177c478bd9Sstevel@tonic-gate 			else
20187c478bd9Sstevel@tonic-gate 				c1 = c;
20197c478bd9Sstevel@tonic-gate 			break;
20207c478bd9Sstevel@tonic-gate 		}
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 		/*
20237c478bd9Sstevel@tonic-gate 		 * We fake start of break condition.
20247c478bd9Sstevel@tonic-gate 		 */
20257c478bd9Sstevel@tonic-gate 		if ((s1 & ZSRR1_FE) && c1 == 0) {
20267c478bd9Sstevel@tonic-gate 			za->za_slav_break = 1;
20277c478bd9Sstevel@tonic-gate 			return;
20287c478bd9Sstevel@tonic-gate 		}
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	if (s1 & ZSRR1_PE) {
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 		/*
20357c478bd9Sstevel@tonic-gate 		 * Mark the parity error so zsa_process will
20367c478bd9Sstevel@tonic-gate 		 * notice it and send it up in an M_BREAK
20377c478bd9Sstevel@tonic-gate 		 * message; ldterm will do the actual parity error
20387c478bd9Sstevel@tonic-gate 		 * processing
20397c478bd9Sstevel@tonic-gate 		 */
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 		if (bp && zs->zs_rd_cur) {	/* M_DATA msg */
20427c478bd9Sstevel@tonic-gate 			ZSA_KICK_RCV;
20437c478bd9Sstevel@tonic-gate 			bp = NULL;
20447c478bd9Sstevel@tonic-gate 		}
20457c478bd9Sstevel@tonic-gate 		if (!bp)
20467c478bd9Sstevel@tonic-gate 			ZSA_ALLOCB(bp);
20477c478bd9Sstevel@tonic-gate 		if (!bp) {
20487c478bd9Sstevel@tonic-gate 			za->za_sw_overrun++;
20497c478bd9Sstevel@tonic-gate 			ZSSETSOFT(zs);
20507c478bd9Sstevel@tonic-gate 		} else {
20517c478bd9Sstevel@tonic-gate 			za->za_rcvblk = bp;
20527c478bd9Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur = bp->b_wptr;
20537c478bd9Sstevel@tonic-gate 			zs->zs_rd_lim = bp->b_datap->db_lim;
20547c478bd9Sstevel@tonic-gate 			*rd_cur++ = c;
20557c478bd9Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur;
20567c478bd9Sstevel@tonic-gate 			bp->b_datap->db_type = M_BREAK;
20577c478bd9Sstevel@tonic-gate 			if (bp->b_datap->db_lim <= rd_cur)
20587c478bd9Sstevel@tonic-gate 				ZSA_KICK_RCV;
20597c478bd9Sstevel@tonic-gate 			za->za_do_kick_rcv_in_softint = 1;
20607c478bd9Sstevel@tonic-gate 			ZSSETSOFT(zs);
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 		}
20637c478bd9Sstevel@tonic-gate 	}
20647c478bd9Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
20657c478bd9Sstevel@tonic-gate 	if (s1 & ZSRR1_DO) {
20667c478bd9Sstevel@tonic-gate 		za->za_hw_overrun++;
20677c478bd9Sstevel@tonic-gate 		ZSSETSOFT(zs);
20687c478bd9Sstevel@tonic-gate 	}
20697c478bd9Sstevel@tonic-gate }
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate /*
20727c478bd9Sstevel@tonic-gate  * Process software interrupts (or poll)
20737c478bd9Sstevel@tonic-gate  * Crucial points:
20747c478bd9Sstevel@tonic-gate  * 3.	BUG - breaks are handled "out-of-band" - their relative position
20757c478bd9Sstevel@tonic-gate  *	among input events is lost, as well as multiple breaks together.
20767c478bd9Sstevel@tonic-gate  *	This is probably not a problem in practice.
20777c478bd9Sstevel@tonic-gate  */
20787c478bd9Sstevel@tonic-gate static int
zsa_softint(struct zscom * zs)20797c478bd9Sstevel@tonic-gate zsa_softint(struct zscom *zs)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
20827c478bd9Sstevel@tonic-gate 	register uchar_t r0;
20837c478bd9Sstevel@tonic-gate 	register uchar_t za_kick_active;
20847c478bd9Sstevel@tonic-gate 	register int	m_error;
20857c478bd9Sstevel@tonic-gate 	register int	allocbcount = 0;
20867c478bd9Sstevel@tonic-gate 	register int 	do_ttycommon_qfull = 0;
20877c478bd9Sstevel@tonic-gate 	boolean_t	hangup = B_FALSE, unhangup = B_FALSE;
20887c478bd9Sstevel@tonic-gate 	boolean_t	m_break = B_FALSE, wakeup = B_FALSE;
20897c478bd9Sstevel@tonic-gate 	register queue_t *q;
20907c478bd9Sstevel@tonic-gate 	register mblk_t	*bp;
20917c478bd9Sstevel@tonic-gate 	register mblk_t *head = NULL, *tail = NULL;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
20947c478bd9Sstevel@tonic-gate 	if (zs->zs_suspended || (zs->zs_flags & ZS_CLOSED)) {
20957c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
20967c478bd9Sstevel@tonic-gate 		return (0);
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
20997c478bd9Sstevel@tonic-gate 	if (za->za_flags & ZAS_WOPEN && !q) {
21007c478bd9Sstevel@tonic-gate 		if (za->za_ext) {
21017c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
21027c478bd9Sstevel@tonic-gate 			r0 = SCC_READ0();
21037c478bd9Sstevel@tonic-gate 			za->za_ext = 0;
21047c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
21057c478bd9Sstevel@tonic-gate 			/*
21067c478bd9Sstevel@tonic-gate 			 * carrier up?
21077c478bd9Sstevel@tonic-gate 			 */
21087c478bd9Sstevel@tonic-gate 			if ((r0 & ZSRR0_CD) ||
21097c478bd9Sstevel@tonic-gate 			    (za->za_ttycommon.t_flags & TS_SOFTCAR)) {
21107c478bd9Sstevel@tonic-gate 				/*
21117c478bd9Sstevel@tonic-gate 				 * carrier present
21127c478bd9Sstevel@tonic-gate 				 */
21137c478bd9Sstevel@tonic-gate 				if ((za->za_flags & ZAS_CARR_ON) == 0) {
21147c478bd9Sstevel@tonic-gate 					za->za_flags |= ZAS_CARR_ON;
21157c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_excl);
21167c478bd9Sstevel@tonic-gate 					cv_broadcast(&zs->zs_flags_cv);
21177c478bd9Sstevel@tonic-gate 					return (0);
21187c478bd9Sstevel@tonic-gate 				}
21197c478bd9Sstevel@tonic-gate 			}
21207c478bd9Sstevel@tonic-gate 		}
21217c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
21227c478bd9Sstevel@tonic-gate 		return (0);
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
21257c478bd9Sstevel@tonic-gate 	if (!q) {
21267c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
21277c478bd9Sstevel@tonic-gate 		return (0);
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	m_error = za->za_m_error;
21317c478bd9Sstevel@tonic-gate 	za->za_m_error = 0;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	if (za->za_do_kick_rcv_in_softint) {
21347c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
21357c478bd9Sstevel@tonic-gate 		ZSA_KICK_RCV;
21367c478bd9Sstevel@tonic-gate 		za->za_do_kick_rcv_in_softint = 0;
21377c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
21387c478bd9Sstevel@tonic-gate 	}
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	za_kick_active = za->za_kick_active;
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 	while (!za_kick_active) {
21437c478bd9Sstevel@tonic-gate 		ZSA_SEEQ(bp);
21447c478bd9Sstevel@tonic-gate 		if (!bp)
21457c478bd9Sstevel@tonic-gate 			break;
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 		allocbcount++;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 		if (bp->b_datap->db_type <= QPCTL) {
21507c478bd9Sstevel@tonic-gate 			if (!(canputnext(q))) {
21517c478bd9Sstevel@tonic-gate 				if (za->za_grace_flow_control >=
21527c478bd9Sstevel@tonic-gate 				    zsa_grace_flow_control) {
2153*d3d50737SRafael Vanoni 					if (za->za_ttycommon.t_cflag &
2154*d3d50737SRafael Vanoni 					    CRTSXOFF) {
21557c478bd9Sstevel@tonic-gate 						allocbcount--;
21567c478bd9Sstevel@tonic-gate 						break;
21577c478bd9Sstevel@tonic-gate 					}
21587c478bd9Sstevel@tonic-gate 					ZSA_GETQ(bp);
21597c478bd9Sstevel@tonic-gate 					freemsg(bp);
21607c478bd9Sstevel@tonic-gate 					do_ttycommon_qfull = 1;
21617c478bd9Sstevel@tonic-gate 					continue;
21627c478bd9Sstevel@tonic-gate 				} else
21637c478bd9Sstevel@tonic-gate 					za->za_grace_flow_control++;
21647c478bd9Sstevel@tonic-gate 			} else
21657c478bd9Sstevel@tonic-gate 				za->za_grace_flow_control = 0;
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 		ZSA_GETQ(bp);
21687c478bd9Sstevel@tonic-gate 		if (!head) {
21697c478bd9Sstevel@tonic-gate 			head = bp;
21707c478bd9Sstevel@tonic-gate 		} else {
21717c478bd9Sstevel@tonic-gate 			if (!tail)
21727c478bd9Sstevel@tonic-gate 				tail = head;
21737c478bd9Sstevel@tonic-gate 			tail->b_next = bp;
21747c478bd9Sstevel@tonic-gate 			tail = bp;
21757c478bd9Sstevel@tonic-gate 		}
21767c478bd9Sstevel@tonic-gate 	}
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	if (allocbcount)
21797c478bd9Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	if (za->za_ext) {
21827c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
21837c478bd9Sstevel@tonic-gate 		r0 = SCC_READ0();
21847c478bd9Sstevel@tonic-gate 		za->za_ext = 0;
21857c478bd9Sstevel@tonic-gate 		/*
21867c478bd9Sstevel@tonic-gate 		 * carrier up?
21877c478bd9Sstevel@tonic-gate 		 */
21887c478bd9Sstevel@tonic-gate 		if ((r0 & ZSRR0_CD) ||
21897c478bd9Sstevel@tonic-gate 		    (za->za_ttycommon.t_flags & TS_SOFTCAR)) {
21907c478bd9Sstevel@tonic-gate 			/*
21917c478bd9Sstevel@tonic-gate 			 * carrier present
21927c478bd9Sstevel@tonic-gate 			 */
21937c478bd9Sstevel@tonic-gate 			if ((za->za_flags & ZAS_CARR_ON) == 0) {
21947c478bd9Sstevel@tonic-gate 				za->za_flags |= ZAS_CARR_ON;
21957c478bd9Sstevel@tonic-gate 				unhangup = B_TRUE;
21967c478bd9Sstevel@tonic-gate 				wakeup = B_TRUE;
21977c478bd9Sstevel@tonic-gate 			}
21987c478bd9Sstevel@tonic-gate 		} else {
21997c478bd9Sstevel@tonic-gate 			if ((za->za_flags & ZAS_CARR_ON) &&
22007c478bd9Sstevel@tonic-gate 			    !(za->za_ttycommon.t_cflag & CLOCAL)) {
22017c478bd9Sstevel@tonic-gate 				/*
22027c478bd9Sstevel@tonic-gate 				 * Carrier went away.
22037c478bd9Sstevel@tonic-gate 				 * Drop DTR, abort any output in progress,
22047c478bd9Sstevel@tonic-gate 				 * indicate that output is not stopped, and
22057c478bd9Sstevel@tonic-gate 				 * send a hangup notification upstream.
22067c478bd9Sstevel@tonic-gate 				 */
22077c478bd9Sstevel@tonic-gate 				(void) zsmctl(zs, ZSWR5_DTR, DMBIC);
22087c478bd9Sstevel@tonic-gate 				if ((za->za_flags & ZAS_BUSY) &&
22097c478bd9Sstevel@tonic-gate 				    (zs->zs_wr_cur != NULL)) {
22107c478bd9Sstevel@tonic-gate 					zs->zs_wr_cur = NULL;
22117c478bd9Sstevel@tonic-gate 					zs->zs_wr_lim = NULL;
22127c478bd9Sstevel@tonic-gate 				}
22137c478bd9Sstevel@tonic-gate 				hangup = B_TRUE;
22147c478bd9Sstevel@tonic-gate 				wakeup = B_TRUE;
22157c478bd9Sstevel@tonic-gate 				za->za_flags &= ~(ZAS_STOPPED | ZAS_CARR_ON |
22167c478bd9Sstevel@tonic-gate 				    ZAS_BUSY);
22177c478bd9Sstevel@tonic-gate 				za->za_rcv_flags_mask &= ~(DO_TRANSMIT |
22187c478bd9Sstevel@tonic-gate 				    DO_RETRANSMIT);
22197c478bd9Sstevel@tonic-gate 			}
22207c478bd9Sstevel@tonic-gate 		}
22217c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
22227c478bd9Sstevel@tonic-gate 		if (hangup && (bp = za->za_xmitblk) != NULL) {
22237c478bd9Sstevel@tonic-gate 			za->za_xmitblk = NULL;
22247c478bd9Sstevel@tonic-gate 			freeb(bp);
22257c478bd9Sstevel@tonic-gate 		}
22267c478bd9Sstevel@tonic-gate 	}
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	if (za->za_break != 0) {
22297c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
22307c478bd9Sstevel@tonic-gate 		r0 = SCC_READ0();
22317c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
22327c478bd9Sstevel@tonic-gate 		if ((r0 & ZSRR0_BREAK) == 0) {
22337c478bd9Sstevel@tonic-gate 			za->za_break = 0;
22347c478bd9Sstevel@tonic-gate 			m_break = B_TRUE;
22357c478bd9Sstevel@tonic-gate 		}
22367c478bd9Sstevel@tonic-gate 	}
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	/*
22397c478bd9Sstevel@tonic-gate 	 * If a transmission has finished, indicate that it's
22407c478bd9Sstevel@tonic-gate 	 * finished, and start that line up again.
22417c478bd9Sstevel@tonic-gate 	 */
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
22447c478bd9Sstevel@tonic-gate 	if (za->za_rcv_flags_mask & DO_TRANSMIT) {
22457c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_TRANSMIT;
22467c478bd9Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BUSY;
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 		if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
22497c478bd9Sstevel@tonic-gate 		    (za->za_rcv_flags_mask & DO_RETRANSMIT) &&
22507c478bd9Sstevel@tonic-gate 		    zs->zs_wr_cur)
22517c478bd9Sstevel@tonic-gate 			bp = NULL;
22527c478bd9Sstevel@tonic-gate 		else {
22537c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
22547c478bd9Sstevel@tonic-gate 			bp = za->za_xmitblk;
22557c478bd9Sstevel@tonic-gate 			za->za_xmitblk = 0;
22567c478bd9Sstevel@tonic-gate 		}
22577c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
22587c478bd9Sstevel@tonic-gate 		if (bp)
22597c478bd9Sstevel@tonic-gate 			freemsg(bp);
22607c478bd9Sstevel@tonic-gate 		zsa_start(zs);
22617c478bd9Sstevel@tonic-gate 		/* if we didn't start anything, then notify waiters */
22627c478bd9Sstevel@tonic-gate 		if (!(za->za_flags & ZAS_BUSY))
22637c478bd9Sstevel@tonic-gate 			wakeup = B_TRUE;
22647c478bd9Sstevel@tonic-gate 	} else {
22657c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
22667c478bd9Sstevel@tonic-gate 	}
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	/*
22707c478bd9Sstevel@tonic-gate 	 * A note about these overrun bits: all they do is *tell* someone
22717c478bd9Sstevel@tonic-gate 	 * about an error- They do not track multiple errors. In fact,
22727c478bd9Sstevel@tonic-gate 	 * you could consider them latched register bits if you like.
22737c478bd9Sstevel@tonic-gate 	 * We are only interested in printing the error message once for
22747c478bd9Sstevel@tonic-gate 	 * any cluster of overrun errrors.
22757c478bd9Sstevel@tonic-gate 	 */
22767c478bd9Sstevel@tonic-gate 	if ((!za->za_kick_rcv_id) && (zs->zs_rd_cur || za_kick_active)) {
22777c478bd9Sstevel@tonic-gate 		if (g_zsticks)
2278*d3d50737SRafael Vanoni 			za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs,
2279*d3d50737SRafael Vanoni 			    g_zsticks);
22807c478bd9Sstevel@tonic-gate 		else
22817c478bd9Sstevel@tonic-gate 			za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs,
22827c478bd9Sstevel@tonic-gate 			    zsticks[SPEED(za->za_ttycommon.t_cflag)]);
22837c478bd9Sstevel@tonic-gate 		za->za_kick_rcv_count = ZA_KICK_RCV_COUNT;
22847c478bd9Sstevel@tonic-gate 	}
22857c478bd9Sstevel@tonic-gate 	za->za_soft_active = 1;
22867c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	if (!hangup && do_ttycommon_qfull) {
22897c478bd9Sstevel@tonic-gate 		ttycommon_qfull(&za->za_ttycommon, q);
22907c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
22917c478bd9Sstevel@tonic-gate 		zsa_start(zs);
22927c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
22937c478bd9Sstevel@tonic-gate 	}
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	if (za->za_hw_overrun > 10) {
22967c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zs%d: silo overflow\n", UNIT(za->za_dev));
22977c478bd9Sstevel@tonic-gate 		za->za_hw_overrun = 0;
22987c478bd9Sstevel@tonic-gate 	}
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	if (za->za_sw_overrun > 10) {
23017c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zs%d:ring buffer overflow\n",
23027c478bd9Sstevel@tonic-gate 		    UNIT(za->za_dev));
23037c478bd9Sstevel@tonic-gate 		za->za_sw_overrun = 0;
23047c478bd9Sstevel@tonic-gate 	}
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate 	if (unhangup)
23077c478bd9Sstevel@tonic-gate 		(void) putnextctl(q, M_UNHANGUP);
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	if (m_break)
23107c478bd9Sstevel@tonic-gate 		(void) putnextctl(q, M_BREAK);
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate 	while (head) {
23137c478bd9Sstevel@tonic-gate 		if (!tail) {
23147c478bd9Sstevel@tonic-gate 			putnext(q, head);
23157c478bd9Sstevel@tonic-gate 			break;
23167c478bd9Sstevel@tonic-gate 		}
23177c478bd9Sstevel@tonic-gate 		bp = head;
23187c478bd9Sstevel@tonic-gate 		head = head->b_next;
23197c478bd9Sstevel@tonic-gate 		bp->b_next = NULL;
23207c478bd9Sstevel@tonic-gate 		putnext(q, bp);
23217c478bd9Sstevel@tonic-gate 	}
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	if (hangup) {
23247c478bd9Sstevel@tonic-gate 		int flushflag;
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 		/*
23277c478bd9Sstevel@tonic-gate 		 * If we're in the midst of close, then flush everything.  Don't
23287c478bd9Sstevel@tonic-gate 		 * leave stale ioctls lying about.
23297c478bd9Sstevel@tonic-gate 		 */
23307c478bd9Sstevel@tonic-gate 		flushflag = (zs->zs_flags & ZS_CLOSING) ? FLUSHALL : FLUSHDATA;
23317c478bd9Sstevel@tonic-gate 		flushq(za->za_ttycommon.t_writeq, flushflag);
23327c478bd9Sstevel@tonic-gate 		(void) putnextctl(q, M_HANGUP);
23337c478bd9Sstevel@tonic-gate 	}
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 	if (m_error)
23367c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_ERROR, m_error);
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	za->za_soft_active = 0;
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	if (wakeup || (zs->zs_flags & ZS_CLOSED))
23417c478bd9Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	return (0);
23447c478bd9Sstevel@tonic-gate }
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate /*
23477c478bd9Sstevel@tonic-gate  * Start output on a line, unless it's busy, frozen, or otherwise.
23487c478bd9Sstevel@tonic-gate  */
23497c478bd9Sstevel@tonic-gate static void
zsa_start(struct zscom * zs)23507c478bd9Sstevel@tonic-gate zsa_start(struct zscom *zs)
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
23537c478bd9Sstevel@tonic-gate 	register int cc;
23547c478bd9Sstevel@tonic-gate 	register queue_t *q;
23557c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
23567c478bd9Sstevel@tonic-gate 	uchar_t *rptr, *wptr;
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	/*
23597c478bd9Sstevel@tonic-gate 	 * If the chip is busy (i.e., we're waiting for a break timeout
23607c478bd9Sstevel@tonic-gate 	 * to expire, or for the current transmission to finish, or for
23617c478bd9Sstevel@tonic-gate 	 * output to finish draining from chip), don't grab anything new.
23627c478bd9Sstevel@tonic-gate 	 */
23637c478bd9Sstevel@tonic-gate 	if ((za->za_flags & (ZAS_BREAK|ZAS_BUSY|ZAS_DRAINING)) ||
23647c478bd9Sstevel@tonic-gate 	    zs->zs_suspended)
23657c478bd9Sstevel@tonic-gate 		return;
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS) {
23687c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
23697c478bd9Sstevel@tonic-gate 		if (za->za_rcv_flags_mask & DO_RETRANSMIT) {
23707c478bd9Sstevel@tonic-gate 			rptr = zs->zs_wr_cur;
23717c478bd9Sstevel@tonic-gate 			wptr = zs->zs_wr_lim;
23727c478bd9Sstevel@tonic-gate 			goto zsa_start_retransmit;
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 		}
23757c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
23767c478bd9Sstevel@tonic-gate 	}
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	/*
23797c478bd9Sstevel@tonic-gate 	 * If we have a flow-control character to transmit, do it now.
23807c478bd9Sstevel@tonic-gate 	 */
23817c478bd9Sstevel@tonic-gate 	if (za->za_flowc != '\0') {
23827c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
23837c478bd9Sstevel@tonic-gate 		if (za->za_ttycommon.t_cflag & CRTSCTS) {
23847c478bd9Sstevel@tonic-gate 			if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
23857c478bd9Sstevel@tonic-gate 			    (ZSRR0_CTS|ZSRR0_TX_READY)) {
23867c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
23877c478bd9Sstevel@tonic-gate 				return;
23887c478bd9Sstevel@tonic-gate 			}
23897c478bd9Sstevel@tonic-gate 		} else if (!(SCC_READ0() & ZSRR0_TX_READY)) {
23907c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
23917c478bd9Sstevel@tonic-gate 			return;
23927c478bd9Sstevel@tonic-gate 		}
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 		ZSDELAY();
23957c478bd9Sstevel@tonic-gate 		SCC_WRITEDATA(za->za_flowc);
23967c478bd9Sstevel@tonic-gate 		za->za_flowc = '\0';
23977c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
23987c478bd9Sstevel@tonic-gate 		return;
23997c478bd9Sstevel@tonic-gate 	}
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	/*
24027c478bd9Sstevel@tonic-gate 	 * If we're waiting for a delay timeout to expire, don't grab
24037c478bd9Sstevel@tonic-gate 	 * anything new.
24047c478bd9Sstevel@tonic-gate 	 */
24057c478bd9Sstevel@tonic-gate 	if (za->za_flags & ZAS_DELAY)
24067c478bd9Sstevel@tonic-gate 		return;
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) == NULL)
24097c478bd9Sstevel@tonic-gate 		return;	/* not attached to a stream */
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate zsa_start_again:
24127c478bd9Sstevel@tonic-gate 	for (;;) {
24137c478bd9Sstevel@tonic-gate 		if ((bp = getq(q)) == NULL)
24147c478bd9Sstevel@tonic-gate 			return;	/* no data to transmit */
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate 		/*
24177c478bd9Sstevel@tonic-gate 		 * We have a message block to work on.
24187c478bd9Sstevel@tonic-gate 		 * Check whether it's a break, a delay, or an ioctl (the latter
24197c478bd9Sstevel@tonic-gate 		 * occurs if the ioctl in question was waiting for the output
24207c478bd9Sstevel@tonic-gate 		 * to drain). If it's one of those, process it immediately.
24217c478bd9Sstevel@tonic-gate 		 */
24227c478bd9Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 		case M_BREAK:
24257c478bd9Sstevel@tonic-gate 			/*
24267c478bd9Sstevel@tonic-gate 			 * Set the break bit, and arrange for "zsa_restart"
24277c478bd9Sstevel@tonic-gate 			 * to be called in 1/4 second; it will turn the
24287c478bd9Sstevel@tonic-gate 			 * break bit off, and call "zsa_start" to grab
24297c478bd9Sstevel@tonic-gate 			 * the next message.
24307c478bd9Sstevel@tonic-gate 			 */
24317c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
24327c478bd9Sstevel@tonic-gate 			SCC_BIS(5, ZSWR5_BREAK);
24337c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
24347c478bd9Sstevel@tonic-gate 			if (!za->za_zsa_restart_id) {
24357c478bd9Sstevel@tonic-gate 				za->za_zsa_restart_id =
24367c478bd9Sstevel@tonic-gate 				    timeout(zsa_restart, zs, hz/4);
24377c478bd9Sstevel@tonic-gate 			}
24387c478bd9Sstevel@tonic-gate 			za->za_flags |= ZAS_BREAK;
24397c478bd9Sstevel@tonic-gate 			freemsg(bp);
24407c478bd9Sstevel@tonic-gate 			return;	/* wait for this to finish */
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 		case M_DELAY:
24437c478bd9Sstevel@tonic-gate 			/*
24447c478bd9Sstevel@tonic-gate 			 * Arrange for "zsa_restart" to be called when the
24457c478bd9Sstevel@tonic-gate 			 * delay expires; it will turn MTS_DELAY off,
24467c478bd9Sstevel@tonic-gate 			 * and call "zsa_start" to grab the next message.
24477c478bd9Sstevel@tonic-gate 			 */
24487c478bd9Sstevel@tonic-gate 			if (! za->za_zsa_restart_id) {
24497c478bd9Sstevel@tonic-gate 				za->za_zsa_restart_id = timeout(zsa_restart,
24507c478bd9Sstevel@tonic-gate 				    zs,
24517c478bd9Sstevel@tonic-gate 				    (int)(*(unsigned char *)bp->b_rptr + 6));
24527c478bd9Sstevel@tonic-gate 			}
24537c478bd9Sstevel@tonic-gate 			za->za_flags |= ZAS_DELAY;
24547c478bd9Sstevel@tonic-gate 			freemsg(bp);
24557c478bd9Sstevel@tonic-gate 			return;	/* wait for this to finish */
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 		case M_IOCTL:
24587c478bd9Sstevel@tonic-gate 			/*
24597c478bd9Sstevel@tonic-gate 			 * This ioctl was waiting for the output ahead of
24607c478bd9Sstevel@tonic-gate 			 * it to drain; obviously, it has. Do it, and
24617c478bd9Sstevel@tonic-gate 			 * then grab the next message after it.
24627c478bd9Sstevel@tonic-gate 			 */
24637c478bd9Sstevel@tonic-gate 			zsa_ioctl(za, q, bp);
24647c478bd9Sstevel@tonic-gate 			continue;
24657c478bd9Sstevel@tonic-gate 		default: /* M_DATA */
24667c478bd9Sstevel@tonic-gate 			goto zsa_start_transmit;
24677c478bd9Sstevel@tonic-gate 		}
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 	}
24707c478bd9Sstevel@tonic-gate zsa_start_transmit:
24717c478bd9Sstevel@tonic-gate 	/*
24727c478bd9Sstevel@tonic-gate 	 * We have data to transmit. If output is stopped, put
24737c478bd9Sstevel@tonic-gate 	 * it back and try again later.
24747c478bd9Sstevel@tonic-gate 	 */
24757c478bd9Sstevel@tonic-gate 	if (za->za_flags & ZAS_STOPPED) {
24767c478bd9Sstevel@tonic-gate 		(void) putbq(q, bp);
24777c478bd9Sstevel@tonic-gate 		return;
24787c478bd9Sstevel@tonic-gate 	}
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	za->za_xmitblk = bp;
24817c478bd9Sstevel@tonic-gate 	rptr = bp->b_rptr;
24827c478bd9Sstevel@tonic-gate 	wptr = bp->b_wptr;
24837c478bd9Sstevel@tonic-gate 	cc = wptr - rptr;
24847c478bd9Sstevel@tonic-gate 	bp = bp->b_cont;
24857c478bd9Sstevel@tonic-gate 	if (bp != NULL) {
24867c478bd9Sstevel@tonic-gate 		za->za_xmitblk->b_cont = NULL;
24877c478bd9Sstevel@tonic-gate 		(void) putbq(q, bp);	/* not done with this message yet */
24887c478bd9Sstevel@tonic-gate 	}
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	if (rptr >= wptr) {
24917c478bd9Sstevel@tonic-gate 		freeb(za->za_xmitblk);
24927c478bd9Sstevel@tonic-gate 		za->za_xmitblk = NULL;
24937c478bd9Sstevel@tonic-gate 		goto zsa_start_again;
24947c478bd9Sstevel@tonic-gate 	}
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	/*
24977c478bd9Sstevel@tonic-gate 	 * In 5-bit mode, the high order bits are used
24987c478bd9Sstevel@tonic-gate 	 * to indicate character sizes less than five,
24997c478bd9Sstevel@tonic-gate 	 * so we need to explicitly mask before transmitting
25007c478bd9Sstevel@tonic-gate 	 */
25017c478bd9Sstevel@tonic-gate 	if ((za->za_ttycommon.t_cflag & CSIZE) == CS5) {
25027c478bd9Sstevel@tonic-gate 		register unsigned char *p = rptr;
25037c478bd9Sstevel@tonic-gate 		register int cnt = cc;
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 		while (cnt--)
25067c478bd9Sstevel@tonic-gate 			*p++ &= (unsigned char) 0x1f;
25077c478bd9Sstevel@tonic-gate 	}
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 	/*
25107c478bd9Sstevel@tonic-gate 	 * Set up this block for pseudo-DMA.
25117c478bd9Sstevel@tonic-gate 	 */
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
25147c478bd9Sstevel@tonic-gate 	zs->zs_wr_cur = rptr;
25157c478bd9Sstevel@tonic-gate 	zs->zs_wr_lim = wptr;
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate zsa_start_retransmit:
25187c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~DO_TRANSMIT;
25197c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS) {
25207c478bd9Sstevel@tonic-gate 		if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
25217c478bd9Sstevel@tonic-gate 		    (ZSRR0_CTS|ZSRR0_TX_READY)) {
25227c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_RETRANSMIT;
25237c478bd9Sstevel@tonic-gate 			za->za_flags |= ZAS_BUSY;
25247c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
25257c478bd9Sstevel@tonic-gate 			return;
25267c478bd9Sstevel@tonic-gate 		}
25277c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
2528*d3d50737SRafael Vanoni 	} else {
2529*d3d50737SRafael Vanoni 		if (!(SCC_READ0() & ZSRR0_TX_READY)) {
25307c478bd9Sstevel@tonic-gate 			za->za_flags |= ZAS_BUSY;
25317c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
25327c478bd9Sstevel@tonic-gate 			return;
25337c478bd9Sstevel@tonic-gate 		}
2534*d3d50737SRafael Vanoni 	}
25357c478bd9Sstevel@tonic-gate 	/*
25367c478bd9Sstevel@tonic-gate 	 * If the transmitter is ready, shove the first
25377c478bd9Sstevel@tonic-gate 	 * character out.
25387c478bd9Sstevel@tonic-gate 	 */
25397c478bd9Sstevel@tonic-gate 	ZSDELAY();
25407c478bd9Sstevel@tonic-gate 	SCC_WRITEDATA(*rptr++);
25417c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
25427c478bd9Sstevel@tonic-gate 	za->za_wr++;
25437c478bd9Sstevel@tonic-gate #endif
25447c478bd9Sstevel@tonic-gate 	zs->zs_wr_cur = rptr;
25457c478bd9Sstevel@tonic-gate 	za->za_flags |= ZAS_BUSY;
25467c478bd9Sstevel@tonic-gate 	zs->zs_flags |= ZS_PROGRESS;
25477c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
25487c478bd9Sstevel@tonic-gate }
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate /*
25517c478bd9Sstevel@tonic-gate  * Restart output on a line after a delay or break timer expired.
25527c478bd9Sstevel@tonic-gate  */
25537c478bd9Sstevel@tonic-gate static void
zsa_restart(void * arg)25547c478bd9Sstevel@tonic-gate zsa_restart(void *arg)
25557c478bd9Sstevel@tonic-gate {
25567c478bd9Sstevel@tonic-gate 	struct zscom *zs = arg;
25577c478bd9Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	/*
25607c478bd9Sstevel@tonic-gate 	 * If break timer expired, turn off the break bit.
25617c478bd9Sstevel@tonic-gate 	 */
25627c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
25637c478bd9Sstevel@tonic-gate 	if (!za->za_zsa_restart_id) {
25647c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
25657c478bd9Sstevel@tonic-gate 		return;
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 	za->za_zsa_restart_id = 0;
25687c478bd9Sstevel@tonic-gate 	if (za->za_flags & ZAS_BREAK) {
25697c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
25707c478bd9Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
25717c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
25727c478bd9Sstevel@tonic-gate 	}
25737c478bd9Sstevel@tonic-gate 	za->za_flags &= ~(ZAS_DELAY|ZAS_BREAK);
25747c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_writeq != NULL)
25757c478bd9Sstevel@tonic-gate 		zsa_start(zs);
25767c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
25777c478bd9Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate /*
25817c478bd9Sstevel@tonic-gate  * See if the receiver has any data after zs_tick delay
25827c478bd9Sstevel@tonic-gate  */
25837c478bd9Sstevel@tonic-gate static void
zsa_kick_rcv(void * arg)25847c478bd9Sstevel@tonic-gate zsa_kick_rcv(void *arg)
25857c478bd9Sstevel@tonic-gate {
25867c478bd9Sstevel@tonic-gate 	struct zscom *zs = arg;
25877c478bd9Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
25887c478bd9Sstevel@tonic-gate 	queue_t *q;
25897c478bd9Sstevel@tonic-gate 	int	tmp;
25907c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
25917c478bd9Sstevel@tonic-gate 	uchar_t za_soft_active, za_kick_active;
25927c478bd9Sstevel@tonic-gate 	int	allocbcount = 0;
25937c478bd9Sstevel@tonic-gate 	int do_ttycommon_qfull = 0;
25947c478bd9Sstevel@tonic-gate 	mblk_t *head = NULL, *tail = NULL;
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
25977c478bd9Sstevel@tonic-gate 	if (za->za_kick_rcv_id == 0 || (zs->zs_flags & ZS_CLOSED)) {
25987c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
25997c478bd9Sstevel@tonic-gate 		return;
26007c478bd9Sstevel@tonic-gate 	}
26017c478bd9Sstevel@tonic-gate 	za_soft_active = za->za_soft_active;
26027c478bd9Sstevel@tonic-gate 	za_kick_active = za->za_kick_active;
26037c478bd9Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
26047c478bd9Sstevel@tonic-gate 	if (!q) {
26057c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
26067c478bd9Sstevel@tonic-gate 		return;
26077c478bd9Sstevel@tonic-gate 	}
26087c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
26097c478bd9Sstevel@tonic-gate 	if (zs->zs_rd_cur) {
26107c478bd9Sstevel@tonic-gate 		ZSA_KICK_RCV;
26117c478bd9Sstevel@tonic-gate 		za->za_kick_rcv_count = tmp = ZA_KICK_RCV_COUNT;
26127c478bd9Sstevel@tonic-gate 	} else
26137c478bd9Sstevel@tonic-gate 		tmp = --za->za_kick_rcv_count;
26147c478bd9Sstevel@tonic-gate 	if (tmp > 0 || za_soft_active || za_kick_active) {
26157c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
26167c478bd9Sstevel@tonic-gate 		if (g_zsticks)
26177c478bd9Sstevel@tonic-gate 			za->za_kick_rcv_id = timeout(zsa_kick_rcv,
26187c478bd9Sstevel@tonic-gate 			    zs, g_zsticks);
26197c478bd9Sstevel@tonic-gate 		else
26207c478bd9Sstevel@tonic-gate 			za->za_kick_rcv_id = timeout(zsa_kick_rcv,
26217c478bd9Sstevel@tonic-gate 			    zs, zsticks[SPEED(za->za_ttycommon.t_cflag)]);
26227c478bd9Sstevel@tonic-gate 		if (za_soft_active || za_kick_active) {
26237c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
26247c478bd9Sstevel@tonic-gate 			return;
26257c478bd9Sstevel@tonic-gate 		}
26267c478bd9Sstevel@tonic-gate 	} else {
26277c478bd9Sstevel@tonic-gate 		za->za_kick_rcv_id = 0;
26287c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
26297c478bd9Sstevel@tonic-gate 	}
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	for (;;) {
26337c478bd9Sstevel@tonic-gate 		ZSA_SEEQ(mp);
26347c478bd9Sstevel@tonic-gate 		if (!mp)
26357c478bd9Sstevel@tonic-gate 			break;
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 		allocbcount++;
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type <= QPCTL) {
26407c478bd9Sstevel@tonic-gate 			if (!(canputnext(q))) {
26417c478bd9Sstevel@tonic-gate 				if (za->za_grace_flow_control >=
26427c478bd9Sstevel@tonic-gate 				    zsa_grace_flow_control) {
2643*d3d50737SRafael Vanoni 					if (za->za_ttycommon.t_cflag &
2644*d3d50737SRafael Vanoni 					    CRTSXOFF) {
26457c478bd9Sstevel@tonic-gate 						allocbcount--;
26467c478bd9Sstevel@tonic-gate 						break;
26477c478bd9Sstevel@tonic-gate 					}
26487c478bd9Sstevel@tonic-gate 					ZSA_GETQ(mp);
26497c478bd9Sstevel@tonic-gate 					freemsg(mp);
26507c478bd9Sstevel@tonic-gate 					do_ttycommon_qfull = 1;
26517c478bd9Sstevel@tonic-gate 					continue;
26527c478bd9Sstevel@tonic-gate 				} else
26537c478bd9Sstevel@tonic-gate 					za->za_grace_flow_control++;
26547c478bd9Sstevel@tonic-gate 			} else
26557c478bd9Sstevel@tonic-gate 				za->za_grace_flow_control = 0;
26567c478bd9Sstevel@tonic-gate 		}
26577c478bd9Sstevel@tonic-gate 		ZSA_GETQ(mp);
26587c478bd9Sstevel@tonic-gate 		if (!head) {
26597c478bd9Sstevel@tonic-gate 			head = mp;
26607c478bd9Sstevel@tonic-gate 		} else {
26617c478bd9Sstevel@tonic-gate 			if (!tail)
26627c478bd9Sstevel@tonic-gate 				tail = head;
26637c478bd9Sstevel@tonic-gate 			tail->b_next = mp;
26647c478bd9Sstevel@tonic-gate 			tail = mp;
26657c478bd9Sstevel@tonic-gate 		}
26667c478bd9Sstevel@tonic-gate 	}
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	if (allocbcount)
26697c478bd9Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	za->za_kick_active = 1;
26727c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	if (do_ttycommon_qfull) {
26757c478bd9Sstevel@tonic-gate 		ttycommon_qfull(&za->za_ttycommon, q);
26767c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
26777c478bd9Sstevel@tonic-gate 		zsa_start(zs);
26787c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	while (head) {
26827c478bd9Sstevel@tonic-gate 		if (!tail) {
26837c478bd9Sstevel@tonic-gate 			putnext(q, head);
26847c478bd9Sstevel@tonic-gate 			break;
26857c478bd9Sstevel@tonic-gate 		}
26867c478bd9Sstevel@tonic-gate 		mp = head;
26877c478bd9Sstevel@tonic-gate 		head = head->b_next;
26887c478bd9Sstevel@tonic-gate 		mp->b_next = NULL;
26897c478bd9Sstevel@tonic-gate 		putnext(q, mp);
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 	}
26927c478bd9Sstevel@tonic-gate 	za->za_kick_active = 0;
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	if (zs->zs_flags & ZS_CLOSED)
26957c478bd9Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate /*
26997c478bd9Sstevel@tonic-gate  * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
27007c478bd9Sstevel@tonic-gate  * the buffer we need.
27017c478bd9Sstevel@tonic-gate  */
27027c478bd9Sstevel@tonic-gate static void
zsa_reioctl(void * arg)27037c478bd9Sstevel@tonic-gate zsa_reioctl(void *arg)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate 	struct asyncline *za = arg;
27067c478bd9Sstevel@tonic-gate 	struct zscom *zs = za->za_common;
27077c478bd9Sstevel@tonic-gate 	queue_t *q;
27087c478bd9Sstevel@tonic-gate 	mblk_t	 *mp;
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	/*
27117c478bd9Sstevel@tonic-gate 	 * The bufcall is no longer pending.
27127c478bd9Sstevel@tonic-gate 	 */
27137c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
27147c478bd9Sstevel@tonic-gate 	if (!za->za_wbufcid) {
27157c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
27167c478bd9Sstevel@tonic-gate 		return;
27177c478bd9Sstevel@tonic-gate 	}
27187c478bd9Sstevel@tonic-gate 	za->za_wbufcid = 0;
27197c478bd9Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) == NULL) {
27207c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
27217c478bd9Sstevel@tonic-gate 		return;
27227c478bd9Sstevel@tonic-gate 	}
27237c478bd9Sstevel@tonic-gate 	if ((mp = za->za_ttycommon.t_iocpending) != NULL) {
27247c478bd9Sstevel@tonic-gate 		/*
27257c478bd9Sstevel@tonic-gate 		 * not pending any more
27267c478bd9Sstevel@tonic-gate 		 */
27277c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
27287c478bd9Sstevel@tonic-gate 		zsa_ioctl(za, q, mp);
27297c478bd9Sstevel@tonic-gate 	}
27307c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
27317c478bd9Sstevel@tonic-gate }
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate /*
27347c478bd9Sstevel@tonic-gate  * Process an "ioctl" message sent down to us.
27357c478bd9Sstevel@tonic-gate  * Note that we don't need to get any locks until we are ready to access
27367c478bd9Sstevel@tonic-gate  * the hardware. Nothing we access until then is going to be altered
27377c478bd9Sstevel@tonic-gate  * outside of the STREAMS framework, so we should be safe.
27387c478bd9Sstevel@tonic-gate  */
27397c478bd9Sstevel@tonic-gate static void
zsa_ioctl(struct asyncline * za,queue_t * wq,mblk_t * mp)27407c478bd9Sstevel@tonic-gate zsa_ioctl(struct asyncline *za, queue_t *wq, mblk_t *mp)
27417c478bd9Sstevel@tonic-gate {
27427c478bd9Sstevel@tonic-gate 	register struct zscom *zs = za->za_common;
27437c478bd9Sstevel@tonic-gate 	register struct iocblk *iocp;
27447c478bd9Sstevel@tonic-gate 	register unsigned datasize;
27457c478bd9Sstevel@tonic-gate 	int error;
27467c478bd9Sstevel@tonic-gate 	register mblk_t *tmp;
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iocpending != NULL) {
27497c478bd9Sstevel@tonic-gate 		/*
27507c478bd9Sstevel@tonic-gate 		 * We were holding an "ioctl" response pending the
27517c478bd9Sstevel@tonic-gate 		 * availability of an "mblk" to hold data to be passed up;
27527c478bd9Sstevel@tonic-gate 		 * another "ioctl" came through, which means that "ioctl"
27537c478bd9Sstevel@tonic-gate 		 * must have timed out or been aborted.
27547c478bd9Sstevel@tonic-gate 		 */
27557c478bd9Sstevel@tonic-gate 		freemsg(za->za_ttycommon.t_iocpending);
27567c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
27577c478bd9Sstevel@tonic-gate 	}
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	/*
27627c478bd9Sstevel@tonic-gate 	 * The only way in which "ttycommon_ioctl" can fail is if the "ioctl"
27637c478bd9Sstevel@tonic-gate 	 * requires a response containing data to be returned to the user,
27647c478bd9Sstevel@tonic-gate 	 * and no mblk could be allocated for the data.
27657c478bd9Sstevel@tonic-gate 	 * No such "ioctl" alters our state. Thus, we always go ahead and
27667c478bd9Sstevel@tonic-gate 	 * do any state-changes the "ioctl" calls for. If we couldn't allocate
27677c478bd9Sstevel@tonic-gate 	 * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so
27687c478bd9Sstevel@tonic-gate 	 * we just call "bufcall" to request that we be called back when we
27697c478bd9Sstevel@tonic-gate 	 * stand a better chance of allocating the data.
27707c478bd9Sstevel@tonic-gate 	 */
27717c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
27727c478bd9Sstevel@tonic-gate 	datasize = ttycommon_ioctl(&za->za_ttycommon, wq, mp, &error);
27737c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
27747c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_SOFTCAR)
27757c478bd9Sstevel@tonic-gate 		zssoftCAR[zs->zs_unit] = 1;
27767c478bd9Sstevel@tonic-gate 	else
27777c478bd9Sstevel@tonic-gate 		zssoftCAR[zs->zs_unit] = 0;
27787c478bd9Sstevel@tonic-gate 	if (datasize != 0) {
27797c478bd9Sstevel@tonic-gate 		if (za->za_wbufcid)
27807c478bd9Sstevel@tonic-gate 			unbufcall(za->za_wbufcid);
27817c478bd9Sstevel@tonic-gate 		za->za_wbufcid = bufcall(datasize, BPRI_HI, zsa_reioctl, za);
27827c478bd9Sstevel@tonic-gate 		return;
27837c478bd9Sstevel@tonic-gate 	}
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 	if (error == 0) {
27877c478bd9Sstevel@tonic-gate 		/*
27887c478bd9Sstevel@tonic-gate 		 * "ttycommon_ioctl" did most of the work; we just use the
27897c478bd9Sstevel@tonic-gate 		 * data it set up.
27907c478bd9Sstevel@tonic-gate 		 */
27917c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate 		case TCSETS:
27947c478bd9Sstevel@tonic-gate 		case TCSETSW:
27957c478bd9Sstevel@tonic-gate 		case TCSETSF:
27967c478bd9Sstevel@tonic-gate 		case TCSETA:
27977c478bd9Sstevel@tonic-gate 		case TCSETAW:
27987c478bd9Sstevel@tonic-gate 		case TCSETAF:
27997c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
28007c478bd9Sstevel@tonic-gate 			zsa_program(za, 1);
28017c478bd9Sstevel@tonic-gate 			zsa_set_za_rcv_flags_mask(za);
28027c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
28037c478bd9Sstevel@tonic-gate 			break;
28047c478bd9Sstevel@tonic-gate 		}
28057c478bd9Sstevel@tonic-gate 	} else if (error < 0) {
28067c478bd9Sstevel@tonic-gate 		/*
28077c478bd9Sstevel@tonic-gate 		 * "ttycommon_ioctl" didn't do anything; we process it here.
28087c478bd9Sstevel@tonic-gate 		 */
28097c478bd9Sstevel@tonic-gate 		error = 0;
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 		case TCSBRK:
28147c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
28157c478bd9Sstevel@tonic-gate 			if (error != 0)
28167c478bd9Sstevel@tonic-gate 				break;
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate 			if (*(int *)mp->b_cont->b_rptr == 0) {
28197c478bd9Sstevel@tonic-gate 				/*
28207c478bd9Sstevel@tonic-gate 				 * The delay ensures that a 3 byte transmit
28217c478bd9Sstevel@tonic-gate 				 * fifo is empty.
28227c478bd9Sstevel@tonic-gate 				 */
28237c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
28247c478bd9Sstevel@tonic-gate 				delay(ztdelay(SPEED(za->za_ttycommon.t_cflag)));
28257c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl);
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate 				/*
28287c478bd9Sstevel@tonic-gate 				 * Set the break bit, and arrange for
28297c478bd9Sstevel@tonic-gate 				 * "zsa_restart" to be called in 1/4 second;
28307c478bd9Sstevel@tonic-gate 				 * it will turn the break bit off, and call
28317c478bd9Sstevel@tonic-gate 				 * "zsa_start" to grab the next message.
28327c478bd9Sstevel@tonic-gate 				 */
28337c478bd9Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
28347c478bd9Sstevel@tonic-gate 				SCC_BIS(5, ZSWR5_BREAK);
28357c478bd9Sstevel@tonic-gate 				if (!za->za_zsa_restart_id) {
28367c478bd9Sstevel@tonic-gate 					mutex_exit(zs->zs_excl_hi);
28377c478bd9Sstevel@tonic-gate 					za->za_zsa_restart_id =
28387c478bd9Sstevel@tonic-gate 					    timeout(zsa_restart, zs, hz / 4);
28397c478bd9Sstevel@tonic-gate 					mutex_enter(zs->zs_excl_hi);
28407c478bd9Sstevel@tonic-gate 				}
28417c478bd9Sstevel@tonic-gate 				za->za_flags |= ZAS_BREAK;
28427c478bd9Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
28437c478bd9Sstevel@tonic-gate 			}
28447c478bd9Sstevel@tonic-gate 			break;
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 		case TIOCSBRK:
28477c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
28487c478bd9Sstevel@tonic-gate 			SCC_BIS(5, ZSWR5_BREAK);
28497c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
28507c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
28517c478bd9Sstevel@tonic-gate 			break;
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 		case TIOCCBRK:
28547c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
28557c478bd9Sstevel@tonic-gate 			SCC_BIC(5, ZSWR5_BREAK);
28567c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
28577c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
28587c478bd9Sstevel@tonic-gate 			break;
28597c478bd9Sstevel@tonic-gate 
28607c478bd9Sstevel@tonic-gate 		case TIOCMSET:
28617c478bd9Sstevel@tonic-gate 		case TIOCMBIS:
28627c478bd9Sstevel@tonic-gate 		case TIOCMBIC: {
28637c478bd9Sstevel@tonic-gate 			int mlines;
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 			if (iocp->ioc_count == TRANSPARENT) {
28667c478bd9Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (int), NULL);
28677c478bd9Sstevel@tonic-gate 				break;
28687c478bd9Sstevel@tonic-gate 			}
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
28717c478bd9Sstevel@tonic-gate 			if (error != 0)
28727c478bd9Sstevel@tonic-gate 				break;
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 			mlines = *(int *)mp->b_cont->b_rptr;
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
28777c478bd9Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
28787c478bd9Sstevel@tonic-gate 			case TIOCMSET:
28797c478bd9Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMSET);
28807c478bd9Sstevel@tonic-gate 				break;
28817c478bd9Sstevel@tonic-gate 			case TIOCMBIS:
28827c478bd9Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMBIS);
28837c478bd9Sstevel@tonic-gate 				break;
28847c478bd9Sstevel@tonic-gate 			case TIOCMBIC:
28857c478bd9Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMBIC);
28867c478bd9Sstevel@tonic-gate 				break;
28877c478bd9Sstevel@tonic-gate 			}
28887c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
28917c478bd9Sstevel@tonic-gate 			break;
28927c478bd9Sstevel@tonic-gate 		}
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 		case TIOCMGET:
28957c478bd9Sstevel@tonic-gate 			tmp = allocb(sizeof (int), BPRI_MED);
28967c478bd9Sstevel@tonic-gate 			if (tmp == NULL) {
28977c478bd9Sstevel@tonic-gate 				error = EAGAIN;
28987c478bd9Sstevel@tonic-gate 				break;
28997c478bd9Sstevel@tonic-gate 			}
29007c478bd9Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT)
29017c478bd9Sstevel@tonic-gate 				mioc2ack(mp, tmp, sizeof (int), 0);
29027c478bd9Sstevel@tonic-gate 			else
29037c478bd9Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (int), NULL, tmp);
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
29067c478bd9Sstevel@tonic-gate 			*(int *)mp->b_cont->b_rptr =
29077c478bd9Sstevel@tonic-gate 			    zstodm(zsmctl(zs, 0, DMGET));
29087c478bd9Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
29097c478bd9Sstevel@tonic-gate 			/*
29107c478bd9Sstevel@tonic-gate 			 * qreply done below
29117c478bd9Sstevel@tonic-gate 			 */
29127c478bd9Sstevel@tonic-gate 			break;
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 		default:
29157c478bd9Sstevel@tonic-gate 			/*
29167c478bd9Sstevel@tonic-gate 			 * If we don't understand it, it's an error. NAK it.
29177c478bd9Sstevel@tonic-gate 			 */
29187c478bd9Sstevel@tonic-gate 			error = EINVAL;
29197c478bd9Sstevel@tonic-gate 			break;
29207c478bd9Sstevel@tonic-gate 		}
29217c478bd9Sstevel@tonic-gate 	}
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 	if (error != 0) {
29247c478bd9Sstevel@tonic-gate 		iocp->ioc_error = error;
29257c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
29267c478bd9Sstevel@tonic-gate 	}
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 	ZSA_QREPLY(wq, mp);
29297c478bd9Sstevel@tonic-gate }
29307c478bd9Sstevel@tonic-gate 
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate static int
dmtozs(int bits)29337c478bd9Sstevel@tonic-gate dmtozs(int bits)
29347c478bd9Sstevel@tonic-gate {
29357c478bd9Sstevel@tonic-gate 	register int b = 0;
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate 	if (bits & TIOCM_CAR)
29387c478bd9Sstevel@tonic-gate 		b |= ZSRR0_CD;
29397c478bd9Sstevel@tonic-gate 	if (bits & TIOCM_CTS)
29407c478bd9Sstevel@tonic-gate 		b |= ZSRR0_CTS;
29417c478bd9Sstevel@tonic-gate 	if (bits & TIOCM_RTS)
29427c478bd9Sstevel@tonic-gate 		b |= ZSWR5_RTS;
29437c478bd9Sstevel@tonic-gate 	if (bits & TIOCM_DTR)
29447c478bd9Sstevel@tonic-gate 		b |= ZSWR5_DTR;
29457c478bd9Sstevel@tonic-gate 	return (b);
29467c478bd9Sstevel@tonic-gate }
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate static int
zstodm(int bits)29497c478bd9Sstevel@tonic-gate zstodm(int bits)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate 	register int b;
29527c478bd9Sstevel@tonic-gate 
29537c478bd9Sstevel@tonic-gate 	b = 0;
29547c478bd9Sstevel@tonic-gate 	if (bits & ZSRR0_CD)
29557c478bd9Sstevel@tonic-gate 		b |= TIOCM_CAR;
29567c478bd9Sstevel@tonic-gate 	if (bits & ZSRR0_CTS)
29577c478bd9Sstevel@tonic-gate 		b |= TIOCM_CTS;
29587c478bd9Sstevel@tonic-gate 	if (bits & ZSWR5_RTS)
29597c478bd9Sstevel@tonic-gate 		b |= TIOCM_RTS;
29607c478bd9Sstevel@tonic-gate 	if (bits & ZSWR5_DTR)
29617c478bd9Sstevel@tonic-gate 		b |= TIOCM_DTR;
29627c478bd9Sstevel@tonic-gate 	return (b);
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate /*
29667c478bd9Sstevel@tonic-gate  * Assemble registers and flags necessary to program the port to our liking.
29677c478bd9Sstevel@tonic-gate  * For async operation, most of this is based on the values of
29687c478bd9Sstevel@tonic-gate  * the "c_iflag" and "c_cflag" fields supplied to us.
29697c478bd9Sstevel@tonic-gate  */
29707c478bd9Sstevel@tonic-gate static void
zsa_program(struct asyncline * za,int setibaud)29717c478bd9Sstevel@tonic-gate zsa_program(struct asyncline *za, int setibaud)
29727c478bd9Sstevel@tonic-gate {
29737c478bd9Sstevel@tonic-gate 	register struct zscom *zs = za->za_common;
29747c478bd9Sstevel@tonic-gate 	register struct zs_prog *zspp;
29757c478bd9Sstevel@tonic-gate 	register int wr3, wr4, wr5, wr15, speed, baudrate, flags = 0;
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate 	if ((baudrate = SPEED(za->za_ttycommon.t_cflag)) == 0) {
29787c478bd9Sstevel@tonic-gate 		/*
29797c478bd9Sstevel@tonic-gate 		 * Hang up line.
29807c478bd9Sstevel@tonic-gate 		 */
29817c478bd9Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_OFF, DMSET);
29827c478bd9Sstevel@tonic-gate 		return;
29837c478bd9Sstevel@tonic-gate 	}
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate 	/*
29867c478bd9Sstevel@tonic-gate 	 * set input speed same as output, as split speed not supported
29877c478bd9Sstevel@tonic-gate 	 */
29887c478bd9Sstevel@tonic-gate 	if (setibaud) {
29897c478bd9Sstevel@tonic-gate 		za->za_ttycommon.t_cflag &= ~(CIBAUD);
29907c478bd9Sstevel@tonic-gate 		if (baudrate > CBAUD) {
29917c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |= CIBAUDEXT;
29927c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |=
29937c478bd9Sstevel@tonic-gate 			    (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
29947c478bd9Sstevel@tonic-gate 		} else {
29957c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag &= ~CIBAUDEXT;
29967c478bd9Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |=
29977c478bd9Sstevel@tonic-gate 			    ((baudrate << IBSHIFT) & CIBAUD);
29987c478bd9Sstevel@tonic-gate 		}
29997c478bd9Sstevel@tonic-gate 	}
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 	/*
30027c478bd9Sstevel@tonic-gate 	 * Do not allow the console/keyboard device to have its receiver
30037c478bd9Sstevel@tonic-gate 	 * disabled; doing that would mean you couldn't type an abort
30047c478bd9Sstevel@tonic-gate 	 * sequence.
30057c478bd9Sstevel@tonic-gate 	 */
30067c478bd9Sstevel@tonic-gate 	if ((za->za_dev == rconsdev) || (za->za_dev == kbddev) ||
30077c478bd9Sstevel@tonic-gate 	    (za->za_dev == stdindev) || (za->za_ttycommon.t_cflag & CREAD))
30087c478bd9Sstevel@tonic-gate 		wr3 = ZSWR3_RX_ENABLE;
30097c478bd9Sstevel@tonic-gate 	else
30107c478bd9Sstevel@tonic-gate 		wr3 = 0;
30117c478bd9Sstevel@tonic-gate 	wr4 = ZSWR4_X16_CLK;
30127c478bd9Sstevel@tonic-gate 	wr5 = (zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR)) | ZSWR5_TX_ENABLE;
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 	if (zsb134_weird && baudrate == B134) {	/* what a joke! */
30157c478bd9Sstevel@tonic-gate 		/*
30167c478bd9Sstevel@tonic-gate 		 * XXX - should B134 set all this crap in the compatibility
30177c478bd9Sstevel@tonic-gate 		 * module, leaving this stuff fairly clean?
30187c478bd9Sstevel@tonic-gate 		 */
30197c478bd9Sstevel@tonic-gate 		flags |= ZSP_PARITY_SPECIAL;
30207c478bd9Sstevel@tonic-gate 		wr3 |= ZSWR3_RX_6;
30217c478bd9Sstevel@tonic-gate 		wr4 |= ZSWR4_PARITY_ENABLE | ZSWR4_PARITY_EVEN;
30227c478bd9Sstevel@tonic-gate 		wr4 |= ZSWR4_1_5_STOP;
30237c478bd9Sstevel@tonic-gate 		wr5 |= ZSWR5_TX_6;
30247c478bd9Sstevel@tonic-gate 	} else {
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate 		switch (za->za_ttycommon.t_cflag & CSIZE) {
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 		case CS5:
30297c478bd9Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_5;
30307c478bd9Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_5;
30317c478bd9Sstevel@tonic-gate 			break;
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate 		case CS6:
30347c478bd9Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_6;
30357c478bd9Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_6;
30367c478bd9Sstevel@tonic-gate 			break;
30377c478bd9Sstevel@tonic-gate 
30387c478bd9Sstevel@tonic-gate 		case CS7:
30397c478bd9Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_7;
30407c478bd9Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_7;
30417c478bd9Sstevel@tonic-gate 			break;
30427c478bd9Sstevel@tonic-gate 
30437c478bd9Sstevel@tonic-gate 		case CS8:
30447c478bd9Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_8;
30457c478bd9Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_8;
30467c478bd9Sstevel@tonic-gate 			break;
30477c478bd9Sstevel@tonic-gate 		}
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate 		if (za->za_ttycommon.t_cflag & PARENB) {
30507c478bd9Sstevel@tonic-gate 			/*
30517c478bd9Sstevel@tonic-gate 			 * The PARITY_SPECIAL bit causes a special rx
30527c478bd9Sstevel@tonic-gate 			 * interrupt on parity errors. Turn it on if
30537c478bd9Sstevel@tonic-gate 			 * we're checking the parity of characters.
30547c478bd9Sstevel@tonic-gate 			 */
30557c478bd9Sstevel@tonic-gate 			if (za->za_ttycommon.t_iflag & INPCK)
30567c478bd9Sstevel@tonic-gate 				flags |= ZSP_PARITY_SPECIAL;
30577c478bd9Sstevel@tonic-gate 			wr4 |= ZSWR4_PARITY_ENABLE;
30587c478bd9Sstevel@tonic-gate 			if (!(za->za_ttycommon.t_cflag & PARODD))
30597c478bd9Sstevel@tonic-gate 				wr4 |= ZSWR4_PARITY_EVEN;
30607c478bd9Sstevel@tonic-gate 		}
30617c478bd9Sstevel@tonic-gate 		wr4 |= (za->za_ttycommon.t_cflag & CSTOPB) ?
30627c478bd9Sstevel@tonic-gate 		    ZSWR4_2_STOP : ZSWR4_1_STOP;
30637c478bd9Sstevel@tonic-gate 	}
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate #if 0
30667c478bd9Sstevel@tonic-gate 	/*
30677c478bd9Sstevel@tonic-gate 	 * The AUTO_CD_CTS flag enables the hardware flow control feature of
30687c478bd9Sstevel@tonic-gate 	 * the 8530, which allows the state of CTS and DCD to control the
30697c478bd9Sstevel@tonic-gate 	 * enabling of the transmitter and receiver, respectively. The
30707c478bd9Sstevel@tonic-gate 	 * receiver and transmitter still must have their enable bits set in
30717c478bd9Sstevel@tonic-gate 	 * WR3 and WR5, respectively, for CTS and DCD to be monitored this way.
30727c478bd9Sstevel@tonic-gate 	 * Hardware flow control can thus be implemented with no help from
30737c478bd9Sstevel@tonic-gate 	 * software.
30747c478bd9Sstevel@tonic-gate 	 */
30757c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS)
30767c478bd9Sstevel@tonic-gate 		wr3 |= ZSWR3_AUTO_CD_CTS;
30777c478bd9Sstevel@tonic-gate #endif
30787c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS)
30797c478bd9Sstevel@tonic-gate 		wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD | ZSR15_CTS;
30807c478bd9Sstevel@tonic-gate 	else
30817c478bd9Sstevel@tonic-gate 		wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD;
30827c478bd9Sstevel@tonic-gate 
30837c478bd9Sstevel@tonic-gate 	speed = zs->zs_wreg[12] + (zs->zs_wreg[13] << 8);
30847c478bd9Sstevel@tonic-gate 
30857c478bd9Sstevel@tonic-gate 	/*
30867c478bd9Sstevel@tonic-gate 	 * Here we assemble a set of changes to be passed to zs_program.
30877c478bd9Sstevel@tonic-gate 	 * Note: Write Register 15 must be set to enable BREAK and UNDERrun
30887c478bd9Sstevel@tonic-gate 	 * interrupts.  It must also enable CD interrupts which, although
30897c478bd9Sstevel@tonic-gate 	 * not processed by the hardware interrupt handler, will be processed
30907c478bd9Sstevel@tonic-gate 	 * by zsa_process, indirectly resulting in a SIGHUP being delivered
30917c478bd9Sstevel@tonic-gate 	 * to the controlling process if CD drops.  CTS interrupts must NOT
30927c478bd9Sstevel@tonic-gate 	 * be enabled.  We don't use them at all, and they will hang IPC/IPX
30937c478bd9Sstevel@tonic-gate 	 * systems at boot time if synchronous modems that supply transmit
30947c478bd9Sstevel@tonic-gate 	 * clock are attached to any of their serial ports.
30957c478bd9Sstevel@tonic-gate 	 */
30967c478bd9Sstevel@tonic-gate 	if (((zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
30977c478bd9Sstevel@tonic-gate 	    !(flags & ZSP_PARITY_SPECIAL)) ||
30987c478bd9Sstevel@tonic-gate 	    (!(zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
30997c478bd9Sstevel@tonic-gate 	    (flags & ZSP_PARITY_SPECIAL)) ||
31007c478bd9Sstevel@tonic-gate 	    wr3 != zs->zs_wreg[3] || wr4 != zs->zs_wreg[4] ||
31017c478bd9Sstevel@tonic-gate 	    wr5 != zs->zs_wreg[5] || wr15 != zs->zs_wreg[15] ||
31027c478bd9Sstevel@tonic-gate 	    speed != zs_speeds[baudrate]) {
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 		za->za_flags |= ZAS_DRAINING;
31057c478bd9Sstevel@tonic-gate 		zspp = &zs_prog[zs->zs_unit];
31067c478bd9Sstevel@tonic-gate 		zspp->zs = zs;
31077c478bd9Sstevel@tonic-gate 		zspp->flags = (uchar_t)flags;
31087c478bd9Sstevel@tonic-gate 		zspp->wr4 = (uchar_t)wr4;
31097c478bd9Sstevel@tonic-gate 		zspp->wr11 = (uchar_t)(ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD);
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 		speed = zs_speeds[baudrate];
31127c478bd9Sstevel@tonic-gate 		zspp->wr12 = (uchar_t)(speed & 0xff);
31137c478bd9Sstevel@tonic-gate 		zspp->wr13 = (uchar_t)((speed >> 8) & 0xff);
31147c478bd9Sstevel@tonic-gate 		zspp->wr3 = (uchar_t)wr3;
31157c478bd9Sstevel@tonic-gate 		zspp->wr5 = (uchar_t)wr5;
31167c478bd9Sstevel@tonic-gate 		zspp->wr15 = (uchar_t)wr15;
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 		zs_program(zspp);
31197c478bd9Sstevel@tonic-gate 		za->za_flags &= ~ZAS_DRAINING;
31207c478bd9Sstevel@tonic-gate 	}
31217c478bd9Sstevel@tonic-gate }
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate /*
31247c478bd9Sstevel@tonic-gate  * Get the current speed of the console and turn it into something
31257c478bd9Sstevel@tonic-gate  * UNIX knows about - used to preserve console speed when UNIX comes up.
31267c478bd9Sstevel@tonic-gate  */
31277c478bd9Sstevel@tonic-gate int
zsgetspeed(dev_t dev)31287c478bd9Sstevel@tonic-gate zsgetspeed(dev_t dev)
31297c478bd9Sstevel@tonic-gate {
31307c478bd9Sstevel@tonic-gate 	register struct zscom *zs;
31317c478bd9Sstevel@tonic-gate 	register int uspeed, zspeed;
31327c478bd9Sstevel@tonic-gate 	register uchar_t rr;
31337c478bd9Sstevel@tonic-gate 
31347c478bd9Sstevel@tonic-gate 	zs = &zscom[UNIT(dev)];
31357c478bd9Sstevel@tonic-gate 	SCC_READ(12, zspeed);
31367c478bd9Sstevel@tonic-gate 	SCC_READ(13, rr);
31377c478bd9Sstevel@tonic-gate 	zspeed |= rr << 8;
31387c478bd9Sstevel@tonic-gate 	for (uspeed = 0; uspeed < NSPEED; uspeed++)
31397c478bd9Sstevel@tonic-gate 		if (zs_speeds[uspeed] == zspeed)
31407c478bd9Sstevel@tonic-gate 			return (uspeed);
31417c478bd9Sstevel@tonic-gate 	/*
31427c478bd9Sstevel@tonic-gate 	 * 9600 baud if we can't figure it out
31437c478bd9Sstevel@tonic-gate 	 */
31447c478bd9Sstevel@tonic-gate 	return (ISPEED);
31457c478bd9Sstevel@tonic-gate }
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate /*
31487c478bd9Sstevel@tonic-gate  * callback routine when enough memory is available.
31497c478bd9Sstevel@tonic-gate  */
31507c478bd9Sstevel@tonic-gate static void
zsa_callback(void * arg)31517c478bd9Sstevel@tonic-gate zsa_callback(void *arg)
31527c478bd9Sstevel@tonic-gate {
31537c478bd9Sstevel@tonic-gate 	struct zscom *zs = arg;
31547c478bd9Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
31557c478bd9Sstevel@tonic-gate 	int allocbcount = zsa_rstandby;
31567c478bd9Sstevel@tonic-gate 
31577c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
31587c478bd9Sstevel@tonic-gate 	if (za->za_bufcid) {
31597c478bd9Sstevel@tonic-gate 		za->za_bufcid = 0;
31607c478bd9Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
31617c478bd9Sstevel@tonic-gate 	}
31627c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
31637c478bd9Sstevel@tonic-gate }
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate /*
31667c478bd9Sstevel@tonic-gate  * Set the receiver flags
31677c478bd9Sstevel@tonic-gate  */
31687c478bd9Sstevel@tonic-gate static void
zsa_set_za_rcv_flags_mask(struct asyncline * za)31697c478bd9Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(struct asyncline *za)
31707c478bd9Sstevel@tonic-gate {
31717c478bd9Sstevel@tonic-gate 	register uint_t mask;
31727c478bd9Sstevel@tonic-gate 
31737c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~0xFF;
31747c478bd9Sstevel@tonic-gate 	switch (za->za_ttycommon.t_cflag & CSIZE) {
31757c478bd9Sstevel@tonic-gate 	case CS5:
31767c478bd9Sstevel@tonic-gate 		mask = 0x1f;
31777c478bd9Sstevel@tonic-gate 		break;
31787c478bd9Sstevel@tonic-gate 	case CS6:
31797c478bd9Sstevel@tonic-gate 		mask = 0x3f;
31807c478bd9Sstevel@tonic-gate 		break;
31817c478bd9Sstevel@tonic-gate 	case CS7:
31827c478bd9Sstevel@tonic-gate 		mask = 0x7f;
31837c478bd9Sstevel@tonic-gate 		break;
31847c478bd9Sstevel@tonic-gate 	default:
31857c478bd9Sstevel@tonic-gate 		mask = 0xff;
31867c478bd9Sstevel@tonic-gate 	}
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~(0xFF << 16);
31897c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask |=  mask << 16;
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	if ((za->za_ttycommon.t_iflag & PARMRK) &&
31927c478bd9Sstevel@tonic-gate 	    !(za->za_ttycommon.t_iflag & (IGNPAR|ISTRIP))) {
31937c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask |= DO_ESC;
31947c478bd9Sstevel@tonic-gate 	} else
31957c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_ESC;
31967c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXON) {
31977c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask |= DO_STOPC;
31987c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~0xFF;
31997c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask |= za->za_ttycommon.t_stopc;
32007c478bd9Sstevel@tonic-gate 	} else
32017c478bd9Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_STOPC;
32027c478bd9Sstevel@tonic-gate }
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate static int
zsa_suspend(struct zscom * zs)32057c478bd9Sstevel@tonic-gate zsa_suspend(struct zscom *zs)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate 	struct asyncline	*za;
32087c478bd9Sstevel@tonic-gate 	queue_t			*q;
32097c478bd9Sstevel@tonic-gate 	mblk_t			*bp = NULL;
32107c478bd9Sstevel@tonic-gate 	timeout_id_t		restart_id, kick_rcv_id;
32117c478bd9Sstevel@tonic-gate 	struct zs_prog		*zspp;
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
32147c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
32157c478bd9Sstevel@tonic-gate 	if (zs->zs_suspended) {
32167c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
32177c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
32187c478bd9Sstevel@tonic-gate 	}
32197c478bd9Sstevel@tonic-gate 	zs->zs_suspended = 1;
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 	/*
32227c478bd9Sstevel@tonic-gate 	 * Turn off interrupts and get any bytes in receiver
32237c478bd9Sstevel@tonic-gate 	 */
32247c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
32257c478bd9Sstevel@tonic-gate 	SCC_BIC(1, ZSWR1_INIT);
32267c478bd9Sstevel@tonic-gate 	ZSA_KICK_RCV;
32277c478bd9Sstevel@tonic-gate 	restart_id = za->za_zsa_restart_id;
32287c478bd9Sstevel@tonic-gate 	za->za_zsa_restart_id = 0;
32297c478bd9Sstevel@tonic-gate 	kick_rcv_id = za->za_kick_rcv_id;
32307c478bd9Sstevel@tonic-gate 	za->za_kick_rcv_id = 0;
32317c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
32327c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 	/*
32357c478bd9Sstevel@tonic-gate 	 * Cancel any timeouts
32367c478bd9Sstevel@tonic-gate 	 */
32377c478bd9Sstevel@tonic-gate 	if (restart_id)
32387c478bd9Sstevel@tonic-gate 		(void) untimeout(restart_id);
32397c478bd9Sstevel@tonic-gate 	if (kick_rcv_id)
32407c478bd9Sstevel@tonic-gate 		(void) untimeout(kick_rcv_id);
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	/*
32437c478bd9Sstevel@tonic-gate 	 * Since we have turned off interrupts, zsa_txint will not be called
32447c478bd9Sstevel@tonic-gate 	 * and no new chars will given to the chip. We just wait for the
32457c478bd9Sstevel@tonic-gate 	 * current character(s) to drain.
32467c478bd9Sstevel@tonic-gate 	 */
32477c478bd9Sstevel@tonic-gate 	delay(ztdelay(za->za_ttycommon.t_cflag & CBAUD));
32487c478bd9Sstevel@tonic-gate 
32497c478bd9Sstevel@tonic-gate 	/*
32507c478bd9Sstevel@tonic-gate 	 * Return remains of partially sent message to queue
32517c478bd9Sstevel@tonic-gate 	 */
32527c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
32537c478bd9Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) != NULL) {
32547c478bd9Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
32557c478bd9Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
32567c478bd9Sstevel@tonic-gate 			za->za_flags &= ~ZAS_BUSY;
32577c478bd9Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
32587c478bd9Sstevel@tonic-gate 			bp = za->za_xmitblk;
32597c478bd9Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
32607c478bd9Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
32617c478bd9Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
32627c478bd9Sstevel@tonic-gate 			za->za_xmitblk = NULL;
32637c478bd9Sstevel@tonic-gate 		}
32647c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
32657c478bd9Sstevel@tonic-gate 		if (bp)
32667c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
32677c478bd9Sstevel@tonic-gate 	}
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate 	/*
32707c478bd9Sstevel@tonic-gate 	 * Stop any breaks in progress.
32717c478bd9Sstevel@tonic-gate 	 */
32727c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
32737c478bd9Sstevel@tonic-gate 	if (zs->zs_wreg[5] & ZSWR5_BREAK) {
32747c478bd9Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
32757c478bd9Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BREAK;
32767c478bd9Sstevel@tonic-gate 	}
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 	/*
32797c478bd9Sstevel@tonic-gate 	 * Now get a copy of current registers setting.
32807c478bd9Sstevel@tonic-gate 	 */
32817c478bd9Sstevel@tonic-gate 	zspp = &zs_prog[zs->zs_unit];
32827c478bd9Sstevel@tonic-gate 	zspp->zs = zs;
32837c478bd9Sstevel@tonic-gate 	zspp->flags = 0;
32847c478bd9Sstevel@tonic-gate 	zspp->wr3 = zs->zs_wreg[3];
32857c478bd9Sstevel@tonic-gate 	zspp->wr4 = zs->zs_wreg[4];
32867c478bd9Sstevel@tonic-gate 	zspp->wr5 = zs->zs_wreg[5];
32877c478bd9Sstevel@tonic-gate 	zspp->wr11 = zs->zs_wreg[11];
32887c478bd9Sstevel@tonic-gate 	zspp->wr12 = zs->zs_wreg[12];
32897c478bd9Sstevel@tonic-gate 	zspp->wr13 = zs->zs_wreg[13];
32907c478bd9Sstevel@tonic-gate 	zspp->wr15 = zs->zs_wreg[15];
32917c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
32927c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
32937c478bd9Sstevel@tonic-gate 	/*
32947c478bd9Sstevel@tonic-gate 	 * We do this on the off chance that zsa_close is waiting on a timed
32957c478bd9Sstevel@tonic-gate 	 * break to complete and nothing else.
32967c478bd9Sstevel@tonic-gate 	 */
32977c478bd9Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
32987c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
32997c478bd9Sstevel@tonic-gate }
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate static int
zsa_resume(struct zscom * zs)33027c478bd9Sstevel@tonic-gate zsa_resume(struct zscom *zs)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate 	register struct asyncline *za;
33057c478bd9Sstevel@tonic-gate 	struct zs_prog	*zspp;
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
33087c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
33097c478bd9Sstevel@tonic-gate 	if (!(zs->zs_suspended)) {
33107c478bd9Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
33117c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
33127c478bd9Sstevel@tonic-gate 	}
33137c478bd9Sstevel@tonic-gate 
33147c478bd9Sstevel@tonic-gate 	/*
33157c478bd9Sstevel@tonic-gate 	 * Restore H/W state
33167c478bd9Sstevel@tonic-gate 	 */
33177c478bd9Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
33187c478bd9Sstevel@tonic-gate 	zspp = &zs_prog[zs->zs_unit];
33197c478bd9Sstevel@tonic-gate 	zs_program(zspp);
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 	/*
33227c478bd9Sstevel@tonic-gate 	 * Enable all interrupts for this chip and delay to let chip settle
33237c478bd9Sstevel@tonic-gate 	 */
33247c478bd9Sstevel@tonic-gate 	SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT);
33257c478bd9Sstevel@tonic-gate 	DELAY(4000);
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 	/*
33287c478bd9Sstevel@tonic-gate 	 * Restart receiving and transmitting
33297c478bd9Sstevel@tonic-gate 	 */
33307c478bd9Sstevel@tonic-gate 	zs->zs_suspended = 0;
33317c478bd9Sstevel@tonic-gate 	za->za_rcv_flags_mask |= DO_TRANSMIT;
33327c478bd9Sstevel@tonic-gate 	za->za_ext = 1;
33337c478bd9Sstevel@tonic-gate 	ZSSETSOFT(zs);
33347c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
33357c478bd9Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
33367c478bd9Sstevel@tonic-gate 
33377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
33387c478bd9Sstevel@tonic-gate }
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
33417c478bd9Sstevel@tonic-gate static void
zsa_print_info(struct zscom * zs)33427c478bd9Sstevel@tonic-gate zsa_print_info(struct zscom *zs)
33437c478bd9Sstevel@tonic-gate {
33447c478bd9Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
33457c478bd9Sstevel@tonic-gate 	register queue_t *q = za->za_ttycommon.t_writeq;
33467c478bd9Sstevel@tonic-gate 
33477c478bd9Sstevel@tonic-gate 	printf(" next q=%s\n", (RD(q))->q_next->q_qinfo->qi_minfo->mi_idname);
33487c478bd9Sstevel@tonic-gate 	printf("unit=%d\n", zs->zs_unit);
33497c478bd9Sstevel@tonic-gate 	printf("tflag:\n");
33507c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_SOFTCAR) printf(" t_fl:TS_SOFTCAR");
33517c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_XCLUDE) printf(" t_fl:TS_XCLUDE");
33527c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNBRK) printf(" t_ifl:IGNBRK");
33537c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & BRKINT) printf(" t_ifl:BRKINT");
33547c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNPAR) printf(" t_ifl:IGNPAR");
33557c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & PARMRK) printf(" t_ifl:PARMRK");
33567c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & INPCK) printf(" t_ifl:INPCK");
33577c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & ISTRIP) printf(" t_ifl:ISTRIP");
33587c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & INLCR) printf(" t_ifl:INLCR");
33597c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNCR) printf(" t_ifl:IGNCR");
33607c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & ICRNL) printf(" t_ifl:ICRNL");
33617c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IUCLC) printf(" t_ifl:IUCLC");
33627c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXON) printf(" t_ifl:IXON");
33637c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXOFF) printf(" t_ifl:IXOFF");
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate 	printf("\n");
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS5) printf(" t_cfl:CS5");
33697c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS6) printf(" t_cfl:CS6");
33707c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS7) printf(" t_cfl:CS7");
33717c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS8) printf(" t_cfl:CS8");
33727c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSTOPB) printf(" t_cfl:CSTOPB");
33737c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CREAD) printf(" t_cfl:CREAD");
33747c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARENB) printf(" t_cfl:PARENB");
33757c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARODD) printf(" t_cfl:PARODD");
33767c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & HUPCL) printf(" t_cfl:HUPCL");
33777c478bd9Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CLOCAL) printf(" t_cfl:CLOCAL");
33787c478bd9Sstevel@tonic-gate 	printf(" t_stopc=%x", za->za_ttycommon.t_stopc);
33797c478bd9Sstevel@tonic-gate 	printf("\n");
33807c478bd9Sstevel@tonic-gate }
33817c478bd9Sstevel@tonic-gate #endif
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate /*
33847c478bd9Sstevel@tonic-gate  * Check for abort character sequence
33857c478bd9Sstevel@tonic-gate  */
33867c478bd9Sstevel@tonic-gate static boolean_t
abort_charseq_recognize(uchar_t ch)33877c478bd9Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch)
33887c478bd9Sstevel@tonic-gate {
33897c478bd9Sstevel@tonic-gate 	static int state = 0;
33907c478bd9Sstevel@tonic-gate #define	CNTRL(c) ((c)&037)
33917c478bd9Sstevel@tonic-gate 	static char sequence[] = { '\r', '~', CNTRL('b') };
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 	if (ch == sequence[state]) {
33947c478bd9Sstevel@tonic-gate 		if (++state >= sizeof (sequence)) {
33957c478bd9Sstevel@tonic-gate 			state = 0;
33967c478bd9Sstevel@tonic-gate 			return (B_TRUE);
33977c478bd9Sstevel@tonic-gate 		}
33987c478bd9Sstevel@tonic-gate 	} else {
33997c478bd9Sstevel@tonic-gate 		state = (ch == sequence[0]) ? 1 : 0;
34007c478bd9Sstevel@tonic-gate 	}
34017c478bd9Sstevel@tonic-gate 	return (B_FALSE);
34027c478bd9Sstevel@tonic-gate }
3403