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