1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * HDLC protocol handler for Z8530 SCC. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/param.h> 34*0Sstevel@tonic-gate #include <sys/systm.h> 35*0Sstevel@tonic-gate #include <sys/types.h> 36*0Sstevel@tonic-gate #include <sys/sysmacros.h> 37*0Sstevel@tonic-gate #include <sys/kmem.h> 38*0Sstevel@tonic-gate #include <sys/stropts.h> 39*0Sstevel@tonic-gate #include <sys/stream.h> 40*0Sstevel@tonic-gate #include <sys/strsun.h> 41*0Sstevel@tonic-gate #include <sys/stat.h> 42*0Sstevel@tonic-gate #include <sys/cred.h> 43*0Sstevel@tonic-gate #include <sys/user.h> 44*0Sstevel@tonic-gate #include <sys/proc.h> 45*0Sstevel@tonic-gate #include <sys/file.h> 46*0Sstevel@tonic-gate #include <sys/uio.h> 47*0Sstevel@tonic-gate #include <sys/buf.h> 48*0Sstevel@tonic-gate #include <sys/mkdev.h> 49*0Sstevel@tonic-gate #include <sys/cmn_err.h> 50*0Sstevel@tonic-gate #include <sys/errno.h> 51*0Sstevel@tonic-gate #include <sys/fcntl.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <sys/zsdev.h> 54*0Sstevel@tonic-gate #include <sys/ser_sync.h> 55*0Sstevel@tonic-gate #include <sys/conf.h> 56*0Sstevel@tonic-gate #include <sys/ddi.h> 57*0Sstevel@tonic-gate #include <sys/sunddi.h> 58*0Sstevel@tonic-gate #include <sys/dlpi.h> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #define ZSH_TRACING 61*0Sstevel@tonic-gate #ifdef ZSH_TRACING 62*0Sstevel@tonic-gate #include <sys/vtrace.h> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* 65*0Sstevel@tonic-gate * Temp tracepoint definitions 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate #define TR_ZSH 50 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #define TR_ZSH_TXINT 1 70*0Sstevel@tonic-gate #define TR_ZSH_XSINT 2 71*0Sstevel@tonic-gate #define TR_ZSH_RXINT 3 72*0Sstevel@tonic-gate #define TR_ZSH_SRINT 4 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #define TR_ZSH_WPUT_START 5 75*0Sstevel@tonic-gate #define TR_ZSH_WPUT_END 6 76*0Sstevel@tonic-gate #define TR_ZSH_START_START 7 77*0Sstevel@tonic-gate #define TR_ZSH_START_END 8 78*0Sstevel@tonic-gate #define TR_ZSH_SOFT_START 9 79*0Sstevel@tonic-gate #define TR_ZSH_SOFT_END 10 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #define TR_ZSH_OPEN 11 82*0Sstevel@tonic-gate #define TR_ZSH_CLOSE 12 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #endif /* ZSH_TRACING */ 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * Logging definitions 88*0Sstevel@tonic-gate */ 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* 91*0Sstevel@tonic-gate * #define ZSH_DEBUG 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate #ifdef ZSH_DEBUG 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL 96*0Sstevel@tonic-gate extern char zs_h_log[]; 97*0Sstevel@tonic-gate extern int zs_h_log_n; 98*0Sstevel@tonic-gate #define zsh_h_log_add(c) \ 99*0Sstevel@tonic-gate { \ 100*0Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \ 101*0Sstevel@tonic-gate zs_h_log_n = 0; \ 102*0Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \ 103*0Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \ 104*0Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \ 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate #define zsh_h_log_clear 107*0Sstevel@tonic-gate #else 108*0Sstevel@tonic-gate #define ZSH_H_LOG_MAX 0x8000 109*0Sstevel@tonic-gate char zsh_h_log[2][ZSH_H_LOG_MAX +10]; 110*0Sstevel@tonic-gate int zsh_h_log_n[2]; 111*0Sstevel@tonic-gate #define zsh_h_log_add(c) \ 112*0Sstevel@tonic-gate { \ 113*0Sstevel@tonic-gate if (zsh_h_log_n[zs->zs_unit] >= ZSH_H_LOG_MAX) \ 114*0Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \ 115*0Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]++] = c; \ 116*0Sstevel@tonic-gate zsh_h_log[zs->zs_unit][zsh_h_log_n[zs->zs_unit]] = '\0'; \ 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate #define zsh_h_log_clear \ 120*0Sstevel@tonic-gate { register char *p; \ 121*0Sstevel@tonic-gate for (p = &zsh_h_log[zs->zs_unit][ZSH_H_LOG_MAX]; \ 122*0Sstevel@tonic-gate p >= &zsh_h_log[zs->zs_unit][0]; p--) \ 123*0Sstevel@tonic-gate *p = '\0'; \ 124*0Sstevel@tonic-gate zsh_h_log_n[zs->zs_unit] = 0; \ 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate #endif 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate #define ZSH_R0_LOG(r0) { \ 129*0Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsh_h_log_add('R'); \ 130*0Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsh_h_log_add('Z'); \ 131*0Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsh_h_log_add('T'); \ 132*0Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsh_h_log_add('D'); \ 133*0Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsh_h_log_add('S'); \ 134*0Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsh_h_log_add('C'); \ 135*0Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsh_h_log_add('U'); \ 136*0Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsh_h_log_add('B'); \ 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate #endif 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate char _depends_on[] = "drv/zs"; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #ifndef MAXZSH 144*0Sstevel@tonic-gate #define MAXZSH 2 145*0Sstevel@tonic-gate #define MAXZSHCLONES (80) /* three clone opens per instance */ 146*0Sstevel@tonic-gate #endif /* MAXZSH */ 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate int maxzsh = MAXZSH; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate int zsh_timer_count = 10; 151*0Sstevel@tonic-gate int zsh_default_mru = 1024; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate struct ser_str *zsh_str = NULL; 154*0Sstevel@tonic-gate unsigned char zsh_usedminor[MAXZSHCLONES]; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * The HDLC protocol 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate int zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); 161*0Sstevel@tonic-gate static int zsh_probe(dev_info_t *dev); 162*0Sstevel@tonic-gate static int zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd); 163*0Sstevel@tonic-gate static int zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd); 164*0Sstevel@tonic-gate static int zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 165*0Sstevel@tonic-gate static int zsh_close(queue_t *rq, int flag); 166*0Sstevel@tonic-gate static void zsh_wput(queue_t *wq, mblk_t *mp); 167*0Sstevel@tonic-gate static int zsh_start(struct zscom *zs, struct syncline *zss); 168*0Sstevel@tonic-gate static void zsh_ioctl(queue_t *wq, mblk_t *mp); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate static struct module_info hdlc_minfo = { 171*0Sstevel@tonic-gate 0x5a48, /* module ID number: "ZH" */ 172*0Sstevel@tonic-gate "zsh", /* module name */ 173*0Sstevel@tonic-gate 0, /* minimum packet size accepted */ 174*0Sstevel@tonic-gate INFPSZ, /* maximum packet size accepted */ 175*0Sstevel@tonic-gate 12*1024, /* queue high water mark (bytes) */ 176*0Sstevel@tonic-gate 4*1024 /* queue low water mark (bytes) */ 177*0Sstevel@tonic-gate }; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate static struct qinit hdlc_rinit = { 180*0Sstevel@tonic-gate putq, /* input put procedure */ 181*0Sstevel@tonic-gate NULL, /* input service procedure */ 182*0Sstevel@tonic-gate zsh_open, /* open procedure */ 183*0Sstevel@tonic-gate zsh_close, /* close procedure */ 184*0Sstevel@tonic-gate NULL, /* reserved */ 185*0Sstevel@tonic-gate &hdlc_minfo, /* module info */ 186*0Sstevel@tonic-gate NULL /* reserved */ 187*0Sstevel@tonic-gate }; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate static struct qinit hdlc_winit = { 190*0Sstevel@tonic-gate (int (*)())zsh_wput, /* output put procedure */ 191*0Sstevel@tonic-gate NULL, /* output service procedure */ 192*0Sstevel@tonic-gate NULL, /* open procedure */ 193*0Sstevel@tonic-gate NULL, /* close procedure */ 194*0Sstevel@tonic-gate NULL, /* reserved */ 195*0Sstevel@tonic-gate &hdlc_minfo, /* module info */ 196*0Sstevel@tonic-gate NULL /* reserved */ 197*0Sstevel@tonic-gate }; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate struct streamtab hdlctab = { 200*0Sstevel@tonic-gate &hdlc_rinit, /* initialize read queue */ 201*0Sstevel@tonic-gate &hdlc_winit, /* initialize write queue */ 202*0Sstevel@tonic-gate NULL, /* mux read qinit */ 203*0Sstevel@tonic-gate NULL /* mux write qinit */ 204*0Sstevel@tonic-gate }; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(zsh_ops, nulldev, zsh_probe, zsh_attach, 207*0Sstevel@tonic-gate zsh_detach, nodev, zsh_info, D_MP, &hdlctab); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * This is the loadable module wrapper. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate #include <sys/errno.h> 214*0Sstevel@tonic-gate #include <sys/modctl.h> 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Module linkage information for the kernel. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate static struct modldrv modldrv = { 221*0Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 222*0Sstevel@tonic-gate "Z8530 serial HDLC drv V%I%", 223*0Sstevel@tonic-gate &zsh_ops, /* our own ops for this module */ 224*0Sstevel@tonic-gate }; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 227*0Sstevel@tonic-gate MODREV_1, 228*0Sstevel@tonic-gate (void *)&modldrv, 229*0Sstevel@tonic-gate NULL 230*0Sstevel@tonic-gate }; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate int 233*0Sstevel@tonic-gate _init(void) 234*0Sstevel@tonic-gate { 235*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate int 239*0Sstevel@tonic-gate _fini(void) 240*0Sstevel@tonic-gate { 241*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate int 245*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 246*0Sstevel@tonic-gate { 247*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * The HDLC interrupt entry points. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate static void zsh_txint(struct zscom *zs); 255*0Sstevel@tonic-gate static void zsh_xsint(struct zscom *zs); 256*0Sstevel@tonic-gate static void zsh_rxint(struct zscom *zs); 257*0Sstevel@tonic-gate static void zsh_srint(struct zscom *zs); 258*0Sstevel@tonic-gate static int zsh_softint(struct zscom *zs); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate struct zsops zsops_hdlc = { 261*0Sstevel@tonic-gate zsh_txint, 262*0Sstevel@tonic-gate zsh_xsint, 263*0Sstevel@tonic-gate zsh_rxint, 264*0Sstevel@tonic-gate zsh_srint, 265*0Sstevel@tonic-gate zsh_softint, 266*0Sstevel@tonic-gate NULL, 267*0Sstevel@tonic-gate NULL 268*0Sstevel@tonic-gate }; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate static int zsh_program(struct zscom *zs, struct scc_mode *sm); 271*0Sstevel@tonic-gate static void zsh_setmstat(struct zscom *zs, int event); 272*0Sstevel@tonic-gate static void zsh_rxbad(struct zscom *zs, struct syncline *zss); 273*0Sstevel@tonic-gate static void zsh_txbad(struct zscom *zs, struct syncline *zss); 274*0Sstevel@tonic-gate static void zsh_watchdog(void *); 275*0Sstevel@tonic-gate static void zsh_callback(void *); 276*0Sstevel@tonic-gate static int zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss); 277*0Sstevel@tonic-gate static void zsh_init_port(struct zscom *zs, struct syncline *zss); 278*0Sstevel@tonic-gate static int zsh_setmode(struct zscom *zs, struct syncline *zss, 279*0Sstevel@tonic-gate struct scc_mode *sm); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * The HDLC Driver. 284*0Sstevel@tonic-gate */ 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * Special macros to handle STREAMS operations. 289*0Sstevel@tonic-gate * These are required to address memory leakage problems. 290*0Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate /* 294*0Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate #define ZSH_GETBLOCK(zs, allocbcount) \ 297*0Sstevel@tonic-gate { \ 298*0Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \ 299*0Sstevel@tonic-gate while (--n >= 0) { \ 300*0Sstevel@tonic-gate if (!zss->sl_rstandby[n]) { \ 301*0Sstevel@tonic-gate if ((zss->sl_rstandby[n] = \ 302*0Sstevel@tonic-gate allocb(zss->sl_mru, BPRI_MED)) == NULL) { \ 303*0Sstevel@tonic-gate if (zss->sl_bufcid == 0) { \ 304*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \ 305*0Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) { \ 306*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 307*0Sstevel@tonic-gate zss->sl_bufcid = bufcall(zss->sl_mru, \ 308*0Sstevel@tonic-gate BPRI_MED, zsh_callback, zs); \ 309*0Sstevel@tonic-gate break; \ 310*0Sstevel@tonic-gate } else \ 311*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 312*0Sstevel@tonic-gate } \ 313*0Sstevel@tonic-gate } \ 314*0Sstevel@tonic-gate allocbcount--; \ 315*0Sstevel@tonic-gate } \ 316*0Sstevel@tonic-gate } \ 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate #define ZSH_ALLOCB(mp) \ 323*0Sstevel@tonic-gate { \ 324*0Sstevel@tonic-gate register int n = ZSH_MAX_RSTANDBY; \ 325*0Sstevel@tonic-gate mp = NULL; \ 326*0Sstevel@tonic-gate while (--n >= 0) { \ 327*0Sstevel@tonic-gate if ((mp = zss->sl_rstandby[n]) != NULL) { \ 328*0Sstevel@tonic-gate zss->sl_rstandby[n] = NULL; \ 329*0Sstevel@tonic-gate break; \ 330*0Sstevel@tonic-gate } \ 331*0Sstevel@tonic-gate } \ 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate #define ZSH_PUTQ(mp) \ 335*0Sstevel@tonic-gate { \ 336*0Sstevel@tonic-gate register int wptr, rptr; \ 337*0Sstevel@tonic-gate wptr = zss->sl_rdone_wptr; \ 338*0Sstevel@tonic-gate rptr = zss->sl_rdone_rptr; \ 339*0Sstevel@tonic-gate zss->sl_rdone[wptr] = mp; \ 340*0Sstevel@tonic-gate if ((wptr) + 1 == ZSH_RDONE_MAX) \ 341*0Sstevel@tonic-gate zss->sl_rdone_wptr = wptr = 0; \ 342*0Sstevel@tonic-gate else \ 343*0Sstevel@tonic-gate zss->sl_rdone_wptr = ++wptr; \ 344*0Sstevel@tonic-gate if (wptr == rptr) { /* Should never occur */ \ 345*0Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \ 346*0Sstevel@tonic-gate zss->sl_m_error = ENOSR; \ 347*0Sstevel@tonic-gate ZSSETSOFT(zs); \ 348*0Sstevel@tonic-gate } \ 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate #define ZSH_FREEMSG(mp) \ 352*0Sstevel@tonic-gate { \ 353*0Sstevel@tonic-gate ZSH_PUTQ(mp); \ 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate /* 358*0Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 359*0Sstevel@tonic-gate */ 360*0Sstevel@tonic-gate #define ZSH_GETQ(mp) \ 361*0Sstevel@tonic-gate { \ 362*0Sstevel@tonic-gate if (zss->sl_rdone_rptr != zss->sl_rdone_wptr) { \ 363*0Sstevel@tonic-gate mp = zss->sl_rdone[zss->sl_rdone_rptr++]; \ 364*0Sstevel@tonic-gate if (zss->sl_rdone_rptr == ZSH_RDONE_MAX) \ 365*0Sstevel@tonic-gate zss->sl_rdone_rptr = 0; \ 366*0Sstevel@tonic-gate } else \ 367*0Sstevel@tonic-gate mp = NULL; \ 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate #define ZSH_FLUSHQ \ 371*0Sstevel@tonic-gate { \ 372*0Sstevel@tonic-gate register mblk_t *tmp; \ 373*0Sstevel@tonic-gate for (;;) { \ 374*0Sstevel@tonic-gate ZSH_GETQ(tmp); \ 375*0Sstevel@tonic-gate if (!(tmp)) \ 376*0Sstevel@tonic-gate break; \ 377*0Sstevel@tonic-gate freemsg(tmp); \ 378*0Sstevel@tonic-gate } \ 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /*ARGSUSED*/ 382*0Sstevel@tonic-gate static int 383*0Sstevel@tonic-gate zsh_probe(dev_info_t *dev) 384*0Sstevel@tonic-gate { 385*0Sstevel@tonic-gate return (DDI_PROBE_DONTCARE); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate /*ARGSUSED*/ 389*0Sstevel@tonic-gate static int 390*0Sstevel@tonic-gate zsh_attach(dev_info_t *dev, ddi_attach_cmd_t cmd) 391*0Sstevel@tonic-gate { 392*0Sstevel@tonic-gate register int unit; 393*0Sstevel@tonic-gate char name[3] = { 394*0Sstevel@tonic-gate '\0', '\0', '\0' }; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * Since zsh is a child of the "pseudo" nexus, we can expect the 398*0Sstevel@tonic-gate * attach routine to be called only once. We need to create all 399*0Sstevel@tonic-gate * necessary devices in one shot. There is never more than one 400*0Sstevel@tonic-gate * SCC chip that supports zsh devices. 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate if (cmd != DDI_ATTACH) 404*0Sstevel@tonic-gate return (DDI_FAILURE); 405*0Sstevel@tonic-gate if (zscom == NULL) 406*0Sstevel@tonic-gate return (DDI_FAILURE); /* zsattach not done */ 407*0Sstevel@tonic-gate unit = 2 * ddi_get_instance(dev); 408*0Sstevel@tonic-gate if (unit > 1) 409*0Sstevel@tonic-gate return (DDI_FAILURE); /* only use cpu ports */ 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate if (ddi_create_minor_node(dev, "zsh", S_IFCHR, 412*0Sstevel@tonic-gate NULL, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) { 413*0Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 414*0Sstevel@tonic-gate cmn_err(CE_WARN, "zsh clone device creation failed."); 415*0Sstevel@tonic-gate return (DDI_FAILURE); 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate for (; unit < maxzsh/2; unit++) { 419*0Sstevel@tonic-gate zscom[unit].zs_hdlc_dip = dev; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate (void) sprintf(name, "%d", unit); 422*0Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 423*0Sstevel@tonic-gate 2*unit, DDI_PSEUDO, NULL) == DDI_FAILURE) { 424*0Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 425*0Sstevel@tonic-gate return (DDI_FAILURE); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate unit++; 428*0Sstevel@tonic-gate (void) sprintf(name, "%d", unit); 429*0Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 430*0Sstevel@tonic-gate 2*(unit-1)+1, DDI_PSEUDO, NULL) == DDI_FAILURE) { 431*0Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 432*0Sstevel@tonic-gate return (DDI_FAILURE); 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate return (DDI_SUCCESS); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* ARGSUSED */ 440*0Sstevel@tonic-gate int 441*0Sstevel@tonic-gate zsh_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 442*0Sstevel@tonic-gate void **result) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate register dev_t dev = (dev_t)arg; 445*0Sstevel@tonic-gate register int unit, error; 446*0Sstevel@tonic-gate register struct zscom *zs; 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs) 449*0Sstevel@tonic-gate return (DDI_FAILURE); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate switch (infocmd) { 452*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 453*0Sstevel@tonic-gate if (zscom == NULL) { 454*0Sstevel@tonic-gate error = DDI_FAILURE; 455*0Sstevel@tonic-gate } else { 456*0Sstevel@tonic-gate zs = &zscom[unit]; 457*0Sstevel@tonic-gate *result = zs->zs_hdlc_dip; 458*0Sstevel@tonic-gate error = DDI_SUCCESS; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate break; 461*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 462*0Sstevel@tonic-gate *result = (void *)(unit / 2); 463*0Sstevel@tonic-gate error = DDI_SUCCESS; 464*0Sstevel@tonic-gate break; 465*0Sstevel@tonic-gate default: 466*0Sstevel@tonic-gate error = DDI_FAILURE; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate return (error); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate static int 472*0Sstevel@tonic-gate zsh_detach(dev_info_t *dev, ddi_detach_cmd_t cmd) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate if (cmd != DDI_DETACH) 475*0Sstevel@tonic-gate return (DDI_FAILURE); 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate return (DDI_SUCCESS); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate static void 483*0Sstevel@tonic-gate zsh_init_port(struct zscom *zs, struct syncline *zss) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate register uchar_t s0; 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate SCC_WRITE(3, (ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE | ZSWR3_RX_8)); 488*0Sstevel@tonic-gate SCC_WRITE(5, (ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE)); 489*0Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0(); 490*0Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) { 491*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE); 492*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS); 493*0Sstevel@tonic-gate s0 = SCC_READ0(); 494*0Sstevel@tonic-gate if ((s0 & ZSRR0_CTS) || 495*0Sstevel@tonic-gate !(zss->sl_mode.sm_config & (CONN_SIGNAL | CONN_IBM))) { 496*0Sstevel@tonic-gate /* 497*0Sstevel@tonic-gate * send msg that CTS is up 498*0Sstevel@tonic-gate */ 499*0Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; 500*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 501*0Sstevel@tonic-gate } else { 502*0Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG; 503*0Sstevel@tonic-gate zss->sl_txstate = TX_RTS; 504*0Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS; 505*0Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count; 506*0Sstevel@tonic-gate if (!zss->sl_wd_id) 507*0Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, 508*0Sstevel@tonic-gate zs, SIO_WATCHDOG_TICK); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate } else { 511*0Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS); 512*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE); 513*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); 514*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* 519*0Sstevel@tonic-gate * Open routine. 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate /*ARGSUSED*/ 523*0Sstevel@tonic-gate static int 524*0Sstevel@tonic-gate zsh_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 525*0Sstevel@tonic-gate { 526*0Sstevel@tonic-gate register struct zscom *zs; 527*0Sstevel@tonic-gate register struct syncline *zss; 528*0Sstevel@tonic-gate register struct ser_str *stp; 529*0Sstevel@tonic-gate register int unit; 530*0Sstevel@tonic-gate register int tmp; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate if (sflag != CLONEOPEN) { 533*0Sstevel@tonic-gate if (rq->q_ptr) 534*0Sstevel@tonic-gate return (EBUSY); /* We got a stream that is in use */ 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate unit = UNIT(*dev); 537*0Sstevel@tonic-gate if (unit >= maxzsh) 538*0Sstevel@tonic-gate return (ENXIO); /* unit not configured */ 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate if (zscom == NULL) 541*0Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */ 542*0Sstevel@tonic-gate zs = &zscom[unit]; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate if (zs->zs_ops == NULL) { 545*0Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */ 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_OPEN, "zsh_open:unit = %d", unit); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 551*0Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) && 552*0Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) { 553*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 554*0Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */ 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* Mark device as busy (for power management) */ 558*0Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1); 559*0Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, unit%2+1, 1); 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate zsopinit(zs, &zsops_hdlc); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate zss = (struct syncline *)&zscom[unit].zs_priv_str; 564*0Sstevel@tonic-gate stp = &zss->sl_stream; 565*0Sstevel@tonic-gate stp->str_state = NULL; 566*0Sstevel@tonic-gate stp->str_com = (caddr_t)zs; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate zss->sl_xhead = NULL; 569*0Sstevel@tonic-gate zss->sl_xactb = NULL; 570*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 571*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 572*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 573*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 574*0Sstevel@tonic-gate zss->sl_rhead = NULL; 575*0Sstevel@tonic-gate zss->sl_ractb = NULL; 576*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 577*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 578*0Sstevel@tonic-gate zss->sl_mstat = NULL; 579*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 580*0Sstevel@tonic-gate zss->sl_wd_id = 0; 581*0Sstevel@tonic-gate zss->sl_soft_active = 0; 582*0Sstevel@tonic-gate zss->sl_stream.str_rq = NULL; 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate zs->zs_priv = (caddr_t)zss; 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate zss->sl_mru = zsh_default_mru; 587*0Sstevel@tonic-gate tmp = ZSH_MAX_RSTANDBY; 588*0Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp); 589*0Sstevel@tonic-gate if (zss->sl_rstandby[0] == NULL) { 590*0Sstevel@tonic-gate cmn_err(CE_WARN, "zsh_open: can't alloc message block"); 591*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 592*0Sstevel@tonic-gate return (ENOSR); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 595*0Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb); 596*0Sstevel@tonic-gate zss->sl_txstate = TX_OFF; 597*0Sstevel@tonic-gate zss->sl_rr0 = SCC_READ0(); 598*0Sstevel@tonic-gate zss->sl_flags &= (SF_INITIALIZED | SF_FDXPTP); 599*0Sstevel@tonic-gate if (zss->sl_flags & SF_INITIALIZED) 600*0Sstevel@tonic-gate zsh_init_port(zs, zss); 601*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 602*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 603*0Sstevel@tonic-gate } else { /* CLONEOPEN */ 604*0Sstevel@tonic-gate mutex_enter(&zs_curr_lock); 605*0Sstevel@tonic-gate for (unit = maxzsh; unit < MAXZSHCLONES; unit++) 606*0Sstevel@tonic-gate if (!zsh_usedminor[unit]) { 607*0Sstevel@tonic-gate zsh_usedminor[unit] = (unsigned char)unit; 608*0Sstevel@tonic-gate break; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate mutex_exit(&zs_curr_lock); 611*0Sstevel@tonic-gate if (unit >= MAXZSHCLONES) /* no slots available */ 612*0Sstevel@tonic-gate return (ENODEV); 613*0Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), unit); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate stp = kmem_zalloc(sizeof (struct ser_str), KM_NOSLEEP); 616*0Sstevel@tonic-gate if (stp == NULL) { 617*0Sstevel@tonic-gate cmn_err(CE_WARN, 618*0Sstevel@tonic-gate "zsh clone open failed, no memory, rq=%p\n", 619*0Sstevel@tonic-gate (void *)rq); 620*0Sstevel@tonic-gate return (ENOMEM); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate stp->str_state = STR_CLONE; 623*0Sstevel@tonic-gate stp->str_com = NULL; /* can't determine without ppa */ 624*0Sstevel@tonic-gate } 625*0Sstevel@tonic-gate stp->str_rq = rq; 626*0Sstevel@tonic-gate stp->str_inst = unit; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)stp; 629*0Sstevel@tonic-gate qprocson(rq); 630*0Sstevel@tonic-gate return (0); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * Close routine. 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate int zsh_tx_enable_in_close = 0; 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate /*ARGSUSED*/ 639*0Sstevel@tonic-gate static int 640*0Sstevel@tonic-gate zsh_close(queue_t *rq, int flag) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate struct ser_str *stp; 643*0Sstevel@tonic-gate struct zscom *zs; 644*0Sstevel@tonic-gate struct syncline *zss; 645*0Sstevel@tonic-gate mblk_t *mp; 646*0Sstevel@tonic-gate int i; 647*0Sstevel@tonic-gate timeout_id_t sl_wd_id; 648*0Sstevel@tonic-gate bufcall_id_t sl_bufcid; 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate /* 651*0Sstevel@tonic-gate * Note that a close is only called on the last close of a 652*0Sstevel@tonic-gate * particular stream. Assume that we need to do it all. 653*0Sstevel@tonic-gate */ 654*0Sstevel@tonic-gate qprocsoff(rq); /* no new business after this */ 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate stp = (struct ser_str *)rq->q_ptr; 657*0Sstevel@tonic-gate if (stp == NULL) 658*0Sstevel@tonic-gate return (0); /* already been closed once */ 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate if (stp->str_state == STR_CLONE) { 661*0Sstevel@tonic-gate zsh_usedminor[stp->str_inst] = 0; 662*0Sstevel@tonic-gate } else { 663*0Sstevel@tonic-gate zs = (struct zscom *)stp->str_com; 664*0Sstevel@tonic-gate if (zs == NULL) 665*0Sstevel@tonic-gate goto out; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_CLOSE, "zs = %p", zs); 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv; 670*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 671*0Sstevel@tonic-gate flushq(WR(rq), FLUSHALL); 672*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 673*0Sstevel@tonic-gate if (zss->sl_xstandby) { 674*0Sstevel@tonic-gate zss->sl_xstandby->b_wptr = zss->sl_xstandby->b_rptr; 675*0Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xstandby); 676*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate ZSH_FLUSHQ; 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate /* 683*0Sstevel@tonic-gate * Stop the Watchdog Timer. 684*0Sstevel@tonic-gate */ 685*0Sstevel@tonic-gate if ((sl_wd_id = zss->sl_wd_id) != 0) 686*0Sstevel@tonic-gate zss->sl_wd_id = 0; 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 690*0Sstevel@tonic-gate */ 691*0Sstevel@tonic-gate if ((sl_bufcid = zss->sl_bufcid) != 0) 692*0Sstevel@tonic-gate zss->sl_bufcid = 0; 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 695*0Sstevel@tonic-gate if (zs->zs_wr_cur) { 696*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 697*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 698*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT); 699*0Sstevel@tonic-gate ZSDELAY(); 700*0Sstevel@tonic-gate ZSDELAY(); 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */ 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 705*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 706*0Sstevel@tonic-gate SCC_BIC(15, 707*0Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS)); 708*0Sstevel@tonic-gate SCC_WRITE(3, 0); /* Quiesce receiver */ 709*0Sstevel@tonic-gate if (zsh_tx_enable_in_close && !(zss->sl_flags & SF_FDXPTP)) { 710*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE); 711*0Sstevel@tonic-gate } else 712*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate SCC_BIC(5, (ZSWR5_DTR | ZSWR5_RTS | ZSWR5_TXCRC_ENABLE)); 715*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); /* reset TX */ 716*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */ 717*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 718*0Sstevel@tonic-gate (void) SCC_READDATA(); /* reset RX */ 719*0Sstevel@tonic-gate ZSDELAY(); 720*0Sstevel@tonic-gate (void) SCC_READDATA(); 721*0Sstevel@tonic-gate ZSDELAY(); 722*0Sstevel@tonic-gate (void) SCC_READDATA(); 723*0Sstevel@tonic-gate ZSDELAY(); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * Free up everything we ever allocated. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate if ((mp = zss->sl_rhead) != NULL) { 730*0Sstevel@tonic-gate zss->sl_ractb = NULL; /* already freed */ 731*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 732*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 733*0Sstevel@tonic-gate zss->sl_rhead = NULL; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 736*0Sstevel@tonic-gate if (mp) 737*0Sstevel@tonic-gate freemsg(mp); 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 740*0Sstevel@tonic-gate if ((mp = zss->sl_ractb) != NULL) { 741*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 742*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 743*0Sstevel@tonic-gate zss->sl_ractb = NULL; 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 746*0Sstevel@tonic-gate if (mp) 747*0Sstevel@tonic-gate freemsg(mp); 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate for (i = 0; i < ZSH_MAX_RSTANDBY; i++) { 750*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 751*0Sstevel@tonic-gate mp = zss->sl_rstandby[i]; 752*0Sstevel@tonic-gate zss->sl_rstandby[i] = NULL; 753*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 754*0Sstevel@tonic-gate if (mp) 755*0Sstevel@tonic-gate freemsg(mp); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 759*0Sstevel@tonic-gate if ((mp = zss->sl_xhead) != NULL) { 760*0Sstevel@tonic-gate zss->sl_xhead = NULL; 761*0Sstevel@tonic-gate zss->sl_xactb = NULL; 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 764*0Sstevel@tonic-gate if (mp) 765*0Sstevel@tonic-gate freemsg(mp); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate ZSH_FLUSHQ; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 770*0Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL) 771*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 772*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 773*0Sstevel@tonic-gate if (mp) 774*0Sstevel@tonic-gate freemsg(mp); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 777*0Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL) 778*0Sstevel@tonic-gate zss->sl_mstat = NULL; 779*0Sstevel@tonic-gate zss->sl_txstate = TX_OFF; /* so it can't rearm in close */ 780*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 781*0Sstevel@tonic-gate if (mp) 782*0Sstevel@tonic-gate freemsg(mp); 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate zss->sl_stream.str_rq = NULL; 785*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 786*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 787*0Sstevel@tonic-gate if (sl_wd_id) 788*0Sstevel@tonic-gate (void) untimeout(sl_wd_id); 789*0Sstevel@tonic-gate if (sl_bufcid) 790*0Sstevel@tonic-gate unbufcall(sl_bufcid); 791*0Sstevel@tonic-gate while (zss->sl_soft_active) 792*0Sstevel@tonic-gate drv_usecwait(1); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate /* Mark device as available for power management */ 795*0Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1); 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate if (stp->str_state == STR_CLONE) 799*0Sstevel@tonic-gate kmem_free(stp, sizeof (struct ser_str)); 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate out: 802*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate return (0); 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate static int 808*0Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(struct zscom *zs, struct syncline *zss) 809*0Sstevel@tonic-gate { 810*0Sstevel@tonic-gate register uchar_t s0; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS); 813*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS); 814*0Sstevel@tonic-gate s0 = SCC_READ0(); 815*0Sstevel@tonic-gate if (s0 & ZSRR0_CTS) { 816*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE); 817*0Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; 818*0Sstevel@tonic-gate return (1); 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG; 821*0Sstevel@tonic-gate zss->sl_txstate = TX_RTS; 822*0Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS; 823*0Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count; 824*0Sstevel@tonic-gate return (0); 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate /* 828*0Sstevel@tonic-gate * Put procedure for write queue. 829*0Sstevel@tonic-gate */ 830*0Sstevel@tonic-gate static void 831*0Sstevel@tonic-gate zsh_wput(queue_t *wq, mblk_t *mp) 832*0Sstevel@tonic-gate { 833*0Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr; 834*0Sstevel@tonic-gate register struct zscom *zs; 835*0Sstevel@tonic-gate register struct syncline *zss = NULL; 836*0Sstevel@tonic-gate register ulong_t prim, error = 0; 837*0Sstevel@tonic-gate register union DL_primitives *dlp; 838*0Sstevel@tonic-gate register int ppa; 839*0Sstevel@tonic-gate register mblk_t *tmp; 840*0Sstevel@tonic-gate register struct copyresp *resp; 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate /* 843*0Sstevel@tonic-gate * stp->str_com supplied by open or DLPI attach. 844*0Sstevel@tonic-gate */ 845*0Sstevel@tonic-gate if (stp == NULL) { 846*0Sstevel@tonic-gate freemsg(mp); 847*0Sstevel@tonic-gate return; 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate zs = (struct zscom *)stp->str_com; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate TRACE_0(TR_ZSH, TR_ZSH_WPUT_START, "zsh_wput start"); 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate if ((mp->b_datap->db_type == M_FLUSH) && 854*0Sstevel@tonic-gate (stp->str_state == STR_CLONE)) { 855*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 856*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 857*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) 860*0Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */ 861*0Sstevel@tonic-gate else 862*0Sstevel@tonic-gate freemsg(mp); 863*0Sstevel@tonic-gate return; 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate if ((zs == NULL) && (mp->b_datap->db_type != M_PROTO)) { 867*0Sstevel@tonic-gate freemsg(mp); 868*0Sstevel@tonic-gate cmn_err(CE_WARN, 869*0Sstevel@tonic-gate "zsh: clone device %d must be attached before use!", 870*0Sstevel@tonic-gate stp->str_inst); 871*0Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, EPROTO); 872*0Sstevel@tonic-gate return; 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate if (stp->str_state == STR_CLONE) { /* Clone opened, limited. */ 876*0Sstevel@tonic-gate if ((mp->b_datap->db_type != M_PROTO) && 877*0Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCTL) && 878*0Sstevel@tonic-gate (mp->b_datap->db_type != M_IOCDATA)) { 879*0Sstevel@tonic-gate freemsg(mp); 880*0Sstevel@tonic-gate cmn_err(CE_WARN, 881*0Sstevel@tonic-gate "zsh%x: invalid operation for clone dev.\n", 882*0Sstevel@tonic-gate stp->str_inst); 883*0Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, EPROTO); 884*0Sstevel@tonic-gate return; 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate } else { 887*0Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv; 888*0Sstevel@tonic-gate } 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate case M_DATA: 893*0Sstevel@tonic-gate /* 894*0Sstevel@tonic-gate * Queue the message up to be transmitted. 895*0Sstevel@tonic-gate * Set "in progress" flag and call the start routine. 896*0Sstevel@tonic-gate */ 897*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 898*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_INITIALIZED)) { 899*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 900*0Sstevel@tonic-gate cmn_err(CE_WARN, 901*0Sstevel@tonic-gate "zsh%x not initialized, can't send message", 902*0Sstevel@tonic-gate zs->zs_unit); 903*0Sstevel@tonic-gate freemsg(mp); 904*0Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_ERROR, ECOMM); 905*0Sstevel@tonic-gate return; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 908*0Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) { 909*0Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT; 910*0Sstevel@tonic-gate (void) zsh_softint(zs); 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate while (mp->b_wptr == mp->b_rptr) { 913*0Sstevel@tonic-gate register mblk_t *mp1; 914*0Sstevel@tonic-gate mp1 = unlinkb(mp); 915*0Sstevel@tonic-gate freemsg(mp); 916*0Sstevel@tonic-gate mp = mp1; 917*0Sstevel@tonic-gate if (mp == NULL) 918*0Sstevel@tonic-gate return; 919*0Sstevel@tonic-gate } 920*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 921*0Sstevel@tonic-gate (void) putq(wq, mp); 922*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 923*0Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) { 924*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 925*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 926*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END, 929*0Sstevel@tonic-gate "zsh_wput end: zs = %p", zs); 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate return; 932*0Sstevel@tonic-gate } 933*0Sstevel@tonic-gate tmp = NULL; 934*0Sstevel@tonic-gate again: 935*0Sstevel@tonic-gate if (!zss->sl_xstandby) { 936*0Sstevel@tonic-gate if (tmp) 937*0Sstevel@tonic-gate zss->sl_xstandby = tmp; 938*0Sstevel@tonic-gate else { 939*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 940*0Sstevel@tonic-gate tmp = getq(wq); 941*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 942*0Sstevel@tonic-gate if (tmp) 943*0Sstevel@tonic-gate goto again; 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate } else if (tmp) { 946*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 947*0Sstevel@tonic-gate (void) putbq(wq, tmp); 948*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate if (zss->sl_flags & SF_XMT_INPROG) { 952*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 953*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END, 956*0Sstevel@tonic-gate "zsh_wput end: zs = %p", zs); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate return; 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate if (!zss->sl_wd_id) { 962*0Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count; 963*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 964*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 965*0Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs, 966*0Sstevel@tonic-gate SIO_WATCHDOG_TICK); 967*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG; 971*0Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) || 972*0Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss)) 973*0Sstevel@tonic-gate (void) zsh_start(zs, zss); 974*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 975*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 976*0Sstevel@tonic-gate break; 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate case M_PROTO: 979*0Sstevel@tonic-gate /* 980*0Sstevel@tonic-gate * Here is where a clone device finds out about the 981*0Sstevel@tonic-gate * hardware it is going to attach to. The request is 982*0Sstevel@tonic-gate * validated and a ppa is extracted from it and validated. 983*0Sstevel@tonic-gate * This number is used to index the hardware data structure 984*0Sstevel@tonic-gate * and the protocol data structure, in case the latter 985*0Sstevel@tonic-gate * was not provided by a data-path open before this. 986*0Sstevel@tonic-gate */ 987*0Sstevel@tonic-gate if (stp->str_state != STR_CLONE) { 988*0Sstevel@tonic-gate freemsg(mp); 989*0Sstevel@tonic-gate return; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) { 993*0Sstevel@tonic-gate prim = DL_ATTACH_REQ; 994*0Sstevel@tonic-gate error = DL_BADPRIM; 995*0Sstevel@tonic-gate goto end_proto; 996*0Sstevel@tonic-gate } 997*0Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 998*0Sstevel@tonic-gate prim = dlp->dl_primitive; 999*0Sstevel@tonic-gate if (prim != DL_ATTACH_REQ) { 1000*0Sstevel@tonic-gate error = DL_BADPRIM; 1001*0Sstevel@tonic-gate goto end_proto; 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate ppa = dlp->attach_req.dl_ppa; 1004*0Sstevel@tonic-gate ppa = (ppa%2) ? ((ppa-1)*2 +1) : (ppa*2); 1005*0Sstevel@tonic-gate if (ppa >= maxzsh) { 1006*0Sstevel@tonic-gate error = DL_BADPPA; 1007*0Sstevel@tonic-gate goto end_proto; 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate zs = &zscom[ppa]; 1010*0Sstevel@tonic-gate if (zs->zs_ops == NULL) { 1011*0Sstevel@tonic-gate error = ENXIO; 1012*0Sstevel@tonic-gate goto end_proto; 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1015*0Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) && 1016*0Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) { 1017*0Sstevel@tonic-gate /* 1018*0Sstevel@tonic-gate * another protocol got here first 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate error = (EBUSY); 1021*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1022*0Sstevel@tonic-gate goto end_proto; 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate stp->str_com = (caddr_t)zs; 1027*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1028*0Sstevel@tonic-gate end_proto: 1029*0Sstevel@tonic-gate if (error) 1030*0Sstevel@tonic-gate dlerrorack(wq, mp, prim, error, 0); 1031*0Sstevel@tonic-gate else 1032*0Sstevel@tonic-gate dlokack(wq, mp, DL_ATTACH_REQ); 1033*0Sstevel@tonic-gate break; 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate case M_IOCTL: 1036*0Sstevel@tonic-gate zsh_ioctl(wq, mp); 1037*0Sstevel@tonic-gate break; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate case M_IOCDATA: 1040*0Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr; 1041*0Sstevel@tonic-gate if (resp->cp_rval) { 1042*0Sstevel@tonic-gate /* 1043*0Sstevel@tonic-gate * Just free message on failure. 1044*0Sstevel@tonic-gate */ 1045*0Sstevel@tonic-gate freemsg(mp); 1046*0Sstevel@tonic-gate break; 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate switch (resp->cp_cmd) { 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate case S_IOCGETMODE: 1052*0Sstevel@tonic-gate case S_IOCGETSTATS: 1053*0Sstevel@tonic-gate case S_IOCGETSPEED: 1054*0Sstevel@tonic-gate case S_IOCGETMCTL: 1055*0Sstevel@tonic-gate case S_IOCGETMRU: 1056*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1057*0Sstevel@tonic-gate qreply(wq, mp); 1058*0Sstevel@tonic-gate break; 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate case S_IOCSETMODE: 1061*0Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str; 1062*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1063*0Sstevel@tonic-gate error = zsh_setmode(zs, zss, 1064*0Sstevel@tonic-gate (struct scc_mode *)mp->b_cont->b_rptr); 1065*0Sstevel@tonic-gate if (error) { 1066*0Sstevel@tonic-gate register struct iocblk *iocp = 1067*0Sstevel@tonic-gate (struct iocblk *)mp->b_rptr; 1068*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1069*0Sstevel@tonic-gate iocp->ioc_error = error; 1070*0Sstevel@tonic-gate } else 1071*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1072*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1073*0Sstevel@tonic-gate qreply(wq, mp); 1074*0Sstevel@tonic-gate break; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate case S_IOCSETMRU: 1077*0Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str; 1078*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1079*0Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr; 1080*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1081*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1082*0Sstevel@tonic-gate qreply(wq, mp); 1083*0Sstevel@tonic-gate break; 1084*0Sstevel@tonic-gate default: 1085*0Sstevel@tonic-gate freemsg(mp); 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate break; 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate /* 1090*0Sstevel@tonic-gate * We're at the bottom of the food chain, so we flush our 1091*0Sstevel@tonic-gate * write queue, clear the FLUSHW bit so it doesn't go round 1092*0Sstevel@tonic-gate * and round forever, then flush our read queue (since there's 1093*0Sstevel@tonic-gate * no read put procedure down here) and pass it up for any 1094*0Sstevel@tonic-gate * higher modules to deal with in their own way. 1095*0Sstevel@tonic-gate */ 1096*0Sstevel@tonic-gate case M_FLUSH: 1097*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 1098*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1099*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 1100*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1101*0Sstevel@tonic-gate tmp = zss->sl_xstandby; 1102*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 1103*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1104*0Sstevel@tonic-gate if (tmp) 1105*0Sstevel@tonic-gate freemsg(tmp); 1106*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1107*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 1108*0Sstevel@tonic-gate } 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 1111*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1112*0Sstevel@tonic-gate ZSH_FLUSHQ; 1113*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1114*0Sstevel@tonic-gate qreply(wq, mp); /* let the read queues have at it */ 1115*0Sstevel@tonic-gate } else 1116*0Sstevel@tonic-gate freemsg(mp); 1117*0Sstevel@tonic-gate break; 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate default: 1120*0Sstevel@tonic-gate /* 1121*0Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 1122*0Sstevel@tonic-gate * thank you anyway." 1123*0Sstevel@tonic-gate */ 1124*0Sstevel@tonic-gate freemsg(mp); 1125*0Sstevel@tonic-gate break; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_WPUT_END, "zsh_wput end: zs = %p", zs); 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate /* 1132*0Sstevel@tonic-gate * Get the next message from the write queue, set up the necessary pointers, 1133*0Sstevel@tonic-gate * state info, etc., and start the transmit "engine" by sending the first 1134*0Sstevel@tonic-gate * character. We'll then rotate through txint until done, then get an xsint. 1135*0Sstevel@tonic-gate */ 1136*0Sstevel@tonic-gate static int 1137*0Sstevel@tonic-gate zsh_start(struct zscom *zs, struct syncline *zss) 1138*0Sstevel@tonic-gate { 1139*0Sstevel@tonic-gate register mblk_t *mp; 1140*0Sstevel@tonic-gate register uchar_t *wptr; 1141*0Sstevel@tonic-gate register uchar_t *rptr; 1142*0Sstevel@tonic-gate register uchar_t sl_flags = zss->sl_flags; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate /* 1145*0Sstevel@tonic-gate * Attempt to grab the next M_DATA message off the queue (that's 1146*0Sstevel@tonic-gate * all that will be left after wput) and begin transmission. 1147*0Sstevel@tonic-gate * This routine is normally called after completion of a previous 1148*0Sstevel@tonic-gate * frame, or when zsh_wput gets a new message. If we are in a 1149*0Sstevel@tonic-gate * mode that put us in the TX_RTS state, waiting for CTS, and CTS 1150*0Sstevel@tonic-gate * is not up yet, we have no business here. Ditto if we're in 1151*0Sstevel@tonic-gate * either the TX_ACTIVE or TX_CRC states. In these cases we 1152*0Sstevel@tonic-gate * don't clear SF_CALLSTART, so we don't forget there's work to do. 1153*0Sstevel@tonic-gate */ 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_START, 1156*0Sstevel@tonic-gate "zsh_start start: zs = %p", zs); 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate if (sl_flags & SF_PHONY) { 1159*0Sstevel@tonic-gate sl_flags &= ~SF_PHONY; 1160*0Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS); 1161*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); 1162*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1163*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE); 1164*0Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS; 1165*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 1166*0Sstevel@tonic-gate /* 1167*0Sstevel@tonic-gate * if we get another msg by chance zsh_watchog will start 1168*0Sstevel@tonic-gate */ 1169*0Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG; 1170*0Sstevel@tonic-gate zss->sl_flags = sl_flags; 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END, 1173*0Sstevel@tonic-gate "zsh_start end: zs = %d", zs); 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate return (0); 1176*0Sstevel@tonic-gate } 1177*0Sstevel@tonic-gate mp = zss->sl_xstandby; 1178*0Sstevel@tonic-gate if (mp == NULL) { 1179*0Sstevel@tonic-gate if (!(sl_flags & SF_FDXPTP)) { 1180*0Sstevel@tonic-gate sl_flags |= SF_PHONY; 1181*0Sstevel@tonic-gate ZSH_ALLOCB(mp); 1182*0Sstevel@tonic-gate if (!mp) 1183*0Sstevel@tonic-gate return (0); 1184*0Sstevel@tonic-gate mp->b_datap->db_type = M_RSE; 1185*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + 1; 1186*0Sstevel@tonic-gate goto transmit; 1187*0Sstevel@tonic-gate } 1188*0Sstevel@tonic-gate sl_flags &= ~SF_XMT_INPROG; 1189*0Sstevel@tonic-gate zss->sl_flags = sl_flags; 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END, 1192*0Sstevel@tonic-gate "zsh_start end: zs = %p", zs); 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate return (0); 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate transmit: 1198*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 1199*0Sstevel@tonic-gate rptr = mp->b_rptr; 1200*0Sstevel@tonic-gate wptr = mp->b_wptr; 1201*0Sstevel@tonic-gate ZSSETSOFT(zs); 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate #ifdef ZSH_DEBUG 1204*0Sstevel@tonic-gate if (zss->sl_xhead || zss->sl_xactb) { 1205*0Sstevel@tonic-gate debug_enter("xhead1"); 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate #endif 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate zss->sl_xhead = mp; 1210*0Sstevel@tonic-gate zss->sl_xactb = mp; 1211*0Sstevel@tonic-gate zss->sl_wd_count = zsh_timer_count; 1212*0Sstevel@tonic-gate zss->sl_txstate = TX_ACTIVE; 1213*0Sstevel@tonic-gate zss->sl_ocnt = 0; 1214*0Sstevel@tonic-gate SCC_BIS(10, ZSWR10_UNDERRUN_ABORT); /* abort on underrun */ 1215*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXCRC); /* reset transmit CRC */ 1216*0Sstevel@tonic-gate zss->sl_ocnt = wptr - rptr; 1217*0Sstevel@tonic-gate mp->b_wptr = rptr; /* to tell soft to free this msg */ 1218*0Sstevel@tonic-gate SCC_WRITEDATA(*rptr++); /* resets TXINT */ 1219*0Sstevel@tonic-gate zs->zs_wr_cur = rptr; 1220*0Sstevel@tonic-gate zs->zs_wr_lim = wptr; 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_EOM); 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_START_END, 1225*0Sstevel@tonic-gate "zsh_start end: zs = %p", zs); 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate zss->sl_flags = sl_flags; 1228*0Sstevel@tonic-gate return (1); 1229*0Sstevel@tonic-gate } 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate /* 1233*0Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 1234*0Sstevel@tonic-gate */ 1235*0Sstevel@tonic-gate static void 1236*0Sstevel@tonic-gate zsh_ioctl(queue_t *wq, mblk_t *mp) 1237*0Sstevel@tonic-gate { 1238*0Sstevel@tonic-gate register struct ser_str *stp = (struct ser_str *)wq->q_ptr; 1239*0Sstevel@tonic-gate register struct zscom *zs = (struct zscom *)stp->str_com; 1240*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 1241*0Sstevel@tonic-gate register struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 1242*0Sstevel@tonic-gate register struct scc_mode *sm; 1243*0Sstevel@tonic-gate register struct sl_stats *st; 1244*0Sstevel@tonic-gate register uchar_t *msignals; 1245*0Sstevel@tonic-gate register mblk_t *tmp; 1246*0Sstevel@tonic-gate register int error = 0; 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1249*0Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) && 1250*0Sstevel@tonic-gate (zs->zs_ops != &zsops_hdlc)) { 1251*0Sstevel@tonic-gate /* 1252*0Sstevel@tonic-gate * another protocol got here first 1253*0Sstevel@tonic-gate */ 1254*0Sstevel@tonic-gate error = (EBUSY); 1255*0Sstevel@tonic-gate goto end_zsh_ioctl; 1256*0Sstevel@tonic-gate } 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate case S_IOCGETMODE: 1262*0Sstevel@tonic-gate tmp = allocb(sizeof (struct scc_mode), BPRI_MED); 1263*0Sstevel@tonic-gate if (tmp == NULL) { 1264*0Sstevel@tonic-gate error = EAGAIN; 1265*0Sstevel@tonic-gate break; 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 1268*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct scc_mode), 0); 1269*0Sstevel@tonic-gate else 1270*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct scc_mode), NULL, tmp); 1271*0Sstevel@tonic-gate sm = (struct scc_mode *)mp->b_cont->b_rptr; 1272*0Sstevel@tonic-gate bcopy(&zss->sl_mode, sm, sizeof (struct scc_mode)); 1273*0Sstevel@tonic-gate break; 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate case S_IOCGETSTATS: 1276*0Sstevel@tonic-gate tmp = allocb(sizeof (struct sl_stats), BPRI_MED); 1277*0Sstevel@tonic-gate if (tmp == NULL) { 1278*0Sstevel@tonic-gate error = EAGAIN; 1279*0Sstevel@tonic-gate break; 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 1282*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (struct sl_stats), 0); 1283*0Sstevel@tonic-gate else 1284*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (struct sl_stats), NULL, tmp); 1285*0Sstevel@tonic-gate st = (struct sl_stats *)mp->b_cont->b_rptr; 1286*0Sstevel@tonic-gate bcopy(&zss->sl_st, st, sizeof (struct sl_stats)); 1287*0Sstevel@tonic-gate break; 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate case S_IOCGETSPEED: 1290*0Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 1291*0Sstevel@tonic-gate if (tmp == NULL) { 1292*0Sstevel@tonic-gate error = EAGAIN; 1293*0Sstevel@tonic-gate break; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 1296*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 1297*0Sstevel@tonic-gate else 1298*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 1299*0Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mode.sm_baudrate; 1300*0Sstevel@tonic-gate break; 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate case S_IOCGETMCTL: 1303*0Sstevel@tonic-gate tmp = allocb(sizeof (char), BPRI_MED); 1304*0Sstevel@tonic-gate if (tmp == NULL) { 1305*0Sstevel@tonic-gate error = EAGAIN; 1306*0Sstevel@tonic-gate break; 1307*0Sstevel@tonic-gate } 1308*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 1309*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (char), 0); 1310*0Sstevel@tonic-gate else 1311*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (char), NULL, tmp); 1312*0Sstevel@tonic-gate msignals = (uchar_t *)mp->b_cont->b_rptr; 1313*0Sstevel@tonic-gate *msignals = zss->sl_rr0 & (ZSRR0_CD | ZSRR0_CTS); 1314*0Sstevel@tonic-gate break; 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate case S_IOCGETMRU: 1317*0Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 1318*0Sstevel@tonic-gate if (tmp == NULL) { 1319*0Sstevel@tonic-gate error = EAGAIN; 1320*0Sstevel@tonic-gate break; 1321*0Sstevel@tonic-gate } 1322*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 1323*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 1324*0Sstevel@tonic-gate else 1325*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 1326*0Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = zss->sl_mru; 1327*0Sstevel@tonic-gate break; 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate case S_IOCSETMODE: 1330*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 1331*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct scc_mode)); 1332*0Sstevel@tonic-gate if (error != 0) 1333*0Sstevel@tonic-gate break; 1334*0Sstevel@tonic-gate error = zsh_setmode(zs, zss, 1335*0Sstevel@tonic-gate (struct scc_mode *)mp->b_cont->b_rptr); 1336*0Sstevel@tonic-gate if (error == 0) 1337*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1338*0Sstevel@tonic-gate } else 1339*0Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (struct scc_mode), NULL); 1340*0Sstevel@tonic-gate break; 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate case S_IOCCLRSTATS: 1343*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1344*0Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats)); 1345*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1346*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1347*0Sstevel@tonic-gate break; 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate case S_IOCSETMRU: 1350*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 1351*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 1352*0Sstevel@tonic-gate if (error != 0) 1353*0Sstevel@tonic-gate break; 1354*0Sstevel@tonic-gate zss->sl_mru = *(int *)mp->b_cont->b_rptr; 1355*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1356*0Sstevel@tonic-gate } else 1357*0Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 1358*0Sstevel@tonic-gate break; 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate case S_IOCSETDTR: 1361*0Sstevel@tonic-gate /* 1362*0Sstevel@tonic-gate * The first integer of the M_DATA block that should 1363*0Sstevel@tonic-gate * follow indicate if DTR must be set or reset 1364*0Sstevel@tonic-gate */ 1365*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 1366*0Sstevel@tonic-gate if (error != 0) 1367*0Sstevel@tonic-gate break; 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1370*0Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0) 1371*0Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIS); 1372*0Sstevel@tonic-gate else 1373*0Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC); 1374*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1375*0Sstevel@tonic-gate break; 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate default: 1378*0Sstevel@tonic-gate error = EINVAL; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate } 1381*0Sstevel@tonic-gate end_zsh_ioctl: 1382*0Sstevel@tonic-gate iocp->ioc_error = error; 1383*0Sstevel@tonic-gate mp->b_datap->db_type = (error) ? M_IOCNAK : M_IOCACK; 1384*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1385*0Sstevel@tonic-gate qreply(wq, mp); 1386*0Sstevel@tonic-gate } 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate /* 1389*0Sstevel@tonic-gate * Set the mode of the zsh port 1390*0Sstevel@tonic-gate */ 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate int 1393*0Sstevel@tonic-gate zsh_setmode(struct zscom *zs, struct syncline *zss, struct scc_mode *sm) 1394*0Sstevel@tonic-gate { 1395*0Sstevel@tonic-gate register int error = 0; 1396*0Sstevel@tonic-gate register mblk_t *mp; 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1399*0Sstevel@tonic-gate if (sm->sm_rxclock == RXC_IS_PLL) { 1400*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC; 1401*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1402*0Sstevel@tonic-gate return (EINVAL); /* not supported */ 1403*0Sstevel@tonic-gate } else { 1404*0Sstevel@tonic-gate if (((zss->sl_mode.sm_config ^ sm->sm_config) & 1405*0Sstevel@tonic-gate CONN_SIGNAL) != 0) { /* Changing, going... */ 1406*0Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL) { /* ...up. */ 1407*0Sstevel@tonic-gate if (zss->sl_mstat == NULL) { 1408*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1409*0Sstevel@tonic-gate mp = allocb( 1410*0Sstevel@tonic-gate sizeof (struct sl_status), BPRI_MED); 1411*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1412*0Sstevel@tonic-gate zss->sl_mstat = mp; 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate } else { /* ...down. */ 1415*0Sstevel@tonic-gate if ((mp = zss->sl_mstat) != NULL) 1416*0Sstevel@tonic-gate zss->sl_mstat = NULL; 1417*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1418*0Sstevel@tonic-gate if (mp) 1419*0Sstevel@tonic-gate freemsg(mp); 1420*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate } 1423*0Sstevel@tonic-gate if (!(sm->sm_config & CONN_IBM)) { 1424*0Sstevel@tonic-gate if (sm->sm_config & CONN_HDX) { 1425*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_HDX; 1426*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1427*0Sstevel@tonic-gate return (EINVAL); 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate if (sm->sm_config & CONN_MPT) { 1430*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_MPT; 1431*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1432*0Sstevel@tonic-gate return (EINVAL); 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate } 1435*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FDXPTP; /* "conmode" */ 1436*0Sstevel@tonic-gate if ((sm->sm_config & (CONN_HDX | CONN_MPT)) == 0) 1437*0Sstevel@tonic-gate zss->sl_flags |= SF_FDXPTP; 1438*0Sstevel@tonic-gate 1439*0Sstevel@tonic-gate error = zsh_program(zs, sm); 1440*0Sstevel@tonic-gate if (!error && (zs->zs_ops != &zsops_null)) 1441*0Sstevel@tonic-gate zsh_init_port(zs, zss); 1442*0Sstevel@tonic-gate } 1443*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate return (error); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate /* 1449*0Sstevel@tonic-gate * Transmit interrupt service procedure 1450*0Sstevel@tonic-gate */ 1451*0Sstevel@tonic-gate 1452*0Sstevel@tonic-gate static void 1453*0Sstevel@tonic-gate zsh_txint(struct zscom *zs) 1454*0Sstevel@tonic-gate { 1455*0Sstevel@tonic-gate register struct syncline *zss; 1456*0Sstevel@tonic-gate register mblk_t *mp; 1457*0Sstevel@tonic-gate register int tmp; 1458*0Sstevel@tonic-gate register uchar_t *wr_cur; 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_TXINT, "zsh_txint: zs = %p", zs); 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL && (wr_cur < zs->zs_wr_lim)) { 1463*0Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++); 1464*0Sstevel@tonic-gate zs->zs_wr_cur = wr_cur; 1465*0Sstevel@tonic-gate return; 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate zss = (struct syncline *)&zs->zs_priv_str; 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate switch (zss->sl_txstate) { 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate /* 1474*0Sstevel@tonic-gate * we here because end of message block lim = cur 1475*0Sstevel@tonic-gate */ 1476*0Sstevel@tonic-gate case TX_ACTIVE: 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate mp = zss->sl_xactb; 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate again_txint: 1481*0Sstevel@tonic-gate mp = mp->b_cont; 1482*0Sstevel@tonic-gate if (mp) { 1483*0Sstevel@tonic-gate zss->sl_xactb = mp; 1484*0Sstevel@tonic-gate zss->sl_ocnt += tmp = mp->b_wptr - mp->b_rptr; 1485*0Sstevel@tonic-gate if (!tmp) 1486*0Sstevel@tonic-gate goto again_txint; 1487*0Sstevel@tonic-gate zs->zs_wr_cur = mp->b_rptr; 1488*0Sstevel@tonic-gate zs->zs_wr_lim = mp->b_wptr; 1489*0Sstevel@tonic-gate SCC_WRITEDATA(*zs->zs_wr_cur++); 1490*0Sstevel@tonic-gate return; 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate /* 1494*0Sstevel@tonic-gate * This is where the fun starts. At this point the 1495*0Sstevel@tonic-gate * last character in the frame has been sent. We 1496*0Sstevel@tonic-gate * issue a RESET_TXINT so we won't get another txint 1497*0Sstevel@tonic-gate * until the CRC has been completely sent. Also we 1498*0Sstevel@tonic-gate * reset the Abort-On-Underrun bit so that CRC is 1499*0Sstevel@tonic-gate * sent at EOM, rather than an Abort. 1500*0Sstevel@tonic-gate */ 1501*0Sstevel@tonic-gate zs->zs_wr_cur = zs->zs_wr_lim = NULL; 1502*0Sstevel@tonic-gate zss->sl_txstate = TX_CRC; 1503*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1504*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY)) { 1505*0Sstevel@tonic-gate SCC_BIC(10, ZSWR10_UNDERRUN_ABORT); 1506*0Sstevel@tonic-gate zss->sl_st.opack++; 1507*0Sstevel@tonic-gate zss->sl_st.ochar += zss->sl_ocnt; 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate zss->sl_ocnt = 0; 1510*0Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead); 1511*0Sstevel@tonic-gate zss->sl_xhead = zss->sl_xactb = NULL; 1512*0Sstevel@tonic-gate ZSSETSOFT(zs); 1513*0Sstevel@tonic-gate break; 1514*0Sstevel@tonic-gate /* 1515*0Sstevel@tonic-gate * This txint means we have sent the CRC bytes at EOF. 1516*0Sstevel@tonic-gate * The next txint will mean we are sending or have sent the 1517*0Sstevel@tonic-gate * flag character at EOF, but we handle that differently, and 1518*0Sstevel@tonic-gate * enter different states,depending on whether we're IBM or not. 1519*0Sstevel@tonic-gate */ 1520*0Sstevel@tonic-gate case TX_CRC: 1521*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) { 1522*0Sstevel@tonic-gate zss->sl_txstate = TX_FLAG; /* HDX path */ 1523*0Sstevel@tonic-gate } else { /* FDX path */ 1524*0Sstevel@tonic-gate if (!zsh_start(zs, zss)) { 1525*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 1526*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1527*0Sstevel@tonic-gate } 1528*0Sstevel@tonic-gate } 1529*0Sstevel@tonic-gate break; 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate /* 1532*0Sstevel@tonic-gate * This txint means the closing flag byte is going out the door. 1533*0Sstevel@tonic-gate * We use this state to allow this to complete before dropping RTS. 1534*0Sstevel@tonic-gate */ 1535*0Sstevel@tonic-gate case TX_FLAG: 1536*0Sstevel@tonic-gate zss->sl_txstate = TX_LAST; 1537*0Sstevel@tonic-gate (void) zsh_start(zs, zss); 1538*0Sstevel@tonic-gate break; 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate /* 1541*0Sstevel@tonic-gate * Arriving here means the flag should be out and it's finally 1542*0Sstevel@tonic-gate * time to close the barn door. 1543*0Sstevel@tonic-gate */ 1544*0Sstevel@tonic-gate case TX_LAST: 1545*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 1546*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1547*0Sstevel@tonic-gate break; 1548*0Sstevel@tonic-gate 1549*0Sstevel@tonic-gate /* 1550*0Sstevel@tonic-gate * If transmit was aborted, do nothing - watchdog will recover. 1551*0Sstevel@tonic-gate */ 1552*0Sstevel@tonic-gate case TX_ABORTED: 1553*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1554*0Sstevel@tonic-gate break; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate default: 1557*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1558*0Sstevel@tonic-gate break; 1559*0Sstevel@tonic-gate } 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate /* 1563*0Sstevel@tonic-gate * External Status Change interrupt service procedure 1564*0Sstevel@tonic-gate */ 1565*0Sstevel@tonic-gate static void 1566*0Sstevel@tonic-gate zsh_xsint(struct zscom *zs) 1567*0Sstevel@tonic-gate { 1568*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 1569*0Sstevel@tonic-gate register uchar_t s0, x0; 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_XSINT, "zsh_xsint: zs = %p", zs); 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate s0 = SCC_READ0(); 1574*0Sstevel@tonic-gate x0 = s0 ^ zss->sl_rr0; 1575*0Sstevel@tonic-gate zss->sl_rr0 = s0; 1576*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate if (s0 & ZSRR0_TXUNDER) { 1579*0Sstevel@tonic-gate switch (zss->sl_txstate) { 1580*0Sstevel@tonic-gate /* 1581*0Sstevel@tonic-gate * A transmitter underrun has occurred. If we are not 1582*0Sstevel@tonic-gate * here as the result of an abort sent by the watchdog 1583*0Sstevel@tonic-gate * timeout routine, we need to send an abort to flush 1584*0Sstevel@tonic-gate * the transmitter. Otherwise there is a danger of 1585*0Sstevel@tonic-gate * trashing the next frame but still sending a good crc. 1586*0Sstevel@tonic-gate * The TX_ABORTED flag is set so that the watchdog 1587*0Sstevel@tonic-gate * routine can initiate recovery. 1588*0Sstevel@tonic-gate */ 1589*0Sstevel@tonic-gate case TX_ACTIVE: 1590*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT); 1591*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1592*0Sstevel@tonic-gate zss->sl_st.underrun++; 1593*0Sstevel@tonic-gate zsh_txbad(zs, zss); 1594*0Sstevel@tonic-gate 1595*0Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED; 1596*0Sstevel@tonic-gate zss->sl_wd_count = 0; 1597*0Sstevel@tonic-gate break; 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate case TX_CRC: 1600*0Sstevel@tonic-gate break; 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate case TX_FLAG: 1603*0Sstevel@tonic-gate break; 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate case TX_ABORTED: 1606*0Sstevel@tonic-gate break; 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate case TX_OFF: 1609*0Sstevel@tonic-gate break; 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate case TX_LAST: 1612*0Sstevel@tonic-gate break; 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate default: 1615*0Sstevel@tonic-gate break; 1616*0Sstevel@tonic-gate } 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) && zs->zs_rd_cur) { 1620*0Sstevel@tonic-gate zss->sl_st.abort++; 1621*0Sstevel@tonic-gate zsh_rxbad(zs, zss); 1622*0Sstevel@tonic-gate } else if ((s0 & ZSRR0_SYNC) && (zs->zs_rd_cur)) { 1623*0Sstevel@tonic-gate /* 1624*0Sstevel@tonic-gate * Tricky code to avoid disaster in the case where 1625*0Sstevel@tonic-gate * an abort was detected while receiving a packet, 1626*0Sstevel@tonic-gate * but the abort did not last long enough to be 1627*0Sstevel@tonic-gate * detected by zsh_xsint - this can happen since 1628*0Sstevel@tonic-gate * the ZSRR0_BREAK is not latched. Since an abort 1629*0Sstevel@tonic-gate * will automatically cause the SCC to enter 1630*0Sstevel@tonic-gate * hunt mode, hopefully, the sync/hunt bit will be 1631*0Sstevel@tonic-gate * set in this case (although if the interrupt is 1632*0Sstevel@tonic-gate * sufficiently delayed, the SCC may have sync'ed 1633*0Sstevel@tonic-gate * in again if it has detected a flag). 1634*0Sstevel@tonic-gate */ 1635*0Sstevel@tonic-gate zss->sl_st.abort++; 1636*0Sstevel@tonic-gate zsh_rxbad(zs, zss); 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate if (x0 & s0 & ZSRR0_CTS) { 1640*0Sstevel@tonic-gate if (zss->sl_txstate == TX_RTS) { 1641*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) { 1642*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_TX_ENABLE); 1643*0Sstevel@tonic-gate } 1644*0Sstevel@tonic-gate (void) zsh_start(zs, zss); 1645*0Sstevel@tonic-gate } else if ((zss->sl_mode.sm_config & (CONN_IBM | CONN_SIGNAL))) { 1646*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 1647*0Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP); 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate /* 1652*0Sstevel@tonic-gate * We don't care about CTS transitions unless we are in either 1653*0Sstevel@tonic-gate * IBM or SIGNAL mode, or both. So, if we see CTS drop, and we 1654*0Sstevel@tonic-gate * care, and we are not idle, send up a report message. 1655*0Sstevel@tonic-gate */ 1656*0Sstevel@tonic-gate if ((x0 & ZSRR0_CTS) && ((s0 & ZSRR0_CTS) == 0) && 1657*0Sstevel@tonic-gate (zss->sl_txstate != TX_OFF) && 1658*0Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_IBM | CONN_SIGNAL))) { 1659*0Sstevel@tonic-gate SCC_BIC(15, ZSR15_CTS); 1660*0Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_DOWN); 1661*0Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG; 1662*0Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ; 1663*0Sstevel@tonic-gate zss->sl_st.cts++; 1664*0Sstevel@tonic-gate if (zss->sl_txstate != TX_IDLE) 1665*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT); 1666*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 1667*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1668*0Sstevel@tonic-gate zss->sl_wd_count = 0; 1669*0Sstevel@tonic-gate zsh_txbad(zs, zss); 1670*0Sstevel@tonic-gate } 1671*0Sstevel@tonic-gate } 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate /* 1675*0Sstevel@tonic-gate * Receive interrupt service procedure 1676*0Sstevel@tonic-gate */ 1677*0Sstevel@tonic-gate static void 1678*0Sstevel@tonic-gate zsh_rxint(struct zscom *zs) 1679*0Sstevel@tonic-gate { 1680*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 1681*0Sstevel@tonic-gate register mblk_t *bp = zss->sl_ractb; 1682*0Sstevel@tonic-gate unsigned char *rd_cur; 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_RXINT, "zsh_rxint: zs = %p", zs); 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate if (((rd_cur = zs->zs_rd_cur) != NULL) && rd_cur < zs->zs_rd_lim) { 1687*0Sstevel@tonic-gate *rd_cur++ = SCC_READDATA(); 1688*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur; 1689*0Sstevel@tonic-gate return; 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate if (!rd_cur) { /* Beginning of frame */ 1693*0Sstevel@tonic-gate if (!bp) { 1694*0Sstevel@tonic-gate ZSH_ALLOCB(bp); 1695*0Sstevel@tonic-gate zss->sl_ractb = bp; 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate zss->sl_rhead = bp; 1698*0Sstevel@tonic-gate } else { /* end of data block should be cur==lim */ 1699*0Sstevel@tonic-gate bp->b_wptr = zs->zs_rd_cur; 1700*0Sstevel@tonic-gate ZSH_ALLOCB(bp->b_cont); 1701*0Sstevel@tonic-gate bp = zss->sl_ractb = bp->b_cont; 1702*0Sstevel@tonic-gate } 1703*0Sstevel@tonic-gate if (!bp) { 1704*0Sstevel@tonic-gate zss->sl_st.nobuffers++; 1705*0Sstevel@tonic-gate zsh_rxbad(zs, zss); 1706*0Sstevel@tonic-gate return; 1707*0Sstevel@tonic-gate } 1708*0Sstevel@tonic-gate zs->zs_rd_cur = bp->b_wptr; 1709*0Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim; 1710*0Sstevel@tonic-gate *zs->zs_rd_cur++ = SCC_READDATA(); /* Also resets interrupt */ 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate /* 1715*0Sstevel@tonic-gate * Special Receive Condition Interrupt routine 1716*0Sstevel@tonic-gate */ 1717*0Sstevel@tonic-gate static void 1718*0Sstevel@tonic-gate zsh_srint(struct zscom *zs) 1719*0Sstevel@tonic-gate { 1720*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 1721*0Sstevel@tonic-gate register uchar_t s1; 1722*0Sstevel@tonic-gate register uchar_t *rd_cur; 1723*0Sstevel@tonic-gate 1724*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SRINT, "zsh_srint: zs = %p", zs); 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate SCC_READ(1, s1); 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate if (s1 & ZSRR1_RXEOF) { /* end of frame */ 1729*0Sstevel@tonic-gate (void) SCC_READDATA(); 1730*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 1731*0Sstevel@tonic-gate if (s1 & ZSRR1_FE) { /* bad CRC */ 1732*0Sstevel@tonic-gate zss->sl_st.crc++; 1733*0Sstevel@tonic-gate zsh_rxbad(zs, zss); 1734*0Sstevel@tonic-gate return; 1735*0Sstevel@tonic-gate } 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate if ((rd_cur = zs->zs_rd_cur) == NULL) 1738*0Sstevel@tonic-gate return; 1739*0Sstevel@tonic-gate 1740*0Sstevel@tonic-gate /* 1741*0Sstevel@tonic-gate * Drop one CRC byte from length because it came in 1742*0Sstevel@tonic-gate * before the special interrupt got here. 1743*0Sstevel@tonic-gate */ 1744*0Sstevel@tonic-gate zss->sl_ractb->b_wptr = rd_cur - 1; 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate /* 1747*0Sstevel@tonic-gate * put on done queue 1748*0Sstevel@tonic-gate */ 1749*0Sstevel@tonic-gate ZSH_PUTQ(zss->sl_rhead); 1750*0Sstevel@tonic-gate zss->sl_rhead = NULL; 1751*0Sstevel@tonic-gate zss->sl_ractb = NULL; 1752*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 1753*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 1754*0Sstevel@tonic-gate ZSSETSOFT(zs); 1755*0Sstevel@tonic-gate 1756*0Sstevel@tonic-gate } else if (s1 & ZSRR1_DO) { 1757*0Sstevel@tonic-gate (void) SCC_READDATA(); 1758*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 1759*0Sstevel@tonic-gate zss->sl_st.overrun++; 1760*0Sstevel@tonic-gate zsh_rxbad(zs, zss); 1761*0Sstevel@tonic-gate } else 1762*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate /* 1766*0Sstevel@tonic-gate * Handle a second stage interrupt. 1767*0Sstevel@tonic-gate * Does mostly lower priority buffer management stuff. 1768*0Sstevel@tonic-gate */ 1769*0Sstevel@tonic-gate static int 1770*0Sstevel@tonic-gate zsh_softint(struct zscom *zs) 1771*0Sstevel@tonic-gate { 1772*0Sstevel@tonic-gate register struct syncline *zss; 1773*0Sstevel@tonic-gate register queue_t *q; 1774*0Sstevel@tonic-gate register mblk_t *mp, *tmp; 1775*0Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL; 1776*0Sstevel@tonic-gate register int allocbcount = 0; 1777*0Sstevel@tonic-gate int m_error; 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_START, "zsh_soft start: zs = %p", zs); 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1782*0Sstevel@tonic-gate zss = (struct syncline *)zs->zs_priv; 1783*0Sstevel@tonic-gate if (!zss || (q = zss->sl_stream.str_rq) == NULL) { 1784*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1785*0Sstevel@tonic-gate return (0); 1786*0Sstevel@tonic-gate } 1787*0Sstevel@tonic-gate m_error = zss->sl_m_error; 1788*0Sstevel@tonic-gate 1789*0Sstevel@tonic-gate zss->sl_m_error = 0; 1790*0Sstevel@tonic-gate 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate if (!zss->sl_mstat) 1793*0Sstevel@tonic-gate zss->sl_mstat = allocb(sizeof (struct sl_status), BPRI_MED); 1794*0Sstevel@tonic-gate 1795*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1796*0Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) { 1797*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) { 1798*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 1799*0Sstevel@tonic-gate } else { 1800*0Sstevel@tonic-gate register uchar_t s0; 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate s0 = SCC_READ0(); 1803*0Sstevel@tonic-gate if (s0 & ZSRR0_CTS) { 1804*0Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; 1805*0Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS); 1806*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 1807*0Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP); 1808*0Sstevel@tonic-gate } 1809*0Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) { 1810*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1811*0Sstevel@tonic-gate flushq(WR(q), FLUSHDATA); 1812*0Sstevel@tonic-gate goto next; 1813*0Sstevel@tonic-gate } 1814*0Sstevel@tonic-gate } 1815*0Sstevel@tonic-gate } 1816*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1817*0Sstevel@tonic-gate 1818*0Sstevel@tonic-gate next: 1819*0Sstevel@tonic-gate for (;;) { 1820*0Sstevel@tonic-gate ZSH_GETQ(mp); 1821*0Sstevel@tonic-gate if (!mp) 1822*0Sstevel@tonic-gate break; 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate if (mp->b_rptr == mp->b_wptr) { 1825*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_RSE) { 1826*0Sstevel@tonic-gate allocbcount++; 1827*0Sstevel@tonic-gate } 1828*0Sstevel@tonic-gate freemsg(mp); 1829*0Sstevel@tonic-gate continue; 1830*0Sstevel@tonic-gate } 1831*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 1832*0Sstevel@tonic-gate zss->sl_st.ichar += msgdsize(mp); 1833*0Sstevel@tonic-gate zss->sl_st.ipack++; 1834*0Sstevel@tonic-gate if (!(canputnext(q))) { 1835*0Sstevel@tonic-gate zss->sl_st.ierror++; 1836*0Sstevel@tonic-gate allocbcount++; 1837*0Sstevel@tonic-gate freemsg(mp); 1838*0Sstevel@tonic-gate continue; 1839*0Sstevel@tonic-gate } 1840*0Sstevel@tonic-gate } else if (mp->b_datap->db_type == M_PROTO) { 1841*0Sstevel@tonic-gate if (!(canputnext(q))) { 1842*0Sstevel@tonic-gate freemsg(mp); 1843*0Sstevel@tonic-gate continue; 1844*0Sstevel@tonic-gate } 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate if (!head) { 1847*0Sstevel@tonic-gate allocbcount++; 1848*0Sstevel@tonic-gate zss->sl_soft_active = 1; 1849*0Sstevel@tonic-gate head = mp; 1850*0Sstevel@tonic-gate } else { 1851*0Sstevel@tonic-gate if (!tail) 1852*0Sstevel@tonic-gate tail = head; 1853*0Sstevel@tonic-gate tail->b_next = mp; 1854*0Sstevel@tonic-gate tail = mp; 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate } 1857*0Sstevel@tonic-gate if (allocbcount) 1858*0Sstevel@tonic-gate ZSH_GETBLOCK(zs, allocbcount); 1859*0Sstevel@tonic-gate 1860*0Sstevel@tonic-gate tmp = NULL; 1861*0Sstevel@tonic-gate again: 1862*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1863*0Sstevel@tonic-gate if (!zss->sl_xstandby) { 1864*0Sstevel@tonic-gate if (tmp) { 1865*0Sstevel@tonic-gate zss->sl_xstandby = tmp; 1866*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1867*0Sstevel@tonic-gate } else { 1868*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1869*0Sstevel@tonic-gate if (tmp = getq(WR(q))) 1870*0Sstevel@tonic-gate goto again; 1871*0Sstevel@tonic-gate } 1872*0Sstevel@tonic-gate } else { 1873*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1874*0Sstevel@tonic-gate if (tmp) 1875*0Sstevel@tonic-gate (void) putbq(WR(q), tmp); 1876*0Sstevel@tonic-gate } 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1879*0Sstevel@tonic-gate 1880*0Sstevel@tonic-gate while (head) { 1881*0Sstevel@tonic-gate if (!tail) { 1882*0Sstevel@tonic-gate putnext(q, head); 1883*0Sstevel@tonic-gate break; 1884*0Sstevel@tonic-gate } 1885*0Sstevel@tonic-gate mp = head; 1886*0Sstevel@tonic-gate head = head->b_next; 1887*0Sstevel@tonic-gate mp->b_next = NULL; 1888*0Sstevel@tonic-gate putnext(q, mp); 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate if (m_error) 1893*0Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error); 1894*0Sstevel@tonic-gate 1895*0Sstevel@tonic-gate zss->sl_soft_active = 0; 1896*0Sstevel@tonic-gate 1897*0Sstevel@tonic-gate TRACE_1(TR_ZSH, TR_ZSH_SOFT_END, "zsh_soft end: zs = %p", zs); 1898*0Sstevel@tonic-gate 1899*0Sstevel@tonic-gate return (0); 1900*0Sstevel@tonic-gate } 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate /* 1903*0Sstevel@tonic-gate * Initialization routine. 1904*0Sstevel@tonic-gate * Sets Clock sources, baud rate, modes and miscellaneous parameters. 1905*0Sstevel@tonic-gate */ 1906*0Sstevel@tonic-gate static int 1907*0Sstevel@tonic-gate zsh_program(struct zscom *zs, struct scc_mode *sm) 1908*0Sstevel@tonic-gate { 1909*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 1910*0Sstevel@tonic-gate register struct zs_prog *zspp; 1911*0Sstevel@tonic-gate register ushort_t tconst = 0; 1912*0Sstevel@tonic-gate register int wr11 = 0; 1913*0Sstevel@tonic-gate register int baud = 0; 1914*0Sstevel@tonic-gate register int pll = 0; 1915*0Sstevel@tonic-gate register int speed = 0; 1916*0Sstevel@tonic-gate register int flags = ZSP_SYNC; 1917*0Sstevel@tonic-gate int err = 0; 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate ZSSETSOFT(zs); /* get our house in order */ 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate switch (sm->sm_txclock) { 1922*0Sstevel@tonic-gate case TXC_IS_TXC: 1923*0Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_TRXC; 1924*0Sstevel@tonic-gate break; 1925*0Sstevel@tonic-gate case TXC_IS_RXC: 1926*0Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_RTXC; 1927*0Sstevel@tonic-gate break; 1928*0Sstevel@tonic-gate case TXC_IS_BAUD: 1929*0Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_BAUD; 1930*0Sstevel@tonic-gate wr11 |= ZSWR11_TRXC_OUT_ENA + ZSWR11_TRXC_XMIT; 1931*0Sstevel@tonic-gate baud++; 1932*0Sstevel@tonic-gate break; 1933*0Sstevel@tonic-gate case TXC_IS_PLL: 1934*0Sstevel@tonic-gate wr11 |= ZSWR11_TXCLK_DPLL; 1935*0Sstevel@tonic-gate pll++; 1936*0Sstevel@tonic-gate break; 1937*0Sstevel@tonic-gate default: 1938*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_TXC; 1939*0Sstevel@tonic-gate err = EINVAL; 1940*0Sstevel@tonic-gate goto out; 1941*0Sstevel@tonic-gate } 1942*0Sstevel@tonic-gate switch (sm->sm_rxclock) { 1943*0Sstevel@tonic-gate case RXC_IS_RXC: 1944*0Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_RTXC; 1945*0Sstevel@tonic-gate break; 1946*0Sstevel@tonic-gate case RXC_IS_TXC: 1947*0Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_TRXC; 1948*0Sstevel@tonic-gate break; 1949*0Sstevel@tonic-gate case RXC_IS_BAUD: 1950*0Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_BAUD; 1951*0Sstevel@tonic-gate baud++; 1952*0Sstevel@tonic-gate break; 1953*0Sstevel@tonic-gate case RXC_IS_PLL: 1954*0Sstevel@tonic-gate wr11 |= ZSWR11_RXCLK_DPLL; 1955*0Sstevel@tonic-gate pll++; 1956*0Sstevel@tonic-gate break; 1957*0Sstevel@tonic-gate default: 1958*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_RXC; 1959*0Sstevel@tonic-gate err = EINVAL; 1960*0Sstevel@tonic-gate goto out; 1961*0Sstevel@tonic-gate } 1962*0Sstevel@tonic-gate if (baud && pll) { 1963*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL; 1964*0Sstevel@tonic-gate err = EINVAL; 1965*0Sstevel@tonic-gate goto out; 1966*0Sstevel@tonic-gate } 1967*0Sstevel@tonic-gate if (pll && !(sm->sm_config & CONN_NRZI)) { 1968*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_PLL; 1969*0Sstevel@tonic-gate err = EINVAL; 1970*0Sstevel@tonic-gate goto out; 1971*0Sstevel@tonic-gate } 1972*0Sstevel@tonic-gate 1973*0Sstevel@tonic-gate /* 1974*0Sstevel@tonic-gate * If we're going to use the BRG and the speed we want is != 0... 1975*0Sstevel@tonic-gate */ 1976*0Sstevel@tonic-gate if (baud && (speed = sm->sm_baudrate)) { 1977*0Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2; 1978*0Sstevel@tonic-gate if (tconst == 0) { 1979*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE; 1980*0Sstevel@tonic-gate err = EINVAL; 1981*0Sstevel@tonic-gate goto out; 1982*0Sstevel@tonic-gate } 1983*0Sstevel@tonic-gate sm->sm_baudrate = PCLK / (2 * ((int)tconst + 2)); 1984*0Sstevel@tonic-gate } else { 1985*0Sstevel@tonic-gate tconst = 0; /* Stop BRG. Also quiesces pin 24. */ 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate if (pll) { 1989*0Sstevel@tonic-gate if ((speed = sm->sm_baudrate * 32) != 0) 1990*0Sstevel@tonic-gate tconst = (PCLK + speed) / (2 * speed) - 2; 1991*0Sstevel@tonic-gate else 1992*0Sstevel@tonic-gate tconst = 0; 1993*0Sstevel@tonic-gate if (tconst == 0) { 1994*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_BAUDRATE; 1995*0Sstevel@tonic-gate err = EINVAL; 1996*0Sstevel@tonic-gate goto out; 1997*0Sstevel@tonic-gate } 1998*0Sstevel@tonic-gate speed = PCLK / (2 * ((int)tconst + 2)); 1999*0Sstevel@tonic-gate sm->sm_baudrate = speed / 32; 2000*0Sstevel@tonic-gate flags |= ZSP_PLL; 2001*0Sstevel@tonic-gate } 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate if ((sm->sm_config & (CONN_LPBK|CONN_ECHO)) == (CONN_LPBK|CONN_ECHO)) { 2004*0Sstevel@tonic-gate zss->sl_mode.sm_retval = SMERR_LPBKS; 2005*0Sstevel@tonic-gate err = EINVAL; 2006*0Sstevel@tonic-gate goto out; 2007*0Sstevel@tonic-gate } 2008*0Sstevel@tonic-gate if (sm->sm_config & CONN_LPBK) 2009*0Sstevel@tonic-gate flags |= ZSP_LOOP; 2010*0Sstevel@tonic-gate if (sm->sm_config & CONN_NRZI) 2011*0Sstevel@tonic-gate flags |= ZSP_NRZI; 2012*0Sstevel@tonic-gate if (sm->sm_config & CONN_ECHO) 2013*0Sstevel@tonic-gate flags |= ZSP_ECHO; 2014*0Sstevel@tonic-gate 2015*0Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 2016*0Sstevel@tonic-gate 2017*0Sstevel@tonic-gate zspp->zs = zs; 2018*0Sstevel@tonic-gate zspp->flags = (uchar_t)flags; 2019*0Sstevel@tonic-gate zspp->wr4 = ZSWR4_SDLC; 2020*0Sstevel@tonic-gate zspp->wr11 = (uchar_t)wr11; 2021*0Sstevel@tonic-gate zspp->wr12 = (uchar_t)(tconst & 0xff); 2022*0Sstevel@tonic-gate zspp->wr13 = (uchar_t)((tconst >> 8) & 0xff); 2023*0Sstevel@tonic-gate zspp->wr3 = (uchar_t)(ZSWR3_RX_ENABLE | ZSWR3_RXCRC_ENABLE | 2024*0Sstevel@tonic-gate ZSWR3_RX_8); 2025*0Sstevel@tonic-gate zspp->wr5 = (uchar_t)(ZSWR5_TX_8 | ZSWR5_DTR | ZSWR5_TXCRC_ENABLE); 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) { 2028*0Sstevel@tonic-gate zspp->wr5 |= ZSWR5_RTS; 2029*0Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; /* Assume CTS is high */ 2030*0Sstevel@tonic-gate } 2031*0Sstevel@tonic-gate if (sm->sm_config & CONN_IBM) { 2032*0Sstevel@tonic-gate zspp->wr15 = (uchar_t) 2033*0Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC | ZSR15_CTS); 2034*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) 2035*0Sstevel@tonic-gate zspp->wr15 &= ~ZSR15_CTS; 2036*0Sstevel@tonic-gate } else { 2037*0Sstevel@tonic-gate zspp->wr5 |= ZSWR5_TX_ENABLE; 2038*0Sstevel@tonic-gate zspp->wr15 = (uchar_t) 2039*0Sstevel@tonic-gate (ZSR15_TX_UNDER | ZSR15_BREAK | ZSR15_SYNC); 2040*0Sstevel@tonic-gate if (sm->sm_config & CONN_SIGNAL) 2041*0Sstevel@tonic-gate zspp->wr15 |= ZSR15_CTS; 2042*0Sstevel@tonic-gate } 2043*0Sstevel@tonic-gate 2044*0Sstevel@tonic-gate zs_program(zspp); 2045*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */ 2046*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); /* reset XS */ 2047*0Sstevel@tonic-gate zss->sl_flags |= SF_INITIALIZED; 2048*0Sstevel@tonic-gate bzero(&zss->sl_st, sizeof (struct sl_stats)); 2049*0Sstevel@tonic-gate bcopy(sm, &zss->sl_mode, sizeof (struct scc_mode)); 2050*0Sstevel@tonic-gate zss->sl_mode.sm_retval = 0; /* successful */ 2051*0Sstevel@tonic-gate out: 2052*0Sstevel@tonic-gate return (err); 2053*0Sstevel@tonic-gate } 2054*0Sstevel@tonic-gate 2055*0Sstevel@tonic-gate /* 2056*0Sstevel@tonic-gate * Function to store modem signal changes in sl_mstat field. 2057*0Sstevel@tonic-gate * Note that these events are supposed to be so far apart in time that 2058*0Sstevel@tonic-gate * we should always be able to send up the event and allocate a message 2059*0Sstevel@tonic-gate * block before another one happens. If not, we'll overwrite this one. 2060*0Sstevel@tonic-gate */ 2061*0Sstevel@tonic-gate static void 2062*0Sstevel@tonic-gate zsh_setmstat(struct zscom *zs, int event) 2063*0Sstevel@tonic-gate { 2064*0Sstevel@tonic-gate register struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 2065*0Sstevel@tonic-gate register struct sl_status *mstat; 2066*0Sstevel@tonic-gate register mblk_t *mp; 2067*0Sstevel@tonic-gate 2068*0Sstevel@tonic-gate if (((mp = zss->sl_mstat) != NULL) && 2069*0Sstevel@tonic-gate (zss->sl_mode.sm_config & (CONN_SIGNAL))) { 2070*0Sstevel@tonic-gate mstat = (struct sl_status *)mp->b_wptr; 2071*0Sstevel@tonic-gate mstat->type = (zss->sl_mode.sm_config & CONN_IBM) ? 2072*0Sstevel@tonic-gate SLS_LINKERR : SLS_MDMSTAT; 2073*0Sstevel@tonic-gate mstat->status = event; 2074*0Sstevel@tonic-gate gethrestime(&mstat->tstamp); 2075*0Sstevel@tonic-gate mp->b_wptr += sizeof (struct sl_status); 2076*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 2077*0Sstevel@tonic-gate ZSH_PUTQ(mp); 2078*0Sstevel@tonic-gate zss->sl_mstat = NULL; 2079*0Sstevel@tonic-gate ZSSETSOFT(zs); 2080*0Sstevel@tonic-gate } 2081*0Sstevel@tonic-gate } 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate /* 2084*0Sstevel@tonic-gate * Received Bad Frame procedure 2085*0Sstevel@tonic-gate */ 2086*0Sstevel@tonic-gate static void 2087*0Sstevel@tonic-gate zsh_rxbad(struct zscom *zs, struct syncline *zss) 2088*0Sstevel@tonic-gate { 2089*0Sstevel@tonic-gate /* 2090*0Sstevel@tonic-gate * swallow bad characters 2091*0Sstevel@tonic-gate */ 2092*0Sstevel@tonic-gate (void) SCC_READDATA(); 2093*0Sstevel@tonic-gate (void) SCC_READDATA(); 2094*0Sstevel@tonic-gate (void) SCC_READDATA(); 2095*0Sstevel@tonic-gate 2096*0Sstevel@tonic-gate SCC_BIS(3, ZSWR3_HUNT); /* enter hunt mode - ignores rest of frame */ 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate zss->sl_st.ierror++; 2099*0Sstevel@tonic-gate 2100*0Sstevel@tonic-gate /* 2101*0Sstevel@tonic-gate * Free active receive message. 2102*0Sstevel@tonic-gate */ 2103*0Sstevel@tonic-gate if (zss->sl_rhead) { 2104*0Sstevel@tonic-gate zss->sl_rhead->b_wptr = zss->sl_rhead->b_rptr; 2105*0Sstevel@tonic-gate zss->sl_rhead->b_datap->db_type = M_RSE; 2106*0Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_rhead); 2107*0Sstevel@tonic-gate zss->sl_ractb = NULL; 2108*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 2109*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 2110*0Sstevel@tonic-gate } 2111*0Sstevel@tonic-gate if (zss->sl_rhead) { 2112*0Sstevel@tonic-gate zss->sl_rhead = NULL; 2113*0Sstevel@tonic-gate ZSH_ALLOCB(zss->sl_ractb); 2114*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 2115*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 2116*0Sstevel@tonic-gate } 2117*0Sstevel@tonic-gate 2118*0Sstevel@tonic-gate ZSSETSOFT(zs); 2119*0Sstevel@tonic-gate } 2120*0Sstevel@tonic-gate 2121*0Sstevel@tonic-gate /* 2122*0Sstevel@tonic-gate * Transmit error procedure 2123*0Sstevel@tonic-gate */ 2124*0Sstevel@tonic-gate static void 2125*0Sstevel@tonic-gate zsh_txbad(struct zscom *zs, struct syncline *zss) 2126*0Sstevel@tonic-gate { 2127*0Sstevel@tonic-gate if (zss->sl_xhead) { /* free the message we were sending */ 2128*0Sstevel@tonic-gate zss->sl_xhead->b_wptr = zss->sl_xhead->b_rptr; 2129*0Sstevel@tonic-gate ZSH_FREEMSG(zss->sl_xhead); 2130*0Sstevel@tonic-gate zss->sl_xactb = NULL; 2131*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 2132*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 2133*0Sstevel@tonic-gate } 2134*0Sstevel@tonic-gate zss->sl_xhead = NULL; 2135*0Sstevel@tonic-gate 2136*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) { 2137*0Sstevel@tonic-gate /* 2138*0Sstevel@tonic-gate * drop RTS and our notion of CTS 2139*0Sstevel@tonic-gate */ 2140*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); 2141*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_TX_ENABLE); 2142*0Sstevel@tonic-gate zss->sl_rr0 &= ~ZSRR0_CTS; 2143*0Sstevel@tonic-gate } 2144*0Sstevel@tonic-gate zss->sl_txstate = TX_IDLE; 2145*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_PHONY)) 2146*0Sstevel@tonic-gate zss->sl_st.oerror++; 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate /* 2150*0Sstevel@tonic-gate * Transmitter watchdog timeout routine 2151*0Sstevel@tonic-gate */ 2152*0Sstevel@tonic-gate static void 2153*0Sstevel@tonic-gate zsh_watchdog(void *arg) 2154*0Sstevel@tonic-gate { 2155*0Sstevel@tonic-gate struct zscom *zs = arg; 2156*0Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 2157*0Sstevel@tonic-gate queue_t *wq; 2158*0Sstevel@tonic-gate mblk_t *mp; 2159*0Sstevel@tonic-gate int warning = 0; 2160*0Sstevel@tonic-gate uchar_t s0; 2161*0Sstevel@tonic-gate int do_flushwq = 0; 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate /* 2164*0Sstevel@tonic-gate * The main reason for this routine is because, under some 2165*0Sstevel@tonic-gate * circumstances, a transmit interrupt may get lost (ie., if 2166*0Sstevel@tonic-gate * underrun occurs after the last character has been sent, and 2167*0Sstevel@tonic-gate * the tx interrupt following the abort gets scheduled before 2168*0Sstevel@tonic-gate * the current tx interrupt has been serviced). Transmit can 2169*0Sstevel@tonic-gate * also get hung if the cable is pulled out and the clock was 2170*0Sstevel@tonic-gate * coming in from the modem. 2171*0Sstevel@tonic-gate */ 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2174*0Sstevel@tonic-gate if (zss->sl_stream.str_rq) 2175*0Sstevel@tonic-gate wq = WR(zss->sl_stream.str_rq); 2176*0Sstevel@tonic-gate else { 2177*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2178*0Sstevel@tonic-gate return; /* guard against close/callback race */ 2179*0Sstevel@tonic-gate } 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2182*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_XMT_INPROG) && wq->q_first) { 2183*0Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG; 2184*0Sstevel@tonic-gate if ((zss->sl_flags & SF_FDXPTP) || 2185*0Sstevel@tonic-gate zsh_hdp_ok_or_rts_state(zs, zss)) 2186*0Sstevel@tonic-gate (void) zsh_start(zs, zss); 2187*0Sstevel@tonic-gate goto end_watchdog; 2188*0Sstevel@tonic-gate } 2189*0Sstevel@tonic-gate 2190*0Sstevel@tonic-gate if (zss->sl_wd_count-- > 0) 2191*0Sstevel@tonic-gate goto end_watchdog; 2192*0Sstevel@tonic-gate 2193*0Sstevel@tonic-gate if (zss->sl_flags & SF_FLUSH_WQ) { 2194*0Sstevel@tonic-gate if (!(zss->sl_flags & SF_FDXPTP)) 2195*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 2196*0Sstevel@tonic-gate else { 2197*0Sstevel@tonic-gate s0 = SCC_READ0(); 2198*0Sstevel@tonic-gate if (s0 & ZSRR0_CTS) { 2199*0Sstevel@tonic-gate zss->sl_rr0 |= ZSRR0_CTS; 2200*0Sstevel@tonic-gate SCC_BIS(15, ZSR15_CTS); 2201*0Sstevel@tonic-gate zss->sl_flags &= ~SF_FLUSH_WQ; 2202*0Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_UP); 2203*0Sstevel@tonic-gate } 2204*0Sstevel@tonic-gate } 2205*0Sstevel@tonic-gate } 2206*0Sstevel@tonic-gate 2207*0Sstevel@tonic-gate switch (zss->sl_txstate) { 2208*0Sstevel@tonic-gate 2209*0Sstevel@tonic-gate case TX_ABORTED: 2210*0Sstevel@tonic-gate /* 2211*0Sstevel@tonic-gate * Transmitter was hung ... try restarting it. 2212*0Sstevel@tonic-gate */ 2213*0Sstevel@tonic-gate if (zss->sl_flags & SF_FDXPTP) { 2214*0Sstevel@tonic-gate zss->sl_flags |= SF_XMT_INPROG; 2215*0Sstevel@tonic-gate (void) zsh_start(zs, zss); 2216*0Sstevel@tonic-gate } else 2217*0Sstevel@tonic-gate do_flushwq = 1; 2218*0Sstevel@tonic-gate break; 2219*0Sstevel@tonic-gate 2220*0Sstevel@tonic-gate case TX_ACTIVE: 2221*0Sstevel@tonic-gate case TX_CRC: 2222*0Sstevel@tonic-gate /* 2223*0Sstevel@tonic-gate * Transmit is hung for some reason. Reset tx interrupt. 2224*0Sstevel@tonic-gate * Flush transmit fifo by sending an abort command 2225*0Sstevel@tonic-gate * which also sets the Underrun/EOM latch in WR0 and in 2226*0Sstevel@tonic-gate * turn generates an External Status interrupt that 2227*0Sstevel@tonic-gate * will reset the necessary message buffer pointers. 2228*0Sstevel@tonic-gate * The watchdog timer will cycle again to allow the SCC 2229*0Sstevel@tonic-gate * to settle down after the abort command. The next 2230*0Sstevel@tonic-gate * time through we'll see that the state is now TX_ABORTED 2231*0Sstevel@tonic-gate * and call zsh_start to grab a new message. 2232*0Sstevel@tonic-gate */ 2233*0Sstevel@tonic-gate if (--zss->sl_wd_count <= 0) { 2234*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_SEND_ABORT); 2235*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 2236*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 2237*0Sstevel@tonic-gate zsh_txbad(zs, zss); 2238*0Sstevel@tonic-gate zss->sl_txstate = TX_ABORTED; /* must be after txbad */ 2239*0Sstevel@tonic-gate warning = 1; 2240*0Sstevel@tonic-gate } 2241*0Sstevel@tonic-gate break; 2242*0Sstevel@tonic-gate 2243*0Sstevel@tonic-gate case TX_RTS: 2244*0Sstevel@tonic-gate /* 2245*0Sstevel@tonic-gate * Timer expired after we raised RTS. CTS never came up. 2246*0Sstevel@tonic-gate */ 2247*0Sstevel@tonic-gate zss->sl_st.cts++; 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate zsh_setmstat(zs, CS_CTS_TO); 2250*0Sstevel@tonic-gate zss->sl_flags &= ~SF_XMT_INPROG; 2251*0Sstevel@tonic-gate zss->sl_flags |= SF_FLUSH_WQ; 2252*0Sstevel@tonic-gate ZSSETSOFT(zs); 2253*0Sstevel@tonic-gate break; 2254*0Sstevel@tonic-gate 2255*0Sstevel@tonic-gate default: 2256*0Sstevel@tonic-gate /* 2257*0Sstevel@tonic-gate * If we time out in an inactive state we set a soft 2258*0Sstevel@tonic-gate * interrupt. This will call zsh_start which will 2259*0Sstevel@tonic-gate * clear SF_XMT_INPROG if the queue is empty. 2260*0Sstevel@tonic-gate */ 2261*0Sstevel@tonic-gate break; 2262*0Sstevel@tonic-gate } 2263*0Sstevel@tonic-gate end_watchdog: 2264*0Sstevel@tonic-gate if (zss->sl_txstate != TX_OFF) { 2265*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2266*0Sstevel@tonic-gate zss->sl_wd_id = timeout(zsh_watchdog, zs, SIO_WATCHDOG_TICK); 2267*0Sstevel@tonic-gate } else { 2268*0Sstevel@tonic-gate zss->sl_wd_id = 0; /* safety */ 2269*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2270*0Sstevel@tonic-gate } 2271*0Sstevel@tonic-gate if (warning || do_flushwq) { 2272*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 2273*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2274*0Sstevel@tonic-gate if ((mp = zss->sl_xstandby) != NULL) 2275*0Sstevel@tonic-gate zss->sl_xstandby = NULL; 2276*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2277*0Sstevel@tonic-gate if (mp) 2278*0Sstevel@tonic-gate freemsg(mp); 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2281*0Sstevel@tonic-gate if (warning) 2282*0Sstevel@tonic-gate cmn_err(CE_WARN, "zsh%x: transmit hung", zs->zs_unit); 2283*0Sstevel@tonic-gate } 2284*0Sstevel@tonic-gate 2285*0Sstevel@tonic-gate static void 2286*0Sstevel@tonic-gate zsh_callback(void *arg) 2287*0Sstevel@tonic-gate { 2288*0Sstevel@tonic-gate struct zscom *zs = arg; 2289*0Sstevel@tonic-gate struct syncline *zss = (struct syncline *)&zs->zs_priv_str; 2290*0Sstevel@tonic-gate int tmp = ZSH_MAX_RSTANDBY; 2291*0Sstevel@tonic-gate 2292*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2293*0Sstevel@tonic-gate if (zss->sl_bufcid) { 2294*0Sstevel@tonic-gate zss->sl_bufcid = 0; 2295*0Sstevel@tonic-gate ZSH_GETBLOCK(zs, tmp); 2296*0Sstevel@tonic-gate } 2297*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2298*0Sstevel@tonic-gate } 2299