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 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 
     28 #include <sys/types.h>
     29 #include <sys/file.h>
     30 #include <sys/errno.h>
     31 #include <sys/uio.h>
     32 #include <sys/open.h>
     33 #include <sys/cred.h>
     34 #include <sys/kmem.h>
     35 #include <sys/conf.h>
     36 #include <sys/cmn_err.h>
     37 #include <sys/ksynch.h>
     38 #include <sys/modctl.h>
     39 #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
     40 #include <sys/debug.h>
     41 #include <sys/promif.h>
     42 #include <sys/ddi.h>
     43 #include <sys/sunddi.h>
     44 #include <sys/cyclic.h>
     45 #include <sys/termio.h>
     46 #include <sys/intr.h>
     47 #include <sys/ivintr.h>
     48 #include <sys/note.h>
     49 #include <sys/stat.h>
     50 #include <sys/fcntl.h>
     51 #include <sys/sysmacros.h>
     52 
     53 #include <sys/ldc.h>
     54 #include <sys/mdeg.h>
     55 #include <sys/vcc_impl.h>
     56 
     57 #define	VCC_LDC_RETRIES		5
     58 #define	VCC_LDC_DELAY		1000 /* usec */
     59 
     60 /*
     61  * Function prototypes.
     62  */
     63 
     64 /* DDI entrypoints */
     65 static int	vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
     66 static int	vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
     67 static int	vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred);
     68 static int	vcc_close(dev_t dev, int flag, int otyp, cred_t *cred);
     69 static int	vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
     70 			cred_t *credp, int *rvalp);
     71 static int	vcc_read(dev_t dev, struct uio *uiop, cred_t *credp);
     72 static int	vcc_write(dev_t dev, struct uio *uiop, cred_t *credp);
     73 static int	vcc_chpoll(dev_t dev, short events, int anyyet,
     74 			short *reventsp, struct pollhead **phpp);
     75 static int	vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
     76 			void *arg, void **resultp);
     77 
     78 /* callback functions */
     79 static uint_t	vcc_ldc_cb(uint64_t event, caddr_t arg);
     80 static int	vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
     81 
     82 /* Internal functions */
     83 static int	i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport);
     84 static int	i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port,
     85 			uint_t portno, char *domain_name);
     86 static int	i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id);
     87 static int	i_vcc_reset_events(vcc_t *vccp);
     88 static int	i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports,
     89 			caddr_t buf, int mode);
     90 static int	i_vcc_del_cons_ok(vcc_t *vccp, caddr_t buf, int mode);
     91 static int	i_vcc_close_port(vcc_port_t *vport);
     92 static int	i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf);
     93 static int	i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz);
     94 
     95 static void *vcc_ssp;
     96 
     97 static struct cb_ops vcc_cb_ops = {
     98 	vcc_open,	    /* open */
     99 	vcc_close,	    /* close */
    100 	nodev,		    /* strategy */
    101 	nodev,		    /* print */
    102 	nodev,		    /* dump */
    103 	vcc_read,	    /* read */
    104 	vcc_write,	    /* write */
    105 	vcc_ioctl,	    /* ioctl */
    106 	nodev,		    /* devmap */
    107 	nodev,		    /* mmap */
    108 	ddi_segmap,	    /* segmap */
    109 	vcc_chpoll,	    /* chpoll */
    110 	ddi_prop_op,	    /* prop_op */
    111 	NULL,		    /* stream */
    112 	D_NEW | D_MP	    /* flags */
    113 };
    114 
    115 
    116 static struct dev_ops vcc_ops = {
    117 	DEVO_REV,		/* rev */
    118 	0,			/* ref count */
    119 	vcc_getinfo,		/* getinfo */
    120 	nulldev,		/* identify */
    121 	nulldev,		/* probe */
    122 	vcc_attach,		/* attach */
    123 	vcc_detach,		/* detach */
    124 	nodev,			/* reset */
    125 	&vcc_cb_ops,		/* cb_ops */
    126 	(struct bus_ops *)NULL,	/* bus_ops */
    127 	NULL,			/* power */
    128 	ddi_quiesce_not_needed,		/* quiesce */
    129 };
    130 
    131 extern struct mod_ops mod_driverops;
    132 
    133 #define	    VCC_CHANNEL_ENDPOINT	"channel-endpoint"
    134 #define	    VCC_ID_PROP		"id"
    135 
    136 /*
    137  * This is the string displayed by modinfo(1m).
    138  */
    139 static char vcc_ident[] = "sun4v Virtual Console Concentrator Driver";
    140 
    141 static struct modldrv md = {
    142 	&mod_driverops, 	/* Type - it is a driver */
    143 	vcc_ident,		/* Name of the module */
    144 	&vcc_ops,		/* driver specfic opts */
    145 };
    146 
    147 static struct modlinkage ml = {
    148 	MODREV_1,
    149 	&md,
    150 	NULL
    151 };
    152 
    153 /*
    154  * Matching criteria passed to the MDEG to register interest
    155  * in changes to 'virtual-device-port' nodes identified by their
    156  * 'id' property.
    157  */
    158 static md_prop_match_t vcc_port_prop_match[] = {
    159 	{ MDET_PROP_VAL,	    "id"   },
    160 	{ MDET_LIST_END,	    NULL    }
    161 };
    162 
    163 static mdeg_node_match_t vcc_port_match = {"virtual-device-port",
    164 					vcc_port_prop_match};
    165 
    166 /*
    167  * Specification of an MD node passed to the MDEG to filter any
    168  * 'virtual-device-port' nodes that do not belong to the specified node.
    169  * This template is copied for each vldc instance and filled in with
    170  * the appropriate 'cfg-handle' value before being passed to the MDEG.
    171  */
    172 static mdeg_prop_spec_t vcc_prop_template[] = {
    173 	{ MDET_PROP_STR,    "name",	"virtual-console-concentrator"	},
    174 	{ MDET_PROP_VAL,    "cfg-handle",	NULL	},
    175 	{ MDET_LIST_END,    NULL,		NULL	}
    176 };
    177 
    178 #define	VCC_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val);
    179 
    180 
    181 #ifdef DEBUG
    182 
    183 /*
    184  * Print debug messages
    185  *
    186  * set vldcdbg to 0xf to enable all messages
    187  *
    188  * 0x8 - Errors
    189  * 0x4 - Warnings
    190  * 0x2 - All debug messages (most verbose)
    191  * 0x1 - Minimal debug messages
    192  */
    193 
    194 int vccdbg = 0x8;
    195 
    196 static void
    197 vccdebug(const char *fmt, ...)
    198 {
    199 	char buf[512];
    200 	va_list ap;
    201 
    202 	va_start(ap, fmt);
    203 	(void) vsprintf(buf, fmt, ap);
    204 	va_end(ap);
    205 
    206 	cmn_err(CE_CONT, "%s\n", buf);
    207 }
    208 
    209 #define	D1		\
    210 if (vccdbg & 0x01)	\
    211 	vccdebug
    212 
    213 #define	D2		\
    214 if (vccdbg & 0x02)	\
    215 	vccdebug
    216 
    217 #define	DWARN		\
    218 if (vccdbg & 0x04)	\
    219 	vccdebug
    220 
    221 #else
    222 
    223 #define	D1
    224 #define	D2
    225 #define	DWARN
    226 
    227 #endif
    228 
    229 /* _init(9E): initialize the loadable module */
    230 int
    231 _init(void)
    232 {
    233 	int error;
    234 
    235 	/* init the soft state structure */
    236 	error = ddi_soft_state_init(&vcc_ssp, sizeof (vcc_t), 1);
    237 	if (error != 0) {
    238 		return (error);
    239 	}
    240 
    241 	/* Link the driver into the system */
    242 	error = mod_install(&ml);
    243 
    244 	return (error);
    245 
    246 }
    247 
    248 /* _info(9E): return information about the loadable module */
    249 int
    250 _info(struct modinfo *modinfop)
    251 {
    252 	/* Report status of the dynamically loadable driver module */
    253 	return (mod_info(&ml, modinfop));
    254 }
    255 
    256 /* _fini(9E): prepare the module for unloading. */
    257 int
    258 _fini(void)
    259 {
    260 	int error;
    261 
    262 	/* Unlink the driver module from the system */
    263 	if ((error = mod_remove(&ml)) == 0) {
    264 		/*
    265 		 * We have successfully "removed" the driver.
    266 		 * destroy soft state
    267 		 */
    268 		ddi_soft_state_fini(&vcc_ssp);
    269 	}
    270 
    271 	return (error);
    272 }
    273 
    274 /* getinfo(9E) */
    275 static int
    276 vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,  void *arg, void **resultp)
    277 {
    278 	_NOTE(ARGUNUSED(dip))
    279 
    280 	int	instance = VCCINST(getminor((dev_t)arg));
    281 	vcc_t	*vccp = NULL;
    282 
    283 	switch (cmd) {
    284 
    285 	case DDI_INFO_DEVT2DEVINFO:
    286 		if ((vccp = ddi_get_soft_state(vcc_ssp, instance)) == NULL) {
    287 			*resultp = NULL;
    288 			return (DDI_FAILURE);
    289 		}
    290 		*resultp = vccp->dip;
    291 		return (DDI_SUCCESS);
    292 
    293 	case DDI_INFO_DEVT2INSTANCE:
    294 		*resultp = (void *)(uintptr_t)instance;
    295 		return (DDI_SUCCESS);
    296 
    297 	default:
    298 		*resultp = NULL;
    299 		return (DDI_FAILURE);
    300 	}
    301 }
    302 
    303 /*
    304  * There are two cases that need special blocking. One of them is to block
    305  * a minor node without a port and another is to block application other
    306  * than vntsd.
    307  *
    308  * A minor node can exist in the file system without associated with a port
    309  * because when a port is deleted, ddi_remove_minor does not unlink it.
    310  * Clients might try to open a minor node even after the corresponding port
    311  * node has been removed.  To identify and block these calls,
    312  * we need to validate the association between a port and its minor node.
    313  *
    314  * An application other than vntsd can access a console port as long
    315  * as vntsd is not using the port. A port opened by an application other
    316  * than vntsd will be closed when vntsd wants to use the port.
    317  * However, other application could use same file descriptor
    318  * access vcc cb_ops. So we need to identify and block caller other
    319  * than vntsd, when vntsd is using the port.
    320  */
    321 static int
    322 i_vcc_can_use_port(vcc_minor_t *minorp, vcc_port_t *vport)
    323 {
    324 	if (vport->minorp != minorp) {
    325 		/* port config changed */
    326 		return (ENXIO);
    327 	}
    328 
    329 	if (vport->valid_pid == VCC_NO_PID_BLOCKING) {
    330 		/* no blocking needed */
    331 		return (0);
    332 	}
    333 
    334 	if (vport->valid_pid != ddi_get_pid()) {
    335 		return (EIO);
    336 	}
    337 
    338 	return (0);
    339 }
    340 
    341 
    342 /* Syncronization between thread using cv_wait */
    343 static int
    344 i_vcc_wait_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status)
    345 {
    346 
    347 	int	    rv;
    348 
    349 	ASSERT(mutex_owned(&vport->lock));
    350 
    351 	for (; ; ) {
    352 
    353 		if ((vport->status & VCC_PORT_AVAIL) == 0) {
    354 			/* port has been deleted */
    355 			D1("i_vcc_wait_port_status: port%d deleted\n",
    356 			    vport->number);
    357 			return (EIO);
    358 		}
    359 
    360 		if ((vport->status & VCC_PORT_OPEN) == 0) {
    361 			D1("i_vcc_wait_port_status: port%d is closed \n",
    362 			    vport->number);
    363 			return (EIO);
    364 		}
    365 
    366 		if (vport->status & VCC_PORT_LDC_LINK_DOWN) {
    367 			return (EIO);
    368 		}
    369 
    370 		if ((vport->valid_pid != VCC_NO_PID_BLOCKING) &&
    371 		    (vport->valid_pid != ddi_get_pid())) {
    372 			return (EIO);
    373 		}
    374 
    375 		if ((vport->status & status) == status) {
    376 			return (0);
    377 		}
    378 
    379 		if (!ddi_can_receive_sig()) {
    380 			return (EIO);
    381 		}
    382 
    383 		rv = cv_wait_sig(cv, &vport->lock);
    384 		if (rv == 0) {
    385 			D1("i_vcc_wait_port_status: port%d get intr \n",
    386 			    vport->number);
    387 			/* got signal */
    388 			return (EINTR);
    389 		}
    390 	}
    391 
    392 }
    393 
    394 /* Syncronization between threads, signal state change */
    395 static void
    396 i_vcc_set_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status)
    397 {
    398 
    399 	mutex_enter(&vport->lock);
    400 	vport->status |= status;
    401 	cv_broadcast(cv);
    402 	mutex_exit(&vport->lock);
    403 }
    404 
    405 /* initialize a ldc channel */
    406 static int
    407 i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport)
    408 {
    409 	ldc_attr_t 	attr;
    410 	int		rv = EIO;
    411 
    412 	ASSERT(mutex_owned(&vport->lock));
    413 	ASSERT(vport->ldc_id != VCC_INVALID_CHANNEL);
    414 
    415 	/* initialize the channel */
    416 	attr.devclass = LDC_DEV_SERIAL;
    417 	attr.instance = ddi_get_instance(vccp->dip);
    418 	attr.mtu = VCC_MTU_SZ;
    419 	attr.mode = LDC_MODE_RAW;
    420 
    421 	if ((rv = ldc_init(vport->ldc_id, &attr, &(vport->ldc_handle))) != 0) {
    422 		cmn_err(CE_CONT, "i_vcc_ldc_init: port %d ldc channel %ld"
    423 		    " failed ldc_init %d \n", vport->number, vport->ldc_id, rv);
    424 		vport->ldc_id = VCC_INVALID_CHANNEL;
    425 		return (rv);
    426 	}
    427 
    428 	/* register it */
    429 	if ((rv = ldc_reg_callback(vport->ldc_handle, vcc_ldc_cb,
    430 	    (caddr_t)vport)) != 0) {
    431 		cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_register_cb"
    432 		    "failed\n", vport->number);
    433 		(void) ldc_fini(vport->ldc_handle);
    434 		vport->ldc_id = VCC_INVALID_CHANNEL;
    435 		return (rv);
    436 	}
    437 
    438 	/* open and bring channel up */
    439 	if ((rv = ldc_open(vport->ldc_handle)) != 0) {
    440 		cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d inv channel 0x%lx\n",
    441 		    vport->number, vport->ldc_id);
    442 		(void) ldc_unreg_callback(vport->ldc_handle);
    443 		(void) ldc_fini(vport->ldc_handle);
    444 		vport->ldc_id = VCC_INVALID_CHANNEL;
    445 		return (rv);
    446 	}
    447 
    448 	/* init the channel status */
    449 	if ((rv = ldc_status(vport->ldc_handle, &vport->ldc_status)) != 0) {
    450 		cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_status failed\n",
    451 		    vport->number);
    452 		(void) ldc_close(vport->ldc_handle);
    453 		(void) ldc_unreg_callback(vport->ldc_handle);
    454 		(void) ldc_fini(vport->ldc_handle);
    455 		vport->ldc_id = VCC_INVALID_CHANNEL;
    456 		return (rv);
    457 	}
    458 
    459 	return (0);
    460 }
    461 
    462 /*  release a ldc channel */
    463 static void
    464 i_vcc_ldc_fini(vcc_port_t *vport)
    465 {
    466 	int 		rv = EIO;
    467 	vcc_msg_t	buf;
    468 	size_t		sz;
    469 	int		retry = 0;
    470 
    471 	D1("i_vcc_ldc_fini: port@%lld, ldc_id%%llx\n", vport->number,
    472 	    vport->ldc_id);
    473 
    474 	ASSERT(mutex_owned(&vport->lock));
    475 
    476 	/* wait for write available */
    477 	rv = i_vcc_wait_port_status(vport, &vport->write_cv,
    478 	    VCC_PORT_USE_WRITE_LDC);
    479 
    480 	if (rv == 0) {
    481 		vport->status &= ~VCC_PORT_USE_WRITE_LDC;
    482 
    483 		/* send a HUP message */
    484 		buf.type = LDC_CONSOLE_CTRL;
    485 		buf.ctrl_msg = LDC_CONSOLE_HUP;
    486 		buf.size = 0;
    487 
    488 		/*
    489 		 * ignore write error since we still want to clean up
    490 		 * ldc channel.
    491 		 */
    492 		(void) i_vcc_write_ldc(vport, &buf);
    493 
    494 		mutex_exit(&vport->lock);
    495 		i_vcc_set_port_status(vport, &vport->write_cv,
    496 		    VCC_PORT_USE_WRITE_LDC);
    497 		mutex_enter(&vport->lock);
    498 	}
    499 
    500 	/* flush ldc channel */
    501 	rv = i_vcc_wait_port_status(vport, &vport->read_cv,
    502 	    VCC_PORT_USE_READ_LDC);
    503 
    504 	if (rv == 0) {
    505 		vport->status &= ~VCC_PORT_USE_READ_LDC;
    506 		do {
    507 			sz = sizeof (buf);
    508 			rv = i_vcc_read_ldc(vport, (char *)&buf, &sz);
    509 		} while (rv == 0 && sz > 0);
    510 
    511 		vport->status |= VCC_PORT_USE_READ_LDC;
    512 
    513 	}
    514 
    515 	/*
    516 	 * ignore read error since we still want to clean up
    517 	 * ldc channel.
    518 	 */
    519 
    520 	(void) ldc_set_cb_mode(vport->ldc_handle, LDC_CB_DISABLE);
    521 
    522 	/* close LDC channel - retry on EAGAIN */
    523 	while ((rv = ldc_close(vport->ldc_handle)) == EAGAIN) {
    524 
    525 		if (++retry > VCC_LDC_RETRIES) {
    526 			cmn_err(CE_CONT, "i_vcc_ldc_fini: cannot close channel"
    527 			    " %ld\n", vport->ldc_id);
    528 			break;
    529 		}
    530 
    531 		drv_usecwait(VCC_LDC_DELAY);
    532 	}
    533 
    534 	if (rv == 0) {
    535 		(void) ldc_unreg_callback(vport->ldc_handle);
    536 		(void) ldc_fini(vport->ldc_handle);
    537 	} else {
    538 		/*
    539 		 * Closing the LDC channel has failed. Ideally we should
    540 		 * fail here but there is no Zeus level infrastructure
    541 		 * to handle this. The MD has already been changed and
    542 		 * we have to do the close. So we try to do as much
    543 		 * clean up as we can.
    544 		 */
    545 		while (ldc_unreg_callback(vport->ldc_handle) == EAGAIN)
    546 			drv_usecwait(VCC_LDC_DELAY);
    547 	}
    548 
    549 }
    550 
    551 /* read data from ldc channel */
    552 
    553 static int
    554 i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz)
    555 {
    556 
    557 	int		rv;
    558 	size_t		size;
    559 	size_t		space_left = *sz;
    560 	vcc_msg_t  	buf;
    561 	int 		i;
    562 
    563 
    564 
    565 
    566 	/* make sure holding read lock */
    567 	ASSERT((vport->status & VCC_PORT_USE_READ_LDC) == 0);
    568 	ASSERT(space_left >= VCC_MTU_SZ);
    569 
    570 	*sz = 0;
    571 	while (space_left >= VCC_MTU_SZ)  {
    572 		size = sizeof (buf);
    573 
    574 		rv = ldc_read(vport->ldc_handle, (caddr_t)&buf, &size);
    575 
    576 		if (rv) {
    577 			return (rv);
    578 		}
    579 
    580 
    581 		/*
    582 		 * FIXME: ldc_read should not reaturn 0 with
    583 		 * either size == 0, buf.size == 0 or size < VCC_HDR_SZ
    584 		 */
    585 		if (size == 0) {
    586 			if (*sz > 0) {
    587 				return (0);
    588 			}
    589 			return (EAGAIN);
    590 		}
    591 
    592 		if (size < VCC_HDR_SZ) {
    593 			return (EIO);
    594 		}
    595 
    596 		/*
    597 		 * only data is expected from console - otherwise
    598 		 * return error
    599 		 */
    600 		if (buf.type != LDC_CONSOLE_DATA) {
    601 			return (EIO);
    602 		}
    603 
    604 		if (buf.size == 0) {
    605 			if (*sz > 0) {
    606 				return (0);
    607 			}
    608 			return (EAGAIN);
    609 		}
    610 
    611 		/* copy  data */
    612 		for (i = 0; i < buf.size; i++, (*sz)++) {
    613 			data_buf[*sz] = buf.data[i];
    614 		}
    615 
    616 		space_left -= buf.size;
    617 	}
    618 
    619 	return (0);
    620 }
    621 
    622 /* callback from ldc */
    623 static uint_t
    624 vcc_ldc_cb(uint64_t event, caddr_t arg)
    625 {
    626 
    627 	vcc_port_t  *vport = (vcc_port_t *)arg;
    628 	boolean_t   hasdata;
    629 
    630 	/*
    631 	 * do not need to hold lock because if ldc calls back, the
    632 	 * ldc_handle must be valid.
    633 	 */
    634 	D2("vcc_ldc_cb: callback invoked port=%d events=%llx\n",
    635 	    vport->number, event);
    636 
    637 	/* check event from ldc */
    638 	if (event & LDC_EVT_WRITE) {
    639 		/* channel has space for write */
    640 
    641 		i_vcc_set_port_status(vport, &vport->write_cv,
    642 		    VCC_PORT_LDC_WRITE_READY);
    643 		return (LDC_SUCCESS);
    644 	}
    645 
    646 	if (event & LDC_EVT_READ) {
    647 
    648 		/* channel has data for read */
    649 		(void) ldc_chkq(vport->ldc_handle, &hasdata);
    650 		if (!hasdata) {
    651 			/* data already read */
    652 			return (LDC_SUCCESS);
    653 		}
    654 
    655 		i_vcc_set_port_status(vport, &vport->read_cv,
    656 		    VCC_PORT_LDC_DATA_READY);
    657 		return (LDC_SUCCESS);
    658 	}
    659 
    660 	if (event & LDC_EVT_DOWN) {
    661 		/* channel is down */
    662 		i_vcc_set_port_status(vport, &vport->write_cv,
    663 		    VCC_PORT_LDC_LINK_DOWN);
    664 		cv_broadcast(&vport->read_cv);
    665 
    666 	}
    667 
    668 	return (LDC_SUCCESS);
    669 
    670 }
    671 
    672 
    673 /* configure a vcc port with ldc channel */
    674 static int
    675 i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id)
    676 {
    677 	int 		rv = EIO;
    678 	vcc_port_t 	*vport;
    679 
    680 	if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
    681 		cmn_err(CE_CONT, "i_vcc_config_port: invalid port number %d\n",
    682 		    portno);
    683 		return (EINVAL);
    684 	}
    685 
    686 	vport = &(vccp->port[portno]);
    687 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
    688 		cmn_err(CE_CONT, "i_vcc_config_port: port@%d does not exist\n",
    689 		    portno);
    690 		return (EINVAL);
    691 	}
    692 
    693 
    694 	if (vport->ldc_id != VCC_INVALID_CHANNEL) {
    695 		cmn_err(CE_CONT, "i_vcc_config_port: port@%d channel already"
    696 		    "configured\n", portno);
    697 		return (EINVAL);
    698 	}
    699 
    700 	mutex_enter(&vport->lock);
    701 
    702 	/* store the ldc ID */
    703 	vport->ldc_id = ldc_id;
    704 	/* check if someone has already opened this port */
    705 	if (vport->status & VCC_PORT_OPEN) {
    706 
    707 		if ((rv = i_vcc_ldc_init(vccp, vport)) != 0) {
    708 			mutex_exit(&vport->lock);
    709 			return (rv);
    710 		}
    711 
    712 		/* mark port as ready */
    713 		vport->status |= VCC_PORT_LDC_CHANNEL_READY;
    714 		cv_broadcast(&vport->read_cv);
    715 		cv_broadcast(&vport->write_cv);
    716 	}
    717 
    718 	mutex_exit(&vport->lock);
    719 
    720 	D1("i_vcc_config_port: port@%d ldc=%d, domain=%s",
    721 	    vport->number, vport->ldc_id, vport->minorp->domain_name);
    722 
    723 	return (0);
    724 }
    725 
    726 /* add a vcc console port */
    727 static int
    728 i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port,
    729     uint_t portno, char *domain_name)
    730 {
    731 	int 		instance;
    732 	int		rv = MDEG_FAILURE;
    733 	minor_t 	minor;
    734 	vcc_port_t 	*vport;
    735 	uint_t		minor_idx;
    736 	char		name[MAXPATHLEN];
    737 
    738 	if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
    739 		DWARN("i_vcc_add_port: invalid port number %d\n", portno);
    740 		return (MDEG_FAILURE);
    741 	}
    742 
    743 	vport = &(vccp->port[portno]);
    744 	if (vport->status & VCC_PORT_AVAIL) {
    745 		/* this port already exists */
    746 		cmn_err(CE_CONT, "i_vcc_add_port: invalid port - port@%d "
    747 		    "exists\n", portno);
    748 		return (MDEG_FAILURE);
    749 	}
    750 
    751 	vport->number = portno;
    752 	vport->ldc_id = VCC_INVALID_CHANNEL;
    753 
    754 	if (domain_name == NULL) {
    755 		cmn_err(CE_CONT, "i_vcc_add_port: invalid domain name\n");
    756 		return (MDEG_FAILURE);
    757 	}
    758 
    759 	if (group_name == NULL) {
    760 		cmn_err(CE_CONT, "i_vcc_add_port: invalid group name\n");
    761 		return (MDEG_FAILURE);
    762 	}
    763 
    764 	/* look up minor number */
    765 	for (minor_idx = 0; minor_idx < vccp->minors_assigned; minor_idx++) {
    766 		if (strcmp(vccp->minor_tbl[minor_idx].domain_name,
    767 		    domain_name) == 0) {
    768 			/* found previous assigned minor number */
    769 			break;
    770 		}
    771 	}
    772 
    773 	if (minor_idx == vccp->minors_assigned) {
    774 		/* end of lookup - assign new minor number */
    775 		if (minor_idx == VCC_MAX_PORTS) {
    776 			cmn_err(CE_CONT, "i_vcc_add_port:"
    777 			    "too many minornodes (%d)\n",
    778 			    minor_idx);
    779 			return (MDEG_FAILURE);
    780 		}
    781 
    782 		(void) strlcpy(vccp->minor_tbl[minor_idx].domain_name,
    783 		    domain_name, MAXPATHLEN);
    784 
    785 		vccp->minors_assigned++;
    786 	}
    787 
    788 	vport->minorp = &vccp->minor_tbl[minor_idx];
    789 	vccp->minor_tbl[minor_idx].portno = portno;
    790 
    791 	(void) strlcpy(vport->group_name, group_name, MAXPATHLEN);
    792 
    793 	vport->tcp_port = tcp_port;
    794 	D1("i_vcc_add_port:@%d domain=%s, group=%s, tcp=%lld",
    795 	    vport->number, vport->minorp->domain_name,
    796 	    vport->group_name, vport->tcp_port);
    797 
    798 
    799 	/*
    800 	 * Create a minor node. The minor number is
    801 	 * (instance << VCC_INST_SHIFT) | minor_idx
    802 	 */
    803 	instance = ddi_get_instance(vccp->dip);
    804 
    805 	minor = (instance << VCC_INST_SHIFT) | (minor_idx);
    806 
    807 	(void) snprintf(name, MAXPATHLEN - 1, "%s%s", VCC_MINOR_NAME_PREFIX,
    808 	    domain_name);
    809 
    810 	rv = ddi_create_minor_node(vccp->dip, name, S_IFCHR, minor,
    811 	    DDI_NT_SERIAL, 0);
    812 
    813 	if (rv != DDI_SUCCESS) {
    814 		vccp->minors_assigned--;
    815 		return (MDEG_FAILURE);
    816 	}
    817 
    818 	mutex_enter(&vport->lock);
    819 	vport->status = VCC_PORT_AVAIL | VCC_PORT_ADDED;
    820 	mutex_exit(&vport->lock);
    821 
    822 
    823 	return (MDEG_SUCCESS);
    824 }
    825 
    826 /* delete a port */
    827 static int
    828 i_vcc_delete_port(vcc_t *vccp, vcc_port_t *vport)
    829 {
    830 
    831 	char	name[MAXPATHLEN];
    832 	int	rv;
    833 
    834 
    835 	ASSERT(mutex_owned(&vport->lock));
    836 
    837 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
    838 		D1("vcc_del_port port already deleted \n");
    839 		return (0);
    840 	}
    841 
    842 	if (vport->status & VCC_PORT_OPEN) {
    843 		/* do not block mdeg callback */
    844 		vport->valid_pid = VCC_NO_PID_BLOCKING;
    845 		rv = i_vcc_close_port(vport);
    846 	}
    847 
    848 	/* remove minor node */
    849 	(void) snprintf(name, MAXPATHLEN-1, "%s%s", VCC_MINOR_NAME_PREFIX,
    850 	    vport->minorp->domain_name);
    851 
    852 	ddi_remove_minor_node(vccp->dip, name);
    853 
    854 	/* let read and write thread know */
    855 	cv_broadcast(&vport->read_cv);
    856 	cv_broadcast(&vport->write_cv);
    857 	vport->status = 0;
    858 	return (rv);
    859 
    860 
    861 }
    862 
    863 /* register callback to MDEG */
    864 static int
    865 i_vcc_mdeg_register(vcc_t *vccp, int instance)
    866 {
    867 	mdeg_prop_spec_t	*pspecp;
    868 	mdeg_node_spec_t	*ispecp;
    869 	mdeg_handle_t		mdeg_hdl;
    870 	int			sz;
    871 	int			rv;
    872 
    873 	/*
    874 	 * Allocate and initialize a per-instance copy
    875 	 * of the global property spec array that will
    876 	 * uniquely identify this vcc instance.
    877 	 */
    878 	sz = sizeof (vcc_prop_template);
    879 	pspecp = kmem_alloc(sz, KM_SLEEP);
    880 
    881 	bcopy(vcc_prop_template, pspecp, sz);
    882 
    883 	VCC_SET_MDEG_PROP_INST(pspecp, instance);
    884 
    885 	/* initialize the complete prop spec structure */
    886 	ispecp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP);
    887 	ispecp->namep = "virtual-device";
    888 	ispecp->specp = pspecp;
    889 
    890 	/* perform the registration */
    891 	rv = mdeg_register(ispecp, &vcc_port_match, vcc_mdeg_cb,
    892 	    vccp, &mdeg_hdl);
    893 
    894 	if (rv != MDEG_SUCCESS) {
    895 		cmn_err(CE_CONT, "i_vcc_mdeg_register:"
    896 		    "mdeg_register failed (%d)\n", rv);
    897 		kmem_free(ispecp, sizeof (mdeg_node_spec_t));
    898 		kmem_free(pspecp, sz);
    899 		return (DDI_FAILURE);
    900 	}
    901 
    902 	/* save off data that will be needed later */
    903 	vccp->md_ispecp = (void *)ispecp;
    904 	vccp->mdeg_hdl = mdeg_hdl;
    905 
    906 	return (0);
    907 }
    908 
    909 /* destroy all mutex from port table */
    910 static void
    911 i_vcc_cleanup_port_table(vcc_t *vccp)
    912 {
    913 	int i;
    914 	vcc_port_t *vport;
    915 
    916 	for (i = 0; i < VCC_MAX_PORTS; i++) {
    917 		vport = &(vccp->port[i]);
    918 		mutex_destroy(&vport->lock);
    919 		cv_destroy(&vport->read_cv);
    920 		cv_destroy(&vport->write_cv);
    921 	}
    922 }
    923 
    924 /*
    925  * attach(9E): attach a device to the system.
    926  * called once for each instance of the device on the system.
    927  */
    928 static int
    929 vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    930 {
    931 	int 		i, instance, inst;
    932 	int 		rv = DDI_FAILURE;
    933 	vcc_t		*vccp;
    934 	minor_t 	minor;
    935 	vcc_port_t	*vport;
    936 
    937 	switch (cmd) {
    938 
    939 	case DDI_ATTACH:
    940 
    941 		instance = ddi_get_instance(dip);
    942 		if (ddi_soft_state_zalloc(vcc_ssp, instance) != DDI_SUCCESS)
    943 			return (DDI_FAILURE);
    944 
    945 		vccp = ddi_get_soft_state(vcc_ssp, instance);
    946 		if (vccp == NULL) {
    947 			ddi_soft_state_free(vccp, instance);
    948 			return (ENXIO);
    949 		}
    950 
    951 		D1("vcc_attach: DDI_ATTACH instance=%d\n", instance);
    952 
    953 		/* initialize the mutex */
    954 		mutex_init(&vccp->lock, NULL, MUTEX_DRIVER, NULL);
    955 
    956 		mutex_enter(&vccp->lock);
    957 
    958 		vccp->dip = dip;
    959 
    960 		for (i = 0; i < VCC_MAX_PORTS; i++) {
    961 			vport = &(vccp->port[i]);
    962 			mutex_init(&vport->lock, NULL, MUTEX_DRIVER, NULL);
    963 			cv_init(&vport->read_cv, NULL, CV_DRIVER, NULL);
    964 			cv_init(&vport->write_cv, NULL, CV_DRIVER, NULL);
    965 			vport->valid_pid = VCC_NO_PID_BLOCKING;
    966 		}
    967 
    968 		vport = &vccp->port[VCC_CONTROL_PORT];
    969 		mutex_enter(&vport->lock);
    970 
    971 		vport->minorp = &vccp->minor_tbl[VCC_CONTROL_MINOR_IDX];
    972 		vport->status |= VCC_PORT_AVAIL;
    973 
    974 		/* create a minor node for vcc control */
    975 		minor = (instance << VCC_INST_SHIFT) | VCC_CONTROL_MINOR_IDX;
    976 
    977 		vccp->minor_tbl[VCC_CONTROL_PORT].portno =
    978 		    VCC_CONTROL_MINOR_IDX;
    979 
    980 
    981 		rv = ddi_create_minor_node(vccp->dip, "ctl", S_IFCHR, minor,
    982 		    DDI_NT_SERIAL, 0);
    983 
    984 		mutex_exit(&vport->lock);
    985 
    986 		if (rv != DDI_SUCCESS) {
    987 			cmn_err(CE_CONT, "vcc_attach: error"
    988 			    "creating control minor node\n");
    989 
    990 			i_vcc_cleanup_port_table(vccp);
    991 
    992 			mutex_exit(&vccp->lock);
    993 			/* clean up soft state */
    994 			ddi_soft_state_free(vccp, instance);
    995 
    996 			return (DDI_FAILURE);
    997 		}
    998 
    999 		/* get the instance number by reading 'reg' property */
   1000 		inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
   1001 		    "reg", -1);
   1002 		if (inst == -1) {
   1003 			cmn_err(CE_CONT, "vcc_attach: vcc%d has no "
   1004 			    "'reg' property\n",
   1005 			    ddi_get_instance(dip));
   1006 
   1007 			i_vcc_cleanup_port_table(vccp);
   1008 
   1009 			/* remove minor */
   1010 			ddi_remove_minor_node(vccp->dip, NULL);
   1011 
   1012 			/* clean up soft state */
   1013 			mutex_exit(&vccp->lock);
   1014 			ddi_soft_state_free(vccp, instance);
   1015 
   1016 			return (DDI_FAILURE);
   1017 		}
   1018 
   1019 		/*
   1020 		 * Mdeg might invoke callback in the same call sequence
   1021 		 * if there is a domain port at the time of registration.
   1022 		 * Since the callback also grabs vcc->lock mutex, to avoid
   1023 		 * mutex reentry error, release the lock before registration
   1024 		 */
   1025 		mutex_exit(&vccp->lock);
   1026 
   1027 		/* register for notifications from Zeus */
   1028 		rv = i_vcc_mdeg_register(vccp, inst);
   1029 		if (rv != MDEG_SUCCESS) {
   1030 			cmn_err(CE_CONT, "vcc_attach: error register to MD\n");
   1031 
   1032 			i_vcc_cleanup_port_table(vccp);
   1033 
   1034 			/* remove minor */
   1035 			ddi_remove_minor_node(vccp->dip, NULL);
   1036 
   1037 			/* clean up soft state */
   1038 			ddi_soft_state_free(vccp, instance);
   1039 
   1040 			return (DDI_FAILURE);
   1041 		}
   1042 
   1043 		return (DDI_SUCCESS);
   1044 
   1045 	case DDI_RESUME:
   1046 
   1047 		return (DDI_SUCCESS);
   1048 
   1049 	default:
   1050 
   1051 		return (DDI_FAILURE);
   1052 	}
   1053 }
   1054 
   1055 /*
   1056  * detach(9E): detach a device from the system.
   1057  */
   1058 static int
   1059 vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
   1060 {
   1061 	int		    i, instance;
   1062 	vcc_t		    *vccp;
   1063 	mdeg_node_spec_t    *ispecp;
   1064 	vcc_port_t	    *vport;
   1065 
   1066 	switch (cmd) {
   1067 
   1068 	case DDI_DETACH:
   1069 
   1070 		instance = ddi_get_instance(dip);
   1071 		vccp = ddi_get_soft_state(vcc_ssp, instance);
   1072 		if (vccp == NULL)
   1073 			return (ENXIO);
   1074 
   1075 		D1("vcc_detach: DDI_DETACH instance=%d\n", instance);
   1076 
   1077 		mutex_enter(&vccp->lock);
   1078 
   1079 		/* unregister from MD event generator */
   1080 
   1081 		ASSERT(vccp->mdeg_hdl);
   1082 		(void) mdeg_unregister(vccp->mdeg_hdl);
   1083 
   1084 		ispecp = (mdeg_node_spec_t *)vccp->md_ispecp;
   1085 		ASSERT(ispecp);
   1086 
   1087 		kmem_free(ispecp->specp, sizeof (vcc_prop_template));
   1088 		kmem_free(ispecp, sizeof (mdeg_node_spec_t));
   1089 
   1090 		/* remove minor nodes */
   1091 		ddi_remove_minor_node(vccp->dip, NULL);
   1092 		mutex_exit(&vccp->lock);
   1093 
   1094 		for (i = 0; i < VCC_MAX_PORTS; i++) {
   1095 
   1096 			vport = &vccp->port[i];
   1097 			mutex_enter(&vport->lock);
   1098 			if (i == VCC_CONTROL_PORT) {
   1099 				if (vport->status & VCC_PORT_OPEN) {
   1100 					(void) i_vcc_close_port(vport);
   1101 				}
   1102 			}
   1103 
   1104 			if ((vccp->port[i].status & VCC_PORT_AVAIL) &&
   1105 			    (i != VCC_CONTROL_PORT)) {
   1106 				D1("vcc_detach: removing port port@%d\n", i);
   1107 				(void) i_vcc_delete_port(vccp, vport);
   1108 			}
   1109 			mutex_exit(&vport->lock);
   1110 			cv_destroy(&vport->read_cv);
   1111 			cv_destroy(&vport->write_cv);
   1112 			mutex_destroy(&vport->lock);
   1113 		}
   1114 
   1115 
   1116 
   1117 		/* destroy mutex and free the soft state */
   1118 		mutex_destroy(&vccp->lock);
   1119 		ddi_soft_state_free(vcc_ssp, instance);
   1120 
   1121 		return (DDI_SUCCESS);
   1122 
   1123 	case DDI_SUSPEND:
   1124 
   1125 		return (DDI_SUCCESS);
   1126 
   1127 	default:
   1128 
   1129 		return (DDI_FAILURE);
   1130 	}
   1131 }
   1132 
   1133 /* cb_open */
   1134 static int
   1135 vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred)
   1136 {
   1137 	_NOTE(ARGUNUSED(otyp, cred))
   1138 
   1139 	int	    instance;
   1140 	int	    rv = EIO;
   1141 	minor_t	    minor;
   1142 	uint_t	    portno;
   1143 	vcc_t	    *vccp;
   1144 	vcc_port_t  *vport;
   1145 
   1146 	minor = getminor(*devp);
   1147 	instance = VCCINST(minor);
   1148 
   1149 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   1150 	if (vccp == NULL) {
   1151 		return (ENXIO);
   1152 	}
   1153 
   1154 	portno = VCCPORT(vccp, minor);
   1155 
   1156 	vport = &(vccp->port[portno]);
   1157 
   1158 	mutex_enter(&vport->lock);
   1159 
   1160 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1161 		/* port may be removed */
   1162 		mutex_exit(&vport->lock);
   1163 		return (ENXIO);
   1164 	}
   1165 
   1166 	if (vport->status & VCC_PORT_OPEN) {
   1167 		/* only one open per port */
   1168 		cmn_err(CE_CONT, "vcc_open: virtual-console-concentrator@%d:%d "
   1169 		    "is already open\n", instance, portno);
   1170 		mutex_exit(&vport->lock);
   1171 		return (EAGAIN);
   1172 	}
   1173 
   1174 	/* check minor no and pid */
   1175 	if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1176 	    vport)) != 0) {
   1177 		mutex_exit(&vport->lock);
   1178 		return (rv);
   1179 	}
   1180 
   1181 	if (portno == VCC_CONTROL_PORT) {
   1182 		vport->status |= VCC_PORT_OPEN;
   1183 		mutex_exit(&vport->lock);
   1184 		return (0);
   1185 	}
   1186 
   1187 	/*
   1188 	 * the port may just be added by mdeg callback and may
   1189 	 * not be configured yet.
   1190 	 */
   1191 	if (vport->ldc_id == VCC_INVALID_CHANNEL) {
   1192 		mutex_exit(&vport->lock);
   1193 		return (ENXIO);
   1194 	}
   1195 
   1196 
   1197 	/* check if channel has been initialized */
   1198 	if ((vport->status & VCC_PORT_LDC_CHANNEL_READY) == 0) {
   1199 		rv = i_vcc_ldc_init(vccp, vport);
   1200 		if (rv) {
   1201 			mutex_exit(&vport->lock);
   1202 			return (EIO);
   1203 		}
   1204 
   1205 		/* mark port as ready */
   1206 		vport->status |= VCC_PORT_LDC_CHANNEL_READY;
   1207 	}
   1208 
   1209 	vport->status |= VCC_PORT_USE_READ_LDC | VCC_PORT_USE_WRITE_LDC|
   1210 	    VCC_PORT_TERM_RD|VCC_PORT_TERM_WR|VCC_PORT_OPEN;
   1211 
   1212 	if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
   1213 		vport->status |= VCC_PORT_NONBLOCK;
   1214 	}
   1215 
   1216 	mutex_exit(&vport->lock);
   1217 
   1218 	return (0);
   1219 }
   1220 
   1221 /* close port */
   1222 static int
   1223 i_vcc_close_port(vcc_port_t *vport)
   1224 {
   1225 
   1226 	if ((vport->status & VCC_PORT_OPEN) == 0) {
   1227 		return (0);
   1228 	}
   1229 
   1230 	ASSERT(mutex_owned(&vport->lock));
   1231 
   1232 	if (vport->status & VCC_PORT_LDC_CHANNEL_READY) {
   1233 		/* clean up ldc channel */
   1234 		i_vcc_ldc_fini(vport);
   1235 		vport->status &= ~VCC_PORT_LDC_CHANNEL_READY;
   1236 	}
   1237 
   1238 	/* reset  rd/wr suspends  */
   1239 	vport->status |= VCC_PORT_TERM_RD | VCC_PORT_TERM_WR;
   1240 	vport->status &= ~VCC_PORT_NONBLOCK;
   1241 	vport->status &= ~VCC_PORT_OPEN;
   1242 	vport->valid_pid = VCC_NO_PID_BLOCKING;
   1243 
   1244 	/* signal any blocked read and write thread */
   1245 	cv_broadcast(&vport->read_cv);
   1246 	cv_broadcast(&vport->write_cv);
   1247 
   1248 	return (0);
   1249 }
   1250 
   1251 /* cb_close */
   1252 static int
   1253 vcc_close(dev_t dev, int flag, int otyp, cred_t *cred)
   1254 {
   1255 	_NOTE(ARGUNUSED(flag, otyp, cred))
   1256 
   1257 	int	    instance;
   1258 	minor_t	    minor;
   1259 	int	    rv = EIO;
   1260 	uint_t	    portno;
   1261 	vcc_t	    *vccp;
   1262 	vcc_port_t  *vport;
   1263 
   1264 	minor = getminor(dev);
   1265 
   1266 	instance = VCCINST(minor);
   1267 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   1268 	if (vccp == NULL) {
   1269 		return (ENXIO);
   1270 	}
   1271 
   1272 	portno = VCCPORT(vccp, minor);
   1273 
   1274 	D1("vcc_close: closing virtual-console-concentrator@%d:%d\n",
   1275 	    instance, portno);
   1276 	vport = &(vccp->port[portno]);
   1277 
   1278 
   1279 	/*
   1280 	 * needs lock to provent i_vcc_delete_port, which is called by
   1281 	 * the mdeg callback, from closing port.
   1282 	 */
   1283 	mutex_enter(&vport->lock);
   1284 
   1285 	if ((vport->status & VCC_PORT_OPEN) == 0) {
   1286 		mutex_exit(&vport->lock);
   1287 		return (0);
   1288 	}
   1289 
   1290 	if (portno == VCC_CONTROL_PORT) {
   1291 		/*
   1292 		 * vntsd closes control port before it exits. There
   1293 		 * could be events still pending for vntsd.
   1294 		 */
   1295 		mutex_exit(&vport->lock);
   1296 		rv = i_vcc_reset_events(vccp);
   1297 		return (0);
   1298 	}
   1299 
   1300 
   1301 	/* check minor no and pid */
   1302 	if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1303 	    vport)) != 0) {
   1304 		mutex_exit(&vport->lock);
   1305 		return (rv);
   1306 	}
   1307 
   1308 	rv = i_vcc_close_port(vport);
   1309 	mutex_exit(&vport->lock);
   1310 
   1311 	return (rv);
   1312 }
   1313 
   1314 /*
   1315  * ioctl VCC_CONS_TBL - vntsd allocates buffer according to return of
   1316  * VCC_NUM_PORTS. However, when vntsd requests for the console table, console
   1317  * ports could be deleted or added. parameter num_ports is number of structures
   1318  * that vntsd allocated for the table. If there are more ports than
   1319  * num_ports, set up to wakeup vntsd to add ports.
   1320  * If there less ports than num_ports, fill (-1) for cons_no to tell vntsd.
   1321  */
   1322 static int
   1323 i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, caddr_t buf, int mode)
   1324 {
   1325 	vcc_console_t	cons;
   1326 	int		i;
   1327 	vcc_port_t	*vport;
   1328 	boolean_t	notify_vntsd = B_FALSE;
   1329 	char pathname[MAXPATHLEN];
   1330 
   1331 
   1332 	(void) ddi_pathname(vccp->dip, pathname);
   1333 	for (i = 0; i < VCC_MAX_PORTS; i++) {
   1334 
   1335 		vport = &vccp->port[i];
   1336 
   1337 		if (i == VCC_CONTROL_PORT) {
   1338 			continue;
   1339 		}
   1340 
   1341 		if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1342 			continue;
   1343 		}
   1344 
   1345 		/* a port exists before vntsd becomes online */
   1346 		mutex_enter(&vport->lock);
   1347 
   1348 		if (num_ports == 0) {
   1349 			/* more ports than vntsd's buffer can hold */
   1350 			vport->status |= VCC_PORT_ADDED;
   1351 			notify_vntsd = B_TRUE;
   1352 			mutex_exit(&vport->lock);
   1353 			continue;
   1354 		}
   1355 
   1356 		bzero(&cons, sizeof (vcc_console_t));
   1357 
   1358 		/* construct console buffer */
   1359 		cons.cons_no = vport->number;
   1360 		cons.tcp_port = vport->tcp_port;
   1361 		(void) memcpy(cons.domain_name,
   1362 		    vport->minorp->domain_name, MAXPATHLEN);
   1363 
   1364 		(void) memcpy(cons.group_name, vport->group_name,
   1365 		    MAXPATHLEN);
   1366 		vport->status &= ~VCC_PORT_ADDED;
   1367 		mutex_exit(&vport->lock);
   1368 
   1369 		(void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s",
   1370 		    pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name);
   1371 
   1372 		/* copy out data */
   1373 		if (ddi_copyout(&cons, (void *)buf,
   1374 		    sizeof (vcc_console_t), mode)) {
   1375 			mutex_exit(&vport->lock);
   1376 			return (EFAULT);
   1377 		}
   1378 		buf += sizeof (vcc_console_t);
   1379 
   1380 		num_ports--;
   1381 
   1382 	}
   1383 
   1384 	if (num_ports == 0) {
   1385 		/* vntsd's buffer is full */
   1386 
   1387 		if (notify_vntsd) {
   1388 			/* more ports need to notify vntsd */
   1389 			vport = &vccp->port[VCC_CONTROL_PORT];
   1390 			mutex_enter(&vport->lock);
   1391 			vport->pollevent |= VCC_POLL_ADD_PORT;
   1392 			mutex_exit(&vport->lock);
   1393 		}
   1394 
   1395 		return (0);
   1396 	}
   1397 
   1398 	/* less ports than vntsd expected */
   1399 	bzero(&cons, sizeof (vcc_console_t));
   1400 	cons.cons_no = -1;
   1401 
   1402 	while (num_ports > 0) {
   1403 		/* fill vntsd buffer with no console */
   1404 		if (ddi_copyout(&cons, (void *)buf,
   1405 		    sizeof (vcc_console_t), mode) != 0) {
   1406 			mutex_exit(&vport->lock);
   1407 			return (EFAULT);
   1408 		}
   1409 		D1("i_vcc_cons_tbl: a port is  deleted\n");
   1410 		buf += sizeof (vcc_console_t) +MAXPATHLEN;
   1411 		num_ports--;
   1412 	}
   1413 
   1414 	return (0);
   1415 }
   1416 
   1417 
   1418 /* turn off event flag if there is no more change */
   1419 static void
   1420 i_vcc_turn_off_event(vcc_t *vccp, uint32_t port_status, uint32_t event)
   1421 {
   1422 
   1423 	vcc_port_t *vport;
   1424 	int i;
   1425 
   1426 	for (i = 0; i < VCC_MAX_PORTS; i++) {
   1427 
   1428 		vport = &(vccp->port[i]);
   1429 
   1430 		if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1431 			continue;
   1432 		}
   1433 
   1434 
   1435 		if (vport->status & port_status) {
   1436 			/* more port changes status */
   1437 			return;
   1438 		}
   1439 
   1440 	}
   1441 
   1442 	/* no more changed port  */
   1443 	vport = &vccp->port[VCC_CONTROL_PORT];
   1444 
   1445 	/* turn off event */
   1446 	mutex_enter(&vport->lock);
   1447 	vport->pollevent &= ~event;
   1448 	mutex_exit(&vport->lock);
   1449 }
   1450 
   1451 /* ioctl VCC_CONS_INFO */
   1452 static int
   1453 i_vcc_cons_info(vcc_t *vccp, caddr_t buf, int mode)
   1454 {
   1455 	vcc_console_t	cons;
   1456 	uint_t		portno;
   1457 	vcc_port_t	*vport;
   1458 	char pathname[MAXPATHLEN];
   1459 
   1460 	/* read in portno */
   1461 	if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) {
   1462 		return (EFAULT);
   1463 	}
   1464 
   1465 	D1("i_vcc_cons_info@%d:\n", portno);
   1466 
   1467 	if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
   1468 		return (EINVAL);
   1469 	}
   1470 
   1471 	vport = &vccp->port[portno];
   1472 
   1473 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1474 		return (EINVAL);
   1475 	}
   1476 
   1477 	mutex_enter(&vport->lock);
   1478 	vport->status &= ~VCC_PORT_ADDED;
   1479 
   1480 	/* construct configruation data  */
   1481 	bzero(&cons, sizeof (vcc_console_t));
   1482 
   1483 	cons.cons_no = vport->number;
   1484 	cons.tcp_port = vport->tcp_port;
   1485 
   1486 	(void) memcpy(cons.domain_name, vport->minorp->domain_name, MAXPATHLEN);
   1487 
   1488 	(void) memcpy(cons.group_name, vport->group_name, MAXPATHLEN);
   1489 
   1490 	mutex_exit(&vport->lock);
   1491 
   1492 	(void) ddi_pathname(vccp->dip, pathname),
   1493 
   1494 	    /* copy device name */
   1495 	    (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s",
   1496 	    pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name);
   1497 	/* copy data */
   1498 	if (ddi_copyout(&cons, (void *)buf,
   1499 	    sizeof (vcc_console_t), mode) != 0) {
   1500 		mutex_exit(&vport->lock);
   1501 		return (EFAULT);
   1502 	}
   1503 
   1504 	D1("i_vcc_cons_info@%d:domain:%s serv:%s tcp@%lld %s\n",
   1505 	    cons.cons_no, cons.domain_name,
   1506 	    cons.group_name, cons.tcp_port, cons.dev_name);
   1507 
   1508 	i_vcc_turn_off_event(vccp, VCC_PORT_ADDED, VCC_POLL_ADD_PORT);
   1509 
   1510 	return (0);
   1511 }
   1512 
   1513 
   1514 /* response to vntsd inquiry ioctl call */
   1515 static int
   1516 i_vcc_inquiry(vcc_t *vccp, caddr_t buf, int mode)
   1517 {
   1518 	vcc_port_t	*vport;
   1519 	uint_t		i;
   1520 	vcc_response_t	msg;
   1521 
   1522 	vport = &(vccp->port[VCC_CONTROL_PORT]);
   1523 
   1524 	if ((vport->pollevent & VCC_POLL_ADD_PORT) == 0) {
   1525 		return (EINVAL);
   1526 	}
   1527 
   1528 	/* an added port */
   1529 
   1530 	D1("i_vcc_inquiry\n");
   1531 
   1532 	for (i = 0; i < VCC_MAX_PORTS; i++) {
   1533 		if ((vccp->port[i].status & VCC_PORT_AVAIL) == 0) {
   1534 			continue;
   1535 		}
   1536 
   1537 		if (vccp->port[i].status & VCC_PORT_ADDED) {
   1538 			/* port added */
   1539 			msg.reason = VCC_CONS_ADDED;
   1540 			msg.cons_no = i;
   1541 
   1542 			if (ddi_copyout((void *)&msg, (void *)buf,
   1543 			    sizeof (msg), mode) == -1) {
   1544 				cmn_err(CE_CONT, "i_vcc_find_changed_port:"
   1545 				    "ddi_copyout"
   1546 				    " failed\n");
   1547 				return (EFAULT);
   1548 			}
   1549 			return (0);
   1550 		}
   1551 	}
   1552 
   1553 	/* the added port was deleted before vntsd wakes up */
   1554 	msg.reason = VCC_CONS_MISS_ADDED;
   1555 
   1556 	if (ddi_copyout((void *)&msg, (void *)buf,
   1557 	    sizeof (msg), mode) == -1) {
   1558 		cmn_err(CE_CONT, "i_vcc_find_changed_port: ddi_copyout"
   1559 		    " failed\n");
   1560 		return (EFAULT);
   1561 	}
   1562 
   1563 	return (0);
   1564 }
   1565 
   1566 /* clean up events after vntsd exits */
   1567 static int
   1568 i_vcc_reset_events(vcc_t *vccp)
   1569 {
   1570 	uint_t	    i;
   1571 	vcc_port_t  *vport;
   1572 
   1573 	for (i = 0; i < VCC_MAX_PORTS; i++) {
   1574 		vport = &(vccp->port[i]);
   1575 
   1576 		if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1577 			continue;
   1578 		}
   1579 
   1580 		ASSERT(!mutex_owned(&vport->lock));
   1581 
   1582 		if (i == VCC_CONTROL_PORT) {
   1583 			/* close control port */
   1584 			mutex_enter(&vport->lock);
   1585 			vport->status &= ~VCC_PORT_OPEN;
   1586 
   1587 			/* clean up poll events */
   1588 			vport->pollevent = 0;
   1589 			vport->pollflag = 0;
   1590 			mutex_exit(&vport->lock);
   1591 			continue;
   1592 		}
   1593 		if (vport->status & VCC_PORT_ADDED) {
   1594 			/* pending added port event to vntsd */
   1595 			mutex_enter(&vport->lock);
   1596 			vport->status &= ~VCC_PORT_ADDED;
   1597 			mutex_exit(&vport->lock);
   1598 		}
   1599 
   1600 	}
   1601 
   1602 	vport = &vccp->port[VCC_CONTROL_PORT];
   1603 
   1604 	return (0);
   1605 }
   1606 
   1607 /* ioctl VCC_FORCE_CLOSE */
   1608 static int
   1609 i_vcc_force_close(vcc_t *vccp, caddr_t buf, int mode)
   1610 {
   1611 	uint_t		portno;
   1612 	vcc_port_t	*vport;
   1613 	int		rv;
   1614 
   1615 	/* read in portno */
   1616 	if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) {
   1617 		return (EFAULT);
   1618 	}
   1619 
   1620 	D1("i_vcc_force_close@%d:\n", portno);
   1621 
   1622 	if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
   1623 		return (EINVAL);
   1624 	}
   1625 
   1626 	vport = &vccp->port[portno];
   1627 
   1628 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1629 		return (EINVAL);
   1630 	}
   1631 
   1632 	mutex_enter(&vport->lock);
   1633 
   1634 	rv = i_vcc_close_port(vport);
   1635 
   1636 	/* block callers other than vntsd */
   1637 	vport->valid_pid = ddi_get_pid();
   1638 
   1639 	mutex_exit(&vport->lock);
   1640 	return (rv);
   1641 
   1642 }
   1643 
   1644 /* ioctl VCC_CONS_STATUS */
   1645 static int
   1646 i_vcc_cons_status(vcc_t *vccp, caddr_t buf, int mode)
   1647 {
   1648 	vcc_console_t	console;
   1649 	vcc_port_t	*vport;
   1650 
   1651 	/* read in portno */
   1652 	if (ddi_copyin((void*)buf, &console, sizeof (console), mode)) {
   1653 		return (EFAULT);
   1654 	}
   1655 
   1656 	D1("i_vcc_cons_status@%d:\n", console.cons_no);
   1657 
   1658 	if ((console.cons_no >= VCC_MAX_PORTS) ||
   1659 	    (console.cons_no == VCC_CONTROL_PORT)) {
   1660 		return (EINVAL);
   1661 	}
   1662 
   1663 
   1664 	vport = &vccp->port[console.cons_no];
   1665 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1666 		console.cons_no = -1;
   1667 	} else  if (strncmp(console.domain_name, vport->minorp->domain_name,
   1668 	    MAXPATHLEN)) {
   1669 		console.cons_no = -1;
   1670 	} else if (strncmp(console.group_name, vport->group_name,
   1671 	    MAXPATHLEN)) {
   1672 		console.cons_no = -1;
   1673 	} else if (console.tcp_port != vport->tcp_port) {
   1674 		console.cons_no = -1;
   1675 	} else if (vport->ldc_id == VCC_INVALID_CHANNEL) {
   1676 		console.cons_no = -1;
   1677 	}
   1678 
   1679 	D1("i_vcc_cons_status@%d: %s %s %llx\n", console.cons_no,
   1680 	    console.group_name, console.domain_name, console.tcp_port);
   1681 	if (ddi_copyout(&console, (void *)buf, sizeof (console), mode) == -1) {
   1682 		cmn_err(CE_CONT, "i_vcc_cons_status ddi_copyout failed\n");
   1683 		return (EFAULT);
   1684 	}
   1685 
   1686 	return (0);
   1687 }
   1688 
   1689 /* cb_ioctl handler for vcc control port */
   1690 static int
   1691 i_vcc_ctrl_ioctl(vcc_t *vccp, int cmd, void* arg, int mode)
   1692 {
   1693 
   1694 	static uint_t	num_ports;
   1695 
   1696 
   1697 	switch (cmd) {
   1698 
   1699 	case VCC_NUM_CONSOLE:
   1700 
   1701 		mutex_enter(&vccp->lock);
   1702 		num_ports = vccp->num_ports;
   1703 		mutex_exit(&vccp->lock);
   1704 		/* number of consoles */
   1705 
   1706 		return (ddi_copyout((void *)&num_ports, arg,
   1707 		    sizeof (int), mode));
   1708 	case VCC_CONS_TBL:
   1709 
   1710 		/* console config table */
   1711 		return (i_vcc_cons_tbl(vccp, num_ports, (caddr_t)arg, mode));
   1712 
   1713 	case VCC_INQUIRY:
   1714 
   1715 		/* reason for wakeup */
   1716 		return (i_vcc_inquiry(vccp, (caddr_t)arg, mode));
   1717 
   1718 	case VCC_CONS_INFO:
   1719 		/* a console config */
   1720 		return (i_vcc_cons_info(vccp, (caddr_t)arg, mode));
   1721 
   1722 	case VCC_FORCE_CLOSE:
   1723 		/* force to close a console */
   1724 		return (i_vcc_force_close(vccp, (caddr_t)arg, mode));
   1725 
   1726 	case VCC_CONS_STATUS:
   1727 		/* console status */
   1728 		return (i_vcc_cons_status(vccp, (caddr_t)arg, mode));
   1729 
   1730 	default:
   1731 
   1732 		/* unknown command */
   1733 		return (ENODEV);
   1734 	}
   1735 
   1736 
   1737 }
   1738 
   1739 /* write data to ldc. may block if channel has no space for write */
   1740 static int
   1741 i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf)
   1742 {
   1743 	int	rv = EIO;
   1744 	size_t	size;
   1745 
   1746 	ASSERT(mutex_owned(&vport->lock));
   1747 	ASSERT((vport->status & VCC_PORT_USE_WRITE_LDC) == 0);
   1748 
   1749 	for (; ; ) {
   1750 
   1751 		size = VCC_HDR_SZ + buf->size;
   1752 		rv = ldc_write(vport->ldc_handle, (caddr_t)buf, &size);
   1753 
   1754 		D1("i_vcc_write_ldc: port@%d: err=%d %d bytes\n",
   1755 		    vport->number, rv, size);
   1756 
   1757 		if (rv == 0) {
   1758 			return (rv);
   1759 		}
   1760 
   1761 		if (rv != EWOULDBLOCK) {
   1762 			return (EIO);
   1763 		}
   1764 
   1765 		if (vport->status & VCC_PORT_NONBLOCK) {
   1766 			return (EAGAIN);
   1767 		}
   1768 
   1769 		/*  block util ldc has more space */
   1770 
   1771 		rv = i_vcc_wait_port_status(vport, &vport->write_cv,
   1772 		    VCC_PORT_LDC_WRITE_READY);
   1773 
   1774 		if (rv) {
   1775 			return (rv);
   1776 		}
   1777 
   1778 		vport->status &= ~VCC_PORT_LDC_WRITE_READY;
   1779 
   1780 	}
   1781 
   1782 }
   1783 
   1784 
   1785 
   1786 /* cb_ioctl handler for port ioctl */
   1787 static int
   1788 i_vcc_port_ioctl(vcc_t *vccp, minor_t minor, int portno, int cmd, void *arg,
   1789     int mode)
   1790 {
   1791 
   1792 	vcc_port_t	*vport;
   1793 	struct termios	term;
   1794 	vcc_msg_t	buf;
   1795 	int		rv;
   1796 
   1797 	D1("i_vcc_port_ioctl@%d cmd %d\n", portno, cmd);
   1798 
   1799 	vport = &(vccp->port[portno]);
   1800 
   1801 	if ((vport->status & VCC_PORT_AVAIL) == 0) {
   1802 		return (EIO);
   1803 	}
   1804 
   1805 
   1806 	switch (cmd) {
   1807 
   1808 	/* terminal support */
   1809 	case TCGETA:
   1810 	case TCGETS:
   1811 
   1812 		mutex_enter(&vport->lock);
   1813 
   1814 		/* check minor no and pid */
   1815 		if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1816 		    vport)) != 0) {
   1817 			mutex_exit(&vport->lock);
   1818 			return (rv);
   1819 		}
   1820 
   1821 		(void) memcpy(&term, &vport->term, sizeof (term));
   1822 		mutex_exit(&vport->lock);
   1823 
   1824 		return (ddi_copyout(&term, arg, sizeof (term), mode));
   1825 
   1826 	case TCSETS:
   1827 	case TCSETA:
   1828 	case TCSETAW:
   1829 	case TCSETAF:
   1830 
   1831 		if (ddi_copyin(arg, &term, sizeof (term), mode) != 0) {
   1832 			return (EFAULT);
   1833 		}
   1834 
   1835 		mutex_enter(&vport->lock);
   1836 
   1837 		/* check minor no and pid */
   1838 		if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1839 		    vport)) != 0) {
   1840 			mutex_exit(&vport->lock);
   1841 			return (rv);
   1842 		}
   1843 
   1844 		(void) memcpy(&vport->term, &term, sizeof (term));
   1845 		mutex_exit(&vport->lock);
   1846 		return (0);
   1847 
   1848 
   1849 	case TCSBRK:
   1850 
   1851 		/* send break to console */
   1852 		mutex_enter(&vport->lock);
   1853 
   1854 		/* check minor no and pid */
   1855 		if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1856 		    vport)) != 0) {
   1857 			mutex_exit(&vport->lock);
   1858 			return (rv);
   1859 		}
   1860 
   1861 		/* wait for write available */
   1862 		rv = i_vcc_wait_port_status(vport, &vport->write_cv,
   1863 		    VCC_PORT_LDC_CHANNEL_READY| VCC_PORT_USE_WRITE_LDC);
   1864 		if (rv) {
   1865 			mutex_exit(&vport->lock);
   1866 			return (rv);
   1867 		}
   1868 
   1869 		vport->status &= ~VCC_PORT_USE_WRITE_LDC;
   1870 
   1871 		buf.type = LDC_CONSOLE_CTRL;
   1872 		buf.ctrl_msg = LDC_CONSOLE_BREAK;
   1873 		buf.size = 0;
   1874 
   1875 		rv = i_vcc_write_ldc(vport, &buf);
   1876 
   1877 		mutex_exit(&vport->lock);
   1878 
   1879 		i_vcc_set_port_status(vport, &vport->write_cv,
   1880 		    VCC_PORT_USE_WRITE_LDC);
   1881 		return (0);
   1882 
   1883 	case TCXONC:
   1884 		/* suspend read or write */
   1885 		if (ddi_copyin(arg, &cmd, sizeof (int), mode) != 0) {
   1886 			return (EFAULT);
   1887 		}
   1888 
   1889 		mutex_enter(&vport->lock);
   1890 
   1891 		/* check minor no and pid */
   1892 		if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   1893 		    vport)) != 0) {
   1894 			mutex_exit(&vport->lock);
   1895 			return (rv);
   1896 		}
   1897 
   1898 
   1899 		switch (cmd) {
   1900 
   1901 		case 0:
   1902 			/* suspend read */
   1903 			vport->status &= ~VCC_PORT_TERM_RD;
   1904 			break;
   1905 
   1906 		case 1:
   1907 			/* resume read */
   1908 			vport->status |= VCC_PORT_TERM_RD;
   1909 			cv_broadcast(&vport->read_cv);
   1910 			break;
   1911 
   1912 		case 2:
   1913 			/* suspend write */
   1914 			vport->status &= ~VCC_PORT_TERM_WR;
   1915 			break;
   1916 
   1917 		case 3:
   1918 			/* resume write */
   1919 			vport->status |= VCC_PORT_TERM_WR;
   1920 			cv_broadcast(&vport->write_cv);
   1921 			break;
   1922 
   1923 		default:
   1924 			mutex_exit(&vport->lock);
   1925 			return (EINVAL);
   1926 		}
   1927 
   1928 		mutex_exit(&vport->lock);
   1929 		return (0);
   1930 
   1931 	case TCFLSH:
   1932 		return (0);
   1933 
   1934 	default:
   1935 		return (EINVAL);
   1936 	}
   1937 
   1938 }
   1939 
   1940 /* cb_ioctl */
   1941 static int
   1942 vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
   1943     cred_t *credp, int *rvalp)
   1944 {
   1945 	_NOTE(ARGUNUSED(credp, rvalp))
   1946 
   1947 	int instance;
   1948 	minor_t minor;
   1949 	int portno;
   1950 	vcc_t *vccp;
   1951 
   1952 	minor = getminor(dev);
   1953 
   1954 	instance = VCCINST(minor);
   1955 
   1956 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   1957 	if (vccp == NULL) {
   1958 		return (ENXIO);
   1959 	}
   1960 
   1961 	portno = VCCPORT(vccp, minor);
   1962 
   1963 	D1("vcc_ioctl: virtual-console-concentrator@%d:%d\n", instance, portno);
   1964 
   1965 	if (portno >= VCC_MAX_PORTS) {
   1966 		cmn_err(CE_CONT, "vcc_ioctl:virtual-console-concentrator@%d"
   1967 		    " invalid portno\n", portno);
   1968 		return (EINVAL);
   1969 	}
   1970 
   1971 	D1("vcc_ioctl: virtual-console-concentrator@%d:%d ioctl cmd=%d\n",
   1972 	    instance, portno, cmd);
   1973 
   1974 	if (portno == VCC_CONTROL_PORT) {
   1975 		/* control ioctl */
   1976 		return (i_vcc_ctrl_ioctl(vccp, cmd, (void *)arg, mode));
   1977 	}
   1978 
   1979 	/* data port ioctl */
   1980 	return (i_vcc_port_ioctl(vccp, minor, portno, cmd, (void *)arg, mode));
   1981 }
   1982 
   1983 /* cb_read */
   1984 static int
   1985 vcc_read(dev_t dev, struct uio *uiop, cred_t *credp)
   1986 {
   1987 	_NOTE(ARGUNUSED(credp))
   1988 
   1989 	int	    instance;
   1990 	minor_t	    minor;
   1991 	uint_t	    portno;
   1992 	vcc_t	    *vccp;
   1993 	vcc_port_t  *vport;
   1994 	int	    rv = EIO;	/* by default fail ! */
   1995 	char 		*buf;
   1996 	size_t		uio_size;
   1997 	size_t		size;
   1998 
   1999 	minor = getminor(dev);
   2000 
   2001 	instance = VCCINST(minor);
   2002 
   2003 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   2004 	if (vccp == NULL) {
   2005 		return (ENXIO);
   2006 	}
   2007 
   2008 	portno = VCCPORT(vccp, minor);
   2009 
   2010 	/* no read for control port */
   2011 	if (portno == VCC_CONTROL_PORT) {
   2012 		return (EIO);
   2013 	}
   2014 
   2015 	/* temp buf to hold ldc data */
   2016 	uio_size = uiop->uio_resid;
   2017 
   2018 	if (uio_size < VCC_MTU_SZ) {
   2019 		return (EINVAL);
   2020 	}
   2021 
   2022 	vport = &(vccp->port[portno]);
   2023 
   2024 	mutex_enter(&vport->lock);
   2025 
   2026 	/* check minor no and pid */
   2027 	if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   2028 	    vport)) != 0) {
   2029 		mutex_exit(&vport->lock);
   2030 		return (rv);
   2031 	}
   2032 
   2033 	rv = i_vcc_wait_port_status(vport, &vport->read_cv,
   2034 	    VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY|
   2035 	    VCC_PORT_USE_READ_LDC);
   2036 	if (rv) {
   2037 		mutex_exit(&vport->lock);
   2038 		return (rv);
   2039 	}
   2040 
   2041 	buf = kmem_alloc(uio_size, KM_SLEEP);
   2042 
   2043 	vport->status &= ~VCC_PORT_USE_READ_LDC;
   2044 
   2045 	for (; ; ) {
   2046 
   2047 		size = uio_size;
   2048 		rv = i_vcc_read_ldc(vport, buf, &size);
   2049 
   2050 
   2051 		if (rv == EAGAIN) {
   2052 			/* should block? */
   2053 			if (vport->status & VCC_PORT_NONBLOCK) {
   2054 				break;
   2055 			}
   2056 
   2057 		} else if (rv) {
   2058 			/* error */
   2059 			break;
   2060 		}
   2061 
   2062 		if (size > 0) {
   2063 			/* got data */
   2064 			break;
   2065 		}
   2066 
   2067 		/* wait for data from ldc */
   2068 		vport->status &= ~VCC_PORT_LDC_DATA_READY;
   2069 
   2070 		mutex_exit(&vport->lock);
   2071 		i_vcc_set_port_status(vport, &vport->read_cv,
   2072 		    VCC_PORT_USE_READ_LDC);
   2073 		mutex_enter(&vport->lock);
   2074 
   2075 		rv = i_vcc_wait_port_status(vport, &vport->read_cv,
   2076 		    VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY|
   2077 		    VCC_PORT_USE_READ_LDC| VCC_PORT_LDC_DATA_READY);
   2078 		if (rv) {
   2079 			break;
   2080 		}
   2081 
   2082 		vport->status &= ~VCC_PORT_USE_READ_LDC;
   2083 	}
   2084 
   2085 	mutex_exit(&vport->lock);
   2086 
   2087 	if ((rv == 0) && (size > 0)) {
   2088 		/* data is in buf */
   2089 		rv = uiomove(buf, size, UIO_READ, uiop);
   2090 	}
   2091 
   2092 	kmem_free(buf, uio_size);
   2093 	i_vcc_set_port_status(vport, &vport->read_cv, VCC_PORT_USE_READ_LDC);
   2094 
   2095 	return (rv);
   2096 }
   2097 
   2098 
   2099 /* cb_write */
   2100 static int
   2101 vcc_write(dev_t dev, struct uio *uiop, cred_t *credp)
   2102 {
   2103 	_NOTE(ARGUNUSED(credp))
   2104 
   2105 	int	    instance;
   2106 	minor_t	    minor;
   2107 	size_t	    size;
   2108 	size_t	    bytes;
   2109 	uint_t	    portno;
   2110 	vcc_t	    *vccp;
   2111 
   2112 	vcc_port_t  *vport;
   2113 	int	    rv = EIO;
   2114 
   2115 	vcc_msg_t	buf;
   2116 
   2117 	minor = getminor(dev);
   2118 
   2119 	instance = VCCINST(minor);
   2120 
   2121 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   2122 	if (vccp == NULL) {
   2123 		return (ENXIO);
   2124 	}
   2125 
   2126 	portno = VCCPORT(vccp, minor);
   2127 
   2128 	/* no write for control port */
   2129 	if (portno == VCC_CONTROL_PORT) {
   2130 		return (EIO);
   2131 	}
   2132 	vport = &(vccp->port[portno]);
   2133 
   2134 	/*
   2135 	 * check if the channel has been configured,
   2136 	 * if write has been suspend and grab write lock.
   2137 	 */
   2138 	mutex_enter(&vport->lock);
   2139 
   2140 	/* check minor no and pid */
   2141 	if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   2142 	    vport)) != 0) {
   2143 		mutex_exit(&vport->lock);
   2144 		return (rv);
   2145 	}
   2146 
   2147 	rv = i_vcc_wait_port_status(vport, &vport->write_cv,
   2148 	    VCC_PORT_TERM_WR|VCC_PORT_LDC_CHANNEL_READY|
   2149 	    VCC_PORT_USE_WRITE_LDC);
   2150 	if (rv) {
   2151 		mutex_exit(&vport->lock);
   2152 		return (rv);
   2153 	}
   2154 
   2155 	vport->status &= ~VCC_PORT_USE_WRITE_LDC;
   2156 	mutex_exit(&vport->lock);
   2157 	size = uiop->uio_resid;
   2158 
   2159 	D2("vcc_write: virtual-console-concentrator@%d:%d writing %d bytes\n",
   2160 	    instance, portno, size);
   2161 
   2162 
   2163 
   2164 	buf.type = LDC_CONSOLE_DATA;
   2165 
   2166 	while (size) {
   2167 
   2168 		bytes = MIN(size, VCC_MTU_SZ);
   2169 		/* move data */
   2170 		rv = uiomove(&(buf.data), bytes, UIO_WRITE, uiop);
   2171 
   2172 		if (rv) {
   2173 			break;
   2174 		}
   2175 
   2176 		/* write to ldc */
   2177 		buf.size = bytes;
   2178 
   2179 		mutex_enter(&vport->lock);
   2180 
   2181 		/* check minor no and pid */
   2182 		if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
   2183 		    vport)) != 0) {
   2184 			mutex_exit(&vport->lock);
   2185 			return (rv);
   2186 		}
   2187 
   2188 		rv = i_vcc_write_ldc(vport, &buf);
   2189 
   2190 		mutex_exit(&vport->lock);
   2191 
   2192 		if (rv) {
   2193 			break;
   2194 		}
   2195 
   2196 		size -= bytes;
   2197 
   2198 	}
   2199 
   2200 	i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC);
   2201 	return (rv);
   2202 }
   2203 
   2204 /* mdeg callback for a removed port */
   2205 static int
   2206 i_vcc_md_remove_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp)
   2207 {
   2208 	uint64_t  portno;	/* md requires 64bit for port number */
   2209 	int rv = MDEG_FAILURE;
   2210 	vcc_port_t *vport;
   2211 
   2212 	if (md_get_prop_val(mdp, mdep, "id", &portno)) {
   2213 		cmn_err(CE_CONT, "vcc_mdeg_cb: port has no 'id' property\n");
   2214 		return (MDEG_FAILURE);
   2215 	}
   2216 
   2217 	if ((portno >= VCC_MAX_PORTS) || (portno < 0)) {
   2218 		cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld invalid port no\n",
   2219 		    portno);
   2220 		return (MDEG_FAILURE);
   2221 	}
   2222 
   2223 	if (portno == VCC_CONTROL_PORT) {
   2224 		cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld can not remove"
   2225 		    "control port\n",
   2226 		    portno);
   2227 		return (MDEG_FAILURE);
   2228 	}
   2229 
   2230 	vport = &(vccp->port[portno]);
   2231 
   2232 	/* delete the port */
   2233 	mutex_enter(&vport->lock);
   2234 	rv = i_vcc_delete_port(vccp, vport);
   2235 	mutex_exit(&vport->lock);
   2236 
   2237 	mutex_enter(&vccp->lock);
   2238 	vccp->num_ports--;
   2239 	mutex_exit(&vccp->lock);
   2240 
   2241 	return (rv ? MDEG_FAILURE : MDEG_SUCCESS);
   2242 }
   2243 
   2244 static int
   2245 i_vcc_get_ldc_id(md_t *md, mde_cookie_t mdep, uint64_t *ldc_id)
   2246 {
   2247 	int		num_nodes;
   2248 	size_t		size;
   2249 	mde_cookie_t	*channel;
   2250 	int		num_channels;
   2251 
   2252 
   2253 	if ((num_nodes = md_node_count(md)) <= 0) {
   2254 		cmn_err(CE_CONT, "i_vcc_get_ldc_channel_id:"
   2255 		    "  Invalid node count in Machine Description subtree");
   2256 		return (-1);
   2257 	}
   2258 	size = num_nodes*(sizeof (*channel));
   2259 	channel = kmem_zalloc(size, KM_SLEEP);
   2260 	ASSERT(channel != NULL);	/* because KM_SLEEP */
   2261 
   2262 
   2263 	/* Look for channel endpoint child(ren) of the vdisk MD node */
   2264 	if ((num_channels = md_scan_dag(md, mdep,
   2265 	    md_find_name(md, "channel-endpoint"),
   2266 	    md_find_name(md, "fwd"), channel)) <= 0) {
   2267 		cmn_err(CE_CONT, "i_vcc_get_ldc_id:  No 'channel-endpoint'"
   2268 		    " found for vcc");
   2269 		kmem_free(channel, size);
   2270 		return (-1);
   2271 	}
   2272 
   2273 	/* Get the "id" value for the first channel endpoint node */
   2274 	if (md_get_prop_val(md, channel[0], "id", ldc_id) != 0) {
   2275 		cmn_err(CE_CONT, "i_vcc_get_ldc:  No id property found "
   2276 		    "for channel-endpoint of vcc");
   2277 		kmem_free(channel, size);
   2278 		return (-1);
   2279 	}
   2280 
   2281 	if (num_channels > 1) {
   2282 		cmn_err(CE_CONT, "i_vcc_get_ldc:  Warning:  Using ID of first"
   2283 		    " of multiple channels for this vcc");
   2284 	}
   2285 
   2286 	kmem_free(channel, size);
   2287 	return (0);
   2288 }
   2289 /* mdeg callback for an added port  */
   2290 static int
   2291 i_vcc_md_add_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp)
   2292 {
   2293 	uint64_t	portno;		/* md requires 64 bit */
   2294 	char		*domain_name;
   2295 	char		*group_name;
   2296 	uint64_t	ldc_id;
   2297 	uint64_t	tcp_port;
   2298 	vcc_port_t	*vport;
   2299 
   2300 	/* read in the port's reg property */
   2301 	if (md_get_prop_val(mdp, mdep, "id", &portno)) {
   2302 		cmn_err(CE_CONT, "i_vcc_md_add_port_: port has no 'id' "
   2303 		    "property\n");
   2304 		return (MDEG_FAILURE);
   2305 	}
   2306 
   2307 	/* read in the port's "vcc-doman-name" property */
   2308 	if (md_get_prop_str(mdp, mdep, "vcc-domain-name", &domain_name)) {
   2309 		cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has "
   2310 		    "no 'vcc-domain-name' property\n", portno);
   2311 		return (MDEG_FAILURE);
   2312 	}
   2313 
   2314 
   2315 	/* read in the port's "vcc-group-name" property */
   2316 	if (md_get_prop_str(mdp, mdep, "vcc-group-name", &group_name)) {
   2317 		cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no "
   2318 		    "'vcc-group-name'property\n", portno);
   2319 		return (MDEG_FAILURE);
   2320 	}
   2321 
   2322 
   2323 	/* read in the port's "vcc-tcp-port" property */
   2324 	if (md_get_prop_val(mdp, mdep, "vcc-tcp-port", &tcp_port)) {
   2325 		cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no"
   2326 		    "'vcc-tcp-port' property\n", portno);
   2327 		return (MDEG_FAILURE);
   2328 	}
   2329 
   2330 	D1("i_vcc_md_add_port: port@%d domain-name=%s group-name=%s"
   2331 	    " tcp-port=%lld\n", portno, domain_name, group_name, tcp_port);
   2332 
   2333 	/* add the port */
   2334 	if (i_vcc_add_port(vccp, group_name, tcp_port, portno, domain_name)) {
   2335 		return (MDEG_FAILURE);
   2336 	}
   2337 
   2338 	vport = &vccp->port[portno];
   2339 	if (i_vcc_get_ldc_id(mdp, mdep, &ldc_id)) {
   2340 		mutex_enter(&vport->lock);
   2341 		(void) i_vcc_delete_port(vccp, vport);
   2342 		mutex_exit(&vport->lock);
   2343 		return (MDEG_FAILURE);
   2344 	}
   2345 
   2346 	/* configure the port */
   2347 	if (i_vcc_config_port(vccp, portno, ldc_id)) {
   2348 		mutex_enter(&vport->lock);
   2349 		(void) i_vcc_delete_port(vccp, vport);
   2350 		mutex_exit(&vport->lock);
   2351 		return (MDEG_FAILURE);
   2352 	}
   2353 
   2354 	mutex_enter(&vccp->lock);
   2355 	vccp->num_ports++;
   2356 	mutex_exit(&vccp->lock);
   2357 
   2358 	vport = &vccp->port[VCC_CONTROL_PORT];
   2359 
   2360 	if (vport->pollflag & VCC_POLL_CONFIG) {
   2361 		/* wakeup vntsd */
   2362 		mutex_enter(&vport->lock);
   2363 		vport->pollevent |= VCC_POLL_ADD_PORT;
   2364 		mutex_exit(&vport->lock);
   2365 		pollwakeup(&vport->poll, POLLIN);
   2366 	}
   2367 
   2368 	return (MDEG_SUCCESS);
   2369 }
   2370 
   2371 /* mdeg callback */
   2372 static int
   2373 vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
   2374 {
   2375 	int	idx;
   2376 	vcc_t 	*vccp;
   2377 	int	rv;
   2378 
   2379 	vccp = (vcc_t *)cb_argp;
   2380 	ASSERT(vccp);
   2381 
   2382 	if (resp == NULL) {
   2383 		return (MDEG_FAILURE);
   2384 	}
   2385 
   2386 	/* added port */
   2387 	D1("vcc_mdeg_cb: added %d port(s)\n", resp->added.nelem);
   2388 
   2389 	for (idx = 0; idx < resp->added.nelem; idx++) {
   2390 		rv = i_vcc_md_add_port(resp->added.mdp,
   2391 		    resp->added.mdep[idx], vccp);
   2392 
   2393 		if (rv !=  MDEG_SUCCESS) {
   2394 			return (rv);
   2395 		}
   2396 	}
   2397 
   2398 	/* removed port */
   2399 	D1("vcc_mdeg_cb: removed %d port(s)\n", resp->removed.nelem);
   2400 
   2401 	for (idx = 0; idx < resp->removed.nelem; idx++) {
   2402 		rv = i_vcc_md_remove_port(resp->removed.mdp,
   2403 		    resp->removed.mdep[idx], vccp);
   2404 
   2405 		if (rv !=  MDEG_SUCCESS) {
   2406 			return (rv);
   2407 		}
   2408 
   2409 	}
   2410 
   2411 	/*
   2412 	 * XXX - Currently no support for updating already active
   2413 	 * ports. So, ignore the match_curr and match_prev arrays
   2414 	 * for now.
   2415 	 */
   2416 
   2417 	return (MDEG_SUCCESS);
   2418 }
   2419 
   2420 
   2421 /* cb_chpoll */
   2422 static int
   2423 vcc_chpoll(dev_t dev, short events, int anyyet,  short *reventsp,
   2424     struct pollhead **phpp)
   2425 {
   2426 	int	    instance;
   2427 	minor_t	    minor;
   2428 	uint_t	    portno;
   2429 	vcc_t	    *vccp;
   2430 	vcc_port_t  *vport;
   2431 
   2432 	minor = getminor(dev);
   2433 
   2434 	instance = VCCINST(minor);
   2435 
   2436 	vccp = ddi_get_soft_state(vcc_ssp, instance);
   2437 	if (vccp == NULL) {
   2438 		return (ENXIO);
   2439 	}
   2440 
   2441 	portno = VCCPORT(vccp, minor);
   2442 
   2443 	vport = &(vccp->port[portno]);
   2444 
   2445 	D1("vcc_chpoll: virtual-console-concentrator@%d events 0x%x\n",
   2446 	    portno, events);
   2447 
   2448 	*reventsp = 0;
   2449 
   2450 	if (portno != VCC_CONTROL_PORT) {
   2451 		return (ENXIO);
   2452 	}
   2453 
   2454 	/* poll for config change */
   2455 	if (vport->pollevent) {
   2456 		*reventsp |= (events & POLLIN);
   2457 	}
   2458 
   2459 	if (((*reventsp) == 0) && (!anyyet)) {
   2460 		*phpp = &vport->poll;
   2461 		if (events & POLLIN) {
   2462 			mutex_enter(&vport->lock);
   2463 			vport->pollflag |= VCC_POLL_CONFIG;
   2464 			mutex_exit(&vport->lock);
   2465 		} else {
   2466 			return (ENXIO);
   2467 		}
   2468 	}
   2469 
   2470 	D1("vcc_chpoll: virtual-console-concentrator@%d:%d ev=0x%x, "
   2471 	    "rev=0x%x pev=0x%x, flag=0x%x\n",
   2472 	    instance, portno, events, (*reventsp),
   2473 	    vport->pollevent, vport->pollflag);
   2474 
   2475 
   2476 	return (0);
   2477 }
   2478