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