10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * HDLC protocol handler for Z8530 SCC.
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/stropts.h>
370Sstevel@tonic-gate #include <sys/stream.h>
380Sstevel@tonic-gate #include <sys/strsun.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/cred.h>
410Sstevel@tonic-gate #include <sys/user.h>
420Sstevel@tonic-gate #include <sys/proc.h>
430Sstevel@tonic-gate #include <sys/file.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <sys/buf.h>
460Sstevel@tonic-gate #include <sys/mkdev.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/errno.h>
490Sstevel@tonic-gate #include <sys/fcntl.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate #include <sys/zsdev.h>
520Sstevel@tonic-gate #include <sys/ser_sync.h>
530Sstevel@tonic-gate #include <sys/conf.h>
540Sstevel@tonic-gate #include <sys/ddi.h>
550Sstevel@tonic-gate #include <sys/sunddi.h>
560Sstevel@tonic-gate #include <sys/dlpi.h>
570Sstevel@tonic-gate
580Sstevel@tonic-gate #define ZSH_TRACING
590Sstevel@tonic-gate #ifdef ZSH_TRACING
600Sstevel@tonic-gate #include <sys/vtrace.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate * Temp tracepoint definitions
640Sstevel@tonic-gate */
650Sstevel@tonic-gate #define TR_ZSH 50
660Sstevel@tonic-gate
670Sstevel@tonic-gate #define TR_ZSH_TXINT 1
680Sstevel@tonic-gate #define TR_ZSH_XSINT 2
690Sstevel@tonic-gate #define TR_ZSH_RXINT 3
700Sstevel@tonic-gate #define TR_ZSH_SRINT 4
710Sstevel@tonic-gate
720Sstevel@tonic-gate #define TR_ZSH_WPUT_START 5
730Sstevel@tonic-gate #define TR_ZSH_WPUT_END 6
740Sstevel@tonic-gate #define TR_ZSH_START_START 7
750Sstevel@tonic-gate #define TR_ZSH_START_END 8
760Sstevel@tonic-gate #define TR_ZSH_SOFT_START 9
770Sstevel@tonic-gate #define TR_ZSH_SOFT_END 10
780Sstevel@tonic-gate
790Sstevel@tonic-gate #define TR_ZSH_OPEN 11
800Sstevel@tonic-gate #define TR_ZSH_CLOSE 12
810Sstevel@tonic-gate
820Sstevel@tonic-gate #endif /* ZSH_TRACING */
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * Logging definitions
860Sstevel@tonic-gate */
870Sstevel@tonic-gate
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate * #define ZSH_DEBUG
900Sstevel@tonic-gate */
910Sstevel@tonic-gate #ifdef ZSH_DEBUG
920Sstevel@tonic-gate
930Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL
940Sstevel@tonic-gate extern char zs_h_log[];
950Sstevel@tonic-gate extern int zs_h_log_n;
960Sstevel@tonic-gate #define zsh_h_log_add(c) \
970Sstevel@tonic-gate { \
980Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \
990Sstevel@tonic-gate zs_h_log_n = 0; \
1000Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \
1010Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \
1020Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate #define zsh_h_log_clear
1050Sstevel@tonic-gate #else
1060Sstevel@tonic-gate #define ZSH_H_LOG_MAX 0x8000
1070Sstevel@tonic-gate char zsh_h_log[2][ZSH_H_LOG_MAX +10];
1080Sstevel@tonic-gate int zsh_h_log_n[2];
1090Sstevel@tonic-gate #define zsh_h_log_add(c) \
1100Sstevel@tonic-gate { \
1110Sstevel@tonic-gate if (zsh_h_log_n[zs->zs_unit] >= ZSH_H_LOG_MAX) \
1120Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \
1130Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]++] = c; \
1140Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]] = '\0'; \
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate #define zsh_h_log_clear \
1180Sstevel@tonic-gate { register char *p; \
1190Sstevel@tonic-gate for (p = &zsh_h_log[zs->zs_unit][ZSH_H_LOG_MAX]; \
1200Sstevel@tonic-gate p >= &zsh_h_log[zs->zs_unit][0]; p--) \
1210Sstevel@tonic-gate *p = '\0'; \
1220Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate #endif
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate #define ZSH_R0_LOG(r0) { \
1270Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsh_h_log_add('R'); \
1280Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsh_h_log_add('Z'); \
1290Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsh_h_log_add('T'); \
1300Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsh_h_log_add('D'); \
1310Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsh_h_log_add('S'); \
1320Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsh_h_log_add('C'); \
1330Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsh_h_log_add('U'); \
1340Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsh_h_log_add('B'); \
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate #endif
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate char _depends_on[] = "drv/zs";
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate #ifndef MAXZSH
1420Sstevel@tonic-gate #define MAXZSH 2
1430Sstevel@tonic-gate #define MAXZSHCLONES (80) /* three clone opens per instance */
1440Sstevel@tonic-gate #endif /* MAXZSH */
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate int maxzsh = MAXZSH;
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate int zsh_timer_count = 10;
1490Sstevel@tonic-gate int zsh_default_mru = 1024;
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate struct ser_str *zsh_str = NULL;
1520Sstevel@tonic-gate unsigned char zsh_usedminor[MAXZSHCLONES];
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * The HDLC protocol
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate int zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
1590Sstevel@tonic-gate static int zsh_probe(dev_info_t *dev);
1600Sstevel@tonic-gate static int zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
1610Sstevel@tonic-gate static int zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
1620Sstevel@tonic-gate static int zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
1630Sstevel@tonic-gate static int zsh_close(queue_t *rq, int flag);
1640Sstevel@tonic-gate static void zsh_wput(queue_t *wq, mblk_t *mp);
1650Sstevel@tonic-gate static int zsh_start(struct zscom *zs, struct syncline *zss);
1660Sstevel@tonic-gate static void zsh_ioctl(queue_t *wq, mblk_t *mp);
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate static struct module_info hdlc_minfo = {
1690Sstevel@tonic-gate 0x5a48, /* module ID number: "ZH" */
1700Sstevel@tonic-gate "zsh", /* module name */
1710Sstevel@tonic-gate 0, /* minimum packet size accepted */
1720Sstevel@tonic-gate INFPSZ, /* maximum packet size accepted */
1730Sstevel@tonic-gate 12*1024, /* queue high water mark (bytes) */
1740Sstevel@tonic-gate 4*1024 /* queue low water mark (bytes) */
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate static struct qinit hdlc_rinit = {
1780Sstevel@tonic-gate putq, /* input put procedure */
1790Sstevel@tonic-gate NULL, /* input service procedure */
1800Sstevel@tonic-gate zsh_open, /* open procedure */
1810Sstevel@tonic-gate zsh_close, /* close procedure */
1820Sstevel@tonic-gate NULL, /* reserved */
1830Sstevel@tonic-gate &hdlc_minfo, /* module info */
1840Sstevel@tonic-gate NULL /* reserved */
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate static struct qinit hdlc_winit = {
1880Sstevel@tonic-gate (int (*)())zsh_wput, /* output put procedure */
1890Sstevel@tonic-gate NULL, /* output service procedure */
1900Sstevel@tonic-gate NULL, /* open procedure */
1910Sstevel@tonic-gate NULL, /* close procedure */
1920Sstevel@tonic-gate NULL, /* reserved */
1930Sstevel@tonic-gate &hdlc_minfo, /* module info */
1940Sstevel@tonic-gate NULL /* reserved */
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate struct streamtab hdlctab = {
1980Sstevel@tonic-gate &hdlc_rinit, /* initialize read queue */
1990Sstevel@tonic-gate &hdlc_winit, /* initialize write queue */
2000Sstevel@tonic-gate NULL, /* mux read qinit */
2010Sstevel@tonic-gate NULL /* mux write qinit */
2020Sstevel@tonic-gate };
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(zsh_ops, nulldev, zsh_probe, zsh_attach,
205*7656SSherry.Moore@Sun.COM zsh_detach, nodev, zsh_info, D_MP, &hdlctab, ddi_quiesce_not_supported);
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * This is the loadable module wrapper.
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate #include <sys/errno.h>
2120Sstevel@tonic-gate #include <sys/modctl.h>
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * Module linkage information for the kernel.
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate static struct modldrv modldrv = {
2190Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
220*7656SSherry.Moore@Sun.COM "Z8530 serial HDLC drv",
2210Sstevel@tonic-gate &zsh_ops, /* our own ops for this module */
2220Sstevel@tonic-gate };
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate static struct modlinkage modlinkage = {
2250Sstevel@tonic-gate MODREV_1,
2260Sstevel@tonic-gate (void *)&modldrv,
2270Sstevel@tonic-gate NULL
2280Sstevel@tonic-gate };
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate int
_init(void)2310Sstevel@tonic-gate _init(void)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate return (mod_install(&modlinkage));
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate int
_fini(void)2370Sstevel@tonic-gate _fini(void)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate return (mod_remove(&modlinkage));
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2430Sstevel@tonic-gate _info(struct modinfo *modinfop)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate * The HDLC interrupt entry points.
2510Sstevel@tonic-gate */
2520Sstevel@tonic-gate static void zsh_txint(struct zscom *zs);
2530Sstevel@tonic-gate static void zsh_xsint(struct zscom *zs);
2540Sstevel@tonic-gate static void zsh_rxint(struct zscom *zs);
2550Sstevel@tonic-gate static void zsh_srint(struct zscom *zs);
2560Sstevel@tonic-gate static int zsh_softint(struct zscom *zs);
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate struct zsops zsops_hdlc = {
2590Sstevel@tonic-gate zsh_txint,
2600Sstevel@tonic-gate zsh_xsint,
2610Sstevel@tonic-gate zsh_rxint,
2620Sstevel@tonic-gate zsh_srint,
2630Sstevel@tonic-gate zsh_softint,
2640Sstevel@tonic-gate NULL,
2650Sstevel@tonic-gate NULL
2660Sstevel@tonic-gate };
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static int zsh_program(struct zscom *zs, struct scc_mode *sm);
2690Sstevel@tonic-gate static void zsh_setmstat(struct zscom *zs, int event);
2700Sstevel@tonic-gate static void zsh_rxbad(struct zscom *zs, struct syncline *zss);
2710Sstevel@tonic-gate static void zsh_txbad(struct zscom *zs, struct syncline *zss);
2720Sstevel@tonic-gate static void zsh_watchdog(void *);
2730Sstevel@tonic-gate static void zsh_callback(void *);
2740Sstevel@tonic-gate static int zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss);
2750Sstevel@tonic-gate static void zsh_init_port(struct zscom *zs, struct syncline *zss);
2760Sstevel@tonic-gate static int zsh_setmode(struct zscom *zs, struct syncline *zss,
2770Sstevel@tonic-gate struct scc_mode *sm);
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate * The HDLC Driver.
2820Sstevel@tonic-gate */
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Special macros to handle STREAMS operations.
2870Sstevel@tonic-gate * These are required to address memory leakage problems.
2880Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT
2890Sstevel@tonic-gate */
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate #define ZSH_GETBLOCK(zs, allocbcount) \
2950Sstevel@tonic-gate { \
2960Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \
2970Sstevel@tonic-gate while (--n >= 0) { \
2980Sstevel@tonic-gate if (!zss->sl_rstandby[n]) { \
2990Sstevel@tonic-gate if ((zss->sl_rstandby[n] = \
3000Sstevel@tonic-gate allocb(zss->sl_mru, BPRI_MED)) == NULL) { \
3010Sstevel@tonic-gate if (zss->sl_bufcid == 0) { \
3020Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \
3030Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) { \
3040Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
3050Sstevel@tonic-gate zss->sl_bufcid = bufcall(zss->sl_mru, \
3060Sstevel@tonic-gate BPRI_MED, zsh_callback, zs); \
3070Sstevel@tonic-gate break; \
3080Sstevel@tonic-gate } else \
3090Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
3100Sstevel@tonic-gate } \
3110Sstevel@tonic-gate } \
3120Sstevel@tonic-gate allocbcount--; \
3130Sstevel@tonic-gate } \
3140Sstevel@tonic-gate } \
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex.
3190Sstevel@tonic-gate */
3200Sstevel@tonic-gate #define ZSH_ALLOCB(mp) \
3210Sstevel@tonic-gate { \
3220Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \
3230Sstevel@tonic-gate mp = NULL; \
3240Sstevel@tonic-gate while (--n >= 0) { \
3250Sstevel@tonic-gate if ((mp = zss->sl_rstandby[n]) != NULL) { \
3260Sstevel@tonic-gate zss->sl_rstandby[n] = NULL; \
3270Sstevel@tonic-gate break; \
3280Sstevel@tonic-gate } \
3290Sstevel@tonic-gate } \
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate #define ZSH_PUTQ(mp) \
3330Sstevel@tonic-gate { \
3340Sstevel@tonic-gate register int wptr, rptr; \
3350Sstevel@tonic-gate wptr = zss->sl_rdone_wptr; \
3360Sstevel@tonic-gate rptr = zss->sl_rdone_rptr; \
3370Sstevel@tonic-gate zss->sl_rdone[wptr] = mp; \
3380Sstevel@tonic-gate if ((wptr) + 1 == ZSH_RDONE_MAX) \
3390Sstevel@tonic-gate zss->sl_rdone_wptr = wptr = 0; \
3400Sstevel@tonic-gate else \
3410Sstevel@tonic-gate zss->sl_rdone_wptr = ++wptr; \
3420Sstevel@tonic-gate if (wptr == rptr) { /* Should never occur */ \
3430Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \
3440Sstevel@tonic-gate zss->sl_m_error = ENOSR; \
3450Sstevel@tonic-gate ZSSETSOFT(zs); \
3460Sstevel@tonic-gate } \
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate #define ZSH_FREEMSG(mp) \
3500Sstevel@tonic-gate { \
3510Sstevel@tonic-gate ZSH_PUTQ(mp); \
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
3570Sstevel@tonic-gate */
3580Sstevel@tonic-gate #define ZSH_GETQ(mp) \
3590Sstevel@tonic-gate { \
3600Sstevel@tonic-gate if (zss->sl_rdone_rptr != zss->sl_rdone_wptr) { \
3610Sstevel@tonic-gate mp = zss->sl_rdone[zss->sl_rdone_rptr++]; \
3620Sstevel@tonic-gate if (zss->sl_rdone_rptr == ZSH_RDONE_MAX) \
3630Sstevel@tonic-gate zss->sl_rdone_rptr = 0; \
3640Sstevel@tonic-gate } else \
3650Sstevel@tonic-gate mp = NULL; \
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate #define ZSH_FLUSHQ \
3690Sstevel@tonic-gate { \
3700Sstevel@tonic-gate register mblk_t *tmp; \
3710Sstevel@tonic-gate for (;;) { \
3720Sstevel@tonic-gate ZSH_GETQ(tmp); \
3730Sstevel@tonic-gate if (!(tmp)) \
3740Sstevel@tonic-gate break; \
3750Sstevel@tonic-gate freemsg(tmp); \
3760Sstevel@tonic-gate } \
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /*ARGSUSED*/
3800Sstevel@tonic-gate static int
zsh_probe(dev_info_t * dev)3810Sstevel@tonic-gate zsh_probe(dev_info_t *dev)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate return (DDI_PROBE_DONTCARE);
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate /*ARGSUSED*/
3870Sstevel@tonic-gate static int
zsh_attach(dev_info_t * dev,ddi_attach_cmd_t cmd)3880Sstevel@tonic-gate zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate register int unit;
3910Sstevel@tonic-gate char name[3] = {
3920Sstevel@tonic-gate '\0', '\0', '\0' };
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate /*
3950Sstevel@tonic-gate * Since zsh is a child of the "pseudo" nexus, we can expect the
3960Sstevel@tonic-gate * attach routine to be called only once. We need to create all
3970Sstevel@tonic-gate * necessary devices in one shot. There is never more than one
3980Sstevel@tonic-gate * SCC chip that supports zsh devices.
3990Sstevel@tonic-gate */
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate if (cmd != DDI_ATTACH)
4020Sstevel@tonic-gate return (DDI_FAILURE);
4030Sstevel@tonic-gate if (zscom == NULL)
4040Sstevel@tonic-gate return (DDI_FAILURE); /* zsattach not done */
4050Sstevel@tonic-gate unit = 2 * ddi_get_instance(dev);
4060Sstevel@tonic-gate if (unit > 1)
4070Sstevel@tonic-gate return (DDI_FAILURE); /* only use cpu ports */
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate if (ddi_create_minor_node(dev, "zsh", S_IFCHR,
4100Sstevel@tonic-gate NULL, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
4110Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4120Sstevel@tonic-gate cmn_err(CE_WARN, "zsh clone device creation failed.");
4130Sstevel@tonic-gate return (DDI_FAILURE);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate for (; unit < maxzsh/2; unit++) {
4170Sstevel@tonic-gate zscom[unit].zs_hdlc_dip = dev;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate (void) sprintf(name, "%d", unit);
4200Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
4210Sstevel@tonic-gate 2*unit, DDI_PSEUDO, NULL) == DDI_FAILURE) {
4220Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4230Sstevel@tonic-gate return (DDI_FAILURE);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate unit++;
4260Sstevel@tonic-gate (void) sprintf(name, "%d", unit);
4270Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
4280Sstevel@tonic-gate 2*(unit-1)+1, DDI_PSEUDO, NULL) == DDI_FAILURE) {
4290Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4300Sstevel@tonic-gate return (DDI_FAILURE);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate return (DDI_SUCCESS);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /* ARGSUSED */
4380Sstevel@tonic-gate int
zsh_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4390Sstevel@tonic-gate zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
4400Sstevel@tonic-gate void **result)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate register dev_t dev = (dev_t)arg;
4430Sstevel@tonic-gate register int unit, error;
4440Sstevel@tonic-gate register struct zscom *zs;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs)
4470Sstevel@tonic-gate return (DDI_FAILURE);
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate switch (infocmd) {
4500Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
4510Sstevel@tonic-gate if (zscom == NULL) {
4520Sstevel@tonic-gate error = DDI_FAILURE;
4530Sstevel@tonic-gate } else {
4540Sstevel@tonic-gate zs = &zscom[unit];
4550Sstevel@tonic-gate *result = zs->zs_hdlc_dip;
4560Sstevel@tonic-gate error = DDI_SUCCESS;
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate break;
4590Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
460796Smathue *result = (void *)(uintptr_t)(unit / 2);
4610Sstevel@tonic-gate error = DDI_SUCCESS;
4620Sstevel@tonic-gate break;
4630Sstevel@tonic-gate default:
4640Sstevel@tonic-gate error = DDI_FAILURE;
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate return (error);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate static int
zsh_detach(dev_info_t * dev,ddi_detach_cmd_t cmd)4700Sstevel@tonic-gate zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
4710Sstevel@tonic-gate {
4720Sstevel@tonic-gate if (cmd != DDI_DETACH)
4730Sstevel@tonic-gate return (DDI_FAILURE);
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate return (DDI_SUCCESS);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate static void
zsh_init_port(struct zscom * zs,struct syncline * zss)4810Sstevel@tonic-gate zsh_init_port(struct zscom *zs, struct syncline *zss)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate register uchar_t s0;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate SCC_WRITE(3, (ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE | ZSWR3_RX_8));
4860Sstevel@tonic-gate SCC_WRITE(5, (ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE));
4870Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0();
4880Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
4890Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
4900Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS);
4910Sstevel@tonic-gate s0 = SCC_READ0();
4920Sstevel@tonic-gate if ((s0 & ZSRR0_CTS) ||
4930Sstevel@tonic-gate !(zss->sl_mode.sm_config & (CONN_SIGNAL | CONN_IBM))) {
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate * send msg that CTS is up
4960Sstevel@tonic-gate */
4970Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
4980Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
4990Sstevel@tonic-gate } else {
5000Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
5010Sstevel@tonic-gate zss->sl_txstate = TX_RTS;
5020Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
5030Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
5040Sstevel@tonic-gate if (!zss->sl_wd_id)
5050Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog,
5060Sstevel@tonic-gate zs, SIO_WATCHDOG_TICK);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate } else {
5090Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
5100Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
5110Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
5120Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate * Open routine.
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate /*ARGSUSED*/
5210Sstevel@tonic-gate static int
zsh_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)5220Sstevel@tonic-gate zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate register struct zscom *zs;
5250Sstevel@tonic-gate register struct syncline *zss;
5260Sstevel@tonic-gate register struct ser_str *stp;
5270Sstevel@tonic-gate register int unit;
5280Sstevel@tonic-gate register int tmp;
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate if (sflag != CLONEOPEN) {
5310Sstevel@tonic-gate if (rq->q_ptr)
5320Sstevel@tonic-gate return (EBUSY); /* We got a stream that is in use */
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate unit = UNIT(*dev);
5350Sstevel@tonic-gate if (unit >= maxzsh)
5360Sstevel@tonic-gate return (ENXIO); /* unit not configured */
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate if (zscom == NULL)
5390Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */
5400Sstevel@tonic-gate zs = &zscom[unit];
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate if (zs->zs_ops == NULL) {
5430Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_OPEN, "zsh_open:unit = %d", unit);
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate mutex_enter(zs->zs_excl);
5490Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
5500Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
5510Sstevel@tonic-gate mutex_exit(zs->zs_excl);
5520Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /* Mark device as busy (for power management) */
5560Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1);
5570Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, unit%2+1, 1);
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate zsopinit(zs, &zsops_hdlc);
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate zss = (struct syncline *)&zscom[unit].zs_priv_str;
5620Sstevel@tonic-gate stp = &zss->sl_stream;
5630Sstevel@tonic-gate stp->str_state = NULL;
5640Sstevel@tonic-gate stp->str_com = (caddr_t)zs;
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate zss->sl_xhead = NULL;
5670Sstevel@tonic-gate zss->sl_xactb = NULL;
5680Sstevel@tonic-gate zs->zs_wr_cur = NULL;
5690Sstevel@tonic-gate zs->zs_wr_lim = NULL;
5700Sstevel@tonic-gate zs->zs_wr_cur = NULL;
5710Sstevel@tonic-gate zs->zs_wr_lim = NULL;
5720Sstevel@tonic-gate zss->sl_rhead = NULL;
5730Sstevel@tonic-gate zss->sl_ractb = NULL;
5740Sstevel@tonic-gate zs->zs_rd_cur = NULL;
5750Sstevel@tonic-gate zs->zs_rd_lim = NULL;
5760Sstevel@tonic-gate zss->sl_mstat = NULL;
5770Sstevel@tonic-gate zss->sl_xstandby = NULL;
5780Sstevel@tonic-gate zss->sl_wd_id = 0;
5790Sstevel@tonic-gate zss->sl_soft_active = 0;
5800Sstevel@tonic-gate zss->sl_stream.str_rq = NULL;
5810Sstevel@tonic-gate
5820Sstevel@tonic-gate zs->zs_priv = (caddr_t)zss;
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate zss->sl_mru = zsh_default_mru;
5850Sstevel@tonic-gate tmp = ZSH_MAX_RSTANDBY;
5860Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp);
5870Sstevel@tonic-gate if (zss->sl_rstandby[0] == NULL) {
588*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "zsh_open: can't alloc message block");
589*7656SSherry.Moore@Sun.COM mutex_exit(zs->zs_excl);
590*7656SSherry.Moore@Sun.COM return (ENOSR);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
5930Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb);
5940Sstevel@tonic-gate zss->sl_txstate = TX_OFF;
5950Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0();
5960Sstevel@tonic-gate zss->sl_flags &= (SF_INITIALIZED | SF_FDXPTP);
5970Sstevel@tonic-gate if (zss->sl_flags & SF_INITIALIZED)
5980Sstevel@tonic-gate zsh_init_port(zs, zss);
5990Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
6000Sstevel@tonic-gate mutex_exit(zs->zs_excl);
6010Sstevel@tonic-gate } else { /* CLONEOPEN */
6020Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
6030Sstevel@tonic-gate for (unit = maxzsh; unit < MAXZSHCLONES; unit++)
6040Sstevel@tonic-gate if (!zsh_usedminor[unit]) {
6050Sstevel@tonic-gate zsh_usedminor[unit] = (unsigned char)unit;
6060Sstevel@tonic-gate break;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
6090Sstevel@tonic-gate if (unit >= MAXZSHCLONES) /* no slots available */
6100Sstevel@tonic-gate return (ENODEV);
6110Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), unit);
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate stp = kmem_zalloc(sizeof (struct ser_str), KM_NOSLEEP);
6140Sstevel@tonic-gate if (stp == NULL) {
6150Sstevel@tonic-gate cmn_err(CE_WARN,
6160Sstevel@tonic-gate "zsh clone open failed, no memory, rq=%p\n",
6170Sstevel@tonic-gate (void *)rq);
6180Sstevel@tonic-gate return (ENOMEM);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate stp->str_state = STR_CLONE;
6210Sstevel@tonic-gate stp->str_com = NULL; /* can't determine without ppa */
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate stp->str_rq = rq;
6240Sstevel@tonic-gate stp->str_inst = unit;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)stp;
6270Sstevel@tonic-gate qprocson(rq);
6280Sstevel@tonic-gate return (0);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate /*
6320Sstevel@tonic-gate * Close routine.
6330Sstevel@tonic-gate */
6340Sstevel@tonic-gate int zsh_tx_enable_in_close = 0;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate /*ARGSUSED*/
6370Sstevel@tonic-gate static int
zsh_close(queue_t * rq,int flag)6380Sstevel@tonic-gate zsh_close(queue_t *rq, int flag)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate struct ser_str *stp;
6410Sstevel@tonic-gate struct zscom *zs;
6420Sstevel@tonic-gate struct syncline *zss;
6430Sstevel@tonic-gate mblk_t *mp;
6440Sstevel@tonic-gate int i;
6450Sstevel@tonic-gate timeout_id_t sl_wd_id;
6460Sstevel@tonic-gate bufcall_id_t sl_bufcid;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate /*
6490Sstevel@tonic-gate * Note that a close is only called on the last close of a
6500Sstevel@tonic-gate * particular stream. Assume that we need to do it all.
6510Sstevel@tonic-gate */
6520Sstevel@tonic-gate qprocsoff(rq); /* no new business after this */
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate stp = (struct ser_str *)rq->q_ptr;
6550Sstevel@tonic-gate if (stp == NULL)
6560Sstevel@tonic-gate return (0); /* already been closed once */
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate if (stp->str_state == STR_CLONE) {
6590Sstevel@tonic-gate zsh_usedminor[stp->str_inst] = 0;
6600Sstevel@tonic-gate } else {
6610Sstevel@tonic-gate zs = (struct zscom *)stp->str_com;
6620Sstevel@tonic-gate if (zs == NULL)
6630Sstevel@tonic-gate goto out;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_CLOSE, "zs = %p", zs);
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
6680Sstevel@tonic-gate mutex_enter(zs->zs_excl);
6690Sstevel@tonic-gate flushq(WR(rq), FLUSHALL);
6700Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
6710Sstevel@tonic-gate if (zss->sl_xstandby) {
6720Sstevel@tonic-gate zss->sl_xstandby->b_wptr = zss->sl_xstandby->b_rptr;
6730Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xstandby);
6740Sstevel@tonic-gate zss->sl_xstandby = NULL;
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate ZSH_FLUSHQ;
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate /*
6810Sstevel@tonic-gate * Stop the Watchdog Timer.
6820Sstevel@tonic-gate */
6830Sstevel@tonic-gate if ((sl_wd_id = zss->sl_wd_id) != 0)
6840Sstevel@tonic-gate zss->sl_wd_id = 0;
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate /*
6870Sstevel@tonic-gate * Cancel outstanding "bufcall" request.
6880Sstevel@tonic-gate */
6890Sstevel@tonic-gate if ((sl_bufcid = zss->sl_bufcid) != 0)
6900Sstevel@tonic-gate zss->sl_bufcid = 0;
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
6930Sstevel@tonic-gate if (zs->zs_wr_cur) {
6940Sstevel@tonic-gate zs->zs_wr_cur = NULL;
6950Sstevel@tonic-gate zs->zs_wr_lim = NULL;
6960Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
6970Sstevel@tonic-gate ZSDELAY();
6980Sstevel@tonic-gate ZSDELAY();
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate zs->zs_wr_cur = NULL;
7030Sstevel@tonic-gate zs->zs_wr_lim = NULL;
7040Sstevel@tonic-gate SCC_BIC(15,
7050Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS));
7060Sstevel@tonic-gate SCC_WRITE(3, 0); /* Quiesce receiver */
7070Sstevel@tonic-gate if (zsh_tx_enable_in_close && !(zss->sl_flags & SF_FDXPTP)) {
7080Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
7090Sstevel@tonic-gate } else
7100Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate SCC_BIC(5, (ZSWR5_DTR | ZSWR5_RTS | ZSWR5_TXCRC_ENABLE));
7130Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); /* reset TX */
7140Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
7150Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
7160Sstevel@tonic-gate (void) SCC_READDATA(); /* reset RX */
7170Sstevel@tonic-gate ZSDELAY();
7180Sstevel@tonic-gate (void) SCC_READDATA();
7190Sstevel@tonic-gate ZSDELAY();
7200Sstevel@tonic-gate (void) SCC_READDATA();
7210Sstevel@tonic-gate ZSDELAY();
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate * Free up everything we ever allocated.
7260Sstevel@tonic-gate */
7270Sstevel@tonic-gate if ((mp = zss->sl_rhead) != NULL) {
7280Sstevel@tonic-gate zss->sl_ractb = NULL; /* already freed */
7290Sstevel@tonic-gate zs->zs_rd_cur = NULL;
7300Sstevel@tonic-gate zs->zs_rd_lim = NULL;
7310Sstevel@tonic-gate zss->sl_rhead = NULL;
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7340Sstevel@tonic-gate if (mp)
7350Sstevel@tonic-gate freemsg(mp);
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7380Sstevel@tonic-gate if ((mp = zss->sl_ractb) != NULL) {
7390Sstevel@tonic-gate zs->zs_rd_cur = NULL;
7400Sstevel@tonic-gate zs->zs_rd_lim = NULL;
7410Sstevel@tonic-gate zss->sl_ractb = NULL;
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7440Sstevel@tonic-gate if (mp)
7450Sstevel@tonic-gate freemsg(mp);
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate for (i = 0; i < ZSH_MAX_RSTANDBY; i++) {
7480Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7490Sstevel@tonic-gate mp = zss->sl_rstandby[i];
7500Sstevel@tonic-gate zss->sl_rstandby[i] = NULL;
7510Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7520Sstevel@tonic-gate if (mp)
7530Sstevel@tonic-gate freemsg(mp);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7570Sstevel@tonic-gate if ((mp = zss->sl_xhead) != NULL) {
7580Sstevel@tonic-gate zss->sl_xhead = NULL;
7590Sstevel@tonic-gate zss->sl_xactb = NULL;
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7620Sstevel@tonic-gate if (mp)
7630Sstevel@tonic-gate freemsg(mp);
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate ZSH_FLUSHQ;
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7680Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL)
7690Sstevel@tonic-gate zss->sl_xstandby = NULL;
7700Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7710Sstevel@tonic-gate if (mp)
7720Sstevel@tonic-gate freemsg(mp);
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7750Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL)
7760Sstevel@tonic-gate zss->sl_mstat = NULL;
7770Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */
7780Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7790Sstevel@tonic-gate if (mp)
7800Sstevel@tonic-gate freemsg(mp);
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate zss->sl_stream.str_rq = NULL;
7830Sstevel@tonic-gate zsopinit(zs, &zsops_null);
7840Sstevel@tonic-gate mutex_exit(zs->zs_excl);
7850Sstevel@tonic-gate if (sl_wd_id)
7860Sstevel@tonic-gate (void) untimeout(sl_wd_id);
7870Sstevel@tonic-gate if (sl_bufcid)
7880Sstevel@tonic-gate unbufcall(sl_bufcid);
7890Sstevel@tonic-gate while (zss->sl_soft_active)
7900Sstevel@tonic-gate drv_usecwait(1);
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate /* Mark device as available for power management */
7930Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate if (stp->str_state == STR_CLONE)
7970Sstevel@tonic-gate kmem_free(stp, sizeof (struct ser_str));
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate out:
8000Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate return (0);
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate static int
zsh_hdp_ok_or_rts_state(struct zscom * zs,struct syncline * zss)8060Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss)
8070Sstevel@tonic-gate {
8080Sstevel@tonic-gate register uchar_t s0;
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
8110Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS);
8120Sstevel@tonic-gate s0 = SCC_READ0();
8130Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
8140Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE);
8150Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
8160Sstevel@tonic-gate return (1);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
8190Sstevel@tonic-gate zss->sl_txstate = TX_RTS;
8200Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
8210Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
8220Sstevel@tonic-gate return (0);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate * Put procedure for write queue.
8270Sstevel@tonic-gate */
8280Sstevel@tonic-gate static void
zsh_wput(queue_t * wq,mblk_t * mp)8290Sstevel@tonic-gate zsh_wput(queue_t *wq, mblk_t *mp)
8300Sstevel@tonic-gate {
8310Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr;
8320Sstevel@tonic-gate register struct zscom *zs;
8330Sstevel@tonic-gate register struct syncline *zss = NULL;
8340Sstevel@tonic-gate register ulong_t prim, error = 0;
8350Sstevel@tonic-gate register union DL_primitives *dlp;
8360Sstevel@tonic-gate register int ppa;
8370Sstevel@tonic-gate register mblk_t *tmp;
8380Sstevel@tonic-gate register struct copyresp *resp;
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate /*
8410Sstevel@tonic-gate * stp->str_com supplied by open or DLPI attach.
8420Sstevel@tonic-gate */
8430Sstevel@tonic-gate if (stp == NULL) {
8440Sstevel@tonic-gate freemsg(mp);
8450Sstevel@tonic-gate return;
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate zs = (struct zscom *)stp->str_com;
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate TRACE_0(TR_ZSH, TR_ZSH_WPUT_START, "zsh_wput start");
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate if ((mp->b_datap->db_type == M_FLUSH) &&
852*7656SSherry.Moore@Sun.COM (stp->str_state == STR_CLONE)) {
8530Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
8540Sstevel@tonic-gate flushq(wq, FLUSHDATA);
8550Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
8580Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */
8590Sstevel@tonic-gate else
8600Sstevel@tonic-gate freemsg(mp);
8610Sstevel@tonic-gate return;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate if ((zs == NULL) && (mp->b_datap->db_type != M_PROTO)) {
865*7656SSherry.Moore@Sun.COM freemsg(mp);
866*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN,
867*7656SSherry.Moore@Sun.COM "zsh: clone device %d must be attached before use!",
868*7656SSherry.Moore@Sun.COM stp->str_inst);
869*7656SSherry.Moore@Sun.COM (void) putnextctl1(RD(wq), M_ERROR, EPROTO);
870*7656SSherry.Moore@Sun.COM return;
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate if (stp->str_state == STR_CLONE) { /* Clone opened, limited. */
8740Sstevel@tonic-gate if ((mp->b_datap->db_type != M_PROTO) &&
8750Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCTL) &&
8760Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCDATA)) {
8770Sstevel@tonic-gate freemsg(mp);
8780Sstevel@tonic-gate cmn_err(CE_WARN,
8790Sstevel@tonic-gate "zsh%x: invalid operation for clone dev.\n",
8800Sstevel@tonic-gate stp->str_inst);
8810Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, EPROTO);
8820Sstevel@tonic-gate return;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate } else {
8850Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate case M_DATA:
8910Sstevel@tonic-gate /*
8920Sstevel@tonic-gate * Queue the message up to be transmitted.
8930Sstevel@tonic-gate * Set "in progress" flag and call the start routine.
8940Sstevel@tonic-gate */
8950Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
8960Sstevel@tonic-gate if (!(zss->sl_flags & SF_INITIALIZED)) {
8970Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
8980Sstevel@tonic-gate cmn_err(CE_WARN,
8990Sstevel@tonic-gate "zsh%x not initialized, can't send message",
9000Sstevel@tonic-gate zs->zs_unit);
9010Sstevel@tonic-gate freemsg(mp);
9020Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, ECOMM);
9030Sstevel@tonic-gate return;
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9060Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) {
9070Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT;
9080Sstevel@tonic-gate (void) zsh_softint(zs);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate while (mp->b_wptr == mp->b_rptr) {
9110Sstevel@tonic-gate register mblk_t *mp1;
9120Sstevel@tonic-gate mp1 = unlinkb(mp);
9130Sstevel@tonic-gate freemsg(mp);
9140Sstevel@tonic-gate mp = mp1;
9150Sstevel@tonic-gate if (mp == NULL)
9160Sstevel@tonic-gate return;
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate mutex_enter(zs->zs_excl);
9190Sstevel@tonic-gate (void) putq(wq, mp);
9200Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9210Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
9220Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9230Sstevel@tonic-gate flushq(wq, FLUSHDATA);
9240Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END,
9270Sstevel@tonic-gate "zsh_wput end: zs = %p", zs);
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate return;
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate tmp = NULL;
9320Sstevel@tonic-gate again:
9330Sstevel@tonic-gate if (!zss->sl_xstandby) {
9340Sstevel@tonic-gate if (tmp)
9350Sstevel@tonic-gate zss->sl_xstandby = tmp;
9360Sstevel@tonic-gate else {
9370Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9380Sstevel@tonic-gate tmp = getq(wq);
9390Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9400Sstevel@tonic-gate if (tmp)
9410Sstevel@tonic-gate goto again;
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate } else if (tmp) {
9440Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9450Sstevel@tonic-gate (void) putbq(wq, tmp);
9460Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate if (zss->sl_flags & SF_XMT_INPROG) {
9500Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9510Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END,
9540Sstevel@tonic-gate "zsh_wput end: zs = %p", zs);
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate return;
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate if (!zss->sl_wd_id) {
9600Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
9610Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
9620Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9630Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs,
9640Sstevel@tonic-gate SIO_WATCHDOG_TICK);
9650Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
9690Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) ||
9700Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss))
9710Sstevel@tonic-gate (void) zsh_start(zs, zss);
9720Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9730Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9740Sstevel@tonic-gate break;
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate case M_PROTO:
9770Sstevel@tonic-gate /*
9780Sstevel@tonic-gate * Here is where a clone device finds out about the
9790Sstevel@tonic-gate * hardware it is going to attach to. The request is
9800Sstevel@tonic-gate * validated and a ppa is extracted from it and validated.
9810Sstevel@tonic-gate * This number is used to index the hardware data structure
9820Sstevel@tonic-gate * and the protocol data structure, in case the latter
9830Sstevel@tonic-gate * was not provided by a data-path open before this.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (stp->str_state != STR_CLONE) {
9860Sstevel@tonic-gate freemsg(mp);
9870Sstevel@tonic-gate return;
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) {
9910Sstevel@tonic-gate prim = DL_ATTACH_REQ;
9920Sstevel@tonic-gate error = DL_BADPRIM;
9930Sstevel@tonic-gate goto end_proto;
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
9960Sstevel@tonic-gate prim = dlp->dl_primitive;
9970Sstevel@tonic-gate if (prim != DL_ATTACH_REQ) {
9980Sstevel@tonic-gate error = DL_BADPRIM;
9990Sstevel@tonic-gate goto end_proto;
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate ppa = dlp->attach_req.dl_ppa;
10020Sstevel@tonic-gate ppa = (ppa%2) ? ((ppa-1)*2 +1) : (ppa*2);
10030Sstevel@tonic-gate if (ppa >= maxzsh) {
10040Sstevel@tonic-gate error = DL_BADPPA;
10050Sstevel@tonic-gate goto end_proto;
10060Sstevel@tonic-gate }
10070Sstevel@tonic-gate zs = &zscom[ppa];
10080Sstevel@tonic-gate if (zs->zs_ops == NULL) {
10090Sstevel@tonic-gate error = ENXIO;
10100Sstevel@tonic-gate goto end_proto;
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10130Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
10140Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate * another protocol got here first
10170Sstevel@tonic-gate */
10180Sstevel@tonic-gate error = (EBUSY);
10190Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10200Sstevel@tonic-gate goto end_proto;
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate stp->str_com = (caddr_t)zs;
10250Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10260Sstevel@tonic-gate end_proto:
10270Sstevel@tonic-gate if (error)
10280Sstevel@tonic-gate dlerrorack(wq, mp, prim, error, 0);
10290Sstevel@tonic-gate else
10300Sstevel@tonic-gate dlokack(wq, mp, DL_ATTACH_REQ);
10310Sstevel@tonic-gate break;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate case M_IOCTL:
10340Sstevel@tonic-gate zsh_ioctl(wq, mp);
10350Sstevel@tonic-gate break;
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate case M_IOCDATA:
10380Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr;
10390Sstevel@tonic-gate if (resp->cp_rval) {
10400Sstevel@tonic-gate /*
10410Sstevel@tonic-gate * Just free message on failure.
10420Sstevel@tonic-gate */
10430Sstevel@tonic-gate freemsg(mp);
10440Sstevel@tonic-gate break;
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate switch (resp->cp_cmd) {
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate case S_IOCGETMODE:
10500Sstevel@tonic-gate case S_IOCGETSTATS:
10510Sstevel@tonic-gate case S_IOCGETSPEED:
10520Sstevel@tonic-gate case S_IOCGETMCTL:
10530Sstevel@tonic-gate case S_IOCGETMRU:
10540Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10550Sstevel@tonic-gate qreply(wq, mp);
10560Sstevel@tonic-gate break;
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate case S_IOCSETMODE:
10590Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
10600Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10610Sstevel@tonic-gate error = zsh_setmode(zs, zss,
1062*7656SSherry.Moore@Sun.COM (struct scc_mode *)mp->b_cont->b_rptr);
10630Sstevel@tonic-gate if (error) {
10640Sstevel@tonic-gate register struct iocblk *iocp =
1065*7656SSherry.Moore@Sun.COM (struct iocblk *)mp->b_rptr;
10660Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
10670Sstevel@tonic-gate iocp->ioc_error = error;
10680Sstevel@tonic-gate } else
10690Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10700Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10710Sstevel@tonic-gate qreply(wq, mp);
10720Sstevel@tonic-gate break;
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate case S_IOCSETMRU:
10750Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
10760Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10770Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr;
10780Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10790Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
10800Sstevel@tonic-gate qreply(wq, mp);
10810Sstevel@tonic-gate break;
10820Sstevel@tonic-gate default:
10830Sstevel@tonic-gate freemsg(mp);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate break;
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate /*
10880Sstevel@tonic-gate * We're at the bottom of the food chain, so we flush our
10890Sstevel@tonic-gate * write queue, clear the FLUSHW bit so it doesn't go round
10900Sstevel@tonic-gate * and round forever, then flush our read queue (since there's
10910Sstevel@tonic-gate * no read put procedure down here) and pass it up for any
10920Sstevel@tonic-gate * higher modules to deal with in their own way.
10930Sstevel@tonic-gate */
10940Sstevel@tonic-gate case M_FLUSH:
10950Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
10960Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10970Sstevel@tonic-gate flushq(wq, FLUSHDATA);
10980Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
10990Sstevel@tonic-gate tmp = zss->sl_xstandby;
11000Sstevel@tonic-gate zss->sl_xstandby = NULL;
11010Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11020Sstevel@tonic-gate if (tmp)
11030Sstevel@tonic-gate freemsg(tmp);
11040Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11050Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
11090Sstevel@tonic-gate mutex_enter(zs->zs_excl);
11100Sstevel@tonic-gate ZSH_FLUSHQ;
11110Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11120Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */
11130Sstevel@tonic-gate } else
11140Sstevel@tonic-gate freemsg(mp);
11150Sstevel@tonic-gate break;
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate default:
11180Sstevel@tonic-gate /*
11190Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age,
11200Sstevel@tonic-gate * thank you anyway."
11210Sstevel@tonic-gate */
11220Sstevel@tonic-gate freemsg(mp);
11230Sstevel@tonic-gate break;
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END, "zsh_wput end: zs = %p", zs);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate * Get the next message from the write queue, set up the necessary pointers,
11310Sstevel@tonic-gate * state info, etc., and start the transmit "engine" by sending the first
11320Sstevel@tonic-gate * character. We'll then rotate through txint until done, then get an xsint.
11330Sstevel@tonic-gate */
11340Sstevel@tonic-gate static int
zsh_start(struct zscom * zs,struct syncline * zss)11350Sstevel@tonic-gate zsh_start(struct zscom *zs, struct syncline *zss)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate register mblk_t *mp;
11380Sstevel@tonic-gate register uchar_t *wptr;
11390Sstevel@tonic-gate register uchar_t *rptr;
11400Sstevel@tonic-gate register uchar_t sl_flags = zss->sl_flags;
11410Sstevel@tonic-gate
11420Sstevel@tonic-gate /*
11430Sstevel@tonic-gate * Attempt to grab the next M_DATA message off the queue (that's
11440Sstevel@tonic-gate * all that will be left after wput) and begin transmission.
11450Sstevel@tonic-gate * This routine is normally called after completion of a previous
11460Sstevel@tonic-gate * frame, or when zsh_wput gets a new message. If we are in a
11470Sstevel@tonic-gate * mode that put us in the TX_RTS state, waiting for CTS, and CTS
11480Sstevel@tonic-gate * is not up yet, we have no business here. Ditto if we're in
11490Sstevel@tonic-gate * either the TX_ACTIVE or TX_CRC states. In these cases we
11500Sstevel@tonic-gate * don't clear SF_CALLSTART, so we don't forget there's work to do.
11510Sstevel@tonic-gate */
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_START,
11540Sstevel@tonic-gate "zsh_start start: zs = %p", zs);
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate if (sl_flags & SF_PHONY) {
11570Sstevel@tonic-gate sl_flags &= ~SF_PHONY;
11580Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
11590Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
11600Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
11610Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
11620Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
11630Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * if we get another msg by chance zsh_watchog will start
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG;
11680Sstevel@tonic-gate zss->sl_flags = sl_flags;
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
11710Sstevel@tonic-gate "zsh_start end: zs = %d", zs);
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate return (0);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate mp = zss->sl_xstandby;
11760Sstevel@tonic-gate if (mp == NULL) {
11770Sstevel@tonic-gate if (!(sl_flags & SF_FDXPTP)) {
11780Sstevel@tonic-gate sl_flags |= SF_PHONY;
11790Sstevel@tonic-gate ZSH_ALLOCB(mp);
11800Sstevel@tonic-gate if (!mp)
11810Sstevel@tonic-gate return (0);
11820Sstevel@tonic-gate mp->b_datap->db_type = M_RSE;
11830Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + 1;
11840Sstevel@tonic-gate goto transmit;
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG;
11870Sstevel@tonic-gate zss->sl_flags = sl_flags;
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
11900Sstevel@tonic-gate "zsh_start end: zs = %p", zs);
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate return (0);
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate transmit:
11960Sstevel@tonic-gate zss->sl_xstandby = NULL;
11970Sstevel@tonic-gate rptr = mp->b_rptr;
11980Sstevel@tonic-gate wptr = mp->b_wptr;
11990Sstevel@tonic-gate ZSSETSOFT(zs);
12000Sstevel@tonic-gate
12010Sstevel@tonic-gate #ifdef ZSH_DEBUG
12020Sstevel@tonic-gate if (zss->sl_xhead || zss->sl_xactb) {
12030Sstevel@tonic-gate debug_enter("xhead1");
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate #endif
12060Sstevel@tonic-gate
12070Sstevel@tonic-gate zss->sl_xhead = mp;
12080Sstevel@tonic-gate zss->sl_xactb = mp;
12090Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count;
12100Sstevel@tonic-gate zss->sl_txstate = TX_ACTIVE;
12110Sstevel@tonic-gate zss->sl_ocnt = 0;
12120Sstevel@tonic-gate SCC_BIS(10, ZSWR10_UNDERRUN_ABORT); /* abort on underrun */
12130Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXCRC); /* reset transmit CRC */
12140Sstevel@tonic-gate zss->sl_ocnt = wptr - rptr;
12150Sstevel@tonic-gate mp->b_wptr = rptr; /* to tell soft to free this msg */
12160Sstevel@tonic-gate SCC_WRITEDATA(*rptr++); /* resets TXINT */
12170Sstevel@tonic-gate zs->zs_wr_cur = rptr;
12180Sstevel@tonic-gate zs->zs_wr_lim = wptr;
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_EOM);
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END,
12230Sstevel@tonic-gate "zsh_start end: zs = %p", zs);
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate zss->sl_flags = sl_flags;
12260Sstevel@tonic-gate return (1);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate * Process an "ioctl" message sent down to us.
12320Sstevel@tonic-gate */
12330Sstevel@tonic-gate static void
zsh_ioctl(queue_t * wq,mblk_t * mp)12340Sstevel@tonic-gate zsh_ioctl(queue_t *wq, mblk_t *mp)
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr;
12370Sstevel@tonic-gate register struct zscom *zs = (struct zscom *)stp->str_com;
12380Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
12390Sstevel@tonic-gate register struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
12400Sstevel@tonic-gate register struct scc_mode *sm;
12410Sstevel@tonic-gate register struct sl_stats *st;
12420Sstevel@tonic-gate register uchar_t *msignals;
12430Sstevel@tonic-gate register mblk_t *tmp;
12440Sstevel@tonic-gate register int error = 0;
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate mutex_enter(zs->zs_excl);
12470Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
12480Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) {
12490Sstevel@tonic-gate /*
12500Sstevel@tonic-gate * another protocol got here first
12510Sstevel@tonic-gate */
12520Sstevel@tonic-gate error = (EBUSY);
12530Sstevel@tonic-gate goto end_zsh_ioctl;
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate switch (iocp->ioc_cmd) {
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate case S_IOCGETMODE:
12600Sstevel@tonic-gate tmp = allocb(sizeof (struct scc_mode), BPRI_MED);
12610Sstevel@tonic-gate if (tmp == NULL) {
12620Sstevel@tonic-gate error = EAGAIN;
12630Sstevel@tonic-gate break;
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12660Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct scc_mode), 0);
12670Sstevel@tonic-gate else
12680Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct scc_mode), NULL, tmp);
12690Sstevel@tonic-gate sm = (struct scc_mode *)mp->b_cont->b_rptr;
12700Sstevel@tonic-gate bcopy(&zss->sl_mode, sm, sizeof (struct scc_mode));
12710Sstevel@tonic-gate break;
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate case S_IOCGETSTATS:
12740Sstevel@tonic-gate tmp = allocb(sizeof (struct sl_stats), BPRI_MED);
12750Sstevel@tonic-gate if (tmp == NULL) {
12760Sstevel@tonic-gate error = EAGAIN;
12770Sstevel@tonic-gate break;
12780Sstevel@tonic-gate }
12790Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12800Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct sl_stats), 0);
12810Sstevel@tonic-gate else
12820Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct sl_stats), NULL, tmp);
12830Sstevel@tonic-gate st = (struct sl_stats *)mp->b_cont->b_rptr;
12840Sstevel@tonic-gate bcopy(&zss->sl_st, st, sizeof (struct sl_stats));
12850Sstevel@tonic-gate break;
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate case S_IOCGETSPEED:
12880Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED);
12890Sstevel@tonic-gate if (tmp == NULL) {
12900Sstevel@tonic-gate error = EAGAIN;
12910Sstevel@tonic-gate break;
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
12940Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0);
12950Sstevel@tonic-gate else
12960Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp);
12970Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mode.sm_baudrate;
12980Sstevel@tonic-gate break;
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate case S_IOCGETMCTL:
13010Sstevel@tonic-gate tmp = allocb(sizeof (char), BPRI_MED);
13020Sstevel@tonic-gate if (tmp == NULL) {
13030Sstevel@tonic-gate error = EAGAIN;
13040Sstevel@tonic-gate break;
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
13070Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (char), 0);
13080Sstevel@tonic-gate else
13090Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (char), NULL, tmp);
13100Sstevel@tonic-gate msignals = (uchar_t *)mp->b_cont->b_rptr;
13110Sstevel@tonic-gate *msignals = zss->sl_rr0 & (ZSRR0_CD | ZSRR0_CTS);
13120Sstevel@tonic-gate break;
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate case S_IOCGETMRU:
13150Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED);
13160Sstevel@tonic-gate if (tmp == NULL) {
13170Sstevel@tonic-gate error = EAGAIN;
13180Sstevel@tonic-gate break;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
13210Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0);
13220Sstevel@tonic-gate else
13230Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp);
13240Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mru;
13250Sstevel@tonic-gate break;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate case S_IOCSETMODE:
13280Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) {
13290Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct scc_mode));
13300Sstevel@tonic-gate if (error != 0)
13310Sstevel@tonic-gate break;
13320Sstevel@tonic-gate error = zsh_setmode(zs, zss,
13330Sstevel@tonic-gate (struct scc_mode *)mp->b_cont->b_rptr);
13340Sstevel@tonic-gate if (error == 0)
13350Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13360Sstevel@tonic-gate } else
13370Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (struct scc_mode), NULL);
13380Sstevel@tonic-gate break;
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate case S_IOCCLRSTATS:
13410Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13420Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats));
13430Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
13440Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13450Sstevel@tonic-gate break;
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate case S_IOCSETMRU:
13480Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) {
13490Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
13500Sstevel@tonic-gate if (error != 0)
13510Sstevel@tonic-gate break;
13520Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr;
13530Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
13540Sstevel@tonic-gate } else
13550Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL);
13560Sstevel@tonic-gate break;
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate case S_IOCSETDTR:
13590Sstevel@tonic-gate /*
13600Sstevel@tonic-gate * The first integer of the M_DATA block that should
13610Sstevel@tonic-gate * follow indicate if DTR must be set or reset
13620Sstevel@tonic-gate */
13630Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
13640Sstevel@tonic-gate if (error != 0)
13650Sstevel@tonic-gate break;
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13680Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0)
13690Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIS);
13700Sstevel@tonic-gate else
13710Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC);
13720Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
13730Sstevel@tonic-gate break;
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate default:
13760Sstevel@tonic-gate error = EINVAL;
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate end_zsh_ioctl:
13800Sstevel@tonic-gate iocp->ioc_error = error;
13810Sstevel@tonic-gate mp->b_datap->db_type = (error) ? M_IOCNAK : M_IOCACK;
13820Sstevel@tonic-gate mutex_exit(zs->zs_excl);
13830Sstevel@tonic-gate qreply(wq, mp);
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate /*
13870Sstevel@tonic-gate * Set the mode of the zsh port
13880Sstevel@tonic-gate */
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate int
zsh_setmode(struct zscom * zs,struct syncline * zss,struct scc_mode * sm)13910Sstevel@tonic-gate zsh_setmode(struct zscom *zs, struct syncline *zss, struct scc_mode *sm)
13920Sstevel@tonic-gate {
13930Sstevel@tonic-gate register int error = 0;
13940Sstevel@tonic-gate register mblk_t *mp;
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
13970Sstevel@tonic-gate if (sm->sm_rxclock == RXC_IS_PLL) {
13980Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC;
13990Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14000Sstevel@tonic-gate return (EINVAL); /* not supported */
14010Sstevel@tonic-gate } else {
14020Sstevel@tonic-gate if (((zss->sl_mode.sm_config ^ sm->sm_config) &
1403*7656SSherry.Moore@Sun.COM CONN_SIGNAL) != 0) { /* Changing, going... */
14040Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL) { /* ...up. */
14050Sstevel@tonic-gate if (zss->sl_mstat == NULL) {
1406*7656SSherry.Moore@Sun.COM mutex_exit(zs->zs_excl_hi);
1407*7656SSherry.Moore@Sun.COM mp = allocb(
1408*7656SSherry.Moore@Sun.COM sizeof (struct sl_status),
1409*7656SSherry.Moore@Sun.COM BPRI_MED);
1410*7656SSherry.Moore@Sun.COM mutex_enter(zs->zs_excl_hi);
1411*7656SSherry.Moore@Sun.COM zss->sl_mstat = mp;
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate } else { /* ...down. */
14140Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL)
14150Sstevel@tonic-gate zss->sl_mstat = NULL;
14160Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14170Sstevel@tonic-gate if (mp)
14180Sstevel@tonic-gate freemsg(mp);
14190Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate if (!(sm->sm_config & CONN_IBM)) {
14230Sstevel@tonic-gate if (sm->sm_config & CONN_HDX) {
14240Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_HDX;
14250Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14260Sstevel@tonic-gate return (EINVAL);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate if (sm->sm_config & CONN_MPT) {
14290Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_MPT;
14300Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14310Sstevel@tonic-gate return (EINVAL);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate }
14340Sstevel@tonic-gate zss->sl_flags &= ~SF_FDXPTP; /* "conmode" */
14350Sstevel@tonic-gate if ((sm->sm_config & (CONN_HDX | CONN_MPT)) == 0)
14360Sstevel@tonic-gate zss->sl_flags |= SF_FDXPTP;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate error = zsh_program(zs, sm);
14390Sstevel@tonic-gate if (!error && (zs->zs_ops != &zsops_null))
14400Sstevel@tonic-gate zsh_init_port(zs, zss);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate return (error);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate /*
14480Sstevel@tonic-gate * Transmit interrupt service procedure
14490Sstevel@tonic-gate */
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate static void
zsh_txint(struct zscom * zs)14520Sstevel@tonic-gate zsh_txint(struct zscom *zs)
14530Sstevel@tonic-gate {
14540Sstevel@tonic-gate register struct syncline *zss;
14550Sstevel@tonic-gate register mblk_t *mp;
14560Sstevel@tonic-gate register int tmp;
14570Sstevel@tonic-gate register uchar_t *wr_cur;
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_TXINT, "zsh_txint: zs = %p", zs);
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL && (wr_cur < zs->zs_wr_lim)) {
14620Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++);
14630Sstevel@tonic-gate zs->zs_wr_cur = wr_cur;
14640Sstevel@tonic-gate return;
14650Sstevel@tonic-gate }
14660Sstevel@tonic-gate
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str;
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate switch (zss->sl_txstate) {
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate /*
14730Sstevel@tonic-gate * we here because end of message block lim = cur
14740Sstevel@tonic-gate */
14750Sstevel@tonic-gate case TX_ACTIVE:
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate mp = zss->sl_xactb;
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate again_txint:
14800Sstevel@tonic-gate mp = mp->b_cont;
14810Sstevel@tonic-gate if (mp) {
14820Sstevel@tonic-gate zss->sl_xactb = mp;
14830Sstevel@tonic-gate zss->sl_ocnt += tmp = mp->b_wptr - mp->b_rptr;
14840Sstevel@tonic-gate if (!tmp)
14850Sstevel@tonic-gate goto again_txint;
14860Sstevel@tonic-gate zs->zs_wr_cur = mp->b_rptr;
14870Sstevel@tonic-gate zs->zs_wr_lim = mp->b_wptr;
14880Sstevel@tonic-gate SCC_WRITEDATA(*zs->zs_wr_cur++);
14890Sstevel@tonic-gate return;
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate * This is where the fun starts. At this point the
14940Sstevel@tonic-gate * last character in the frame has been sent. We
14950Sstevel@tonic-gate * issue a RESET_TXINT so we won't get another txint
14960Sstevel@tonic-gate * until the CRC has been completely sent. Also we
14970Sstevel@tonic-gate * reset the Abort-On-Underrun bit so that CRC is
14980Sstevel@tonic-gate * sent at EOM, rather than an Abort.
14990Sstevel@tonic-gate */
15000Sstevel@tonic-gate zs->zs_wr_cur = zs->zs_wr_lim = NULL;
15010Sstevel@tonic-gate zss->sl_txstate = TX_CRC;
15020Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15030Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY)) {
15040Sstevel@tonic-gate SCC_BIC(10, ZSWR10_UNDERRUN_ABORT);
15050Sstevel@tonic-gate zss->sl_st.opack++;
15060Sstevel@tonic-gate zss->sl_st.ochar += zss->sl_ocnt;
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate zss->sl_ocnt = 0;
15090Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead);
15100Sstevel@tonic-gate zss->sl_xhead = zss->sl_xactb = NULL;
15110Sstevel@tonic-gate ZSSETSOFT(zs);
15120Sstevel@tonic-gate break;
15130Sstevel@tonic-gate /*
15140Sstevel@tonic-gate * This txint means we have sent the CRC bytes at EOF.
15150Sstevel@tonic-gate * The next txint will mean we are sending or have sent the
15160Sstevel@tonic-gate * flag character at EOF, but we handle that differently, and
15170Sstevel@tonic-gate * enter different states,depending on whether we're IBM or not.
15180Sstevel@tonic-gate */
15190Sstevel@tonic-gate case TX_CRC:
15200Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
15210Sstevel@tonic-gate zss->sl_txstate = TX_FLAG; /* HDX path */
15220Sstevel@tonic-gate } else { /* FDX path */
15230Sstevel@tonic-gate if (!zsh_start(zs, zss)) {
15240Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
15250Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15260Sstevel@tonic-gate }
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate break;
15290Sstevel@tonic-gate
15300Sstevel@tonic-gate /*
15310Sstevel@tonic-gate * This txint means the closing flag byte is going out the door.
15320Sstevel@tonic-gate * We use this state to allow this to complete before dropping RTS.
15330Sstevel@tonic-gate */
15340Sstevel@tonic-gate case TX_FLAG:
15350Sstevel@tonic-gate zss->sl_txstate = TX_LAST;
15360Sstevel@tonic-gate (void) zsh_start(zs, zss);
15370Sstevel@tonic-gate break;
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate * Arriving here means the flag should be out and it's finally
15410Sstevel@tonic-gate * time to close the barn door.
15420Sstevel@tonic-gate */
15430Sstevel@tonic-gate case TX_LAST:
15440Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
15450Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15460Sstevel@tonic-gate break;
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate /*
15490Sstevel@tonic-gate * If transmit was aborted, do nothing - watchdog will recover.
15500Sstevel@tonic-gate */
15510Sstevel@tonic-gate case TX_ABORTED:
15520Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15530Sstevel@tonic-gate break;
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate default:
15560Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15570Sstevel@tonic-gate break;
15580Sstevel@tonic-gate }
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate /*
15620Sstevel@tonic-gate * External Status Change interrupt service procedure
15630Sstevel@tonic-gate */
15640Sstevel@tonic-gate static void
zsh_xsint(struct zscom * zs)15650Sstevel@tonic-gate zsh_xsint(struct zscom *zs)
15660Sstevel@tonic-gate {
15670Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
15680Sstevel@tonic-gate register uchar_t s0, x0;
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_XSINT, "zsh_xsint: zs = %p", zs);
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate s0 = SCC_READ0();
15730Sstevel@tonic-gate x0 = s0 ^ zss->sl_rr0;
15740Sstevel@tonic-gate zss->sl_rr0 = s0;
15750Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
15760Sstevel@tonic-gate
15770Sstevel@tonic-gate if (s0 & ZSRR0_TXUNDER) {
15780Sstevel@tonic-gate switch (zss->sl_txstate) {
15790Sstevel@tonic-gate /*
15800Sstevel@tonic-gate * A transmitter underrun has occurred. If we are not
15810Sstevel@tonic-gate * here as the result of an abort sent by the watchdog
15820Sstevel@tonic-gate * timeout routine, we need to send an abort to flush
15830Sstevel@tonic-gate * the transmitter. Otherwise there is a danger of
15840Sstevel@tonic-gate * trashing the next frame but still sending a good crc.
15850Sstevel@tonic-gate * The TX_ABORTED flag is set so that the watchdog
15860Sstevel@tonic-gate * routine can initiate recovery.
15870Sstevel@tonic-gate */
15880Sstevel@tonic-gate case TX_ACTIVE:
15890Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
15900Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
15910Sstevel@tonic-gate zss->sl_st.underrun++;
15920Sstevel@tonic-gate zsh_txbad(zs, zss);
15930Sstevel@tonic-gate
15940Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED;
15950Sstevel@tonic-gate zss->sl_wd_count = 0;
15960Sstevel@tonic-gate break;
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate case TX_CRC:
15990Sstevel@tonic-gate break;
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate case TX_FLAG:
16020Sstevel@tonic-gate break;
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate case TX_ABORTED:
16050Sstevel@tonic-gate break;
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate case TX_OFF:
16080Sstevel@tonic-gate break;
16090Sstevel@tonic-gate
16100Sstevel@tonic-gate case TX_LAST:
16110Sstevel@tonic-gate break;
16120Sstevel@tonic-gate
16130Sstevel@tonic-gate default:
16140Sstevel@tonic-gate break;
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate
16180Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) && zs->zs_rd_cur) {
16190Sstevel@tonic-gate zss->sl_st.abort++;
16200Sstevel@tonic-gate zsh_rxbad(zs, zss);
16210Sstevel@tonic-gate } else if ((s0 & ZSRR0_SYNC) && (zs->zs_rd_cur)) {
16220Sstevel@tonic-gate /*
16230Sstevel@tonic-gate * Tricky code to avoid disaster in the case where
16240Sstevel@tonic-gate * an abort was detected while receiving a packet,
16250Sstevel@tonic-gate * but the abort did not last long enough to be
16260Sstevel@tonic-gate * detected by zsh_xsint - this can happen since
16270Sstevel@tonic-gate * the ZSRR0_BREAK is not latched. Since an abort
16280Sstevel@tonic-gate * will automatically cause the SCC to enter
16290Sstevel@tonic-gate * hunt mode, hopefully, the sync/hunt bit will be
16300Sstevel@tonic-gate * set in this case (although if the interrupt is
16310Sstevel@tonic-gate * sufficiently delayed, the SCC may have sync'ed
16320Sstevel@tonic-gate * in again if it has detected a flag).
16330Sstevel@tonic-gate */
16340Sstevel@tonic-gate zss->sl_st.abort++;
16350Sstevel@tonic-gate zsh_rxbad(zs, zss);
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate if (x0 & s0 & ZSRR0_CTS) {
1639*7656SSherry.Moore@Sun.COM if (zss->sl_txstate == TX_RTS) {
1640*7656SSherry.Moore@Sun.COM if (!(zss->sl_flags & SF_FDXPTP)) {
1641*7656SSherry.Moore@Sun.COM SCC_BIS(5, ZSWR5_TX_ENABLE);
1642*7656SSherry.Moore@Sun.COM }
1643*7656SSherry.Moore@Sun.COM (void) zsh_start(zs, zss);
1644*7656SSherry.Moore@Sun.COM } else if ((zss->sl_mode.sm_config &
1645*7656SSherry.Moore@Sun.COM (CONN_IBM | CONN_SIGNAL))) {
1646*7656SSherry.Moore@Sun.COM zss->sl_flags &= ~SF_FLUSH_WQ;
1647*7656SSherry.Moore@Sun.COM zsh_setmstat(zs, CS_CTS_UP);
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate /*
16520Sstevel@tonic-gate * We don't care about CTS transitions unless we are in either
16530Sstevel@tonic-gate * IBM or SIGNAL mode, or both. So, if we see CTS drop, and we
16540Sstevel@tonic-gate * care, and we are not idle, send up a report message.
16550Sstevel@tonic-gate */
16560Sstevel@tonic-gate if ((x0 & ZSRR0_CTS) && ((s0 & ZSRR0_CTS) == 0) &&
16570Sstevel@tonic-gate (zss->sl_txstate != TX_OFF) &&
16580Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_IBM | CONN_SIGNAL))) {
16590Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS);
16600Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_DOWN);
16610Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG;
16620Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ;
16630Sstevel@tonic-gate zss->sl_st.cts++;
16640Sstevel@tonic-gate if (zss->sl_txstate != TX_IDLE)
16650Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
16660Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
16670Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16680Sstevel@tonic-gate zss->sl_wd_count = 0;
16690Sstevel@tonic-gate zsh_txbad(zs, zss);
16700Sstevel@tonic-gate }
16710Sstevel@tonic-gate }
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate /*
16750Sstevel@tonic-gate * Receive interrupt service procedure
16760Sstevel@tonic-gate */
16770Sstevel@tonic-gate static void
zsh_rxint(struct zscom * zs)16780Sstevel@tonic-gate zsh_rxint(struct zscom *zs)
16790Sstevel@tonic-gate {
16800Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
16810Sstevel@tonic-gate register mblk_t *bp = zss->sl_ractb;
16820Sstevel@tonic-gate unsigned char *rd_cur;
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_RXINT, "zsh_rxint: zs = %p", zs);
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate if (((rd_cur = zs->zs_rd_cur) != NULL) && rd_cur < zs->zs_rd_lim) {
16870Sstevel@tonic-gate *rd_cur++ = SCC_READDATA();
16880Sstevel@tonic-gate zs->zs_rd_cur = rd_cur;
16890Sstevel@tonic-gate return;
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate if (!rd_cur) { /* Beginning of frame */
16930Sstevel@tonic-gate if (!bp) {
16940Sstevel@tonic-gate ZSH_ALLOCB(bp);
16950Sstevel@tonic-gate zss->sl_ractb = bp;
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate zss->sl_rhead = bp;
16980Sstevel@tonic-gate } else { /* end of data block should be cur==lim */
16990Sstevel@tonic-gate bp->b_wptr = zs->zs_rd_cur;
17000Sstevel@tonic-gate ZSH_ALLOCB(bp->b_cont);
17010Sstevel@tonic-gate bp = zss->sl_ractb = bp->b_cont;
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate if (!bp) {
17040Sstevel@tonic-gate zss->sl_st.nobuffers++;
17050Sstevel@tonic-gate zsh_rxbad(zs, zss);
17060Sstevel@tonic-gate return;
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate zs->zs_rd_cur = bp->b_wptr;
17090Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim;
17100Sstevel@tonic-gate *zs->zs_rd_cur++ = SCC_READDATA(); /* Also resets interrupt */
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate /*
17150Sstevel@tonic-gate * Special Receive Condition Interrupt routine
17160Sstevel@tonic-gate */
17170Sstevel@tonic-gate static void
zsh_srint(struct zscom * zs)17180Sstevel@tonic-gate zsh_srint(struct zscom *zs)
17190Sstevel@tonic-gate {
17200Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
17210Sstevel@tonic-gate register uchar_t s1;
17220Sstevel@tonic-gate register uchar_t *rd_cur;
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SRINT, "zsh_srint: zs = %p", zs);
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate SCC_READ(1, s1);
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate if (s1 & ZSRR1_RXEOF) { /* end of frame */
17290Sstevel@tonic-gate (void) SCC_READDATA();
17300Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17310Sstevel@tonic-gate if (s1 & ZSRR1_FE) { /* bad CRC */
17320Sstevel@tonic-gate zss->sl_st.crc++;
17330Sstevel@tonic-gate zsh_rxbad(zs, zss);
17340Sstevel@tonic-gate return;
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate if ((rd_cur = zs->zs_rd_cur) == NULL)
17380Sstevel@tonic-gate return;
17390Sstevel@tonic-gate
17400Sstevel@tonic-gate /*
17410Sstevel@tonic-gate * Drop one CRC byte from length because it came in
17420Sstevel@tonic-gate * before the special interrupt got here.
17430Sstevel@tonic-gate */
17440Sstevel@tonic-gate zss->sl_ractb->b_wptr = rd_cur - 1;
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate * put on done queue
17480Sstevel@tonic-gate */
17490Sstevel@tonic-gate ZSH_PUTQ(zss->sl_rhead);
17500Sstevel@tonic-gate zss->sl_rhead = NULL;
17510Sstevel@tonic-gate zss->sl_ractb = NULL;
17520Sstevel@tonic-gate zs->zs_rd_cur = NULL;
17530Sstevel@tonic-gate zs->zs_rd_lim = NULL;
17540Sstevel@tonic-gate ZSSETSOFT(zs);
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate } else if (s1 & ZSRR1_DO) {
17570Sstevel@tonic-gate (void) SCC_READDATA();
17580Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17590Sstevel@tonic-gate zss->sl_st.overrun++;
17600Sstevel@tonic-gate zsh_rxbad(zs, zss);
17610Sstevel@tonic-gate } else
17620Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17630Sstevel@tonic-gate }
17640Sstevel@tonic-gate
17650Sstevel@tonic-gate /*
17660Sstevel@tonic-gate * Handle a second stage interrupt.
17670Sstevel@tonic-gate * Does mostly lower priority buffer management stuff.
17680Sstevel@tonic-gate */
17690Sstevel@tonic-gate static int
zsh_softint(struct zscom * zs)17700Sstevel@tonic-gate zsh_softint(struct zscom *zs)
17710Sstevel@tonic-gate {
17720Sstevel@tonic-gate register struct syncline *zss;
17730Sstevel@tonic-gate register queue_t *q;
17740Sstevel@tonic-gate register mblk_t *mp, *tmp;
17750Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL;
17760Sstevel@tonic-gate register int allocbcount = 0;
17770Sstevel@tonic-gate int m_error;
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_START, "zsh_soft start: zs = %p", zs);
17800Sstevel@tonic-gate
17810Sstevel@tonic-gate mutex_enter(zs->zs_excl);
17820Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv;
17830Sstevel@tonic-gate if (!zss || (q = zss->sl_stream.str_rq) == NULL) {
17840Sstevel@tonic-gate mutex_exit(zs->zs_excl);
17850Sstevel@tonic-gate return (0);
17860Sstevel@tonic-gate }
17870Sstevel@tonic-gate m_error = zss->sl_m_error;
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate zss->sl_m_error = 0;
17900Sstevel@tonic-gate
17910Sstevel@tonic-gate
17920Sstevel@tonic-gate if (!zss->sl_mstat)
17930Sstevel@tonic-gate zss->sl_mstat = allocb(sizeof (struct sl_status), BPRI_MED);
17940Sstevel@tonic-gate
17950Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
17960Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
17970Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
17980Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
17990Sstevel@tonic-gate } else {
18000Sstevel@tonic-gate register uchar_t s0;
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate s0 = SCC_READ0();
18030Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
18040Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
18050Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
18060Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
18070Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP);
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
18100Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18110Sstevel@tonic-gate flushq(WR(q), FLUSHDATA);
18120Sstevel@tonic-gate goto next;
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate next:
18190Sstevel@tonic-gate for (;;) {
18200Sstevel@tonic-gate ZSH_GETQ(mp);
18210Sstevel@tonic-gate if (!mp)
18220Sstevel@tonic-gate break;
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate if (mp->b_rptr == mp->b_wptr) {
18250Sstevel@tonic-gate if (mp->b_datap->db_type == M_RSE) {
18260Sstevel@tonic-gate allocbcount++;
18270Sstevel@tonic-gate }
18280Sstevel@tonic-gate freemsg(mp);
18290Sstevel@tonic-gate continue;
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) {
18320Sstevel@tonic-gate zss->sl_st.ichar += msgdsize(mp);
18330Sstevel@tonic-gate zss->sl_st.ipack++;
18340Sstevel@tonic-gate if (!(canputnext(q))) {
18350Sstevel@tonic-gate zss->sl_st.ierror++;
18360Sstevel@tonic-gate allocbcount++;
18370Sstevel@tonic-gate freemsg(mp);
18380Sstevel@tonic-gate continue;
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate } else if (mp->b_datap->db_type == M_PROTO) {
18410Sstevel@tonic-gate if (!(canputnext(q))) {
18420Sstevel@tonic-gate freemsg(mp);
18430Sstevel@tonic-gate continue;
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate }
18460Sstevel@tonic-gate if (!head) {
18470Sstevel@tonic-gate allocbcount++;
18480Sstevel@tonic-gate zss->sl_soft_active = 1;
18490Sstevel@tonic-gate head = mp;
18500Sstevel@tonic-gate } else {
18510Sstevel@tonic-gate if (!tail)
18520Sstevel@tonic-gate tail = head;
18530Sstevel@tonic-gate tail->b_next = mp;
18540Sstevel@tonic-gate tail = mp;
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate }
18570Sstevel@tonic-gate if (allocbcount)
18580Sstevel@tonic-gate ZSH_GETBLOCK(zs, allocbcount);
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate tmp = NULL;
18610Sstevel@tonic-gate again:
18620Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
18630Sstevel@tonic-gate if (!zss->sl_xstandby) {
18640Sstevel@tonic-gate if (tmp) {
18650Sstevel@tonic-gate zss->sl_xstandby = tmp;
18660Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18670Sstevel@tonic-gate } else {
18680Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18690Sstevel@tonic-gate if (tmp = getq(WR(q)))
18700Sstevel@tonic-gate goto again;
18710Sstevel@tonic-gate }
18720Sstevel@tonic-gate } else {
18730Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
18740Sstevel@tonic-gate if (tmp)
18750Sstevel@tonic-gate (void) putbq(WR(q), tmp);
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate mutex_exit(zs->zs_excl);
18790Sstevel@tonic-gate
18800Sstevel@tonic-gate while (head) {
18810Sstevel@tonic-gate if (!tail) {
18820Sstevel@tonic-gate putnext(q, head);
18830Sstevel@tonic-gate break;
18840Sstevel@tonic-gate }
18850Sstevel@tonic-gate mp = head;
18860Sstevel@tonic-gate head = head->b_next;
18870Sstevel@tonic-gate mp->b_next = NULL;
18880Sstevel@tonic-gate putnext(q, mp);
18890Sstevel@tonic-gate
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate if (m_error)
18930Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error);
18940Sstevel@tonic-gate
18950Sstevel@tonic-gate zss->sl_soft_active = 0;
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_END, "zsh_soft end: zs = %p", zs);
18980Sstevel@tonic-gate
18990Sstevel@tonic-gate return (0);
19000Sstevel@tonic-gate }
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate /*
19030Sstevel@tonic-gate * Initialization routine.
19040Sstevel@tonic-gate * Sets Clock sources, baud rate, modes and miscellaneous parameters.
19050Sstevel@tonic-gate */
19060Sstevel@tonic-gate static int
zsh_program(struct zscom * zs,struct scc_mode * sm)19070Sstevel@tonic-gate zsh_program(struct zscom *zs, struct scc_mode *sm)
19080Sstevel@tonic-gate {
19090Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
19100Sstevel@tonic-gate register struct zs_prog *zspp;
19110Sstevel@tonic-gate register ushort_t tconst = 0;
19120Sstevel@tonic-gate register int wr11 = 0;
19130Sstevel@tonic-gate register int baud = 0;
19140Sstevel@tonic-gate register int pll = 0;
19150Sstevel@tonic-gate register int speed = 0;
19160Sstevel@tonic-gate register int flags = ZSP_SYNC;
19170Sstevel@tonic-gate int err = 0;
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate ZSSETSOFT(zs); /* get our house in order */
19200Sstevel@tonic-gate
19210Sstevel@tonic-gate switch (sm->sm_txclock) {
19220Sstevel@tonic-gate case TXC_IS_TXC:
19230Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_TRXC;
19240Sstevel@tonic-gate break;
19250Sstevel@tonic-gate case TXC_IS_RXC:
19260Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_RTXC;
19270Sstevel@tonic-gate break;
19280Sstevel@tonic-gate case TXC_IS_BAUD:
19290Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_BAUD;
19300Sstevel@tonic-gate wr11 |= ZSWR11_TRXC_OUT_ENA + ZSWR11_TRXC_XMIT;
19310Sstevel@tonic-gate baud++;
19320Sstevel@tonic-gate break;
19330Sstevel@tonic-gate case TXC_IS_PLL:
19340Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_DPLL;
19350Sstevel@tonic-gate pll++;
19360Sstevel@tonic-gate break;
19370Sstevel@tonic-gate default:
19380Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_TXC;
19390Sstevel@tonic-gate err = EINVAL;
19400Sstevel@tonic-gate goto out;
19410Sstevel@tonic-gate }
19420Sstevel@tonic-gate switch (sm->sm_rxclock) {
19430Sstevel@tonic-gate case RXC_IS_RXC:
19440Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_RTXC;
19450Sstevel@tonic-gate break;
19460Sstevel@tonic-gate case RXC_IS_TXC:
19470Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_TRXC;
19480Sstevel@tonic-gate break;
19490Sstevel@tonic-gate case RXC_IS_BAUD:
19500Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_BAUD;
19510Sstevel@tonic-gate baud++;
19520Sstevel@tonic-gate break;
19530Sstevel@tonic-gate case RXC_IS_PLL:
19540Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_DPLL;
19550Sstevel@tonic-gate pll++;
19560Sstevel@tonic-gate break;
19570Sstevel@tonic-gate default:
19580Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC;
19590Sstevel@tonic-gate err = EINVAL;
19600Sstevel@tonic-gate goto out;
19610Sstevel@tonic-gate }
19620Sstevel@tonic-gate if (baud && pll) {
19630Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL;
19640Sstevel@tonic-gate err = EINVAL;
19650Sstevel@tonic-gate goto out;
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate if (pll && !(sm->sm_config & CONN_NRZI)) {
19680Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL;
19690Sstevel@tonic-gate err = EINVAL;
19700Sstevel@tonic-gate goto out;
19710Sstevel@tonic-gate }
19720Sstevel@tonic-gate
19730Sstevel@tonic-gate /*
19740Sstevel@tonic-gate * If we're going to use the BRG and the speed we want is != 0...
19750Sstevel@tonic-gate */
19760Sstevel@tonic-gate if (baud && (speed = sm->sm_baudrate)) {
19770Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2;
19780Sstevel@tonic-gate if (tconst == 0) {
19790Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE;
19800Sstevel@tonic-gate err = EINVAL;
19810Sstevel@tonic-gate goto out;
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate sm->sm_baudrate = PCLK / (2 * ((int)tconst + 2));
19840Sstevel@tonic-gate } else {
19850Sstevel@tonic-gate tconst = 0; /* Stop BRG. Also quiesces pin 24. */
19860Sstevel@tonic-gate }
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate if (pll) {
19890Sstevel@tonic-gate if ((speed = sm->sm_baudrate * 32) != 0)
19900Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2;
19910Sstevel@tonic-gate else
19920Sstevel@tonic-gate tconst = 0;
19930Sstevel@tonic-gate if (tconst == 0) {
19940Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE;
19950Sstevel@tonic-gate err = EINVAL;
19960Sstevel@tonic-gate goto out;
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate speed = PCLK / (2 * ((int)tconst + 2));
19990Sstevel@tonic-gate sm->sm_baudrate = speed / 32;
20000Sstevel@tonic-gate flags |= ZSP_PLL;
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate if ((sm->sm_config & (CONN_LPBK|CONN_ECHO)) == (CONN_LPBK|CONN_ECHO)) {
20040Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_LPBKS;
20050Sstevel@tonic-gate err = EINVAL;
20060Sstevel@tonic-gate goto out;
20070Sstevel@tonic-gate }
20080Sstevel@tonic-gate if (sm->sm_config & CONN_LPBK)
20090Sstevel@tonic-gate flags |= ZSP_LOOP;
20100Sstevel@tonic-gate if (sm->sm_config & CONN_NRZI)
20110Sstevel@tonic-gate flags |= ZSP_NRZI;
20120Sstevel@tonic-gate if (sm->sm_config & CONN_ECHO)
20130Sstevel@tonic-gate flags |= ZSP_ECHO;
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit];
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate zspp->zs = zs;
20180Sstevel@tonic-gate zspp->flags = (uchar_t)flags;
20190Sstevel@tonic-gate zspp->wr4 = ZSWR4_SDLC;
20200Sstevel@tonic-gate zspp->wr11 = (uchar_t)wr11;
20210Sstevel@tonic-gate zspp->wr12 = (uchar_t)(tconst & 0xff);
20220Sstevel@tonic-gate zspp->wr13 = (uchar_t)((tconst >> 8) & 0xff);
20230Sstevel@tonic-gate zspp->wr3 = (uchar_t)(ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE |
20240Sstevel@tonic-gate ZSWR3_RX_8);
20250Sstevel@tonic-gate zspp->wr5 = (uchar_t)(ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE);
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
20280Sstevel@tonic-gate zspp->wr5 |= ZSWR5_RTS;
20290Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; /* Assume CTS is high */
20300Sstevel@tonic-gate }
20310Sstevel@tonic-gate if (sm->sm_config & CONN_IBM) {
20320Sstevel@tonic-gate zspp->wr15 = (uchar_t)
20330Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS);
20340Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP))
20350Sstevel@tonic-gate zspp->wr15 &= ~ZSR15_CTS;
20360Sstevel@tonic-gate } else {
20370Sstevel@tonic-gate zspp->wr5 |= ZSWR5_TX_ENABLE;
20380Sstevel@tonic-gate zspp->wr15 = (uchar_t)
20390Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC);
20400Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL)
20410Sstevel@tonic-gate zspp->wr15 |= ZSR15_CTS;
20420Sstevel@tonic-gate }
20430Sstevel@tonic-gate
20440Sstevel@tonic-gate zs_program(zspp);
20450Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
20460Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */
20470Sstevel@tonic-gate zss->sl_flags |= SF_INITIALIZED;
20480Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats));
20490Sstevel@tonic-gate bcopy(sm, &zss->sl_mode, sizeof (struct scc_mode));
20500Sstevel@tonic-gate zss->sl_mode.sm_retval = 0; /* successful */
20510Sstevel@tonic-gate out:
20520Sstevel@tonic-gate return (err);
20530Sstevel@tonic-gate }
20540Sstevel@tonic-gate
20550Sstevel@tonic-gate /*
20560Sstevel@tonic-gate * Function to store modem signal changes in sl_mstat field.
20570Sstevel@tonic-gate * Note that these events are supposed to be so far apart in time that
20580Sstevel@tonic-gate * we should always be able to send up the event and allocate a message
20590Sstevel@tonic-gate * block before another one happens. If not, we'll overwrite this one.
20600Sstevel@tonic-gate */
20610Sstevel@tonic-gate static void
zsh_setmstat(struct zscom * zs,int event)20620Sstevel@tonic-gate zsh_setmstat(struct zscom *zs, int event)
20630Sstevel@tonic-gate {
20640Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
20650Sstevel@tonic-gate register struct sl_status *mstat;
20660Sstevel@tonic-gate register mblk_t *mp;
20670Sstevel@tonic-gate
20680Sstevel@tonic-gate if (((mp = zss->sl_mstat) != NULL) &&
20690Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_SIGNAL))) {
20700Sstevel@tonic-gate mstat = (struct sl_status *)mp->b_wptr;
20710Sstevel@tonic-gate mstat->type = (zss->sl_mode.sm_config & CONN_IBM) ?
20720Sstevel@tonic-gate SLS_LINKERR : SLS_MDMSTAT;
20730Sstevel@tonic-gate mstat->status = event;
20740Sstevel@tonic-gate gethrestime(&mstat->tstamp);
20750Sstevel@tonic-gate mp->b_wptr += sizeof (struct sl_status);
20760Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
20770Sstevel@tonic-gate ZSH_PUTQ(mp);
20780Sstevel@tonic-gate zss->sl_mstat = NULL;
20790Sstevel@tonic-gate ZSSETSOFT(zs);
20800Sstevel@tonic-gate }
20810Sstevel@tonic-gate }
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate /*
20840Sstevel@tonic-gate * Received Bad Frame procedure
20850Sstevel@tonic-gate */
20860Sstevel@tonic-gate static void
zsh_rxbad(struct zscom * zs,struct syncline * zss)20870Sstevel@tonic-gate zsh_rxbad(struct zscom *zs, struct syncline *zss)
20880Sstevel@tonic-gate {
20890Sstevel@tonic-gate /*
20900Sstevel@tonic-gate * swallow bad characters
20910Sstevel@tonic-gate */
20920Sstevel@tonic-gate (void) SCC_READDATA();
20930Sstevel@tonic-gate (void) SCC_READDATA();
20940Sstevel@tonic-gate (void) SCC_READDATA();
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate SCC_BIS(3, ZSWR3_HUNT); /* enter hunt mode - ignores rest of frame */
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate zss->sl_st.ierror++;
20990Sstevel@tonic-gate
21000Sstevel@tonic-gate /*
21010Sstevel@tonic-gate * Free active receive message.
21020Sstevel@tonic-gate */
21030Sstevel@tonic-gate if (zss->sl_rhead) {
21040Sstevel@tonic-gate zss->sl_rhead->b_wptr = zss->sl_rhead->b_rptr;
21050Sstevel@tonic-gate zss->sl_rhead->b_datap->db_type = M_RSE;
21060Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_rhead);
21070Sstevel@tonic-gate zss->sl_ractb = NULL;
21080Sstevel@tonic-gate zs->zs_rd_cur = NULL;
21090Sstevel@tonic-gate zs->zs_rd_lim = NULL;
21100Sstevel@tonic-gate }
21110Sstevel@tonic-gate if (zss->sl_rhead) {
21120Sstevel@tonic-gate zss->sl_rhead = NULL;
21130Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb);
21140Sstevel@tonic-gate zs->zs_rd_cur = NULL;
21150Sstevel@tonic-gate zs->zs_rd_lim = NULL;
21160Sstevel@tonic-gate }
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate ZSSETSOFT(zs);
21190Sstevel@tonic-gate }
21200Sstevel@tonic-gate
21210Sstevel@tonic-gate /*
21220Sstevel@tonic-gate * Transmit error procedure
21230Sstevel@tonic-gate */
21240Sstevel@tonic-gate static void
zsh_txbad(struct zscom * zs,struct syncline * zss)21250Sstevel@tonic-gate zsh_txbad(struct zscom *zs, struct syncline *zss)
21260Sstevel@tonic-gate {
21270Sstevel@tonic-gate if (zss->sl_xhead) { /* free the message we were sending */
21280Sstevel@tonic-gate zss->sl_xhead->b_wptr = zss->sl_xhead->b_rptr;
21290Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead);
21300Sstevel@tonic-gate zss->sl_xactb = NULL;
21310Sstevel@tonic-gate zs->zs_wr_cur = NULL;
21320Sstevel@tonic-gate zs->zs_wr_lim = NULL;
21330Sstevel@tonic-gate }
21340Sstevel@tonic-gate zss->sl_xhead = NULL;
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) {
21370Sstevel@tonic-gate /*
21380Sstevel@tonic-gate * drop RTS and our notion of CTS
21390Sstevel@tonic-gate */
21400Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS);
21410Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE);
21420Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS;
21430Sstevel@tonic-gate }
21440Sstevel@tonic-gate zss->sl_txstate = TX_IDLE;
21450Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY))
21460Sstevel@tonic-gate zss->sl_st.oerror++;
21470Sstevel@tonic-gate }
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate /*
21500Sstevel@tonic-gate * Transmitter watchdog timeout routine
21510Sstevel@tonic-gate */
21520Sstevel@tonic-gate static void
zsh_watchdog(void * arg)21530Sstevel@tonic-gate zsh_watchdog(void *arg)
21540Sstevel@tonic-gate {
21550Sstevel@tonic-gate struct zscom *zs = arg;
21560Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
21570Sstevel@tonic-gate queue_t *wq;
21580Sstevel@tonic-gate mblk_t *mp;
21590Sstevel@tonic-gate int warning = 0;
21600Sstevel@tonic-gate uchar_t s0;
21610Sstevel@tonic-gate int do_flushwq = 0;
21620Sstevel@tonic-gate
21630Sstevel@tonic-gate /*
21640Sstevel@tonic-gate * The main reason for this routine is because, under some
21650Sstevel@tonic-gate * circumstances, a transmit interrupt may get lost (ie., if
21660Sstevel@tonic-gate * underrun occurs after the last character has been sent, and
21670Sstevel@tonic-gate * the tx interrupt following the abort gets scheduled before
21680Sstevel@tonic-gate * the current tx interrupt has been serviced). Transmit can
21690Sstevel@tonic-gate * also get hung if the cable is pulled out and the clock was
21700Sstevel@tonic-gate * coming in from the modem.
21710Sstevel@tonic-gate */
21720Sstevel@tonic-gate
21730Sstevel@tonic-gate mutex_enter(zs->zs_excl);
21740Sstevel@tonic-gate if (zss->sl_stream.str_rq)
21750Sstevel@tonic-gate wq = WR(zss->sl_stream.str_rq);
21760Sstevel@tonic-gate else {
21770Sstevel@tonic-gate mutex_exit(zs->zs_excl);
21780Sstevel@tonic-gate return; /* guard against close/callback race */
21790Sstevel@tonic-gate }
21800Sstevel@tonic-gate
21810Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
21820Sstevel@tonic-gate if (!(zss->sl_flags & SF_XMT_INPROG) && wq->q_first) {
21830Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
21840Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) ||
21850Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss))
21860Sstevel@tonic-gate (void) zsh_start(zs, zss);
21870Sstevel@tonic-gate goto end_watchdog;
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate if (zss->sl_wd_count-- > 0)
21910Sstevel@tonic-gate goto end_watchdog;
21920Sstevel@tonic-gate
21930Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) {
21940Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP))
21950Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
21960Sstevel@tonic-gate else {
21970Sstevel@tonic-gate s0 = SCC_READ0();
21980Sstevel@tonic-gate if (s0 & ZSRR0_CTS) {
21990Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS;
22000Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS);
22010Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ;
22020Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP);
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate }
22050Sstevel@tonic-gate }
22060Sstevel@tonic-gate
22070Sstevel@tonic-gate switch (zss->sl_txstate) {
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate case TX_ABORTED:
22100Sstevel@tonic-gate /*
22110Sstevel@tonic-gate * Transmitter was hung ... try restarting it.
22120Sstevel@tonic-gate */
22130Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) {
22140Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG;
22150Sstevel@tonic-gate (void) zsh_start(zs, zss);
22160Sstevel@tonic-gate } else
22170Sstevel@tonic-gate do_flushwq = 1;
22180Sstevel@tonic-gate break;
22190Sstevel@tonic-gate
22200Sstevel@tonic-gate case TX_ACTIVE:
22210Sstevel@tonic-gate case TX_CRC:
22220Sstevel@tonic-gate /*
22230Sstevel@tonic-gate * Transmit is hung for some reason. Reset tx interrupt.
22240Sstevel@tonic-gate * Flush transmit fifo by sending an abort command
22250Sstevel@tonic-gate * which also sets the Underrun/EOM latch in WR0 and in
22260Sstevel@tonic-gate * turn generates an External Status interrupt that
22270Sstevel@tonic-gate * will reset the necessary message buffer pointers.
22280Sstevel@tonic-gate * The watchdog timer will cycle again to allow the SCC
22290Sstevel@tonic-gate * to settle down after the abort command. The next
22300Sstevel@tonic-gate * time through we'll see that the state is now TX_ABORTED
22310Sstevel@tonic-gate * and call zsh_start to grab a new message.
22320Sstevel@tonic-gate */
22330Sstevel@tonic-gate if (--zss->sl_wd_count <= 0) {
22340Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT);
22350Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
22360Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
22370Sstevel@tonic-gate zsh_txbad(zs, zss);
22380Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED; /* must be after txbad */
22390Sstevel@tonic-gate warning = 1;
22400Sstevel@tonic-gate }
22410Sstevel@tonic-gate break;
22420Sstevel@tonic-gate
22430Sstevel@tonic-gate case TX_RTS:
22440Sstevel@tonic-gate /*
22450Sstevel@tonic-gate * Timer expired after we raised RTS. CTS never came up.
22460Sstevel@tonic-gate */
22470Sstevel@tonic-gate zss->sl_st.cts++;
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_TO);
22500Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG;
22510Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ;
22520Sstevel@tonic-gate ZSSETSOFT(zs);
22530Sstevel@tonic-gate break;
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate default:
22560Sstevel@tonic-gate /*
22570Sstevel@tonic-gate * If we time out in an inactive state we set a soft
22580Sstevel@tonic-gate * interrupt. This will call zsh_start which will
22590Sstevel@tonic-gate * clear SF_XMT_INPROG if the queue is empty.
22600Sstevel@tonic-gate */
22610Sstevel@tonic-gate break;
22620Sstevel@tonic-gate }
22630Sstevel@tonic-gate end_watchdog:
22640Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) {
22650Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22660Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs, SIO_WATCHDOG_TICK);
22670Sstevel@tonic-gate } else {
22680Sstevel@tonic-gate zss->sl_wd_id = 0; /* safety */
22690Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22700Sstevel@tonic-gate }
22710Sstevel@tonic-gate if (warning || do_flushwq) {
22720Sstevel@tonic-gate flushq(wq, FLUSHDATA);
22730Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
22740Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL)
22750Sstevel@tonic-gate zss->sl_xstandby = NULL;
22760Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22770Sstevel@tonic-gate if (mp)
22780Sstevel@tonic-gate freemsg(mp);
22790Sstevel@tonic-gate }
22800Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22810Sstevel@tonic-gate if (warning)
22820Sstevel@tonic-gate cmn_err(CE_WARN, "zsh%x: transmit hung", zs->zs_unit);
22830Sstevel@tonic-gate }
22840Sstevel@tonic-gate
22850Sstevel@tonic-gate static void
zsh_callback(void * arg)22860Sstevel@tonic-gate zsh_callback(void *arg)
22870Sstevel@tonic-gate {
22880Sstevel@tonic-gate struct zscom *zs = arg;
22890Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str;
22900Sstevel@tonic-gate int tmp = ZSH_MAX_RSTANDBY;
22910Sstevel@tonic-gate
22920Sstevel@tonic-gate mutex_enter(zs->zs_excl);
22930Sstevel@tonic-gate if (zss->sl_bufcid) {
22940Sstevel@tonic-gate zss->sl_bufcid = 0;
22950Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp);
22960Sstevel@tonic-gate }
22970Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22980Sstevel@tonic-gate }
2299