vldc.c revision 3af08d828975d7e2581b6829e0eecff14d87a483
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER START
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The contents of this file are subject to the terms of the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Common Development and Distribution License (the "License").
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You may not use this file except in compliance with the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * See the License for the specific language governing permissions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and limitations under the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * When distributing Covered Code, include this CDDL HEADER in each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If applicable, add the following below this CDDL HEADER, with the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * fields enclosed by brackets "[]" replaced with your own identifying
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * information: Portions Copyright [yyyy] [name of copyright owner]
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER END
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Use is subject to license terms.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#pragma ident "%Z%%M% %I% %E% SMI"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Function prototypes.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* DDI entrypoints */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_close(dev_t dev, int flag, int otyp, cred_t *cred);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_read(dev_t dev, struct uio *uiop, cred_t *credp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_write(dev_t dev, struct uio *uiop, cred_t *credp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vldc_chpoll(dev_t dev, short events, int anyyet,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Internal functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_vldc_remove_port(vldc_t *vldcp, uint_t portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_vldc_close_port(vldc_t *vldcp, uint_t portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* soft state structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void *vldc_ssp;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Matching criteria passed to the MDEG to register interest
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in changes to 'virtual-device-port' nodes identified by their
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 'id' property.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic mdeg_node_match_t vport_match = { "virtual-device-port",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Specification of an MD node passed to the MDEG to filter any
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 'virtual-device-port' nodes that do not belong to the specified
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * node. This template is copied for each vldc instance and filled
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in with the appropriate 'name' and 'cfg-handle' values before
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * being passed to the MDEG.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define VLDC_SET_MDEG_PROP_NAME(specp, name) ((specp)[0].ps_str = (name))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define VLDC_SET_MDEG_PROP_INST(specp, inst) ((specp)[1].ps_val = (inst))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo 0, /* ref count */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "sun4v Virtual LDC Driver %I%", /* Name of the module */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* maximum MTU and cookie size tunables */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Print debug messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * set vldcdbg to 0x7 to enable all messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x4 - Warnings
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x2 - All debug messages (most verbose)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x1 - Minimal debug messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#else /* not DEBUG */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* not DEBUG */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* _init(9E): initialize the loadable module */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* init the soft state structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo error = ddi_soft_state_init(&vldc_ssp, sizeof (vldc_t), 1);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (error != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Link the driver into the system */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* _info(9E): return information about the loadable module */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Report status of the dynamically loadable driver module */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* _fini(9E): prepare the module for unloading. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Unlink the driver module from the system */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * We have successfully "removed" the driver.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * destroy soft state
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* ldc callback */
3af08d828975d7e2581b6829e0eecff14d87a483lm D1("i_vldc_cb: vldc@%d:%d callback invoked, channel=0x%lx, "
3af08d828975d7e2581b6829e0eecff14d87a483lm "event=0x%lx\n", vport->inst, vport->number, vport->ldc_id, event);
3af08d828975d7e2581b6829e0eecff14d87a483lm * Mark the port in reset. This implies that it
3af08d828975d7e2581b6829e0eecff14d87a483lm * cannot be used until it has been closed and
3af08d828975d7e2581b6829e0eecff14d87a483lm * reopened.
3af08d828975d7e2581b6829e0eecff14d87a483lm * The other side went away
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* mdeg callback */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_mdeg_cb: added=%d, removed=%d, matched=%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process added ports */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_mdeg_cb: processing added node 0x%lx\n", node);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* attempt to add a port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((rv = i_vldc_add_port(vldcp, mdp, node)) != MDEG_SUCCESS) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to add port, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process removed ports */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_mdeg_cb: processing removed node 0x%lx\n", node);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read in the port's id property */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* attempt to remove a port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Currently no support for updating already active ports. So, ignore
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the match_curr and match_prev arrays for now.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* register callback to mdeg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the unique vldc instance assigned by the LDom manager */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the name of the vldc instance */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Allocate and initialize a per-instance copy
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * of the global property spec array that will
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * uniquely identify this vldc instance.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* copy in the name property */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* copy in the instance property */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the complete prop spec structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* perform the registration */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save off data that will be needed later */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* unregister callback from mdeg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_mdeg_unregister: hdl=0x%lx\n", vldcp->mdeg_hdl);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Clean up cached MDEG data
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kmem_free(vldcp->inst_spec->specp, sizeof (vldc_prop_template));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kmem_free(vldcp->inst_spec, sizeof (mdeg_node_spec_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Find the channel-endpoint node(s) (which should be under this
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * port node) which contain the channel id(s).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (-1);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate space for node list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (nchan <= 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " nodes found");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (-1);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* use property from first node found */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "has no 'id' property");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (-1);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* add a vldc port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read in the port's id property */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_add_port: node 0x%lx of added "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_add_port: found port number (%lu) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "larger than maximum supported number of ports", portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get all channels for this device (currently only one) */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (i_vldc_get_port_channel(mdp, node, &vport->ldc_id) == -1) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the default MTU */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the service being exported by this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (md_get_prop_str(mdp, node, "vldc-svc-name", &sname)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "'vldc-svc-name' property");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* minor number look up */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (minor_idx = 0; minor_idx < vldcp->minors_assigned;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (strcmp(vldcp->minor_tbl[minor_idx].sname, sname) == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* found previously assigned minor number */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* end of lookup - assign new minor number */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ASSERT(vldcp->minor_tbl[minor_idx].portno == VLDC_INVALID_PORTNO);
3af08d828975d7e2581b6829e0eecff14d87a483lm D1("i_vldc_add_port: vldc@%d:%d mtu=%d, ldc=%ld, service=%s\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm vport->inst, vport->number, vport->mtu, vport->ldc_id, sname);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Create a minor node. The minor number is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * (vldc_inst << VLDC_INST_SHIFT) | minor_idx
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ddi_create_minor_node(vldcp->dip, sname, S_IFCHR,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_add_port: failed to create minor"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo vldcp->minor_tbl[minor_idx].portno = VLDC_INVALID_PORTNO;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The port is now bound to a minor node and is initially in the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * closed state.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_add_port: port %lu initialized\n", portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* remove a vldc port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_NOTE, "?i_vldc_remove_port: trying to remove a "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Make sure that all new attempts to open or use the minor node
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * associated with the port will fail.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send hangup to anyone polling */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Now wait for all current users of the minor node to finish. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* close the port before it is torn down */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* remove minor node */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ddi_remove_minor_node(vldcp->dip, vport->minorp->sname);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("i_vldc_remove_port: removed vldc port %u\n", portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* close a ldc channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* close a vldc port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* nothing to do */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free memory */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * attach(9E): attach a device to the system.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * called once for each instance of the device on the system.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo switch (cmd) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ddi_soft_state_zalloc(vldc_ssp, instance) != DDI_SUCCESS) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_attach: DDI_ATTACH instance=%d\n", instance);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < VLDC_MAX_PORTS; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* No minor node association to start with */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < VLDC_MAX_MINORS; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* No port association to start with */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Register for MD update notification */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * detach(9E): detach a device from the system.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo switch (cmd) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_detach: DDI_DETACH instance=%d\n", instance);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Fail the detach if all ports have not been removed. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < VLDC_MAX_MINORS; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "detach failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Prevent MDEG from adding new ports before the callback can
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * be unregistered. The lock can't be held accross the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * unregistration call because a callback may be in progress
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and blocked on the lock.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Tear down all bound ports and free resources. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < VLDC_MAX_MINORS; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_open */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovldc_open(dev_t *devp, int flag, int otyp, cred_t *cred)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_open: opening vldc@%d:%lu\n", instance, portno);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vport->cookie_buf = kmem_alloc(vldc_max_cookie, KM_SLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_close */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovldc_close(dev_t dev, int flag, int otyp, cred_t *cred)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_close: closing vldc@%d:%lu\n", instance, portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovldc_set_ldc_mode(vldc_port_t *vport, vldc_t *vldcp, int channel_mode)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate mode */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_ioctl_opt_op: ldc_init failed, rv=%d\n", rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* register it */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_ioctl_opt_op: ldc_reg_callback failed, rv=%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* open the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_ioctl_opt_op: ldc_open failed, rv=%d\n", rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Attempt to bring the channel up, but do not
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * fail if the other end is not up yet.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_ioctl_opt_op: remote endpoint not up yet\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } else if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_ioctl_opt_op: ldc_up failed, rv=%d\n", rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_ioctl_opt_op: ldc %ld initialized successfully\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* ioctl to read cookie */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_vldc_ioctl_read_cookie(vldc_port_t *vport, int vldc_instance, void *arg,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) == -1) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan while (balance > 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* get the max amount to the copied */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan D2("i_vldc_ioctl_read_cookie: vldc@%d:%d reading from 0x%p "
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "size 0x%lx to 0x%p\n", vldc_instance, vport->number,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* read from the HV into the temporary buffer */
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (rv != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan DWARN("i_vldc_ioctl_read_cookie: vldc@%d:%d cannot "
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "read address 0x%p, rv=%d\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan D2("i_vldc_ioctl_read_cookie: vldc@%d:%d read succeeded\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * copy data from temporary buffer out to the
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * caller and free buffer
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan rv = ddi_copyout(vport->cookie_buf, src_addr, copy_size, mode);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (rv != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* adjust len, source and dest */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the structure to reflect outcome */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ddi_copyout(©_info, arg, sizeof (copy_info), mode) != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* ioctl to write cookie */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_vldc_ioctl_write_cookie(vldc_port_t *vport, int vldc_instance, void *arg,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2("i_vldc_ioctl_write_cookie: vldc@%d:%d writing 0x%lx size 0x%lx "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "to 0x%lx\n", vldc_instance, vport->number, copy_info.src_addr,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan while (balance > 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* get the max amount to the copied */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * copy into the temporary buffer the data
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * to be written to the HV
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (ddi_copyin((caddr_t)src_addr, vport->cookie_buf,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* write the data from the temporary buffer to the HV */
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (rv != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "failed to write at address 0x%p\n, rv=%d",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan D2("i_vldc_ioctl_write_cookie: vldc@%d:%d write succeeded\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* adjust len, source and dest */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the structure to reflect outcome */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vldc specific ioctl option commands */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_vldc_ioctl_opt_op(vldc_port_t *vport, vldc_t *vldcp, void *arg, int mode)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ddi_copyin(arg, &vldc_cmd, sizeof (vldc_cmd), mode) != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The port has buffers allocated since it is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * not closed plus the MTU size has changed.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Reallocate the buffers to the new MTU size.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vldc_set_ldc_mode(vport, vldcp, vldc_cmd.opt_val);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_ioctl_opt_op: unsupported op %d\n", vldc_cmd.opt_sel);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_ioctl */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1("vldc_ioctl: vldc@%d:%lu cmd=0x%x\n", instance, portno, cmd);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo switch (cmd) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = i_vldc_ioctl_opt_op(vport, vldcp, (void *)arg, mode);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_read */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2("vldc_read: vldc@%d:%lu reading data\n", instance, portno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check the port status */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_read: vldc@%d:%lu not in the ready state\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read data */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_read(vport->ldc_handle, vport->recv_buf, &size);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2("vldc_read: vldc@%d:%lu ldc_read size=%ld, rv=%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (size != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo switch (rv) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_write */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check the port status */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_write: vldc@%d:%lu not in the ready state\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* can only send MTU size at a time */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2("vldc_write: vldc@%d:%lu writing %lu bytes\n", instance, portno,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_write(vport->ldc_handle, (caddr_t)vport->send_buf,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* resid is total number of bytes *not* sent */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* cb_chpoll */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovldc_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check the port status */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN("vldc_chpoll: vldc@%d:%lu could not get ldc status, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check if the receive queue is empty and if not, signal that
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * there is data ready to read.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);