xref: /onnv-gate/usr/src/uts/sun/io/zs_common.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*
28*0Sstevel@tonic-gate  *	Serial I/O driver for Z8530 chips
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include	<sys/types.h>
34*0Sstevel@tonic-gate #include	<sys/param.h>
35*0Sstevel@tonic-gate #include	<sys/systm.h>
36*0Sstevel@tonic-gate #include	<sys/sysmacros.h>
37*0Sstevel@tonic-gate #include	<sys/stropts.h>
38*0Sstevel@tonic-gate #include	<sys/stream.h>
39*0Sstevel@tonic-gate #include	<sys/stat.h>
40*0Sstevel@tonic-gate #include	<sys/mkdev.h>
41*0Sstevel@tonic-gate #include	<sys/cmn_err.h>
42*0Sstevel@tonic-gate #include	<sys/errno.h>
43*0Sstevel@tonic-gate #include	<sys/kmem.h>
44*0Sstevel@tonic-gate #include	<sys/zsdev.h>
45*0Sstevel@tonic-gate #include	<sys/debug.h>
46*0Sstevel@tonic-gate #include	<sys/machsystm.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include	<sys/conf.h>
49*0Sstevel@tonic-gate #include	<sys/sunddi.h>
50*0Sstevel@tonic-gate #include	<sys/errno.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #define	 ZS_TRACING
53*0Sstevel@tonic-gate #ifdef  ZS_TRACING
54*0Sstevel@tonic-gate #include <sys/vtrace.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * Temp tracepoint definitions
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate #define	TR_FAC_ZS		51
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #define	TR_ZS_H_INT_START	1
62*0Sstevel@tonic-gate #define	TR_ZS_H_INT_END		2
63*0Sstevel@tonic-gate #define	TR_ZS_INT_START		3
64*0Sstevel@tonic-gate #define	TR_ZS_INT_END		4
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate #define	TR_FAC_ZS_INT		52
67*0Sstevel@tonic-gate #define	TR_READ_START		1
68*0Sstevel@tonic-gate #define	TR_READ_END		2
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #endif  /* ZSH_TRACING */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #define	KIOIP		KSTAT_INTR_PTR(zs->intrstats)
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #ifndef	MAXZS
75*0Sstevel@tonic-gate #define	MAXZS		4
76*0Sstevel@tonic-gate #endif
77*0Sstevel@tonic-gate int maxzs = MAXZS;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate int nzs = 0;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate struct zscom *zscom;
82*0Sstevel@tonic-gate struct zscom *zscurr;
83*0Sstevel@tonic-gate struct zscom *zslast;
84*0Sstevel@tonic-gate struct zs_prog *zs_prog;
85*0Sstevel@tonic-gate char  *zssoftCAR;
86*0Sstevel@tonic-gate int	zs_watchdog_count = 10;	/* countdown to determine if tx hung */
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate int zs_drain_check = 15000000;		/* tunable: exit drain check time */
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate #ifdef ZS_DEBUG
91*0Sstevel@tonic-gate char zs_h_log[ZS_H_LOG_MAX +10];
92*0Sstevel@tonic-gate int zs_h_log_n = 0;
93*0Sstevel@tonic-gate #define	zs_h_log_add(c) \
94*0Sstevel@tonic-gate 	{ \
95*0Sstevel@tonic-gate 		if (zs_h_log_n >= ZS_H_LOG_MAX) \
96*0Sstevel@tonic-gate 			zs_h_log_n = 0; \
97*0Sstevel@tonic-gate 		zs_h_log[zs_h_log_n++] = c; \
98*0Sstevel@tonic-gate 		zs_h_log[zs_h_log_n] = '\0'; \
99*0Sstevel@tonic-gate 	}
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate #else /* NO_ZS_DEBUG */
102*0Sstevel@tonic-gate #define	zs_h_log_add(c)
103*0Sstevel@tonic-gate #endif /* ZS_DEBUG */
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate /*
107*0Sstevel@tonic-gate  * Driver data
108*0Sstevel@tonic-gate  */
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate #define	GETPROP(dip, str, defval) \
111*0Sstevel@tonic-gate 	ddi_getprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, (str), (defval))
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate int	zs_usec_delay = 1;
114*0Sstevel@tonic-gate int	zssoftpend;
115*0Sstevel@tonic-gate ddi_softintr_t zs_softintr_id;
116*0Sstevel@tonic-gate time_t	default_dtrlow = 3;	/* hold dtr low nearly this long on close */
117*0Sstevel@tonic-gate static ddi_iblock_cookie_t zs_iblock;
118*0Sstevel@tonic-gate static ddi_iblock_cookie_t zs_hi_iblock;
119*0Sstevel@tonic-gate static int zs_addedsoft = 0;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /*
123*0Sstevel@tonic-gate  * Driver information for auto-configuration stuff.
124*0Sstevel@tonic-gate  */
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate static int zsprobe(dev_info_t *dev);
127*0Sstevel@tonic-gate static int zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd);
128*0Sstevel@tonic-gate static int zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd);
129*0Sstevel@tonic-gate void	zsopinit(struct zscom *zs, struct zsops *zso);
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate static void zsnull_intr(struct zscom *zs);
132*0Sstevel@tonic-gate static int zsnull_softint(struct zscom *zs);
133*0Sstevel@tonic-gate static int zsnull_suspend(struct zscom *zs);
134*0Sstevel@tonic-gate static int zsnull_resume(struct zscom *zs);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate struct zsops zsops_null = {
137*0Sstevel@tonic-gate 			zsnull_intr,
138*0Sstevel@tonic-gate 			zsnull_intr,
139*0Sstevel@tonic-gate 			zsnull_intr,
140*0Sstevel@tonic-gate 			zsnull_intr,
141*0Sstevel@tonic-gate 			zsnull_softint,
142*0Sstevel@tonic-gate 			zsnull_suspend,
143*0Sstevel@tonic-gate 			zsnull_resume
144*0Sstevel@tonic-gate };
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate extern struct streamtab asynctab;	/* default -- from zs_async.c */
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate uint_t zs_high_intr(caddr_t argzs);
149*0Sstevel@tonic-gate uint_t zsintr(caddr_t intarg);
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate extern int zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
152*0Sstevel@tonic-gate void **result);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
155*0Sstevel@tonic-gate     int spec_type, minor_t minor_num);
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate extern struct streamtab zsstab;
158*0Sstevel@tonic-gate int		zssoftpend;		/* soft interrupt pending */
159*0Sstevel@tonic-gate kmutex_t	zs_soft_lock;		/* adapt.lock,to use to protect data */
160*0Sstevel@tonic-gate 					/* common to sev. streams or ports   */
161*0Sstevel@tonic-gate kmutex_t	zs_curr_lock;		/* lock protecting zscurr */
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate extern kcondvar_t lbolt_cv;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate  * curently the only spin lock level 12 for all ocasions
167*0Sstevel@tonic-gate  */
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate #define	ZSS_CONF_FLAG   (D_NEW | D_MP)
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate static  struct cb_ops cb_zs_ops = {
172*0Sstevel@tonic-gate 	nulldev,		/* cb_open */
173*0Sstevel@tonic-gate 	nulldev,		/* cb_close */
174*0Sstevel@tonic-gate 	nodev,			/* cb_strategy */
175*0Sstevel@tonic-gate 	nodev,			/* cb_print */
176*0Sstevel@tonic-gate 	nodev,			/* cb_dump */
177*0Sstevel@tonic-gate 	nodev,			/* cb_read */
178*0Sstevel@tonic-gate 	nodev,			/* cb_write */
179*0Sstevel@tonic-gate 	nodev,			/* cb_ioctl */
180*0Sstevel@tonic-gate 	nodev,			/* cb_devmap */
181*0Sstevel@tonic-gate 	nodev,			/* cb_mmap */
182*0Sstevel@tonic-gate 	nodev,			/* cb_segmap */
183*0Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
184*0Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
185*0Sstevel@tonic-gate 	&asynctab,		/* cb_stream */
186*0Sstevel@tonic-gate 	(int)(ZSS_CONF_FLAG)	/* cb_flag */
187*0Sstevel@tonic-gate };
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate struct dev_ops zs_ops = {
190*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
191*0Sstevel@tonic-gate 	0,			/* devo_refcnt */
192*0Sstevel@tonic-gate 	zsc_info,		/* devo_getinfo */
193*0Sstevel@tonic-gate 	nulldev,		/* devo_identify */
194*0Sstevel@tonic-gate 	zsprobe,		/* devo_probe */
195*0Sstevel@tonic-gate 	zsattach,		/* devo_attach */
196*0Sstevel@tonic-gate 	zsdetach,		/* devo_detach */
197*0Sstevel@tonic-gate 	nodev,			/* devo_reset */
198*0Sstevel@tonic-gate 	&cb_zs_ops,		/* devo_cb_ops */
199*0Sstevel@tonic-gate 	(struct bus_ops *)NULL,	/* devo_bus_ops */
200*0Sstevel@tonic-gate 	ddi_power		/* devo_power */
201*0Sstevel@tonic-gate };
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate /*
205*0Sstevel@tonic-gate  * This is the loadable module wrapper.
206*0Sstevel@tonic-gate  */
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate #include <sys/modctl.h>
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate /*
211*0Sstevel@tonic-gate  * Module linkage information for the kernel.
212*0Sstevel@tonic-gate  */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate static struct modldrv modldrv = {
217*0Sstevel@tonic-gate 		&mod_driverops, /* Type of module.  This one is a driver */
218*0Sstevel@tonic-gate 		"Z8530 serial driver V%I%",
219*0Sstevel@tonic-gate 		&zs_ops,	/* driver ops */
220*0Sstevel@tonic-gate };
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
223*0Sstevel@tonic-gate 			MODREV_1, (void *)&modldrv, NULL
224*0Sstevel@tonic-gate };
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate int
227*0Sstevel@tonic-gate _init(void)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate int
233*0Sstevel@tonic-gate _fini(void)
234*0Sstevel@tonic-gate {
235*0Sstevel@tonic-gate 	return (EBUSY);
236*0Sstevel@tonic-gate }
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate int
239*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
240*0Sstevel@tonic-gate {
241*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate static int
245*0Sstevel@tonic-gate zsprobe(dev_info_t *dev)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	struct zscc_device *zsaddr;
248*0Sstevel@tonic-gate 	int	rval;
249*0Sstevel@tonic-gate 	auto char	c;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	rval = DDI_PROBE_FAILURE;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * temporarily map in  registers
255*0Sstevel@tonic-gate 	 */
256*0Sstevel@tonic-gate 	if (ddi_map_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0)) {
257*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "zsprobe: unable to map registers");
258*0Sstevel@tonic-gate 		return (rval);
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/*
262*0Sstevel@tonic-gate 	 * NON-DDI Compliant call
263*0Sstevel@tonic-gate 	 */
264*0Sstevel@tonic-gate 	mon_clock_stop();
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	/*
267*0Sstevel@tonic-gate 	 * get in sync with the chip
268*0Sstevel@tonic-gate 	 */
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) {
271*0Sstevel@tonic-gate 		goto out;
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 	drv_usecwait(2);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	/*
276*0Sstevel@tonic-gate 	 * The traditional test for the presence of an 8530 has been to write
277*0Sstevel@tonic-gate 	 * a 15 (octal 017) to its control register address, then read it back.
278*0Sstevel@tonic-gate 	 * A Z8530 will respond to this with the contents of Read-Register 15.
279*0Sstevel@tonic-gate 	 * If this address were memory, or something else, we would expect to
280*0Sstevel@tonic-gate 	 * see the 15 again.  Normally, the contents of RR15 will be entirely
281*0Sstevel@tonic-gate 	 * different.  A Z8530 does not use the D0 and D2 bits of register 15,
282*0Sstevel@tonic-gate 	 * so they should equal zero.  Compatable chips should do the same.
283*0Sstevel@tonic-gate 	 * Beware of "enhanced" SCC's that do not guarantee this.
284*0Sstevel@tonic-gate 	 */
285*0Sstevel@tonic-gate 	if (ddi_poke8(dev, (char *)&zsaddr->zscc_control, '\017')
286*0Sstevel@tonic-gate 	    != DDI_SUCCESS) {
287*0Sstevel@tonic-gate 		goto out;
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 	drv_usecwait(2);
290*0Sstevel@tonic-gate 	if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) {
291*0Sstevel@tonic-gate 		goto out;
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 	drv_usecwait(2);
294*0Sstevel@tonic-gate 	if (c & 5) {
295*0Sstevel@tonic-gate 		goto out;
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	rval = DDI_PROBE_SUCCESS;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate out:
301*0Sstevel@tonic-gate 	/*
302*0Sstevel@tonic-gate 	 * NON-DDI Compliant call
303*0Sstevel@tonic-gate 	 */
304*0Sstevel@tonic-gate 	mon_clock_start();
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	ddi_unmap_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0);
307*0Sstevel@tonic-gate 	return (rval);
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate /*ARGSUSED*/
311*0Sstevel@tonic-gate static int
312*0Sstevel@tonic-gate zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	struct zscom	*zs;
315*0Sstevel@tonic-gate 	int		loops, i;
316*0Sstevel@tonic-gate 	uint_t		s;
317*0Sstevel@tonic-gate 	int		rtsdtr_bits = 0;
318*0Sstevel@tonic-gate 	char			softcd;
319*0Sstevel@tonic-gate 	uchar_t	rr;
320*0Sstevel@tonic-gate 	short			speed[2];
321*0Sstevel@tonic-gate 	int			current_chip = ddi_get_instance(dev);
322*0Sstevel@tonic-gate 	struct zscc_device	*tmpzs;		/* for mapping purposes */
323*0Sstevel@tonic-gate 	char name[16];
324*0Sstevel@tonic-gate 	int keyboard_prop;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	switch (cmd) {
327*0Sstevel@tonic-gate 	case DDI_ATTACH:
328*0Sstevel@tonic-gate 		break;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	case DDI_RESUME:
331*0Sstevel@tonic-gate 		zs = &zscom[current_chip*2];
332*0Sstevel@tonic-gate 		/*
333*0Sstevel@tonic-gate 		 * Try to resume first channel
334*0Sstevel@tonic-gate 		 */
335*0Sstevel@tonic-gate 		if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS)
336*0Sstevel@tonic-gate 			return (DDI_FAILURE);
337*0Sstevel@tonic-gate 		/*
338*0Sstevel@tonic-gate 		 * And the second channel
339*0Sstevel@tonic-gate 		 */
340*0Sstevel@tonic-gate 		zs++;
341*0Sstevel@tonic-gate 		if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS) {
342*0Sstevel@tonic-gate 			zs--;
343*0Sstevel@tonic-gate 			if (!zs->zs_suspend ||
344*0Sstevel@tonic-gate 			    (zs->zs_suspend)(zs) != DDI_SUCCESS)
345*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
346*0Sstevel@tonic-gate 				    "zs: inconsistent suspend/resume state");
347*0Sstevel@tonic-gate 			return (DDI_FAILURE);
348*0Sstevel@tonic-gate 		}
349*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	default:
352*0Sstevel@tonic-gate 		return (DDI_FAILURE);
353*0Sstevel@tonic-gate 	}
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	if (zscom == NULL) {
356*0Sstevel@tonic-gate 		mutex_init(&zs_soft_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL);
357*0Sstevel@tonic-gate 		mutex_init(&zs_curr_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL_HI);
358*0Sstevel@tonic-gate 		zscom = kmem_zalloc(maxzs * sizeof (struct zscom), KM_SLEEP);
359*0Sstevel@tonic-gate 		zs_prog = kmem_zalloc(maxzs * sizeof (struct zs_prog),
360*0Sstevel@tonic-gate 		    KM_SLEEP);
361*0Sstevel@tonic-gate 		zssoftCAR = kmem_zalloc(maxzs, KM_SLEEP);
362*0Sstevel@tonic-gate 		/* don't set nzs until arrays are allocated */
363*0Sstevel@tonic-gate 		membar_producer();
364*0Sstevel@tonic-gate 		nzs = maxzs;
365*0Sstevel@tonic-gate 		zscurr = &zscom[(current_chip*2) + 1];
366*0Sstevel@tonic-gate 		zslast = &zscom[current_chip*2];
367*0Sstevel@tonic-gate 		i = GETPROP(dev, "zs-usec-delay", 0);
368*0Sstevel@tonic-gate 		zs_usec_delay = (i <= 0) ? 1 : i;
369*0Sstevel@tonic-gate 	}
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	if (2 * current_chip >=  maxzs) {
372*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
373*0Sstevel@tonic-gate 		    "zs: unable to allocate resources for  chip %d.",
374*0Sstevel@tonic-gate 		    current_chip);
375*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "Change zs:maxzs in /etc/system");
376*0Sstevel@tonic-gate 		return (DDI_FAILURE);
377*0Sstevel@tonic-gate 	}
378*0Sstevel@tonic-gate 	zs = &zscom[current_chip*2];
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	/*
381*0Sstevel@tonic-gate 	 * map in the device registers
382*0Sstevel@tonic-gate 	 */
383*0Sstevel@tonic-gate 	if (ddi_map_regs(dev, 0, (caddr_t *)&zs->zs_addr, 0, 0)) {
384*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "zs%d: unable to map registers\n",
385*0Sstevel@tonic-gate 		    current_chip);
386*0Sstevel@tonic-gate 		return (DDI_FAILURE);
387*0Sstevel@tonic-gate 	}
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	tmpzs = zs->zs_addr;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	/*
392*0Sstevel@tonic-gate 	 * Non-DDI compliant Sun-Ness specfic call(s)
393*0Sstevel@tonic-gate 	 */
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	/*
396*0Sstevel@tonic-gate 	 * Stop the monitor's polling interrupt.
397*0Sstevel@tonic-gate 	 *
398*0Sstevel@tonic-gate 	 * I know that this is not exactly obvious. On all sunmon PROM
399*0Sstevel@tonic-gate 	 * machines, the PROM has can have a high level periodic clock
400*0Sstevel@tonic-gate 	 * interrupt going at this time. It uses this periodic interrupt
401*0Sstevel@tonic-gate 	 * to poll the console tty or kbd uart to check for things like
402*0Sstevel@tonic-gate 	 * BREAK or L1-A (abort). While we're probing this device out we
403*0Sstevel@tonic-gate 	 * have to shut that off so the PROM won't get confused by what
404*0Sstevel@tonic-gate 	 * we're doing to the zs. This has caused some pretty funny bugs
405*0Sstevel@tonic-gate 	 * in its time.
406*0Sstevel@tonic-gate 	 *
407*0Sstevel@tonic-gate 	 * For OPENPROM machines, the prom  takes level12 interrupts directly,
408*0Sstevel@tonic-gate 	 * but we call this routine anyway (I forget why).
409*0Sstevel@tonic-gate 	 */
410*0Sstevel@tonic-gate 	mon_clock_stop();
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	/*
413*0Sstevel@tonic-gate 	 * Go critical to keep uart from urking.
414*0Sstevel@tonic-gate 	 */
415*0Sstevel@tonic-gate 	s = ddi_enter_critical();
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	/*
418*0Sstevel@tonic-gate 	 * We are about to issue a full reset to this chip.
419*0Sstevel@tonic-gate 	 * First, now that interrupts are blocked, we will delay up to a
420*0Sstevel@tonic-gate 	 * half-second, checking both channels for any stray activity.
421*0Sstevel@tonic-gate 	 * Next we will preserve the time constants from both channels,
422*0Sstevel@tonic-gate 	 * so that they can be restored after the reset.  This is especially
423*0Sstevel@tonic-gate 	 * important for the console device.  Finally, do the reset and
424*0Sstevel@tonic-gate 	 * follow it with an extended recovery while the chip settles down.
425*0Sstevel@tonic-gate 	 */
426*0Sstevel@tonic-gate 	for (loops = 0; loops++ <= 500; DELAY(1000)) {
427*0Sstevel@tonic-gate 		SCC_READA(1, rr);
428*0Sstevel@tonic-gate 		if ((rr & ZSRR1_ALL_SENT) == 0) continue;
429*0Sstevel@tonic-gate 		SCC_READB(1, rr);
430*0Sstevel@tonic-gate 		if ((rr & ZSRR1_ALL_SENT) == 0) continue;
431*0Sstevel@tonic-gate 		SCC_READA(0, rr);
432*0Sstevel@tonic-gate 		if ((rr & ZSRR0_TX_READY) == 0) continue;
433*0Sstevel@tonic-gate 		SCC_READB(0, rr);
434*0Sstevel@tonic-gate 		if ((rr & ZSRR0_TX_READY) != 0) break;
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	SCC_READA(12, speed[0]);
438*0Sstevel@tonic-gate 	SCC_READA(13, rr);
439*0Sstevel@tonic-gate 	speed[0] |= rr << 8;
440*0Sstevel@tonic-gate 	SCC_READB(12, speed[1]);
441*0Sstevel@tonic-gate 	SCC_READB(13, rr);
442*0Sstevel@tonic-gate 	speed[1] |= rr << 8;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	SCC_WRITE(9, ZSWR9_RESET_WORLD);
445*0Sstevel@tonic-gate 	DELAY(10);
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/*
448*0Sstevel@tonic-gate 	 * Set up the other components of the zscom structs for this chip.
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
451*0Sstevel@tonic-gate 		/*
452*0Sstevel@tonic-gate 		 * Property for ignoring DCD.
453*0Sstevel@tonic-gate 		 * We switch between 'a' and 'b' ports for this device.
454*0Sstevel@tonic-gate 		 */
455*0Sstevel@tonic-gate 		static char *prop = "port-a-ignore-cd";
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 		/*
458*0Sstevel@tonic-gate 		 * For this channel, set the hardware address, allocate the
459*0Sstevel@tonic-gate 		 * high-level mutex, and update the zscurr pointer.
460*0Sstevel@tonic-gate 		 * The high-level lock is shared by both channels because
461*0Sstevel@tonic-gate 		 * 8530 register addressing is non-atomic and asymetrical.
462*0Sstevel@tonic-gate 		 * Multiple threads crossing paths during this operation
463*0Sstevel@tonic-gate 		 * could trash the chip, and thus, possibly the system console.
464*0Sstevel@tonic-gate 		 */
465*0Sstevel@tonic-gate 		if (i == 0) {		/* port A */
466*0Sstevel@tonic-gate 			zs->zs_addr = (struct zscc_device *)
467*0Sstevel@tonic-gate 			    ((uintptr_t)tmpzs | ZSOFF);
468*0Sstevel@tonic-gate 			(zs+1)->zs_excl_hi = zs->zs_excl_hi = &zs_curr_lock;
469*0Sstevel@tonic-gate 		} else {		/* port B */
470*0Sstevel@tonic-gate 			zs++;
471*0Sstevel@tonic-gate 			zs->zs_addr = (struct zscc_device *)
472*0Sstevel@tonic-gate 			    ((uintptr_t)tmpzs & ~ZSOFF);
473*0Sstevel@tonic-gate 			zscurr = zs;
474*0Sstevel@tonic-gate 		}
475*0Sstevel@tonic-gate 		zs->zs_unit = current_chip * 2 + i;
476*0Sstevel@tonic-gate 		zs->zs_dip = dev;
477*0Sstevel@tonic-gate 		zs->zs_excl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
478*0Sstevel@tonic-gate 		mutex_init(zs->zs_excl, NULL, MUTEX_DRIVER, (void *)ZS_PL);
479*0Sstevel@tonic-gate 		zs->zs_ocexcl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
480*0Sstevel@tonic-gate 		mutex_init(zs->zs_ocexcl, NULL, MUTEX_DRIVER, (void *)ZS_PL);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 		zsopinit(zs, &zsops_null);
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 		prop[5] = 'a' + i;
485*0Sstevel@tonic-gate 		softcd = GETPROP((dev_info_t *)(dev), prop, 0);
486*0Sstevel@tonic-gate 		zssoftCAR[zs->zs_unit] = softcd;
487*0Sstevel@tonic-gate 		if (softcd)
488*0Sstevel@tonic-gate 			rtsdtr_bits = ZSWR5_RTS | ZSWR5_DTR;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		keyboard_prop = GETPROP((dev_info_t *)(zs->zs_dip),
491*0Sstevel@tonic-gate 		    "keyboard", 0);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 		mutex_enter(&zs_curr_lock);
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		/*
496*0Sstevel@tonic-gate 		 * Set up the default asynch modes
497*0Sstevel@tonic-gate 		 * so the monitor will still work
498*0Sstevel@tonic-gate 		 */
499*0Sstevel@tonic-gate 		SCC_WRITE(4, ZSWR4_PARITY_EVEN | ZSWR4_1_STOP | ZSWR4_X16_CLK);
500*0Sstevel@tonic-gate 		SCC_WRITE(3, ZSWR3_RX_8);
501*0Sstevel@tonic-gate 		SCC_WRITE(11, ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD);
502*0Sstevel@tonic-gate 		SCC_WRITE(12, (speed[i] & 0xff));
503*0Sstevel@tonic-gate 		SCC_WRITE(13, (speed[i] >> 8) & 0xff);
504*0Sstevel@tonic-gate 		SCC_WRITE(14, ZSWR14_BAUD_FROM_PCLK);
505*0Sstevel@tonic-gate 		SCC_WRITE(3, ZSWR3_RX_8 | ZSWR3_RX_ENABLE);
506*0Sstevel@tonic-gate 		SCC_WRITE(5, ZSWR5_TX_ENABLE | ZSWR5_TX_8 | rtsdtr_bits);
507*0Sstevel@tonic-gate 		SCC_WRITE(14, ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK);
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		/*
510*0Sstevel@tonic-gate 		 * The SYNC pin on the second SCC (keyboard & mouse) may not
511*0Sstevel@tonic-gate 		 * be connected and noise creates transitions on this line.
512*0Sstevel@tonic-gate 		 * This floods the system with interrupts, unless the
513*0Sstevel@tonic-gate 		 * Sync/Hunt Interrupt Enable is cleared.  So write
514*0Sstevel@tonic-gate 		 * register 15 with everything we need but that one.
515*0Sstevel@tonic-gate 		 */
516*0Sstevel@tonic-gate 		if (keyboard_prop) {
517*0Sstevel@tonic-gate 			SCC_WRITE(15, ZSR15_BREAK | ZSR15_TX_UNDER |
518*0Sstevel@tonic-gate 			    ZSR15_CTS | ZSR15_CD);
519*0Sstevel@tonic-gate 		}
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_ERRORS);
522*0Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_STATUS);
523*0Sstevel@tonic-gate 		mutex_exit(&zs_curr_lock);
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 		zs->zs_dtrlow = gethrestime_sec() - default_dtrlow;
526*0Sstevel@tonic-gate 		cv_init(&zs->zs_flags_cv, NULL, CV_DEFAULT, NULL);
527*0Sstevel@tonic-gate 		zsa_init(zs);
528*0Sstevel@tonic-gate 	}
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	mutex_enter(&zs_curr_lock);
531*0Sstevel@tonic-gate 	SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT);
532*0Sstevel@tonic-gate 	DELAY(4000);
533*0Sstevel@tonic-gate 	mutex_exit(&zs_curr_lock);
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	/*
536*0Sstevel@tonic-gate 	 * Two levels of interrupt - chip interrupts at a high level (12),
537*0Sstevel@tonic-gate 	 * (which is seen below as zs_high_intr), and then as a secondary
538*0Sstevel@tonic-gate 	 * stage soft interrupt as seen in zsintr below.
539*0Sstevel@tonic-gate 	 *
540*0Sstevel@tonic-gate 	 * Because zs_high_intr does a window save, as well as calls to
541*0Sstevel@tonic-gate 	 * other functions, we cannot install it as a "fast" interrupt
542*0Sstevel@tonic-gate 	 * that would execute right out of the trap window.  Too bad...
543*0Sstevel@tonic-gate 	 */
544*0Sstevel@tonic-gate 	if (ddi_add_intr(dev, (uint_t)0, &zs_hi_iblock,
545*0Sstevel@tonic-gate 	    (ddi_idevice_cookie_t *)0, zs_high_intr,
546*0Sstevel@tonic-gate 	    (caddr_t)0) != DDI_SUCCESS) {
547*0Sstevel@tonic-gate 		cmn_err(CE_PANIC, "cannot set high level zs interrupt");
548*0Sstevel@tonic-gate 		/*NOTREACHED*/
549*0Sstevel@tonic-gate 	}
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	if (zs_addedsoft == 0) {
552*0Sstevel@tonic-gate 		if (ddi_add_softintr(dev, DDI_SOFTINT_HIGH, &zs_softintr_id,
553*0Sstevel@tonic-gate 		    &zs_iblock, (ddi_idevice_cookie_t *)0,
554*0Sstevel@tonic-gate 		    zsintr, (caddr_t)0) != DDI_SUCCESS) {
555*0Sstevel@tonic-gate 			cmn_err(CE_PANIC,
556*0Sstevel@tonic-gate 				"cannot set second stage zs interrupt");
557*0Sstevel@tonic-gate 			/*NOTREACHED*/
558*0Sstevel@tonic-gate 		}
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 		zs_addedsoft++;	/* we only need one zsintr! */
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	if (zs > zslast)
564*0Sstevel@tonic-gate 		zslast = zs;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	(void) ddi_exit_critical(s);
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	/*
569*0Sstevel@tonic-gate 	 * Non-DDI compliant Sun-Ness specific call
570*0Sstevel@tonic-gate 	 */
571*0Sstevel@tonic-gate 	mon_clock_start();	/* re-enable monitor's polling interrupt */
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (!GETPROP(zs->zs_dip, "keyboard", 0)) {
574*0Sstevel@tonic-gate 		static char *serial_line = DDI_NT_SERIAL_MB;
575*0Sstevel@tonic-gate 		static char *dial_out = DDI_NT_SERIAL_MB_DO;
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 		/*
578*0Sstevel@tonic-gate 		 * Export names for channel a or b consconfig match...
579*0Sstevel@tonic-gate 		 * The names exported to the filesystem include the
580*0Sstevel@tonic-gate 		 * designated tty'a' type name and may not match the PROM
581*0Sstevel@tonic-gate 		 * pathname.
582*0Sstevel@tonic-gate 		 * Note the special name "obp-console-name" used in these calls.
583*0Sstevel@tonic-gate 		 * This keeps the ports and devlinks programs from seeing these
584*0Sstevel@tonic-gate 		 * names. (But allows ddi_pathname_to_dev_t to see them.)
585*0Sstevel@tonic-gate 		 * We don't need to do this if the instance number is zero,
586*0Sstevel@tonic-gate 		 * because we'll create them below, in this case.
587*0Sstevel@tonic-gate 		 */
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		if (ddi_get_instance(dev) != 0)  {
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 			/*
592*0Sstevel@tonic-gate 			 * Select a node type unused by ddi/devfs
593*0Sstevel@tonic-gate 			 */
594*0Sstevel@tonic-gate 			static char *obp_type = "obp-console-name";
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 			(void) strcpy(name, "a");
597*0Sstevel@tonic-gate 			if (ddi_create_minor_node(dev, name, S_IFCHR,
598*0Sstevel@tonic-gate 			    ddi_get_instance(dev) * 2,
599*0Sstevel@tonic-gate 			    obp_type, NULL) == DDI_FAILURE) {
600*0Sstevel@tonic-gate 				ddi_remove_minor_node(dev, NULL);
601*0Sstevel@tonic-gate 				return (DDI_FAILURE);
602*0Sstevel@tonic-gate 			}
603*0Sstevel@tonic-gate 			(void) strcpy(name, "b");
604*0Sstevel@tonic-gate 			if (ddi_create_minor_node(dev, name, S_IFCHR,
605*0Sstevel@tonic-gate 			    (ddi_get_instance(dev) * 2) + 1,
606*0Sstevel@tonic-gate 			    obp_type, NULL) == DDI_FAILURE) {
607*0Sstevel@tonic-gate 				ddi_remove_minor_node(dev, NULL);
608*0Sstevel@tonic-gate 				return (DDI_FAILURE);
609*0Sstevel@tonic-gate 			}
610*0Sstevel@tonic-gate 		}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 		/*
613*0Sstevel@tonic-gate 		 * Export normal device names...
614*0Sstevel@tonic-gate 		 */
615*0Sstevel@tonic-gate 		(void) sprintf(name, "%c", (ddi_get_instance(dev) + 'a'));
616*0Sstevel@tonic-gate 		if (ddi_create_minor_node(dev, name, S_IFCHR,
617*0Sstevel@tonic-gate 		    ddi_get_instance(dev) * 2,
618*0Sstevel@tonic-gate 		    serial_line, NULL) == DDI_FAILURE) {
619*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
620*0Sstevel@tonic-gate 			return (DDI_FAILURE);
621*0Sstevel@tonic-gate 		}
622*0Sstevel@tonic-gate 		(void) sprintf(name, "%c", (ddi_get_instance(dev) + 'b'));
623*0Sstevel@tonic-gate 		if (ddi_create_minor_node(dev, name, S_IFCHR,
624*0Sstevel@tonic-gate 		    (ddi_get_instance(dev) * 2) + 1,
625*0Sstevel@tonic-gate 		    serial_line, NULL) == DDI_FAILURE) {
626*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
627*0Sstevel@tonic-gate 			return (DDI_FAILURE);
628*0Sstevel@tonic-gate 		}
629*0Sstevel@tonic-gate 		(void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'a'));
630*0Sstevel@tonic-gate 		if (ddi_create_minor_node(dev, name, S_IFCHR,
631*0Sstevel@tonic-gate 		    (ddi_get_instance(dev) * 2) | OUTLINE,
632*0Sstevel@tonic-gate 		    dial_out, NULL) == DDI_FAILURE) {
633*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
634*0Sstevel@tonic-gate 			return (DDI_FAILURE);
635*0Sstevel@tonic-gate 		}
636*0Sstevel@tonic-gate 		(void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'b'));
637*0Sstevel@tonic-gate 		if (ddi_create_minor_node(dev, name, S_IFCHR,
638*0Sstevel@tonic-gate 		    ((ddi_get_instance(dev)  * 2) + 1) | OUTLINE,
639*0Sstevel@tonic-gate 		    dial_out, NULL) == DDI_FAILURE) {
640*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
641*0Sstevel@tonic-gate 			return (DDI_FAILURE);
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 	} else {
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 		/*
646*0Sstevel@tonic-gate 		 * Create keyboard and mouse nodes which devfs doesn't see
647*0Sstevel@tonic-gate 		 */
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 		/*
650*0Sstevel@tonic-gate 		 * This set of minor nodes is for use with the consconfig_dacf
651*0Sstevel@tonic-gate 		 * module for the sun4u platforms.  (See PSARC/1998/212)
652*0Sstevel@tonic-gate 		 */
653*0Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dev, "keyboard", S_IFCHR,
654*0Sstevel@tonic-gate 		    ddi_get_instance(dev) * 2) == DDI_FAILURE) {
655*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
656*0Sstevel@tonic-gate 			return (DDI_FAILURE);
657*0Sstevel@tonic-gate 		}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dev, "mouse", S_IFCHR,
660*0Sstevel@tonic-gate 		    (ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) {
661*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
662*0Sstevel@tonic-gate 			return (DDI_FAILURE);
663*0Sstevel@tonic-gate 		}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 		/*
666*0Sstevel@tonic-gate 		 * These minor nodes are for use with pre-sun4u platforms.
667*0Sstevel@tonic-gate 		 * Either one set or the other will be opened by consconfig.
668*0Sstevel@tonic-gate 		 */
669*0Sstevel@tonic-gate 		(void) strcpy(name, "a");
670*0Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dev, name, S_IFCHR,
671*0Sstevel@tonic-gate 			ddi_get_instance(dev) * 2) == DDI_FAILURE) {
672*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
673*0Sstevel@tonic-gate 			return (DDI_FAILURE);
674*0Sstevel@tonic-gate 		}
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 		(void) strcpy(name, "b");
677*0Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dev, name, S_IFCHR,
678*0Sstevel@tonic-gate 			(ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) {
679*0Sstevel@tonic-gate 			ddi_remove_minor_node(dev, NULL);
680*0Sstevel@tonic-gate 			return (DDI_FAILURE);
681*0Sstevel@tonic-gate 		}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	ddi_report_dev(dev);
686*0Sstevel@tonic-gate 	/*
687*0Sstevel@tonic-gate 	 * Initialize power management bookkeeping; components are
688*0Sstevel@tonic-gate 	 * created idle.
689*0Sstevel@tonic-gate 	 */
690*0Sstevel@tonic-gate 	if (pm_create_components(dev, 3) == DDI_SUCCESS) {
691*0Sstevel@tonic-gate 		(void) pm_busy_component(dev, 0);
692*0Sstevel@tonic-gate 		pm_set_normal_power(dev, 0, 1);
693*0Sstevel@tonic-gate 		pm_set_normal_power(dev, 1, 1);
694*0Sstevel@tonic-gate 		pm_set_normal_power(dev, 2, 1);
695*0Sstevel@tonic-gate 	} else {
696*0Sstevel@tonic-gate 		return (DDI_FAILURE);
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	(void) sprintf(name, "zsc%d", current_chip);
700*0Sstevel@tonic-gate 	zs->intrstats = kstat_create("zs", current_chip, name, "controller",
701*0Sstevel@tonic-gate 		KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
702*0Sstevel@tonic-gate 	if (zs->intrstats) {
703*0Sstevel@tonic-gate 		kstat_install(zs->intrstats);
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
707*0Sstevel@tonic-gate }
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate static int
710*0Sstevel@tonic-gate zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd)
711*0Sstevel@tonic-gate {
712*0Sstevel@tonic-gate 	struct zscom *zs;
713*0Sstevel@tonic-gate 	int	current_chip = ddi_get_instance(dev);
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	switch (cmd) {
716*0Sstevel@tonic-gate 	case DDI_DETACH:
717*0Sstevel@tonic-gate 		return (DDI_FAILURE);
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	case DDI_SUSPEND:
720*0Sstevel@tonic-gate 		zs = &zscom[current_chip*2];
721*0Sstevel@tonic-gate 		/*
722*0Sstevel@tonic-gate 		 * Try to suspend first channel
723*0Sstevel@tonic-gate 		 */
724*0Sstevel@tonic-gate 		if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS)
725*0Sstevel@tonic-gate 			return (DDI_FAILURE);
726*0Sstevel@tonic-gate 		/*
727*0Sstevel@tonic-gate 		 * And the second channel
728*0Sstevel@tonic-gate 		 */
729*0Sstevel@tonic-gate 		zs++;
730*0Sstevel@tonic-gate 		if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS) {
731*0Sstevel@tonic-gate 			zs--;
732*0Sstevel@tonic-gate 			if (!zs->zs_resume ||
733*0Sstevel@tonic-gate 			    (zs->zs_resume)(zs) != DDI_SUCCESS)
734*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
735*0Sstevel@tonic-gate 				    "zs: inconsistent suspend/resume state");
736*0Sstevel@tonic-gate 			return (DDI_FAILURE);
737*0Sstevel@tonic-gate 		}
738*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	default:
741*0Sstevel@tonic-gate 		return (DDI_FAILURE);
742*0Sstevel@tonic-gate 	}
743*0Sstevel@tonic-gate }
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate /*
746*0Sstevel@tonic-gate  * SCC High Level Interrupt Handler
747*0Sstevel@tonic-gate  *
748*0Sstevel@tonic-gate  * This routine fields the level 12 interrupts generated by the 8530 chips.
749*0Sstevel@tonic-gate  * When the SCC interrupts the conditions that triggered it are available
750*0Sstevel@tonic-gate  * for reference in Read Register 3 of the A channel (RR3A).  We process
751*0Sstevel@tonic-gate  * all the pending interrupts before returning.  The maximum interrupts
752*0Sstevel@tonic-gate  * that will be processed before returning is set to 6, which is twice
753*0Sstevel@tonic-gate  * the size of RX-FIFO.
754*0Sstevel@tonic-gate  * We keep a pointer to the B side of the most recently interrupting chip
755*0Sstevel@tonic-gate  * in zscurr.
756*0Sstevel@tonic-gate  */
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate /*
759*0Sstevel@tonic-gate  * 'argzs' actually 'struct zscom *argzs'
760*0Sstevel@tonic-gate  */
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate #define	ZSRR3_INT_PENDING (ZSRR3_IP_B_STAT | ZSRR3_IP_B_TX | ZSRR3_IP_B_RX |\
763*0Sstevel@tonic-gate 			ZSRR3_IP_A_STAT | ZSRR3_IP_A_TX | ZSRR3_IP_A_RX)
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate #define	ZSRR1_ANY_ERRORS (ZSRR1_PE | ZSRR1_DO | ZSRR1_FE | ZSRR1_RXEOF)
766*0Sstevel@tonic-gate #define	ZS_HIGH_INTR_LOOPLIMIT 6
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate /*ARGSUSED*/
769*0Sstevel@tonic-gate uint_t
770*0Sstevel@tonic-gate zs_high_intr(caddr_t argzs)
771*0Sstevel@tonic-gate {
772*0Sstevel@tonic-gate 	struct zscom	*zs;
773*0Sstevel@tonic-gate 	uchar_t	stat, isource, count;
774*0Sstevel@tonic-gate 	int		unit;
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_START, "zs_h_int start");
777*0Sstevel@tonic-gate 	mutex_enter(&zs_curr_lock);
778*0Sstevel@tonic-gate 	zs = zscurr;				/* Points at Channel B */
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	ZSNEXTPOLL(zs, zscurr);
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	SCC_READA(3, isource);
783*0Sstevel@tonic-gate start_zs_h:
784*0Sstevel@tonic-gate 	count = ZS_HIGH_INTR_LOOPLIMIT;
785*0Sstevel@tonic-gate 	while ((isource & ZSRR3_INT_PENDING) && (count--)) {
786*0Sstevel@tonic-gate 		if (isource & ZSRR3_IP_B_STAT)
787*0Sstevel@tonic-gate 			(zs->zs_xsint)(zs);
788*0Sstevel@tonic-gate 		else {
789*0Sstevel@tonic-gate 			if (isource & ZSRR3_IP_B_TX)
790*0Sstevel@tonic-gate 				(zs->zs_txint)(zs);
791*0Sstevel@tonic-gate 			if (isource & ZSRR3_IP_B_RX) {
792*0Sstevel@tonic-gate 				SCC_READ(1, stat);
793*0Sstevel@tonic-gate 				if (stat & ZSRR1_ANY_ERRORS)
794*0Sstevel@tonic-gate 					(zs->zs_srint)(zs);
795*0Sstevel@tonic-gate 				else if ((SCC_READ0()) & ZSRR0_RX_READY)
796*0Sstevel@tonic-gate 					(zs->zs_rxint)(zs);
797*0Sstevel@tonic-gate 			}
798*0Sstevel@tonic-gate 		}
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 		zs -= 1;
801*0Sstevel@tonic-gate 		if (isource & ZSRR3_IP_A_STAT)
802*0Sstevel@tonic-gate 			(zs->zs_xsint)(zs);
803*0Sstevel@tonic-gate 		else {
804*0Sstevel@tonic-gate 			if (isource & ZSRR3_IP_A_TX)
805*0Sstevel@tonic-gate 				(zs->zs_txint)(zs);
806*0Sstevel@tonic-gate 			if (isource & ZSRR3_IP_A_RX) {
807*0Sstevel@tonic-gate 				SCC_READ(1, stat);
808*0Sstevel@tonic-gate 				if (stat & ZSRR1_ANY_ERRORS)
809*0Sstevel@tonic-gate 					(zs->zs_srint)(zs);
810*0Sstevel@tonic-gate 				else if ((SCC_READ0()) & ZSRR0_RX_READY)
811*0Sstevel@tonic-gate 					(zs->zs_rxint)(zs);
812*0Sstevel@tonic-gate 			}
813*0Sstevel@tonic-gate 		}
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 		zs = zscurr;
816*0Sstevel@tonic-gate 		SCC_READA(3, isource);
817*0Sstevel@tonic-gate 	}
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	if (count == ZS_HIGH_INTR_LOOPLIMIT) {
820*0Sstevel@tonic-gate 		unit = (nzs >> 1) - 1;
821*0Sstevel@tonic-gate 		while (unit--) {
822*0Sstevel@tonic-gate 			zs += 2;	/* Always Channel B */
823*0Sstevel@tonic-gate 			if (zs > zslast)
824*0Sstevel@tonic-gate 				zs = &zscom[1];
825*0Sstevel@tonic-gate 			if (!zs->zs_ops)
826*0Sstevel@tonic-gate 				continue;
827*0Sstevel@tonic-gate 			SCC_READA(3, isource);
828*0Sstevel@tonic-gate 			if (isource & ZSRR3_INT_PENDING) {
829*0Sstevel@tonic-gate 				zscurr = zs;	/* update zscurr and */
830*0Sstevel@tonic-gate 				goto start_zs_h;
831*0Sstevel@tonic-gate 			}
832*0Sstevel@tonic-gate 		}
833*0Sstevel@tonic-gate 		if (zs->intrstats) {
834*0Sstevel@tonic-gate 			KIOIP->intrs[KSTAT_INTR_HARD]++;
835*0Sstevel@tonic-gate 		}
836*0Sstevel@tonic-gate 		mutex_exit(&zs_curr_lock);
837*0Sstevel@tonic-gate 		TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end");
838*0Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);	/* Must not be for us. */
839*0Sstevel@tonic-gate 	}
840*0Sstevel@tonic-gate 	if (zs->intrstats) {
841*0Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_HARD]++;
842*0Sstevel@tonic-gate 	}
843*0Sstevel@tonic-gate 	mutex_exit(&zs_curr_lock);	/* we're done with zscurr */
844*0Sstevel@tonic-gate 	TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end");
845*0Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
846*0Sstevel@tonic-gate }
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate /*
849*0Sstevel@tonic-gate  * Handle a second-stage interrupt.
850*0Sstevel@tonic-gate  */
851*0Sstevel@tonic-gate /*ARGSUSED*/
852*0Sstevel@tonic-gate uint_t
853*0Sstevel@tonic-gate zsintr(caddr_t intarg)
854*0Sstevel@tonic-gate {
855*0Sstevel@tonic-gate 	struct zscom *zs;
856*0Sstevel@tonic-gate 	int    rv;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	/*
859*0Sstevel@tonic-gate 	 * Test and clear soft interrupt.
860*0Sstevel@tonic-gate 	 */
861*0Sstevel@tonic-gate 	TRACE_0(TR_FAC_ZS, TR_ZS_INT_START,
862*0Sstevel@tonic-gate 	    "zs_int start");
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 	mutex_enter(&zs_curr_lock);
865*0Sstevel@tonic-gate 	rv = zssoftpend;
866*0Sstevel@tonic-gate 	if (rv != 0) {
867*0Sstevel@tonic-gate 		zssoftpend = 0;
868*0Sstevel@tonic-gate 	}
869*0Sstevel@tonic-gate 	mutex_exit(&zs_curr_lock);
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	if (rv) {
872*0Sstevel@tonic-gate 		for (zs = &zscom[0]; zs <= zslast; zs++) {
873*0Sstevel@tonic-gate 			if (zs->zs_flags & ZS_NEEDSOFT) {
874*0Sstevel@tonic-gate 				zs->zs_flags &= ~ZS_NEEDSOFT;
875*0Sstevel@tonic-gate 				(*zs->zs_ops->zsop_softint)(zs);
876*0Sstevel@tonic-gate 				if (zs->intrstats) {
877*0Sstevel@tonic-gate 					KIOIP->intrs[KSTAT_INTR_SOFT]++;
878*0Sstevel@tonic-gate 				}
879*0Sstevel@tonic-gate 			}
880*0Sstevel@tonic-gate 		}
881*0Sstevel@tonic-gate 	}
882*0Sstevel@tonic-gate 	TRACE_0(TR_FAC_ZS, TR_ZS_INT_END,
883*0Sstevel@tonic-gate 	    "zs_int end");
884*0Sstevel@tonic-gate 	return (rv);
885*0Sstevel@tonic-gate }
886*0Sstevel@tonic-gate 
887*0Sstevel@tonic-gate void
888*0Sstevel@tonic-gate setzssoft(void)
889*0Sstevel@tonic-gate {
890*0Sstevel@tonic-gate 	ddi_trigger_softintr(zs_softintr_id);
891*0Sstevel@tonic-gate }
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate /*
894*0Sstevel@tonic-gate  * Install a new ops vector into low level vector routine addresses
895*0Sstevel@tonic-gate  */
896*0Sstevel@tonic-gate void
897*0Sstevel@tonic-gate zsopinit(struct zscom *zs, struct zsops *zso)
898*0Sstevel@tonic-gate {
899*0Sstevel@tonic-gate 	zs->zs_txint	= zso->zsop_txint;
900*0Sstevel@tonic-gate 	zs->zs_xsint	= zso->zsop_xsint;
901*0Sstevel@tonic-gate 	zs->zs_rxint	= zso->zsop_rxint;
902*0Sstevel@tonic-gate 	zs->zs_srint	= zso->zsop_srint;
903*0Sstevel@tonic-gate 	zs->zs_suspend	= zso->zsop_suspend;
904*0Sstevel@tonic-gate 	zs->zs_resume	= zso->zsop_resume;
905*0Sstevel@tonic-gate 	zs->zs_ops	= zso;
906*0Sstevel@tonic-gate 	zs->zs_flags	= 0;
907*0Sstevel@tonic-gate }
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate /*
910*0Sstevel@tonic-gate  * Set or get the modem control status.
911*0Sstevel@tonic-gate  *
912*0Sstevel@tonic-gate  * This routine relies on the fact that the bits of interest in RR0 (CD and
913*0Sstevel@tonic-gate  * CTS) do not overlap the bits of interest in WR5 (RTS and DTR).  Thus, they
914*0Sstevel@tonic-gate  * can be combined into a single 'int' without harm.
915*0Sstevel@tonic-gate  */
916*0Sstevel@tonic-gate int
917*0Sstevel@tonic-gate zsmctl(struct zscom *zs, int bits, int how)
918*0Sstevel@tonic-gate {
919*0Sstevel@tonic-gate 	int mbits, obits;
920*0Sstevel@tonic-gate 	time_t now, held;
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	ASSERT(mutex_owned(zs->zs_excl_hi));
923*0Sstevel@tonic-gate 	ASSERT(mutex_owned(zs->zs_excl));
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate again:
926*0Sstevel@tonic-gate 	mbits = zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR);
927*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
928*0Sstevel@tonic-gate 	mbits |= SCC_READ0() & (ZSRR0_CD|ZSRR0_CTS);
929*0Sstevel@tonic-gate 	ZSDELAY();
930*0Sstevel@tonic-gate 	obits = mbits;
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	switch (how) {
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	case DMSET:
935*0Sstevel@tonic-gate 		mbits = bits;
936*0Sstevel@tonic-gate 		break;
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	case DMBIS:
939*0Sstevel@tonic-gate 		mbits |= bits;
940*0Sstevel@tonic-gate 		break;
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	case DMBIC:
943*0Sstevel@tonic-gate 		mbits &= ~bits;
944*0Sstevel@tonic-gate 		break;
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	case DMGET:
947*0Sstevel@tonic-gate 		return (mbits);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	now = gethrestime_sec();
951*0Sstevel@tonic-gate 	held = now - zs->zs_dtrlow;
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	/*
954*0Sstevel@tonic-gate 	 * if DTR is going low, stash current time away
955*0Sstevel@tonic-gate 	 */
956*0Sstevel@tonic-gate 	if (~mbits & obits & ZSWR5_DTR)
957*0Sstevel@tonic-gate 		zs->zs_dtrlow = now;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	/*
960*0Sstevel@tonic-gate 	 * if DTR is going high, sleep until it has been low a bit
961*0Sstevel@tonic-gate 	 */
962*0Sstevel@tonic-gate 	if ((mbits & ~obits & ZSWR5_DTR) && (held < default_dtrlow)) {
963*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
964*0Sstevel@tonic-gate 		cv_wait(&lbolt_cv, zs->zs_excl);
965*0Sstevel@tonic-gate 		if (zs->zs_suspended)
966*0Sstevel@tonic-gate 			(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
967*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
968*0Sstevel@tonic-gate 		goto again;
969*0Sstevel@tonic-gate 	}
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	zs->zs_wreg[5] &= ~(ZSWR5_RTS|ZSWR5_DTR);
972*0Sstevel@tonic-gate 	SCC_BIS(5, mbits & (ZSWR5_RTS|ZSWR5_DTR));
973*0Sstevel@tonic-gate 	return (mbits);
974*0Sstevel@tonic-gate }
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate /*
977*0Sstevel@tonic-gate  * Program the Z8530 registers.
978*0Sstevel@tonic-gate  */
979*0Sstevel@tonic-gate void
980*0Sstevel@tonic-gate zs_program(struct zs_prog *zspp)
981*0Sstevel@tonic-gate {
982*0Sstevel@tonic-gate 	struct zscom *zs = zspp->zs;
983*0Sstevel@tonic-gate 	int	loops;
984*0Sstevel@tonic-gate 	uchar_t	c;
985*0Sstevel@tonic-gate 	uchar_t wr10 = 0, wr14 = 0;
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	ASSERT(mutex_owned(zs->zs_excl));
988*0Sstevel@tonic-gate 	ASSERT(mutex_owned(zs->zs_excl_hi));
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	/*
991*0Sstevel@tonic-gate 	 * There are some special cases to account for before reprogramming.
992*0Sstevel@tonic-gate 	 * We might be transmitting, so delay 100,000 usec (worst case at 110
993*0Sstevel@tonic-gate 	 * baud) for this to finish, then disable the receiver until later,
994*0Sstevel@tonic-gate 	 * reset the External Status Change latches and the error bits, and
995*0Sstevel@tonic-gate 	 * drain the receive FIFO.
996*0Sstevel@tonic-gate 	 * XXX: Doing any kind of reset (WR9) here causes trouble!
997*0Sstevel@tonic-gate 	 */
998*0Sstevel@tonic-gate 	if (zspp->flags & ZSP_SYNC) {
999*0Sstevel@tonic-gate 		SCC_WRITE(7, SDLCFLAG);
1000*0Sstevel@tonic-gate 		wr10 = ZSWR10_PRESET_ONES;
1001*0Sstevel@tonic-gate 		if (zspp->flags & ZSP_NRZI)
1002*0Sstevel@tonic-gate 			wr10 |= ZSWR10_NRZI;
1003*0Sstevel@tonic-gate 		SCC_WRITE(10, wr10);
1004*0Sstevel@tonic-gate 	} else {
1005*0Sstevel@tonic-gate 		for (loops = 1000; loops > 0; --loops) {
1006*0Sstevel@tonic-gate 			SCC_READ(1, c);
1007*0Sstevel@tonic-gate 			if (c & ZSRR1_ALL_SENT)
1008*0Sstevel@tonic-gate 				break;
1009*0Sstevel@tonic-gate 			DELAY(100);
1010*0Sstevel@tonic-gate 		}
1011*0Sstevel@tonic-gate 		SCC_WRITE(3, 0);
1012*0Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_STATUS);
1013*0Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_ERRORS);
1014*0Sstevel@tonic-gate 		c = SCC_READDATA();		/* Empty the FIFO */
1015*0Sstevel@tonic-gate 		c = SCC_READDATA();
1016*0Sstevel@tonic-gate 		c = SCC_READDATA();
1017*0Sstevel@tonic-gate 	}
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	/*
1020*0Sstevel@tonic-gate 	 * Programming the SCC is done in three phases.
1021*0Sstevel@tonic-gate 	 * Phase one sets operating modes:
1022*0Sstevel@tonic-gate 	 */
1023*0Sstevel@tonic-gate 	SCC_WRITE(4, zspp->wr4);
1024*0Sstevel@tonic-gate 	SCC_WRITE(11, zspp->wr11);
1025*0Sstevel@tonic-gate 	SCC_WRITE(12, zspp->wr12);
1026*0Sstevel@tonic-gate 	SCC_WRITE(13, zspp->wr13);
1027*0Sstevel@tonic-gate 	if (zspp->flags & ZSP_PLL) {
1028*0Sstevel@tonic-gate 		SCC_WRITE(14, ZSWR14_DPLL_SRC_BAUD);
1029*0Sstevel@tonic-gate 		SCC_WRITE(14, ZSWR14_DPLL_NRZI);
1030*0Sstevel@tonic-gate 	} else
1031*0Sstevel@tonic-gate 		SCC_WRITE(14, ZSWR14_DPLL_DISABLE);
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 	/*
1034*0Sstevel@tonic-gate 	 * Phase two enables special hardware functions:
1035*0Sstevel@tonic-gate 	 */
1036*0Sstevel@tonic-gate 	wr14 = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA;
1037*0Sstevel@tonic-gate 	if (zspp->flags & ZSP_LOOP)
1038*0Sstevel@tonic-gate 		wr14 |= ZSWR14_LOCAL_LOOPBACK;
1039*0Sstevel@tonic-gate 	if (zspp->flags & ZSP_ECHO)
1040*0Sstevel@tonic-gate 		wr14 |= ZSWR14_AUTO_ECHO;
1041*0Sstevel@tonic-gate 	SCC_WRITE(14, wr14);
1042*0Sstevel@tonic-gate 	SCC_WRITE(3, zspp->wr3);
1043*0Sstevel@tonic-gate 	SCC_WRITE(5, zspp->wr5);
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXCRC);
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	if (zspp->flags & ZSP_PARITY_SPECIAL) {
1048*0Sstevel@tonic-gate 		SCC_WRITE(1, ZSWR1_PARITY_SPECIAL);
1049*0Sstevel@tonic-gate 	} else {
1050*0Sstevel@tonic-gate 		SCC_WRITE(1, 0);
1051*0Sstevel@tonic-gate 	}
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 	/*
1054*0Sstevel@tonic-gate 	 * Phase three enables interrupt sources:
1055*0Sstevel@tonic-gate 	 */
1056*0Sstevel@tonic-gate 	SCC_WRITE(15, zspp->wr15);
1057*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
1058*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
1059*0Sstevel@tonic-gate 	SCC_BIS(1, ZSWR1_INIT);
1060*0Sstevel@tonic-gate }
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate static void
1063*0Sstevel@tonic-gate zsnull_intr(struct zscom *zs)
1064*0Sstevel@tonic-gate {
1065*0Sstevel@tonic-gate 	short	c;
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXINT);
1068*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
1069*0Sstevel@tonic-gate 	c = SCC_READDATA();
1070*0Sstevel@tonic-gate 	ZSDELAY();
1071*0Sstevel@tonic-gate #ifdef lint
1072*0Sstevel@tonic-gate 	c = c;
1073*0Sstevel@tonic-gate #endif /* lint */
1074*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
1075*0Sstevel@tonic-gate }
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate static int
1078*0Sstevel@tonic-gate zsnull_softint(struct zscom *zs)
1079*0Sstevel@tonic-gate {
1080*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "zs%d: unexpected soft int\n", zs->zs_unit);
1081*0Sstevel@tonic-gate 	return (0);
1082*0Sstevel@tonic-gate }
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate /*
1085*0Sstevel@tonic-gate  * These will be called on suspend/resume for un-opened zs ports.
1086*0Sstevel@tonic-gate  */
1087*0Sstevel@tonic-gate static int
1088*0Sstevel@tonic-gate zsnull_suspend(struct zscom *zs)
1089*0Sstevel@tonic-gate {
1090*0Sstevel@tonic-gate 	struct zs_prog	*zspp = &zs_prog[zs->zs_unit];
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	/*
1093*0Sstevel@tonic-gate 	 * Get a copy of the current registers
1094*0Sstevel@tonic-gate 	 */
1095*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
1096*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
1097*0Sstevel@tonic-gate 	zspp->zs = zs;
1098*0Sstevel@tonic-gate 	zspp->flags = 0;
1099*0Sstevel@tonic-gate 	zspp->wr3 = zs->zs_wreg[3];
1100*0Sstevel@tonic-gate 	zspp->wr4 = zs->zs_wreg[4];
1101*0Sstevel@tonic-gate 	zspp->wr5 = zs->zs_wreg[5];
1102*0Sstevel@tonic-gate 	zspp->wr11 = zs->zs_wreg[11];
1103*0Sstevel@tonic-gate 	zspp->wr12 = zs->zs_wreg[12];
1104*0Sstevel@tonic-gate 	zspp->wr13 = zs->zs_wreg[13];
1105*0Sstevel@tonic-gate 	zspp->wr15 = zs->zs_wreg[15];
1106*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
1107*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1110*0Sstevel@tonic-gate }
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate static int
1113*0Sstevel@tonic-gate zsnull_resume(struct zscom *zs)
1114*0Sstevel@tonic-gate {
1115*0Sstevel@tonic-gate 	struct zs_prog	*zspp = &zs_prog[zs->zs_unit];
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate 	/*
1118*0Sstevel@tonic-gate 	 * Restore registers
1119*0Sstevel@tonic-gate 	 */
1120*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
1121*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
1122*0Sstevel@tonic-gate 	zs_program(zspp);
1123*0Sstevel@tonic-gate 	SCC_WRITE(9, ZSWR9_MASTER_IE);
1124*0Sstevel@tonic-gate 	DELAY(4000);
1125*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
1126*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
1127*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1128*0Sstevel@tonic-gate }
1129