xref: /titanic_54/usr/src/uts/common/io/zcons.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Zone Console Driver.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * This driver, derived from the pts/ptm drivers, is the pseudo console driver
33*7c478bd9Sstevel@tonic-gate  * for system zones.  Its implementation is straightforward.  Each instance
34*7c478bd9Sstevel@tonic-gate  * of the driver represents a global-zone/local-zone pair (this maps in a
35*7c478bd9Sstevel@tonic-gate  * straightforward way to the commonly used terminal notion of "master side"
36*7c478bd9Sstevel@tonic-gate  * and "slave side", and we use that terminology throughout).
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  * Instances of zcons are onlined as children of /pseudo/zconsnex@1/
39*7c478bd9Sstevel@tonic-gate  * by zoneadmd in userland, using the devctl framework; thus the driver
40*7c478bd9Sstevel@tonic-gate  * does not need to maintain any sort of "admin" node.
41*7c478bd9Sstevel@tonic-gate  *
42*7c478bd9Sstevel@tonic-gate  * The driver shuttles I/O from master side to slave side and back.  In a break
43*7c478bd9Sstevel@tonic-gate  * from the pts/ptm semantics, if one side is not open, I/O directed towards
44*7c478bd9Sstevel@tonic-gate  * it will simply be discarded.  This is so that if zoneadmd is not holding
45*7c478bd9Sstevel@tonic-gate  * the master side console open (i.e. it has died somehow), processes in
46*7c478bd9Sstevel@tonic-gate  * the zone do not experience any errors and I/O to the console does not
47*7c478bd9Sstevel@tonic-gate  * hang.
48*7c478bd9Sstevel@tonic-gate  *
49*7c478bd9Sstevel@tonic-gate  * TODO: we may want to revisit the other direction; i.e. we may want
50*7c478bd9Sstevel@tonic-gate  * zoneadmd to be able to detect whether no zone processes are holding the
51*7c478bd9Sstevel@tonic-gate  * console open, an unusual situation.
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/devops.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
68*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
71*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
73*7c478bd9Sstevel@tonic-gate #include <sys/zcons.h>
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static int zc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
76*7c478bd9Sstevel@tonic-gate static int zc_attach(dev_info_t *, ddi_attach_cmd_t);
77*7c478bd9Sstevel@tonic-gate static int zc_detach(dev_info_t *, ddi_detach_cmd_t);
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static int zc_open(queue_t *, dev_t *, int, int, cred_t *);
80*7c478bd9Sstevel@tonic-gate static int zc_close(queue_t *, int, cred_t *);
81*7c478bd9Sstevel@tonic-gate static void zc_wput(queue_t *, mblk_t *);
82*7c478bd9Sstevel@tonic-gate static void zc_rsrv(queue_t *);
83*7c478bd9Sstevel@tonic-gate static void zc_wsrv(queue_t *);
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate /*
86*7c478bd9Sstevel@tonic-gate  * The instance number is encoded in the dev_t in the minor number; the lowest
87*7c478bd9Sstevel@tonic-gate  * bit of the minor number is used to track the master vs. slave side of the
88*7c478bd9Sstevel@tonic-gate  * virtual console.  The rest of the bits in the minor number are the instance.
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate #define	ZC_MASTER_MINOR	0
91*7c478bd9Sstevel@tonic-gate #define	ZC_SLAVE_MINOR	1
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate #define	ZC_INSTANCE(x)	(getminor((x)) >> 1)
94*7c478bd9Sstevel@tonic-gate #define	ZC_NODE(x)	(getminor((x)) & 0x01)
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate int zcons_debug = 0;
97*7c478bd9Sstevel@tonic-gate #define	DBG(a)   if (zcons_debug) cmn_err(CE_NOTE, a)
98*7c478bd9Sstevel@tonic-gate #define	DBG1(a, b)   if (zcons_debug) cmn_err(CE_NOTE, a, b)
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * Zone Console Pseudo Terminal Module: stream data structure definitions
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate static struct module_info zc_info = {
105*7c478bd9Sstevel@tonic-gate 	31337,	/* c0z we r hAx0rs */
106*7c478bd9Sstevel@tonic-gate 	"zcons",
107*7c478bd9Sstevel@tonic-gate 	0,
108*7c478bd9Sstevel@tonic-gate 	INFPSZ,
109*7c478bd9Sstevel@tonic-gate 	2048,
110*7c478bd9Sstevel@tonic-gate 	128
111*7c478bd9Sstevel@tonic-gate };
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate static struct qinit zc_rinit = {
114*7c478bd9Sstevel@tonic-gate 	NULL,
115*7c478bd9Sstevel@tonic-gate 	(int (*)()) zc_rsrv,
116*7c478bd9Sstevel@tonic-gate 	zc_open,
117*7c478bd9Sstevel@tonic-gate 	zc_close,
118*7c478bd9Sstevel@tonic-gate 	NULL,
119*7c478bd9Sstevel@tonic-gate 	&zc_info,
120*7c478bd9Sstevel@tonic-gate 	NULL
121*7c478bd9Sstevel@tonic-gate };
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate static struct qinit zc_winit = {
124*7c478bd9Sstevel@tonic-gate 	(int (*)()) zc_wput,
125*7c478bd9Sstevel@tonic-gate 	(int (*)()) zc_wsrv,
126*7c478bd9Sstevel@tonic-gate 	NULL,
127*7c478bd9Sstevel@tonic-gate 	NULL,
128*7c478bd9Sstevel@tonic-gate 	NULL,
129*7c478bd9Sstevel@tonic-gate 	&zc_info,
130*7c478bd9Sstevel@tonic-gate 	NULL
131*7c478bd9Sstevel@tonic-gate };
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate static struct streamtab zc_tab_info = {
134*7c478bd9Sstevel@tonic-gate 	&zc_rinit,
135*7c478bd9Sstevel@tonic-gate 	&zc_winit,
136*7c478bd9Sstevel@tonic-gate 	NULL,
137*7c478bd9Sstevel@tonic-gate 	NULL
138*7c478bd9Sstevel@tonic-gate };
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate #define	ZC_CONF_FLAG	(D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL)
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate /*
143*7c478bd9Sstevel@tonic-gate  * this will define (struct cb_ops cb_zc_ops) and (struct dev_ops zc_ops)
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(zc_ops, nulldev, nulldev,	zc_attach, zc_detach, nodev, \
146*7c478bd9Sstevel@tonic-gate 	zc_getinfo, ZC_CONF_FLAG, &zc_tab_info);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /*
149*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
153*7c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
154*7c478bd9Sstevel@tonic-gate 	"Zone console driver 'zcons' %I%",
155*7c478bd9Sstevel@tonic-gate 	&zc_ops		/* driver ops */
156*7c478bd9Sstevel@tonic-gate };
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
159*7c478bd9Sstevel@tonic-gate 	MODREV_1,
160*7c478bd9Sstevel@tonic-gate 	&modldrv,
161*7c478bd9Sstevel@tonic-gate 	NULL
162*7c478bd9Sstevel@tonic-gate };
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate typedef struct zc_state {
165*7c478bd9Sstevel@tonic-gate 	dev_info_t *zc_devinfo;
166*7c478bd9Sstevel@tonic-gate 	queue_t *zc_master_rdq;
167*7c478bd9Sstevel@tonic-gate 	queue_t *zc_slave_rdq;
168*7c478bd9Sstevel@tonic-gate 	int zc_state;
169*7c478bd9Sstevel@tonic-gate } zc_state_t;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate #define	ZC_STATE_MOPEN	0x01
172*7c478bd9Sstevel@tonic-gate #define	ZC_STATE_SOPEN	0x02
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate static void *zc_soft_state;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate int
177*7c478bd9Sstevel@tonic-gate _init(void)
178*7c478bd9Sstevel@tonic-gate {
179*7c478bd9Sstevel@tonic-gate 	int err;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if ((err = ddi_soft_state_init(&zc_soft_state,
182*7c478bd9Sstevel@tonic-gate 	    sizeof (zc_state_t), 0)) != 0) {
183*7c478bd9Sstevel@tonic-gate 		return (err);
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0)
187*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(zc_soft_state);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	return (err);
190*7c478bd9Sstevel@tonic-gate }
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate int
194*7c478bd9Sstevel@tonic-gate _fini(void)
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	int err;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) != 0) {
199*7c478bd9Sstevel@tonic-gate 		return (err);
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&zc_soft_state);
203*7c478bd9Sstevel@tonic-gate 	return (0);
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate int
207*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate static int
213*7c478bd9Sstevel@tonic-gate zc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
216*7c478bd9Sstevel@tonic-gate 	int instance;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
219*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
222*7c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(zc_soft_state, instance) != DDI_SUCCESS)
223*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	if ((ddi_create_minor_node(dip, ZCONS_SLAVE_NAME, S_IFCHR,
226*7c478bd9Sstevel@tonic-gate 	    instance << 1 | ZC_SLAVE_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE) ||
227*7c478bd9Sstevel@tonic-gate 	    (ddi_create_minor_node(dip, ZCONS_MASTER_NAME, S_IFCHR,
228*7c478bd9Sstevel@tonic-gate 	    instance << 1 | ZC_MASTER_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE)) {
229*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
230*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(zc_soft_state, instance);
231*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL) {
235*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
236*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(zc_soft_state, instance);
237*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 	zcs->zc_devinfo = dip;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
242*7c478bd9Sstevel@tonic-gate }
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate static int
245*7c478bd9Sstevel@tonic-gate zc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
246*7c478bd9Sstevel@tonic-gate {
247*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
248*7c478bd9Sstevel@tonic-gate 	int instance;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
251*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
254*7c478bd9Sstevel@tonic-gate 	if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
255*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	if ((zcs->zc_state & ZC_STATE_MOPEN) ||
258*7c478bd9Sstevel@tonic-gate 	    (zcs->zc_state & ZC_STATE_SOPEN)) {
259*7c478bd9Sstevel@tonic-gate 		DBG1("zc_detach: device (dip=%p) still open\n", (void *)dip);
260*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
264*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(zc_soft_state, instance);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
267*7c478bd9Sstevel@tonic-gate }
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate /*
270*7c478bd9Sstevel@tonic-gate  * zc_getinfo()
271*7c478bd9Sstevel@tonic-gate  *	getinfo(9e) entrypoint.
272*7c478bd9Sstevel@tonic-gate  */
273*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
274*7c478bd9Sstevel@tonic-gate static int
275*7c478bd9Sstevel@tonic-gate zc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
276*7c478bd9Sstevel@tonic-gate {
277*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
278*7c478bd9Sstevel@tonic-gate 	int instance = ZC_INSTANCE((dev_t)arg);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
281*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
282*7c478bd9Sstevel@tonic-gate 		if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
283*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
284*7c478bd9Sstevel@tonic-gate 		*result = zcs->zc_devinfo;
285*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
286*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
287*7c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
288*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
291*7c478bd9Sstevel@tonic-gate }
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate /*
294*7c478bd9Sstevel@tonic-gate  * Return the equivalent queue from the other side of the relationship.
295*7c478bd9Sstevel@tonic-gate  * e.g.: given the slave's write queue, return the master's write queue.
296*7c478bd9Sstevel@tonic-gate  */
297*7c478bd9Sstevel@tonic-gate static queue_t *
298*7c478bd9Sstevel@tonic-gate zc_switch(queue_t *qp)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs = qp->q_ptr;
301*7c478bd9Sstevel@tonic-gate 	ASSERT(zcs != NULL);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (qp == zcs->zc_master_rdq)
304*7c478bd9Sstevel@tonic-gate 		return (zcs->zc_slave_rdq);
305*7c478bd9Sstevel@tonic-gate 	else if (OTHERQ(qp) == zcs->zc_master_rdq && zcs->zc_slave_rdq != NULL)
306*7c478bd9Sstevel@tonic-gate 		return (OTHERQ(zcs->zc_slave_rdq));
307*7c478bd9Sstevel@tonic-gate 	else if (qp == zcs->zc_slave_rdq)
308*7c478bd9Sstevel@tonic-gate 		return (zcs->zc_master_rdq);
309*7c478bd9Sstevel@tonic-gate 	else if (OTHERQ(qp) == zcs->zc_slave_rdq && zcs->zc_master_rdq != NULL)
310*7c478bd9Sstevel@tonic-gate 		return (OTHERQ(zcs->zc_master_rdq));
311*7c478bd9Sstevel@tonic-gate 	else
312*7c478bd9Sstevel@tonic-gate 		return (NULL);
313*7c478bd9Sstevel@tonic-gate }
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate /*
316*7c478bd9Sstevel@tonic-gate  * For debugging and outputting messages.  Returns the name of the side of
317*7c478bd9Sstevel@tonic-gate  * the relationship associated with this queue.
318*7c478bd9Sstevel@tonic-gate  */
319*7c478bd9Sstevel@tonic-gate static const char *
320*7c478bd9Sstevel@tonic-gate zc_side(queue_t *qp)
321*7c478bd9Sstevel@tonic-gate {
322*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs = qp->q_ptr;
323*7c478bd9Sstevel@tonic-gate 	ASSERT(zcs != NULL);
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	if (qp == zcs->zc_master_rdq ||
326*7c478bd9Sstevel@tonic-gate 	    OTHERQ(qp) == zcs->zc_master_rdq) {
327*7c478bd9Sstevel@tonic-gate 		return ("master");
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 	ASSERT(qp == zcs->zc_slave_rdq || OTHERQ(qp) == zcs->zc_slave_rdq);
330*7c478bd9Sstevel@tonic-gate 	return ("slave");
331*7c478bd9Sstevel@tonic-gate }
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
334*7c478bd9Sstevel@tonic-gate static int
335*7c478bd9Sstevel@tonic-gate zc_master_open(zc_state_t *zcs,
336*7c478bd9Sstevel@tonic-gate     queue_t	*rqp,	/* pointer to the read side queue */
337*7c478bd9Sstevel@tonic-gate     dev_t	*devp,	/* pointer to stream tail's dev */
338*7c478bd9Sstevel@tonic-gate     int		oflag,	/* the user open(2) supplied flags */
339*7c478bd9Sstevel@tonic-gate     int		sflag,	/* open state flag */
340*7c478bd9Sstevel@tonic-gate     cred_t	*credp)	/* credentials */
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	mblk_t *mop;
343*7c478bd9Sstevel@tonic-gate 	struct stroptions *sop;
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	/*
346*7c478bd9Sstevel@tonic-gate 	 * Enforce exclusivity on the master side; the only consumer should
347*7c478bd9Sstevel@tonic-gate 	 * be the zoneadmd for the zone.
348*7c478bd9Sstevel@tonic-gate 	 */
349*7c478bd9Sstevel@tonic-gate 	if ((zcs->zc_state & ZC_STATE_MOPEN) != 0)
350*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
353*7c478bd9Sstevel@tonic-gate 		DBG("zc_master_open(): mop allocation failed\n");
354*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	zcs->zc_state |= ZC_STATE_MOPEN;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	/*
360*7c478bd9Sstevel@tonic-gate 	 * q_ptr stores driver private data; stash the soft state data on both
361*7c478bd9Sstevel@tonic-gate 	 * read and write sides of the queue.
362*7c478bd9Sstevel@tonic-gate 	 */
363*7c478bd9Sstevel@tonic-gate 	WR(rqp)->q_ptr = rqp->q_ptr = zcs;
364*7c478bd9Sstevel@tonic-gate 	qprocson(rqp);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/*
367*7c478bd9Sstevel@tonic-gate 	 * Following qprocson(), the master side is fully plumbed into the
368*7c478bd9Sstevel@tonic-gate 	 * STREAM and may send/receive messages.  Setting zcs->zc_master_rdq
369*7c478bd9Sstevel@tonic-gate 	 * will allow the slave to send messages to us (the master).
370*7c478bd9Sstevel@tonic-gate 	 * This cannot occur before qprocson() because the master is not
371*7c478bd9Sstevel@tonic-gate 	 * ready to process them until that point.
372*7c478bd9Sstevel@tonic-gate 	 */
373*7c478bd9Sstevel@tonic-gate 	zcs->zc_master_rdq = rqp;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	/*
376*7c478bd9Sstevel@tonic-gate 	 * set up hi/lo water marks on stream head read queue and add
377*7c478bd9Sstevel@tonic-gate 	 * controlling tty as needed.
378*7c478bd9Sstevel@tonic-gate 	 */
379*7c478bd9Sstevel@tonic-gate 	mop->b_datap->db_type = M_SETOPTS;
380*7c478bd9Sstevel@tonic-gate 	mop->b_wptr += sizeof (struct stroptions);
381*7c478bd9Sstevel@tonic-gate 	sop = (struct stroptions *)mop->b_rptr;
382*7c478bd9Sstevel@tonic-gate 	if (oflag & FNOCTTY)
383*7c478bd9Sstevel@tonic-gate 		sop->so_flags = SO_HIWAT | SO_LOWAT;
384*7c478bd9Sstevel@tonic-gate 	else
385*7c478bd9Sstevel@tonic-gate 		sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
386*7c478bd9Sstevel@tonic-gate 	sop->so_hiwat = 512;
387*7c478bd9Sstevel@tonic-gate 	sop->so_lowat = 256;
388*7c478bd9Sstevel@tonic-gate 	putnext(rqp, mop);
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	return (0);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
394*7c478bd9Sstevel@tonic-gate static int
395*7c478bd9Sstevel@tonic-gate zc_slave_open(zc_state_t *zcs,
396*7c478bd9Sstevel@tonic-gate     queue_t	*rqp,	/* pointer to the read side queue */
397*7c478bd9Sstevel@tonic-gate     dev_t	*devp,	/* pointer to stream tail's dev */
398*7c478bd9Sstevel@tonic-gate     int		oflag,	/* the user open(2) supplied flags */
399*7c478bd9Sstevel@tonic-gate     int		sflag,	/* open state flag */
400*7c478bd9Sstevel@tonic-gate     cred_t	*credp)	/* credentials */
401*7c478bd9Sstevel@tonic-gate {
402*7c478bd9Sstevel@tonic-gate 	mblk_t *mop;
403*7c478bd9Sstevel@tonic-gate 	struct stroptions *sop;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	/*
406*7c478bd9Sstevel@tonic-gate 	 * The slave side can be opened as many times as needed.
407*7c478bd9Sstevel@tonic-gate 	 */
408*7c478bd9Sstevel@tonic-gate 	if ((zcs->zc_state & ZC_STATE_SOPEN) != 0) {
409*7c478bd9Sstevel@tonic-gate 		ASSERT((rqp != NULL) && (WR(rqp)->q_ptr == zcs));
410*7c478bd9Sstevel@tonic-gate 		return (0);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
414*7c478bd9Sstevel@tonic-gate 		DBG("zc_slave_open(): mop allocation failed\n");
415*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	zcs->zc_state |= ZC_STATE_SOPEN;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/*
421*7c478bd9Sstevel@tonic-gate 	 * q_ptr stores driver private data; stash the soft state data on both
422*7c478bd9Sstevel@tonic-gate 	 * read and write sides of the queue.
423*7c478bd9Sstevel@tonic-gate 	 */
424*7c478bd9Sstevel@tonic-gate 	WR(rqp)->q_ptr = rqp->q_ptr = zcs;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	qprocson(rqp);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	/*
429*7c478bd9Sstevel@tonic-gate 	 * Must follow qprocson(), since we aren't ready to process until then.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	zcs->zc_slave_rdq = rqp;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	/*
434*7c478bd9Sstevel@tonic-gate 	 * set up hi/lo water marks on stream head read queue and add
435*7c478bd9Sstevel@tonic-gate 	 * controlling tty as needed.
436*7c478bd9Sstevel@tonic-gate 	 */
437*7c478bd9Sstevel@tonic-gate 	mop->b_datap->db_type = M_SETOPTS;
438*7c478bd9Sstevel@tonic-gate 	mop->b_wptr += sizeof (struct stroptions);
439*7c478bd9Sstevel@tonic-gate 	sop = (struct stroptions *)mop->b_rptr;
440*7c478bd9Sstevel@tonic-gate 	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
441*7c478bd9Sstevel@tonic-gate 	sop->so_hiwat = 512;
442*7c478bd9Sstevel@tonic-gate 	sop->so_lowat = 256;
443*7c478bd9Sstevel@tonic-gate 	putnext(rqp, mop);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	return (0);
446*7c478bd9Sstevel@tonic-gate }
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate /*
449*7c478bd9Sstevel@tonic-gate  * open(9e) entrypoint; checks sflag, and rejects anything unordinary.
450*7c478bd9Sstevel@tonic-gate  */
451*7c478bd9Sstevel@tonic-gate static int
452*7c478bd9Sstevel@tonic-gate zc_open(queue_t *rqp,		/* pointer to the read side queue */
453*7c478bd9Sstevel@tonic-gate 	dev_t   *devp,		/* pointer to stream tail's dev */
454*7c478bd9Sstevel@tonic-gate 	int	oflag,		/* the user open(2) supplied flags */
455*7c478bd9Sstevel@tonic-gate 	int	sflag,		/* open state flag */
456*7c478bd9Sstevel@tonic-gate 	cred_t  *credp)		/* credentials */
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	int instance = ZC_INSTANCE(*devp);
459*7c478bd9Sstevel@tonic-gate 	int ret;
460*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	if (sflag != 0)
463*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
466*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	switch (ZC_NODE(*devp)) {
469*7c478bd9Sstevel@tonic-gate 	case ZC_MASTER_MINOR:
470*7c478bd9Sstevel@tonic-gate 		ret = zc_master_open(zcs, rqp, devp, oflag, sflag, credp);
471*7c478bd9Sstevel@tonic-gate 		break;
472*7c478bd9Sstevel@tonic-gate 	case ZC_SLAVE_MINOR:
473*7c478bd9Sstevel@tonic-gate 		ret = zc_slave_open(zcs, rqp, devp, oflag, sflag, credp);
474*7c478bd9Sstevel@tonic-gate 		break;
475*7c478bd9Sstevel@tonic-gate 	default:
476*7c478bd9Sstevel@tonic-gate 		ret = ENXIO;
477*7c478bd9Sstevel@tonic-gate 		break;
478*7c478bd9Sstevel@tonic-gate 	}
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	return (ret);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate /*
484*7c478bd9Sstevel@tonic-gate  * close(9e) entrypoint.
485*7c478bd9Sstevel@tonic-gate  */
486*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
487*7c478bd9Sstevel@tonic-gate static int
488*7c478bd9Sstevel@tonic-gate zc_close(queue_t *rqp, int flag, cred_t *credp)
489*7c478bd9Sstevel@tonic-gate {
490*7c478bd9Sstevel@tonic-gate 	queue_t *wqp;
491*7c478bd9Sstevel@tonic-gate 	mblk_t	*bp;
492*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	zcs = (zc_state_t *)rqp->q_ptr;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	if (rqp == zcs->zc_master_rdq) {
497*7c478bd9Sstevel@tonic-gate 		DBG("Closing master side");
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 		zcs->zc_master_rdq = NULL;
500*7c478bd9Sstevel@tonic-gate 		zcs->zc_state &= ~ZC_STATE_MOPEN;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 		/*
503*7c478bd9Sstevel@tonic-gate 		 * qenable slave side write queue so that it can flush
504*7c478bd9Sstevel@tonic-gate 		 * its messages as master's read queue is going away
505*7c478bd9Sstevel@tonic-gate 		 */
506*7c478bd9Sstevel@tonic-gate 		if (zcs->zc_slave_rdq != NULL) {
507*7c478bd9Sstevel@tonic-gate 			qenable(WR(zcs->zc_slave_rdq));
508*7c478bd9Sstevel@tonic-gate 		}
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 		qprocsoff(rqp);
511*7c478bd9Sstevel@tonic-gate 		WR(rqp)->q_ptr = rqp->q_ptr = NULL;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	} else if (rqp == zcs->zc_slave_rdq) {
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 		DBG("Closing slave side");
516*7c478bd9Sstevel@tonic-gate 		zcs->zc_state &= ~ZC_STATE_SOPEN;
517*7c478bd9Sstevel@tonic-gate 		zcs->zc_slave_rdq = NULL;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		wqp = WR(rqp);
520*7c478bd9Sstevel@tonic-gate 		while ((bp = getq(wqp)) != NULL) {
521*7c478bd9Sstevel@tonic-gate 			if (zcs->zc_master_rdq != NULL)
522*7c478bd9Sstevel@tonic-gate 				putnext(zcs->zc_master_rdq, bp);
523*7c478bd9Sstevel@tonic-gate 			else if (bp->b_datap->db_type == M_IOCTL)
524*7c478bd9Sstevel@tonic-gate 				miocnak(wqp, bp, 0, 0);
525*7c478bd9Sstevel@tonic-gate 			else
526*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		/*
530*7c478bd9Sstevel@tonic-gate 		 * Qenable master side write queue so that it can flush its
531*7c478bd9Sstevel@tonic-gate 		 * messages as slaves's read queue is going away.
532*7c478bd9Sstevel@tonic-gate 		 */
533*7c478bd9Sstevel@tonic-gate 		if (zcs->zc_master_rdq != NULL)
534*7c478bd9Sstevel@tonic-gate 			qenable(WR(zcs->zc_master_rdq));
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 		qprocsoff(rqp);
537*7c478bd9Sstevel@tonic-gate 		WR(rqp)->q_ptr = rqp->q_ptr = NULL;
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	return (0);
541*7c478bd9Sstevel@tonic-gate }
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate static void
544*7c478bd9Sstevel@tonic-gate handle_mflush(queue_t *qp, mblk_t *mp)
545*7c478bd9Sstevel@tonic-gate {
546*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
547*7c478bd9Sstevel@tonic-gate 	DBG1("M_FLUSH on %s side", zc_side(qp));
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	if (*mp->b_rptr & FLUSHW) {
550*7c478bd9Sstevel@tonic-gate 		DBG1("M_FLUSH, FLUSHW, %s side", zc_side(qp));
551*7c478bd9Sstevel@tonic-gate 		flushq(qp, FLUSHDATA);
552*7c478bd9Sstevel@tonic-gate 		*mp->b_rptr &= ~FLUSHW;
553*7c478bd9Sstevel@tonic-gate 		if ((*mp->b_rptr & FLUSHR) == 0) {
554*7c478bd9Sstevel@tonic-gate 			/*
555*7c478bd9Sstevel@tonic-gate 			 * FLUSHW only. Change to FLUSHR and putnext other side,
556*7c478bd9Sstevel@tonic-gate 			 * then we are done.
557*7c478bd9Sstevel@tonic-gate 			 */
558*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr |= FLUSHR;
559*7c478bd9Sstevel@tonic-gate 			if (zc_switch(RD(qp)) != NULL) {
560*7c478bd9Sstevel@tonic-gate 				putnext(zc_switch(RD(qp)), mp);
561*7c478bd9Sstevel@tonic-gate 				return;
562*7c478bd9Sstevel@tonic-gate 			}
563*7c478bd9Sstevel@tonic-gate 		} else if ((zc_switch(RD(qp)) != NULL) &&
564*7c478bd9Sstevel@tonic-gate 		    (nmp = copyb(mp)) != NULL) {
565*7c478bd9Sstevel@tonic-gate 			/*
566*7c478bd9Sstevel@tonic-gate 			 * It is a FLUSHRW; we copy the mblk and send
567*7c478bd9Sstevel@tonic-gate 			 * it to the other side, since we still need to use
568*7c478bd9Sstevel@tonic-gate 			 * the mblk in FLUSHR processing, below.
569*7c478bd9Sstevel@tonic-gate 			 */
570*7c478bd9Sstevel@tonic-gate 			putnext(zc_switch(RD(qp)), nmp);
571*7c478bd9Sstevel@tonic-gate 		}
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	if (*mp->b_rptr & FLUSHR) {
575*7c478bd9Sstevel@tonic-gate 		DBG("qreply(qp) turning FLUSHR around\n");
576*7c478bd9Sstevel@tonic-gate 		qreply(qp, mp);
577*7c478bd9Sstevel@tonic-gate 		return;
578*7c478bd9Sstevel@tonic-gate 	}
579*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
580*7c478bd9Sstevel@tonic-gate }
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate /*
583*7c478bd9Sstevel@tonic-gate  * wput(9E) is symmetric for master and slave sides, so this handles both
584*7c478bd9Sstevel@tonic-gate  * without splitting the codepath.
585*7c478bd9Sstevel@tonic-gate  *
586*7c478bd9Sstevel@tonic-gate  * zc_wput() looks at the other side; if there is no process holding that
587*7c478bd9Sstevel@tonic-gate  * side open, it frees the message.  This prevents processes from hanging
588*7c478bd9Sstevel@tonic-gate  * if no one is holding open the console.  Otherwise, it putnext's high
589*7c478bd9Sstevel@tonic-gate  * priority messages, putnext's normal messages if possible, and otherwise
590*7c478bd9Sstevel@tonic-gate  * enqueues the messages; in the case that something is enqueued, wsrv(9E)
591*7c478bd9Sstevel@tonic-gate  * will take care of eventually shuttling I/O to the other side.
592*7c478bd9Sstevel@tonic-gate  */
593*7c478bd9Sstevel@tonic-gate static void
594*7c478bd9Sstevel@tonic-gate zc_wput(queue_t *qp, mblk_t *mp)
595*7c478bd9Sstevel@tonic-gate {
596*7c478bd9Sstevel@tonic-gate 	unsigned char type = mp->b_datap->db_type;
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	ASSERT(qp->q_ptr);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	DBG1("entering zc_wput, %s side", zc_side(qp));
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if (zc_switch(RD(qp)) == NULL) {
603*7c478bd9Sstevel@tonic-gate 		DBG1("wput to %s side (no one listening)", zc_side(qp));
604*7c478bd9Sstevel@tonic-gate 		switch (type) {
605*7c478bd9Sstevel@tonic-gate 		case M_FLUSH:
606*7c478bd9Sstevel@tonic-gate 			handle_mflush(qp, mp);
607*7c478bd9Sstevel@tonic-gate 			break;
608*7c478bd9Sstevel@tonic-gate 		case M_IOCTL:
609*7c478bd9Sstevel@tonic-gate 			miocnak(qp, mp, 0, 0);
610*7c478bd9Sstevel@tonic-gate 			break;
611*7c478bd9Sstevel@tonic-gate 		default:
612*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
613*7c478bd9Sstevel@tonic-gate 			break;
614*7c478bd9Sstevel@tonic-gate 		}
615*7c478bd9Sstevel@tonic-gate 		return;
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	if (type >= QPCTL) {
619*7c478bd9Sstevel@tonic-gate 		DBG1("(hipri) wput, %s side", zc_side(qp));
620*7c478bd9Sstevel@tonic-gate 		switch (type) {
621*7c478bd9Sstevel@tonic-gate 		case M_READ:		/* supposedly from ldterm? */
622*7c478bd9Sstevel@tonic-gate 			DBG("zc_wput: tossing M_READ\n");
623*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
624*7c478bd9Sstevel@tonic-gate 			break;
625*7c478bd9Sstevel@tonic-gate 		case M_FLUSH:
626*7c478bd9Sstevel@tonic-gate 			handle_mflush(qp, mp);
627*7c478bd9Sstevel@tonic-gate 			break;
628*7c478bd9Sstevel@tonic-gate 		default:
629*7c478bd9Sstevel@tonic-gate 			/*
630*7c478bd9Sstevel@tonic-gate 			 * Put this to the other side.
631*7c478bd9Sstevel@tonic-gate 			 */
632*7c478bd9Sstevel@tonic-gate 			ASSERT(zc_switch(RD(qp)) != NULL);
633*7c478bd9Sstevel@tonic-gate 			putnext(zc_switch(RD(qp)), mp);
634*7c478bd9Sstevel@tonic-gate 			break;
635*7c478bd9Sstevel@tonic-gate 		}
636*7c478bd9Sstevel@tonic-gate 		DBG1("done (hipri) wput, %s side", zc_side(qp));
637*7c478bd9Sstevel@tonic-gate 		return;
638*7c478bd9Sstevel@tonic-gate 	}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	/*
641*7c478bd9Sstevel@tonic-gate 	 * Only putnext if there isn't already something in the queue.
642*7c478bd9Sstevel@tonic-gate 	 * otherwise things would wind up out of order.
643*7c478bd9Sstevel@tonic-gate 	 */
644*7c478bd9Sstevel@tonic-gate 	if (qp->q_first == NULL && bcanputnext(RD(zc_switch(qp)), mp->b_band)) {
645*7c478bd9Sstevel@tonic-gate 		DBG("wput: putting message to other side\n");
646*7c478bd9Sstevel@tonic-gate 		putnext(RD(zc_switch(qp)), mp);
647*7c478bd9Sstevel@tonic-gate 	} else {
648*7c478bd9Sstevel@tonic-gate 		DBG("wput: putting msg onto queue\n");
649*7c478bd9Sstevel@tonic-gate 		(void) putq(qp, mp);
650*7c478bd9Sstevel@tonic-gate 	}
651*7c478bd9Sstevel@tonic-gate 	DBG1("done wput, %s side", zc_side(qp));
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * rsrv(9E) is symmetric for master and slave, so zc_rsrv() handles both
656*7c478bd9Sstevel@tonic-gate  * without splitting up the codepath.
657*7c478bd9Sstevel@tonic-gate  *
658*7c478bd9Sstevel@tonic-gate  * Enable the write side of the partner.  This triggers the partner to send
659*7c478bd9Sstevel@tonic-gate  * messages queued on its write side to this queue's read side.
660*7c478bd9Sstevel@tonic-gate  */
661*7c478bd9Sstevel@tonic-gate static void
662*7c478bd9Sstevel@tonic-gate zc_rsrv(queue_t *qp)
663*7c478bd9Sstevel@tonic-gate {
664*7c478bd9Sstevel@tonic-gate 	zc_state_t *zcs;
665*7c478bd9Sstevel@tonic-gate 	zcs = (zc_state_t *)qp->q_ptr;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	/*
668*7c478bd9Sstevel@tonic-gate 	 * Care must be taken here, as either of the master or slave side
669*7c478bd9Sstevel@tonic-gate 	 * qptr could be NULL.
670*7c478bd9Sstevel@tonic-gate 	 */
671*7c478bd9Sstevel@tonic-gate 	ASSERT(qp == zcs->zc_master_rdq || qp == zcs->zc_slave_rdq);
672*7c478bd9Sstevel@tonic-gate 	if (zc_switch(qp) == NULL) {
673*7c478bd9Sstevel@tonic-gate 		DBG("zc_rsrv: other side isn't listening\n");
674*7c478bd9Sstevel@tonic-gate 		return;
675*7c478bd9Sstevel@tonic-gate 	}
676*7c478bd9Sstevel@tonic-gate 	qenable(WR(zc_switch(qp)));
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate /*
680*7c478bd9Sstevel@tonic-gate  * This routine is symmetric for master and slave, so it handles both without
681*7c478bd9Sstevel@tonic-gate  * splitting up the codepath.
682*7c478bd9Sstevel@tonic-gate  *
683*7c478bd9Sstevel@tonic-gate  * If there are messages on this queue that can be sent to the other, send
684*7c478bd9Sstevel@tonic-gate  * them via putnext(). Else, if queued messages cannot be sent, leave them
685*7c478bd9Sstevel@tonic-gate  * on this queue.
686*7c478bd9Sstevel@tonic-gate  */
687*7c478bd9Sstevel@tonic-gate static void
688*7c478bd9Sstevel@tonic-gate zc_wsrv(queue_t *qp)
689*7c478bd9Sstevel@tonic-gate {
690*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	DBG1("zc_wsrv master (%s) side", zc_side(qp));
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	/*
695*7c478bd9Sstevel@tonic-gate 	 * Partner has no read queue, so take the data, and throw it away.
696*7c478bd9Sstevel@tonic-gate 	 */
697*7c478bd9Sstevel@tonic-gate 	if (zc_switch(RD(qp)) == NULL) {
698*7c478bd9Sstevel@tonic-gate 		DBG("zc_wsrv: other side isn't listening");
699*7c478bd9Sstevel@tonic-gate 		while ((mp = getq(qp)) != NULL) {
700*7c478bd9Sstevel@tonic-gate 			if (mp->b_datap->db_type == M_IOCTL)
701*7c478bd9Sstevel@tonic-gate 				miocnak(qp, mp, 0, 0);
702*7c478bd9Sstevel@tonic-gate 			else
703*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
704*7c478bd9Sstevel@tonic-gate 		}
705*7c478bd9Sstevel@tonic-gate 		flushq(qp, FLUSHALL);
706*7c478bd9Sstevel@tonic-gate 		return;
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	/*
710*7c478bd9Sstevel@tonic-gate 	 * while there are messages on this write queue...
711*7c478bd9Sstevel@tonic-gate 	 */
712*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(qp)) != NULL) {
713*7c478bd9Sstevel@tonic-gate 		/*
714*7c478bd9Sstevel@tonic-gate 		 * Due to the way zc_wput is implemented, we should never
715*7c478bd9Sstevel@tonic-gate 		 * see a control message here.
716*7c478bd9Sstevel@tonic-gate 		 */
717*7c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap->db_type < QPCTL);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		if (bcanputnext(RD(zc_switch(qp)), mp->b_band)) {
720*7c478bd9Sstevel@tonic-gate 			DBG("wsrv: send message to other side\n");
721*7c478bd9Sstevel@tonic-gate 			putnext(RD(zc_switch(qp)), mp);
722*7c478bd9Sstevel@tonic-gate 		} else {
723*7c478bd9Sstevel@tonic-gate 			DBG("wsrv: putting msg back on queue\n");
724*7c478bd9Sstevel@tonic-gate 			(void) putbq(qp, mp);
725*7c478bd9Sstevel@tonic-gate 			break;
726*7c478bd9Sstevel@tonic-gate 		}
727*7c478bd9Sstevel@tonic-gate 	}
728*7c478bd9Sstevel@tonic-gate }
729