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