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