xref: /onnv-gate/usr/src/uts/sun/io/ttymux/ttymux.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 2001-2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * DESCRIPTION
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * ttymux - Multiplexer driver for multiplexing termio compliant streams onto
33*0Sstevel@tonic-gate  * a single upper stream.
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  * ADD2FRONT macro can be used to specify the order in which a console
36*0Sstevel@tonic-gate  * device is put in the queue of multiplexed physical serial devices,
37*0Sstevel@tonic-gate  * during the association and disassociation of a console interface.
38*0Sstevel@tonic-gate  * When this macro is defined, the device is placed in front of the queue,
39*0Sstevel@tonic-gate  * otherwise by default it is placed at the end.
40*0Sstevel@tonic-gate  * Console I/O happens to each of the physical devices in the order of
41*0Sstevel@tonic-gate  * their position in this queue.
42*0Sstevel@tonic-gate  */
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #include <sys/types.h>
45*0Sstevel@tonic-gate #include <sys/file.h>
46*0Sstevel@tonic-gate #include <sys/stream.h>
47*0Sstevel@tonic-gate #include <sys/strsubr.h>
48*0Sstevel@tonic-gate #include <sys/strlog.h>
49*0Sstevel@tonic-gate #include <sys/strsun.h>
50*0Sstevel@tonic-gate #include <sys/modctl.h>
51*0Sstevel@tonic-gate #include <sys/debug.h>
52*0Sstevel@tonic-gate #include <sys/kbio.h>
53*0Sstevel@tonic-gate #include <sys/devops.h>
54*0Sstevel@tonic-gate #include <sys/errno.h>
55*0Sstevel@tonic-gate #include <sys/stat.h>
56*0Sstevel@tonic-gate #include <sys/kmem.h>
57*0Sstevel@tonic-gate #include <sys/ddi.h>
58*0Sstevel@tonic-gate #include <sys/consdev.h>
59*0Sstevel@tonic-gate #include <sys/tty.h>
60*0Sstevel@tonic-gate #include <sys/ptyvar.h>
61*0Sstevel@tonic-gate #include <sys/termio.h>
62*0Sstevel@tonic-gate #include <sys/fcntl.h>
63*0Sstevel@tonic-gate #include <sys/mkdev.h>
64*0Sstevel@tonic-gate #include <sys/ser_sync.h>
65*0Sstevel@tonic-gate #include <sys/esunddi.h>
66*0Sstevel@tonic-gate #include <sys/policy.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate #include <sys/ttymux.h>
69*0Sstevel@tonic-gate #include "ttymux_impl.h"
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /*
72*0Sstevel@tonic-gate  * Extern declarations
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate extern mblk_t *mkiocb(uint_t);
75*0Sstevel@tonic-gate extern int nulldev();
76*0Sstevel@tonic-gate extern uintptr_t space_fetch(char *key);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate extern int sm_ioctl_cmd(sm_uqi_t *, mblk_t *);
79*0Sstevel@tonic-gate extern int ttymux_abort_ioctl(mblk_t *);
80*0Sstevel@tonic-gate extern int ttymux_device_fini(sm_lqi_t *);
81*0Sstevel@tonic-gate extern int ttymux_device_init(sm_lqi_t *);
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /*
84*0Sstevel@tonic-gate  * Exported interfaces
85*0Sstevel@tonic-gate  */
86*0Sstevel@tonic-gate int sm_disassociate(int, sm_lqi_t *, ulong_t);
87*0Sstevel@tonic-gate int sm_associate(int, sm_lqi_t *, ulong_t, uint_t, char *);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * Variables defined here and visible only internally
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate sm_ss_t		*sm_ssp = 0;
93*0Sstevel@tonic-gate static int	sm_instance = 0;
94*0Sstevel@tonic-gate static int	smctlunit;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static uint_t	sm_default_trflag = 0;
97*0Sstevel@tonic-gate uint_t		sm_max_units = 6;
98*0Sstevel@tonic-gate uint_t		sm_minor_cnt = 0;
99*0Sstevel@tonic-gate static uint_t	sm_refuse_opens = 0;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /*
102*0Sstevel@tonic-gate  * Local definitions.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate /* force these flags to be unset on console devices */
106*0Sstevel@tonic-gate static ulong_t	sm_cmask = (ulong_t)(CRTSXOFF|CRTSCTS);
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate /*
109*0Sstevel@tonic-gate  * SECTION
110*0Sstevel@tonic-gate  * Implementation Section:
111*0Sstevel@tonic-gate  */
112*0Sstevel@tonic-gate void
113*0Sstevel@tonic-gate sm_debug(char *msg, ...)
114*0Sstevel@tonic-gate {
115*0Sstevel@tonic-gate 	va_list	args;
116*0Sstevel@tonic-gate 	char	buf[256];
117*0Sstevel@tonic-gate 	int	sz;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	va_start(args, msg);
120*0Sstevel@tonic-gate 	sz = vsnprintf(buf, sizeof (buf), msg, args);
121*0Sstevel@tonic-gate 	va_end(args);
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (sz < 0)
124*0Sstevel@tonic-gate 		(void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1,
125*0Sstevel@tonic-gate 		    SL_TRACE, "vsnprintf parse error\n");
126*0Sstevel@tonic-gate 	else if (sz > sizeof (buf)) {
127*0Sstevel@tonic-gate 		char *b;
128*0Sstevel@tonic-gate 		size_t	len = sz + 1;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 		b = kmem_alloc(len, KM_SLEEP);
131*0Sstevel@tonic-gate 		va_start(args, msg);
132*0Sstevel@tonic-gate 		sz = vsnprintf(b, len, msg, args);
133*0Sstevel@tonic-gate 		va_end(args);
134*0Sstevel@tonic-gate 		if (sz > 0)
135*0Sstevel@tonic-gate 			(void) strlog(ddi_driver_major(sm_ssp->sm_dip),
136*0Sstevel@tonic-gate 			    sm_instance, 1, SL_TRACE, b);
137*0Sstevel@tonic-gate 		kmem_free(b, len);
138*0Sstevel@tonic-gate 	} else {
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 		(void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance,
141*0Sstevel@tonic-gate 		    1, SL_TRACE, buf);
142*0Sstevel@tonic-gate 	}
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate void
146*0Sstevel@tonic-gate sm_log(char *msg, ...)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	va_list	args;
149*0Sstevel@tonic-gate 	char	buf[128];
150*0Sstevel@tonic-gate 	int	sz;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	va_start(args, msg);
153*0Sstevel@tonic-gate 	sz = vsnprintf(buf, sizeof (buf), msg, args);
154*0Sstevel@tonic-gate 	va_end(args);
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	if (sz < 0)
157*0Sstevel@tonic-gate 		(void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1,
158*0Sstevel@tonic-gate 		    SL_TRACE, "vsnprintf parse error\n");
159*0Sstevel@tonic-gate 	else if (sz > sizeof (buf)) {
160*0Sstevel@tonic-gate 		char *b;
161*0Sstevel@tonic-gate 		size_t	len = sz + 1;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		b = kmem_alloc(len, KM_SLEEP);
164*0Sstevel@tonic-gate 		va_start(args, msg);
165*0Sstevel@tonic-gate 		sz = vsnprintf(b, len, msg, args);
166*0Sstevel@tonic-gate 		va_end(args);
167*0Sstevel@tonic-gate 		if (sz > 0)
168*0Sstevel@tonic-gate 			(void) strlog(ddi_driver_major(sm_ssp->sm_dip),
169*0Sstevel@tonic-gate 			    sm_instance, 1, SL_NOTE, b);
170*0Sstevel@tonic-gate 		kmem_free(b, len);
171*0Sstevel@tonic-gate 	} else {
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 		(void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance,
174*0Sstevel@tonic-gate 		    1, SL_NOTE, buf);
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate /*
179*0Sstevel@tonic-gate  * Should only be called if the caller can guarantee that the vnode
180*0Sstevel@tonic-gate  * and/or the stream won't disappear while finding the dip.
181*0Sstevel@tonic-gate  * This routine is only called during an I_PLINK request so it's safe.
182*0Sstevel@tonic-gate  * The routine obtains the dev_t for a linked se stream.
183*0Sstevel@tonic-gate  */
184*0Sstevel@tonic-gate static void
185*0Sstevel@tonic-gate sm_setdip(queue_t *q, sm_lqi_t *lqi)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	lqi->sm_dev = q && STREAM(q) ? STREAM(q)->sd_vnode->v_rdev : NODEV;
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate /*
191*0Sstevel@tonic-gate  * Called from driver close, state change reports and I_PUNLINK ioctl.
192*0Sstevel@tonic-gate  * A lower stream has been unlinked - clean up the state associated with it.
193*0Sstevel@tonic-gate  */
194*0Sstevel@tonic-gate void
195*0Sstevel@tonic-gate sm_lqifree(sm_lqi_t *lqi)
196*0Sstevel@tonic-gate {
197*0Sstevel@tonic-gate 	int mu_owned;
198*0Sstevel@tonic-gate 	sm_lqi_t **pplqi;
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	ASSERT(mutex_owned(lqi->sm_umutex));
201*0Sstevel@tonic-gate 	ASSERT(SM_RQ(lqi) != 0);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/*
204*0Sstevel@tonic-gate 	 * Clear all state associated with this lower queue except
205*0Sstevel@tonic-gate 	 * the identity of the queues themselves and the link id which
206*0Sstevel@tonic-gate 	 * can only be cleared by issuing a streams I_PUNLINK ioctl.
207*0Sstevel@tonic-gate 	 *
208*0Sstevel@tonic-gate 	 * The association of a lower queue is a two step process:
209*0Sstevel@tonic-gate 	 * 1. initialise the lower q data structure on I_PLINK
210*0Sstevel@tonic-gate 	 * 2. associate an upper q with the lower q on SM_CMD_ASSOCIATE.
211*0Sstevel@tonic-gate 	 *
212*0Sstevel@tonic-gate 	 * If step 2 has ocurred then
213*0Sstevel@tonic-gate 	 * remove this lower queue info from the logical unit.
214*0Sstevel@tonic-gate 	 */
215*0Sstevel@tonic-gate 	if (lqi->sm_uqi) {
216*0Sstevel@tonic-gate 		sm_dbg('Y', ("lqifree unit %d, ", lqi->sm_uqi->sm_lunit));
217*0Sstevel@tonic-gate 		if ((mu_owned = mutex_owned(lqi->sm_uqi->sm_umutex)) == 0)
218*0Sstevel@tonic-gate 			LOCK_UNIT(lqi->sm_uqi);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		pplqi = &lqi->sm_uqi->sm_lqs;
221*0Sstevel@tonic-gate 		while (*pplqi != lqi) {
222*0Sstevel@tonic-gate 			ASSERT(*pplqi);
223*0Sstevel@tonic-gate 			pplqi = &((*pplqi)->sm_nlqi);
224*0Sstevel@tonic-gate 		}
225*0Sstevel@tonic-gate 		*pplqi = lqi->sm_nlqi;
226*0Sstevel@tonic-gate 		lqi->sm_uqi->sm_nlqs--;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 		if (mu_owned == 0)
229*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi->sm_uqi);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		lqi->sm_uqi = 0;
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate /*
236*0Sstevel@tonic-gate  * Given a q return the associated lower queue data structure or NULL.
237*0Sstevel@tonic-gate  * Return the data locked.
238*0Sstevel@tonic-gate  */
239*0Sstevel@tonic-gate static sm_lqi_t *
240*0Sstevel@tonic-gate get_lqi_byq(queue_t *q)
241*0Sstevel@tonic-gate {
242*0Sstevel@tonic-gate 	int i;
243*0Sstevel@tonic-gate 	sm_lqi_t *lqi, *flqi = 0;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	for (i = 0; i < MAX_LQS; i++) {
246*0Sstevel@tonic-gate 		lqi = &sm_ssp->sm_lqs[i];
247*0Sstevel@tonic-gate 		LOCK_UNIT(lqi);
248*0Sstevel@tonic-gate 		if (flqi == 0 && lqi->sm_linkid == 0) /* assumes muxids != 0 */
249*0Sstevel@tonic-gate 			flqi = lqi;
250*0Sstevel@tonic-gate 		else if (SM_RQ(lqi) == q || SM_WQ(lqi) == q) {
251*0Sstevel@tonic-gate 			if (flqi)
252*0Sstevel@tonic-gate 				UNLOCK_UNIT(flqi);
253*0Sstevel@tonic-gate 			return (lqi);
254*0Sstevel@tonic-gate 		}
255*0Sstevel@tonic-gate 		else
256*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 	return (flqi);
259*0Sstevel@tonic-gate }
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate /*
262*0Sstevel@tonic-gate  * Given a streams link identifier return the associated lower queue data
263*0Sstevel@tonic-gate  * structure or NULL.
264*0Sstevel@tonic-gate  */
265*0Sstevel@tonic-gate sm_lqi_t *
266*0Sstevel@tonic-gate get_lqi_byid(int linkid)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	int i;
269*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	if (linkid == 0)
272*0Sstevel@tonic-gate 		return (NULL);
273*0Sstevel@tonic-gate 	for (i = 0; i < MAX_LQS; i++) {
274*0Sstevel@tonic-gate 		lqi = &sm_ssp->sm_lqs[i];
275*0Sstevel@tonic-gate 		if (lqi->sm_linkid == linkid)
276*0Sstevel@tonic-gate 			return (lqi);
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 	return (NULL);
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate /*
282*0Sstevel@tonic-gate  * Given a dev_t for a lower stream return the associated lower queue data
283*0Sstevel@tonic-gate  * structure or NULL.
284*0Sstevel@tonic-gate  */
285*0Sstevel@tonic-gate sm_lqi_t *
286*0Sstevel@tonic-gate get_lqi_bydevt(dev_t dev)
287*0Sstevel@tonic-gate {
288*0Sstevel@tonic-gate 	int i;
289*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (dev == NODEV)
292*0Sstevel@tonic-gate 		return (NULL);
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	for (i = 0; i < MAX_LQS; i++) {
295*0Sstevel@tonic-gate 		lqi = &sm_ssp->sm_lqs[i];
296*0Sstevel@tonic-gate 		if (lqi->sm_dev == dev)
297*0Sstevel@tonic-gate 			return (lqi);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	return (NULL);
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate /*
303*0Sstevel@tonic-gate  * Determine whether the input flag is set on at least
304*0Sstevel@tonic-gate  * howmany queues.
305*0Sstevel@tonic-gate  */
306*0Sstevel@tonic-gate static int
307*0Sstevel@tonic-gate sm_is_flag_set(sm_uqi_t *uqi, uint_t flag, uint_t howmany)
308*0Sstevel@tonic-gate {
309*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	if (howmany == 0)
312*0Sstevel@tonic-gate 		return (0);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) {
315*0Sstevel@tonic-gate 		if (lqi->sm_flags & flag)
316*0Sstevel@tonic-gate 			if (--howmany == 0)
317*0Sstevel@tonic-gate 				return (1);
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 	return (0);
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate /*
323*0Sstevel@tonic-gate  * How many usable queues are associated with a given upper stream
324*0Sstevel@tonic-gate  */
325*0Sstevel@tonic-gate static int
326*0Sstevel@tonic-gate sm_uwq_error(sm_uqi_t *uqi)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	return (sm_is_flag_set(uqi, (WERROR_MODE|HANGUP_MODE), uqi->sm_nlqs));
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate /*
332*0Sstevel@tonic-gate  * How many of the queues associated with a given upper stream
333*0Sstevel@tonic-gate  * - do not - have the given flags set.
334*0Sstevel@tonic-gate  */
335*0Sstevel@tonic-gate static int
336*0Sstevel@tonic-gate sm_q_count(sm_uqi_t *uqi, uint_t flag)
337*0Sstevel@tonic-gate {
338*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
339*0Sstevel@tonic-gate 	int count = 0;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) {
342*0Sstevel@tonic-gate 		if ((lqi->sm_flags & flag) == 0)
343*0Sstevel@tonic-gate 			count++;
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate 	return (count);
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate /*
349*0Sstevel@tonic-gate  * How many of the queues associated with a given upper stream
350*0Sstevel@tonic-gate  * - do not - have the given flags set.
351*0Sstevel@tonic-gate  */
352*0Sstevel@tonic-gate static int
353*0Sstevel@tonic-gate sm_qs_without(sm_uqi_t *uqi, uint_t flag, uint_t ioflag)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
356*0Sstevel@tonic-gate 	int count = 0;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) {
359*0Sstevel@tonic-gate 		if ((lqi->sm_flags & flag) == 0 &&
360*0Sstevel@tonic-gate 			(lqi->sm_ioflag & ioflag) == 0)
361*0Sstevel@tonic-gate 			count++;
362*0Sstevel@tonic-gate 	}
363*0Sstevel@tonic-gate 	return (count);
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate /*
367*0Sstevel@tonic-gate  * How many usable queues are associated with a given upper stream
368*0Sstevel@tonic-gate  */
369*0Sstevel@tonic-gate static int
370*0Sstevel@tonic-gate sm_good_qs(sm_uqi_t *uqi)
371*0Sstevel@tonic-gate {
372*0Sstevel@tonic-gate 	return (sm_q_count(uqi, (WERROR_MODE|HANGUP_MODE)));
373*0Sstevel@tonic-gate }
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate static int
376*0Sstevel@tonic-gate sm_cnt_oqs(sm_uqi_t *uqi)
377*0Sstevel@tonic-gate {
378*0Sstevel@tonic-gate 	return (sm_qs_without(uqi, (WERROR_MODE|HANGUP_MODE),
379*0Sstevel@tonic-gate 		(uint_t)FOROUTPUT));
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate /*
383*0Sstevel@tonic-gate  * Send an ioctl downstream and remember that it was sent so that
384*0Sstevel@tonic-gate  * its response can be caught on the way back up.
385*0Sstevel@tonic-gate  */
386*0Sstevel@tonic-gate static void
387*0Sstevel@tonic-gate sm_issue_ioctl(void *arg)
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate 	sm_lqi_t *lqi = arg;
390*0Sstevel@tonic-gate 	uint_t cmdflag = 0;
391*0Sstevel@tonic-gate 	queue_t *q = SM_WQ(lqi);
392*0Sstevel@tonic-gate 	int iocmd, size;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	LOCK_UNIT(lqi);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	lqi->sm_bid = 0;
397*0Sstevel@tonic-gate 	if ((lqi->sm_flags & (WERROR_MODE|HANGUP_MODE)) == 0 &&
398*0Sstevel@tonic-gate 		(lqi->sm_flags & (WANT_CDSTAT|WANT_TCSET))) {
399*0Sstevel@tonic-gate 		mblk_t *pioc;
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 		if (lqi->sm_flags & WANT_TCSET) {
402*0Sstevel@tonic-gate 			lqi->sm_flags &= ~WANT_TCSET;
403*0Sstevel@tonic-gate 			iocmd = TCSETS;
404*0Sstevel@tonic-gate 			cmdflag = WANT_TCSET;
405*0Sstevel@tonic-gate 		} else if (lqi->sm_flags & WANT_SC) {
406*0Sstevel@tonic-gate 			lqi->sm_flags &= ~WANT_SC;
407*0Sstevel@tonic-gate 			iocmd = TIOCGSOFTCAR;
408*0Sstevel@tonic-gate 			cmdflag = WANT_SC;
409*0Sstevel@tonic-gate 		} else if (lqi->sm_flags & WANT_CD) {
410*0Sstevel@tonic-gate 			lqi->sm_flags &= ~WANT_CD;
411*0Sstevel@tonic-gate 			iocmd = TIOCMGET;
412*0Sstevel@tonic-gate 		} else if (lqi->sm_flags & WANT_CL) {
413*0Sstevel@tonic-gate 			lqi->sm_flags &= ~WANT_CL;
414*0Sstevel@tonic-gate 			iocmd = TCGETS;
415*0Sstevel@tonic-gate 			cmdflag = WANT_CL;
416*0Sstevel@tonic-gate 		} else {
417*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
418*0Sstevel@tonic-gate 			return;
419*0Sstevel@tonic-gate 		}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 		if (pioc = mkiocb(iocmd)) {
422*0Sstevel@tonic-gate 			if (cmdflag == WANT_TCSET) {
423*0Sstevel@tonic-gate 				pioc->b_cont =
424*0Sstevel@tonic-gate 				    sm_allocb(sizeof (struct termios),
425*0Sstevel@tonic-gate 				    BPRI_MED);
426*0Sstevel@tonic-gate 				if (pioc->b_cont == 0) {
427*0Sstevel@tonic-gate 					freemsg(pioc);
428*0Sstevel@tonic-gate 					pioc = 0;
429*0Sstevel@tonic-gate 				} else {
430*0Sstevel@tonic-gate 					struct termios *tc = (struct termios *)
431*0Sstevel@tonic-gate 					    pioc->b_cont->b_wptr;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 					bzero((caddr_t)tc,
434*0Sstevel@tonic-gate 					    sizeof (struct termios));
435*0Sstevel@tonic-gate 					tc->c_cflag = lqi->sm_ttycommon->
436*0Sstevel@tonic-gate 							t_cflag;
437*0Sstevel@tonic-gate 					pioc->b_cont->b_rptr =
438*0Sstevel@tonic-gate 					    pioc->b_cont->b_wptr;
439*0Sstevel@tonic-gate 					pioc->b_cont->b_wptr +=
440*0Sstevel@tonic-gate 					    sizeof (struct termios);
441*0Sstevel@tonic-gate 				}
442*0Sstevel@tonic-gate 				size = sizeof (struct iocblk) +
443*0Sstevel@tonic-gate 				    sizeof (struct termios);
444*0Sstevel@tonic-gate 			}
445*0Sstevel@tonic-gate 			else
446*0Sstevel@tonic-gate 				size = sizeof (struct iocblk);
447*0Sstevel@tonic-gate 		}
448*0Sstevel@tonic-gate 		else
449*0Sstevel@tonic-gate 			size = sizeof (struct iocblk);
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 		if (pioc != 0) {
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 			lqi->sm_piocid = ((struct iocblk *)pioc->b_rptr)->
454*0Sstevel@tonic-gate 						ioc_id;
455*0Sstevel@tonic-gate 			lqi->sm_flags |= SM_IOCPENDING;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 			/* lqi->sm_flags |= cmdflag; */
458*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
459*0Sstevel@tonic-gate 			(void) putq(q, pioc);
460*0Sstevel@tonic-gate 		} else {
461*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
462*0Sstevel@tonic-gate 			lqi->sm_bid = qbufcall(WR(q), size, BPRI_MED,
463*0Sstevel@tonic-gate 				sm_issue_ioctl, lqi);
464*0Sstevel@tonic-gate 		}
465*0Sstevel@tonic-gate 	}
466*0Sstevel@tonic-gate 	else
467*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate /*
471*0Sstevel@tonic-gate  * Associate one of the drivers minor nodes with a serial device.
472*0Sstevel@tonic-gate  */
473*0Sstevel@tonic-gate int
474*0Sstevel@tonic-gate sm_associate(int unit, sm_lqi_t *plqi, ulong_t tag, uint_t ioflag, char *dp)
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate 	sm_uqi_t *uqi;
477*0Sstevel@tonic-gate 	int rval = 0;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	sm_dbg('Y', ("sm_associate(%d, %d, %d): ",
480*0Sstevel@tonic-gate 		(plqi) ? plqi->sm_linkid : 0, unit, ioflag));
481*0Sstevel@tonic-gate 	/*
482*0Sstevel@tonic-gate 	 * Check the data is valid.
483*0Sstevel@tonic-gate 	 * Associate a lower queue with a logical unit.
484*0Sstevel@tonic-gate 	 */
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	if (unit < 0 || unit >= NLUNITS || plqi == 0 ||
487*0Sstevel@tonic-gate 	    (uqi = get_uqi(sm_ssp, unit)) == 0) {
488*0Sstevel@tonic-gate 		sm_dbg('@', (" invalid: lqi=0x%p lui=0x%p:", plqi, uqi));
489*0Sstevel@tonic-gate 		rval = EINVAL;
490*0Sstevel@tonic-gate 	} else {
491*0Sstevel@tonic-gate 		if ((ioflag & FORIO) == 0)
492*0Sstevel@tonic-gate 			ioflag = FORIO;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		LOCK_UNIT(plqi);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		if (plqi->sm_uqi) {
497*0Sstevel@tonic-gate 			if (plqi->sm_uqi->sm_lunit == unit) {
498*0Sstevel@tonic-gate 				if ((ioflag & (uint_t)FORIO) != 0)
499*0Sstevel@tonic-gate 					plqi->sm_ioflag =
500*0Sstevel@tonic-gate 					    (ioflag & (uint_t)FORIO);
501*0Sstevel@tonic-gate 				rval = 0;
502*0Sstevel@tonic-gate 			} else {
503*0Sstevel@tonic-gate 				sm_dbg('@', ("already associated with unit %d:",
504*0Sstevel@tonic-gate 				    plqi->sm_uqi->sm_lunit));
505*0Sstevel@tonic-gate 				rval = EINVAL;
506*0Sstevel@tonic-gate 			}
507*0Sstevel@tonic-gate 		} else {
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 			LOCK_UNIT(uqi);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 			if ((ioflag & (uint_t)FORIO) != 0)
512*0Sstevel@tonic-gate 				plqi->sm_ioflag = (ioflag & (uint_t)FORIO);
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_cflag = uqi->sm_ttycommon->
515*0Sstevel@tonic-gate 							t_cflag;
516*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_flags = uqi->sm_ttycommon->
517*0Sstevel@tonic-gate 							t_flags;
518*0Sstevel@tonic-gate 			plqi->sm_uqi = uqi;
519*0Sstevel@tonic-gate 			plqi->sm_mbits = 0;
520*0Sstevel@tonic-gate 			plqi->sm_tag = tag;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 			if (*dp == '/')
523*0Sstevel@tonic-gate 				(void) strncpy(plqi->sm_path, dp, MAXPATHLEN);
524*0Sstevel@tonic-gate 			else
525*0Sstevel@tonic-gate 				*(plqi->sm_path) = '\0';
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 			plqi->sm_flags |= WANT_TCSET;
528*0Sstevel@tonic-gate #ifdef ADD2FRONT
529*0Sstevel@tonic-gate 			plqi->sm_nlqi = uqi->sm_lqs;
530*0Sstevel@tonic-gate 			uqi->sm_lqs = plqi;
531*0Sstevel@tonic-gate #else
532*0Sstevel@tonic-gate 			plqi->sm_nlqi = 0;
533*0Sstevel@tonic-gate 			if (uqi->sm_lqs) {
534*0Sstevel@tonic-gate 				sm_lqi_t *lq;
535*0Sstevel@tonic-gate 				for (lq = uqi->sm_lqs; lq->sm_nlqi;
536*0Sstevel@tonic-gate 						lq = lq->sm_nlqi) {
537*0Sstevel@tonic-gate 				}
538*0Sstevel@tonic-gate 				lq->sm_nlqi = plqi;
539*0Sstevel@tonic-gate 			} else
540*0Sstevel@tonic-gate 				uqi->sm_lqs = plqi;
541*0Sstevel@tonic-gate #endif
542*0Sstevel@tonic-gate 			uqi->sm_nlqs++;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 			(void) ttymux_device_init(plqi);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 			UNLOCK_UNIT(uqi);
547*0Sstevel@tonic-gate 			rval = 0;
548*0Sstevel@tonic-gate 			/*
549*0Sstevel@tonic-gate 			 * Everything looks good so it's now ok to enable lower
550*0Sstevel@tonic-gate 			 * queue processing.
551*0Sstevel@tonic-gate 			 * Note the lower queue should be enabled as soon as
552*0Sstevel@tonic-gate 			 * I_PLINK returns (used in sm_get_ttymodes etc).
553*0Sstevel@tonic-gate 			 * Schedule ioctls to obtain the terminal settings.
554*0Sstevel@tonic-gate 			 */
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 			if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_waitq)
557*0Sstevel@tonic-gate 				plqi->sm_uqflags |= SM_UQVALID;
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 			qenable(SM_RQ(plqi));
560*0Sstevel@tonic-gate 			if (plqi->sm_flags & (WANT_CDSTAT|WANT_TCSET)) {
561*0Sstevel@tonic-gate 				/*
562*0Sstevel@tonic-gate 				 * Bypass the lower half of the driver (hence
563*0Sstevel@tonic-gate 				 * no qwriter) and apply the current termio
564*0Sstevel@tonic-gate 				 * settings on the lower stream.
565*0Sstevel@tonic-gate 				 */
566*0Sstevel@tonic-gate 				UNLOCK_UNIT(plqi);
567*0Sstevel@tonic-gate 				if (plqi->sm_bid) {
568*0Sstevel@tonic-gate 					qunbufcall(SM_WQ(plqi), plqi->sm_bid);
569*0Sstevel@tonic-gate 					plqi->sm_bid = 0;
570*0Sstevel@tonic-gate 				}
571*0Sstevel@tonic-gate 				/*
572*0Sstevel@tonic-gate 				 * Only set cflags on the lower q if we know
573*0Sstevel@tonic-gate 				 * the settings on any other lower queue.
574*0Sstevel@tonic-gate 				 */
575*0Sstevel@tonic-gate 				sm_issue_ioctl(plqi);
576*0Sstevel@tonic-gate 				LOCK_UNIT(plqi);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 			}
579*0Sstevel@tonic-gate 		}
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 		UNLOCK_UNIT(plqi);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	sm_dbg('Y', ("sm_associate: rval=%d.\n", rval));
584*0Sstevel@tonic-gate 	return (rval);
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate /*
588*0Sstevel@tonic-gate  * Break an association between one of the driver's minor nodes and
589*0Sstevel@tonic-gate  * a serial device.
590*0Sstevel@tonic-gate  */
591*0Sstevel@tonic-gate int
592*0Sstevel@tonic-gate sm_disassociate(int unit, sm_lqi_t *plqi, ulong_t tag)
593*0Sstevel@tonic-gate {
594*0Sstevel@tonic-gate 	sm_uqi_t *uqi;
595*0Sstevel@tonic-gate 	int rval = 0;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	sm_dbg('Y', ("sm_disassociate: link %d, unit %d: ",
598*0Sstevel@tonic-gate 	    (plqi) ? plqi->sm_linkid : 0, unit));
599*0Sstevel@tonic-gate 	/*
600*0Sstevel@tonic-gate 	 * Check the data is valid.
601*0Sstevel@tonic-gate 	 * Disassociate a lower queue with a logical unit.
602*0Sstevel@tonic-gate 	 */
603*0Sstevel@tonic-gate 	if (unit < 0 || unit >= NLUNITS || plqi == 0 ||
604*0Sstevel@tonic-gate 	    (uqi = get_uqi(sm_ssp, unit)) == 0) {
605*0Sstevel@tonic-gate 		sm_dbg('@', ("invalid: lqi=0x%p lui=0x%p", plqi, uqi));
606*0Sstevel@tonic-gate 		rval = EINVAL;
607*0Sstevel@tonic-gate 	} else {
608*0Sstevel@tonic-gate 		LOCK_UNIT(plqi);
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 		if (plqi->sm_uqi == NULL) {
611*0Sstevel@tonic-gate 			sm_dbg('@', ("unit not associated"));
612*0Sstevel@tonic-gate 			rval = EINVAL;
613*0Sstevel@tonic-gate 		} else if (plqi->sm_uqi->sm_lunit != unit) {
614*0Sstevel@tonic-gate 			sm_dbg('@', ("unit and linkid not related",
615*0Sstevel@tonic-gate 			    plqi->sm_uqi->sm_lunit));
616*0Sstevel@tonic-gate 			rval = EINVAL;
617*0Sstevel@tonic-gate 		} else if (plqi->sm_tag != tag) {
618*0Sstevel@tonic-gate 			sm_dbg('@',
619*0Sstevel@tonic-gate 			    ("Invalid tag for TTYMUX_DISASSOC ioctl\n"));
620*0Sstevel@tonic-gate 			rval = EPERM;
621*0Sstevel@tonic-gate 		} else {
622*0Sstevel@tonic-gate 			sm_dbg('Y', ("disassociating "));
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 			(void) ttymux_device_fini(plqi);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 			/*
627*0Sstevel@tonic-gate 			 * Indicate that carrier status is no
628*0Sstevel@tonic-gate 			 * longer required and that the upper
629*0Sstevel@tonic-gate 			 * queue should not be used by plqi
630*0Sstevel@tonic-gate 			 */
631*0Sstevel@tonic-gate 			plqi->sm_flags &= ~(WANT_CDSTAT|WANT_TCSET);
632*0Sstevel@tonic-gate 			plqi->sm_uqflags &= ~(SM_UQVALID|SM_OBPCNDEV);
633*0Sstevel@tonic-gate 			plqi->sm_ioflag = 0u;
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 			sm_lqifree(plqi);
636*0Sstevel@tonic-gate 			rval = 0;
637*0Sstevel@tonic-gate 		}
638*0Sstevel@tonic-gate 		UNLOCK_UNIT(plqi);
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 	sm_dbg('Y', (" rval=%d.\n", rval));
641*0Sstevel@tonic-gate 	return (rval);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate }
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate /*
646*0Sstevel@tonic-gate  * Streams helper routines;
647*0Sstevel@tonic-gate  */
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate /*
650*0Sstevel@tonic-gate  * Schedule a qbufcall for an upper queue.
651*0Sstevel@tonic-gate  * Must be called within the perimiter of the parameter q.
652*0Sstevel@tonic-gate  * fn must reenable the q.
653*0Sstevel@tonic-gate  * Called:
654*0Sstevel@tonic-gate  *	 whenever a message must be placed on multiple queues and allocb fails;
655*0Sstevel@tonic-gate  */
656*0Sstevel@tonic-gate static void
657*0Sstevel@tonic-gate sm_sched_uqcb(queue_t *q, int memreq, int pri, void (*fn)())
658*0Sstevel@tonic-gate {
659*0Sstevel@tonic-gate 	sm_uqi_t	*uqi = q->q_ptr;
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	if (uqi->sm_ttybid != 0)
662*0Sstevel@tonic-gate 		qunbufcall(q, uqi->sm_ttybid);
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	noenable(q);
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	uqi->sm_ttybid = qbufcall(q, memreq, pri, fn, uqi);
667*0Sstevel@tonic-gate }
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate /*
670*0Sstevel@tonic-gate  * qbufcall routine to restart the queues when memory is available.
671*0Sstevel@tonic-gate  */
672*0Sstevel@tonic-gate static void
673*0Sstevel@tonic-gate sm_reenable_q(sm_uqi_t *uqi)
674*0Sstevel@tonic-gate {
675*0Sstevel@tonic-gate 	queue_t *wq = SM_WQ(uqi);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	if ((uqi->sm_flags & SM_STOPPED) == 0) {
678*0Sstevel@tonic-gate 		enableok(wq);
679*0Sstevel@tonic-gate 		qenable(wq);
680*0Sstevel@tonic-gate 	}
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate /*
684*0Sstevel@tonic-gate  * Place a message on the write queue of each stream associated with
685*0Sstevel@tonic-gate  * the given upper stream.
686*0Sstevel@tonic-gate  */
687*0Sstevel@tonic-gate static void
688*0Sstevel@tonic-gate sm_senddown(sm_uqi_t *uqi)
689*0Sstevel@tonic-gate {
690*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
693*0Sstevel@tonic-gate 		if (lqi->sm_mp != 0) {
694*0Sstevel@tonic-gate 			putnext(SM_WQ(lqi), lqi->sm_mp);
695*0Sstevel@tonic-gate 			lqi->sm_mp = 0;
696*0Sstevel@tonic-gate 		}
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate }
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate /*
701*0Sstevel@tonic-gate  * For each lower device that should receive a write message duplicate
702*0Sstevel@tonic-gate  * the message block.
703*0Sstevel@tonic-gate  */
704*0Sstevel@tonic-gate static int
705*0Sstevel@tonic-gate sm_dupmsg(sm_uqi_t *uqi, mblk_t *mp)
706*0Sstevel@tonic-gate {
707*0Sstevel@tonic-gate 	sm_lqi_t	*lqi;
708*0Sstevel@tonic-gate 	mblk_t	*origmp = mp;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
711*0Sstevel@tonic-gate 		lqi->sm_mp = 0;
712*0Sstevel@tonic-gate 		if (lqi->sm_flags & WERROR_MODE) {
713*0Sstevel@tonic-gate 			continue;
714*0Sstevel@tonic-gate 		}
715*0Sstevel@tonic-gate 		if ((lqi->sm_ioflag & (uint_t)FOROUTPUT) == 0) {
716*0Sstevel@tonic-gate 			if (DB_TYPE(mp) == M_DATA)
717*0Sstevel@tonic-gate 				continue;
718*0Sstevel@tonic-gate 		}
719*0Sstevel@tonic-gate 		if (lqi->sm_nlqi == 0) {
720*0Sstevel@tonic-gate 			lqi->sm_mp = mp;
721*0Sstevel@tonic-gate 			origmp = NULL;
722*0Sstevel@tonic-gate 		} else if ((lqi->sm_mp = sm_copymsg(mp)) == 0) {
723*0Sstevel@tonic-gate 			sm_lqi_t *flqi;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 			for (flqi = uqi->sm_lqs; flqi != lqi;
726*0Sstevel@tonic-gate 					flqi = flqi->sm_nlqi) {
727*0Sstevel@tonic-gate 				if (lqi->sm_mp) {
728*0Sstevel@tonic-gate 				/* must have been sm_copymsg */
729*0Sstevel@tonic-gate 					sm_freemsg(lqi->sm_mp);
730*0Sstevel@tonic-gate 					lqi->sm_mp = 0;
731*0Sstevel@tonic-gate 				}
732*0Sstevel@tonic-gate 			}
733*0Sstevel@tonic-gate 			return (sm_cnt_oqs(uqi) * msgdsize(mp));
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 	if (origmp != NULL)
737*0Sstevel@tonic-gate 		freemsg(origmp);
738*0Sstevel@tonic-gate 	return (0);
739*0Sstevel@tonic-gate }
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate /*
742*0Sstevel@tonic-gate  * Return 1 if all associated lower devices have room for another message
743*0Sstevel@tonic-gate  * otherwise return 0.
744*0Sstevel@tonic-gate  */
745*0Sstevel@tonic-gate static int
746*0Sstevel@tonic-gate sm_cansenddown(sm_uqi_t *uqi)
747*0Sstevel@tonic-gate {
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	register sm_lqi_t	*lqi;
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	if (uqi->sm_lqs == 0)
752*0Sstevel@tonic-gate 		return (0);
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
755*0Sstevel@tonic-gate 		if ((lqi->sm_flags & WERROR_MODE) == 0 &&
756*0Sstevel@tonic-gate 		    canputnext(SM_WQ(lqi)) == 0)
757*0Sstevel@tonic-gate 			return (0);
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 	return (1);
760*0Sstevel@tonic-gate }
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate /*
763*0Sstevel@tonic-gate  * Put a message down all associated lower queues.
764*0Sstevel@tonic-gate  * Return 1 if the q function was called.
765*0Sstevel@tonic-gate  */
766*0Sstevel@tonic-gate static int
767*0Sstevel@tonic-gate sm_putqs(queue_t *q, mblk_t *mp, int (*qfn)())
768*0Sstevel@tonic-gate {
769*0Sstevel@tonic-gate 	register sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr;
770*0Sstevel@tonic-gate 	register int memreq;
771*0Sstevel@tonic-gate 	int pri = (DB_TYPE(mp) < QPCTL) ? BPRI_MED : BPRI_HI;
772*0Sstevel@tonic-gate 	int rval = 0;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	if (uqi->sm_lqs == 0 || (uqi->sm_flags & WERROR_MODE)) {
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 		sm_dbg('Q', ("sm_putqs: freeing (0x%p 0x%p).\n", uqi->sm_lqs,
777*0Sstevel@tonic-gate 					uqi->sm_flags));
778*0Sstevel@tonic-gate 		freemsg(mp);
779*0Sstevel@tonic-gate 	} else if (pri != BPRI_HI && sm_cansenddown(uqi) == 0) {
780*0Sstevel@tonic-gate 		/* a lower q is flow controlled */
781*0Sstevel@tonic-gate 		(void) qfn(q, mp);
782*0Sstevel@tonic-gate 		rval = 1;
783*0Sstevel@tonic-gate 	} else if ((memreq = sm_dupmsg(uqi, mp)) == 0) {
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 		sm_senddown(uqi);
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	} else {
788*0Sstevel@tonic-gate 		sm_log("sm_putqs: msg 0x%x - can't alloc %d bytes (pri %d).\n",
789*0Sstevel@tonic-gate 				DB_TYPE(mp), memreq, pri);
790*0Sstevel@tonic-gate 		sm_sched_uqcb(q, memreq, pri, sm_reenable_q);
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 		(void) qfn(q, mp);
793*0Sstevel@tonic-gate 		rval = 1;
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 	}
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	return (rval);
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate /*
801*0Sstevel@tonic-gate  * sm_reply - send an ioctl reply back up the queue.
802*0Sstevel@tonic-gate  */
803*0Sstevel@tonic-gate static void
804*0Sstevel@tonic-gate sm_reply(queue_t *q, mblk_t *mp, uchar_t type, int error)
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate 	struct iocblk *iocbp;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	iocbp = (struct iocblk *)mp->b_rptr;
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	DB_TYPE(mp) = type;
811*0Sstevel@tonic-gate 	iocbp->ioc_count = 0;
812*0Sstevel@tonic-gate 	iocbp->ioc_error = error;
813*0Sstevel@tonic-gate 	qreply(q, mp);
814*0Sstevel@tonic-gate }
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate /*
817*0Sstevel@tonic-gate  * Service a streams link and unlink requests.
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate static void
820*0Sstevel@tonic-gate sm_link_req(queue_t *wq, mblk_t *mp)
821*0Sstevel@tonic-gate {
822*0Sstevel@tonic-gate 	struct linkblk *linkp;
823*0Sstevel@tonic-gate 	int rval;
824*0Sstevel@tonic-gate 	int cmd;
825*0Sstevel@tonic-gate 	sm_lqi_t *plqi;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_IOCTL);
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
830*0Sstevel@tonic-gate 	switch (cmd) {
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	case I_LINK:
833*0Sstevel@tonic-gate 	case I_PLINK:
834*0Sstevel@tonic-gate 		sm_dbg('G', ("sm_link_req: M_IOCTL %x (I_PLINK).\n", cmd));
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 		linkp = (struct linkblk *)mp->b_cont->b_rptr;
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 		/*
839*0Sstevel@tonic-gate 		 * 1.	Sanity check the link block.
840*0Sstevel@tonic-gate 		 * 2.	Validate that the queue is not already linked
841*0Sstevel@tonic-gate 		 *		(and resources available).
842*0Sstevel@tonic-gate 		 * 3.	Validate that the lower queue is not associated with
843*0Sstevel@tonic-gate 		 *		a logical unit.
844*0Sstevel@tonic-gate 		 * 4.	Remember that this lower queue is linked to the driver.
845*0Sstevel@tonic-gate 		 */
846*0Sstevel@tonic-gate 		if ((linkp == NULL) || (MBLKL(mp) < sizeof (*linkp)) ||
847*0Sstevel@tonic-gate 			linkp->l_qbot == NULL) {
848*0Sstevel@tonic-gate 			sm_dbg('I', ("sm_link_req: invalid link block.\n"));
849*0Sstevel@tonic-gate 			rval = EINVAL;
850*0Sstevel@tonic-gate 		} else if ((plqi = get_lqi_byq(linkp->l_qbot)) == 0) {
851*0Sstevel@tonic-gate 			sm_dbg('I', ("sm_link_req: out of resources.\n"));
852*0Sstevel@tonic-gate 			rval = EBUSY; /* out of resources */
853*0Sstevel@tonic-gate 		} else if (plqi->sm_uqi) {
854*0Sstevel@tonic-gate 			UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */
855*0Sstevel@tonic-gate 			sm_dbg('I', ("sm_link_req: already associated.\n"));
856*0Sstevel@tonic-gate 			rval = EBUSY; /* already linked */
857*0Sstevel@tonic-gate 		} else {
858*0Sstevel@tonic-gate 			SM_WQ(plqi) = linkp->l_qbot;
859*0Sstevel@tonic-gate 			SM_RQ(plqi)	= OTHERQ(linkp->l_qbot);
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 			linkp->l_qbot->q_ptr =
862*0Sstevel@tonic-gate 				OTHERQ(linkp->l_qbot)->q_ptr = plqi;
863*0Sstevel@tonic-gate 			plqi->sm_linkid = linkp->l_index;
864*0Sstevel@tonic-gate 			UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 			sm_dbg('H', ("sm_link_req: linkid = %d.\n",
867*0Sstevel@tonic-gate 				linkp->l_index));
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 			sm_setdip(linkp->l_qbot, plqi);
870*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_flags = 0;
871*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_cflag = 0;
872*0Sstevel@tonic-gate 			plqi->sm_mbits = 0;
873*0Sstevel@tonic-gate 			(void) ttymux_device_init(plqi);
874*0Sstevel@tonic-gate 			rval = 0;
875*0Sstevel@tonic-gate 		}
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 		break;
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	case I_UNLINK:
880*0Sstevel@tonic-gate 	case I_PUNLINK:
881*0Sstevel@tonic-gate 		sm_dbg('G', ("sm_link_req: M_IOCTL (I_PUNLINK).\n"));
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 		linkp = (struct linkblk *)mp->b_cont->b_rptr;
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		if ((linkp == NULL) ||
886*0Sstevel@tonic-gate 			(MBLKL(mp) < sizeof (*linkp)) ||
887*0Sstevel@tonic-gate 			linkp->l_qbot == NULL) {
888*0Sstevel@tonic-gate 			rval = EINVAL;
889*0Sstevel@tonic-gate 		} else if ((plqi = get_lqi_byid(linkp->l_index)) == 0) {
890*0Sstevel@tonic-gate 			rval = EINVAL;
891*0Sstevel@tonic-gate 		} else {
892*0Sstevel@tonic-gate 			sm_uqi_t *uqi;
893*0Sstevel@tonic-gate 			int werrmode;
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 			/*
896*0Sstevel@tonic-gate 			 * Mark the lower q as invalid.
897*0Sstevel@tonic-gate 			 */
898*0Sstevel@tonic-gate 			sm_dbg('G', ("I_PUNLINK: freeing link %d\n",
899*0Sstevel@tonic-gate 					linkp->l_index));
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 			if (plqi->sm_bid) {
902*0Sstevel@tonic-gate 				qunbufcall(SM_RQ(plqi), plqi->sm_bid);
903*0Sstevel@tonic-gate 				plqi->sm_bid = 0;
904*0Sstevel@tonic-gate 			}
905*0Sstevel@tonic-gate 			if (plqi->sm_ttybid) {
906*0Sstevel@tonic-gate 				qunbufcall(SM_RQ(plqi), plqi->sm_ttybid);
907*0Sstevel@tonic-gate 				plqi->sm_ttybid = 0;
908*0Sstevel@tonic-gate 			}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 			uqi = plqi->sm_uqi;
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 			(void) ttymux_device_fini(plqi);
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 			if (uqi)
916*0Sstevel@tonic-gate 				(void) sm_disassociate(uqi->sm_lunit,
917*0Sstevel@tonic-gate 					plqi, plqi->sm_tag);
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 			LOCK_UNIT(plqi);
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 			plqi->sm_piocid = 0;
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 			werrmode = (plqi->sm_flags & (WERROR_MODE|HANGUP_MODE))
924*0Sstevel@tonic-gate 			    ? 1 : 0;
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 			plqi->sm_mbits = 0;
927*0Sstevel@tonic-gate 			plqi->sm_flags = 0;
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 			ttycommon_close(plqi->sm_ttycommon);
930*0Sstevel@tonic-gate 			/* SM_RQ(plqi) = SM_WQ(plqi) = 0; */
931*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_flags = 0;
932*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_cflag = 0;
933*0Sstevel@tonic-gate 			plqi->sm_ttycommon->t_iflag = 0;
934*0Sstevel@tonic-gate 			plqi->sm_linkid = 0;
935*0Sstevel@tonic-gate 			plqi->sm_dev = NODEV;
936*0Sstevel@tonic-gate 			plqi->sm_hadkadbchar = 0;
937*0Sstevel@tonic-gate 			plqi->sm_nachar = sm_ssp->sm_abs;
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 			UNLOCK_UNIT(plqi);
940*0Sstevel@tonic-gate 			if (uqi &&
941*0Sstevel@tonic-gate 			    werrmode &&
942*0Sstevel@tonic-gate 			    (uqi->sm_flags & FULLY_OPEN) &&
943*0Sstevel@tonic-gate 			    sm_uwq_error(uqi) &&
944*0Sstevel@tonic-gate 			    putnextctl(SM_RQ(uqi), M_HANGUP) == 0) {
945*0Sstevel@tonic-gate 				sm_log("sm_link_req: putnextctl(M_HANGUP)"
946*0Sstevel@tonic-gate 					" failed.\n");
947*0Sstevel@tonic-gate 			}
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 			rval = 0;
950*0Sstevel@tonic-gate 		}
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 		break;
953*0Sstevel@tonic-gate 	default:
954*0Sstevel@tonic-gate 		rval = EINVAL;
955*0Sstevel@tonic-gate 	}
956*0Sstevel@tonic-gate 	sm_reply(wq, mp, (rval) ? M_IOCNAK : M_IOCACK, rval);
957*0Sstevel@tonic-gate }
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate static int
960*0Sstevel@tonic-gate sm_getiocinfo(mblk_t *mp, struct sm_iocinfo *info)
961*0Sstevel@tonic-gate {
962*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
963*0Sstevel@tonic-gate 	case M_COPYOUT:
964*0Sstevel@tonic-gate 		info->sm_id = ((struct copyreq *)mp->b_rptr)->cq_id;
965*0Sstevel@tonic-gate 		info->sm_cmd = ((struct copyreq *)mp->b_rptr)->cq_cmd;
966*0Sstevel@tonic-gate 		info->sm_data = (((struct copyreq *)mp->b_rptr)->cq_size &&
967*0Sstevel@tonic-gate 		    mp->b_cont) ? (void *)mp->b_cont->b_rptr : 0;
968*0Sstevel@tonic-gate 		break;
969*0Sstevel@tonic-gate 	case M_COPYIN:
970*0Sstevel@tonic-gate 		info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id;
971*0Sstevel@tonic-gate 		info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd;
972*0Sstevel@tonic-gate 		info->sm_data = 0;
973*0Sstevel@tonic-gate 		break;
974*0Sstevel@tonic-gate 	case M_IOCACK:
975*0Sstevel@tonic-gate 		info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id;
976*0Sstevel@tonic-gate 		info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
977*0Sstevel@tonic-gate 		/* the se driver has bug so we cannot use ioc_count */
978*0Sstevel@tonic-gate 		info->sm_data = (((struct iocblk *)mp->b_rptr)->
979*0Sstevel@tonic-gate 					ioc_error == 0 && mp->b_cont) ?
980*0Sstevel@tonic-gate 					(void *)mp->b_cont->b_rptr : 0;
981*0Sstevel@tonic-gate 		break;
982*0Sstevel@tonic-gate 	case M_IOCNAK:
983*0Sstevel@tonic-gate 		info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id;
984*0Sstevel@tonic-gate 		info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
985*0Sstevel@tonic-gate 		info->sm_data = 0;
986*0Sstevel@tonic-gate 		break;
987*0Sstevel@tonic-gate 	case M_IOCDATA:
988*0Sstevel@tonic-gate 		info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id;
989*0Sstevel@tonic-gate 		info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd;
990*0Sstevel@tonic-gate 		info->sm_data = (((struct copyresp *)mp->b_rptr)->
991*0Sstevel@tonic-gate 					cp_rval == 0 && mp->b_cont) ?
992*0Sstevel@tonic-gate 					(void *)mp->b_cont->b_rptr : 0;
993*0Sstevel@tonic-gate 		break;
994*0Sstevel@tonic-gate 	case M_IOCTL:
995*0Sstevel@tonic-gate 		info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id;
996*0Sstevel@tonic-gate 		info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
997*0Sstevel@tonic-gate 		info->sm_data = 0;
998*0Sstevel@tonic-gate 		break;
999*0Sstevel@tonic-gate 	default:
1000*0Sstevel@tonic-gate 		return (EINVAL);
1001*0Sstevel@tonic-gate 	}
1002*0Sstevel@tonic-gate 	return (0);
1003*0Sstevel@tonic-gate }
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate /*
1006*0Sstevel@tonic-gate  * Record the termio settings that have been set on the upper stream
1007*0Sstevel@tonic-gate  */
1008*0Sstevel@tonic-gate static int
1009*0Sstevel@tonic-gate sm_update_ttyinfo(mblk_t *mp, sm_uqi_t *uqi)
1010*0Sstevel@tonic-gate {
1011*0Sstevel@tonic-gate 	int err;
1012*0Sstevel@tonic-gate 	struct sm_iocinfo info;
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	if ((err = sm_getiocinfo(mp, &info)) != 0)
1015*0Sstevel@tonic-gate 		return (err);
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	switch (info.sm_cmd) {
1018*0Sstevel@tonic-gate 	case TIOCSPPS:
1019*0Sstevel@tonic-gate 	case TIOCGPPS:
1020*0Sstevel@tonic-gate 	case TIOCGPPSEV:
1021*0Sstevel@tonic-gate 		return (ENOTSUP);
1022*0Sstevel@tonic-gate 	case TIOCGWINSZ:
1023*0Sstevel@tonic-gate 	case TIOCSWINSZ:
1024*0Sstevel@tonic-gate 		break;
1025*0Sstevel@tonic-gate 	case TCSBRK:
1026*0Sstevel@tonic-gate 	case TIOCSBRK:
1027*0Sstevel@tonic-gate 	case TIOCCBRK:
1028*0Sstevel@tonic-gate 		break;
1029*0Sstevel@tonic-gate 	case TCSETSF:
1030*0Sstevel@tonic-gate 		uqi->sm_flags |= FLUSHR_PEND;
1031*0Sstevel@tonic-gate 		sm_dbg('I', ("TCSETSF: FLUSH is pending\n"));
1032*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
1033*0Sstevel@tonic-gate 	case TCSETSW:
1034*0Sstevel@tonic-gate 	case TCSETS:
1035*0Sstevel@tonic-gate 	case TCGETS:
1036*0Sstevel@tonic-gate 		if (info.sm_data != 0) {
1037*0Sstevel@tonic-gate 			((struct termios *)info.sm_data)->c_cflag &=
1038*0Sstevel@tonic-gate 			    (tcflag_t)(~uqi->sm_cmask);
1039*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_cflag =
1040*0Sstevel@tonic-gate 			    ((struct termios *)info.sm_data)->c_cflag;
1041*0Sstevel@tonic-gate 		}
1042*0Sstevel@tonic-gate 		break;
1043*0Sstevel@tonic-gate 	case TCSETAF:
1044*0Sstevel@tonic-gate 		sm_dbg('I', ("TCSETAF: FLUSH is pending\n"));
1045*0Sstevel@tonic-gate 		uqi->sm_flags |= FLUSHR_PEND;
1046*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
1047*0Sstevel@tonic-gate 	case TCSETAW:
1048*0Sstevel@tonic-gate 	case TCSETA:
1049*0Sstevel@tonic-gate 	case TCGETA:
1050*0Sstevel@tonic-gate 		if (info.sm_data != 0) {
1051*0Sstevel@tonic-gate 			((struct termio *)info.sm_data)->c_cflag &=
1052*0Sstevel@tonic-gate 			    (tcflag_t)(~uqi->sm_cmask);
1053*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_cflag =
1054*0Sstevel@tonic-gate 			    (tcflag_t)((struct termio *)info.sm_data)->c_cflag;
1055*0Sstevel@tonic-gate 		}
1056*0Sstevel@tonic-gate 		break;
1057*0Sstevel@tonic-gate 	case TIOCSSOFTCAR:
1058*0Sstevel@tonic-gate 	case TIOCGSOFTCAR:
1059*0Sstevel@tonic-gate 		if (info.sm_data != 0) {
1060*0Sstevel@tonic-gate 			if (*(int *)info.sm_data == 1)
1061*0Sstevel@tonic-gate 				uqi->sm_ttycommon->t_flags |= TS_SOFTCAR;
1062*0Sstevel@tonic-gate 			else
1063*0Sstevel@tonic-gate 				uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR;
1064*0Sstevel@tonic-gate 		}
1065*0Sstevel@tonic-gate 		break;
1066*0Sstevel@tonic-gate 	case TIOCMSET:
1067*0Sstevel@tonic-gate 	case TIOCMGET:
1068*0Sstevel@tonic-gate 		if (info.sm_data != 0)
1069*0Sstevel@tonic-gate 			uqi->sm_mbits = *(int *)info.sm_data;
1070*0Sstevel@tonic-gate 		break;
1071*0Sstevel@tonic-gate 	case TIOCMBIS:
1072*0Sstevel@tonic-gate 		if (info.sm_data != 0)
1073*0Sstevel@tonic-gate 			uqi->sm_mbits |= *(int *)info.sm_data;
1074*0Sstevel@tonic-gate 		break;
1075*0Sstevel@tonic-gate 	case TIOCMBIC:
1076*0Sstevel@tonic-gate 		if (info.sm_data != 0)
1077*0Sstevel@tonic-gate 			uqi->sm_mbits &= ~(*(int *)info.sm_data);
1078*0Sstevel@tonic-gate 		break;
1079*0Sstevel@tonic-gate 	default:
1080*0Sstevel@tonic-gate 		return (EINVAL);
1081*0Sstevel@tonic-gate 		/* NOTREACHED */
1082*0Sstevel@tonic-gate 	} /* end switch cmd */
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	if ((uqi->sm_mbits & TIOCM_CD) ||
1085*0Sstevel@tonic-gate 		(uqi->sm_ttycommon->t_flags & TS_SOFTCAR) ||
1086*0Sstevel@tonic-gate 		(uqi->sm_ttycommon->t_cflag & CLOCAL))
1087*0Sstevel@tonic-gate 		uqi->sm_flags |= SM_CARON;
1088*0Sstevel@tonic-gate 	else
1089*0Sstevel@tonic-gate 		uqi->sm_flags &= ~SM_CARON;
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 	return (0);
1092*0Sstevel@tonic-gate }
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate /*
1095*0Sstevel@tonic-gate  * SECTION
1096*0Sstevel@tonic-gate  * STREAM's interface to the OS.
1097*0Sstevel@tonic-gate  * Routines directly callable from the OS.
1098*0Sstevel@tonic-gate  */
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate /*
1101*0Sstevel@tonic-gate  * Processes high priority messages comming from modules above the
1102*0Sstevel@tonic-gate  * multiplexor.
1103*0Sstevel@tonic-gate  * Return 1 if the queue was disabled.
1104*0Sstevel@tonic-gate  */
1105*0Sstevel@tonic-gate static int
1106*0Sstevel@tonic-gate sm_hp_uwput(queue_t *wq, mblk_t *mp)
1107*0Sstevel@tonic-gate {
1108*0Sstevel@tonic-gate 	sm_uqi_t	*uqi = (sm_uqi_t *)(wq->q_ptr);
1109*0Sstevel@tonic-gate 	int	rval = 0;
1110*0Sstevel@tonic-gate 	sm_lqi_t	*plqi;
1111*0Sstevel@tonic-gate 	int	msgtype = DB_TYPE(mp);
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	switch (msgtype) {
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	case M_FLUSH:
1116*0Sstevel@tonic-gate 		/*
1117*0Sstevel@tonic-gate 		 * How to flush the bottom half:
1118*0Sstevel@tonic-gate 		 * putctl1(SM_WQ(plqi), *mp->b_rptr)
1119*0Sstevel@tonic-gate 		 * will work on the bottom half but if FLUSHR is set
1120*0Sstevel@tonic-gate 		 * when is the right time to flush the upper read queue.
1121*0Sstevel@tonic-gate 		 *
1122*0Sstevel@tonic-gate 		 * Could set uqi->sm_flags & WANT_FLUSH but then what happens
1123*0Sstevel@tonic-gate 		 * if FLUSHR is set and the driver sends up a FLUSHR
1124*0Sstevel@tonic-gate 		 * before it handles the current FLUSHR request
1125*0Sstevel@tonic-gate 		 * (if only there was an id for the message that could
1126*0Sstevel@tonic-gate 		 * be matched when it returns back from the drivers.
1127*0Sstevel@tonic-gate 		 *
1128*0Sstevel@tonic-gate 		 * Thus I'm going by the book - the bottom half acts like
1129*0Sstevel@tonic-gate 		 * a stream head and turns around FLUSHW back down to
1130*0Sstevel@tonic-gate 		 * the driver (see lrput). The upper half acts like a
1131*0Sstevel@tonic-gate 		 * driver and turns around FLUSHR:
1132*0Sstevel@tonic-gate 		 */
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_hp_uwput: FLUSH request 0x%x\n", *mp->b_rptr));
1135*0Sstevel@tonic-gate 		/* flush the upper write queue */
1136*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
1137*0Sstevel@tonic-gate 			flushq(wq, FLUSHDATA);
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 		/*
1140*0Sstevel@tonic-gate 		 * flush each associated lower write queue
1141*0Sstevel@tonic-gate 		 * and pass down the driver (ignore the FLUSHR and deal with
1142*0Sstevel@tonic-gate 		 * it when it comes back up the read side.
1143*0Sstevel@tonic-gate 		 */
1144*0Sstevel@tonic-gate 		for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) {
1145*0Sstevel@tonic-gate 			if ((plqi->sm_flags & WERROR_MODE) == 0 &&
1146*0Sstevel@tonic-gate 						SM_WQ(plqi)) {
1147*0Sstevel@tonic-gate 				sm_dbg('I', ("flush lq 0x%p\n", SM_WQ(plqi)));
1148*0Sstevel@tonic-gate 				if (*mp->b_rptr & FLUSHW)
1149*0Sstevel@tonic-gate 					flushq(SM_WQ(plqi), FLUSHDATA);
1150*0Sstevel@tonic-gate 				(void) putnextctl1(SM_WQ(plqi), M_FLUSH,
1151*0Sstevel@tonic-gate 				    *mp->b_rptr);
1152*0Sstevel@tonic-gate 			}
1153*0Sstevel@tonic-gate 		}
1154*0Sstevel@tonic-gate 		break;
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 	case M_STARTI:
1157*0Sstevel@tonic-gate 		for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) {
1158*0Sstevel@tonic-gate 			plqi->sm_flags &= ~SM_ISTOPPED;
1159*0Sstevel@tonic-gate 			if ((plqi->sm_flags & WERROR_MODE) == 0)
1160*0Sstevel@tonic-gate 				(void) putnextctl(SM_WQ(plqi), msgtype);
1161*0Sstevel@tonic-gate 		}
1162*0Sstevel@tonic-gate 		break;
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate 	case M_STOPI:
1165*0Sstevel@tonic-gate 		for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) {
1166*0Sstevel@tonic-gate 			plqi->sm_flags |= SM_ISTOPPED;
1167*0Sstevel@tonic-gate 			if ((plqi->sm_flags & WERROR_MODE) == 0)
1168*0Sstevel@tonic-gate 				(void) putnextctl(SM_WQ(plqi), msgtype);
1169*0Sstevel@tonic-gate 		}
1170*0Sstevel@tonic-gate 		break;
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 	case M_STOP:	/* must never be queued */
1173*0Sstevel@tonic-gate 		uqi->sm_flags |= SM_STOPPED;
1174*0Sstevel@tonic-gate 		noenable(wq);
1175*0Sstevel@tonic-gate 		for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi)
1176*0Sstevel@tonic-gate 			if ((plqi->sm_flags & WERROR_MODE) == 0)
1177*0Sstevel@tonic-gate 				(void) putnextctl(SM_WQ(plqi), msgtype);
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 		rval = 1;
1180*0Sstevel@tonic-gate 		break;
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate 	case M_START:	/* never be queued */
1183*0Sstevel@tonic-gate 		uqi->sm_flags &= ~SM_STOPPED;
1184*0Sstevel@tonic-gate 		enableok(wq);
1185*0Sstevel@tonic-gate 		qenable(wq);
1186*0Sstevel@tonic-gate 		for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi)
1187*0Sstevel@tonic-gate 			if ((plqi->sm_flags & WERROR_MODE) == 0)
1188*0Sstevel@tonic-gate 				(void) putnextctl(SM_WQ(plqi), msgtype);
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 		break;
1191*0Sstevel@tonic-gate 
1192*0Sstevel@tonic-gate 	case M_PCSIG:
1193*0Sstevel@tonic-gate 	case M_COPYOUT:
1194*0Sstevel@tonic-gate 	case M_COPYIN:
1195*0Sstevel@tonic-gate 	case M_IOCACK:
1196*0Sstevel@tonic-gate 	case M_IOCNAK:
1197*0Sstevel@tonic-gate 		/* Wrong direction for message */
1198*0Sstevel@tonic-gate 		break;
1199*0Sstevel@tonic-gate 	case M_READ:
1200*0Sstevel@tonic-gate 		break;
1201*0Sstevel@tonic-gate 	case M_PCPROTO:
1202*0Sstevel@tonic-gate 	case M_PCRSE:
1203*0Sstevel@tonic-gate 	default:
1204*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_hp_uwput: default case %d.\n", msgtype));
1205*0Sstevel@tonic-gate 		break;
1206*0Sstevel@tonic-gate 	} /* end switch on high pri message type */
1207*0Sstevel@tonic-gate 
1208*0Sstevel@tonic-gate 	freemsg(mp);
1209*0Sstevel@tonic-gate 	return (rval);
1210*0Sstevel@tonic-gate }
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate static int
1213*0Sstevel@tonic-gate sm_default_uwioctl(queue_t *wq, mblk_t *mp, int (*qfn)())
1214*0Sstevel@tonic-gate {
1215*0Sstevel@tonic-gate 	int	err;
1216*0Sstevel@tonic-gate 	struct iocblk	*iobp;
1217*0Sstevel@tonic-gate 	sm_uqi_t	*uqi;
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	uqi = (sm_uqi_t *)(wq->q_ptr);
1220*0Sstevel@tonic-gate 	iobp = (struct iocblk *)mp->b_rptr;
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate 	switch (iobp->ioc_cmd) {
1223*0Sstevel@tonic-gate 	case TIOCEXCL:
1224*0Sstevel@tonic-gate 	case TIOCNXCL:
1225*0Sstevel@tonic-gate 	case TIOCSTI:
1226*0Sstevel@tonic-gate 		(void) ttycommon_ioctl(uqi->sm_ttycommon, wq, mp, &err);
1227*0Sstevel@tonic-gate 		sm_reply(wq, mp, err ? M_IOCACK : M_IOCNAK, err);
1228*0Sstevel@tonic-gate 		return (0);
1229*0Sstevel@tonic-gate 	default:
1230*0Sstevel@tonic-gate 		break;
1231*0Sstevel@tonic-gate 	}
1232*0Sstevel@tonic-gate 	err = sm_update_ttyinfo(mp, uqi);
1233*0Sstevel@tonic-gate 	if (err) {
1234*0Sstevel@tonic-gate 		iobp->ioc_error = err;
1235*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
1236*0Sstevel@tonic-gate 		qreply(wq, mp);
1237*0Sstevel@tonic-gate 		return (0);
1238*0Sstevel@tonic-gate 	}
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate 	/*
1241*0Sstevel@tonic-gate 	 * If uqi->sm_siocdata.sm_iocid just overwrite it since the stream
1242*0Sstevel@tonic-gate 	 * head will have timed it out
1243*0Sstevel@tonic-gate 	 */
1244*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_iocid = iobp->ioc_id;
1245*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_acked = 0;
1246*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_nacks = sm_good_qs(uqi);
1247*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_acnt = 0;
1248*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_policy = uqi->sm_policy;
1249*0Sstevel@tonic-gate 	uqi->sm_siocdata.sm_flags = 0;
1250*0Sstevel@tonic-gate 	sm_dbg('Z', (" want %d acks for id %d.\n",
1251*0Sstevel@tonic-gate 	    uqi->sm_siocdata.sm_nacks, iobp->ioc_id));
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	return (sm_putqs(wq, mp, qfn));
1254*0Sstevel@tonic-gate }
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate /*
1257*0Sstevel@tonic-gate  *
1258*0Sstevel@tonic-gate  * sm_uwput - put function for an upper STREAM write.
1259*0Sstevel@tonic-gate  */
1260*0Sstevel@tonic-gate static int
1261*0Sstevel@tonic-gate sm_uwput(queue_t *wq, mblk_t *mp)
1262*0Sstevel@tonic-gate {
1263*0Sstevel@tonic-gate 	sm_uqi_t		*uqi;
1264*0Sstevel@tonic-gate 	uchar_t		msgtype;
1265*0Sstevel@tonic-gate 	int		cmd;
1266*0Sstevel@tonic-gate 	struct iocblk	*iobp;
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 	uqi = (sm_uqi_t *)(wq->q_ptr);
1269*0Sstevel@tonic-gate 	msgtype = DB_TYPE(mp);
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 	ASSERT(uqi != 0 && sm_ssp != 0);
1272*0Sstevel@tonic-gate 
1273*0Sstevel@tonic-gate 	if (msgtype >= QPCTL && msgtype != M_IOCDATA) {
1274*0Sstevel@tonic-gate 		(void) sm_hp_uwput(wq, mp);
1275*0Sstevel@tonic-gate 		return (0);
1276*0Sstevel@tonic-gate 	}
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1279*0Sstevel@tonic-gate 	case M_DATA:
1280*0Sstevel@tonic-gate 	case M_DELAY:
1281*0Sstevel@tonic-gate 	case M_BREAK:
1282*0Sstevel@tonic-gate 	default:
1283*0Sstevel@tonic-gate 		(void) sm_putqs(wq, mp, putq);
1284*0Sstevel@tonic-gate 		break;
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 	case M_CTL:
1287*0Sstevel@tonic-gate 		if (((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_CANONQUERY) {
1288*0Sstevel@tonic-gate 			(void) putnextctl1(OTHERQ(wq), M_CTL, MC_NOCANON);
1289*0Sstevel@tonic-gate 		}
1290*0Sstevel@tonic-gate 		freemsg(mp);
1291*0Sstevel@tonic-gate 		break;
1292*0Sstevel@tonic-gate 	case M_IOCDATA: /* not handled as high pri because may need to putbq */
1293*0Sstevel@tonic-gate 		sm_dbg('M', ("sm_uwput(M_IOCDATA)\n"));
1294*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
1295*0Sstevel@tonic-gate 	case M_IOCTL:
1296*0Sstevel@tonic-gate 		cmd = (msgtype == M_IOCDATA) ?
1297*0Sstevel@tonic-gate 		    ((struct copyresp *)mp->b_rptr)->cp_cmd :
1298*0Sstevel@tonic-gate 		    ((struct iocblk *)mp->b_rptr)->ioc_cmd;
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 		iobp = (struct iocblk *)mp->b_rptr;
1301*0Sstevel@tonic-gate 		iobp->ioc_rval = 0;
1302*0Sstevel@tonic-gate 
1303*0Sstevel@tonic-gate 		sm_dbg('M', ("sm_uwput(M_IOCTL:%d)\n", cmd));
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate 		switch (cmd) {
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate 		case CONSGETABORTENABLE:
1308*0Sstevel@tonic-gate 			iobp->ioc_error = ttymux_abort_ioctl(mp);
1309*0Sstevel@tonic-gate 			DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK;
1310*0Sstevel@tonic-gate 			qreply(wq, mp);
1311*0Sstevel@tonic-gate 			break;
1312*0Sstevel@tonic-gate 		case CONSSETABORTENABLE:
1313*0Sstevel@tonic-gate 			iobp->ioc_error =
1314*0Sstevel@tonic-gate 			    secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0 ?
1315*0Sstevel@tonic-gate 				EPERM : ttymux_abort_ioctl(mp);
1316*0Sstevel@tonic-gate 			DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK;
1317*0Sstevel@tonic-gate 			qreply(wq, mp);
1318*0Sstevel@tonic-gate 			break;
1319*0Sstevel@tonic-gate 		case TTYMUX_SETABORT:
1320*0Sstevel@tonic-gate 			if (secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0) {
1321*0Sstevel@tonic-gate 				iobp->ioc_error = EPERM;
1322*0Sstevel@tonic-gate 				DB_TYPE(mp) = M_IOCNAK;
1323*0Sstevel@tonic-gate 				qreply(wq, mp);
1324*0Sstevel@tonic-gate 				break;
1325*0Sstevel@tonic-gate 			}
1326*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
1327*0Sstevel@tonic-gate 		case TTYMUX_GETABORT:
1328*0Sstevel@tonic-gate 		case TTYMUX_GETABORTSTR:
1329*0Sstevel@tonic-gate 		case TTYMUX_ASSOC:
1330*0Sstevel@tonic-gate 		case TTYMUX_DISASSOC:
1331*0Sstevel@tonic-gate 		case TTYMUX_SETCTL:
1332*0Sstevel@tonic-gate 		case TTYMUX_GETLINK:
1333*0Sstevel@tonic-gate 		case TTYMUX_CONSDEV:
1334*0Sstevel@tonic-gate 		case TTYMUX_GETCTL:
1335*0Sstevel@tonic-gate 		case TTYMUX_LIST:
1336*0Sstevel@tonic-gate 			(void) sm_ioctl_cmd(uqi, mp);
1337*0Sstevel@tonic-gate 			qreply(wq, mp);
1338*0Sstevel@tonic-gate 			break;
1339*0Sstevel@tonic-gate 		case I_LINK:
1340*0Sstevel@tonic-gate 		case I_PLINK:
1341*0Sstevel@tonic-gate 		case I_UNLINK:
1342*0Sstevel@tonic-gate 		case I_PUNLINK:
1343*0Sstevel@tonic-gate 			qwriter(wq, mp, sm_link_req, PERIM_OUTER);
1344*0Sstevel@tonic-gate 			break;
1345*0Sstevel@tonic-gate 		case TCSETSW:
1346*0Sstevel@tonic-gate 		case TCSETSF:
1347*0Sstevel@tonic-gate 		case TCSETAW:
1348*0Sstevel@tonic-gate 		case TCSETAF:
1349*0Sstevel@tonic-gate 		case TCSBRK:
1350*0Sstevel@tonic-gate 			if (wq->q_first) {
1351*0Sstevel@tonic-gate 				sm_dbg('A', ("sm_uwput: TCSET-> on srv q.\n"));
1352*0Sstevel@tonic-gate 				/* keep message order intact */
1353*0Sstevel@tonic-gate 				(void) putq(wq, mp);
1354*0Sstevel@tonic-gate 				break;
1355*0Sstevel@tonic-gate 			}
1356*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
1357*0Sstevel@tonic-gate 		default:
1358*0Sstevel@tonic-gate 			(void) sm_default_uwioctl(wq, mp, putq);
1359*0Sstevel@tonic-gate 			break;
1360*0Sstevel@tonic-gate 		}
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 		break; /* M_IOCTL */
1363*0Sstevel@tonic-gate 
1364*0Sstevel@tonic-gate 	} /* end switch on message type */
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate 	return (0);
1367*0Sstevel@tonic-gate }
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate /*
1370*0Sstevel@tonic-gate  * sm_uwsrv - service function for an upper STREAM write.
1371*0Sstevel@tonic-gate  * 'sm_uwsrv' takes a q parameter.	The q parameter specifies the queue
1372*0Sstevel@tonic-gate  * which is to be serviced.	This function reads the messages which are on
1373*0Sstevel@tonic-gate  * this service queue and passes them to the appropriate lower driver queue.
1374*0Sstevel@tonic-gate  */
1375*0Sstevel@tonic-gate static int
1376*0Sstevel@tonic-gate sm_uwsrv(queue_t *q)
1377*0Sstevel@tonic-gate {
1378*0Sstevel@tonic-gate 	mblk_t	*mp;
1379*0Sstevel@tonic-gate 	sm_uqi_t	*uqi = (sm_uqi_t *)(q->q_ptr);
1380*0Sstevel@tonic-gate 	int		msgtype;
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	ASSERT(q == SM_WQ(uqi));
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 	/*
1385*0Sstevel@tonic-gate 	 * Empty the queue unless explicitly stopped.
1386*0Sstevel@tonic-gate 	 */
1387*0Sstevel@tonic-gate 	while (mp = getq(q)) {
1388*0Sstevel@tonic-gate 		msgtype = DB_TYPE(mp);
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 		if (msgtype >= QPCTL && msgtype != M_IOCDATA)
1391*0Sstevel@tonic-gate 			if (sm_hp_uwput(q, mp)) {
1392*0Sstevel@tonic-gate 				sm_dbg('T', ("sm_uwsrv: flowcontrolled.\n"));
1393*0Sstevel@tonic-gate 				break; /* indicates that the is disabled */
1394*0Sstevel@tonic-gate 			}
1395*0Sstevel@tonic-gate 			else
1396*0Sstevel@tonic-gate 				continue;
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate 		if (uqi->sm_flags & SM_STOPPED) {
1399*0Sstevel@tonic-gate 			(void) putbq(q, mp);
1400*0Sstevel@tonic-gate 			sm_dbg('T', ("sm_uwsrv: SM_STOPPED.\n"));
1401*0Sstevel@tonic-gate 			break;
1402*0Sstevel@tonic-gate 		}
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 		/*
1405*0Sstevel@tonic-gate 		 * Read any ttycommon data that may
1406*0Sstevel@tonic-gate 		 * change (TS_SOFTCAR, CREAD, etc.).
1407*0Sstevel@tonic-gate 		 */
1408*0Sstevel@tonic-gate 		switch (DB_TYPE(mp)) {
1409*0Sstevel@tonic-gate 		case M_IOCTL:
1410*0Sstevel@tonic-gate 		case M_IOCDATA:
1411*0Sstevel@tonic-gate 			if (sm_default_uwioctl(q, mp, putbq))
1412*0Sstevel@tonic-gate 				return (0);
1413*0Sstevel@tonic-gate 			break;
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 		default:
1416*0Sstevel@tonic-gate 			if (sm_putqs(q, mp, putbq))
1417*0Sstevel@tonic-gate 				return (0);
1418*0Sstevel@tonic-gate 		}
1419*0Sstevel@tonic-gate 	}
1420*0Sstevel@tonic-gate 	return (0);
1421*0Sstevel@tonic-gate }
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate /*
1424*0Sstevel@tonic-gate  * Lower write side service routine used for backenabling upstream
1425*0Sstevel@tonic-gate  * flow control.
1426*0Sstevel@tonic-gate  */
1427*0Sstevel@tonic-gate static int
1428*0Sstevel@tonic-gate sm_lwsrv(queue_t *q)
1429*0Sstevel@tonic-gate {
1430*0Sstevel@tonic-gate 	sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr;
1431*0Sstevel@tonic-gate 	queue_t *uwq;
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	LOCK_UNIT(lqi);
1434*0Sstevel@tonic-gate 	if (lqi->sm_uqflags & SM_UQVALID) {
1435*0Sstevel@tonic-gate 		/*
1436*0Sstevel@tonic-gate 		 * It's safe to lock uqi since lwsrv runs asynchronously
1437*0Sstevel@tonic-gate 		 * with the upper write routines so this cannot be an
1438*0Sstevel@tonic-gate 		 * upper half thread. While holding the lqi lock and
1439*0Sstevel@tonic-gate 		 * if SM_UQVALID is set we are guaranteed that
1440*0Sstevel@tonic-gate 		 * lqi->sm_uqi will be valid.
1441*0Sstevel@tonic-gate 		 */
1442*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_lwsrv: re-enabling upper queue.\n"));
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 		uwq = SM_WQ(lqi->sm_uqi);
1445*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1446*0Sstevel@tonic-gate 		qenable(uwq);
1447*0Sstevel@tonic-gate 	} else  {
1448*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1449*0Sstevel@tonic-gate 	}
1450*0Sstevel@tonic-gate 	return (0);
1451*0Sstevel@tonic-gate }
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate /*
1454*0Sstevel@tonic-gate  * Upper read queue ioctl response handler for messages
1455*0Sstevel@tonic-gate  * passed from the lower half of the driver.
1456*0Sstevel@tonic-gate  */
1457*0Sstevel@tonic-gate static int
1458*0Sstevel@tonic-gate sm_uriocack(queue_t *rq, mblk_t *mp)
1459*0Sstevel@tonic-gate {
1460*0Sstevel@tonic-gate 	sm_uqi_t		*uqi = (sm_uqi_t *)rq->q_ptr;
1461*0Sstevel@tonic-gate 	int		err, flag;
1462*0Sstevel@tonic-gate 	sm_iocdata_t	*iodp;
1463*0Sstevel@tonic-gate 	struct sm_iocinfo	info;
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 	if ((err = sm_getiocinfo(mp, &info)) != 0) {
1466*0Sstevel@tonic-gate 		sm_dbg('I', ("Unknown ioctl response\n"));
1467*0Sstevel@tonic-gate 		return (err);
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 	if (info.sm_id == uqi->sm_piocdata.sm_iocid) {
1471*0Sstevel@tonic-gate 		iodp = &uqi->sm_piocdata;
1472*0Sstevel@tonic-gate 	} else if (info.sm_id == uqi->sm_siocdata.sm_iocid) {
1473*0Sstevel@tonic-gate 		iodp = &uqi->sm_siocdata;
1474*0Sstevel@tonic-gate 	} else {
1475*0Sstevel@tonic-gate 		sm_log("Unexpected ioctl response\n");
1476*0Sstevel@tonic-gate 		sm_dbg('I', ("Unexpected ioctl response (id %d)\n",
1477*0Sstevel@tonic-gate 				info.sm_id));
1478*0Sstevel@tonic-gate 
1479*0Sstevel@tonic-gate 		/*
1480*0Sstevel@tonic-gate 		 * If the response is sent up it will result in
1481*0Sstevel@tonic-gate 		 * duplicate ioctl responses. The ioctl has probably been
1482*0Sstevel@tonic-gate 		 * timed out by the stream head so dispose of the response
1483*0Sstevel@tonic-gate 		 * (since it has arrived too late.
1484*0Sstevel@tonic-gate 		 */
1485*0Sstevel@tonic-gate 		goto out;
1486*0Sstevel@tonic-gate 	}
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	flag = SM_COPYIN;
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1491*0Sstevel@tonic-gate 	case M_COPYOUT:
1492*0Sstevel@tonic-gate 		flag = SM_COPYOUT;
1493*0Sstevel@tonic-gate 		/*FALLTHRU*/
1494*0Sstevel@tonic-gate 	case M_COPYIN:
1495*0Sstevel@tonic-gate 		if (iodp->sm_flags & flag)
1496*0Sstevel@tonic-gate 			goto out;
1497*0Sstevel@tonic-gate 		iodp->sm_flags |= flag;
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 		break;
1500*0Sstevel@tonic-gate 	case M_IOCACK:
1501*0Sstevel@tonic-gate 		iodp->sm_ackcnt += 1;
1502*0Sstevel@tonic-gate 		iodp->sm_acnt += 1;
1503*0Sstevel@tonic-gate 		if (iodp->sm_policy == FIRSTACK) {
1504*0Sstevel@tonic-gate 			if (iodp->sm_acnt == iodp->sm_nacks)
1505*0Sstevel@tonic-gate 				iodp->sm_iocid = 0;
1506*0Sstevel@tonic-gate 			if (iodp->sm_acnt == 1)
1507*0Sstevel@tonic-gate 				iodp->sm_acked = 1;
1508*0Sstevel@tonic-gate 			else
1509*0Sstevel@tonic-gate 				goto out;
1510*0Sstevel@tonic-gate 		} else {
1511*0Sstevel@tonic-gate 			if (iodp->sm_acnt == iodp->sm_nacks) {
1512*0Sstevel@tonic-gate 				iodp->sm_iocid = 0;
1513*0Sstevel@tonic-gate 				iodp->sm_acked = 1;
1514*0Sstevel@tonic-gate 			} else
1515*0Sstevel@tonic-gate 				goto out;
1516*0Sstevel@tonic-gate 		}
1517*0Sstevel@tonic-gate 		break;
1518*0Sstevel@tonic-gate 	case M_IOCNAK:
1519*0Sstevel@tonic-gate 		iodp->sm_nakcnt += 1;
1520*0Sstevel@tonic-gate 		iodp->sm_acnt += 1;
1521*0Sstevel@tonic-gate 		if (iodp->sm_acnt == iodp->sm_nacks) {
1522*0Sstevel@tonic-gate 			iodp->sm_iocid = 0;
1523*0Sstevel@tonic-gate 			if (iodp->sm_acked == 0) {
1524*0Sstevel@tonic-gate 				iodp->sm_acked = 1;
1525*0Sstevel@tonic-gate 				break;
1526*0Sstevel@tonic-gate 			}
1527*0Sstevel@tonic-gate 		}
1528*0Sstevel@tonic-gate 		goto out;
1529*0Sstevel@tonic-gate 	default:
1530*0Sstevel@tonic-gate 		goto out;
1531*0Sstevel@tonic-gate 	}
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate 	/*
1534*0Sstevel@tonic-gate 	 * Merge the tty settings each of the associated lower streams.
1535*0Sstevel@tonic-gate 	 */
1536*0Sstevel@tonic-gate 	if (info.sm_data)
1537*0Sstevel@tonic-gate 		(void) sm_update_ttyinfo(mp, uqi);
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate 	if (iodp == &uqi->sm_piocdata) {
1540*0Sstevel@tonic-gate 		if (iodp->sm_iocid == 0) {
1541*0Sstevel@tonic-gate 			uqi->sm_flags &= ~SM_IOCPENDING;
1542*0Sstevel@tonic-gate 		}
1543*0Sstevel@tonic-gate 	} else {
1544*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_uriocack: forwarding response for %d.\n",
1545*0Sstevel@tonic-gate 		    info.sm_id));
1546*0Sstevel@tonic-gate 		putnext(rq, mp);
1547*0Sstevel@tonic-gate 		return (0);
1548*0Sstevel@tonic-gate 	}
1549*0Sstevel@tonic-gate out:
1550*0Sstevel@tonic-gate 	sm_dbg('I', ("sm_uriocack: freeing response for %d.\n", info.sm_id));
1551*0Sstevel@tonic-gate 	freemsg(mp);
1552*0Sstevel@tonic-gate 	return (0);
1553*0Sstevel@tonic-gate }
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate /*
1556*0Sstevel@tonic-gate  * Transfer a message from the lower read side of the multiplexer onto
1557*0Sstevel@tonic-gate  * the associated upper stream.
1558*0Sstevel@tonic-gate  */
1559*0Sstevel@tonic-gate static int
1560*0Sstevel@tonic-gate sm_ursendup(queue_t *q, mblk_t *mp)
1561*0Sstevel@tonic-gate {
1562*0Sstevel@tonic-gate 	sm_uqi_t	*uqi = (sm_uqi_t *)q->q_ptr;
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate 	if (!canputnext(q) && DB_TYPE(mp) < QPCTL) {
1565*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_ursendup: flow controlled.\n"));
1566*0Sstevel@tonic-gate 		return (1);
1567*0Sstevel@tonic-gate 	}
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1570*0Sstevel@tonic-gate 	case M_COPYIN:
1571*0Sstevel@tonic-gate 	case M_COPYOUT:
1572*0Sstevel@tonic-gate 	case M_IOCACK:
1573*0Sstevel@tonic-gate 	case M_IOCNAK:
1574*0Sstevel@tonic-gate 		(void) sm_uriocack(q, mp);
1575*0Sstevel@tonic-gate 		break;
1576*0Sstevel@tonic-gate 	case M_HANGUP:
1577*0Sstevel@tonic-gate 		if (sm_uwq_error(uqi)) {
1578*0Sstevel@tonic-gate 			/* there are no usable lower q's */
1579*0Sstevel@tonic-gate 			uqi->sm_flags &= ~SM_CARON;
1580*0Sstevel@tonic-gate 			putnext(q, mp);
1581*0Sstevel@tonic-gate 		} else {
1582*0Sstevel@tonic-gate 			/* there are still usable q's - don't send up */
1583*0Sstevel@tonic-gate 			freemsg(mp);
1584*0Sstevel@tonic-gate 		}
1585*0Sstevel@tonic-gate 		break;
1586*0Sstevel@tonic-gate 	case M_ERROR:
1587*0Sstevel@tonic-gate 		if (sm_uwq_error(uqi)) {
1588*0Sstevel@tonic-gate 			/* there are no usable lower q's */
1589*0Sstevel@tonic-gate 			uqi->sm_flags &= ~SM_CARON;
1590*0Sstevel@tonic-gate 			putnext(q, mp);
1591*0Sstevel@tonic-gate 		} else if (*mp->b_rptr == NOERROR) {
1592*0Sstevel@tonic-gate 			/* the error has cleared */
1593*0Sstevel@tonic-gate 			uqi->sm_flags &= ~ERROR_MODE;
1594*0Sstevel@tonic-gate 			putnext(q, mp);
1595*0Sstevel@tonic-gate 		} else {
1596*0Sstevel@tonic-gate 			/* there are still usable q's - don't send up */
1597*0Sstevel@tonic-gate 			freemsg(mp);
1598*0Sstevel@tonic-gate 		}
1599*0Sstevel@tonic-gate 		break;
1600*0Sstevel@tonic-gate 	case M_FLUSH:
1601*0Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
1602*0Sstevel@tonic-gate 		putnext(q, mp);	/* time to use FLUSHR_PEND flag */
1603*0Sstevel@tonic-gate 		break;
1604*0Sstevel@tonic-gate 	case M_CTL:
1605*0Sstevel@tonic-gate 		/* wrong direction - must have come from sm_close */
1606*0Sstevel@tonic-gate 		uqi->sm_flags |= SM_CLOSE;
1607*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_ursrv: had SM_CLOSE.\n"));
1608*0Sstevel@tonic-gate 		freemsg(mp);
1609*0Sstevel@tonic-gate 		break;
1610*0Sstevel@tonic-gate 	case M_UNHANGUP:
1611*0Sstevel@tonic-gate 		/* just pass them all up - they're harmless */
1612*0Sstevel@tonic-gate 		uqi->sm_flags |= SM_CARON;
1613*0Sstevel@tonic-gate 		/* FALLTHROUGH */
1614*0Sstevel@tonic-gate 	default:
1615*0Sstevel@tonic-gate 		putnext(q, mp);
1616*0Sstevel@tonic-gate 		break;
1617*0Sstevel@tonic-gate 	}
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	return (0);
1620*0Sstevel@tonic-gate }
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate /*
1623*0Sstevel@tonic-gate  * sm_urput - put function for a lower STREAM read.
1624*0Sstevel@tonic-gate  */
1625*0Sstevel@tonic-gate static int
1626*0Sstevel@tonic-gate sm_urput(queue_t *q, mblk_t *mp)
1627*0Sstevel@tonic-gate {
1628*0Sstevel@tonic-gate 	if (sm_ursendup(q, mp) != 0)
1629*0Sstevel@tonic-gate 		(void) putq(q, mp);
1630*0Sstevel@tonic-gate 
1631*0Sstevel@tonic-gate 	return (0);
1632*0Sstevel@tonic-gate }
1633*0Sstevel@tonic-gate 
1634*0Sstevel@tonic-gate /*
1635*0Sstevel@tonic-gate  * Upper read side service routine.
1636*0Sstevel@tonic-gate  * Read side needs to be fast so only check for duplicate M_IOCTL acks.
1637*0Sstevel@tonic-gate  */
1638*0Sstevel@tonic-gate static int
1639*0Sstevel@tonic-gate sm_ursrv(queue_t *q)
1640*0Sstevel@tonic-gate {
1641*0Sstevel@tonic-gate 	sm_uqi_t	*uqi = (sm_uqi_t *)q->q_ptr;
1642*0Sstevel@tonic-gate 	mblk_t	*mp;
1643*0Sstevel@tonic-gate 	int	flags = uqi->sm_flags;
1644*0Sstevel@tonic-gate 
1645*0Sstevel@tonic-gate 	while ((mp = getq(q))) {
1646*0Sstevel@tonic-gate 		if (sm_ursendup(q, mp) != 0) {
1647*0Sstevel@tonic-gate 			sm_dbg('I', ("sm_ursrv: flow controlled.\n"));
1648*0Sstevel@tonic-gate 			(void) putbq(q, mp);
1649*0Sstevel@tonic-gate 			uqi->sm_flags |= WANT_RENB;
1650*0Sstevel@tonic-gate 			break;
1651*0Sstevel@tonic-gate 		}
1652*0Sstevel@tonic-gate 	}
1653*0Sstevel@tonic-gate 
1654*0Sstevel@tonic-gate 	/*
1655*0Sstevel@tonic-gate 	 * If the q service was called because it was no longer
1656*0Sstevel@tonic-gate 	 * flow controled then enable each of the driver queues.
1657*0Sstevel@tonic-gate 	 */
1658*0Sstevel@tonic-gate 	if ((flags & WANT_RENB) && !(uqi->sm_flags & WANT_RENB)) {
1659*0Sstevel@tonic-gate 		sm_lqi_t *lqi;
1660*0Sstevel@tonic-gate 		queue_t *drq; /* read q of linked driver */
1661*0Sstevel@tonic-gate 
1662*0Sstevel@tonic-gate 		uqi->sm_flags &= ~WANT_RENB;
1663*0Sstevel@tonic-gate 		for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
1664*0Sstevel@tonic-gate 			drq = SM_RQ(lqi)->q_next;
1665*0Sstevel@tonic-gate 			if (drq && drq->q_first != 0)
1666*0Sstevel@tonic-gate 				qenable(drq);
1667*0Sstevel@tonic-gate 		}
1668*0Sstevel@tonic-gate 	}
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 	return (0);
1671*0Sstevel@tonic-gate }
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate /*
1674*0Sstevel@tonic-gate  * Check a message sent from a linked device for abort requests and
1675*0Sstevel@tonic-gate  * for flow control.
1676*0Sstevel@tonic-gate  */
1677*0Sstevel@tonic-gate static int
1678*0Sstevel@tonic-gate sm_lrmsg_check(queue_t *q, mblk_t *mp)
1679*0Sstevel@tonic-gate {
1680*0Sstevel@tonic-gate 	sm_lqi_t	*lqi	= (sm_lqi_t *)q->q_ptr;
1681*0Sstevel@tonic-gate 
1682*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1683*0Sstevel@tonic-gate 	case M_DATA:
1684*0Sstevel@tonic-gate 		LOCK_UNIT(lqi);
1685*0Sstevel@tonic-gate 		/*
1686*0Sstevel@tonic-gate 		 * check for abort - only allow abort on I/O consoles
1687*0Sstevel@tonic-gate 		 * known to OBP -
1688*0Sstevel@tonic-gate 		 * fix it when we do polled io
1689*0Sstevel@tonic-gate 		 */
1690*0Sstevel@tonic-gate 		if ((lqi->sm_ioflag & (uint_t)FORINPUT) == 0) {
1691*0Sstevel@tonic-gate 			freemsg(mp);
1692*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
1693*0Sstevel@tonic-gate 			return (1);
1694*0Sstevel@tonic-gate 		}
1695*0Sstevel@tonic-gate 		if ((lqi->sm_uqflags & SM_OBPCNDEV) &&
1696*0Sstevel@tonic-gate 		    lqi->sm_ctrla_abort_on &&
1697*0Sstevel@tonic-gate 		    abort_enable == KIOCABORTALTERNATE) {
1698*0Sstevel@tonic-gate 
1699*0Sstevel@tonic-gate 			uchar_t		*rxc;
1700*0Sstevel@tonic-gate 			boolean_t	aborted = B_FALSE;
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate 			for (rxc = mp->b_rptr;
1703*0Sstevel@tonic-gate 			    rxc != mp->b_wptr;
1704*0Sstevel@tonic-gate 			    rxc++)
1705*0Sstevel@tonic-gate 
1706*0Sstevel@tonic-gate 				if (*rxc == *lqi->sm_nachar) {
1707*0Sstevel@tonic-gate 					lqi->sm_nachar++;
1708*0Sstevel@tonic-gate 					if (*lqi->sm_nachar == '\0') {
1709*0Sstevel@tonic-gate 						abort_sequence_enter(
1710*0Sstevel@tonic-gate 							(char *)NULL);
1711*0Sstevel@tonic-gate 						lqi->sm_nachar = sm_ssp->sm_abs;
1712*0Sstevel@tonic-gate 						aborted = B_TRUE;
1713*0Sstevel@tonic-gate 					}
1714*0Sstevel@tonic-gate 				} else
1715*0Sstevel@tonic-gate 					lqi->sm_nachar = (*rxc == *sm_ssp->
1716*0Sstevel@tonic-gate 								sm_abs) ?
1717*0Sstevel@tonic-gate 								sm_ssp->
1718*0Sstevel@tonic-gate 								sm_abs + 1 :
1719*0Sstevel@tonic-gate 								sm_ssp->sm_abs;
1720*0Sstevel@tonic-gate 
1721*0Sstevel@tonic-gate 			if (aborted) {
1722*0Sstevel@tonic-gate 				freemsg(mp);
1723*0Sstevel@tonic-gate 				UNLOCK_UNIT(lqi);
1724*0Sstevel@tonic-gate 				return (1);
1725*0Sstevel@tonic-gate 			}
1726*0Sstevel@tonic-gate 		}
1727*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1728*0Sstevel@tonic-gate 		break;
1729*0Sstevel@tonic-gate 	case M_BREAK:	/* we'll eventually see this as a flush */
1730*0Sstevel@tonic-gate 		LOCK_UNIT(lqi);
1731*0Sstevel@tonic-gate 		/*
1732*0Sstevel@tonic-gate 		 * Only allow abort on OBP devices. When polled I/O is
1733*0Sstevel@tonic-gate 		 * supported allow abort on any console device.
1734*0Sstevel@tonic-gate 		 * Parity errors are reported upstream as breaks so
1735*0Sstevel@tonic-gate 		 * ensure that there is no data in the message before
1736*0Sstevel@tonic-gate 		 * deciding whether to abort.
1737*0Sstevel@tonic-gate 		 */
1738*0Sstevel@tonic-gate 		if ((lqi->sm_uqflags & SM_OBPCNDEV) && /* console stream */
1739*0Sstevel@tonic-gate 		    (mp->b_wptr - mp->b_rptr == 0 &&
1740*0Sstevel@tonic-gate 		    msgdsize(mp) == 0)) {	/* not due to parity */
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate 			if (lqi->sm_break_abort_on &&
1743*0Sstevel@tonic-gate 			    abort_enable != KIOCABORTALTERNATE)
1744*0Sstevel@tonic-gate 				abort_sequence_enter((char *)NULL);
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 			freemsg(mp);
1747*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
1748*0Sstevel@tonic-gate 			return (1);
1749*0Sstevel@tonic-gate 		} else {
1750*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
1751*0Sstevel@tonic-gate 		}
1752*0Sstevel@tonic-gate 		break;
1753*0Sstevel@tonic-gate 	default:
1754*0Sstevel@tonic-gate 		break;
1755*0Sstevel@tonic-gate 	}
1756*0Sstevel@tonic-gate 
1757*0Sstevel@tonic-gate 	if (DB_TYPE(mp) >= QPCTL)
1758*0Sstevel@tonic-gate 		return (0);
1759*0Sstevel@tonic-gate 
1760*0Sstevel@tonic-gate 	LOCK_UNIT(lqi); /* lock out the upper half */
1761*0Sstevel@tonic-gate 	if ((lqi->sm_uqflags & SM_UQVALID) && SM_RQ(lqi->sm_uqi)) {
1762*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1763*0Sstevel@tonic-gate 		if (!canput(SM_RQ(lqi->sm_uqi))) {
1764*0Sstevel@tonic-gate 			sm_dbg('I', ("sm_lrmsg_check: flow controlled.\n"));
1765*0Sstevel@tonic-gate 			(void) putq(q, mp);
1766*0Sstevel@tonic-gate 			return (1);
1767*0Sstevel@tonic-gate 		}
1768*0Sstevel@tonic-gate 	} else {
1769*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1770*0Sstevel@tonic-gate 	}
1771*0Sstevel@tonic-gate 
1772*0Sstevel@tonic-gate 	return (0);
1773*0Sstevel@tonic-gate }
1774*0Sstevel@tonic-gate 
1775*0Sstevel@tonic-gate /*
1776*0Sstevel@tonic-gate  * sm_sendup - deliver a message to the upper read side of the multiplexer
1777*0Sstevel@tonic-gate  */
1778*0Sstevel@tonic-gate static int
1779*0Sstevel@tonic-gate sm_sendup(queue_t *q, mblk_t *mp)
1780*0Sstevel@tonic-gate {
1781*0Sstevel@tonic-gate 	sm_lqi_t	*lqi	= (sm_lqi_t *)q->q_ptr;
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 	if (sm_ssp == NULL) {
1784*0Sstevel@tonic-gate 		freemsg(mp);
1785*0Sstevel@tonic-gate 		return (0);
1786*0Sstevel@tonic-gate 	}
1787*0Sstevel@tonic-gate 
1788*0Sstevel@tonic-gate 	/*
1789*0Sstevel@tonic-gate 	 * Check for CD status change messages from driver.
1790*0Sstevel@tonic-gate 	 * (Remark: this is an se driver thread running at soft interupt
1791*0Sstevel@tonic-gate 	 * priority and the waiters are in user context).
1792*0Sstevel@tonic-gate 	 */
1793*0Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1794*0Sstevel@tonic-gate 	case M_DATA:
1795*0Sstevel@tonic-gate 	case M_BREAK:	/* we'll eventually see this as a flush */
1796*0Sstevel@tonic-gate 		break;
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate 	/* high priority messages */
1799*0Sstevel@tonic-gate 	case M_IOCACK:
1800*0Sstevel@tonic-gate 	case M_IOCNAK:
1801*0Sstevel@tonic-gate 		if ((lqi->sm_flags & SM_IOCPENDING) && lqi->sm_piocid ==
1802*0Sstevel@tonic-gate 		    ((struct iocblk *)mp->b_rptr)->ioc_id) {
1803*0Sstevel@tonic-gate 			freemsg(mp);
1804*0Sstevel@tonic-gate 			lqi->sm_flags &= ~SM_IOCPENDING;
1805*0Sstevel@tonic-gate 			sm_issue_ioctl(lqi);
1806*0Sstevel@tonic-gate 			return (0);
1807*0Sstevel@tonic-gate 		}
1808*0Sstevel@tonic-gate 		break;
1809*0Sstevel@tonic-gate 	case M_UNHANGUP:
1810*0Sstevel@tonic-gate 		/*
1811*0Sstevel@tonic-gate 		 * If the driver can send an M_UNHANGUP it must be able to
1812*0Sstevel@tonic-gate 		 * accept messages from above (ie clear WERROR_MODE if set).
1813*0Sstevel@tonic-gate 		 */
1814*0Sstevel@tonic-gate 		sm_dbg('E', ("lrput: M_UNHANGUP\n"));
1815*0Sstevel@tonic-gate 		lqi->sm_mbits |= TIOCM_CD;
1816*0Sstevel@tonic-gate 		lqi->sm_flags &= ~(WERROR_MODE|HANGUP_MODE);
1817*0Sstevel@tonic-gate 
1818*0Sstevel@tonic-gate 		break;
1819*0Sstevel@tonic-gate 
1820*0Sstevel@tonic-gate 	case M_HANGUP:
1821*0Sstevel@tonic-gate 		sm_dbg('E', ("lrput: MHANGUP\n"));
1822*0Sstevel@tonic-gate 		lqi->sm_mbits &= ~TIOCM_CD;
1823*0Sstevel@tonic-gate 		lqi->sm_flags |= (WERROR_MODE|HANGUP_MODE);
1824*0Sstevel@tonic-gate 		break;
1825*0Sstevel@tonic-gate 
1826*0Sstevel@tonic-gate 	case M_ERROR:
1827*0Sstevel@tonic-gate 
1828*0Sstevel@tonic-gate 		sm_dbg('E', ("lrput: MERROR\n"));
1829*0Sstevel@tonic-gate 		/*
1830*0Sstevel@tonic-gate 		 * Tell the driver to flush rd/wr queue if its read/write error.
1831*0Sstevel@tonic-gate 		 * if its a read/write error flush rq/wq (type in first bytes).
1832*0Sstevel@tonic-gate 		 */
1833*0Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) == 2) {
1834*0Sstevel@tonic-gate 			uchar_t	rw = 0;
1835*0Sstevel@tonic-gate 
1836*0Sstevel@tonic-gate 			if (*mp->b_rptr == NOERROR) {
1837*0Sstevel@tonic-gate 				/* not in error anymore */
1838*0Sstevel@tonic-gate 				lqi->sm_flags &= ~ERROR_MODE;
1839*0Sstevel@tonic-gate 				lqi->sm_flags |= WANT_CD;
1840*0Sstevel@tonic-gate 			} else {
1841*0Sstevel@tonic-gate 				if (*mp->b_rptr != 0) {
1842*0Sstevel@tonic-gate 					/* read error */
1843*0Sstevel@tonic-gate 					rw |= FLUSHR;
1844*0Sstevel@tonic-gate 					lqi->sm_flags |= RERROR_MODE;
1845*0Sstevel@tonic-gate 				}
1846*0Sstevel@tonic-gate 				mp->b_rptr++;
1847*0Sstevel@tonic-gate 				if (*mp->b_rptr != 0) {
1848*0Sstevel@tonic-gate 					/* write error */
1849*0Sstevel@tonic-gate 					rw |= FLUSHW;
1850*0Sstevel@tonic-gate 					lqi->sm_flags |= WERROR_MODE;
1851*0Sstevel@tonic-gate 				}
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 				mp->b_rptr--;
1854*0Sstevel@tonic-gate 				/* has next driver done qprocsoff */
1855*0Sstevel@tonic-gate 				if (rw && OTHERQ(q)->q_next != NULL) {
1856*0Sstevel@tonic-gate 					(void) putnextctl1(OTHERQ(q), M_FLUSH,
1857*0Sstevel@tonic-gate 						rw);
1858*0Sstevel@tonic-gate 				}
1859*0Sstevel@tonic-gate 			}
1860*0Sstevel@tonic-gate 		} else if (*mp->b_rptr != 0 && OTHERQ(q)->q_next != NULL) {
1861*0Sstevel@tonic-gate 			sm_dbg('E', ("lrput: old style MERROR (?)\n"));
1862*0Sstevel@tonic-gate 
1863*0Sstevel@tonic-gate 			lqi->sm_flags |= (RERROR_MODE | WERROR_MODE);
1864*0Sstevel@tonic-gate 			(void) putnextctl1(OTHERQ(q), M_FLUSH, FLUSHRW);
1865*0Sstevel@tonic-gate 		}
1866*0Sstevel@tonic-gate 		break;
1867*0Sstevel@tonic-gate 
1868*0Sstevel@tonic-gate 	case M_PCSIG:
1869*0Sstevel@tonic-gate 	case M_SIG:
1870*0Sstevel@tonic-gate 		break;
1871*0Sstevel@tonic-gate 	case M_COPYOUT:
1872*0Sstevel@tonic-gate 	case M_COPYIN:
1873*0Sstevel@tonic-gate 		break;
1874*0Sstevel@tonic-gate 	case M_FLUSH:
1875*0Sstevel@tonic-gate 		/* flush the read queue and pass on up */
1876*0Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
1877*0Sstevel@tonic-gate 		break;
1878*0Sstevel@tonic-gate 	default:
1879*0Sstevel@tonic-gate 		break;
1880*0Sstevel@tonic-gate 	}
1881*0Sstevel@tonic-gate 
1882*0Sstevel@tonic-gate 	LOCK_UNIT(lqi); /* lock out the upper half */
1883*0Sstevel@tonic-gate 	if (lqi->sm_uqflags & SM_UQVALID && SM_RQ(lqi->sm_uqi)) {
1884*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
1885*0Sstevel@tonic-gate 		(void) putq(SM_RQ(lqi->sm_uqi), mp);
1886*0Sstevel@tonic-gate 		return (0);
1887*0Sstevel@tonic-gate 	} else {
1888*0Sstevel@tonic-gate 		sm_dbg('I', ("sm_sendup: uq not valid\n"));
1889*0Sstevel@tonic-gate 		freemsg(mp);
1890*0Sstevel@tonic-gate 	}
1891*0Sstevel@tonic-gate 	UNLOCK_UNIT(lqi);
1892*0Sstevel@tonic-gate 
1893*0Sstevel@tonic-gate 	return (0);
1894*0Sstevel@tonic-gate }
1895*0Sstevel@tonic-gate 
1896*0Sstevel@tonic-gate /*
1897*0Sstevel@tonic-gate  * sm_lrput - put function for a lower STREAM read.
1898*0Sstevel@tonic-gate  */
1899*0Sstevel@tonic-gate static int
1900*0Sstevel@tonic-gate sm_lrput(queue_t *q, mblk_t *mp)
1901*0Sstevel@tonic-gate {
1902*0Sstevel@tonic-gate 	if (sm_lrmsg_check(q, mp) == 0)
1903*0Sstevel@tonic-gate 		(void) sm_sendup(q, mp);
1904*0Sstevel@tonic-gate 	return (0);
1905*0Sstevel@tonic-gate }
1906*0Sstevel@tonic-gate 
1907*0Sstevel@tonic-gate /*
1908*0Sstevel@tonic-gate  * sm_lrsrv - service function for the lower read STREAM.
1909*0Sstevel@tonic-gate  */
1910*0Sstevel@tonic-gate static int
1911*0Sstevel@tonic-gate sm_lrsrv(queue_t *q)
1912*0Sstevel@tonic-gate {
1913*0Sstevel@tonic-gate 	mblk_t	*mp;
1914*0Sstevel@tonic-gate 
1915*0Sstevel@tonic-gate 	sm_dbg('I', ("sm_lrsrv: not controlled.\n"));
1916*0Sstevel@tonic-gate 	while (mp = getq(q))
1917*0Sstevel@tonic-gate 		(void) sm_sendup(q, mp);
1918*0Sstevel@tonic-gate 
1919*0Sstevel@tonic-gate 	return (0);
1920*0Sstevel@tonic-gate }
1921*0Sstevel@tonic-gate 
1922*0Sstevel@tonic-gate /*
1923*0Sstevel@tonic-gate  * Check whether a thread is allowed to open the requested device.
1924*0Sstevel@tonic-gate  */
1925*0Sstevel@tonic-gate static int
1926*0Sstevel@tonic-gate sm_ok_to_open(sm_uqi_t *uqi, int protocol, cred_t *credp, int *abort_waiters)
1927*0Sstevel@tonic-gate {
1928*0Sstevel@tonic-gate 	int rval = 0;
1929*0Sstevel@tonic-gate 	int proto;
1930*0Sstevel@tonic-gate 
1931*0Sstevel@tonic-gate 	*abort_waiters = 0;
1932*0Sstevel@tonic-gate 
1933*0Sstevel@tonic-gate 	switch (protocol) {
1934*0Sstevel@tonic-gate 		case ASYNC_DEVICE: /* Standard async protocol */
1935*0Sstevel@tonic-gate 		if ((uqi->sm_protocol == NULL_PROTOCOL) ||
1936*0Sstevel@tonic-gate 			(uqi->sm_protocol == ASYN_PROTOCOL)) {
1937*0Sstevel@tonic-gate 			/*
1938*0Sstevel@tonic-gate 			 * Lock out other incompatible protocol requests.
1939*0Sstevel@tonic-gate 			 */
1940*0Sstevel@tonic-gate 			proto = ASYN_PROTOCOL;
1941*0Sstevel@tonic-gate 			rval = 0;
1942*0Sstevel@tonic-gate 		} else
1943*0Sstevel@tonic-gate 			rval = EBUSY;
1944*0Sstevel@tonic-gate 		break;
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate 		case OUTLINE:	/* Outdial protocol */
1947*0Sstevel@tonic-gate 		if ((uqi->sm_protocol == NULL_PROTOCOL) ||
1948*0Sstevel@tonic-gate 			(uqi->sm_protocol == OUTD_PROTOCOL)) {
1949*0Sstevel@tonic-gate 			proto = OUTD_PROTOCOL;
1950*0Sstevel@tonic-gate 			rval = 0;
1951*0Sstevel@tonic-gate 		} else if (uqi->sm_protocol == ASYN_PROTOCOL) {
1952*0Sstevel@tonic-gate 			/*
1953*0Sstevel@tonic-gate 			 * check for dialout request on a line that is already
1954*0Sstevel@tonic-gate 			 * open for dial in:
1955*0Sstevel@tonic-gate 			 * kick off any thread that is waiting to fully open
1956*0Sstevel@tonic-gate 			 */
1957*0Sstevel@tonic-gate 			if (uqi->sm_flags & FULLY_OPEN)
1958*0Sstevel@tonic-gate 				rval = EBUSY;
1959*0Sstevel@tonic-gate 			else {
1960*0Sstevel@tonic-gate 				proto = OUTD_PROTOCOL;
1961*0Sstevel@tonic-gate 				*abort_waiters = 1;
1962*0Sstevel@tonic-gate 			}
1963*0Sstevel@tonic-gate 		} else
1964*0Sstevel@tonic-gate 			rval = EBUSY;
1965*0Sstevel@tonic-gate 		break;
1966*0Sstevel@tonic-gate 		default:
1967*0Sstevel@tonic-gate 			rval = ENOTSUP;
1968*0Sstevel@tonic-gate 	}
1969*0Sstevel@tonic-gate 
1970*0Sstevel@tonic-gate 	if (rval == 0 &&
1971*0Sstevel@tonic-gate 		(uqi->sm_ttycommon->t_flags & TS_XCLUDE) &&
1972*0Sstevel@tonic-gate 		secpolicy_excl_open(credp) != 0) {
1973*0Sstevel@tonic-gate 
1974*0Sstevel@tonic-gate 		if (uqi->sm_flags & FULLY_OPEN) {
1975*0Sstevel@tonic-gate 			rval = EBUSY; /* exclusive device already open */
1976*0Sstevel@tonic-gate 		} else {
1977*0Sstevel@tonic-gate 			/* NB TS_XCLUDE cant be set during open so NOTREACHED */
1978*0Sstevel@tonic-gate 			/* force any waiters to yield TS_XCLUDE */
1979*0Sstevel@tonic-gate 			*abort_waiters = 1;
1980*0Sstevel@tonic-gate 		}
1981*0Sstevel@tonic-gate 	}
1982*0Sstevel@tonic-gate 
1983*0Sstevel@tonic-gate 	if (rval == 0)
1984*0Sstevel@tonic-gate 		uqi->sm_protocol = proto;
1985*0Sstevel@tonic-gate 
1986*0Sstevel@tonic-gate 	sm_dbg('A', ("ok_to_open (0x%p, %d) proto=%d rval %d (wabort=%d)",
1987*0Sstevel@tonic-gate 		uqi, protocol, uqi->sm_protocol, rval, *abort_waiters));
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate 	return (rval);
1990*0Sstevel@tonic-gate }
1991*0Sstevel@tonic-gate 
1992*0Sstevel@tonic-gate /* wait for memory to become available whilst performing a qwait */
1993*0Sstevel@tonic-gate /*ARGSUSED*/
1994*0Sstevel@tonic-gate static void dummy_callback(void *arg)
1995*0Sstevel@tonic-gate {}
1996*0Sstevel@tonic-gate 
1997*0Sstevel@tonic-gate /* ARGSUSED */
1998*0Sstevel@tonic-gate static int
1999*0Sstevel@tonic-gate sm_dump_msg(queue_t *q, mblk_t *mp)
2000*0Sstevel@tonic-gate {
2001*0Sstevel@tonic-gate 	freemsg(mp);
2002*0Sstevel@tonic-gate 	return (0);
2003*0Sstevel@tonic-gate }
2004*0Sstevel@tonic-gate 
2005*0Sstevel@tonic-gate /*
2006*0Sstevel@tonic-gate  * Wait for a message to arrive - must be called with exclusive
2007*0Sstevel@tonic-gate  * access at the outer perimiter.
2008*0Sstevel@tonic-gate  */
2009*0Sstevel@tonic-gate static int
2010*0Sstevel@tonic-gate sm_qwait_sig(sm_uqi_t *uqi, queue_t *q)
2011*0Sstevel@tonic-gate {
2012*0Sstevel@tonic-gate 	int err;
2013*0Sstevel@tonic-gate 
2014*0Sstevel@tonic-gate 	sm_dbg('C', ("sm_qwait_sig: waiting.\n"));
2015*0Sstevel@tonic-gate 
2016*0Sstevel@tonic-gate 	uqi->sm_waitq = q;
2017*0Sstevel@tonic-gate 	uqi->sm_nwaiters++;	/* required by the close routine */
2018*0Sstevel@tonic-gate 	err = qwait_sig(q);
2019*0Sstevel@tonic-gate 	if (--uqi->sm_nwaiters == 0)
2020*0Sstevel@tonic-gate 		uqi->sm_waitq = 0;
2021*0Sstevel@tonic-gate 
2022*0Sstevel@tonic-gate 	if (err == 0)
2023*0Sstevel@tonic-gate 		err = EINTR;
2024*0Sstevel@tonic-gate 	else if (q->q_ptr == 0) /* can happen if there are multiple waiters */
2025*0Sstevel@tonic-gate 		err = -1;
2026*0Sstevel@tonic-gate 	else if (uqi->sm_flags & SM_CLOSE) {
2027*0Sstevel@tonic-gate 		uqi->sm_flags &= ~SM_CLOSE;
2028*0Sstevel@tonic-gate 		err = 1;	/* a different protocol has closed its stream */
2029*0Sstevel@tonic-gate 	}
2030*0Sstevel@tonic-gate 	else
2031*0Sstevel@tonic-gate 		err = 0;	/* was worth waiting for */
2032*0Sstevel@tonic-gate 
2033*0Sstevel@tonic-gate 	sm_dbg('C', ("sm_qwait_sig: rval %d\n", err));
2034*0Sstevel@tonic-gate 	return (err);
2035*0Sstevel@tonic-gate }
2036*0Sstevel@tonic-gate 
2037*0Sstevel@tonic-gate /*
2038*0Sstevel@tonic-gate  * Defer the opening of one the drivers devices until the state of each
2039*0Sstevel@tonic-gate  * associated lower stream is known.
2040*0Sstevel@tonic-gate  */
2041*0Sstevel@tonic-gate static int
2042*0Sstevel@tonic-gate sm_defer_open(sm_uqi_t *uqi, queue_t *q)
2043*0Sstevel@tonic-gate {
2044*0Sstevel@tonic-gate 	uint_t cmdflags = WANT_CDSTAT;
2045*0Sstevel@tonic-gate 	int err, nqs;
2046*0Sstevel@tonic-gate 
2047*0Sstevel@tonic-gate 	while ((nqs = sm_good_qs(uqi)) == 0) {
2048*0Sstevel@tonic-gate 		sm_dbg('C', ("sm_defer_open: no good qs\n"));
2049*0Sstevel@tonic-gate 		if (err = sm_qwait_sig(uqi, q))
2050*0Sstevel@tonic-gate 			return (err);
2051*0Sstevel@tonic-gate 	}
2052*0Sstevel@tonic-gate 
2053*0Sstevel@tonic-gate 	while ((uqi->sm_flags & SM_CARON) == 0) {
2054*0Sstevel@tonic-gate 		int iocmd;
2055*0Sstevel@tonic-gate 		mblk_t *pioc;
2056*0Sstevel@tonic-gate 
2057*0Sstevel@tonic-gate 		sm_dbg('C', ("sm_defer_open: flags 0x%x cmdflags 0x%x\n",
2058*0Sstevel@tonic-gate 					uqi->sm_flags, cmdflags));
2059*0Sstevel@tonic-gate 		if (cmdflags == 0) {
2060*0Sstevel@tonic-gate 			if (err = sm_qwait_sig(uqi, q))
2061*0Sstevel@tonic-gate 				return (err);
2062*0Sstevel@tonic-gate 			continue;	/* waiting for an M_UNHANGUP */
2063*0Sstevel@tonic-gate 		} else if (cmdflags & WANT_SC) {
2064*0Sstevel@tonic-gate 			cmdflags &= ~WANT_SC;
2065*0Sstevel@tonic-gate 			iocmd = TIOCGSOFTCAR;
2066*0Sstevel@tonic-gate 		} else if (cmdflags & WANT_CD) {
2067*0Sstevel@tonic-gate 			cmdflags &= ~WANT_CD;
2068*0Sstevel@tonic-gate 			iocmd = TIOCMGET;
2069*0Sstevel@tonic-gate 		} else if (cmdflags & WANT_CL) {
2070*0Sstevel@tonic-gate 			cmdflags &= ~WANT_CL;
2071*0Sstevel@tonic-gate 			iocmd = TCGETS;
2072*0Sstevel@tonic-gate 		}
2073*0Sstevel@tonic-gate 
2074*0Sstevel@tonic-gate 		if (uqi->sm_piocdata.sm_iocid == 0) {
2075*0Sstevel@tonic-gate 			while ((pioc = mkiocb(iocmd)) == 0) {
2076*0Sstevel@tonic-gate 				bufcall_id_t id =
2077*0Sstevel@tonic-gate 					qbufcall(q, sizeof (struct iocblk),
2078*0Sstevel@tonic-gate 					BPRI_MED, dummy_callback, 0);
2079*0Sstevel@tonic-gate 				if (err = sm_qwait_sig(uqi, q)) {
2080*0Sstevel@tonic-gate 					/* wait for the bufcall */
2081*0Sstevel@tonic-gate 					qunbufcall(q, id);
2082*0Sstevel@tonic-gate 					return (err);
2083*0Sstevel@tonic-gate 				}
2084*0Sstevel@tonic-gate 				qunbufcall(q, id);
2085*0Sstevel@tonic-gate 			}
2086*0Sstevel@tonic-gate 
2087*0Sstevel@tonic-gate 			uqi->sm_flags |= SM_IOCPENDING;
2088*0Sstevel@tonic-gate 
2089*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_iocid =
2090*0Sstevel@tonic-gate 			    ((struct iocblk *)pioc->b_rptr)->ioc_id;
2091*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_acked = 0;
2092*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_nacks = nqs;
2093*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_acnt = 0;
2094*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_ackcnt = uqi->
2095*0Sstevel@tonic-gate 					sm_piocdata.sm_nakcnt = 0;
2096*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_policy = uqi->sm_policy;
2097*0Sstevel@tonic-gate 			uqi->sm_piocdata.sm_flags = SM_INTERNALIOC;
2098*0Sstevel@tonic-gate 			if (sm_putqs(WR(q), pioc, sm_dump_msg) != 0) {
2099*0Sstevel@tonic-gate 				uqi->sm_piocdata.sm_iocid = 0;
2100*0Sstevel@tonic-gate 				sm_log("sm_defer_open: bad putqs\n");
2101*0Sstevel@tonic-gate 				return (-1);
2102*0Sstevel@tonic-gate 			}
2103*0Sstevel@tonic-gate 		}
2104*0Sstevel@tonic-gate 
2105*0Sstevel@tonic-gate 		sm_dbg('C', ("sm_defer_open: flags 0x%x\n", uqi->sm_flags));
2106*0Sstevel@tonic-gate 		while ((uqi->sm_flags & SM_CARON) == 0 &&
2107*0Sstevel@tonic-gate 		    (uqi->sm_flags & SM_IOCPENDING) != 0)
2108*0Sstevel@tonic-gate 			if (err = sm_qwait_sig(uqi, q))
2109*0Sstevel@tonic-gate 				return (err);
2110*0Sstevel@tonic-gate 
2111*0Sstevel@tonic-gate 		sm_dbg('C', ("defer_open: uq flags 0x%x.\n", uqi->sm_flags));
2112*0Sstevel@tonic-gate 	}
2113*0Sstevel@tonic-gate 	sm_dbg('C', ("defer_open: return 0.\n"));
2114*0Sstevel@tonic-gate 	return (0);
2115*0Sstevel@tonic-gate }
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate static int
2118*0Sstevel@tonic-gate sm_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2119*0Sstevel@tonic-gate {
2120*0Sstevel@tonic-gate 	int		ftstat;
2121*0Sstevel@tonic-gate 	int		unit;
2122*0Sstevel@tonic-gate 	int		protocol;
2123*0Sstevel@tonic-gate 	sm_uqi_t		*uqi;
2124*0Sstevel@tonic-gate 	int		abort_waiters;
2125*0Sstevel@tonic-gate 
2126*0Sstevel@tonic-gate 	if (sm_ssp == NULL)
2127*0Sstevel@tonic-gate 		return (ENXIO);
2128*0Sstevel@tonic-gate 	/*
2129*0Sstevel@tonic-gate 	 * sflag = 0 => streams device.
2130*0Sstevel@tonic-gate 	 */
2131*0Sstevel@tonic-gate 	if (sflag != 0 || DEV_TO_UNIT(*devp) >= NLUNITS) {
2132*0Sstevel@tonic-gate 		sm_dbg('C', ("open: sflag=%d or bad dev_t.\n", sflag));
2133*0Sstevel@tonic-gate 		return (ENXIO);
2134*0Sstevel@tonic-gate 	}
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 	unit = DEV_TO_UNIT(*devp);
2137*0Sstevel@tonic-gate 	protocol = DEV_TO_PROTOBITS(*devp);
2138*0Sstevel@tonic-gate 
2139*0Sstevel@tonic-gate 	uqi = get_uqi(sm_ssp, unit);
2140*0Sstevel@tonic-gate 
2141*0Sstevel@tonic-gate 	sm_dbg('C', ("open(0x%p, %d, 0x%x) :- unit=%d, proto=%d, uqi=0x%p\n",
2142*0Sstevel@tonic-gate 		rq, *devp, flag, unit, protocol, uqi));
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate 	if (uqi == 0)
2145*0Sstevel@tonic-gate 		return (ENXIO);
2146*0Sstevel@tonic-gate 
2147*0Sstevel@tonic-gate 	if (sm_refuse_opens && unit > smctlunit && uqi->sm_nlqs == 0)
2148*0Sstevel@tonic-gate 		return (ENXIO);
2149*0Sstevel@tonic-gate 
2150*0Sstevel@tonic-gate 	if (uqi->sm_flags & EXCL_OPEN && (flag & FEXCL)) {
2151*0Sstevel@tonic-gate 		return (EBUSY); /* device in use */
2152*0Sstevel@tonic-gate 	}
2153*0Sstevel@tonic-gate 
2154*0Sstevel@tonic-gate 	if ((flag & FEXCL)) {
2155*0Sstevel@tonic-gate 		if (secpolicy_excl_open(credp) != 0)
2156*0Sstevel@tonic-gate 			return (EPERM);
2157*0Sstevel@tonic-gate 
2158*0Sstevel@tonic-gate 		if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_nwaiters > 0)
2159*0Sstevel@tonic-gate 			return (EBUSY); /* device in use */
2160*0Sstevel@tonic-gate 
2161*0Sstevel@tonic-gate 		uqi->sm_flags |= EXCL_OPEN;
2162*0Sstevel@tonic-gate 	}
2163*0Sstevel@tonic-gate 
2164*0Sstevel@tonic-gate 	if (uqi->sm_protocol == NULL_PROTOCOL) {
2165*0Sstevel@tonic-gate 		struct termios *termiosp;
2166*0Sstevel@tonic-gate 		int len;
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(),
2169*0Sstevel@tonic-gate 		    DDI_PROP_NOTPROM, "ttymodes", (caddr_t)&termiosp, &len)
2170*0Sstevel@tonic-gate 		    == DDI_PROP_SUCCESS &&
2171*0Sstevel@tonic-gate 		    (len == sizeof (struct termios))) {
2172*0Sstevel@tonic-gate 
2173*0Sstevel@tonic-gate 			sm_dbg('C', ("open: c_cflag=0x%x\n",
2174*0Sstevel@tonic-gate 				termiosp->c_cflag));
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_iflag = termiosp->c_iflag;
2177*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_cflag = termiosp->c_cflag;
2178*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_stopc = termiosp->c_cc[VSTOP];
2179*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_startc = termiosp->c_cc[VSTART];
2180*0Sstevel@tonic-gate 
2181*0Sstevel@tonic-gate 			/*
2182*0Sstevel@tonic-gate 			 * IGNBRK,BRKINT,INPCK,IXON,IXANY,IXOFF - drivers
2183*0Sstevel@tonic-gate 			 * PARMRK,IGNPAR,ISTRIP - how to report parity
2184*0Sstevel@tonic-gate 			 * INLCR,IGNCR,ICRNL,IUCLC - ldterm (sophisticated I/O)
2185*0Sstevel@tonic-gate 			 * IXON, IXANY, IXOFF - flow control input
2186*0Sstevel@tonic-gate 			 * CBAUD,CSIZE,CS5-8,CSTOPB,PARENB,PARODD,HUPCL,
2187*0Sstevel@tonic-gate 			 * RCV1EN,XMT1EN,LOBLK,XCLUDE,CRTSXOFF,CRTSCTS,
2188*0Sstevel@tonic-gate 			 * CIBAUD,PAREXT,CBAUDEXT,CIBAUDEXT,CREAD,CLOCAL
2189*0Sstevel@tonic-gate 			 */
2190*0Sstevel@tonic-gate 
2191*0Sstevel@tonic-gate 			kmem_free(termiosp, len);
2192*0Sstevel@tonic-gate 		}
2193*0Sstevel@tonic-gate 		else
2194*0Sstevel@tonic-gate 			bzero((caddr_t)uqi->sm_ttycommon,
2195*0Sstevel@tonic-gate 				sizeof (uqi->sm_ttycommon));
2196*0Sstevel@tonic-gate 
2197*0Sstevel@tonic-gate 		if (*devp == rconsdev) {
2198*0Sstevel@tonic-gate 			uqi->sm_cmask = sm_cmask;
2199*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_flags |= TS_SOFTCAR;
2200*0Sstevel@tonic-gate 		} else {
2201*0Sstevel@tonic-gate 			uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR;
2202*0Sstevel@tonic-gate 		}
2203*0Sstevel@tonic-gate 
2204*0Sstevel@tonic-gate 		/*
2205*0Sstevel@tonic-gate 		 * Clear the default CLOCAL and TS_SOFTCAR flags since
2206*0Sstevel@tonic-gate 		 * they must correspond to the settings on the real devices.
2207*0Sstevel@tonic-gate 		 */
2208*0Sstevel@tonic-gate 
2209*0Sstevel@tonic-gate 		uqi->sm_ttycommon->t_cflag &= ~(uqi->sm_cmask|CLOCAL);
2210*0Sstevel@tonic-gate 		uqi->sm_mbits = 0;
2211*0Sstevel@tonic-gate 		uqi->sm_policy = FIRSTACK;
2212*0Sstevel@tonic-gate 		if (unit == 0 && sm_ssp->sm_ms == 0)
2213*0Sstevel@tonic-gate 			sm_ssp->sm_ms = (sm_mux_state_t *)
2214*0Sstevel@tonic-gate 						space_fetch(TTYMUXPTR);
2215*0Sstevel@tonic-gate 		if (sm_ssp->sm_ms) {
2216*0Sstevel@tonic-gate 			if (sm_ssp->sm_ms->sm_cons_stdin.sm_dev == *devp ||
2217*0Sstevel@tonic-gate 			    sm_ssp->sm_ms->sm_cons_stdout.sm_dev == *devp)
2218*0Sstevel@tonic-gate 				sm_ssp->sm_lconsole = uqi;
2219*0Sstevel@tonic-gate 		}
2220*0Sstevel@tonic-gate 	}
2221*0Sstevel@tonic-gate 
2222*0Sstevel@tonic-gate 	/*
2223*0Sstevel@tonic-gate 	 * Does this thread need to wait?
2224*0Sstevel@tonic-gate 	 */
2225*0Sstevel@tonic-gate 
2226*0Sstevel@tonic-gate 	sm_dbg('C', ("sm_open: %d %d 0x%p 0x%x\n",
2227*0Sstevel@tonic-gate 	    !(flag & (FNDELAY|FNONBLOCK)), !(protocol == OUTLINE), uqi->sm_lqs,
2228*0Sstevel@tonic-gate 	    uqi->sm_flags));
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate tryopen:
2231*0Sstevel@tonic-gate 
2232*0Sstevel@tonic-gate 	abort_waiters = 0;
2233*0Sstevel@tonic-gate 	if (ftstat = sm_ok_to_open(uqi, protocol, credp, &abort_waiters)) {
2234*0Sstevel@tonic-gate 		sm_dbg('C', ("open failed stat=%d.\n", ftstat));
2235*0Sstevel@tonic-gate 
2236*0Sstevel@tonic-gate 		if ((uqi->sm_flags & FULLY_OPEN) == 0 && uqi->sm_nwaiters == 0)
2237*0Sstevel@tonic-gate 			uqi->sm_protocol = NULL_PROTOCOL;
2238*0Sstevel@tonic-gate 		if (flag & FEXCL)
2239*0Sstevel@tonic-gate 			uqi->sm_flags &= ~EXCL_OPEN;
2240*0Sstevel@tonic-gate 		return (ftstat);
2241*0Sstevel@tonic-gate 	}
2242*0Sstevel@tonic-gate 
2243*0Sstevel@tonic-gate 	if (abort_waiters) {
2244*0Sstevel@tonic-gate 		uqi->sm_dev = *devp;
2245*0Sstevel@tonic-gate 		/* different device wants to use the unit */
2246*0Sstevel@tonic-gate 		SM_RQ(uqi) = rq;
2247*0Sstevel@tonic-gate 		SM_WQ(uqi) = WR(rq);
2248*0Sstevel@tonic-gate 	}
2249*0Sstevel@tonic-gate 	if (rq->q_ptr == 0) {
2250*0Sstevel@tonic-gate 		sm_lqi_t *lqi;
2251*0Sstevel@tonic-gate 
2252*0Sstevel@tonic-gate 		uqi->sm_dev = *devp;
2253*0Sstevel@tonic-gate 		rq->q_ptr = WR(rq)->q_ptr = uqi;
2254*0Sstevel@tonic-gate 		SM_RQ(uqi) = rq;
2255*0Sstevel@tonic-gate 		SM_WQ(uqi) = WR(rq);
2256*0Sstevel@tonic-gate 		qprocson(rq);
2257*0Sstevel@tonic-gate 		for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
2258*0Sstevel@tonic-gate 			LOCK_UNIT(lqi);
2259*0Sstevel@tonic-gate 			lqi->sm_uqflags |= SM_UQVALID;
2260*0Sstevel@tonic-gate 			UNLOCK_UNIT(lqi);
2261*0Sstevel@tonic-gate 		}
2262*0Sstevel@tonic-gate 
2263*0Sstevel@tonic-gate 		sm_dbg('C', ("sm_open: SM_UQVALID set on lqs.\n"));
2264*0Sstevel@tonic-gate 	}
2265*0Sstevel@tonic-gate 
2266*0Sstevel@tonic-gate 	if (*devp != rconsdev && BLOCKING(uqi, protocol, flag)) {
2267*0Sstevel@tonic-gate 
2268*0Sstevel@tonic-gate 		uqi->sm_flags |= WANT_CDSTAT;
2269*0Sstevel@tonic-gate 
2270*0Sstevel@tonic-gate 		do {
2271*0Sstevel@tonic-gate 			/*
2272*0Sstevel@tonic-gate 			 * Wait for notifications of changes in the CLOCAL
2273*0Sstevel@tonic-gate 			 * and TS_SOFTCAR flags and a TIOCM_CD flag of a
2274*0Sstevel@tonic-gate 			 * TIOCMGET request (come in on the write side queue).
2275*0Sstevel@tonic-gate 			 */
2276*0Sstevel@tonic-gate 
2277*0Sstevel@tonic-gate 			if ((ftstat = sm_defer_open(uqi, rq)) != EINTR) {
2278*0Sstevel@tonic-gate 				if (ftstat) {
2279*0Sstevel@tonic-gate 					goto tryopen;
2280*0Sstevel@tonic-gate 				} else {
2281*0Sstevel@tonic-gate 					continue;
2282*0Sstevel@tonic-gate 				}
2283*0Sstevel@tonic-gate 			}
2284*0Sstevel@tonic-gate 
2285*0Sstevel@tonic-gate 			if (uqi->sm_nwaiters == 0) {	/* clean up */
2286*0Sstevel@tonic-gate 				/*
2287*0Sstevel@tonic-gate 				 * only opens on an asynchronous
2288*0Sstevel@tonic-gate 				 * protocols reach here so checking
2289*0Sstevel@tonic-gate 				 * nwaiters == 0 is sufficient to
2290*0Sstevel@tonic-gate 				 * ensure that no other thread
2291*0Sstevel@tonic-gate 				 * is waiting on this logical unit
2292*0Sstevel@tonic-gate 				 */
2293*0Sstevel@tonic-gate 				if ((uqi->sm_flags & FULLY_OPEN) == 0) {
2294*0Sstevel@tonic-gate 
2295*0Sstevel@tonic-gate 					sm_lqi_t *lqi;
2296*0Sstevel@tonic-gate 
2297*0Sstevel@tonic-gate 					uqi->sm_dev = NODEV;
2298*0Sstevel@tonic-gate 					sm_dbg('C', ("sm_open FULLY_OPEN=0\n"));
2299*0Sstevel@tonic-gate 					for (lqi = uqi->sm_lqs; lqi != 0;
2300*0Sstevel@tonic-gate 					    lqi = lqi->sm_nlqi) {
2301*0Sstevel@tonic-gate 						LOCK_UNIT(lqi);
2302*0Sstevel@tonic-gate 						lqi->sm_uqflags &= ~SM_UQVALID;
2303*0Sstevel@tonic-gate 						UNLOCK_UNIT(lqi);
2304*0Sstevel@tonic-gate 					}
2305*0Sstevel@tonic-gate 
2306*0Sstevel@tonic-gate 					qprocsoff(rq);
2307*0Sstevel@tonic-gate 					rq->q_ptr = WR(rq)->q_ptr = 0;
2308*0Sstevel@tonic-gate 					SM_RQ(uqi) = 0;
2309*0Sstevel@tonic-gate 					SM_WQ(uqi) = 0;
2310*0Sstevel@tonic-gate 				}
2311*0Sstevel@tonic-gate 			}
2312*0Sstevel@tonic-gate 			if ((uqi->sm_flags & FULLY_OPEN) == 0 &&
2313*0Sstevel@tonic-gate 			    uqi->sm_nwaiters == 0)
2314*0Sstevel@tonic-gate 				uqi->sm_protocol = NULL_PROTOCOL;
2315*0Sstevel@tonic-gate 			if (flag & FEXCL)
2316*0Sstevel@tonic-gate 				uqi->sm_flags &= ~EXCL_OPEN;
2317*0Sstevel@tonic-gate 			sm_dbg('C', ("sm_open: done (ret %d).\n", ftstat));
2318*0Sstevel@tonic-gate 			return (ftstat);
2319*0Sstevel@tonic-gate 		} while (BLOCKING(uqi, protocol, flag));
2320*0Sstevel@tonic-gate 	}
2321*0Sstevel@tonic-gate 
2322*0Sstevel@tonic-gate 	uqi->sm_flags |= FULLY_OPEN;
2323*0Sstevel@tonic-gate 
2324*0Sstevel@tonic-gate 	sm_dbg('C', ("sm_open done (ret %d).\n", ftstat));
2325*0Sstevel@tonic-gate 	return (ftstat);
2326*0Sstevel@tonic-gate }
2327*0Sstevel@tonic-gate 
2328*0Sstevel@tonic-gate /*
2329*0Sstevel@tonic-gate  * Multiplexer device close routine.
2330*0Sstevel@tonic-gate  */
2331*0Sstevel@tonic-gate /*ARGSUSED*/
2332*0Sstevel@tonic-gate static int
2333*0Sstevel@tonic-gate sm_close(queue_t *rq, int flag, cred_t *credp)
2334*0Sstevel@tonic-gate {
2335*0Sstevel@tonic-gate 	sm_uqi_t *uqi = (sm_uqi_t *)rq->q_ptr;
2336*0Sstevel@tonic-gate 	sm_lqi_t *lqi;
2337*0Sstevel@tonic-gate 
2338*0Sstevel@tonic-gate 	if (sm_ssp == NULL)
2339*0Sstevel@tonic-gate 		return (ENXIO);
2340*0Sstevel@tonic-gate 
2341*0Sstevel@tonic-gate 	if (uqi == NULL) {
2342*0Sstevel@tonic-gate 		sm_dbg('C', ("close: WARN:- q 0x%p already closed.\n", rq));
2343*0Sstevel@tonic-gate 		return (ENXIO);
2344*0Sstevel@tonic-gate 	}
2345*0Sstevel@tonic-gate 
2346*0Sstevel@tonic-gate 	sm_dbg('C', ("close: uqi=0x%p unit=%d q=0x%p)\n", uqi, uqi->sm_lunit,
2347*0Sstevel@tonic-gate 			rq));
2348*0Sstevel@tonic-gate 
2349*0Sstevel@tonic-gate 	if (SM_RQ(uqi) != rq)
2350*0Sstevel@tonic-gate 		sm_dbg('C', ("sm_close: rq != current uqi queue\n"));
2351*0Sstevel@tonic-gate 
2352*0Sstevel@tonic-gate 	if (uqi->sm_ttybid) {
2353*0Sstevel@tonic-gate 		qunbufcall(SM_RQ(uqi), uqi->sm_ttybid);
2354*0Sstevel@tonic-gate 		uqi->sm_ttybid = 0;
2355*0Sstevel@tonic-gate 	}
2356*0Sstevel@tonic-gate 
2357*0Sstevel@tonic-gate 	/*
2358*0Sstevel@tonic-gate 	 * Tell all the linked queues that the upper queue has gone
2359*0Sstevel@tonic-gate 	 * Note close will never get called on a stream while there is a
2360*0Sstevel@tonic-gate 	 * thread blocked trying to open the same stream.
2361*0Sstevel@tonic-gate 	 * If there is a blocked open on a different stream but on
2362*0Sstevel@tonic-gate 	 * the same logical unit it will reset the lower queue flags.
2363*0Sstevel@tonic-gate 	 */
2364*0Sstevel@tonic-gate 	for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) {
2365*0Sstevel@tonic-gate 		LOCK_UNIT(lqi);
2366*0Sstevel@tonic-gate 		lqi->sm_uqflags &= ~SM_UQVALID;
2367*0Sstevel@tonic-gate 		UNLOCK_UNIT(lqi);
2368*0Sstevel@tonic-gate 	}
2369*0Sstevel@tonic-gate 
2370*0Sstevel@tonic-gate 	/*
2371*0Sstevel@tonic-gate 	 * Turn off the STREAMs queue processing for this queue.
2372*0Sstevel@tonic-gate 	 */
2373*0Sstevel@tonic-gate 	qprocsoff(rq);
2374*0Sstevel@tonic-gate 
2375*0Sstevel@tonic-gate 	/*
2376*0Sstevel@tonic-gate 	 * Similarly we will never get here if there is thread trying to
2377*0Sstevel@tonic-gate 	 * open ths stream.
2378*0Sstevel@tonic-gate 	 */
2379*0Sstevel@tonic-gate 	LOCK_UNIT(uqi);
2380*0Sstevel@tonic-gate 	if (uqi->sm_waitq == 0)
2381*0Sstevel@tonic-gate 		uqi->sm_flags = (uqi->sm_flags & SM_OBPCNDEV) ? SM_OBPCNDEV :
2382*0Sstevel@tonic-gate 									0U;
2383*0Sstevel@tonic-gate 
2384*0Sstevel@tonic-gate 	uqi->sm_dev = NODEV;
2385*0Sstevel@tonic-gate 	uqi->sm_protocol = NULL_PROTOCOL;
2386*0Sstevel@tonic-gate 	ttycommon_close(uqi->sm_ttycommon);
2387*0Sstevel@tonic-gate 	/* it just frees any pending ioctl */
2388*0Sstevel@tonic-gate 
2389*0Sstevel@tonic-gate 	uqi->sm_ttycommon->t_cflag = 0;
2390*0Sstevel@tonic-gate 	uqi->sm_ttycommon->t_flags = 0;
2391*0Sstevel@tonic-gate 
2392*0Sstevel@tonic-gate 	/*
2393*0Sstevel@tonic-gate 	 * Reset the queue pointers to NULL.
2394*0Sstevel@tonic-gate 	 * If a thread is qwaiting in the open routine it will recheck
2395*0Sstevel@tonic-gate 	 * the q_ptr.
2396*0Sstevel@tonic-gate 	 */
2397*0Sstevel@tonic-gate 	rq->q_ptr = NULL;
2398*0Sstevel@tonic-gate 	WR(rq)->q_ptr = NULL;
2399*0Sstevel@tonic-gate 	UNLOCK_UNIT(uqi);
2400*0Sstevel@tonic-gate 
2401*0Sstevel@tonic-gate 	if (sm_ssp->sm_lconsole == uqi) {
2402*0Sstevel@tonic-gate 		/* this will never be the outdial device closing */
2403*0Sstevel@tonic-gate 		sm_ssp->sm_lconsole = 0;
2404*0Sstevel@tonic-gate 	}
2405*0Sstevel@tonic-gate 	/*
2406*0Sstevel@tonic-gate 	 * If there is another thread waiting for this close then unblock
2407*0Sstevel@tonic-gate 	 * the thread by putting a message on its read queue.
2408*0Sstevel@tonic-gate 	 */
2409*0Sstevel@tonic-gate 	if (uqi->sm_waitq) {
2410*0Sstevel@tonic-gate 		sm_dbg('C', ("close(0x%p): doing putctl on 0x%p\n",
2411*0Sstevel@tonic-gate 			rq, uqi->sm_waitq));
2412*0Sstevel@tonic-gate 		if (rq == uqi->sm_waitq)
2413*0Sstevel@tonic-gate 			sm_log("close: waitq and closeq are same q\n");
2414*0Sstevel@tonic-gate 		(void) putctl(uqi->sm_waitq, M_CTL);
2415*0Sstevel@tonic-gate 	}
2416*0Sstevel@tonic-gate 
2417*0Sstevel@tonic-gate 	uqi->sm_flags &= ~(EXCL_OPEN | FULLY_OPEN);
2418*0Sstevel@tonic-gate 	sm_dbg('C', ("close: returning ok.\n"));
2419*0Sstevel@tonic-gate 	return (0);
2420*0Sstevel@tonic-gate }
2421*0Sstevel@tonic-gate 
2422*0Sstevel@tonic-gate /*
2423*0Sstevel@tonic-gate  * Initialise the software abort sequence for use when one of the
2424*0Sstevel@tonic-gate  * driver's nodes provides the system console.
2425*0Sstevel@tonic-gate  */
2426*0Sstevel@tonic-gate static void
2427*0Sstevel@tonic-gate sm_set_abort()
2428*0Sstevel@tonic-gate {
2429*0Sstevel@tonic-gate 	char ds[3] = { '\r', '~', CNTRL('b') };
2430*0Sstevel@tonic-gate 	char as[SM_MAX_ABSLEN];
2431*0Sstevel@tonic-gate 	int len = SM_MAX_ABSLEN;
2432*0Sstevel@tonic-gate 
2433*0Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, sm_ssp->sm_dip, PROP_LEN_AND_VAL_BUF, 0,
2434*0Sstevel@tonic-gate 		"abort-str", as, &len) != DDI_PROP_SUCCESS ||
2435*0Sstevel@tonic-gate 		(len = strlen(as)) < SM_MIN_ABSLEN) {
2436*0Sstevel@tonic-gate 		(void) strcpy(as, ds);
2437*0Sstevel@tonic-gate 		len = strlen(as);
2438*0Sstevel@tonic-gate 	} else {
2439*0Sstevel@tonic-gate 		char *s;
2440*0Sstevel@tonic-gate 		int i;
2441*0Sstevel@tonic-gate 
2442*0Sstevel@tonic-gate 		for (s = as, i = 0; i < len-1; i++, s++) {
2443*0Sstevel@tonic-gate 			if (as[i] == '^' && as[i+1] >= 'a' && as[i+1] <= 'z') {
2444*0Sstevel@tonic-gate 				*s = as[i+1] - 'a' + 1;
2445*0Sstevel@tonic-gate 				i++;
2446*0Sstevel@tonic-gate 			} else {
2447*0Sstevel@tonic-gate 				*s = as[i];
2448*0Sstevel@tonic-gate 			}
2449*0Sstevel@tonic-gate 		}
2450*0Sstevel@tonic-gate 		*s++ = as[i];
2451*0Sstevel@tonic-gate 		*s = '\0';
2452*0Sstevel@tonic-gate 		len = strlen(as);
2453*0Sstevel@tonic-gate 	}
2454*0Sstevel@tonic-gate 
2455*0Sstevel@tonic-gate 	if (len < SM_MIN_ABSLEN)
2456*0Sstevel@tonic-gate 		(void) strcpy(sm_ssp->sm_abs, ds);
2457*0Sstevel@tonic-gate 	else
2458*0Sstevel@tonic-gate 		(void) strcpy(sm_ssp->sm_abs, as);
2459*0Sstevel@tonic-gate }
2460*0Sstevel@tonic-gate 
2461*0Sstevel@tonic-gate /*
2462*0Sstevel@tonic-gate  *
2463*0Sstevel@tonic-gate  * sm_attach - initialisation routine per driver instance.
2464*0Sstevel@tonic-gate  */
2465*0Sstevel@tonic-gate static int
2466*0Sstevel@tonic-gate sm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2467*0Sstevel@tonic-gate {
2468*0Sstevel@tonic-gate 	int unit;
2469*0Sstevel@tonic-gate 	char name[32];
2470*0Sstevel@tonic-gate 	sm_uqi_t *uqi;
2471*0Sstevel@tonic-gate 	sm_lqi_t *lqip;
2472*0Sstevel@tonic-gate 
2473*0Sstevel@tonic-gate 	/*
2474*0Sstevel@tonic-gate 	 * Is this an attach?
2475*0Sstevel@tonic-gate 	 */
2476*0Sstevel@tonic-gate 	if (cmd != DDI_ATTACH) {
2477*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2478*0Sstevel@tonic-gate 	}
2479*0Sstevel@tonic-gate 
2480*0Sstevel@tonic-gate 	/*
2481*0Sstevel@tonic-gate 	 * Validate the instance number (sm is a single instance driver).
2482*0Sstevel@tonic-gate 	 */
2483*0Sstevel@tonic-gate 	if (sm_ssp) {	/* only one instance allowed */
2484*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2485*0Sstevel@tonic-gate 	}
2486*0Sstevel@tonic-gate 
2487*0Sstevel@tonic-gate 	sm_instance = ddi_get_instance(dip);
2488*0Sstevel@tonic-gate 
2489*0Sstevel@tonic-gate 	/*
2490*0Sstevel@tonic-gate 	 * Create the default minor node which will become the console.
2491*0Sstevel@tonic-gate 	 * (create it with three different names).:
2492*0Sstevel@tonic-gate 	 *	con which appears in the /dev filesystem;
2493*0Sstevel@tonic-gate 	 *	input which matches the prom /multiplexer:input node;
2494*0Sstevel@tonic-gate 	 *	output which matches the prom /multiplexer:input node
2495*0Sstevel@tonic-gate 	 * Create a minor node for control operations.
2496*0Sstevel@tonic-gate 	 */
2497*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "con", S_IFCHR, 0,
2498*0Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS ||
2499*0Sstevel@tonic-gate 	    ddi_create_minor_node(dip, "input", S_IFCHR, 0,
2500*0Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS ||
2501*0Sstevel@tonic-gate 	    ddi_create_minor_node(dip, "output", S_IFCHR, 0,
2502*0Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS ||
2503*0Sstevel@tonic-gate 	    ddi_create_minor_node(dip, "ctl", S_IFCHR, 1,
2504*0Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
2505*0Sstevel@tonic-gate 
2506*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "sm_attach: create minors failed.\n");
2507*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
2508*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2509*0Sstevel@tonic-gate 	}
2510*0Sstevel@tonic-gate 
2511*0Sstevel@tonic-gate 	smctlunit = 1;
2512*0Sstevel@tonic-gate 
2513*0Sstevel@tonic-gate 	/*
2514*0Sstevel@tonic-gate 	 * Allocate private state for this instance.
2515*0Sstevel@tonic-gate 	 */
2516*0Sstevel@tonic-gate 	sm_ssp = (sm_ss_t *)kmem_zalloc(sizeof (sm_ss_t), KM_SLEEP);
2517*0Sstevel@tonic-gate 
2518*0Sstevel@tonic-gate 	/*
2519*0Sstevel@tonic-gate 	 * Initialise per instance data.
2520*0Sstevel@tonic-gate 	 */
2521*0Sstevel@tonic-gate 	sm_ssp->sm_dip = dip;
2522*0Sstevel@tonic-gate 
2523*0Sstevel@tonic-gate 	/*
2524*0Sstevel@tonic-gate 	 * Get required debug level.
2525*0Sstevel@tonic-gate 	 */
2526*0Sstevel@tonic-gate 	sm_ssp->sm_trflag = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2527*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-trlv", sm_default_trflag);
2528*0Sstevel@tonic-gate 
2529*0Sstevel@tonic-gate 	sm_max_units = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2530*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-max-units", sm_max_units);
2531*0Sstevel@tonic-gate 	sm_minor_cnt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2532*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-minor-cnt", 0);
2533*0Sstevel@tonic-gate 
2534*0Sstevel@tonic-gate 	sm_refuse_opens = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2535*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-refuse-opens", sm_refuse_opens);
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 	sm_ssp->sm_ctrla_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2538*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-ctrla-abort-on", 1);
2539*0Sstevel@tonic-gate 	sm_ssp->sm_break_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2540*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "sm-break-abort-on", 0);
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate 	sm_set_abort();
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 	sm_ssp->sm_lqs = (sm_lqi_t *)kmem_zalloc(sizeof (sm_lqi_t) * MAX_LQS,
2545*0Sstevel@tonic-gate 							KM_SLEEP);
2546*0Sstevel@tonic-gate 	sm_ssp->sm_uqs = (sm_uqi_t *)kmem_zalloc(sizeof (sm_uqi_t) * NLUNITS,
2547*0Sstevel@tonic-gate 							KM_SLEEP);
2548*0Sstevel@tonic-gate 
2549*0Sstevel@tonic-gate 	for (unit = 2; unit < NLUNITS && unit < sm_minor_cnt + 2; unit++) {
2550*0Sstevel@tonic-gate 
2551*0Sstevel@tonic-gate 		if (snprintf(name, sizeof (name), "sm%c", 'a' + unit-2) >
2552*0Sstevel@tonic-gate 		    sizeof (name)) {
2553*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
2554*0Sstevel@tonic-gate 			    "sm_attach: create device for unit %d failed.\n",
2555*0Sstevel@tonic-gate 			    unit);
2556*0Sstevel@tonic-gate 		} else if (ddi_create_minor_node(dip, name, S_IFCHR,
2557*0Sstevel@tonic-gate 		    unit, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) {
2558*0Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
2559*0Sstevel@tonic-gate 			return (DDI_FAILURE);
2560*0Sstevel@tonic-gate 		}
2561*0Sstevel@tonic-gate 
2562*0Sstevel@tonic-gate 		if (snprintf(name, sizeof (name), "sm%c,cu", 'a' + unit-2) >
2563*0Sstevel@tonic-gate 		    sizeof (name)) {
2564*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
2565*0Sstevel@tonic-gate 			    "sm_attach: create cu device for unit %d failed.\n",
2566*0Sstevel@tonic-gate 			    unit);
2567*0Sstevel@tonic-gate 			continue;
2568*0Sstevel@tonic-gate 		} else if (ddi_create_minor_node(dip, name, S_IFCHR,
2569*0Sstevel@tonic-gate 		    unit|OUTLINE, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) {
2570*0Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
2571*0Sstevel@tonic-gate 			return (DDI_FAILURE);
2572*0Sstevel@tonic-gate 		}
2573*0Sstevel@tonic-gate 	}
2574*0Sstevel@tonic-gate 
2575*0Sstevel@tonic-gate 	for (unit = 0; unit < NLUNITS; unit++) {
2576*0Sstevel@tonic-gate 
2577*0Sstevel@tonic-gate 		uqi = get_uqi(sm_ssp, unit);
2578*0Sstevel@tonic-gate 		uqi->sm_lqs = 0;
2579*0Sstevel@tonic-gate 		uqi->sm_dev = NODEV;
2580*0Sstevel@tonic-gate 		uqi->sm_nlqs = 0;
2581*0Sstevel@tonic-gate 		uqi->sm_lunit = unit;
2582*0Sstevel@tonic-gate 		uqi->sm_protocol = NULL_PROTOCOL;
2583*0Sstevel@tonic-gate 		mutex_init(uqi->sm_umutex, NULL, MUTEX_DRIVER, NULL);
2584*0Sstevel@tonic-gate 		cv_init(uqi->sm_ucv, NULL, CV_DRIVER, NULL);
2585*0Sstevel@tonic-gate 		mutex_init(&uqi->sm_ttycommon->t_excl, NULL,
2586*0Sstevel@tonic-gate 				MUTEX_DRIVER, NULL);
2587*0Sstevel@tonic-gate 	}
2588*0Sstevel@tonic-gate 
2589*0Sstevel@tonic-gate 	for (unit = 0; unit < MAX_LQS; unit++) {
2590*0Sstevel@tonic-gate 		lqip = get_lqi(sm_ssp, unit);
2591*0Sstevel@tonic-gate 		lqip->sm_unit = unit;
2592*0Sstevel@tonic-gate 		lqip->sm_hadkadbchar = 0;
2593*0Sstevel@tonic-gate 		lqip->sm_nachar = sm_ssp->sm_abs;
2594*0Sstevel@tonic-gate 		lqip->sm_ioflag = FORIO;
2595*0Sstevel@tonic-gate 		lqip->sm_ctrla_abort_on = sm_ssp->sm_ctrla_abort_on;
2596*0Sstevel@tonic-gate 		lqip->sm_break_abort_on = sm_ssp->sm_break_abort_on;
2597*0Sstevel@tonic-gate 		mutex_init(lqip->sm_umutex, NULL, MUTEX_DRIVER, NULL);
2598*0Sstevel@tonic-gate 		cv_init(lqip->sm_ucv, NULL, CV_DRIVER, NULL);
2599*0Sstevel@tonic-gate 		mutex_init(&lqip->sm_ttycommon->t_excl, NULL,
2600*0Sstevel@tonic-gate 				MUTEX_DRIVER, NULL);
2601*0Sstevel@tonic-gate 	}
2602*0Sstevel@tonic-gate 
2603*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
2604*0Sstevel@tonic-gate }
2605*0Sstevel@tonic-gate 
2606*0Sstevel@tonic-gate /*
2607*0Sstevel@tonic-gate  *
2608*0Sstevel@tonic-gate  * sm_detach - detach routine per driver instance.
2609*0Sstevel@tonic-gate  */
2610*0Sstevel@tonic-gate static int
2611*0Sstevel@tonic-gate sm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2612*0Sstevel@tonic-gate {
2613*0Sstevel@tonic-gate 	sm_uqi_t		*lu;
2614*0Sstevel@tonic-gate 	sm_lqi_t		*pu;
2615*0Sstevel@tonic-gate 	int		unit;
2616*0Sstevel@tonic-gate 
2617*0Sstevel@tonic-gate 	/*
2618*0Sstevel@tonic-gate 	 * Is this a detach request for instance 0 (single instance driver).
2619*0Sstevel@tonic-gate 	 */
2620*0Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2621*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2622*0Sstevel@tonic-gate 
2623*0Sstevel@tonic-gate 	if (sm_ssp == NULL)
2624*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2625*0Sstevel@tonic-gate 
2626*0Sstevel@tonic-gate 	sm_dbg('V', ("detach ..."));
2627*0Sstevel@tonic-gate 
2628*0Sstevel@tonic-gate 
2629*0Sstevel@tonic-gate 	/*
2630*0Sstevel@tonic-gate 	 * Check that all the upper and lower queues are closed.
2631*0Sstevel@tonic-gate 	 */
2632*0Sstevel@tonic-gate 
2633*0Sstevel@tonic-gate 	for (unit = 0; unit < NLUNITS; unit++) {
2634*0Sstevel@tonic-gate 		lu = &sm_ssp->sm_uqs[unit];
2635*0Sstevel@tonic-gate 		if (lu && lu->sm_protocol != NULL_PROTOCOL) {
2636*0Sstevel@tonic-gate 			sm_dbg('V', ("detach: upper unit still open.\n"));
2637*0Sstevel@tonic-gate 			return (DDI_FAILURE);
2638*0Sstevel@tonic-gate 		}
2639*0Sstevel@tonic-gate 	}
2640*0Sstevel@tonic-gate 	for (unit = 0; unit < MAX_LQS; unit++) {
2641*0Sstevel@tonic-gate 		pu = &sm_ssp->sm_lqs[unit];
2642*0Sstevel@tonic-gate 		if (pu && pu->sm_linkid != 0) {
2643*0Sstevel@tonic-gate 			sm_dbg('V', ("detach: lower unit still linked (%d)\n",
2644*0Sstevel@tonic-gate 			    pu->sm_linkid));
2645*0Sstevel@tonic-gate 			return (DDI_FAILURE);
2646*0Sstevel@tonic-gate 		}
2647*0Sstevel@tonic-gate 	}
2648*0Sstevel@tonic-gate 
2649*0Sstevel@tonic-gate 	for (unit = 0; unit < NLUNITS; unit++) {
2650*0Sstevel@tonic-gate 		lu = &sm_ssp->sm_uqs[unit];
2651*0Sstevel@tonic-gate 		mutex_destroy(lu->sm_umutex);
2652*0Sstevel@tonic-gate 		cv_destroy(lu->sm_ucv);
2653*0Sstevel@tonic-gate 		mutex_destroy(&lu->sm_ttycommon->t_excl);
2654*0Sstevel@tonic-gate 	}
2655*0Sstevel@tonic-gate 	for (unit = 0; unit < MAX_LQS; unit++) {
2656*0Sstevel@tonic-gate 		pu = &sm_ssp->sm_lqs[unit];
2657*0Sstevel@tonic-gate 		mutex_destroy(pu->sm_umutex);
2658*0Sstevel@tonic-gate 		cv_destroy(pu->sm_ucv);
2659*0Sstevel@tonic-gate 		mutex_destroy(&pu->sm_ttycommon->t_excl);
2660*0Sstevel@tonic-gate 	}
2661*0Sstevel@tonic-gate 
2662*0Sstevel@tonic-gate 	/*
2663*0Sstevel@tonic-gate 	 * Tidy up per instance state.
2664*0Sstevel@tonic-gate 	 */
2665*0Sstevel@tonic-gate 	kmem_free(sm_ssp->sm_lqs, sizeof (sm_lqi_t) * MAX_LQS);
2666*0Sstevel@tonic-gate 	kmem_free(sm_ssp->sm_uqs, sizeof (sm_uqi_t) * NLUNITS);
2667*0Sstevel@tonic-gate 	kmem_free(sm_ssp, sizeof (sm_ss_t));
2668*0Sstevel@tonic-gate 
2669*0Sstevel@tonic-gate 	sm_ssp = 0;
2670*0Sstevel@tonic-gate 
2671*0Sstevel@tonic-gate 	/*
2672*0Sstevel@tonic-gate 	 * Remove all of the devices created in attach.
2673*0Sstevel@tonic-gate 	 */
2674*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
2675*0Sstevel@tonic-gate 
2676*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
2677*0Sstevel@tonic-gate }
2678*0Sstevel@tonic-gate 
2679*0Sstevel@tonic-gate /*
2680*0Sstevel@tonic-gate  * SECTION
2681*0Sstevel@tonic-gate  * Driver interface to the OS.
2682*0Sstevel@tonic-gate  */
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate /*
2685*0Sstevel@tonic-gate  * The driver is responsible for managing the mapping between the file system
2686*0Sstevel@tonic-gate  * device types (major/minor pairs) and the corresponding instance of the driver
2687*0Sstevel@tonic-gate  * or device information pointer (dip).
2688*0Sstevel@tonic-gate  * sm_info - return the instance or dip corresponding to the dev_t.
2689*0Sstevel@tonic-gate  */
2690*0Sstevel@tonic-gate /*ARGSUSED*/
2691*0Sstevel@tonic-gate static int
2692*0Sstevel@tonic-gate sm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2693*0Sstevel@tonic-gate {
2694*0Sstevel@tonic-gate 	int res = DDI_SUCCESS;
2695*0Sstevel@tonic-gate 
2696*0Sstevel@tonic-gate 	switch (infocmd) {
2697*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2698*0Sstevel@tonic-gate 		if (sm_ssp == NULL)
2699*0Sstevel@tonic-gate 			res = DDI_FAILURE;
2700*0Sstevel@tonic-gate 		else
2701*0Sstevel@tonic-gate 			*result = (void *)sm_ssp->sm_dip;
2702*0Sstevel@tonic-gate 		break;
2703*0Sstevel@tonic-gate 
2704*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2705*0Sstevel@tonic-gate 		*result = (void*)0;	/* single instance driver */
2706*0Sstevel@tonic-gate 		break;
2707*0Sstevel@tonic-gate 
2708*0Sstevel@tonic-gate 	default:
2709*0Sstevel@tonic-gate 		res = DDI_FAILURE;
2710*0Sstevel@tonic-gate 		break;
2711*0Sstevel@tonic-gate 	}
2712*0Sstevel@tonic-gate 
2713*0Sstevel@tonic-gate 	return (res);
2714*0Sstevel@tonic-gate }
2715*0Sstevel@tonic-gate 
2716*0Sstevel@tonic-gate /*
2717*0Sstevel@tonic-gate  * End of driver implementation
2718*0Sstevel@tonic-gate  */
2719*0Sstevel@tonic-gate 
2720*0Sstevel@tonic-gate /*
2721*0Sstevel@tonic-gate  * Loadable module interface to the kernel
2722*0Sstevel@tonic-gate  */
2723*0Sstevel@tonic-gate 
2724*0Sstevel@tonic-gate /*
2725*0Sstevel@tonic-gate  * Firstly the Streams specific interface
2726*0Sstevel@tonic-gate  */
2727*0Sstevel@tonic-gate 
2728*0Sstevel@tonic-gate /*
2729*0Sstevel@tonic-gate  * Solaris driver/STREAM initialisation structures.
2730*0Sstevel@tonic-gate  */
2731*0Sstevel@tonic-gate static struct module_info uinfo =
2732*0Sstevel@tonic-gate {
2733*0Sstevel@tonic-gate 	SM_MOD_ID,
2734*0Sstevel@tonic-gate 	TTYMUX_DRVNAME,
2735*0Sstevel@tonic-gate 	0,		/* min packet size */
2736*0Sstevel@tonic-gate 	INFPSZ,		/* max packet size */
2737*0Sstevel@tonic-gate 	2048,		/* high water mark */
2738*0Sstevel@tonic-gate 	256,		/* low water mark */
2739*0Sstevel@tonic-gate };
2740*0Sstevel@tonic-gate 
2741*0Sstevel@tonic-gate /*
2742*0Sstevel@tonic-gate  * Use zero water marks becuase the lower queues are used only for flow control.
2743*0Sstevel@tonic-gate  */
2744*0Sstevel@tonic-gate static struct module_info linfo =
2745*0Sstevel@tonic-gate {
2746*0Sstevel@tonic-gate 	SM_MOD_ID,
2747*0Sstevel@tonic-gate 	TTYMUX_DRVNAME,
2748*0Sstevel@tonic-gate 	0,		/* min packet size */
2749*0Sstevel@tonic-gate 	INFPSZ,		/* max packet size */
2750*0Sstevel@tonic-gate 	0,		/* high water mark */
2751*0Sstevel@tonic-gate 	0		/* low water mark	*/
2752*0Sstevel@tonic-gate };
2753*0Sstevel@tonic-gate 
2754*0Sstevel@tonic-gate 
2755*0Sstevel@tonic-gate /*
2756*0Sstevel@tonic-gate  * Solaris upper read STREAM initialisation structure.
2757*0Sstevel@tonic-gate  */
2758*0Sstevel@tonic-gate static struct qinit urinit =
2759*0Sstevel@tonic-gate {
2760*0Sstevel@tonic-gate 	sm_urput,	/* put */
2761*0Sstevel@tonic-gate 	sm_ursrv,	/* service */
2762*0Sstevel@tonic-gate 	sm_open,	/* open */
2763*0Sstevel@tonic-gate 	sm_close,	/* close */
2764*0Sstevel@tonic-gate 	NULL,		/* admin */
2765*0Sstevel@tonic-gate 	&uinfo,		/* module info */
2766*0Sstevel@tonic-gate 	NULL		/* stats */
2767*0Sstevel@tonic-gate };
2768*0Sstevel@tonic-gate 
2769*0Sstevel@tonic-gate /*
2770*0Sstevel@tonic-gate  * Solaris upper write STREAM initialisation structure.
2771*0Sstevel@tonic-gate  */
2772*0Sstevel@tonic-gate static struct qinit uwinit =
2773*0Sstevel@tonic-gate {
2774*0Sstevel@tonic-gate 	sm_uwput,
2775*0Sstevel@tonic-gate 	sm_uwsrv,
2776*0Sstevel@tonic-gate 	NULL,
2777*0Sstevel@tonic-gate 	NULL,
2778*0Sstevel@tonic-gate 	NULL,
2779*0Sstevel@tonic-gate 	&uinfo,
2780*0Sstevel@tonic-gate 	NULL
2781*0Sstevel@tonic-gate };
2782*0Sstevel@tonic-gate 
2783*0Sstevel@tonic-gate /*
2784*0Sstevel@tonic-gate  * Solaris lower read STREAM initialisation structure.
2785*0Sstevel@tonic-gate  */
2786*0Sstevel@tonic-gate static struct qinit lrinit =
2787*0Sstevel@tonic-gate {
2788*0Sstevel@tonic-gate 	sm_lrput,
2789*0Sstevel@tonic-gate 	sm_lrsrv,
2790*0Sstevel@tonic-gate 	NULL,
2791*0Sstevel@tonic-gate 	NULL, NULL,
2792*0Sstevel@tonic-gate 	&linfo,
2793*0Sstevel@tonic-gate 	NULL
2794*0Sstevel@tonic-gate };
2795*0Sstevel@tonic-gate 
2796*0Sstevel@tonic-gate /*
2797*0Sstevel@tonic-gate  * Solaris lower write STREAM initialisation structure.
2798*0Sstevel@tonic-gate  */
2799*0Sstevel@tonic-gate static struct qinit lwinit =
2800*0Sstevel@tonic-gate {
2801*0Sstevel@tonic-gate 	putq,
2802*0Sstevel@tonic-gate 	sm_lwsrv,
2803*0Sstevel@tonic-gate 	NULL,
2804*0Sstevel@tonic-gate 	NULL,
2805*0Sstevel@tonic-gate 	NULL,
2806*0Sstevel@tonic-gate 	&linfo,
2807*0Sstevel@tonic-gate 	NULL
2808*0Sstevel@tonic-gate };
2809*0Sstevel@tonic-gate 
2810*0Sstevel@tonic-gate /*
2811*0Sstevel@tonic-gate  * Multiplexing STREAM structure.
2812*0Sstevel@tonic-gate  */
2813*0Sstevel@tonic-gate struct streamtab sm_streamtab =
2814*0Sstevel@tonic-gate {
2815*0Sstevel@tonic-gate 	&urinit,
2816*0Sstevel@tonic-gate 	&uwinit,
2817*0Sstevel@tonic-gate 	&lrinit,
2818*0Sstevel@tonic-gate 	&lwinit
2819*0Sstevel@tonic-gate };
2820*0Sstevel@tonic-gate 
2821*0Sstevel@tonic-gate /*
2822*0Sstevel@tonic-gate  * Driver operations structure (struct cb_ops) and
2823*0Sstevel@tonic-gate  * driver dynamic loading functions (struct dev_ops).
2824*0Sstevel@tonic-gate  */
2825*0Sstevel@tonic-gate 
2826*0Sstevel@tonic-gate /*
2827*0Sstevel@tonic-gate  * Fold the Stream interface to the kernel into the driver interface
2828*0Sstevel@tonic-gate  * to the OS.
2829*0Sstevel@tonic-gate  */
2830*0Sstevel@tonic-gate 
2831*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sm_ops, \
2832*0Sstevel@tonic-gate 	nulldev, nulldev, \
2833*0Sstevel@tonic-gate 	sm_attach, sm_detach, nodev, \
2834*0Sstevel@tonic-gate 	sm_info, (D_NEW | D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL | D_MP),
2835*0Sstevel@tonic-gate 	&sm_streamtab);
2836*0Sstevel@tonic-gate 
2837*0Sstevel@tonic-gate /*
2838*0Sstevel@tonic-gate  * Driver module information.
2839*0Sstevel@tonic-gate  */
2840*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2841*0Sstevel@tonic-gate static struct modldrv modldrv =
2842*0Sstevel@tonic-gate {
2843*0Sstevel@tonic-gate 	&mod_driverops,
2844*0Sstevel@tonic-gate 	"serial mux driver %I%",
2845*0Sstevel@tonic-gate 	&sm_ops
2846*0Sstevel@tonic-gate };
2847*0Sstevel@tonic-gate 
2848*0Sstevel@tonic-gate static struct modlinkage modlinkage =
2849*0Sstevel@tonic-gate {
2850*0Sstevel@tonic-gate 	MODREV_1,
2851*0Sstevel@tonic-gate 	&modldrv,
2852*0Sstevel@tonic-gate 	NULL
2853*0Sstevel@tonic-gate };
2854*0Sstevel@tonic-gate 
2855*0Sstevel@tonic-gate /*
2856*0Sstevel@tonic-gate  * Define the body of our interface to the OS.
2857*0Sstevel@tonic-gate  */
2858*0Sstevel@tonic-gate 
2859*0Sstevel@tonic-gate /*
2860*0Sstevel@tonic-gate  * '_init' is called by Solaris to initialise any driver
2861*0Sstevel@tonic-gate  * specific state and to install the driver.
2862*0Sstevel@tonic-gate  */
2863*0Sstevel@tonic-gate int
2864*0Sstevel@tonic-gate _init(void)
2865*0Sstevel@tonic-gate {
2866*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
2867*0Sstevel@tonic-gate }
2868*0Sstevel@tonic-gate 
2869*0Sstevel@tonic-gate /*
2870*0Sstevel@tonic-gate  * _info - return this drivers interface to the kernel.
2871*0Sstevel@tonic-gate  */
2872*0Sstevel@tonic-gate int
2873*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
2874*0Sstevel@tonic-gate {
2875*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2876*0Sstevel@tonic-gate }
2877*0Sstevel@tonic-gate 
2878*0Sstevel@tonic-gate /*
2879*0Sstevel@tonic-gate  * _fini - the OS is finished with the services provided by the driver.
2880*0Sstevel@tonic-gate  * remove ourself and then remove any footprint that remains.
2881*0Sstevel@tonic-gate  */
2882*0Sstevel@tonic-gate int
2883*0Sstevel@tonic-gate _fini(void)
2884*0Sstevel@tonic-gate {
2885*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2886*0Sstevel@tonic-gate }
2887