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
519397407SSherry Moore * Common Development and Distribution License (the "License").
619397407SSherry Moore * 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 /*
2219397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24*89b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * HDLC protocol handler for Z8530 SCC.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
387c478bd9Sstevel@tonic-gate #include <sys/stream.h>
397c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include <sys/stat.h>
417c478bd9Sstevel@tonic-gate #include <sys/cred.h>
427c478bd9Sstevel@tonic-gate #include <sys/user.h>
437c478bd9Sstevel@tonic-gate #include <sys/proc.h>
447c478bd9Sstevel@tonic-gate #include <sys/file.h>
457c478bd9Sstevel@tonic-gate #include <sys/uio.h>
467c478bd9Sstevel@tonic-gate #include <sys/buf.h>
477c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
487c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
497c478bd9Sstevel@tonic-gate #include <sys/errno.h>
507c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #include <sys/zsdev.h>
537c478bd9Sstevel@tonic-gate #include <sys/ser_sync.h>
547c478bd9Sstevel@tonic-gate #include <sys/conf.h>
557c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
567c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
577c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define ZSH_TRACING
607c478bd9Sstevel@tonic-gate #ifdef ZSH_TRACING
617c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate * Temp tracepoint definitions
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate #define TR_ZSH 50
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #define TR_ZSH_TXINT 1
697c478bd9Sstevel@tonic-gate #define TR_ZSH_XSINT 2
707c478bd9Sstevel@tonic-gate #define TR_ZSH_RXINT 3
717c478bd9Sstevel@tonic-gate #define TR_ZSH_SRINT 4
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate #define TR_ZSH_WPUT_START 5
747c478bd9Sstevel@tonic-gate #define TR_ZSH_WPUT_END 6
757c478bd9Sstevel@tonic-gate #define TR_ZSH_START_START 7
767c478bd9Sstevel@tonic-gate #define TR_ZSH_START_END 8
777c478bd9Sstevel@tonic-gate #define TR_ZSH_SOFT_START 9
787c478bd9Sstevel@tonic-gate #define TR_ZSH_SOFT_END 10
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define TR_ZSH_OPEN 11
817c478bd9Sstevel@tonic-gate #define TR_ZSH_CLOSE 12
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate #endif /* ZSH_TRACING */
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * Logging definitions
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate * #define ZSH_DEBUG
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate #ifdef ZSH_DEBUG
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL
957c478bd9Sstevel@tonic-gate extern char zs_h_log[];
967c478bd9Sstevel@tonic-gate extern int zs_h_log_n;
977c478bd9Sstevel@tonic-gate #define zsh_h_log_add(c) \
987c478bd9Sstevel@tonic-gate { \
997c478bd9Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \
1007c478bd9Sstevel@tonic-gate zs_h_log_n = 0; \
1017c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \
1027c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \
1037c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate #define zsh_h_log_clear
1067c478bd9Sstevel@tonic-gate #else
1077c478bd9Sstevel@tonic-gate #define ZSH_H_LOG_MAX 0x8000
1087c478bd9Sstevel@tonic-gate char zsh_h_log[2][ZSH_H_LOG_MAX +10];
1097c478bd9Sstevel@tonic-gate int zsh_h_log_n[2];
1107c478bd9Sstevel@tonic-gate #define zsh_h_log_add(c) \
1117c478bd9Sstevel@tonic-gate { \
1127c478bd9Sstevel@tonic-gate if (zsh_h_log_n[zs->zs_unit] >= ZSH_H_LOG_MAX) \
1137c478bd9Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \
1147c478bd9Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]++] = c; \
1157c478bd9Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]] = '\0'; \
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate #define zsh_h_log_clear \
1197c478bd9Sstevel@tonic-gate { register char *p; \
1207c478bd9Sstevel@tonic-gate for (p = &zsh_h_log[zs->zs_unit][ZSH_H_LOG_MAX]; \
1217c478bd9Sstevel@tonic-gate p >= &zsh_h_log[zs->zs_unit][0]; p--) \
1227c478bd9Sstevel@tonic-gate *p = '\0'; \
1237c478bd9Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate #endif
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate #define ZSH_R0_LOG(r0) { \
1287c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsh_h_log_add('R'); \
1297c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsh_h_log_add('Z'); \
1307c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsh_h_log_add('T'); \
1317c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsh_h_log_add('D'); \
1327c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsh_h_log_add('S'); \
1337c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsh_h_log_add('C'); \
1347c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsh_h_log_add('U'); \
1357c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsh_h_log_add('B'); \
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate #endif
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate #ifndef MAXZSH
1407c478bd9Sstevel@tonic-gate #define MAXZSH 2
1417c478bd9Sstevel@tonic-gate #define MAXZSHCLONES (80) /* three clone opens per instance */
1427c478bd9Sstevel@tonic-gate #endif /* MAXZSH */
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate int maxzsh = MAXZSH;
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate int zsh_timer_count = 10;
1477c478bd9Sstevel@tonic-gate int zsh_default_mru = 1024;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate struct ser_str *zsh_str = NULL;
1507c478bd9Sstevel@tonic-gate unsigned char zsh_usedminor[MAXZSHCLONES];
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * The HDLC protocol
1557c478bd9Sstevel@tonic-gate */
1567c478bd9Sstevel@tonic-gate int zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
1577c478bd9Sstevel@tonic-gate static int zsh_probe(dev_info_t *dev);
1587c478bd9Sstevel@tonic-gate static int zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
1597c478bd9Sstevel@tonic-gate static int zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
1607c478bd9Sstevel@tonic-gate static int zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
1617c478bd9Sstevel@tonic-gate static int zsh_close(queue_t *rq, int flag);
1627c478bd9Sstevel@tonic-gate static void zsh_wput(queue_t *wq, mblk_t *mp);
1637c478bd9Sstevel@tonic-gate static int zsh_start(struct zscom *zs, struct syncline *zss);
1647c478bd9Sstevel@tonic-gate static void zsh_ioctl(queue_t *wq, mblk_t *mp);
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate static struct module_info hdlc_minfo = {
1677c478bd9Sstevel@tonic-gate 0x5a48, /* module ID number: "ZH" */
1687c478bd9Sstevel@tonic-gate "zsh", /* module name */
1697c478bd9Sstevel@tonic-gate 0, /* minimum packet size accepted */
1707c478bd9Sstevel@tonic-gate INFPSZ, /* maximum packet size accepted */
1717c478bd9Sstevel@tonic-gate 12*1024, /* queue high water mark (bytes) */
1727c478bd9Sstevel@tonic-gate 4*1024 /* queue low water mark (bytes) */
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate static struct qinit hdlc_rinit = {
1767c478bd9Sstevel@tonic-gate putq, /* input put procedure */
1777c478bd9Sstevel@tonic-gate NULL, /* input service procedure */
1787c478bd9Sstevel@tonic-gate zsh_open, /* open procedure */
1797c478bd9Sstevel@tonic-gate zsh_close, /* close procedure */
1807c478bd9Sstevel@tonic-gate NULL, /* reserved */
1817c478bd9Sstevel@tonic-gate &hdlc_minfo, /* module info */
1827c478bd9Sstevel@tonic-gate NULL /* reserved */
1837c478bd9Sstevel@tonic-gate };
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate static struct qinit hdlc_winit = {
1867c478bd9Sstevel@tonic-gate (int (*)())zsh_wput, /* output put procedure */
1877c478bd9Sstevel@tonic-gate NULL, /* output service procedure */
1887c478bd9Sstevel@tonic-gate NULL, /* open procedure */
1897c478bd9Sstevel@tonic-gate NULL, /* close procedure */
1907c478bd9Sstevel@tonic-gate NULL, /* reserved */
1917c478bd9Sstevel@tonic-gate &hdlc_minfo, /* module info */
1927c478bd9Sstevel@tonic-gate NULL /* reserved */
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate struct streamtab hdlctab = {
1967c478bd9Sstevel@tonic-gate &hdlc_rinit, /* initialize read queue */
1977c478bd9Sstevel@tonic-gate &hdlc_winit, /* initialize write queue */
1987c478bd9Sstevel@tonic-gate NULL, /* mux read qinit */
1997c478bd9Sstevel@tonic-gate NULL /* mux write qinit */
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(zsh_ops, nulldev, zsh_probe, zsh_attach,
20319397407SSherry Moore zsh_detach, nodev, zsh_info, D_MP, &hdlctab, ddi_quiesce_not_supported);
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
2077c478bd9Sstevel@tonic-gate */
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate #include <sys/errno.h>
2107c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
2177c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
21819397407SSherry Moore "Z8530 serial HDLC drv",
2197c478bd9Sstevel@tonic-gate &zsh_ops, /* our own ops for this module */
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2237c478bd9Sstevel@tonic-gate MODREV_1,
2247c478bd9Sstevel@tonic-gate (void *)&modldrv,
2257c478bd9Sstevel@tonic-gate NULL
2267c478bd9Sstevel@tonic-gate };
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate int
_init(void)2297c478bd9Sstevel@tonic-gate _init(void)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate int
_fini(void)2357c478bd9Sstevel@tonic-gate _fini(void)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2417c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate * The HDLC interrupt entry points.
2497c478bd9Sstevel@tonic-gate */
2507c478bd9Sstevel@tonic-gate static void zsh_txint(struct zscom *zs);
2517c478bd9Sstevel@tonic-gate static void zsh_xsint(struct zscom *zs);
2527c478bd9Sstevel@tonic-gate static void zsh_rxint(struct zscom *zs);
2537c478bd9Sstevel@tonic-gate static void zsh_srint(struct zscom *zs);
2547c478bd9Sstevel@tonic-gate static int zsh_softint(struct zscom *zs);
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate struct zsops zsops_hdlc = {
2577c478bd9Sstevel@tonic-gate zsh_txint,
2587c478bd9Sstevel@tonic-gate zsh_xsint,
2597c478bd9Sstevel@tonic-gate zsh_rxint,
2607c478bd9Sstevel@tonic-gate zsh_srint,
2617c478bd9Sstevel@tonic-gate zsh_softint,
2627c478bd9Sstevel@tonic-gate NULL,
2637c478bd9Sstevel@tonic-gate NULL
2647c478bd9Sstevel@tonic-gate };
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate static int zsh_program(struct zscom *zs, struct scc_mode *sm);
2677c478bd9Sstevel@tonic-gate static void zsh_setmstat(struct zscom *zs, int event);
2687c478bd9Sstevel@tonic-gate static void zsh_rxbad(struct zscom *zs, struct syncline *zss);
2697c478bd9Sstevel@tonic-gate static void zsh_txbad(struct zscom *zs, struct syncline *zss);
2707c478bd9Sstevel@tonic-gate static void zsh_watchdog(void *);
2717c478bd9Sstevel@tonic-gate static void zsh_callback(void *);
2727c478bd9Sstevel@tonic-gate static int zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss);
2737c478bd9Sstevel@tonic-gate static void zsh_init_port(struct zscom *zs, struct syncline *zss);
2747c478bd9Sstevel@tonic-gate static int zsh_setmode(struct zscom *zs, struct syncline *zss,
2757c478bd9Sstevel@tonic-gate struct scc_mode *sm);
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate * The HDLC Driver.
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate * Special macros to handle STREAMS operations.
2857c478bd9Sstevel@tonic-gate * These are required to address memory leakage problems.
2867c478bd9Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate #define ZSH_GETBLOCK(zs, allocbcount) \
2937c478bd9Sstevel@tonic-gate { \
2947c478bd9Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \
2957c478bd9Sstevel@tonic-gate while (--n >= 0) { \
2967c478bd9Sstevel@tonic-gate if (!zss->sl_rstandby[n]) { \
2977c478bd9Sstevel@tonic-gate if ((zss->sl_rstandby[n] = \
2987c478bd9Sstevel@tonic-gate allocb(zss->sl_mru, BPRI_MED)) == NULL) { \
2997c478bd9Sstevel@tonic-gate if (zss->sl_bufcid == 0) { \
3007c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \
3017c478bd9Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) { \
3027c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
3037c478bd9Sstevel@tonic-gate zss->sl_bufcid = bufcall(zss->sl_mru, \
3047c478bd9Sstevel@tonic-gate BPRI_MED, zsh_callback, zs); \
3057c478bd9Sstevel@tonic-gate break; \
3067c478bd9Sstevel@tonic-gate } else \
3077c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
3087c478bd9Sstevel@tonic-gate } \
3097c478bd9Sstevel@tonic-gate } \
3107c478bd9Sstevel@tonic-gate allocbcount--; \
3117c478bd9Sstevel@tonic-gate } \
3127c478bd9Sstevel@tonic-gate } \
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex.
3177c478bd9Sstevel@tonic-gate */
3187c478bd9Sstevel@tonic-gate #define ZSH_ALLOCB(mp) \
3197c478bd9Sstevel@tonic-gate { \
3207c478bd9Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \
3217c478bd9Sstevel@tonic-gate mp = NULL; \
3227c478bd9Sstevel@tonic-gate while (--n >= 0) { \
3237c478bd9Sstevel@tonic-gate if ((mp = zss->sl_rstandby[n]) != NULL) { \
3247c478bd9Sstevel@tonic-gate zss->sl_rstandby[n] = NULL; \
3257c478bd9Sstevel@tonic-gate break; \
3267c478bd9Sstevel@tonic-gate } \
3277c478bd9Sstevel@tonic-gate } \
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate #define ZSH_PUTQ(mp) \
3317c478bd9Sstevel@tonic-gate { \
3327c478bd9Sstevel@tonic-gate register int wptr, rptr; \
3337c478bd9Sstevel@tonic-gate wptr = zss->sl_rdone_wptr; \
3347c478bd9Sstevel@tonic-gate rptr = zss->sl_rdone_rptr; \
3357c478bd9Sstevel@tonic-gate zss->sl_rdone[wptr] = mp; \
3367c478bd9Sstevel@tonic-gate if ((wptr) + 1 == ZSH_RDONE_MAX) \
3377c478bd9Sstevel@tonic-gate zss->sl_rdone_wptr = wptr = 0; \
3387c478bd9Sstevel@tonic-gate else \
3397c478bd9Sstevel@tonic-gate zss->sl_rdone_wptr = ++wptr; \
3407c478bd9Sstevel@tonic-gate if (wptr == rptr) { /* Should never occur */ \
3417c478bd9Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \
3427c478bd9Sstevel@tonic-gate zss->sl_m_error = ENOSR; \
3437c478bd9Sstevel@tonic-gate ZSSETSOFT(zs); \
3447c478bd9Sstevel@tonic-gate } \
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate #define ZSH_FREEMSG(mp) \
3487c478bd9Sstevel@tonic-gate { \
3497c478bd9Sstevel@tonic-gate ZSH_PUTQ(mp); \
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate #define ZSH_GETQ(mp) \
3577c478bd9Sstevel@tonic-gate { \
3587c478bd9Sstevel@tonic-gate if (zss->sl_rdone_rptr != zss->sl_rdone_wptr) { \
3597c478bd9Sstevel@tonic-gate mp = zss->sl_rdone[zss->sl_rdone_rptr++]; \
3607c478bd9Sstevel@tonic-gate if (zss->sl_rdone_rptr == ZSH_RDONE_MAX) \
3617c478bd9Sstevel@tonic-gate zss->sl_rdone_rptr = 0; \
3627c478bd9Sstevel@tonic-gate } else \
3637c478bd9Sstevel@tonic-gate mp = NULL; \
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate #define ZSH_FLUSHQ \
3677c478bd9Sstevel@tonic-gate { \
3687c478bd9Sstevel@tonic-gate register mblk_t *tmp; \
3697c478bd9Sstevel@tonic-gate for (;;) { \
3707c478bd9Sstevel@tonic-gate ZSH_GETQ(tmp); \
3717c478bd9Sstevel@tonic-gate if (!(tmp)) \
3727c478bd9Sstevel@tonic-gate break; \
3737c478bd9Sstevel@tonic-gate freemsg(tmp); \
3747c478bd9Sstevel@tonic-gate } \
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3787c478bd9Sstevel@tonic-gate static int
zsh_probe(dev_info_t * dev)3797c478bd9Sstevel@tonic-gate zsh_probe(dev_info_t *dev)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate return (DDI_PROBE_DONTCARE);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3857c478bd9Sstevel@tonic-gate static int
zsh_attach(dev_info_t * dev,ddi_attach_cmd_t cmd)3867c478bd9Sstevel@tonic-gate zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate register int unit;
3897c478bd9Sstevel@tonic-gate char name[3] = {
3907c478bd9Sstevel@tonic-gate '\0', '\0', '\0' };
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate * Since zsh is a child of the "pseudo" nexus, we can expect the
3947c478bd9Sstevel@tonic-gate * attach routine to be called only once. We need to create all
3957c478bd9Sstevel@tonic-gate * necessary devices in one shot. There is never more than one
3967c478bd9Sstevel@tonic-gate * SCC chip that supports zsh devices.
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH)
4007c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4017c478bd9Sstevel@tonic-gate if (zscom == NULL)
4027c478bd9Sstevel@tonic-gate return (DDI_FAILURE); /* zsattach not done */
4037c478bd9Sstevel@tonic-gate unit = 2 * ddi_get_instance(dev);
4047c478bd9Sstevel@tonic-gate if (unit > 1)
4057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); /* only use cpu ports */
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, "zsh", S_IFCHR,
4087c478bd9Sstevel@tonic-gate NULL, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
4097c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zsh clone device creation failed.");
4117c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate for (; unit < maxzsh/2; unit++) {
4157c478bd9Sstevel@tonic-gate zscom[unit].zs_hdlc_dip = dev;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", unit);
4187c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
4197c478bd9Sstevel@tonic-gate 2*unit, DDI_PSEUDO, NULL) == DDI_FAILURE) {
4207c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4217c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate unit++;
4247c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", unit);
4257c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
4267c478bd9Sstevel@tonic-gate 2*(unit-1)+1, DDI_PSEUDO, NULL) == DDI_FAILURE) {
4277c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4287c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate /* ARGSUSED */
4367c478bd9Sstevel@tonic-gate int
zsh_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4377c478bd9Sstevel@tonic-gate zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
4387c478bd9Sstevel@tonic-gate void **result)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate register dev_t dev = (dev_t)arg;
4417c478bd9Sstevel@tonic-gate register int unit, error;
4427c478bd9Sstevel@tonic-gate register struct zscom *zs;
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs)
4457c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate switch (infocmd) {
4487c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
4497c478bd9Sstevel@tonic-gate if (zscom == NULL) {
4507c478bd9Sstevel@tonic-gate error = DDI_FAILURE;
4517c478bd9Sstevel@tonic-gate } else {
4527c478bd9Sstevel@tonic-gate zs = &zscom[unit];
4537c478bd9Sstevel@tonic-gate *result = zs->zs_hdlc_dip;
4547c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate break;
4577c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
458360e6f5eSmathue *result = (void *)(uintptr_t)(unit / 2);
4597c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
4607c478bd9Sstevel@tonic-gate break;
4617c478bd9Sstevel@tonic-gate default:
4627c478bd9Sstevel@tonic-gate error = DDI_FAILURE;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate return (error);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate static int
zsh_detach(dev_info_t * dev,ddi_detach_cmd_t cmd)4687c478bd9Sstevel@tonic-gate zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH)
4717c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate static void
zsh_init_port(struct zscom * zs,struct syncline * zss)4797c478bd9Sstevel@tonic-gate zsh_init_port(struct zscom *zs, struct syncline *zss)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate register uchar_t s0;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate SCC_WRITE(3, (ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE | ZSWR3_RX_8));
4847c478bd9Sstevel@tonic-gate SCC_WRITE(5, (ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE));
4857c478bd9Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0();
4867c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
4877c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
4887c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS);
4897c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
4907c478bd9Sstevel@tonic-gate if ((s0 & ZSRR0_CTS) ||
4917c478bd9Sstevel@tonic-gate !(zss->sl_mode.sm_config & (CONN_SIGNAL | CONN_IBM))) {
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * send msg that CTS is up
4947c478bd9Sstevel@tonic-gate */
4957c478bd9Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
4967c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
4977c478bd9Sstevel@tonic-gate } else {
4987c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
4997c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_RTS;
5007c478bd9Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
5017c478bd9Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
5027c478bd9Sstevel@tonic-gate if (!zss->sl_wd_id)
5037c478bd9Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog,
5047c478bd9Sstevel@tonic-gate zs, SIO_WATCHDOG_TICK);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate } else {
5077c478bd9Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
5087c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
5097c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
5107c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate * Open routine.
5167c478bd9Sstevel@tonic-gate */
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5197c478bd9Sstevel@tonic-gate static int
zsh_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)5207c478bd9Sstevel@tonic-gate zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate register struct zscom *zs;
5237c478bd9Sstevel@tonic-gate register struct syncline *zss;
5247c478bd9Sstevel@tonic-gate register struct ser_str *stp;
5257c478bd9Sstevel@tonic-gate register int unit;
5267c478bd9Sstevel@tonic-gate register int tmp;
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate if (sflag != CLONEOPEN) {
5297c478bd9Sstevel@tonic-gate if (rq->q_ptr)
5307c478bd9Sstevel@tonic-gate return (EBUSY); /* We got a stream that is in use */
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate unit = UNIT(*dev);
5337c478bd9Sstevel@tonic-gate if (unit >= maxzsh)
5347c478bd9Sstevel@tonic-gate return (ENXIO); /* unit not configured */
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate if (zscom == NULL)
5377c478bd9Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */
5387c478bd9Sstevel@tonic-gate zs = &zscom[unit];
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate if (zs->zs_ops == NULL) {
5417c478bd9Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_OPEN, "zsh_open:unit = %d", unit);
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
5477c478bd9Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
5487c478bd9Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
5497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
5507c478bd9Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /* Mark device as busy (for power management) */
5547c478bd9Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1);
5557c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, unit%2+1, 1);
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_hdlc);
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate zss = (struct syncline *)&zscom[unit].zs_priv_str;
5607c478bd9Sstevel@tonic-gate stp = &zss->sl_stream;
5617c478bd9Sstevel@tonic-gate stp->str_state = NULL;
5627c478bd9Sstevel@tonic-gate stp->str_com = (caddr_t)zs;
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate zss->sl_xhead = NULL;
5657c478bd9Sstevel@tonic-gate zss->sl_xactb = NULL;
5667c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
5677c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
5687c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
5697c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
5707c478bd9Sstevel@tonic-gate zss->sl_rhead = NULL;
5717c478bd9Sstevel@tonic-gate zss->sl_ractb = NULL;
5727c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
5737c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
5747c478bd9Sstevel@tonic-gate zss->sl_mstat = NULL;
5757c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
5767c478bd9Sstevel@tonic-gate zss->sl_wd_id = 0;
5777c478bd9Sstevel@tonic-gate zss->sl_soft_active = 0;
5787c478bd9Sstevel@tonic-gate zss->sl_stream.str_rq = NULL;
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate zs->zs_priv = (caddr_t)zss;
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate zss->sl_mru = zsh_default_mru;
5837c478bd9Sstevel@tonic-gate tmp = ZSH_MAX_RSTANDBY;
5847c478bd9Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp);
5857c478bd9Sstevel@tonic-gate if (zss->sl_rstandby[0] == NULL) {
5867c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zsh_open: can't alloc message block");
5877c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
5887c478bd9Sstevel@tonic-gate return (ENOSR);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
5917c478bd9Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb);
5927c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_OFF;
5937c478bd9Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0();
5947c478bd9Sstevel@tonic-gate zss->sl_flags &= (SF_INITIALIZED | SF_FDXPTP);
5957c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_INITIALIZED)
5967c478bd9Sstevel@tonic-gate zsh_init_port(zs, zss);
5977c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
5987c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
5997c478bd9Sstevel@tonic-gate } else { /* CLONEOPEN */
6007c478bd9Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
6017c478bd9Sstevel@tonic-gate for (unit = maxzsh; unit < MAXZSHCLONES; unit++)
6027c478bd9Sstevel@tonic-gate if (!zsh_usedminor[unit]) {
6037c478bd9Sstevel@tonic-gate zsh_usedminor[unit] = (unsigned char)unit;
6047c478bd9Sstevel@tonic-gate break;
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
6077c478bd9Sstevel@tonic-gate if (unit >= MAXZSHCLONES) /* no slots available */
6087c478bd9Sstevel@tonic-gate return (ENODEV);
6097c478bd9Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), unit);
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate stp = kmem_zalloc(sizeof (struct ser_str), KM_NOSLEEP);
6127c478bd9Sstevel@tonic-gate if (stp == NULL) {
6137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
6147c478bd9Sstevel@tonic-gate "zsh clone open failed, no memory, rq=%p\n",
6157c478bd9Sstevel@tonic-gate (void *)rq);
6167c478bd9Sstevel@tonic-gate return (ENOMEM);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate stp->str_state = STR_CLONE;
6197c478bd9Sstevel@tonic-gate stp->str_com = NULL; /* can't determine without ppa */
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate stp->str_rq = rq;
6227c478bd9Sstevel@tonic-gate stp->str_inst = unit;
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)stp;
6257c478bd9Sstevel@tonic-gate qprocson(rq);
6267c478bd9Sstevel@tonic-gate return (0);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate * Close routine.
6317c478bd9Sstevel@tonic-gate */
6327c478bd9Sstevel@tonic-gate int zsh_tx_enable_in_close = 0;
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6357c478bd9Sstevel@tonic-gate static int
zsh_close(queue_t * rq,int flag)6367c478bd9Sstevel@tonic-gate zsh_close(queue_t *rq, int flag)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate struct ser_str *stp;
6397c478bd9Sstevel@tonic-gate struct zscom *zs;
6407c478bd9Sstevel@tonic-gate struct syncline *zss;
6417c478bd9Sstevel@tonic-gate mblk_t *mp;
6427c478bd9Sstevel@tonic-gate int i;
6437c478bd9Sstevel@tonic-gate timeout_id_t sl_wd_id;
6447c478bd9Sstevel@tonic-gate bufcall_id_t sl_bufcid;
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate * Note that a close is only called on the last close of a
6487c478bd9Sstevel@tonic-gate * particular stream. Assume that we need to do it all.
6497c478bd9Sstevel@tonic-gate */
6507c478bd9Sstevel@tonic-gate qprocsoff(rq); /* no new business after this */
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate stp = (struct ser_str *)rq->q_ptr;
6537c478bd9Sstevel@tonic-gate if (stp == NULL)
6547c478bd9Sstevel@tonic-gate return (0); /* already been closed once */
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate if (stp->str_state == STR_CLONE) {
6577c478bd9Sstevel@tonic-gate zsh_usedminor[stp->str_inst] = 0;
6587c478bd9Sstevel@tonic-gate } else {
6597c478bd9Sstevel@tonic-gate zs = (struct zscom *)stp->str_com;
6607c478bd9Sstevel@tonic-gate if (zs == NULL)
6617c478bd9Sstevel@tonic-gate goto out;
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_CLOSE, "zs = %p", zs);
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
6667c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
6677c478bd9Sstevel@tonic-gate flushq(WR(rq), FLUSHALL);
6687c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
6697c478bd9Sstevel@tonic-gate if (zss->sl_xstandby) {
6707c478bd9Sstevel@tonic-gate zss->sl_xstandby->b_wptr = zss->sl_xstandby->b_rptr;
6717c478bd9Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xstandby);
6727c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate ZSH_FLUSHQ;
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate * Stop the Watchdog Timer.
6807c478bd9Sstevel@tonic-gate */
6817c478bd9Sstevel@tonic-gate if ((sl_wd_id = zss->sl_wd_id) != 0)
6827c478bd9Sstevel@tonic-gate zss->sl_wd_id = 0;
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate * Cancel outstanding "bufcall" request.
6867c478bd9Sstevel@tonic-gate */
6877c478bd9Sstevel@tonic-gate if ((sl_bufcid = zss->sl_bufcid) != 0)
6887c478bd9Sstevel@tonic-gate zss->sl_bufcid = 0;
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
6917c478bd9Sstevel@tonic-gate if (zs->zs_wr_cur) {
6927c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
6937c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
6947c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
6957c478bd9Sstevel@tonic-gate ZSDELAY();
6967c478bd9Sstevel@tonic-gate ZSDELAY();
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
7017c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
7027c478bd9Sstevel@tonic-gate SCC_BIC(15,
7037c478bd9Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS));
7047c478bd9Sstevel@tonic-gate SCC_WRITE(3, 0); /* Quiesce receiver */
7057c478bd9Sstevel@tonic-gate if (zsh_tx_enable_in_close && !(zss->sl_flags & SF_FDXPTP)) {
7067c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
7077c478bd9Sstevel@tonic-gate } else
7087c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate SCC_BIC(5, (ZSWR5_DTR | ZSWR5_RTS | ZSWR5_TXCRC_ENABLE));
7117c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); /* reset TX */
7127c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
7137c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
7147c478bd9Sstevel@tonic-gate (void) SCC_READDATA(); /* reset RX */
7157c478bd9Sstevel@tonic-gate ZSDELAY();
7167c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
7177c478bd9Sstevel@tonic-gate ZSDELAY();
7187c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
7197c478bd9Sstevel@tonic-gate ZSDELAY();
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * Free up everything we ever allocated.
7247c478bd9Sstevel@tonic-gate */
7257c478bd9Sstevel@tonic-gate if ((mp = zss->sl_rhead) != NULL) {
7267c478bd9Sstevel@tonic-gate zss->sl_ractb = NULL; /* already freed */
7277c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
7287c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
7297c478bd9Sstevel@tonic-gate zss->sl_rhead = NULL;
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7327c478bd9Sstevel@tonic-gate if (mp)
7337c478bd9Sstevel@tonic-gate freemsg(mp);
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7367c478bd9Sstevel@tonic-gate if ((mp = zss->sl_ractb) != NULL) {
7377c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
7387c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
7397c478bd9Sstevel@tonic-gate zss->sl_ractb = NULL;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7427c478bd9Sstevel@tonic-gate if (mp)
7437c478bd9Sstevel@tonic-gate freemsg(mp);
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate for (i = 0; i < ZSH_MAX_RSTANDBY; i++) {
7467c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7477c478bd9Sstevel@tonic-gate mp = zss->sl_rstandby[i];
7487c478bd9Sstevel@tonic-gate zss->sl_rstandby[i] = NULL;
7497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7507c478bd9Sstevel@tonic-gate if (mp)
7517c478bd9Sstevel@tonic-gate freemsg(mp);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7557c478bd9Sstevel@tonic-gate if ((mp = zss->sl_xhead) != NULL) {
7567c478bd9Sstevel@tonic-gate zss->sl_xhead = NULL;
7577c478bd9Sstevel@tonic-gate zss->sl_xactb = NULL;
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7607c478bd9Sstevel@tonic-gate if (mp)
7617c478bd9Sstevel@tonic-gate freemsg(mp);
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate ZSH_FLUSHQ;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7667c478bd9Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL)
7677c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
7687c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7697c478bd9Sstevel@tonic-gate if (mp)
7707c478bd9Sstevel@tonic-gate freemsg(mp);
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7737c478bd9Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL)
7747c478bd9Sstevel@tonic-gate zss->sl_mstat = NULL;
7757c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */
7767c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7777c478bd9Sstevel@tonic-gate if (mp)
7787c478bd9Sstevel@tonic-gate freemsg(mp);
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate zss->sl_stream.str_rq = NULL;
7817c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
7827c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
7837c478bd9Sstevel@tonic-gate if (sl_wd_id)
7847c478bd9Sstevel@tonic-gate (void) untimeout(sl_wd_id);
7857c478bd9Sstevel@tonic-gate if (sl_bufcid)
7867c478bd9Sstevel@tonic-gate unbufcall(sl_bufcid);
7877c478bd9Sstevel@tonic-gate while (zss->sl_soft_active)
7887c478bd9Sstevel@tonic-gate drv_usecwait(1);
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate /* Mark device as available for power management */
7917c478bd9Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1);
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate if (stp->str_state == STR_CLONE)
7957c478bd9Sstevel@tonic-gate kmem_free(stp, sizeof (struct ser_str));
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate out:
7987c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL;
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate return (0);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate static int
zsh_hdp_ok_or_rts_state(struct zscom * zs,struct syncline * zss)8047c478bd9Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate register uchar_t s0;
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
8097c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS);
8107c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
8117c478bd9Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
8127c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
8137c478bd9Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
8147c478bd9Sstevel@tonic-gate return (1);
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
8177c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_RTS;
8187c478bd9Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
8197c478bd9Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
8207c478bd9Sstevel@tonic-gate return (0);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate /*
8247c478bd9Sstevel@tonic-gate * Put procedure for write queue.
8257c478bd9Sstevel@tonic-gate */
8267c478bd9Sstevel@tonic-gate static void
zsh_wput(queue_t * wq,mblk_t * mp)8277c478bd9Sstevel@tonic-gate zsh_wput(queue_t *wq, mblk_t *mp)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr;
8307c478bd9Sstevel@tonic-gate register struct zscom *zs;
8317c478bd9Sstevel@tonic-gate register struct syncline *zss = NULL;
8327c478bd9Sstevel@tonic-gate register ulong_t prim, error = 0;
8337c478bd9Sstevel@tonic-gate register union DL_primitives *dlp;
8347c478bd9Sstevel@tonic-gate register int ppa;
8357c478bd9Sstevel@tonic-gate register mblk_t *tmp;
8367c478bd9Sstevel@tonic-gate register struct copyresp *resp;
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate * stp->str_com supplied by open or DLPI attach.
8407c478bd9Sstevel@tonic-gate */
8417c478bd9Sstevel@tonic-gate if (stp == NULL) {
8427c478bd9Sstevel@tonic-gate freemsg(mp);
8437c478bd9Sstevel@tonic-gate return;
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate zs = (struct zscom *)stp->str_com;
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate TRACE_0(TR_ZSH, TR_ZSH_WPUT_START, "zsh_wput start");
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate if ((mp->b_datap->db_type == M_FLUSH) &&
8507c478bd9Sstevel@tonic-gate (stp->str_state == STR_CLONE)) {
8517c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
8527c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA);
8537c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
8567c478bd9Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */
8577c478bd9Sstevel@tonic-gate else
8587c478bd9Sstevel@tonic-gate freemsg(mp);
8597c478bd9Sstevel@tonic-gate return;
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate if ((zs == NULL) && (mp->b_datap->db_type != M_PROTO)) {
8637c478bd9Sstevel@tonic-gate freemsg(mp);
8647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
8657c478bd9Sstevel@tonic-gate "zsh: clone device %d must be attached before use!",
8667c478bd9Sstevel@tonic-gate stp->str_inst);
8677c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, EPROTO);
8687c478bd9Sstevel@tonic-gate return;
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate if (stp->str_state == STR_CLONE) { /* Clone opened, limited. */
8727c478bd9Sstevel@tonic-gate if ((mp->b_datap->db_type != M_PROTO) &&
8737c478bd9Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCTL) &&
8747c478bd9Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCDATA)) {
8757c478bd9Sstevel@tonic-gate freemsg(mp);
8767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
8777c478bd9Sstevel@tonic-gate "zsh%x: invalid operation for clone dev.\n",
8787c478bd9Sstevel@tonic-gate stp->str_inst);
8797c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, EPROTO);
8807c478bd9Sstevel@tonic-gate return;
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate } else {
8837c478bd9Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate case M_DATA:
8897c478bd9Sstevel@tonic-gate /*
8907c478bd9Sstevel@tonic-gate * Queue the message up to be transmitted.
8917c478bd9Sstevel@tonic-gate * Set "in progress" flag and call the start routine.
8927c478bd9Sstevel@tonic-gate */
8937c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
8947c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_INITIALIZED)) {
8957c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
8967c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
8977c478bd9Sstevel@tonic-gate "zsh%x not initialized, can't send message",
8987c478bd9Sstevel@tonic-gate zs->zs_unit);
8997c478bd9Sstevel@tonic-gate freemsg(mp);
9007c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, ECOMM);
9017c478bd9Sstevel@tonic-gate return;
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9047c478bd9Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) {
9057c478bd9Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT;
9067c478bd9Sstevel@tonic-gate (void) zsh_softint(zs);
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate while (mp->b_wptr == mp->b_rptr) {
9097c478bd9Sstevel@tonic-gate register mblk_t *mp1;
9107c478bd9Sstevel@tonic-gate mp1 = unlinkb(mp);
9117c478bd9Sstevel@tonic-gate freemsg(mp);
9127c478bd9Sstevel@tonic-gate mp = mp1;
9137c478bd9Sstevel@tonic-gate if (mp == NULL)
9147c478bd9Sstevel@tonic-gate return;
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
9177c478bd9Sstevel@tonic-gate (void) putq(wq, mp);
9187c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9197c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
9207c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9217c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA);
9227c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END,
9257c478bd9Sstevel@tonic-gate "zsh_wput end: zs = %p", zs);
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate return;
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate tmp = NULL;
9307c478bd9Sstevel@tonic-gate again:
9317c478bd9Sstevel@tonic-gate if (!zss->sl_xstandby) {
9327c478bd9Sstevel@tonic-gate if (tmp)
9337c478bd9Sstevel@tonic-gate zss->sl_xstandby = tmp;
9347c478bd9Sstevel@tonic-gate else {
9357c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9367c478bd9Sstevel@tonic-gate tmp = getq(wq);
9377c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9387c478bd9Sstevel@tonic-gate if (tmp)
9397c478bd9Sstevel@tonic-gate goto again;
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate } else if (tmp) {
9427c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9437c478bd9Sstevel@tonic-gate (void) putbq(wq, tmp);
9447c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_XMT_INPROG) {
9487c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END,
9527c478bd9Sstevel@tonic-gate "zsh_wput end: zs = %p", zs);
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate return;
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate if (!zss->sl_wd_id) {
9587c478bd9Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
9597c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
9607c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9617c478bd9Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs,
9627c478bd9Sstevel@tonic-gate SIO_WATCHDOG_TICK);
9637c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
9677c478bd9Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) ||
9687c478bd9Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss))
9697c478bd9Sstevel@tonic-gate (void) zsh_start(zs, zss);
9707c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9717c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9727c478bd9Sstevel@tonic-gate break;
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate case M_PROTO:
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate * Here is where a clone device finds out about the
9777c478bd9Sstevel@tonic-gate * hardware it is going to attach to. The request is
9787c478bd9Sstevel@tonic-gate * validated and a ppa is extracted from it and validated.
9797c478bd9Sstevel@tonic-gate * This number is used to index the hardware data structure
9807c478bd9Sstevel@tonic-gate * and the protocol data structure, in case the latter
9817c478bd9Sstevel@tonic-gate * was not provided by a data-path open before this.
9827c478bd9Sstevel@tonic-gate */
9837c478bd9Sstevel@tonic-gate if (stp->str_state != STR_CLONE) {
9847c478bd9Sstevel@tonic-gate freemsg(mp);
9857c478bd9Sstevel@tonic-gate return;
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) {
9897c478bd9Sstevel@tonic-gate prim = DL_ATTACH_REQ;
9907c478bd9Sstevel@tonic-gate error = DL_BADPRIM;
9917c478bd9Sstevel@tonic-gate goto end_proto;
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
9947c478bd9Sstevel@tonic-gate prim = dlp->dl_primitive;
9957c478bd9Sstevel@tonic-gate if (prim != DL_ATTACH_REQ) {
9967c478bd9Sstevel@tonic-gate error = DL_BADPRIM;
9977c478bd9Sstevel@tonic-gate goto end_proto;
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate ppa = dlp->attach_req.dl_ppa;
10007c478bd9Sstevel@tonic-gate ppa = (ppa%2) ? ((ppa-1)*2 +1) : (ppa*2);
10017c478bd9Sstevel@tonic-gate if (ppa >= maxzsh) {
10027c478bd9Sstevel@tonic-gate error = DL_BADPPA;
10037c478bd9Sstevel@tonic-gate goto end_proto;
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate zs = &zscom[ppa];
10067c478bd9Sstevel@tonic-gate if (zs->zs_ops == NULL) {
10077c478bd9Sstevel@tonic-gate error = ENXIO;
10087c478bd9Sstevel@tonic-gate goto end_proto;
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10117c478bd9Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
10127c478bd9Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
10137c478bd9Sstevel@tonic-gate /*
10147c478bd9Sstevel@tonic-gate * another protocol got here first
10157c478bd9Sstevel@tonic-gate */
10167c478bd9Sstevel@tonic-gate error = (EBUSY);
10177c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10187c478bd9Sstevel@tonic-gate goto end_proto;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate stp->str_com = (caddr_t)zs;
10237c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10247c478bd9Sstevel@tonic-gate end_proto:
10257c478bd9Sstevel@tonic-gate if (error)
10267c478bd9Sstevel@tonic-gate dlerrorack(wq, mp, prim, error, 0);
10277c478bd9Sstevel@tonic-gate else
10287c478bd9Sstevel@tonic-gate dlokack(wq, mp, DL_ATTACH_REQ);
10297c478bd9Sstevel@tonic-gate break;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate case M_IOCTL:
10327c478bd9Sstevel@tonic-gate zsh_ioctl(wq, mp);
10337c478bd9Sstevel@tonic-gate break;
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate case M_IOCDATA:
10367c478bd9Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr;
10377c478bd9Sstevel@tonic-gate if (resp->cp_rval) {
10387c478bd9Sstevel@tonic-gate /*
10397c478bd9Sstevel@tonic-gate * Just free message on failure.
10407c478bd9Sstevel@tonic-gate */
10417c478bd9Sstevel@tonic-gate freemsg(mp);
10427c478bd9Sstevel@tonic-gate break;
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate switch (resp->cp_cmd) {
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate case S_IOCGETMODE:
10487c478bd9Sstevel@tonic-gate case S_IOCGETSTATS:
10497c478bd9Sstevel@tonic-gate case S_IOCGETSPEED:
10507c478bd9Sstevel@tonic-gate case S_IOCGETMCTL:
10517c478bd9Sstevel@tonic-gate case S_IOCGETMRU:
10527c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10537c478bd9Sstevel@tonic-gate qreply(wq, mp);
10547c478bd9Sstevel@tonic-gate break;
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate case S_IOCSETMODE:
10577c478bd9Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
10587c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10597c478bd9Sstevel@tonic-gate error = zsh_setmode(zs, zss,
10607c478bd9Sstevel@tonic-gate (struct scc_mode *)mp->b_cont->b_rptr);
10617c478bd9Sstevel@tonic-gate if (error) {
10627c478bd9Sstevel@tonic-gate register struct iocblk *iocp =
10637c478bd9Sstevel@tonic-gate (struct iocblk *)mp->b_rptr;
10647c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
10657c478bd9Sstevel@tonic-gate iocp->ioc_error = error;
10667c478bd9Sstevel@tonic-gate } else
10677c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10687c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10697c478bd9Sstevel@tonic-gate qreply(wq, mp);
10707c478bd9Sstevel@tonic-gate break;
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate case S_IOCSETMRU:
10737c478bd9Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
10747c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10757c478bd9Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr;
10767c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10777c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10787c478bd9Sstevel@tonic-gate qreply(wq, mp);
10797c478bd9Sstevel@tonic-gate break;
10807c478bd9Sstevel@tonic-gate default:
10817c478bd9Sstevel@tonic-gate freemsg(mp);
10827c478bd9Sstevel@tonic-gate }
10837c478bd9Sstevel@tonic-gate break;
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate /*
10867c478bd9Sstevel@tonic-gate * We're at the bottom of the food chain, so we flush our
10877c478bd9Sstevel@tonic-gate * write queue, clear the FLUSHW bit so it doesn't go round
10887c478bd9Sstevel@tonic-gate * and round forever, then flush our read queue (since there's
10897c478bd9Sstevel@tonic-gate * no read put procedure down here) and pass it up for any
10907c478bd9Sstevel@tonic-gate * higher modules to deal with in their own way.
10917c478bd9Sstevel@tonic-gate */
10927c478bd9Sstevel@tonic-gate case M_FLUSH:
10937c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
10947c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10957c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA);
10967c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
10977c478bd9Sstevel@tonic-gate tmp = zss->sl_xstandby;
10987c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
10997c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11007c478bd9Sstevel@tonic-gate if (tmp)
11017c478bd9Sstevel@tonic-gate freemsg(tmp);
11027c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11037c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
11077c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
11087c478bd9Sstevel@tonic-gate ZSH_FLUSHQ;
11097c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11107c478bd9Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */
11117c478bd9Sstevel@tonic-gate } else
11127c478bd9Sstevel@tonic-gate freemsg(mp);
11137c478bd9Sstevel@tonic-gate break;
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate default:
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age,
11187c478bd9Sstevel@tonic-gate * thank you anyway."
11197c478bd9Sstevel@tonic-gate */
11207c478bd9Sstevel@tonic-gate freemsg(mp);
11217c478bd9Sstevel@tonic-gate break;
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END, "zsh_wput end: zs = %p", zs);
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate /*
11287c478bd9Sstevel@tonic-gate * Get the next message from the write queue, set up the necessary pointers,
11297c478bd9Sstevel@tonic-gate * state info, etc., and start the transmit "engine" by sending the first
11307c478bd9Sstevel@tonic-gate * character. We'll then rotate through txint until done, then get an xsint.
11317c478bd9Sstevel@tonic-gate */
11327c478bd9Sstevel@tonic-gate static int
zsh_start(struct zscom * zs,struct syncline * zss)11337c478bd9Sstevel@tonic-gate zsh_start(struct zscom *zs, struct syncline *zss)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate register mblk_t *mp;
11367c478bd9Sstevel@tonic-gate register uchar_t *wptr;
11377c478bd9Sstevel@tonic-gate register uchar_t *rptr;
11387c478bd9Sstevel@tonic-gate register uchar_t sl_flags = zss->sl_flags;
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate * Attempt to grab the next M_DATA message off the queue (that's
11427c478bd9Sstevel@tonic-gate * all that will be left after wput) and begin transmission.
11437c478bd9Sstevel@tonic-gate * This routine is normally called after completion of a previous
11447c478bd9Sstevel@tonic-gate * frame, or when zsh_wput gets a new message. If we are in a
11457c478bd9Sstevel@tonic-gate * mode that put us in the TX_RTS state, waiting for CTS, and CTS
11467c478bd9Sstevel@tonic-gate * is not up yet, we have no business here. Ditto if we're in
11477c478bd9Sstevel@tonic-gate * either the TX_ACTIVE or TX_CRC states. In these cases we
11487c478bd9Sstevel@tonic-gate * don't clear SF_CALLSTART, so we don't forget there's work to do.
11497c478bd9Sstevel@tonic-gate */
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_START,
11527c478bd9Sstevel@tonic-gate "zsh_start start: zs = %p", zs);
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate if (sl_flags & SF_PHONY) {
11557c478bd9Sstevel@tonic-gate sl_flags &= ~SF_PHONY;
11567c478bd9Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
11577c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
11587c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
11597c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
11607c478bd9Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
11617c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
11627c478bd9Sstevel@tonic-gate /*
11637c478bd9Sstevel@tonic-gate * if we get another msg by chance zsh_watchog will start
11647c478bd9Sstevel@tonic-gate */
11657c478bd9Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG;
11667c478bd9Sstevel@tonic-gate zss->sl_flags = sl_flags;
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
11697c478bd9Sstevel@tonic-gate "zsh_start end: zs = %d", zs);
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate return (0);
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate mp = zss->sl_xstandby;
11747c478bd9Sstevel@tonic-gate if (mp == NULL) {
11757c478bd9Sstevel@tonic-gate if (!(sl_flags & SF_FDXPTP)) {
11767c478bd9Sstevel@tonic-gate sl_flags |= SF_PHONY;
11777c478bd9Sstevel@tonic-gate ZSH_ALLOCB(mp);
11787c478bd9Sstevel@tonic-gate if (!mp)
11797c478bd9Sstevel@tonic-gate return (0);
11807c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_RSE;
11817c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + 1;
11827c478bd9Sstevel@tonic-gate goto transmit;
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG;
11857c478bd9Sstevel@tonic-gate zss->sl_flags = sl_flags;
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
11887c478bd9Sstevel@tonic-gate "zsh_start end: zs = %p", zs);
11897c478bd9Sstevel@tonic-gate
11907c478bd9Sstevel@tonic-gate return (0);
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate transmit:
11947c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
11957c478bd9Sstevel@tonic-gate rptr = mp->b_rptr;
11967c478bd9Sstevel@tonic-gate wptr = mp->b_wptr;
11977c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate #ifdef ZSH_DEBUG
12007c478bd9Sstevel@tonic-gate if (zss->sl_xhead || zss->sl_xactb) {
12017c478bd9Sstevel@tonic-gate debug_enter("xhead1");
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate #endif
12047c478bd9Sstevel@tonic-gate
12057c478bd9Sstevel@tonic-gate zss->sl_xhead = mp;
12067c478bd9Sstevel@tonic-gate zss->sl_xactb = mp;
12077c478bd9Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
12087c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_ACTIVE;
12097c478bd9Sstevel@tonic-gate zss->sl_ocnt = 0;
12107c478bd9Sstevel@tonic-gate SCC_BIS(10, ZSWR10_UNDERRUN_ABORT); /* abort on underrun */
12117c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXCRC); /* reset transmit CRC */
12127c478bd9Sstevel@tonic-gate zss->sl_ocnt = wptr - rptr;
12137c478bd9Sstevel@tonic-gate mp->b_wptr = rptr; /* to tell soft to free this msg */
12147c478bd9Sstevel@tonic-gate SCC_WRITEDATA(*rptr++); /* resets TXINT */
12157c478bd9Sstevel@tonic-gate zs->zs_wr_cur = rptr;
12167c478bd9Sstevel@tonic-gate zs->zs_wr_lim = wptr;
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_EOM);
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
12217c478bd9Sstevel@tonic-gate "zsh_start end: zs = %p", zs);
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate zss->sl_flags = sl_flags;
12247c478bd9Sstevel@tonic-gate return (1);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate /*
12297c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us.
12307c478bd9Sstevel@tonic-gate */
12317c478bd9Sstevel@tonic-gate static void
zsh_ioctl(queue_t * wq,mblk_t * mp)12327c478bd9Sstevel@tonic-gate zsh_ioctl(queue_t *wq, mblk_t *mp)
12337c478bd9Sstevel@tonic-gate {
12347c478bd9Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr;
12357c478bd9Sstevel@tonic-gate register struct zscom *zs = (struct zscom *)stp->str_com;
12367c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
12377c478bd9Sstevel@tonic-gate register struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
12387c478bd9Sstevel@tonic-gate register struct scc_mode *sm;
12397c478bd9Sstevel@tonic-gate register struct sl_stats *st;
12407c478bd9Sstevel@tonic-gate register uchar_t *msignals;
12417c478bd9Sstevel@tonic-gate register mblk_t *tmp;
12427c478bd9Sstevel@tonic-gate register int error = 0;
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
12457c478bd9Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
12467c478bd9Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
12477c478bd9Sstevel@tonic-gate /*
12487c478bd9Sstevel@tonic-gate * another protocol got here first
12497c478bd9Sstevel@tonic-gate */
12507c478bd9Sstevel@tonic-gate error = (EBUSY);
12517c478bd9Sstevel@tonic-gate goto end_zsh_ioctl;
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate case S_IOCGETMODE:
12587c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (struct scc_mode), BPRI_MED);
12597c478bd9Sstevel@tonic-gate if (tmp == NULL) {
12607c478bd9Sstevel@tonic-gate error = EAGAIN;
12617c478bd9Sstevel@tonic-gate break;
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12647c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct scc_mode), 0);
12657c478bd9Sstevel@tonic-gate else
12667c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct scc_mode), NULL, tmp);
12677c478bd9Sstevel@tonic-gate sm = (struct scc_mode *)mp->b_cont->b_rptr;
12687c478bd9Sstevel@tonic-gate bcopy(&zss->sl_mode, sm, sizeof (struct scc_mode));
12697c478bd9Sstevel@tonic-gate break;
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate case S_IOCGETSTATS:
12727c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (struct sl_stats), BPRI_MED);
12737c478bd9Sstevel@tonic-gate if (tmp == NULL) {
12747c478bd9Sstevel@tonic-gate error = EAGAIN;
12757c478bd9Sstevel@tonic-gate break;
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12787c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct sl_stats), 0);
12797c478bd9Sstevel@tonic-gate else
12807c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct sl_stats), NULL, tmp);
12817c478bd9Sstevel@tonic-gate st = (struct sl_stats *)mp->b_cont->b_rptr;
12827c478bd9Sstevel@tonic-gate bcopy(&zss->sl_st, st, sizeof (struct sl_stats));
12837c478bd9Sstevel@tonic-gate break;
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate case S_IOCGETSPEED:
12867c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED);
12877c478bd9Sstevel@tonic-gate if (tmp == NULL) {
12887c478bd9Sstevel@tonic-gate error = EAGAIN;
12897c478bd9Sstevel@tonic-gate break;
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12927c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0);
12937c478bd9Sstevel@tonic-gate else
12947c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp);
12957c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mode.sm_baudrate;
12967c478bd9Sstevel@tonic-gate break;
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate case S_IOCGETMCTL:
12997c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (char), BPRI_MED);
13007c478bd9Sstevel@tonic-gate if (tmp == NULL) {
13017c478bd9Sstevel@tonic-gate error = EAGAIN;
13027c478bd9Sstevel@tonic-gate break;
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
13057c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (char), 0);
13067c478bd9Sstevel@tonic-gate else
13077c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (char), NULL, tmp);
13087c478bd9Sstevel@tonic-gate msignals = (uchar_t *)mp->b_cont->b_rptr;
13097c478bd9Sstevel@tonic-gate *msignals = zss->sl_rr0 & (ZSRR0_CD | ZSRR0_CTS);
13107c478bd9Sstevel@tonic-gate break;
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate case S_IOCGETMRU:
13137c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED);
13147c478bd9Sstevel@tonic-gate if (tmp == NULL) {
13157c478bd9Sstevel@tonic-gate error = EAGAIN;
13167c478bd9Sstevel@tonic-gate break;
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
13197c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0);
13207c478bd9Sstevel@tonic-gate else
13217c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp);
13227c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mru;
13237c478bd9Sstevel@tonic-gate break;
13247c478bd9Sstevel@tonic-gate
13257c478bd9Sstevel@tonic-gate case S_IOCSETMODE:
13267c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) {
13277c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct scc_mode));
13287c478bd9Sstevel@tonic-gate if (error != 0)
13297c478bd9Sstevel@tonic-gate break;
13307c478bd9Sstevel@tonic-gate error = zsh_setmode(zs, zss,
13317c478bd9Sstevel@tonic-gate (struct scc_mode *)mp->b_cont->b_rptr);
13327c478bd9Sstevel@tonic-gate if (error == 0)
13337c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13347c478bd9Sstevel@tonic-gate } else
13357c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (struct scc_mode), NULL);
13367c478bd9Sstevel@tonic-gate break;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate case S_IOCCLRSTATS:
13397c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13407c478bd9Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats));
13417c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
13427c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13437c478bd9Sstevel@tonic-gate break;
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate case S_IOCSETMRU:
13467c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) {
13477c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
13487c478bd9Sstevel@tonic-gate if (error != 0)
13497c478bd9Sstevel@tonic-gate break;
13507c478bd9Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr;
13517c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13527c478bd9Sstevel@tonic-gate } else
13537c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL);
13547c478bd9Sstevel@tonic-gate break;
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate case S_IOCSETDTR:
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate * The first integer of the M_DATA block that should
13597c478bd9Sstevel@tonic-gate * follow indicate if DTR must be set or reset
13607c478bd9Sstevel@tonic-gate */
13617c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
13627c478bd9Sstevel@tonic-gate if (error != 0)
13637c478bd9Sstevel@tonic-gate break;
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13667c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0)
13677c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIS);
13687c478bd9Sstevel@tonic-gate else
13697c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC);
13707c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
13717c478bd9Sstevel@tonic-gate break;
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate default:
13747c478bd9Sstevel@tonic-gate error = EINVAL;
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate end_zsh_ioctl:
13787c478bd9Sstevel@tonic-gate iocp->ioc_error = error;
13797c478bd9Sstevel@tonic-gate mp->b_datap->db_type = (error) ? M_IOCNAK : M_IOCACK;
13807c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
13817c478bd9Sstevel@tonic-gate qreply(wq, mp);
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate
13847c478bd9Sstevel@tonic-gate /*
13857c478bd9Sstevel@tonic-gate * Set the mode of the zsh port
13867c478bd9Sstevel@tonic-gate */
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate int
zsh_setmode(struct zscom * zs,struct syncline * zss,struct scc_mode * sm)13897c478bd9Sstevel@tonic-gate zsh_setmode(struct zscom *zs, struct syncline *zss, struct scc_mode *sm)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate register int error = 0;
13927c478bd9Sstevel@tonic-gate register mblk_t *mp;
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13957c478bd9Sstevel@tonic-gate if (sm->sm_rxclock == RXC_IS_PLL) {
13967c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC;
13977c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
13987c478bd9Sstevel@tonic-gate return (EINVAL); /* not supported */
13997c478bd9Sstevel@tonic-gate } else {
14007c478bd9Sstevel@tonic-gate if (((zss->sl_mode.sm_config ^ sm->sm_config) &
14017c478bd9Sstevel@tonic-gate CONN_SIGNAL) != 0) { /* Changing, going... */
14027c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL) { /* ...up. */
14037c478bd9Sstevel@tonic-gate if (zss->sl_mstat == NULL) {
14047c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14057c478bd9Sstevel@tonic-gate mp = allocb(
140619397407SSherry Moore sizeof (struct sl_status),
140719397407SSherry Moore BPRI_MED);
14087c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14097c478bd9Sstevel@tonic-gate zss->sl_mstat = mp;
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate } else { /* ...down. */
14127c478bd9Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL)
14137c478bd9Sstevel@tonic-gate zss->sl_mstat = NULL;
14147c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14157c478bd9Sstevel@tonic-gate if (mp)
14167c478bd9Sstevel@tonic-gate freemsg(mp);
14177c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate if (!(sm->sm_config & CONN_IBM)) {
14217c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_HDX) {
14227c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_HDX;
14237c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14247c478bd9Sstevel@tonic-gate return (EINVAL);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_MPT) {
14277c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_MPT;
14287c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14297c478bd9Sstevel@tonic-gate return (EINVAL);
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate }
14327c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FDXPTP; /* "conmode" */
14337c478bd9Sstevel@tonic-gate if ((sm->sm_config & (CONN_HDX | CONN_MPT)) == 0)
14347c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_FDXPTP;
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate error = zsh_program(zs, sm);
14377c478bd9Sstevel@tonic-gate if (!error && (zs->zs_ops != &zsops_null))
14387c478bd9Sstevel@tonic-gate zsh_init_port(zs, zss);
14397c478bd9Sstevel@tonic-gate }
14407c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate return (error);
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate /*
14467c478bd9Sstevel@tonic-gate * Transmit interrupt service procedure
14477c478bd9Sstevel@tonic-gate */
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate static void
zsh_txint(struct zscom * zs)14507c478bd9Sstevel@tonic-gate zsh_txint(struct zscom *zs)
14517c478bd9Sstevel@tonic-gate {
14527c478bd9Sstevel@tonic-gate register struct syncline *zss;
14537c478bd9Sstevel@tonic-gate register mblk_t *mp;
14547c478bd9Sstevel@tonic-gate register int tmp;
14557c478bd9Sstevel@tonic-gate register uchar_t *wr_cur;
14567c478bd9Sstevel@tonic-gate
14577c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_TXINT, "zsh_txint: zs = %p", zs);
14587c478bd9Sstevel@tonic-gate
14597c478bd9Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL && (wr_cur < zs->zs_wr_lim)) {
14607c478bd9Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++);
14617c478bd9Sstevel@tonic-gate zs->zs_wr_cur = wr_cur;
14627c478bd9Sstevel@tonic-gate return;
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate switch (zss->sl_txstate) {
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate * we here because end of message block lim = cur
14727c478bd9Sstevel@tonic-gate */
14737c478bd9Sstevel@tonic-gate case TX_ACTIVE:
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate mp = zss->sl_xactb;
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate again_txint:
14787c478bd9Sstevel@tonic-gate mp = mp->b_cont;
14797c478bd9Sstevel@tonic-gate if (mp) {
14807c478bd9Sstevel@tonic-gate zss->sl_xactb = mp;
14817c478bd9Sstevel@tonic-gate zss->sl_ocnt += tmp = mp->b_wptr - mp->b_rptr;
14827c478bd9Sstevel@tonic-gate if (!tmp)
14837c478bd9Sstevel@tonic-gate goto again_txint;
14847c478bd9Sstevel@tonic-gate zs->zs_wr_cur = mp->b_rptr;
14857c478bd9Sstevel@tonic-gate zs->zs_wr_lim = mp->b_wptr;
14867c478bd9Sstevel@tonic-gate SCC_WRITEDATA(*zs->zs_wr_cur++);
14877c478bd9Sstevel@tonic-gate return;
14887c478bd9Sstevel@tonic-gate }
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * This is where the fun starts. At this point the
14927c478bd9Sstevel@tonic-gate * last character in the frame has been sent. We
14937c478bd9Sstevel@tonic-gate * issue a RESET_TXINT so we won't get another txint
14947c478bd9Sstevel@tonic-gate * until the CRC has been completely sent. Also we
14957c478bd9Sstevel@tonic-gate * reset the Abort-On-Underrun bit so that CRC is
14967c478bd9Sstevel@tonic-gate * sent at EOM, rather than an Abort.
14977c478bd9Sstevel@tonic-gate */
14987c478bd9Sstevel@tonic-gate zs->zs_wr_cur = zs->zs_wr_lim = NULL;
14997c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_CRC;
15007c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15017c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY)) {
15027c478bd9Sstevel@tonic-gate SCC_BIC(10, ZSWR10_UNDERRUN_ABORT);
15037c478bd9Sstevel@tonic-gate zss->sl_st.opack++;
15047c478bd9Sstevel@tonic-gate zss->sl_st.ochar += zss->sl_ocnt;
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate zss->sl_ocnt = 0;
15077c478bd9Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead);
15087c478bd9Sstevel@tonic-gate zss->sl_xhead = zss->sl_xactb = NULL;
15097c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
15107c478bd9Sstevel@tonic-gate break;
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate * This txint means we have sent the CRC bytes at EOF.
15137c478bd9Sstevel@tonic-gate * The next txint will mean we are sending or have sent the
15147c478bd9Sstevel@tonic-gate * flag character at EOF, but we handle that differently, and
15157c478bd9Sstevel@tonic-gate * enter different states,depending on whether we're IBM or not.
15167c478bd9Sstevel@tonic-gate */
15177c478bd9Sstevel@tonic-gate case TX_CRC:
15187c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
15197c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_FLAG; /* HDX path */
15207c478bd9Sstevel@tonic-gate } else { /* FDX path */
15217c478bd9Sstevel@tonic-gate if (!zsh_start(zs, zss)) {
15227c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
15237c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15247c478bd9Sstevel@tonic-gate }
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate break;
15277c478bd9Sstevel@tonic-gate
15287c478bd9Sstevel@tonic-gate /*
15297c478bd9Sstevel@tonic-gate * This txint means the closing flag byte is going out the door.
15307c478bd9Sstevel@tonic-gate * We use this state to allow this to complete before dropping RTS.
15317c478bd9Sstevel@tonic-gate */
15327c478bd9Sstevel@tonic-gate case TX_FLAG:
15337c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_LAST;
15347c478bd9Sstevel@tonic-gate (void) zsh_start(zs, zss);
15357c478bd9Sstevel@tonic-gate break;
15367c478bd9Sstevel@tonic-gate
15377c478bd9Sstevel@tonic-gate /*
15387c478bd9Sstevel@tonic-gate * Arriving here means the flag should be out and it's finally
15397c478bd9Sstevel@tonic-gate * time to close the barn door.
15407c478bd9Sstevel@tonic-gate */
15417c478bd9Sstevel@tonic-gate case TX_LAST:
15427c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
15437c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15447c478bd9Sstevel@tonic-gate break;
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate /*
15477c478bd9Sstevel@tonic-gate * If transmit was aborted, do nothing - watchdog will recover.
15487c478bd9Sstevel@tonic-gate */
15497c478bd9Sstevel@tonic-gate case TX_ABORTED:
15507c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15517c478bd9Sstevel@tonic-gate break;
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate default:
15547c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15557c478bd9Sstevel@tonic-gate break;
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate /*
15607c478bd9Sstevel@tonic-gate * External Status Change interrupt service procedure
15617c478bd9Sstevel@tonic-gate */
15627c478bd9Sstevel@tonic-gate static void
zsh_xsint(struct zscom * zs)15637c478bd9Sstevel@tonic-gate zsh_xsint(struct zscom *zs)
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
15667c478bd9Sstevel@tonic-gate register uchar_t s0, x0;
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_XSINT, "zsh_xsint: zs = %p", zs);
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
15717c478bd9Sstevel@tonic-gate x0 = s0 ^ zss->sl_rr0;
15727c478bd9Sstevel@tonic-gate zss->sl_rr0 = s0;
15737c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate if (s0 & ZSRR0_TXUNDER) {
15767c478bd9Sstevel@tonic-gate switch (zss->sl_txstate) {
15777c478bd9Sstevel@tonic-gate /*
15787c478bd9Sstevel@tonic-gate * A transmitter underrun has occurred. If we are not
15797c478bd9Sstevel@tonic-gate * here as the result of an abort sent by the watchdog
15807c478bd9Sstevel@tonic-gate * timeout routine, we need to send an abort to flush
15817c478bd9Sstevel@tonic-gate * the transmitter. Otherwise there is a danger of
15827c478bd9Sstevel@tonic-gate * trashing the next frame but still sending a good crc.
15837c478bd9Sstevel@tonic-gate * The TX_ABORTED flag is set so that the watchdog
15847c478bd9Sstevel@tonic-gate * routine can initiate recovery.
15857c478bd9Sstevel@tonic-gate */
15867c478bd9Sstevel@tonic-gate case TX_ACTIVE:
15877c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
15887c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15897c478bd9Sstevel@tonic-gate zss->sl_st.underrun++;
15907c478bd9Sstevel@tonic-gate zsh_txbad(zs, zss);
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED;
15937c478bd9Sstevel@tonic-gate zss->sl_wd_count = 0;
15947c478bd9Sstevel@tonic-gate break;
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate case TX_CRC:
15977c478bd9Sstevel@tonic-gate break;
15987c478bd9Sstevel@tonic-gate
15997c478bd9Sstevel@tonic-gate case TX_FLAG:
16007c478bd9Sstevel@tonic-gate break;
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate case TX_ABORTED:
16037c478bd9Sstevel@tonic-gate break;
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate case TX_OFF:
16067c478bd9Sstevel@tonic-gate break;
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate case TX_LAST:
16097c478bd9Sstevel@tonic-gate break;
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate default:
16127c478bd9Sstevel@tonic-gate break;
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) && zs->zs_rd_cur) {
16177c478bd9Sstevel@tonic-gate zss->sl_st.abort++;
16187c478bd9Sstevel@tonic-gate zsh_rxbad(zs, zss);
16197c478bd9Sstevel@tonic-gate } else if ((s0 & ZSRR0_SYNC) && (zs->zs_rd_cur)) {
16207c478bd9Sstevel@tonic-gate /*
16217c478bd9Sstevel@tonic-gate * Tricky code to avoid disaster in the case where
16227c478bd9Sstevel@tonic-gate * an abort was detected while receiving a packet,
16237c478bd9Sstevel@tonic-gate * but the abort did not last long enough to be
16247c478bd9Sstevel@tonic-gate * detected by zsh_xsint - this can happen since
16257c478bd9Sstevel@tonic-gate * the ZSRR0_BREAK is not latched. Since an abort
16267c478bd9Sstevel@tonic-gate * will automatically cause the SCC to enter
16277c478bd9Sstevel@tonic-gate * hunt mode, hopefully, the sync/hunt bit will be
16287c478bd9Sstevel@tonic-gate * set in this case (although if the interrupt is
16297c478bd9Sstevel@tonic-gate * sufficiently delayed, the SCC may have sync'ed
16307c478bd9Sstevel@tonic-gate * in again if it has detected a flag).
16317c478bd9Sstevel@tonic-gate */
16327c478bd9Sstevel@tonic-gate zss->sl_st.abort++;
16337c478bd9Sstevel@tonic-gate zsh_rxbad(zs, zss);
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate
16367c478bd9Sstevel@tonic-gate if (x0 & s0 & ZSRR0_CTS) {
16377c478bd9Sstevel@tonic-gate if (zss->sl_txstate == TX_RTS) {
16387c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
16397c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate (void) zsh_start(zs, zss);
164219397407SSherry Moore } else if ((zss->sl_mode.sm_config &
164319397407SSherry Moore (CONN_IBM | CONN_SIGNAL))) {
16447c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
16457c478bd9Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate }
16487c478bd9Sstevel@tonic-gate
16497c478bd9Sstevel@tonic-gate /*
16507c478bd9Sstevel@tonic-gate * We don't care about CTS transitions unless we are in either
16517c478bd9Sstevel@tonic-gate * IBM or SIGNAL mode, or both. So, if we see CTS drop, and we
16527c478bd9Sstevel@tonic-gate * care, and we are not idle, send up a report message.
16537c478bd9Sstevel@tonic-gate */
16547c478bd9Sstevel@tonic-gate if ((x0 & ZSRR0_CTS) && ((s0 & ZSRR0_CTS) == 0) &&
16557c478bd9Sstevel@tonic-gate (zss->sl_txstate != TX_OFF) &&
16567c478bd9Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_IBM | CONN_SIGNAL))) {
16577c478bd9Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
16587c478bd9Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_DOWN);
16597c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG;
16607c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ;
16617c478bd9Sstevel@tonic-gate zss->sl_st.cts++;
16627c478bd9Sstevel@tonic-gate if (zss->sl_txstate != TX_IDLE)
16637c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
16647c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
16657c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16667c478bd9Sstevel@tonic-gate zss->sl_wd_count = 0;
16677c478bd9Sstevel@tonic-gate zsh_txbad(zs, zss);
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate /*
16737c478bd9Sstevel@tonic-gate * Receive interrupt service procedure
16747c478bd9Sstevel@tonic-gate */
16757c478bd9Sstevel@tonic-gate static void
zsh_rxint(struct zscom * zs)16767c478bd9Sstevel@tonic-gate zsh_rxint(struct zscom *zs)
16777c478bd9Sstevel@tonic-gate {
16787c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
16797c478bd9Sstevel@tonic-gate register mblk_t *bp = zss->sl_ractb;
16807c478bd9Sstevel@tonic-gate unsigned char *rd_cur;
16817c478bd9Sstevel@tonic-gate
16827c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_RXINT, "zsh_rxint: zs = %p", zs);
16837c478bd9Sstevel@tonic-gate
16847c478bd9Sstevel@tonic-gate if (((rd_cur = zs->zs_rd_cur) != NULL) && rd_cur < zs->zs_rd_lim) {
16857c478bd9Sstevel@tonic-gate *rd_cur++ = SCC_READDATA();
16867c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur;
16877c478bd9Sstevel@tonic-gate return;
16887c478bd9Sstevel@tonic-gate }
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate if (!rd_cur) { /* Beginning of frame */
16917c478bd9Sstevel@tonic-gate if (!bp) {
16927c478bd9Sstevel@tonic-gate ZSH_ALLOCB(bp);
16937c478bd9Sstevel@tonic-gate zss->sl_ractb = bp;
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate zss->sl_rhead = bp;
16967c478bd9Sstevel@tonic-gate } else { /* end of data block should be cur==lim */
16977c478bd9Sstevel@tonic-gate bp->b_wptr = zs->zs_rd_cur;
16987c478bd9Sstevel@tonic-gate ZSH_ALLOCB(bp->b_cont);
16997c478bd9Sstevel@tonic-gate bp = zss->sl_ractb = bp->b_cont;
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate if (!bp) {
17027c478bd9Sstevel@tonic-gate zss->sl_st.nobuffers++;
17037c478bd9Sstevel@tonic-gate zsh_rxbad(zs, zss);
17047c478bd9Sstevel@tonic-gate return;
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate zs->zs_rd_cur = bp->b_wptr;
17077c478bd9Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim;
17087c478bd9Sstevel@tonic-gate *zs->zs_rd_cur++ = SCC_READDATA(); /* Also resets interrupt */
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate
17127c478bd9Sstevel@tonic-gate /*
17137c478bd9Sstevel@tonic-gate * Special Receive Condition Interrupt routine
17147c478bd9Sstevel@tonic-gate */
17157c478bd9Sstevel@tonic-gate static void
zsh_srint(struct zscom * zs)17167c478bd9Sstevel@tonic-gate zsh_srint(struct zscom *zs)
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
17197c478bd9Sstevel@tonic-gate register uchar_t s1;
17207c478bd9Sstevel@tonic-gate register uchar_t *rd_cur;
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SRINT, "zsh_srint: zs = %p", zs);
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate SCC_READ(1, s1);
17257c478bd9Sstevel@tonic-gate
17267c478bd9Sstevel@tonic-gate if (s1 & ZSRR1_RXEOF) { /* end of frame */
17277c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
17287c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17297c478bd9Sstevel@tonic-gate if (s1 & ZSRR1_FE) { /* bad CRC */
17307c478bd9Sstevel@tonic-gate zss->sl_st.crc++;
17317c478bd9Sstevel@tonic-gate zsh_rxbad(zs, zss);
17327c478bd9Sstevel@tonic-gate return;
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate if ((rd_cur = zs->zs_rd_cur) == NULL)
17367c478bd9Sstevel@tonic-gate return;
17377c478bd9Sstevel@tonic-gate
17387c478bd9Sstevel@tonic-gate /*
17397c478bd9Sstevel@tonic-gate * Drop one CRC byte from length because it came in
17407c478bd9Sstevel@tonic-gate * before the special interrupt got here.
17417c478bd9Sstevel@tonic-gate */
17427c478bd9Sstevel@tonic-gate zss->sl_ractb->b_wptr = rd_cur - 1;
17437c478bd9Sstevel@tonic-gate
17447c478bd9Sstevel@tonic-gate /*
17457c478bd9Sstevel@tonic-gate * put on done queue
17467c478bd9Sstevel@tonic-gate */
17477c478bd9Sstevel@tonic-gate ZSH_PUTQ(zss->sl_rhead);
17487c478bd9Sstevel@tonic-gate zss->sl_rhead = NULL;
17497c478bd9Sstevel@tonic-gate zss->sl_ractb = NULL;
17507c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
17517c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
17527c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate } else if (s1 & ZSRR1_DO) {
17557c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
17567c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17577c478bd9Sstevel@tonic-gate zss->sl_st.overrun++;
17587c478bd9Sstevel@tonic-gate zsh_rxbad(zs, zss);
17597c478bd9Sstevel@tonic-gate } else
17607c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate /*
17647c478bd9Sstevel@tonic-gate * Handle a second stage interrupt.
17657c478bd9Sstevel@tonic-gate * Does mostly lower priority buffer management stuff.
17667c478bd9Sstevel@tonic-gate */
17677c478bd9Sstevel@tonic-gate static int
zsh_softint(struct zscom * zs)17687c478bd9Sstevel@tonic-gate zsh_softint(struct zscom *zs)
17697c478bd9Sstevel@tonic-gate {
17707c478bd9Sstevel@tonic-gate register struct syncline *zss;
17717c478bd9Sstevel@tonic-gate register queue_t *q;
17727c478bd9Sstevel@tonic-gate register mblk_t *mp, *tmp;
17737c478bd9Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL;
17747c478bd9Sstevel@tonic-gate register int allocbcount = 0;
17757c478bd9Sstevel@tonic-gate int m_error;
17767c478bd9Sstevel@tonic-gate
17777c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_START, "zsh_soft start: zs = %p", zs);
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
17807c478bd9Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
17817c478bd9Sstevel@tonic-gate if (!zss || (q = zss->sl_stream.str_rq) == NULL) {
17827c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
17837c478bd9Sstevel@tonic-gate return (0);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate m_error = zss->sl_m_error;
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate zss->sl_m_error = 0;
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate if (!zss->sl_mstat)
17917c478bd9Sstevel@tonic-gate zss->sl_mstat = allocb(sizeof (struct sl_status), BPRI_MED);
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
17947c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
17957c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
17967c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
17977c478bd9Sstevel@tonic-gate } else {
17987c478bd9Sstevel@tonic-gate register uchar_t s0;
17997c478bd9Sstevel@tonic-gate
18007c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
18017c478bd9Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
18027c478bd9Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
18037c478bd9Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
18047c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
18057c478bd9Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP);
18067c478bd9Sstevel@tonic-gate }
18077c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
18087c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18097c478bd9Sstevel@tonic-gate flushq(WR(q), FLUSHDATA);
18107c478bd9Sstevel@tonic-gate goto next;
18117c478bd9Sstevel@tonic-gate }
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate next:
18177c478bd9Sstevel@tonic-gate for (;;) {
18187c478bd9Sstevel@tonic-gate ZSH_GETQ(mp);
18197c478bd9Sstevel@tonic-gate if (!mp)
18207c478bd9Sstevel@tonic-gate break;
18217c478bd9Sstevel@tonic-gate
18227c478bd9Sstevel@tonic-gate if (mp->b_rptr == mp->b_wptr) {
18237c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_RSE) {
18247c478bd9Sstevel@tonic-gate allocbcount++;
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate freemsg(mp);
18277c478bd9Sstevel@tonic-gate continue;
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) {
18307c478bd9Sstevel@tonic-gate zss->sl_st.ichar += msgdsize(mp);
18317c478bd9Sstevel@tonic-gate zss->sl_st.ipack++;
18327c478bd9Sstevel@tonic-gate if (!(canputnext(q))) {
18337c478bd9Sstevel@tonic-gate zss->sl_st.ierror++;
18347c478bd9Sstevel@tonic-gate allocbcount++;
18357c478bd9Sstevel@tonic-gate freemsg(mp);
18367c478bd9Sstevel@tonic-gate continue;
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate } else if (mp->b_datap->db_type == M_PROTO) {
18397c478bd9Sstevel@tonic-gate if (!(canputnext(q))) {
18407c478bd9Sstevel@tonic-gate freemsg(mp);
18417c478bd9Sstevel@tonic-gate continue;
18427c478bd9Sstevel@tonic-gate }
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate if (!head) {
18457c478bd9Sstevel@tonic-gate allocbcount++;
18467c478bd9Sstevel@tonic-gate zss->sl_soft_active = 1;
18477c478bd9Sstevel@tonic-gate head = mp;
18487c478bd9Sstevel@tonic-gate } else {
18497c478bd9Sstevel@tonic-gate if (!tail)
18507c478bd9Sstevel@tonic-gate tail = head;
18517c478bd9Sstevel@tonic-gate tail->b_next = mp;
18527c478bd9Sstevel@tonic-gate tail = mp;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate }
18557c478bd9Sstevel@tonic-gate if (allocbcount)
18567c478bd9Sstevel@tonic-gate ZSH_GETBLOCK(zs, allocbcount);
18577c478bd9Sstevel@tonic-gate
18587c478bd9Sstevel@tonic-gate tmp = NULL;
18597c478bd9Sstevel@tonic-gate again:
18607c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
18617c478bd9Sstevel@tonic-gate if (!zss->sl_xstandby) {
18627c478bd9Sstevel@tonic-gate if (tmp) {
18637c478bd9Sstevel@tonic-gate zss->sl_xstandby = tmp;
18647c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18657c478bd9Sstevel@tonic-gate } else {
18667c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18677c478bd9Sstevel@tonic-gate if (tmp = getq(WR(q)))
18687c478bd9Sstevel@tonic-gate goto again;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate } else {
18717c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18727c478bd9Sstevel@tonic-gate if (tmp)
18737c478bd9Sstevel@tonic-gate (void) putbq(WR(q), tmp);
18747c478bd9Sstevel@tonic-gate }
18757c478bd9Sstevel@tonic-gate
18767c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
18777c478bd9Sstevel@tonic-gate
18787c478bd9Sstevel@tonic-gate while (head) {
18797c478bd9Sstevel@tonic-gate if (!tail) {
18807c478bd9Sstevel@tonic-gate putnext(q, head);
18817c478bd9Sstevel@tonic-gate break;
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate mp = head;
18847c478bd9Sstevel@tonic-gate head = head->b_next;
18857c478bd9Sstevel@tonic-gate mp->b_next = NULL;
18867c478bd9Sstevel@tonic-gate putnext(q, mp);
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate
18907c478bd9Sstevel@tonic-gate if (m_error)
18917c478bd9Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error);
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate zss->sl_soft_active = 0;
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_END, "zsh_soft end: zs = %p", zs);
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate return (0);
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate /*
19017c478bd9Sstevel@tonic-gate * Initialization routine.
19027c478bd9Sstevel@tonic-gate * Sets Clock sources, baud rate, modes and miscellaneous parameters.
19037c478bd9Sstevel@tonic-gate */
19047c478bd9Sstevel@tonic-gate static int
zsh_program(struct zscom * zs,struct scc_mode * sm)19057c478bd9Sstevel@tonic-gate zsh_program(struct zscom *zs, struct scc_mode *sm)
19067c478bd9Sstevel@tonic-gate {
19077c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
19087c478bd9Sstevel@tonic-gate register struct zs_prog *zspp;
19097c478bd9Sstevel@tonic-gate register ushort_t tconst = 0;
19107c478bd9Sstevel@tonic-gate register int wr11 = 0;
19117c478bd9Sstevel@tonic-gate register int baud = 0;
19127c478bd9Sstevel@tonic-gate register int pll = 0;
19137c478bd9Sstevel@tonic-gate register int speed = 0;
19147c478bd9Sstevel@tonic-gate register int flags = ZSP_SYNC;
19157c478bd9Sstevel@tonic-gate int err = 0;
19167c478bd9Sstevel@tonic-gate
19177c478bd9Sstevel@tonic-gate ZSSETSOFT(zs); /* get our house in order */
19187c478bd9Sstevel@tonic-gate
19197c478bd9Sstevel@tonic-gate switch (sm->sm_txclock) {
19207c478bd9Sstevel@tonic-gate case TXC_IS_TXC:
19217c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_TRXC;
19227c478bd9Sstevel@tonic-gate break;
19237c478bd9Sstevel@tonic-gate case TXC_IS_RXC:
19247c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_RTXC;
19257c478bd9Sstevel@tonic-gate break;
19267c478bd9Sstevel@tonic-gate case TXC_IS_BAUD:
19277c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_BAUD;
19287c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_TRXC_OUT_ENA + ZSWR11_TRXC_XMIT;
19297c478bd9Sstevel@tonic-gate baud++;
19307c478bd9Sstevel@tonic-gate break;
19317c478bd9Sstevel@tonic-gate case TXC_IS_PLL:
19327c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_DPLL;
19337c478bd9Sstevel@tonic-gate pll++;
19347c478bd9Sstevel@tonic-gate break;
19357c478bd9Sstevel@tonic-gate default:
19367c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_TXC;
19377c478bd9Sstevel@tonic-gate err = EINVAL;
19387c478bd9Sstevel@tonic-gate goto out;
19397c478bd9Sstevel@tonic-gate }
19407c478bd9Sstevel@tonic-gate switch (sm->sm_rxclock) {
19417c478bd9Sstevel@tonic-gate case RXC_IS_RXC:
19427c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_RTXC;
19437c478bd9Sstevel@tonic-gate break;
19447c478bd9Sstevel@tonic-gate case RXC_IS_TXC:
19457c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_TRXC;
19467c478bd9Sstevel@tonic-gate break;
19477c478bd9Sstevel@tonic-gate case RXC_IS_BAUD:
19487c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_BAUD;
19497c478bd9Sstevel@tonic-gate baud++;
19507c478bd9Sstevel@tonic-gate break;
19517c478bd9Sstevel@tonic-gate case RXC_IS_PLL:
19527c478bd9Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_DPLL;
19537c478bd9Sstevel@tonic-gate pll++;
19547c478bd9Sstevel@tonic-gate break;
19557c478bd9Sstevel@tonic-gate default:
19567c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC;
19577c478bd9Sstevel@tonic-gate err = EINVAL;
19587c478bd9Sstevel@tonic-gate goto out;
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate if (baud && pll) {
19617c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL;
19627c478bd9Sstevel@tonic-gate err = EINVAL;
19637c478bd9Sstevel@tonic-gate goto out;
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate if (pll && !(sm->sm_config & CONN_NRZI)) {
19667c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL;
19677c478bd9Sstevel@tonic-gate err = EINVAL;
19687c478bd9Sstevel@tonic-gate goto out;
19697c478bd9Sstevel@tonic-gate }
19707c478bd9Sstevel@tonic-gate
19717c478bd9Sstevel@tonic-gate /*
19727c478bd9Sstevel@tonic-gate * If we're going to use the BRG and the speed we want is != 0...
19737c478bd9Sstevel@tonic-gate */
19747c478bd9Sstevel@tonic-gate if (baud && (speed = sm->sm_baudrate)) {
19757c478bd9Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2;
19767c478bd9Sstevel@tonic-gate if (tconst == 0) {
19777c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE;
19787c478bd9Sstevel@tonic-gate err = EINVAL;
19797c478bd9Sstevel@tonic-gate goto out;
19807c478bd9Sstevel@tonic-gate }
19817c478bd9Sstevel@tonic-gate sm->sm_baudrate = PCLK / (2 * ((int)tconst + 2));
19827c478bd9Sstevel@tonic-gate } else {
19837c478bd9Sstevel@tonic-gate tconst = 0; /* Stop BRG. Also quiesces pin 24. */
19847c478bd9Sstevel@tonic-gate }
19857c478bd9Sstevel@tonic-gate
19867c478bd9Sstevel@tonic-gate if (pll) {
19877c478bd9Sstevel@tonic-gate if ((speed = sm->sm_baudrate * 32) != 0)
19887c478bd9Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2;
19897c478bd9Sstevel@tonic-gate else
19907c478bd9Sstevel@tonic-gate tconst = 0;
19917c478bd9Sstevel@tonic-gate if (tconst == 0) {
19927c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE;
19937c478bd9Sstevel@tonic-gate err = EINVAL;
19947c478bd9Sstevel@tonic-gate goto out;
19957c478bd9Sstevel@tonic-gate }
19967c478bd9Sstevel@tonic-gate speed = PCLK / (2 * ((int)tconst + 2));
19977c478bd9Sstevel@tonic-gate sm->sm_baudrate = speed / 32;
19987c478bd9Sstevel@tonic-gate flags |= ZSP_PLL;
19997c478bd9Sstevel@tonic-gate }
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate if ((sm->sm_config & (CONN_LPBK|CONN_ECHO)) == (CONN_LPBK|CONN_ECHO)) {
20027c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_LPBKS;
20037c478bd9Sstevel@tonic-gate err = EINVAL;
20047c478bd9Sstevel@tonic-gate goto out;
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_LPBK)
20077c478bd9Sstevel@tonic-gate flags |= ZSP_LOOP;
20087c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_NRZI)
20097c478bd9Sstevel@tonic-gate flags |= ZSP_NRZI;
20107c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_ECHO)
20117c478bd9Sstevel@tonic-gate flags |= ZSP_ECHO;
20127c478bd9Sstevel@tonic-gate
20137c478bd9Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit];
20147c478bd9Sstevel@tonic-gate
20157c478bd9Sstevel@tonic-gate zspp->zs = zs;
20167c478bd9Sstevel@tonic-gate zspp->flags = (uchar_t)flags;
20177c478bd9Sstevel@tonic-gate zspp->wr4 = ZSWR4_SDLC;
20187c478bd9Sstevel@tonic-gate zspp->wr11 = (uchar_t)wr11;
20197c478bd9Sstevel@tonic-gate zspp->wr12 = (uchar_t)(tconst & 0xff);
20207c478bd9Sstevel@tonic-gate zspp->wr13 = (uchar_t)((tconst >> 8) & 0xff);
20217c478bd9Sstevel@tonic-gate zspp->wr3 = (uchar_t)(ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE |
20227c478bd9Sstevel@tonic-gate ZSWR3_RX_8);
20237c478bd9Sstevel@tonic-gate zspp->wr5 = (uchar_t)(ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE);
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
20267c478bd9Sstevel@tonic-gate zspp->wr5 |= ZSWR5_RTS;
20277c478bd9Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; /* Assume CTS is high */
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_IBM) {
20307c478bd9Sstevel@tonic-gate zspp->wr15 = (uchar_t)
20317c478bd9Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS);
20327c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP))
20337c478bd9Sstevel@tonic-gate zspp->wr15 &= ~ZSR15_CTS;
20347c478bd9Sstevel@tonic-gate } else {
20357c478bd9Sstevel@tonic-gate zspp->wr5 |= ZSWR5_TX_ENABLE;
20367c478bd9Sstevel@tonic-gate zspp->wr15 = (uchar_t)
20377c478bd9Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC);
20387c478bd9Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL)
20397c478bd9Sstevel@tonic-gate zspp->wr15 |= ZSR15_CTS;
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate zs_program(zspp);
20437c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
20447c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
20457c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_INITIALIZED;
20467c478bd9Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats));
20477c478bd9Sstevel@tonic-gate bcopy(sm, &zss->sl_mode, sizeof (struct scc_mode));
20487c478bd9Sstevel@tonic-gate zss->sl_mode.sm_retval = 0; /* successful */
20497c478bd9Sstevel@tonic-gate out:
20507c478bd9Sstevel@tonic-gate return (err);
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate
20537c478bd9Sstevel@tonic-gate /*
20547c478bd9Sstevel@tonic-gate * Function to store modem signal changes in sl_mstat field.
20557c478bd9Sstevel@tonic-gate * Note that these events are supposed to be so far apart in time that
20567c478bd9Sstevel@tonic-gate * we should always be able to send up the event and allocate a message
20577c478bd9Sstevel@tonic-gate * block before another one happens. If not, we'll overwrite this one.
20587c478bd9Sstevel@tonic-gate */
20597c478bd9Sstevel@tonic-gate static void
zsh_setmstat(struct zscom * zs,int event)20607c478bd9Sstevel@tonic-gate zsh_setmstat(struct zscom *zs, int event)
20617c478bd9Sstevel@tonic-gate {
20627c478bd9Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
20637c478bd9Sstevel@tonic-gate register struct sl_status *mstat;
20647c478bd9Sstevel@tonic-gate register mblk_t *mp;
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate if (((mp = zss->sl_mstat) != NULL) &&
20677c478bd9Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_SIGNAL))) {
20687c478bd9Sstevel@tonic-gate mstat = (struct sl_status *)mp->b_wptr;
20697c478bd9Sstevel@tonic-gate mstat->type = (zss->sl_mode.sm_config & CONN_IBM) ?
20707c478bd9Sstevel@tonic-gate SLS_LINKERR : SLS_MDMSTAT;
20717c478bd9Sstevel@tonic-gate mstat->status = event;
20727c478bd9Sstevel@tonic-gate gethrestime(&mstat->tstamp);
20737c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (struct sl_status);
20747c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
20757c478bd9Sstevel@tonic-gate ZSH_PUTQ(mp);
20767c478bd9Sstevel@tonic-gate zss->sl_mstat = NULL;
20777c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
20787c478bd9Sstevel@tonic-gate }
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate /*
20827c478bd9Sstevel@tonic-gate * Received Bad Frame procedure
20837c478bd9Sstevel@tonic-gate */
20847c478bd9Sstevel@tonic-gate static void
zsh_rxbad(struct zscom * zs,struct syncline * zss)20857c478bd9Sstevel@tonic-gate zsh_rxbad(struct zscom *zs, struct syncline *zss)
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate /*
20887c478bd9Sstevel@tonic-gate * swallow bad characters
20897c478bd9Sstevel@tonic-gate */
20907c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
20917c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
20927c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate SCC_BIS(3, ZSWR3_HUNT); /* enter hunt mode - ignores rest of frame */
20957c478bd9Sstevel@tonic-gate
20967c478bd9Sstevel@tonic-gate zss->sl_st.ierror++;
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate /*
20997c478bd9Sstevel@tonic-gate * Free active receive message.
21007c478bd9Sstevel@tonic-gate */
21017c478bd9Sstevel@tonic-gate if (zss->sl_rhead) {
21027c478bd9Sstevel@tonic-gate zss->sl_rhead->b_wptr = zss->sl_rhead->b_rptr;
21037c478bd9Sstevel@tonic-gate zss->sl_rhead->b_datap->db_type = M_RSE;
21047c478bd9Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_rhead);
21057c478bd9Sstevel@tonic-gate zss->sl_ractb = NULL;
21067c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
21077c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
21087c478bd9Sstevel@tonic-gate }
21097c478bd9Sstevel@tonic-gate if (zss->sl_rhead) {
21107c478bd9Sstevel@tonic-gate zss->sl_rhead = NULL;
21117c478bd9Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb);
21127c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
21137c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate
21167c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
21177c478bd9Sstevel@tonic-gate }
21187c478bd9Sstevel@tonic-gate
21197c478bd9Sstevel@tonic-gate /*
21207c478bd9Sstevel@tonic-gate * Transmit error procedure
21217c478bd9Sstevel@tonic-gate */
21227c478bd9Sstevel@tonic-gate static void
zsh_txbad(struct zscom * zs,struct syncline * zss)21237c478bd9Sstevel@tonic-gate zsh_txbad(struct zscom *zs, struct syncline *zss)
21247c478bd9Sstevel@tonic-gate {
21257c478bd9Sstevel@tonic-gate if (zss->sl_xhead) { /* free the message we were sending */
21267c478bd9Sstevel@tonic-gate zss->sl_xhead->b_wptr = zss->sl_xhead->b_rptr;
21277c478bd9Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead);
21287c478bd9Sstevel@tonic-gate zss->sl_xactb = NULL;
21297c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
21307c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
21317c478bd9Sstevel@tonic-gate }
21327c478bd9Sstevel@tonic-gate zss->sl_xhead = NULL;
21337c478bd9Sstevel@tonic-gate
21347c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
21357c478bd9Sstevel@tonic-gate /*
21367c478bd9Sstevel@tonic-gate * drop RTS and our notion of CTS
21377c478bd9Sstevel@tonic-gate */
21387c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
21397c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
21407c478bd9Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
21437c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY))
21447c478bd9Sstevel@tonic-gate zss->sl_st.oerror++;
21457c478bd9Sstevel@tonic-gate }
21467c478bd9Sstevel@tonic-gate
21477c478bd9Sstevel@tonic-gate /*
21487c478bd9Sstevel@tonic-gate * Transmitter watchdog timeout routine
21497c478bd9Sstevel@tonic-gate */
21507c478bd9Sstevel@tonic-gate static void
zsh_watchdog(void * arg)21517c478bd9Sstevel@tonic-gate zsh_watchdog(void *arg)
21527c478bd9Sstevel@tonic-gate {
21537c478bd9Sstevel@tonic-gate struct zscom *zs = arg;
21547c478bd9Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
21557c478bd9Sstevel@tonic-gate queue_t *wq;
21567c478bd9Sstevel@tonic-gate mblk_t *mp;
21577c478bd9Sstevel@tonic-gate int warning = 0;
21587c478bd9Sstevel@tonic-gate uchar_t s0;
21597c478bd9Sstevel@tonic-gate int do_flushwq = 0;
21607c478bd9Sstevel@tonic-gate
21617c478bd9Sstevel@tonic-gate /*
21627c478bd9Sstevel@tonic-gate * The main reason for this routine is because, under some
21637c478bd9Sstevel@tonic-gate * circumstances, a transmit interrupt may get lost (ie., if
21647c478bd9Sstevel@tonic-gate * underrun occurs after the last character has been sent, and
21657c478bd9Sstevel@tonic-gate * the tx interrupt following the abort gets scheduled before
21667c478bd9Sstevel@tonic-gate * the current tx interrupt has been serviced). Transmit can
21677c478bd9Sstevel@tonic-gate * also get hung if the cable is pulled out and the clock was
21687c478bd9Sstevel@tonic-gate * coming in from the modem.
21697c478bd9Sstevel@tonic-gate */
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
21727c478bd9Sstevel@tonic-gate if (zss->sl_stream.str_rq)
21737c478bd9Sstevel@tonic-gate wq = WR(zss->sl_stream.str_rq);
21747c478bd9Sstevel@tonic-gate else {
21757c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
21767c478bd9Sstevel@tonic-gate return; /* guard against close/callback race */
21777c478bd9Sstevel@tonic-gate }
21787c478bd9Sstevel@tonic-gate
21797c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
21807c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_XMT_INPROG) && wq->q_first) {
21817c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
21827c478bd9Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) ||
21837c478bd9Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss))
21847c478bd9Sstevel@tonic-gate (void) zsh_start(zs, zss);
21857c478bd9Sstevel@tonic-gate goto end_watchdog;
21867c478bd9Sstevel@tonic-gate }
21877c478bd9Sstevel@tonic-gate
21887c478bd9Sstevel@tonic-gate if (zss->sl_wd_count-- > 0)
21897c478bd9Sstevel@tonic-gate goto end_watchdog;
21907c478bd9Sstevel@tonic-gate
21917c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
21927c478bd9Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP))
21937c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
21947c478bd9Sstevel@tonic-gate else {
21957c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
21967c478bd9Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
21977c478bd9Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
21987c478bd9Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
21997c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
22007c478bd9Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP);
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate }
22037c478bd9Sstevel@tonic-gate }
22047c478bd9Sstevel@tonic-gate
22057c478bd9Sstevel@tonic-gate switch (zss->sl_txstate) {
22067c478bd9Sstevel@tonic-gate
22077c478bd9Sstevel@tonic-gate case TX_ABORTED:
22087c478bd9Sstevel@tonic-gate /*
22097c478bd9Sstevel@tonic-gate * Transmitter was hung ... try restarting it.
22107c478bd9Sstevel@tonic-gate */
22117c478bd9Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
22127c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
22137c478bd9Sstevel@tonic-gate (void) zsh_start(zs, zss);
22147c478bd9Sstevel@tonic-gate } else
22157c478bd9Sstevel@tonic-gate do_flushwq = 1;
22167c478bd9Sstevel@tonic-gate break;
22177c478bd9Sstevel@tonic-gate
22187c478bd9Sstevel@tonic-gate case TX_ACTIVE:
22197c478bd9Sstevel@tonic-gate case TX_CRC:
22207c478bd9Sstevel@tonic-gate /*
22217c478bd9Sstevel@tonic-gate * Transmit is hung for some reason. Reset tx interrupt.
22227c478bd9Sstevel@tonic-gate * Flush transmit fifo by sending an abort command
22237c478bd9Sstevel@tonic-gate * which also sets the Underrun/EOM latch in WR0 and in
22247c478bd9Sstevel@tonic-gate * turn generates an External Status interrupt that
22257c478bd9Sstevel@tonic-gate * will reset the necessary message buffer pointers.
22267c478bd9Sstevel@tonic-gate * The watchdog timer will cycle again to allow the SCC
22277c478bd9Sstevel@tonic-gate * to settle down after the abort command. The next
22287c478bd9Sstevel@tonic-gate * time through we'll see that the state is now TX_ABORTED
22297c478bd9Sstevel@tonic-gate * and call zsh_start to grab a new message.
22307c478bd9Sstevel@tonic-gate */
22317c478bd9Sstevel@tonic-gate if (--zss->sl_wd_count <= 0) {
22327c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
22337c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
22347c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
22357c478bd9Sstevel@tonic-gate zsh_txbad(zs, zss);
22367c478bd9Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED; /* must be after txbad */
22377c478bd9Sstevel@tonic-gate warning = 1;
22387c478bd9Sstevel@tonic-gate }
22397c478bd9Sstevel@tonic-gate break;
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate case TX_RTS:
22427c478bd9Sstevel@tonic-gate /*
22437c478bd9Sstevel@tonic-gate * Timer expired after we raised RTS. CTS never came up.
22447c478bd9Sstevel@tonic-gate */
22457c478bd9Sstevel@tonic-gate zss->sl_st.cts++;
22467c478bd9Sstevel@tonic-gate
22477c478bd9Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_TO);
22487c478bd9Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG;
22497c478bd9Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ;
22507c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
22517c478bd9Sstevel@tonic-gate break;
22527c478bd9Sstevel@tonic-gate
22537c478bd9Sstevel@tonic-gate default:
22547c478bd9Sstevel@tonic-gate /*
22557c478bd9Sstevel@tonic-gate * If we time out in an inactive state we set a soft
22567c478bd9Sstevel@tonic-gate * interrupt. This will call zsh_start which will
22577c478bd9Sstevel@tonic-gate * clear SF_XMT_INPROG if the queue is empty.
22587c478bd9Sstevel@tonic-gate */
22597c478bd9Sstevel@tonic-gate break;
22607c478bd9Sstevel@tonic-gate }
22617c478bd9Sstevel@tonic-gate end_watchdog:
22627c478bd9Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) {
22637c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22647c478bd9Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs, SIO_WATCHDOG_TICK);
22657c478bd9Sstevel@tonic-gate } else {
22667c478bd9Sstevel@tonic-gate zss->sl_wd_id = 0; /* safety */
22677c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate if (warning || do_flushwq) {
22707c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA);
22717c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
22727c478bd9Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL)
22737c478bd9Sstevel@tonic-gate zss->sl_xstandby = NULL;
22747c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22757c478bd9Sstevel@tonic-gate if (mp)
22767c478bd9Sstevel@tonic-gate freemsg(mp);
22777c478bd9Sstevel@tonic-gate }
22787c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22797c478bd9Sstevel@tonic-gate if (warning)
22807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zsh%x: transmit hung", zs->zs_unit);
22817c478bd9Sstevel@tonic-gate }
22827c478bd9Sstevel@tonic-gate
22837c478bd9Sstevel@tonic-gate static void
zsh_callback(void * arg)22847c478bd9Sstevel@tonic-gate zsh_callback(void *arg)
22857c478bd9Sstevel@tonic-gate {
22867c478bd9Sstevel@tonic-gate struct zscom *zs = arg;
22877c478bd9Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
22887c478bd9Sstevel@tonic-gate int tmp = ZSH_MAX_RSTANDBY;
22897c478bd9Sstevel@tonic-gate
22907c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
22917c478bd9Sstevel@tonic-gate if (zss->sl_bufcid) {
22927c478bd9Sstevel@tonic-gate zss->sl_bufcid = 0;
22937c478bd9Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp);
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22967c478bd9Sstevel@tonic-gate }
2297