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