Home | History | Annotate | Download | only in io
      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 2009 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  *
     53  * MASTER SIDE IOCTLS
     54  *
     55  * The ZC_HOLDSLAVE and ZC_RELEASESLAVE ioctls instruct the master side of the
     56  * console to hold and release a reference to the slave side's vnode.  They are
     57  * meant to be issued by zoneadmd after the console device node is created and
     58  * before it is destroyed so that the slave's STREAMS anchor, ptem, is
     59  * preserved when ttymon starts popping STREAMS modules from within the
     60  * associated zone.  This guarantees that the zone console will always have
     61  * terminal semantics while the zone is running.
     62  *
     63  * Here is the issue: the ptem module is anchored in the zone console
     64  * (slave side) so that processes within the associated non-global zone will
     65  * fail to pop it off, thus ensuring that the slave will retain terminal
     66  * semantics.  When a process attempts to pop the anchor off of a stream, the
     67  * STREAMS subsystem checks whether the calling process' zone is the same as
     68  * that of the process that pushed the anchor onto the stream and cancels the
     69  * pop if they differ.  zoneadmd used to hold an open file descriptor for the
     70  * slave while the associated non-global zone ran, thus ensuring that the
     71  * slave's STREAMS anchor would never be popped from within the non-global zone
     72  * (because zoneadmd runs in the global zone).  However, this file descriptor
     73  * was removed to make zone console management more robust.  sad(7D) is now
     74  * used to automatically set up the slave's STREAMS modules when the zone
     75  * console is freshly opened within the associated non-global zone.  However,
     76  * when a process within the non-global zone freshly opens the zone console, the
     77  * anchor is pushed from within the non-global zone, making it possible for
     78  * processes within the non-global zone (e.g., ttymon) to pop the anchor and
     79  * destroy the zone console's terminal semantics.
     80  *
     81  * One solution is to make the zcons device hold the slave open while the
     82  * associated non-global zone runs so that the STREAMS anchor will always be
     83  * associated with the global zone.  Unfortunately, the slave cannot be opened
     84  * from within the zcons driver because the driver is not reentrant: it has
     85  * an outer STREAMS perimeter.  Therefore, the next best option is for zcons to
     86  * provide an ioctl interface to zoneadmd to manage holding and releasing
     87  * the slave side of the console.  It is sufficient to hold the slave side's
     88  * vnode and bump the associated snode's reference count to preserve the slave's
     89  * STREAMS configuration while the associated zone runs, so that's what the
     90  * ioctls do.
     91  *
     92  *
     93  * ZC_HOLDSLAVE
     94  *
     95  * This ioctl takes a file descriptor as an argument.  It effectively gets a
     96  * reference to the slave side's minor node's vnode and bumps the associated
     97  * snode's reference count.  The vnode reference is stored in the zcons device
     98  * node's soft state.  This ioctl succeeds if the given file descriptor refers
     99  * to the slave side's minor node or if there is already a reference to the
    100  * slave side's minor node's vnode in the device's soft state.
    101  *
    102  *
    103  * ZC_RELEASESLAVE
    104  *
    105  * This ioctl takes a file descriptor as an argument.  It effectively releases
    106  * the vnode reference stored in the zcons device node's soft state (which was
    107  * previously acquired via ZC_HOLDSLAVE) and decrements the reference count of
    108  * the snode associated with the vnode.  This ioctl succeeds if the given file
    109  * descriptor refers to the slave side's minor node or if no reference to the
    110  * slave side's minor node's vnode is stored in the device's soft state.
    111  *
    112  *
    113  * Note that the file descriptor arguments for both ioctls must be cast to
    114  * integers of pointer width.
    115  *
    116  * Here's how the dance between zcons and zoneadmd works:
    117  *
    118  *     Zone boot:
    119  *     1.  While booting the zone, zoneadmd creates an instance of zcons.
    120  *     2.  zoneadmd opens the master and slave sides of the new zone console
    121  *         and issues the ZC_HOLDSLAVE ioctl on the master side, passing its
    122  *         file descriptor for the slave side as the ioctl argument.
    123  *     3.  zcons holds the slave side's vnode, bumps the snode's reference
    124  *         count, and stores a pointer to the vnode in the device's soft
    125  *         state.
    126  *     4.  zoneadmd closes the master and slave sides and continues to boot
    127  *         the zone.
    128  *
    129  *     Zone halt:
    130  *     1.  While halting the zone, zoneadmd opens the master and slave sides
    131  *         of the zone's console and issues the ZC_RELEASESLAVE ioctl on the
    132  *         master side, passing its file descriptor for the slave side as the
    133  *         ioctl argument.
    134  *     2.  zcons decrements the slave side's snode's reference count, releases
    135  *         the slave's vnode, and eliminates its reference to the vnode in the
    136  *         device's soft state.
    137  *     3.  zoneadmd closes the master and slave sides.
    138  *     4.  zoneadmd destroys the zcons device and continues to halt the zone.
    139  *
    140  * It is necessary for zoneadmd to hold the slave open while issuing
    141  * ZC_RELEASESLAVE because zcons might otherwise release the last reference to
    142  * the slave's vnode.  If it does, then specfs will panic because it will expect
    143  * that the STREAMS configuration for the vnode was destroyed, which VN_RELE
    144  * doesn't do.  Forcing zoneadmd to hold the slave open guarantees that zcons
    145  * won't release the vnode's last reference.  zoneadmd will properly destroy the
    146  * vnode and the snode when it closes the file descriptor.
    147  *
    148  * Technically, any process that can access the master side can issue these
    149  * ioctls, but they should be treated as private interfaces for zoneadmd.
    150  */
    151 
    152 #include <sys/types.h>
    153 #include <sys/cmn_err.h>
    154 #include <sys/conf.h>
    155 #include <sys/cred.h>
    156 #include <sys/ddi.h>
    157 #include <sys/debug.h>
    158 #include <sys/devops.h>
    159 #include <sys/errno.h>
    160 #include <sys/file.h>
    161 #include <sys/kstr.h>
    162 #include <sys/modctl.h>
    163 #include <sys/param.h>
    164 #include <sys/stat.h>
    165 #include <sys/stream.h>
    166 #include <sys/stropts.h>
    167 #include <sys/strsun.h>
    168 #include <sys/sunddi.h>
    169 #include <sys/sysmacros.h>
    170 #include <sys/systm.h>
    171 #include <sys/types.h>
    172 #include <sys/zcons.h>
    173 #include <sys/vnode.h>
    174 #include <sys/fs/snode.h>
    175 #include <sys/zone.h>
    176 
    177 static int zc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
    178 static int zc_attach(dev_info_t *, ddi_attach_cmd_t);
    179 static int zc_detach(dev_info_t *, ddi_detach_cmd_t);
    180 
    181 static int zc_open(queue_t *, dev_t *, int, int, cred_t *);
    182 static int zc_close(queue_t *, int, cred_t *);
    183 static void zc_wput(queue_t *, mblk_t *);
    184 static void zc_rsrv(queue_t *);
    185 static void zc_wsrv(queue_t *);
    186 
    187 /*
    188  * The instance number is encoded in the dev_t in the minor number; the lowest
    189  * bit of the minor number is used to track the master vs. slave side of the
    190  * virtual console.  The rest of the bits in the minor number are the instance.
    191  */
    192 #define	ZC_MASTER_MINOR		0
    193 #define	ZC_SLAVE_MINOR		1
    194 
    195 #define	ZC_INSTANCE(x)		(getminor((x)) >> 1)
    196 #define	ZC_NODE(x)		(getminor((x)) & 0x01)
    197 
    198 /*
    199  * This macro converts a zc_state_t pointer to the associated slave minor node's
    200  * dev_t.
    201  */
    202 #define	ZC_STATE_TO_SLAVEDEV(x)	(makedevice(ddi_driver_major((x)->zc_devinfo), \
    203 	(minor_t)(ddi_get_instance((x)->zc_devinfo) << 1 | ZC_SLAVE_MINOR)))
    204 
    205 int zcons_debug = 0;
    206 #define	DBG(a)   if (zcons_debug) cmn_err(CE_NOTE, a)
    207 #define	DBG1(a, b)   if (zcons_debug) cmn_err(CE_NOTE, a, b)
    208 
    209 
    210 /*
    211  * Zone Console Pseudo Terminal Module: stream data structure definitions
    212  */
    213 static struct module_info zc_info = {
    214 	31337,	/* c0z we r hAx0rs */
    215 	"zcons",
    216 	0,
    217 	INFPSZ,
    218 	2048,
    219 	128
    220 };
    221 
    222 static struct qinit zc_rinit = {
    223 	NULL,
    224 	(int (*)()) zc_rsrv,
    225 	zc_open,
    226 	zc_close,
    227 	NULL,
    228 	&zc_info,
    229 	NULL
    230 };
    231 
    232 static struct qinit zc_winit = {
    233 	(int (*)()) zc_wput,
    234 	(int (*)()) zc_wsrv,
    235 	NULL,
    236 	NULL,
    237 	NULL,
    238 	&zc_info,
    239 	NULL
    240 };
    241 
    242 static struct streamtab zc_tab_info = {
    243 	&zc_rinit,
    244 	&zc_winit,
    245 	NULL,
    246 	NULL
    247 };
    248 
    249 #define	ZC_CONF_FLAG	(D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL)
    250 
    251 /*
    252  * this will define (struct cb_ops cb_zc_ops) and (struct dev_ops zc_ops)
    253  */
    254 DDI_DEFINE_STREAM_OPS(zc_ops, nulldev, nulldev,	zc_attach, zc_detach, nodev, \
    255 	zc_getinfo, ZC_CONF_FLAG, &zc_tab_info, ddi_quiesce_not_needed);
    256 
    257 /*
    258  * Module linkage information for the kernel.
    259  */
    260 
    261 static struct modldrv modldrv = {
    262 	&mod_driverops, 	/* Type of module (this is a pseudo driver) */
    263 	"Zone console driver",	/* description of module */
    264 	&zc_ops			/* driver ops */
    265 };
    266 
    267 static struct modlinkage modlinkage = {
    268 	MODREV_1,
    269 	&modldrv,
    270 	NULL
    271 };
    272 
    273 typedef struct zc_state {
    274 	dev_info_t *zc_devinfo;
    275 	queue_t *zc_master_rdq;
    276 	queue_t *zc_slave_rdq;
    277 	vnode_t *zc_slave_vnode;
    278 	int zc_state;
    279 } zc_state_t;
    280 
    281 #define	ZC_STATE_MOPEN	0x01
    282 #define	ZC_STATE_SOPEN	0x02
    283 
    284 static void *zc_soft_state;
    285 
    286 /*
    287  * List of STREAMS modules that should be pushed onto every slave instance.
    288  */
    289 static char *zcons_mods[] = {
    290 	"ptem",
    291 	"ldterm",
    292 	"ttcompat",
    293 	NULL
    294 };
    295 
    296 int
    297 _init(void)
    298 {
    299 	int err;
    300 
    301 	if ((err = ddi_soft_state_init(&zc_soft_state,
    302 	    sizeof (zc_state_t), 0)) != 0) {
    303 		return (err);
    304 	}
    305 
    306 	if ((err = mod_install(&modlinkage)) != 0)
    307 		ddi_soft_state_fini(zc_soft_state);
    308 
    309 	return (err);
    310 }
    311 
    312 
    313 int
    314 _fini(void)
    315 {
    316 	int err;
    317 
    318 	if ((err = mod_remove(&modlinkage)) != 0) {
    319 		return (err);
    320 	}
    321 
    322 	ddi_soft_state_fini(&zc_soft_state);
    323 	return (0);
    324 }
    325 
    326 int
    327 _info(struct modinfo *modinfop)
    328 {
    329 	return (mod_info(&modlinkage, modinfop));
    330 }
    331 
    332 static int
    333 zc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    334 {
    335 	zc_state_t *zcs;
    336 	int instance;
    337 
    338 	if (cmd != DDI_ATTACH)
    339 		return (DDI_FAILURE);
    340 
    341 	instance = ddi_get_instance(dip);
    342 	if (ddi_soft_state_zalloc(zc_soft_state, instance) != DDI_SUCCESS)
    343 		return (DDI_FAILURE);
    344 
    345 	/*
    346 	 * Create the master and slave minor nodes.
    347 	 */
    348 	if ((ddi_create_minor_node(dip, ZCONS_SLAVE_NAME, S_IFCHR,
    349 	    instance << 1 | ZC_SLAVE_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE) ||
    350 	    (ddi_create_minor_node(dip, ZCONS_MASTER_NAME, S_IFCHR,
    351 	    instance << 1 | ZC_MASTER_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE)) {
    352 		ddi_remove_minor_node(dip, NULL);
    353 		ddi_soft_state_free(zc_soft_state, instance);
    354 		return (DDI_FAILURE);
    355 	}
    356 
    357 	VERIFY((zcs = ddi_get_soft_state(zc_soft_state, instance)) != NULL);
    358 	zcs->zc_devinfo = dip;
    359 	return (DDI_SUCCESS);
    360 }
    361 
    362 static int
    363 zc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    364 {
    365 	zc_state_t *zcs;
    366 	int instance;
    367 
    368 	if (cmd != DDI_DETACH)
    369 		return (DDI_FAILURE);
    370 
    371 	instance = ddi_get_instance(dip);
    372 	if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
    373 		return (DDI_FAILURE);
    374 
    375 	if ((zcs->zc_state & ZC_STATE_MOPEN) ||
    376 	    (zcs->zc_state & ZC_STATE_SOPEN)) {
    377 		DBG1("zc_detach: device (dip=%p) still open\n", (void *)dip);
    378 		return (DDI_FAILURE);
    379 	}
    380 
    381 	ddi_remove_minor_node(dip, NULL);
    382 	ddi_soft_state_free(zc_soft_state, instance);
    383 
    384 	return (DDI_SUCCESS);
    385 }
    386 
    387 /*
    388  * zc_getinfo()
    389  *	getinfo(9e) entrypoint.
    390  */
    391 /*ARGSUSED*/
    392 static int
    393 zc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
    394 {
    395 	zc_state_t *zcs;
    396 	int instance = ZC_INSTANCE((dev_t)arg);
    397 
    398 	switch (infocmd) {
    399 	case DDI_INFO_DEVT2DEVINFO:
    400 		if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
    401 			return (DDI_FAILURE);
    402 		*result = zcs->zc_devinfo;
    403 		return (DDI_SUCCESS);
    404 	case DDI_INFO_DEVT2INSTANCE:
    405 		*result = (void *)(uintptr_t)instance;
    406 		return (DDI_SUCCESS);
    407 	}
    408 	return (DDI_FAILURE);
    409 }
    410 
    411 /*
    412  * Return the equivalent queue from the other side of the relationship.
    413  * e.g.: given the slave's write queue, return the master's write queue.
    414  */
    415 static queue_t *
    416 zc_switch(queue_t *qp)
    417 {
    418 	zc_state_t *zcs = qp->q_ptr;
    419 	ASSERT(zcs != NULL);
    420 
    421 	if (qp == zcs->zc_master_rdq)
    422 		return (zcs->zc_slave_rdq);
    423 	else if (OTHERQ(qp) == zcs->zc_master_rdq && zcs->zc_slave_rdq != NULL)
    424 		return (OTHERQ(zcs->zc_slave_rdq));
    425 	else if (qp == zcs->zc_slave_rdq)
    426 		return (zcs->zc_master_rdq);
    427 	else if (OTHERQ(qp) == zcs->zc_slave_rdq && zcs->zc_master_rdq != NULL)
    428 		return (OTHERQ(zcs->zc_master_rdq));
    429 	else
    430 		return (NULL);
    431 }
    432 
    433 /*
    434  * For debugging and outputting messages.  Returns the name of the side of
    435  * the relationship associated with this queue.
    436  */
    437 static const char *
    438 zc_side(queue_t *qp)
    439 {
    440 	zc_state_t *zcs = qp->q_ptr;
    441 	ASSERT(zcs != NULL);
    442 
    443 	if (qp == zcs->zc_master_rdq ||
    444 	    OTHERQ(qp) == zcs->zc_master_rdq) {
    445 		return ("master");
    446 	}
    447 	ASSERT(qp == zcs->zc_slave_rdq || OTHERQ(qp) == zcs->zc_slave_rdq);
    448 	return ("slave");
    449 }
    450 
    451 /*ARGSUSED*/
    452 static int
    453 zc_master_open(zc_state_t *zcs,
    454     queue_t	*rqp,	/* pointer to the read side queue */
    455     dev_t	*devp,	/* pointer to stream tail's dev */
    456     int		oflag,	/* the user open(2) supplied flags */
    457     int		sflag,	/* open state flag */
    458     cred_t	*credp)	/* credentials */
    459 {
    460 	mblk_t *mop;
    461 	struct stroptions *sop;
    462 
    463 	/*
    464 	 * Enforce exclusivity on the master side; the only consumer should
    465 	 * be the zoneadmd for the zone.
    466 	 */
    467 	if ((zcs->zc_state & ZC_STATE_MOPEN) != 0)
    468 		return (EBUSY);
    469 
    470 	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
    471 		DBG("zc_master_open(): mop allocation failed\n");
    472 		return (ENOMEM);
    473 	}
    474 
    475 	zcs->zc_state |= ZC_STATE_MOPEN;
    476 
    477 	/*
    478 	 * q_ptr stores driver private data; stash the soft state data on both
    479 	 * read and write sides of the queue.
    480 	 */
    481 	WR(rqp)->q_ptr = rqp->q_ptr = zcs;
    482 	qprocson(rqp);
    483 
    484 	/*
    485 	 * Following qprocson(), the master side is fully plumbed into the
    486 	 * STREAM and may send/receive messages.  Setting zcs->zc_master_rdq
    487 	 * will allow the slave to send messages to us (the master).
    488 	 * This cannot occur before qprocson() because the master is not
    489 	 * ready to process them until that point.
    490 	 */
    491 	zcs->zc_master_rdq = rqp;
    492 
    493 	/*
    494 	 * set up hi/lo water marks on stream head read queue and add
    495 	 * controlling tty as needed.
    496 	 */
    497 	mop->b_datap->db_type = M_SETOPTS;
    498 	mop->b_wptr += sizeof (struct stroptions);
    499 	sop = (struct stroptions *)(void *)mop->b_rptr;
    500 	if (oflag & FNOCTTY)
    501 		sop->so_flags = SO_HIWAT | SO_LOWAT;
    502 	else
    503 		sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
    504 	sop->so_hiwat = 512;
    505 	sop->so_lowat = 256;
    506 	putnext(rqp, mop);
    507 
    508 	return (0);
    509 }
    510 
    511 /*ARGSUSED*/
    512 static int
    513 zc_slave_open(zc_state_t *zcs,
    514     queue_t	*rqp,	/* pointer to the read side queue */
    515     dev_t	*devp,	/* pointer to stream tail's dev */
    516     int		oflag,	/* the user open(2) supplied flags */
    517     int		sflag,	/* open state flag */
    518     cred_t	*credp)	/* credentials */
    519 {
    520 	mblk_t *mop;
    521 	struct stroptions *sop;
    522 	major_t major;
    523 	minor_t minor;
    524 	minor_t lastminor;
    525 	uint_t anchorindex;
    526 
    527 	/*
    528 	 * The slave side can be opened as many times as needed.
    529 	 */
    530 	if ((zcs->zc_state & ZC_STATE_SOPEN) != 0) {
    531 		ASSERT((rqp != NULL) && (WR(rqp)->q_ptr == zcs));
    532 		return (0);
    533 	}
    534 
    535 	/*
    536 	 * Set up sad(7D) so that the necessary STREAMS modules will be in
    537 	 * place.  A wrinkle is that 'ptem' must be anchored
    538 	 * in place (see streamio(7i)) because we always want the console to
    539 	 * have terminal semantics.
    540 	 */
    541 	minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
    542 	major = ddi_driver_major(zcs->zc_devinfo);
    543 	lastminor = 0;
    544 	anchorindex = 1;
    545 	if (kstr_autopush(SET_AUTOPUSH, &major, &minor, &lastminor,
    546 	    &anchorindex, zcons_mods) != 0) {
    547 		DBG("zc_slave_open(): kstr_autopush() failed\n");
    548 		return (EIO);
    549 	}
    550 
    551 	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
    552 		DBG("zc_slave_open(): mop allocation failed\n");
    553 		return (ENOMEM);
    554 	}
    555 
    556 	zcs->zc_state |= ZC_STATE_SOPEN;
    557 
    558 	/*
    559 	 * q_ptr stores driver private data; stash the soft state data on both
    560 	 * read and write sides of the queue.
    561 	 */
    562 	WR(rqp)->q_ptr = rqp->q_ptr = zcs;
    563 
    564 	qprocson(rqp);
    565 
    566 	/*
    567 	 * Must follow qprocson(), since we aren't ready to process until then.
    568 	 */
    569 	zcs->zc_slave_rdq = rqp;
    570 
    571 	/*
    572 	 * set up hi/lo water marks on stream head read queue and add
    573 	 * controlling tty as needed.
    574 	 */
    575 	mop->b_datap->db_type = M_SETOPTS;
    576 	mop->b_wptr += sizeof (struct stroptions);
    577 	sop = (struct stroptions *)(void *)mop->b_rptr;
    578 	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
    579 	sop->so_hiwat = 512;
    580 	sop->so_lowat = 256;
    581 	putnext(rqp, mop);
    582 
    583 	return (0);
    584 }
    585 
    586 /*
    587  * open(9e) entrypoint; checks sflag, and rejects anything unordinary.
    588  */
    589 static int
    590 zc_open(queue_t *rqp,		/* pointer to the read side queue */
    591 	dev_t   *devp,		/* pointer to stream tail's dev */
    592 	int	oflag,		/* the user open(2) supplied flags */
    593 	int	sflag,		/* open state flag */
    594 	cred_t  *credp)		/* credentials */
    595 {
    596 	int instance = ZC_INSTANCE(*devp);
    597 	int ret;
    598 	zc_state_t *zcs;
    599 
    600 	if (sflag != 0)
    601 		return (EINVAL);
    602 
    603 	if ((zcs = ddi_get_soft_state(zc_soft_state, instance)) == NULL)
    604 		return (ENXIO);
    605 
    606 	switch (ZC_NODE(*devp)) {
    607 	case ZC_MASTER_MINOR:
    608 		ret = zc_master_open(zcs, rqp, devp, oflag, sflag, credp);
    609 		break;
    610 	case ZC_SLAVE_MINOR:
    611 		ret = zc_slave_open(zcs, rqp, devp, oflag, sflag, credp);
    612 		break;
    613 	default:
    614 		ret = ENXIO;
    615 		break;
    616 	}
    617 
    618 	return (ret);
    619 }
    620 
    621 /*
    622  * close(9e) entrypoint.
    623  */
    624 /*ARGSUSED1*/
    625 static int
    626 zc_close(queue_t *rqp, int flag, cred_t *credp)
    627 {
    628 	queue_t *wqp;
    629 	mblk_t	*bp;
    630 	zc_state_t *zcs;
    631 	major_t major;
    632 	minor_t minor;
    633 
    634 	zcs = (zc_state_t *)rqp->q_ptr;
    635 
    636 	if (rqp == zcs->zc_master_rdq) {
    637 		DBG("Closing master side");
    638 
    639 		zcs->zc_master_rdq = NULL;
    640 		zcs->zc_state &= ~ZC_STATE_MOPEN;
    641 
    642 		/*
    643 		 * qenable slave side write queue so that it can flush
    644 		 * its messages as master's read queue is going away
    645 		 */
    646 		if (zcs->zc_slave_rdq != NULL) {
    647 			qenable(WR(zcs->zc_slave_rdq));
    648 		}
    649 
    650 		qprocsoff(rqp);
    651 		WR(rqp)->q_ptr = rqp->q_ptr = NULL;
    652 
    653 	} else if (rqp == zcs->zc_slave_rdq) {
    654 
    655 		DBG("Closing slave side");
    656 		zcs->zc_state &= ~ZC_STATE_SOPEN;
    657 		zcs->zc_slave_rdq = NULL;
    658 
    659 		wqp = WR(rqp);
    660 		while ((bp = getq(wqp)) != NULL) {
    661 			if (zcs->zc_master_rdq != NULL)
    662 				putnext(zcs->zc_master_rdq, bp);
    663 			else if (bp->b_datap->db_type == M_IOCTL)
    664 				miocnak(wqp, bp, 0, 0);
    665 			else
    666 				freemsg(bp);
    667 		}
    668 
    669 		/*
    670 		 * Qenable master side write queue so that it can flush its
    671 		 * messages as slaves's read queue is going away.
    672 		 */
    673 		if (zcs->zc_master_rdq != NULL)
    674 			qenable(WR(zcs->zc_master_rdq));
    675 
    676 		qprocsoff(rqp);
    677 		WR(rqp)->q_ptr = rqp->q_ptr = NULL;
    678 
    679 		/*
    680 		 * Clear the sad configuration so that reopening doesn't fail
    681 		 * to set up sad configuration.
    682 		 */
    683 		major = ddi_driver_major(zcs->zc_devinfo);
    684 		minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
    685 		(void) kstr_autopush(CLR_AUTOPUSH, &major, &minor, NULL, NULL,
    686 		    NULL);
    687 	}
    688 
    689 	return (0);
    690 }
    691 
    692 static void
    693 handle_mflush(queue_t *qp, mblk_t *mp)
    694 {
    695 	mblk_t *nmp;
    696 	DBG1("M_FLUSH on %s side", zc_side(qp));
    697 
    698 	if (*mp->b_rptr & FLUSHW) {
    699 		DBG1("M_FLUSH, FLUSHW, %s side", zc_side(qp));
    700 		flushq(qp, FLUSHDATA);
    701 		*mp->b_rptr &= ~FLUSHW;
    702 		if ((*mp->b_rptr & FLUSHR) == 0) {
    703 			/*
    704 			 * FLUSHW only. Change to FLUSHR and putnext other side,
    705 			 * then we are done.
    706 			 */
    707 			*mp->b_rptr |= FLUSHR;
    708 			if (zc_switch(RD(qp)) != NULL) {
    709 				putnext(zc_switch(RD(qp)), mp);
    710 				return;
    711 			}
    712 		} else if ((zc_switch(RD(qp)) != NULL) &&
    713 		    (nmp = copyb(mp)) != NULL) {
    714 			/*
    715 			 * It is a FLUSHRW; we copy the mblk and send
    716 			 * it to the other side, since we still need to use
    717 			 * the mblk in FLUSHR processing, below.
    718 			 */
    719 			putnext(zc_switch(RD(qp)), nmp);
    720 		}
    721 	}
    722 
    723 	if (*mp->b_rptr & FLUSHR) {
    724 		DBG("qreply(qp) turning FLUSHR around\n");
    725 		qreply(qp, mp);
    726 		return;
    727 	}
    728 	freemsg(mp);
    729 }
    730 
    731 /*
    732  * wput(9E) is symmetric for master and slave sides, so this handles both
    733  * without splitting the codepath.  (The only exception to this is the
    734  * processing of zcons ioctls, which is restricted to the master side.)
    735  *
    736  * zc_wput() looks at the other side; if there is no process holding that
    737  * side open, it frees the message.  This prevents processes from hanging
    738  * if no one is holding open the console.  Otherwise, it putnext's high
    739  * priority messages, putnext's normal messages if possible, and otherwise
    740  * enqueues the messages; in the case that something is enqueued, wsrv(9E)
    741  * will take care of eventually shuttling I/O to the other side.
    742  */
    743 static void
    744 zc_wput(queue_t *qp, mblk_t *mp)
    745 {
    746 	unsigned char type = mp->b_datap->db_type;
    747 	zc_state_t *zcs;
    748 	struct iocblk *iocbp;
    749 	file_t *slave_filep;
    750 	struct snode *slave_snodep;
    751 	int slave_fd;
    752 
    753 	ASSERT(qp->q_ptr);
    754 
    755 	DBG1("entering zc_wput, %s side", zc_side(qp));
    756 
    757 	/*
    758 	 * Process zcons ioctl messages if qp is the master console's write
    759 	 * queue.
    760 	 */
    761 	zcs = (zc_state_t *)qp->q_ptr;
    762 	if (zcs->zc_master_rdq != NULL && qp == WR(zcs->zc_master_rdq) &&
    763 	    type == M_IOCTL) {
    764 		iocbp = (struct iocblk *)(void *)mp->b_rptr;
    765 		switch (iocbp->ioc_cmd) {
    766 		case ZC_HOLDSLAVE:
    767 			/*
    768 			 * Hold the slave's vnode and increment the refcount
    769 			 * of the snode.  If the vnode is already held, then
    770 			 * indicate success.
    771 			 */
    772 			if (iocbp->ioc_count != TRANSPARENT) {
    773 				miocack(qp, mp, 0, EINVAL);
    774 				return;
    775 			}
    776 			if (zcs->zc_slave_vnode != NULL) {
    777 				miocack(qp, mp, 0, 0);
    778 				return;
    779 			}
    780 
    781 			/*
    782 			 * The process that passed the ioctl must be running in
    783 			 * the global zone.
    784 			 */
    785 			if (curzone != global_zone) {
    786 				miocack(qp, mp, 0, EINVAL);
    787 				return;
    788 			}
    789 
    790 			/*
    791 			 * The calling process must pass a file descriptor for
    792 			 * the slave device.
    793 			 */
    794 			slave_fd =
    795 			    (int)(intptr_t)*(caddr_t *)(void *)mp->b_cont->
    796 			    b_rptr;
    797 			slave_filep = getf(slave_fd);
    798 			if (slave_filep == NULL) {
    799 				miocack(qp, mp, 0, EINVAL);
    800 				return;
    801 			}
    802 			if (ZC_STATE_TO_SLAVEDEV(zcs) !=
    803 			    slave_filep->f_vnode->v_rdev) {
    804 				releasef(slave_fd);
    805 				miocack(qp, mp, 0, EINVAL);
    806 				return;
    807 			}
    808 
    809 			/*
    810 			 * Get a reference to the slave's vnode.  Also bump the
    811 			 * reference count on the associated snode.
    812 			 */
    813 			ASSERT(vn_matchops(slave_filep->f_vnode,
    814 			    spec_getvnodeops()));
    815 			zcs->zc_slave_vnode = slave_filep->f_vnode;
    816 			VN_HOLD(zcs->zc_slave_vnode);
    817 			slave_snodep = VTOCS(zcs->zc_slave_vnode);
    818 			mutex_enter(&slave_snodep->s_lock);
    819 			++slave_snodep->s_count;
    820 			mutex_exit(&slave_snodep->s_lock);
    821 			releasef(slave_fd);
    822 			miocack(qp, mp, 0, 0);
    823 			return;
    824 		case ZC_RELEASESLAVE:
    825 			/*
    826 			 * Release the master's handle on the slave's vnode.
    827 			 * If there isn't a handle for the vnode, then indicate
    828 			 * success.
    829 			 */
    830 			if (iocbp->ioc_count != TRANSPARENT) {
    831 				miocack(qp, mp, 0, EINVAL);
    832 				return;
    833 			}
    834 			if (zcs->zc_slave_vnode == NULL) {
    835 				miocack(qp, mp, 0, 0);
    836 				return;
    837 			}
    838 
    839 			/*
    840 			 * The process that passed the ioctl must be running in
    841 			 * the global zone.
    842 			 */
    843 			if (curzone != global_zone) {
    844 				miocack(qp, mp, 0, EINVAL);
    845 				return;
    846 			}
    847 
    848 			/*
    849 			 * The process that passed the ioctl must have provided
    850 			 * a file descriptor for the slave device.  Make sure
    851 			 * this is correct.
    852 			 */
    853 			slave_fd =
    854 			    (int)(intptr_t)*(caddr_t *)(void *)mp->b_cont->
    855 			    b_rptr;
    856 			slave_filep = getf(slave_fd);
    857 			if (slave_filep == NULL) {
    858 				miocack(qp, mp, 0, EINVAL);
    859 				return;
    860 			}
    861 			if (zcs->zc_slave_vnode->v_rdev !=
    862 			    slave_filep->f_vnode->v_rdev) {
    863 				releasef(slave_fd);
    864 				miocack(qp, mp, 0, EINVAL);
    865 				return;
    866 			}
    867 
    868 			/*
    869 			 * Decrement the snode's reference count and release the
    870 			 * vnode.
    871 			 */
    872 			ASSERT(vn_matchops(slave_filep->f_vnode,
    873 			    spec_getvnodeops()));
    874 			slave_snodep = VTOCS(zcs->zc_slave_vnode);
    875 			mutex_enter(&slave_snodep->s_lock);
    876 			--slave_snodep->s_count;
    877 			mutex_exit(&slave_snodep->s_lock);
    878 			VN_RELE(zcs->zc_slave_vnode);
    879 			zcs->zc_slave_vnode = NULL;
    880 			releasef(slave_fd);
    881 			miocack(qp, mp, 0, 0);
    882 			return;
    883 		default:
    884 			break;
    885 		}
    886 	}
    887 
    888 	if (zc_switch(RD(qp)) == NULL) {
    889 		DBG1("wput to %s side (no one listening)", zc_side(qp));
    890 		switch (type) {
    891 		case M_FLUSH:
    892 			handle_mflush(qp, mp);
    893 			break;
    894 		case M_IOCTL:
    895 			miocnak(qp, mp, 0, 0);
    896 			break;
    897 		default:
    898 			freemsg(mp);
    899 			break;
    900 		}
    901 		return;
    902 	}
    903 
    904 	if (type >= QPCTL) {
    905 		DBG1("(hipri) wput, %s side", zc_side(qp));
    906 		switch (type) {
    907 		case M_READ:		/* supposedly from ldterm? */
    908 			DBG("zc_wput: tossing M_READ\n");
    909 			freemsg(mp);
    910 			break;
    911 		case M_FLUSH:
    912 			handle_mflush(qp, mp);
    913 			break;
    914 		default:
    915 			/*
    916 			 * Put this to the other side.
    917 			 */
    918 			ASSERT(zc_switch(RD(qp)) != NULL);
    919 			putnext(zc_switch(RD(qp)), mp);
    920 			break;
    921 		}
    922 		DBG1("done (hipri) wput, %s side", zc_side(qp));
    923 		return;
    924 	}
    925 
    926 	/*
    927 	 * Only putnext if there isn't already something in the queue.
    928 	 * otherwise things would wind up out of order.
    929 	 */
    930 	if (qp->q_first == NULL && bcanputnext(RD(zc_switch(qp)), mp->b_band)) {
    931 		DBG("wput: putting message to other side\n");
    932 		putnext(RD(zc_switch(qp)), mp);
    933 	} else {
    934 		DBG("wput: putting msg onto queue\n");
    935 		(void) putq(qp, mp);
    936 	}
    937 	DBG1("done wput, %s side", zc_side(qp));
    938 }
    939 
    940 /*
    941  * rsrv(9E) is symmetric for master and slave, so zc_rsrv() handles both
    942  * without splitting up the codepath.
    943  *
    944  * Enable the write side of the partner.  This triggers the partner to send
    945  * messages queued on its write side to this queue's read side.
    946  */
    947 static void
    948 zc_rsrv(queue_t *qp)
    949 {
    950 	zc_state_t *zcs;
    951 	zcs = (zc_state_t *)qp->q_ptr;
    952 
    953 	/*
    954 	 * Care must be taken here, as either of the master or slave side
    955 	 * qptr could be NULL.
    956 	 */
    957 	ASSERT(qp == zcs->zc_master_rdq || qp == zcs->zc_slave_rdq);
    958 	if (zc_switch(qp) == NULL) {
    959 		DBG("zc_rsrv: other side isn't listening\n");
    960 		return;
    961 	}
    962 	qenable(WR(zc_switch(qp)));
    963 }
    964 
    965 /*
    966  * This routine is symmetric for master and slave, so it handles both without
    967  * splitting up the codepath.
    968  *
    969  * If there are messages on this queue that can be sent to the other, send
    970  * them via putnext(). Else, if queued messages cannot be sent, leave them
    971  * on this queue.
    972  */
    973 static void
    974 zc_wsrv(queue_t *qp)
    975 {
    976 	mblk_t *mp;
    977 
    978 	DBG1("zc_wsrv master (%s) side", zc_side(qp));
    979 
    980 	/*
    981 	 * Partner has no read queue, so take the data, and throw it away.
    982 	 */
    983 	if (zc_switch(RD(qp)) == NULL) {
    984 		DBG("zc_wsrv: other side isn't listening");
    985 		while ((mp = getq(qp)) != NULL) {
    986 			if (mp->b_datap->db_type == M_IOCTL)
    987 				miocnak(qp, mp, 0, 0);
    988 			else
    989 				freemsg(mp);
    990 		}
    991 		flushq(qp, FLUSHALL);
    992 		return;
    993 	}
    994 
    995 	/*
    996 	 * while there are messages on this write queue...
    997 	 */
    998 	while ((mp = getq(qp)) != NULL) {
    999 		/*
   1000 		 * Due to the way zc_wput is implemented, we should never
   1001 		 * see a control message here.
   1002 		 */
   1003 		ASSERT(mp->b_datap->db_type < QPCTL);
   1004 
   1005 		if (bcanputnext(RD(zc_switch(qp)), mp->b_band)) {
   1006 			DBG("wsrv: send message to other side\n");
   1007 			putnext(RD(zc_switch(qp)), mp);
   1008 		} else {
   1009 			DBG("wsrv: putting msg back on queue\n");
   1010 			(void) putbq(qp, mp);
   1011 			break;
   1012 		}
   1013 	}
   1014 }
   1015