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