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