xref: /illumos-gate/usr/src/uts/sun4v/io/vldc.c (revision 60405de4d8688d96dd05157c28db3ade5c9bc234)
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/sysmacros.h>
43 #include <sys/types.h>
44 #include <sys/cred.h>
45 #include <sys/promif.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include <sys/cyclic.h>
49 #include <sys/note.h>
50 #include <sys/mach_descrip.h>
51 #include <sys/mdeg.h>
52 #include <sys/ldc.h>
53 #include <sys/vldc_impl.h>
54 
55 /*
56  * Function prototypes.
57  */
58 
59 /* DDI entrypoints */
60 static int vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
61 static int vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
62 static int vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred);
63 static int vldc_close(dev_t dev, int flag, int otyp, cred_t *cred);
64 static int vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
65     cred_t *credp, int *rvalp);
66 static int vldc_read(dev_t dev, struct uio *uiop, cred_t *credp);
67 static int vldc_write(dev_t dev, struct uio *uiop, cred_t *credp);
68 static int vldc_chpoll(dev_t dev, short events, int anyyet,
69     short *reventsp, struct pollhead **phpp);
70 
71 /* Internal functions */
72 static uint_t i_vldc_cb(uint64_t event, caddr_t arg);
73 static int i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
74 static int i_vldc_mdeg_register(vldc_t *vldcp);
75 static int i_vldc_mdeg_unregister(vldc_t *vldcp);
76 static int i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node);
77 static int i_vldc_remove_port(vldc_t *vldcp, uint_t portno);
78 static int i_vldc_close_port(vldc_t *vldcp, uint_t portno);
79 
80 /* soft state structure */
81 static void *vldc_ssp;
82 
83 /*
84  * Matching criteria passed to the MDEG to register interest
85  * in changes to 'virtual-device-port' nodes identified by their
86  * 'id' property.
87  */
88 static md_prop_match_t vport_prop_match[] = {
89 	{ MDET_PROP_VAL,    "id"   },
90 	{ MDET_LIST_END,    NULL    }
91 };
92 
93 static mdeg_node_match_t vport_match = { "virtual-device-port",
94 					vport_prop_match };
95 
96 /*
97  * Specification of an MD node passed to the MDEG to filter any
98  * 'virtual-device-port' nodes that do not belong to the specified
99  * node. This template is copied for each vldc instance and filled
100  * in with the appropriate 'name' and 'cfg-handle' values before
101  * being passed to the MDEG.
102  */
103 static mdeg_prop_spec_t vldc_prop_template[] = {
104 	{ MDET_PROP_STR,    "name",		NULL	},
105 	{ MDET_PROP_VAL,    "cfg-handle",	NULL    },
106 	{ MDET_LIST_END,    NULL,		NULL    }
107 };
108 
109 #define	VLDC_MDEG_PROP_NAME(specp)		((specp)[0].ps_str)
110 #define	VLDC_SET_MDEG_PROP_NAME(specp, name)	((specp)[0].ps_str = (name))
111 #define	VLDC_SET_MDEG_PROP_INST(specp, inst)	((specp)[1].ps_val = (inst))
112 
113 
114 static struct cb_ops vldc_cb_ops = {
115 	vldc_open,	/* open */
116 	vldc_close,	/* close */
117 	nodev,		/* strategy */
118 	nodev,		/* print */
119 	nodev,		/* dump */
120 	vldc_read,	/* read */
121 	vldc_write,	/* write */
122 	vldc_ioctl,	/* ioctl */
123 	nodev,		/* devmap */
124 	nodev,		/* mmap */
125 	ddi_segmap,	/* segmap */
126 	vldc_chpoll,	/* chpoll */
127 	ddi_prop_op,	/* prop_op */
128 	NULL,		/* stream */
129 	D_NEW | D_MP	/* flag */
130 };
131 
132 static struct dev_ops vldc_ops = {
133 	DEVO_REV,		/* rev */
134 	0,			/* ref count */
135 	ddi_getinfo_1to1,	/* getinfo */
136 	nulldev,		/* identify */
137 	nulldev,		/* probe */
138 	vldc_attach,		/* attach */
139 	vldc_detach,		/* detach */
140 	nodev,			/* reset */
141 	&vldc_cb_ops,		/* cb_ops */
142 	(struct bus_ops *)NULL	/* bus_ops */
143 };
144 
145 extern struct mod_ops mod_driverops;
146 
147 static struct modldrv md = {
148 	&mod_driverops, 			/* Type - it is a driver */
149 	"sun4v Virtual LDC Driver %I%",	/* Name of the module */
150 	&vldc_ops,				/* driver specific ops */
151 };
152 
153 static struct modlinkage ml = {
154 	MODREV_1,
155 	&md,
156 	NULL
157 };
158 
159 /* maximum MTU and cookie size tunables */
160 uint32_t vldc_max_mtu = VLDC_MAX_MTU;
161 uint64_t vldc_max_cookie = VLDC_MAX_COOKIE;
162 
163 
164 #ifdef DEBUG
165 
166 /*
167  * Print debug messages
168  *
169  * set vldcdbg to 0x7 to enable all messages
170  *
171  * 0x4 - Warnings
172  * 0x2 - All debug messages (most verbose)
173  * 0x1 - Minimal debug messages
174  */
175 
176 int vldcdbg = 0x0;
177 
178 static void
179 vldcdebug(const char *fmt, ...)
180 {
181 	char buf[512];
182 	va_list ap;
183 
184 	va_start(ap, fmt);
185 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
186 	va_end(ap);
187 
188 	cmn_err(CE_CONT, "?%s", buf);
189 }
190 
191 #define	D1	if (vldcdbg & 0x01) vldcdebug
192 #define	D2	if (vldcdbg & 0x02) vldcdebug
193 #define	DWARN	if (vldcdbg & 0x04) vldcdebug
194 
195 #else /* not DEBUG */
196 
197 #define	D1	if (0) printf
198 #define	D2	if (0) printf
199 #define	DWARN	if (0) printf
200 
201 #endif /* not DEBUG */
202 
203 
204 /* _init(9E): initialize the loadable module */
205 int
206 _init(void)
207 {
208 	int error;
209 
210 	/* init the soft state structure */
211 	error = ddi_soft_state_init(&vldc_ssp, sizeof (vldc_t), 1);
212 	if (error != 0) {
213 		return (error);
214 	}
215 
216 	/* Link the driver into the system */
217 	error = mod_install(&ml);
218 
219 	return (error);
220 }
221 
222 /* _info(9E): return information about the loadable module */
223 int
224 _info(struct modinfo *modinfop)
225 {
226 	/* Report status of the dynamically loadable driver module */
227 	return (mod_info(&ml, modinfop));
228 }
229 
230 /* _fini(9E): prepare the module for unloading. */
231 int
232 _fini(void)
233 {
234 	int error;
235 
236 	/* Unlink the driver module from the system */
237 	if ((error = mod_remove(&ml)) == 0) {
238 		/*
239 		 * We have successfully "removed" the driver.
240 		 * destroy soft state
241 		 */
242 		ddi_soft_state_fini(&vldc_ssp);
243 	}
244 
245 	return (error);
246 }
247 
248 /* ldc callback */
249 static uint_t
250 i_vldc_cb(uint64_t event, caddr_t arg)
251 {
252 	vldc_port_t	*vport = (vldc_port_t *)arg;
253 	short		pollevents = 0;
254 
255 	D1("i_vldc_cb: vldc@%d:%d callback invoked, channel=0x%lx, "
256 	    "event=0x%lx\n", vport->inst, vport->number, vport->ldc_id, event);
257 
258 	if (event & LDC_EVT_UP) {
259 		pollevents |= POLLOUT;
260 		vport->hanged_up = B_FALSE;
261 
262 	} else if (event & LDC_EVT_RESET) {
263 		/*
264 		 * Mark the port in reset. This implies that it
265 		 * cannot be used until it has been closed and
266 		 * reopened.
267 		 */
268 		if (vport->status != VLDC_PORT_CLOSED)
269 			vport->status = VLDC_PORT_RESET;
270 		return (LDC_SUCCESS);
271 
272 	} else if (event & LDC_EVT_DOWN) {
273 		/*
274 		 * The other side went away
275 		 */
276 		vport->hanged_up = B_TRUE;
277 		pollevents = POLLHUP;
278 	}
279 
280 	if (event & LDC_EVT_READ)
281 		pollevents |= POLLIN;
282 
283 	if (pollevents != 0) {
284 		D1("i_vldc_cb: port@%d pollwakeup=0x%x\n",
285 		    vport->number, pollevents);
286 		pollwakeup(&vport->poll, pollevents);
287 	}
288 
289 	return (LDC_SUCCESS);
290 }
291 
292 /* mdeg callback */
293 static int
294 i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
295 {
296 	vldc_t		*vldcp;
297 	int		idx;
298 	uint64_t	portno;
299 	int		rv;
300 	md_t		*mdp;
301 	mde_cookie_t	node;
302 
303 	if (resp == NULL) {
304 		D1("i_vldc_mdeg_cb: no result returned\n");
305 		return (MDEG_FAILURE);
306 	}
307 
308 	vldcp = (vldc_t *)cb_argp;
309 
310 	mutex_enter(&vldcp->lock);
311 	if (vldcp->detaching == B_TRUE) {
312 		D1("i_vldc_mdeg_cb: detach in progress\n");
313 		mutex_exit(&vldcp->lock);
314 		return (MDEG_FAILURE);
315 	}
316 
317 	D1("i_vldc_mdeg_cb: added=%d, removed=%d, matched=%d\n",
318 	    resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem);
319 
320 	/* process added ports */
321 	for (idx = 0; idx < resp->added.nelem; idx++) {
322 		mdp = resp->added.mdp;
323 		node = resp->added.mdep[idx];
324 
325 		D1("i_vldc_mdeg_cb: processing added node 0x%lx\n", node);
326 
327 		/* attempt to add a port */
328 		if ((rv = i_vldc_add_port(vldcp, mdp, node)) != MDEG_SUCCESS) {
329 			cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to add port, "
330 			    "err = %d", rv);
331 		}
332 	}
333 
334 	/* process removed ports */
335 	for (idx = 0; idx < resp->removed.nelem; idx++) {
336 		mdp = resp->removed.mdp;
337 		node = resp->removed.mdep[idx];
338 
339 		D1("i_vldc_mdeg_cb: processing removed node 0x%lx\n", node);
340 
341 		/* read in the port's id property */
342 		if (md_get_prop_val(mdp, node, "id", &portno)) {
343 			cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: node 0x%lx of "
344 			    "removed list has no 'id' property", node);
345 			continue;
346 		}
347 
348 		/* attempt to remove a port */
349 		if ((rv = i_vldc_remove_port(vldcp, portno)) != 0) {
350 			cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to remove "
351 			    "port %lu, err %d", portno, rv);
352 		}
353 	}
354 
355 	/*
356 	 * Currently no support for updating already active ports. So, ignore
357 	 * the match_curr and match_prev arrays for now.
358 	 */
359 
360 	mutex_exit(&vldcp->lock);
361 
362 	return (MDEG_SUCCESS);
363 }
364 
365 /* register callback to mdeg */
366 static int
367 i_vldc_mdeg_register(vldc_t *vldcp)
368 {
369 	mdeg_prop_spec_t *pspecp;
370 	mdeg_node_spec_t *inst_specp;
371 	mdeg_handle_t	mdeg_hdl;
372 	size_t		templatesz;
373 	int		inst;
374 	char		*name;
375 	size_t		namesz;
376 	char		*nameprop;
377 	int		rv;
378 
379 	/* get the unique vldc instance assigned by the LDom manager */
380 	inst = ddi_prop_get_int(DDI_DEV_T_ANY, vldcp->dip,
381 	    DDI_PROP_DONTPASS, "reg", -1);
382 	if (inst == -1) {
383 		cmn_err(CE_NOTE, "?vldc%d has no 'reg' property",
384 		    ddi_get_instance(vldcp->dip));
385 		return (DDI_FAILURE);
386 	}
387 
388 	/* get the name of the vldc instance */
389 	rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip,
390 	    DDI_PROP_DONTPASS, "name", &nameprop);
391 	if (rv != DDI_PROP_SUCCESS) {
392 		cmn_err(CE_NOTE, "?vldc%d has no 'name' property",
393 		    ddi_get_instance(vldcp->dip));
394 		return (DDI_FAILURE);
395 	}
396 
397 	D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst);
398 
399 	/*
400 	 * Allocate and initialize a per-instance copy
401 	 * of the global property spec array that will
402 	 * uniquely identify this vldc instance.
403 	 */
404 	templatesz = sizeof (vldc_prop_template);
405 	pspecp = kmem_alloc(templatesz, KM_SLEEP);
406 
407 	bcopy(vldc_prop_template, pspecp, templatesz);
408 
409 	/* copy in the name property */
410 	namesz = strlen(nameprop) + 1;
411 	name = kmem_alloc(namesz, KM_SLEEP);
412 
413 	bcopy(nameprop, name, namesz);
414 	VLDC_SET_MDEG_PROP_NAME(pspecp, name);
415 	ddi_prop_free(nameprop);
416 
417 	/* copy in the instance property */
418 	VLDC_SET_MDEG_PROP_INST(pspecp, inst);
419 
420 	/* initialize the complete prop spec structure */
421 	inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP);
422 	inst_specp->namep = "virtual-device";
423 	inst_specp->specp = pspecp;
424 
425 	/* perform the registration */
426 	rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb,
427 	    vldcp, &mdeg_hdl);
428 
429 	if (rv != MDEG_SUCCESS) {
430 		cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register "
431 		    "failed, err = %d", rv);
432 		kmem_free(name, namesz);
433 		kmem_free(pspecp, templatesz);
434 		kmem_free(inst_specp, sizeof (mdeg_node_spec_t));
435 		return (DDI_FAILURE);
436 	}
437 
438 	/* save off data that will be needed later */
439 	vldcp->inst_spec = inst_specp;
440 	vldcp->mdeg_hdl = mdeg_hdl;
441 
442 	return (DDI_SUCCESS);
443 }
444 
445 /* unregister callback from mdeg */
446 static int
447 i_vldc_mdeg_unregister(vldc_t *vldcp)
448 {
449 	char	*name;
450 	int	rv;
451 
452 	D1("i_vldc_mdeg_unregister: hdl=0x%lx\n", vldcp->mdeg_hdl);
453 
454 	rv = mdeg_unregister(vldcp->mdeg_hdl);
455 	if (rv != MDEG_SUCCESS) {
456 		return (rv);
457 	}
458 
459 	/*
460 	 * Clean up cached MDEG data
461 	 */
462 	name = VLDC_MDEG_PROP_NAME(vldcp->inst_spec->specp);
463 	if (name != NULL) {
464 		kmem_free(name, strlen(name) + 1);
465 	}
466 	kmem_free(vldcp->inst_spec->specp, sizeof (vldc_prop_template));
467 	vldcp->inst_spec->specp = NULL;
468 
469 	kmem_free(vldcp->inst_spec, sizeof (mdeg_node_spec_t));
470 	vldcp->inst_spec = NULL;
471 
472 	return (MDEG_SUCCESS);
473 }
474 
475 static int
476 i_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id)
477 {
478 	int num_nodes, nchan;
479 	size_t listsz;
480 	mde_cookie_t *listp;
481 
482 	/*
483 	 * Find the channel-endpoint node(s) (which should be under this
484 	 * port node) which contain the channel id(s).
485 	 */
486 	if ((num_nodes = md_node_count(mdp)) <= 0) {
487 		cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of "
488 		    "channel-endpoint nodes found (%d)", num_nodes);
489 		return (-1);
490 	}
491 
492 	/* allocate space for node list */
493 	listsz = num_nodes * sizeof (mde_cookie_t);
494 	listp = kmem_alloc(listsz, KM_SLEEP);
495 
496 	nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"),
497 	    md_find_name(mdp, "fwd"), listp);
498 
499 	if (nchan <= 0) {
500 		cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint"
501 		    " nodes found");
502 		kmem_free(listp, listsz);
503 		return (-1);
504 	}
505 
506 	D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan);
507 
508 	/* use property from first node found */
509 	if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) {
510 		cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint "
511 		    "has no 'id' property");
512 		kmem_free(listp, listsz);
513 		return (-1);
514 	}
515 
516 	kmem_free(listp, listsz);
517 
518 	return (0);
519 }
520 
521 /* add a vldc port */
522 static int
523 i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node)
524 {
525 	vldc_port_t	*vport;
526 	char		*sname;
527 	uint64_t	portno;
528 	int		vldc_inst;
529 	minor_t		minor;
530 	int		minor_idx;
531 	boolean_t	new_minor;
532 	int		rv;
533 
534 	/* read in the port's id property */
535 	if (md_get_prop_val(mdp, node, "id", &portno)) {
536 		cmn_err(CE_NOTE, "?i_vldc_add_port: node 0x%lx of added "
537 		    "list has no 'id' property", node);
538 		return (MDEG_FAILURE);
539 	}
540 
541 	if (portno >= VLDC_MAX_PORTS) {
542 		cmn_err(CE_NOTE, "?i_vldc_add_port: found port number (%lu) "
543 		    "larger than maximum supported number of ports", portno);
544 		return (MDEG_FAILURE);
545 	}
546 
547 	vport = &(vldcp->port[portno]);
548 
549 	if (vport->minorp != NULL) {
550 		cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)"
551 		    " which is already bound", portno);
552 		return (MDEG_FAILURE);
553 	}
554 
555 	vport->number = portno;
556 
557 	/* get all channels for this device (currently only one) */
558 	if (i_vldc_get_port_channel(mdp, node, &vport->ldc_id) == -1) {
559 		return (MDEG_FAILURE);
560 	}
561 
562 	/* set the default MTU */
563 	vport->mtu = VLDC_DEFAULT_MTU;
564 
565 	/* get the service being exported by this port */
566 	if (md_get_prop_str(mdp, node, "vldc-svc-name", &sname)) {
567 		cmn_err(CE_NOTE, "?i_vldc_add_port: vdevice has no "
568 		    "'vldc-svc-name' property");
569 		return (MDEG_FAILURE);
570 	}
571 
572 	/* minor number look up */
573 	for (minor_idx = 0; minor_idx < vldcp->minors_assigned;
574 	    minor_idx++) {
575 		if (strcmp(vldcp->minor_tbl[minor_idx].sname, sname) == 0) {
576 			/* found previously assigned minor number */
577 			break;
578 		}
579 	}
580 
581 	new_minor = B_FALSE;
582 	if (minor_idx == vldcp->minors_assigned) {
583 		/* end of lookup - assign new minor number */
584 		if (vldcp->minors_assigned == VLDC_MAX_MINORS) {
585 			cmn_err(CE_NOTE, "?i_vldc_add_port: too many minor "
586 			    "nodes (%d)", minor_idx);
587 			return (MDEG_FAILURE);
588 		}
589 
590 		(void) strlcpy(vldcp->minor_tbl[minor_idx].sname,
591 		    sname, MAXPATHLEN);
592 
593 		vldcp->minors_assigned++;
594 		new_minor = B_TRUE;
595 	}
596 
597 	ASSERT(vldcp->minor_tbl[minor_idx].portno == VLDC_INVALID_PORTNO);
598 
599 	vldc_inst = ddi_get_instance(vldcp->dip);
600 
601 	vport->inst = vldc_inst;
602 	vport->minorp = &vldcp->minor_tbl[minor_idx];
603 	vldcp->minor_tbl[minor_idx].portno = portno;
604 	vldcp->minor_tbl[minor_idx].in_use = 0;
605 
606 	D1("i_vldc_add_port: vldc@%d:%d  mtu=%d, ldc=%ld, service=%s\n",
607 	    vport->inst, vport->number, vport->mtu, vport->ldc_id, sname);
608 
609 	/*
610 	 * Create a minor node. The minor number is
611 	 * (vldc_inst << VLDC_INST_SHIFT) | minor_idx
612 	 */
613 	minor = (vldc_inst << VLDC_INST_SHIFT) | (minor_idx);
614 
615 	rv = ddi_create_minor_node(vldcp->dip, sname, S_IFCHR,
616 	    minor, DDI_NT_SERIAL, 0);
617 
618 	if (rv != DDI_SUCCESS) {
619 		cmn_err(CE_NOTE, "?i_vldc_add_port: failed to create minor"
620 		    "node (%u), err = %d", minor, rv);
621 		vldcp->minor_tbl[minor_idx].portno = VLDC_INVALID_PORTNO;
622 		if (new_minor) {
623 			vldcp->minors_assigned--;
624 		}
625 		return (MDEG_FAILURE);
626 	}
627 
628 	/*
629 	 * The port is now bound to a minor node and is initially in the
630 	 * closed state.
631 	 */
632 	vport->status = VLDC_PORT_CLOSED;
633 
634 	D1("i_vldc_add_port: port %lu initialized\n", portno);
635 
636 	return (MDEG_SUCCESS);
637 }
638 
639 /* remove a vldc port */
640 static int
641 i_vldc_remove_port(vldc_t *vldcp, uint_t portno)
642 {
643 	vldc_port_t *vport;
644 	vldc_minor_t *vminor;
645 
646 	vport = &(vldcp->port[portno]);
647 	vminor = vport->minorp;
648 	if (vminor == NULL) {
649 		cmn_err(CE_NOTE, "?i_vldc_remove_port: trying to remove a "
650 		    "port (%u) which is not bound", portno);
651 		return (MDEG_FAILURE);
652 	}
653 
654 	/*
655 	 * Make sure that all new attempts to open or use the minor node
656 	 * associated with the port will fail.
657 	 */
658 	mutex_enter(&vminor->lock);
659 	vminor->portno = VLDC_INVALID_PORTNO;
660 	mutex_exit(&vminor->lock);
661 
662 	/* send hangup to anyone polling */
663 	pollwakeup(&vport->poll, POLLHUP);
664 
665 	/* Now wait for all current users of the minor node to finish. */
666 	mutex_enter(&vminor->lock);
667 	while (vminor->in_use > 0) {
668 		cv_wait(&vminor->cv, &vminor->lock);
669 	}
670 
671 	if (vport->status != VLDC_PORT_CLOSED) {
672 		/* close the port before it is torn down */
673 		(void) i_vldc_close_port(vldcp, portno);
674 	}
675 
676 	/* remove minor node */
677 	ddi_remove_minor_node(vldcp->dip, vport->minorp->sname);
678 	vport->minorp = NULL;
679 
680 	mutex_exit(&vminor->lock);
681 
682 	D1("i_vldc_remove_port: removed vldc port %u\n", portno);
683 
684 	return (MDEG_SUCCESS);
685 }
686 
687 /* close a ldc channel */
688 static int
689 i_vldc_ldc_close(vldc_port_t *vport)
690 {
691 	int rv = 0;
692 	int err;
693 
694 	err = ldc_close(vport->ldc_handle);
695 	if (err != 0)
696 		rv = err;
697 	err = ldc_unreg_callback(vport->ldc_handle);
698 	if ((err != 0) && (rv != 0))
699 		rv = err;
700 	err = ldc_fini(vport->ldc_handle);
701 	if ((err != 0) && (rv != 0))
702 		rv = err;
703 
704 	vport->status = VLDC_PORT_OPEN;
705 
706 	return (rv);
707 }
708 
709 /* close a vldc port */
710 static int
711 i_vldc_close_port(vldc_t *vldcp, uint_t portno)
712 {
713 	vldc_port_t	*vport;
714 	int		rv = DDI_SUCCESS;
715 
716 	vport = &(vldcp->port[portno]);
717 
718 	ASSERT(MUTEX_HELD(&vport->minorp->lock));
719 
720 	D1("i_vldc_close_port: vldc@%d:%d: closing port\n",
721 	    vport->inst, vport->minorp->portno);
722 
723 	switch (vport->status) {
724 	case VLDC_PORT_CLOSED:
725 		/* nothing to do */
726 		DWARN("i_vldc_close_port: port %d in an unexpected "
727 		    "state (%d)\n", portno, vport->status);
728 		return (DDI_SUCCESS);
729 
730 	case VLDC_PORT_READY:
731 	case VLDC_PORT_RESET:
732 		rv = i_vldc_ldc_close(vport);
733 		break;
734 	}
735 
736 	ASSERT(vport->status == VLDC_PORT_OPEN);
737 
738 	/* free memory */
739 	kmem_free(vport->send_buf, vport->mtu);
740 	kmem_free(vport->recv_buf, vport->mtu);
741 
742 	if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0)
743 		kmem_free(vport->cookie_buf, vldc_max_cookie);
744 
745 	vport->status = VLDC_PORT_CLOSED;
746 
747 	return (rv);
748 }
749 
750 /*
751  * attach(9E): attach a device to the system.
752  * called once for each instance of the device on the system.
753  */
754 static int
755 vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
756 {
757 	int 	i, instance;
758 	vldc_t	*vldcp;
759 
760 	switch (cmd) {
761 
762 	case DDI_ATTACH:
763 
764 		instance = ddi_get_instance(dip);
765 
766 		if (ddi_soft_state_zalloc(vldc_ssp, instance) != DDI_SUCCESS) {
767 			return (DDI_FAILURE);
768 		}
769 
770 		vldcp = ddi_get_soft_state(vldc_ssp, instance);
771 		if (vldcp == NULL) {
772 			ddi_soft_state_free(vldc_ssp, instance);
773 			return (ENXIO);
774 		}
775 
776 		D1("vldc_attach: DDI_ATTACH instance=%d\n", instance);
777 
778 		mutex_init(&vldcp->lock, NULL, MUTEX_DRIVER, NULL);
779 		vldcp->dip = dip;
780 		vldcp->detaching = B_FALSE;
781 
782 		for (i = 0; i < VLDC_MAX_PORTS; i++) {
783 			/* No minor node association to start with */
784 			vldcp->port[i].minorp = NULL;
785 		}
786 
787 		for (i = 0; i < VLDC_MAX_MINORS; i++) {
788 			mutex_init(&(vldcp->minor_tbl[i].lock), NULL,
789 			    MUTEX_DRIVER, NULL);
790 			cv_init(&(vldcp->minor_tbl[i].cv), NULL,
791 			    CV_DRIVER, NULL);
792 			/* No port association to start with */
793 			vldcp->minor_tbl[i].portno = VLDC_INVALID_PORTNO;
794 		}
795 
796 		/* Register for MD update notification */
797 		if (i_vldc_mdeg_register(vldcp) != DDI_SUCCESS) {
798 			ddi_soft_state_free(vldc_ssp, instance);
799 			return (DDI_FAILURE);
800 		}
801 
802 		return (DDI_SUCCESS);
803 
804 	case DDI_RESUME:
805 
806 		return (DDI_SUCCESS);
807 
808 	default:
809 
810 		return (DDI_FAILURE);
811 	}
812 }
813 
814 /*
815  * detach(9E): detach a device from the system.
816  */
817 static int
818 vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
819 {
820 	int 		i, instance;
821 	vldc_t		*vldcp;
822 
823 	switch (cmd) {
824 
825 	case DDI_DETACH:
826 
827 		instance = ddi_get_instance(dip);
828 
829 		vldcp = ddi_get_soft_state(vldc_ssp, instance);
830 		if (vldcp == NULL) {
831 			return (DDI_FAILURE);
832 		}
833 
834 		D1("vldc_detach: DDI_DETACH instance=%d\n", instance);
835 
836 		mutex_enter(&vldcp->lock);
837 
838 		/* Fail the detach if all ports have not been removed. */
839 		for (i = 0; i < VLDC_MAX_MINORS; i++) {
840 			if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) {
841 				D1("vldc_detach: vldc@%d:%d is bound, "
842 				    "detach failed\n",
843 				    instance, vldcp->minor_tbl[i].portno);
844 				mutex_exit(&vldcp->lock);
845 				return (DDI_FAILURE);
846 			}
847 		}
848 
849 		/*
850 		 * Prevent MDEG from adding new ports before the callback can
851 		 * be unregistered. The lock can't be held accross the
852 		 * unregistration call because a callback may be in progress
853 		 * and blocked on the lock.
854 		 */
855 		vldcp->detaching = B_TRUE;
856 
857 		mutex_exit(&vldcp->lock);
858 
859 		if (i_vldc_mdeg_unregister(vldcp) != MDEG_SUCCESS) {
860 			vldcp->detaching = B_FALSE;
861 			return (DDI_FAILURE);
862 		}
863 
864 		/* Tear down all bound ports and free resources. */
865 		for (i = 0; i < VLDC_MAX_MINORS; i++) {
866 			if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) {
867 				(void) i_vldc_remove_port(vldcp, i);
868 			}
869 			mutex_destroy(&(vldcp->minor_tbl[i].lock));
870 			cv_destroy(&(vldcp->minor_tbl[i].cv));
871 		}
872 
873 		mutex_destroy(&vldcp->lock);
874 		ddi_soft_state_free(vldc_ssp, instance);
875 
876 		return (DDI_SUCCESS);
877 
878 	case DDI_SUSPEND:
879 
880 		return (DDI_SUCCESS);
881 
882 	default:
883 
884 		return (DDI_FAILURE);
885 	}
886 }
887 
888 /* cb_open */
889 static int
890 vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred)
891 {
892 	_NOTE(ARGUNUSED(flag, otyp, cred))
893 
894 	int instance;
895 	minor_t minor;
896 	uint64_t portno;
897 	vldc_t *vldcp;
898 	vldc_port_t *vport;
899 	vldc_minor_t *vminor;
900 
901 	minor = getminor(*devp);
902 	instance = VLDCINST(minor);
903 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
904 	if (vldcp == NULL)
905 		return (ENXIO);
906 
907 	vminor = VLDCMINOR(vldcp, minor);
908 	mutex_enter(&vminor->lock);
909 	portno = vminor->portno;
910 	if (portno == VLDC_INVALID_PORTNO) {
911 		mutex_exit(&vminor->lock);
912 		return (ENXIO);
913 	}
914 
915 	vport = &(vldcp->port[portno]);
916 
917 	D1("vldc_open: opening vldc@%d:%lu\n", instance, portno);
918 
919 	if (vport->status != VLDC_PORT_CLOSED) {
920 		mutex_exit(&vminor->lock);
921 		return (EBUSY);
922 	}
923 
924 	vport->recv_buf = kmem_alloc(vport->mtu, KM_SLEEP);
925 	vport->send_buf = kmem_alloc(vport->mtu, KM_SLEEP);
926 
927 	if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0)
928 		vport->cookie_buf = kmem_alloc(vldc_max_cookie, KM_SLEEP);
929 
930 	vport->is_stream = B_FALSE;	/* assume not a stream */
931 	vport->hanged_up = B_FALSE;
932 
933 	vport->status = VLDC_PORT_OPEN;
934 
935 	mutex_exit(&vminor->lock);
936 
937 	return (DDI_SUCCESS);
938 }
939 
940 /* cb_close */
941 static int
942 vldc_close(dev_t dev, int flag, int otyp, cred_t *cred)
943 {
944 	_NOTE(ARGUNUSED(flag, otyp, cred))
945 
946 	int instance;
947 	minor_t minor;
948 	uint64_t portno;
949 	vldc_t *vldcp;
950 	vldc_minor_t *vminor;
951 	int rv;
952 
953 	minor = getminor(dev);
954 	instance = VLDCINST(minor);
955 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
956 	if (vldcp == NULL) {
957 		return (ENXIO);
958 	}
959 
960 	vminor = VLDCMINOR(vldcp, minor);
961 	mutex_enter(&vminor->lock);
962 	portno = vminor->portno;
963 	if (portno == VLDC_INVALID_PORTNO) {
964 		mutex_exit(&vminor->lock);
965 		return (ENOLINK);
966 	}
967 
968 	D1("vldc_close: closing vldc@%d:%lu\n", instance, portno);
969 
970 	rv = i_vldc_close_port(vldcp, portno);
971 
972 	mutex_exit(&vminor->lock);
973 
974 	return (rv);
975 }
976 
977 static int
978 vldc_set_ldc_mode(vldc_port_t *vport, vldc_t *vldcp, int channel_mode)
979 {
980 	ldc_attr_t attr;
981 	int rv;
982 
983 	ASSERT(MUTEX_HELD(&vport->minorp->lock));
984 
985 	/* validate mode */
986 	switch (channel_mode) {
987 	case LDC_MODE_STREAM:
988 		vport->is_stream = B_TRUE;
989 		break;
990 	case LDC_MODE_RAW:
991 	case LDC_MODE_UNRELIABLE:
992 	case LDC_MODE_RELIABLE:
993 		vport->is_stream = B_FALSE;
994 		break;
995 	default:
996 		return (EINVAL);
997 	}
998 
999 	if (vport->status == VLDC_PORT_READY) {
1000 		rv = i_vldc_ldc_close(vport);
1001 		if (rv != 0) {
1002 			DWARN("vldc_set_ldc_mode: i_vldc_ldc_close "
1003 			    "failed, rv=%d\n", rv);
1004 			return (rv);
1005 		}
1006 	}
1007 
1008 	D1("vldc_set_ldc_mode: vport status %d, mode %d\n",
1009 	    vport->status, channel_mode);
1010 
1011 	vport->ldc_mode = channel_mode;
1012 
1013 	/* initialize the channel */
1014 	attr.devclass = LDC_DEV_SERIAL;
1015 	attr.instance = ddi_get_instance(vldcp->dip);
1016 	attr.mtu = vport->mtu;
1017 	attr.mode = vport->ldc_mode;
1018 
1019 	if ((rv = ldc_init(vport->ldc_id, &attr,
1020 	    &vport->ldc_handle)) != 0) {
1021 		DWARN("vldc_ioctl_opt_op: ldc_init failed, rv=%d\n", rv);
1022 		goto error_init;
1023 	}
1024 
1025 	/* register it */
1026 	if ((rv = ldc_reg_callback(vport->ldc_handle,
1027 	    i_vldc_cb, (caddr_t)vport)) != 0) {
1028 		DWARN("vldc_ioctl_opt_op: ldc_reg_callback failed, rv=%d\n",
1029 		    rv);
1030 		goto error_reg;
1031 	}
1032 
1033 	/* open the channel */
1034 	if ((rv = ldc_open(vport->ldc_handle)) != 0) {
1035 		DWARN("vldc_ioctl_opt_op: ldc_open failed, rv=%d\n", rv);
1036 		goto error_open;
1037 	}
1038 
1039 	vport->status = VLDC_PORT_READY;
1040 
1041 	/*
1042 	 * Attempt to bring the channel up, but do not
1043 	 * fail if the other end is not up yet.
1044 	 */
1045 	rv = ldc_up(vport->ldc_handle);
1046 
1047 	if (rv == ECONNREFUSED) {
1048 		D1("vldc_ioctl_opt_op: remote endpoint not up yet\n");
1049 	} else if (rv != 0) {
1050 		DWARN("vldc_ioctl_opt_op: ldc_up failed, rv=%d\n", rv);
1051 		goto error_up;
1052 	}
1053 
1054 	D1("vldc_ioctl_opt_op: ldc %ld initialized successfully\n",
1055 	    vport->ldc_id);
1056 
1057 	return (0);
1058 
1059 error_up:
1060 	vport->status = VLDC_PORT_OPEN;
1061 	(void) ldc_close(vport->ldc_handle);
1062 error_open:
1063 	(void) ldc_unreg_callback(vport->ldc_handle);
1064 error_reg:
1065 	(void) ldc_fini(vport->ldc_handle);
1066 error_init:
1067 	return (rv);
1068 }
1069 
1070 /* ioctl to read cookie */
1071 static int
1072 i_vldc_ioctl_read_cookie(vldc_port_t *vport, int vldc_instance, void *arg,
1073     int mode)
1074 {
1075 	vldc_data_t copy_info;
1076 	uint64_t len, balance, copy_size;
1077 	caddr_t src_addr, dst_addr;
1078 	int rv;
1079 
1080 	if (ddi_copyin(arg, &copy_info, sizeof (copy_info), mode) == -1) {
1081 		return (EFAULT);
1082 	}
1083 
1084 	len = balance = copy_info.length;
1085 	src_addr = (caddr_t)copy_info.src_addr;
1086 	dst_addr = (caddr_t)copy_info.dst_addr;
1087 	while (balance > 0) {
1088 
1089 		/* get the max amount to the copied */
1090 		copy_size = MIN(balance, vldc_max_cookie);
1091 
1092 		mutex_enter(&vport->minorp->lock);
1093 
1094 		D2("i_vldc_ioctl_read_cookie: vldc@%d:%d reading from 0x%p "
1095 		    "size 0x%lx to 0x%p\n", vldc_instance, vport->number,
1096 		    dst_addr, copy_size, src_addr);
1097 
1098 		/* read from the HV into the temporary buffer */
1099 		rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf,
1100 		    &copy_size, dst_addr, LDC_COPY_IN);
1101 		if (rv != 0) {
1102 			DWARN("i_vldc_ioctl_read_cookie: vldc@%d:%d cannot "
1103 			    "read address 0x%p, rv=%d\n",
1104 			    vldc_instance, vport->number, dst_addr, rv);
1105 			mutex_exit(&vport->minorp->lock);
1106 			return (EFAULT);
1107 		}
1108 
1109 		D2("i_vldc_ioctl_read_cookie: vldc@%d:%d read succeeded\n",
1110 		    vldc_instance, vport->number);
1111 
1112 		mutex_exit(&vport->minorp->lock);
1113 
1114 		/*
1115 		 * copy data from temporary buffer out to the
1116 		 * caller and free buffer
1117 		 */
1118 		rv = ddi_copyout(vport->cookie_buf, src_addr, copy_size, mode);
1119 		if (rv != 0) {
1120 			return (EFAULT);
1121 		}
1122 
1123 		/* adjust len, source and dest */
1124 		balance -= copy_size;
1125 		src_addr += copy_size;
1126 		dst_addr += copy_size;
1127 	}
1128 
1129 	/* set the structure to reflect outcome */
1130 	copy_info.length = len;
1131 	if (ddi_copyout(&copy_info, arg, sizeof (copy_info), mode) != 0) {
1132 		return (EFAULT);
1133 	}
1134 
1135 	return (0);
1136 }
1137 
1138 /* ioctl to write cookie */
1139 static int
1140 i_vldc_ioctl_write_cookie(vldc_port_t *vport, int vldc_instance, void *arg,
1141     int mode)
1142 {
1143 	vldc_data_t copy_info;
1144 	uint64_t len, balance, copy_size;
1145 	caddr_t src_addr, dst_addr;
1146 	int rv;
1147 
1148 	if (ddi_copyin(arg, &copy_info, sizeof (copy_info), mode) != 0) {
1149 		return (EFAULT);
1150 	}
1151 
1152 	D2("i_vldc_ioctl_write_cookie: vldc@%d:%d writing 0x%lx size 0x%lx "
1153 	    "to 0x%lx\n", vldc_instance, vport->number, copy_info.src_addr,
1154 	    copy_info.length, copy_info.dst_addr);
1155 
1156 	len = balance = copy_info.length;
1157 	src_addr = (caddr_t)copy_info.src_addr;
1158 	dst_addr = (caddr_t)copy_info.dst_addr;
1159 	while (balance > 0) {
1160 
1161 		/* get the max amount to the copied */
1162 		copy_size = MIN(balance, vldc_max_cookie);
1163 
1164 		/*
1165 		 * copy into the temporary buffer the data
1166 		 * to be written to the HV
1167 		 */
1168 		if (ddi_copyin((caddr_t)src_addr, vport->cookie_buf,
1169 		    copy_size, mode) != 0) {
1170 			return (EFAULT);
1171 		}
1172 
1173 		mutex_enter(&vport->minorp->lock);
1174 
1175 		/* write the data from the temporary buffer to the HV */
1176 		rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf,
1177 		    &copy_size, dst_addr, LDC_COPY_OUT);
1178 		if (rv != 0) {
1179 			DWARN("i_vldc_ioctl_write_cookie: vldc@%d:%d "
1180 			    "failed to write at address 0x%p\n, rv=%d",
1181 			    vldc_instance, vport->number, dst_addr, rv);
1182 			mutex_exit(&vport->minorp->lock);
1183 			return (EFAULT);
1184 		}
1185 
1186 		D2("i_vldc_ioctl_write_cookie: vldc@%d:%d write succeeded\n",
1187 		    vldc_instance, vport->number);
1188 
1189 		mutex_exit(&vport->minorp->lock);
1190 
1191 		/* adjust len, source and dest */
1192 		balance -= copy_size;
1193 		src_addr += copy_size;
1194 		dst_addr += copy_size;
1195 	}
1196 
1197 	/* set the structure to reflect outcome */
1198 	copy_info.length = len;
1199 	if (ddi_copyout(&copy_info, (caddr_t)arg,
1200 	    sizeof (copy_info), mode) != 0) {
1201 		return (EFAULT);
1202 	}
1203 
1204 	return (0);
1205 }
1206 
1207 /* vldc specific ioctl option commands */
1208 static int
1209 i_vldc_ioctl_opt_op(vldc_port_t *vport, vldc_t *vldcp, void *arg, int mode)
1210 {
1211 	vldc_opt_op_t 	vldc_cmd;
1212 	uint32_t	new_mtu;
1213 	int		rv = 0;
1214 
1215 	if (ddi_copyin(arg, &vldc_cmd, sizeof (vldc_cmd), mode) != 0) {
1216 		return (EFAULT);
1217 	}
1218 
1219 	D1("vldc_ioctl_opt_op: op %d\n", vldc_cmd.opt_sel);
1220 
1221 	switch (vldc_cmd.opt_sel) {
1222 
1223 	case VLDC_OPT_MTU_SZ:
1224 
1225 		if (vldc_cmd.op_sel == VLDC_OP_GET) {
1226 			vldc_cmd.opt_val = vport->mtu;
1227 			if (ddi_copyout(&vldc_cmd, arg,
1228 			    sizeof (vldc_cmd), mode) == -1) {
1229 				return (EFAULT);
1230 			}
1231 		} else {
1232 			new_mtu = vldc_cmd.opt_val;
1233 
1234 			if ((new_mtu < LDC_PACKET_SIZE) ||
1235 			    (new_mtu > vldc_max_mtu)) {
1236 				return (EINVAL);
1237 			}
1238 
1239 			mutex_enter(&vport->minorp->lock);
1240 
1241 			if ((vport->status != VLDC_PORT_CLOSED) &&
1242 			    (new_mtu != vport->mtu)) {
1243 				/*
1244 				 * The port has buffers allocated since it is
1245 				 * not closed plus the MTU size has changed.
1246 				 * Reallocate the buffers to the new MTU size.
1247 				 */
1248 				kmem_free(vport->recv_buf, vport->mtu);
1249 				vport->recv_buf = kmem_alloc(new_mtu, KM_SLEEP);
1250 
1251 				kmem_free(vport->send_buf, vport->mtu);
1252 				vport->send_buf = kmem_alloc(new_mtu, KM_SLEEP);
1253 
1254 				vport->mtu = new_mtu;
1255 			}
1256 
1257 			mutex_exit(&vport->minorp->lock);
1258 		}
1259 
1260 		break;
1261 
1262 	case VLDC_OPT_STATUS:
1263 
1264 		if (vldc_cmd.op_sel == VLDC_OP_GET) {
1265 			vldc_cmd.opt_val = vport->status;
1266 			if (ddi_copyout(&vldc_cmd, arg,
1267 			    sizeof (vldc_cmd), mode) == -1) {
1268 				return (EFAULT);
1269 			}
1270 		} else {
1271 			return (ENOTSUP);
1272 		}
1273 
1274 		break;
1275 
1276 	case VLDC_OPT_MODE:
1277 
1278 		if (vldc_cmd.op_sel == VLDC_OP_GET) {
1279 			vldc_cmd.opt_val = vport->ldc_mode;
1280 			if (ddi_copyout(&vldc_cmd, arg,
1281 			    sizeof (vldc_cmd), mode) == -1) {
1282 				return (EFAULT);
1283 			}
1284 		} else {
1285 			mutex_enter(&vport->minorp->lock);
1286 			rv = vldc_set_ldc_mode(vport, vldcp, vldc_cmd.opt_val);
1287 			mutex_exit(&vport->minorp->lock);
1288 		}
1289 
1290 		break;
1291 
1292 	default:
1293 
1294 		D1("vldc_ioctl_opt_op: unsupported op %d\n", vldc_cmd.opt_sel);
1295 		return (ENOTSUP);
1296 	}
1297 
1298 	return (rv);
1299 }
1300 
1301 /* cb_ioctl */
1302 static int
1303 vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1304     int *rvalp)
1305 {
1306 	_NOTE(ARGUNUSED(credp, rvalp))
1307 
1308 	int rv = EINVAL;
1309 	int instance;
1310 	minor_t minor;
1311 	uint64_t portno;
1312 	vldc_t *vldcp;
1313 	vldc_port_t *vport;
1314 	vldc_minor_t *vminor;
1315 
1316 	minor = getminor(dev);
1317 	instance = VLDCINST(minor);
1318 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
1319 	if (vldcp == NULL) {
1320 		return (ENXIO);
1321 	}
1322 
1323 	vminor = VLDCMINOR(vldcp, minor);
1324 	mutex_enter(&vminor->lock);
1325 	portno = vminor->portno;
1326 	if (portno == VLDC_INVALID_PORTNO) {
1327 		mutex_exit(&vminor->lock);
1328 		return (ENOLINK);
1329 	}
1330 	vminor->in_use += 1;
1331 	mutex_exit(&vminor->lock);
1332 
1333 	vport = &(vldcp->port[portno]);
1334 
1335 	D1("vldc_ioctl: vldc@%d:%lu cmd=0x%x\n", instance, portno, cmd);
1336 
1337 	switch (cmd) {
1338 
1339 	case VLDC_IOCTL_OPT_OP:
1340 
1341 		rv = i_vldc_ioctl_opt_op(vport, vldcp, (void *)arg,  mode);
1342 		break;
1343 
1344 	case VLDC_IOCTL_READ_COOKIE:
1345 		if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) {
1346 			rv = EINVAL;
1347 			break;
1348 		}
1349 		rv = i_vldc_ioctl_read_cookie(vport, instance,
1350 		    (void *)arg, mode);
1351 		break;
1352 
1353 	case VLDC_IOCTL_WRITE_COOKIE:
1354 		if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) {
1355 			rv = EINVAL;
1356 			break;
1357 		}
1358 		rv = i_vldc_ioctl_write_cookie(vport, instance,
1359 		    (void *)arg, mode);
1360 		break;
1361 
1362 	default:
1363 
1364 		DWARN("vldc_ioctl: vldc@%d:%lu unknown cmd=0x%x\n",
1365 		    instance, portno, cmd);
1366 		rv = EINVAL;
1367 		break;
1368 	}
1369 
1370 	mutex_enter(&vminor->lock);
1371 	vminor->in_use -= 1;
1372 	if (vminor->in_use == 0) {
1373 		cv_signal(&vminor->cv);
1374 	}
1375 	mutex_exit(&vminor->lock);
1376 
1377 	D1("vldc_ioctl: rv=%d\n", rv);
1378 
1379 	return (rv);
1380 }
1381 
1382 /* cb_read */
1383 static int
1384 vldc_read(dev_t dev, struct uio *uiop, cred_t *credp)
1385 {
1386 	_NOTE(ARGUNUSED(credp))
1387 
1388 	int instance;
1389 	minor_t minor;
1390 	size_t size = 0;
1391 	uint64_t portno;
1392 	vldc_t *vldcp;
1393 	vldc_port_t *vport;
1394 	vldc_minor_t *vminor;
1395 	int rv = 0;
1396 
1397 	minor = getminor(dev);
1398 	instance = VLDCINST(minor);
1399 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
1400 	if (vldcp == NULL) {
1401 		return (ENXIO);
1402 	}
1403 
1404 	vminor = VLDCMINOR(vldcp, minor);
1405 	mutex_enter(&vminor->lock);
1406 	portno = vminor->portno;
1407 	if (portno == VLDC_INVALID_PORTNO) {
1408 		mutex_exit(&vminor->lock);
1409 		return (ENOLINK);
1410 	}
1411 
1412 	D2("vldc_read: vldc@%d:%lu reading data\n", instance, portno);
1413 
1414 	vport = &(vldcp->port[portno]);
1415 
1416 	/* check the port status */
1417 	if (vport->status != VLDC_PORT_READY) {
1418 		DWARN("vldc_read: vldc@%d:%lu not in the ready state\n",
1419 		    instance, portno);
1420 		mutex_exit(&vminor->lock);
1421 		return (ENOTACTIVE);
1422 	}
1423 
1424 	/* read data */
1425 	size = MIN(vport->mtu, uiop->uio_resid);
1426 	rv = ldc_read(vport->ldc_handle, vport->recv_buf, &size);
1427 
1428 	D2("vldc_read: vldc@%d:%lu ldc_read size=%ld, rv=%d\n",
1429 	    instance, portno, size, rv);
1430 
1431 	if (rv == 0) {
1432 		if (size != 0) {
1433 			rv = uiomove(vport->recv_buf, size, UIO_READ, uiop);
1434 		} else {
1435 			rv = EWOULDBLOCK;
1436 		}
1437 	} else {
1438 		switch (rv) {
1439 		case ENOBUFS:
1440 			break;
1441 		case ETIMEDOUT:
1442 		case EWOULDBLOCK:
1443 			rv = EWOULDBLOCK;
1444 			break;
1445 		default:
1446 			rv = ECONNRESET;
1447 			break;
1448 		}
1449 	}
1450 
1451 	mutex_exit(&vminor->lock);
1452 
1453 	return (rv);
1454 }
1455 
1456 /* cb_write */
1457 static int
1458 vldc_write(dev_t dev, struct uio *uiop, cred_t *credp)
1459 {
1460 	_NOTE(ARGUNUSED(credp))
1461 
1462 	int instance;
1463 	minor_t minor;
1464 	size_t size;
1465 	size_t orig_size;
1466 	uint64_t portno;
1467 	vldc_t *vldcp;
1468 	vldc_port_t *vport;
1469 	vldc_minor_t *vminor;
1470 	int rv = EINVAL;
1471 
1472 	minor = getminor(dev);
1473 	instance = VLDCINST(minor);
1474 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
1475 	if (vldcp == NULL) {
1476 		return (ENXIO);
1477 	}
1478 
1479 	vminor = VLDCMINOR(vldcp, minor);
1480 	mutex_enter(&vminor->lock);
1481 	portno = vminor->portno;
1482 	if (portno == VLDC_INVALID_PORTNO) {
1483 		mutex_exit(&vminor->lock);
1484 		return (ENOLINK);
1485 	}
1486 
1487 	vport = &(vldcp->port[portno]);
1488 
1489 	/* check the port status */
1490 	if (vport->status != VLDC_PORT_READY) {
1491 		DWARN("vldc_write: vldc@%d:%lu not in the ready state\n",
1492 		    instance, portno);
1493 		mutex_exit(&vminor->lock);
1494 		return (ENOTACTIVE);
1495 	}
1496 
1497 	orig_size = uiop->uio_resid;
1498 	size = orig_size;
1499 
1500 	if (size > vport->mtu) {
1501 		if (vport->is_stream) {
1502 			/* can only send MTU size at a time */
1503 			size = vport->mtu;
1504 		} else {
1505 			mutex_exit(&vminor->lock);
1506 			return (EMSGSIZE);
1507 		}
1508 	}
1509 
1510 	D2("vldc_write: vldc@%d:%lu writing %lu bytes\n", instance, portno,
1511 	    size);
1512 
1513 	rv = uiomove(vport->send_buf, size, UIO_WRITE, uiop);
1514 	if (rv == 0) {
1515 		rv = ldc_write(vport->ldc_handle, (caddr_t)vport->send_buf,
1516 		    &size);
1517 		if (rv != 0) {
1518 			DWARN("vldc_write: vldc@%d:%lu failed writing %lu "
1519 			    "bytes rv=%d\n", instance, portno, size, rv);
1520 		}
1521 	} else {
1522 		size = 0;
1523 	}
1524 
1525 	mutex_exit(&vminor->lock);
1526 
1527 	/* resid is total number of bytes *not* sent */
1528 	uiop->uio_resid = orig_size - size;
1529 
1530 	return (rv);
1531 }
1532 
1533 /* cb_chpoll */
1534 static int
1535 vldc_chpoll(dev_t dev, short events, int anyyet,  short *reventsp,
1536     struct pollhead **phpp)
1537 {
1538 	int instance;
1539 	minor_t minor;
1540 	uint64_t portno;
1541 	vldc_t *vldcp;
1542 	vldc_port_t *vport;
1543 	vldc_minor_t *vminor;
1544 	ldc_status_t ldc_state;
1545 	boolean_t haspkts;
1546 	int rv;
1547 
1548 	minor = getminor(dev);
1549 	instance = VLDCINST(minor);
1550 	vldcp = ddi_get_soft_state(vldc_ssp, instance);
1551 	if (vldcp == NULL) {
1552 		return (ENXIO);
1553 	}
1554 
1555 	vminor = VLDCMINOR(vldcp, minor);
1556 	mutex_enter(&vminor->lock);
1557 	portno = vminor->portno;
1558 	if (portno == VLDC_INVALID_PORTNO) {
1559 		mutex_exit(&vminor->lock);
1560 		return (ENOLINK);
1561 	}
1562 
1563 	vport = &(vldcp->port[portno]);
1564 
1565 	/* check the port status */
1566 	if (vport->status != VLDC_PORT_READY) {
1567 		mutex_exit(&vminor->lock);
1568 		return (ENOTACTIVE);
1569 	}
1570 
1571 	D2("vldc_chpoll: vldc@%d:%lu polling events 0x%x\n",
1572 	    instance, portno, events);
1573 
1574 	rv = ldc_status(vport->ldc_handle, &ldc_state);
1575 	if (rv != 0) {
1576 		DWARN("vldc_chpoll: vldc@%d:%lu could not get ldc status, "
1577 		    "rv=%d\n", instance, portno, rv);
1578 		mutex_exit(&vminor->lock);
1579 		return (EBADFD);
1580 	}
1581 
1582 	*reventsp = 0;
1583 
1584 	if (ldc_state == LDC_UP) {
1585 		/*
1586 		 * Check if the receive queue is empty and if not, signal that
1587 		 * there is data ready to read.
1588 		 */
1589 		if (events & POLLIN) {
1590 			if ((ldc_chkq(vport->ldc_handle, &haspkts) == 0) &&
1591 			    haspkts) {
1592 				*reventsp |= POLLIN;
1593 			}
1594 		}
1595 
1596 		if (events & POLLOUT)
1597 			*reventsp |= POLLOUT;
1598 
1599 	} else if (vport->hanged_up) {
1600 		*reventsp |= POLLHUP;
1601 		vport->hanged_up = B_FALSE;
1602 	}
1603 
1604 	mutex_exit(&vminor->lock);
1605 
1606 	if (((*reventsp) == 0) && (!anyyet)) {
1607 		*phpp = &vport->poll;
1608 	}
1609 
1610 	D2("vldc_chpoll: vldc@%d:%lu ev=0x%x, rev=0x%x\n",
1611 	    instance, portno, events, *reventsp);
1612 
1613 	return (0);
1614 }
1615