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