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