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