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