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