vnet_gen.c revision a8ea4ede2107d9ad3895b91946b9f33a83c5f7ee
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 * Implementation of the mac functionality for vnet using the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Function prototypes.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen proxy entry points */
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebint vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic int vgen_stat(void *arg, uint_t stat, uint64_t *val);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* externs - functions provided by vnet to add/remove/modify entries in fdb */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovoid vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
3af08d828975d7e2581b6829e0eecff14d87a483lmvoid vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovoid vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebvoid vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen internal functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen handshake functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanstatic int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic uint64_t vgen_macaddr_strtoul(const uint8_t *macaddr);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * being the pre-handshake phase and VH_DONE is the phase to indicate
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * successful completion of all phases.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Each phase may have one to several handshake states which are required
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to complete successfully to move to the next phase.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * more details.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* handshake phases */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoenum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* handshake states */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * MIB II broadcast/multicast packets
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Property names
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic char rmacaddr_propname[] = "remote-mac-address";
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* versions supported - in decreasing order */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} };
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Tunables */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppouint32_t vgen_hwd_interval = 1000; /* handshake watchdog freq in msec */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppouint32_t vgen_max_hretries = 1; /* max # of handshake retries */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppouint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */
8e6a2a040587479821d1e682a28bcef7e75f19a6lmuint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanuint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanuint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* flags to simulate error conditions for debugging */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* MD update matching structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic mdeg_node_match_t vport_match = { "virtual-device-port",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* template for matching a particular vnet instance */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* externs */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoextern void _vnetdebug_printf(void *vnetp, const char *fmt, ...);
3af08d828975d7e2581b6829e0eecff14d87a483lm * NOTE: definitions below need to be in sync with those in vnet.c
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * debug levels:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * DBG_LEVEL1: Function entry/exit tracing
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * DBG_LEVEL2: Info messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * DBG_LEVEL3: Warning messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * DBG_LEVEL4: Error messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoenum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* simulate handshake error conditions for debug */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_init() is called by an instance of vnet driver to initialize the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * corresponding generic proxy transport layer. The arguments passed by vnet
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * the mac address of the vnet device, and a pointer to mac_register_t of
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * the generic transport is returned in the last argument.
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebvgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate multicast table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* register with MD event generator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo sizeof (struct ether_addr));
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb /* register macp of this vgen_t with vnet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Called by vnet to undo the initializations done by vgen_init().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The handle provided by generic transport during vgen_init() is the argument.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* unregister with MD event generator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* detach all ports from the device */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * free any pending rx mblk pools,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * that couldn't be freed previously during channel detach.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free multicast table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable transmit/receive for the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen transmit function */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* success */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* transmit packets over the given port */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * NOTE: for now, we will assume we have a single channel.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* out of tx resources, see vgen_ldcsend() for details. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* channel transmit function */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id));
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* drop the packet if ldc is not up or handshake is not done */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* retry ldc_up() if needed */
8e6a2a040587479821d1e682a28bcef7e75f19a6lm "vgen_ldcsend: id(%lx) hphase(%x), dropping packet\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * allocate a descriptor
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* copy data into pre-allocated transmit buffer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the corresponding public descriptor (txd) */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send dring datamsg to the peer */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan rv = vgen_send_dring_data(ldcp, (uint32_t)tbuf_ix, -1);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (rv != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* vgen_send_dring_data() error: drop the packet */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "vgen_ldcsend: vgen_send_dring_data(): failed: "
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "id(%lx) rv(%d) len (%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* update next available tbuf in the ring */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* update tx index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* update stats */
3af08d828975d7e2581b6829e0eecff14d87a483lm * Check if either callback thread or another tx thread is
3af08d828975d7e2581b6829e0eecff14d87a483lm * already running. Calling mutex_enter() will result in a
3af08d828975d7e2581b6829e0eecff14d87a483lm * deadlock if the other thread already holds cblock and is
3af08d828975d7e2581b6829e0eecff14d87a483lm * blocked in vnet_modify_fdb() (which is called from
3af08d828975d7e2581b6829e0eecff14d87a483lm * vgen_handle_evt_reset()) waiting for write access on rwlock,
3af08d828975d7e2581b6829e0eecff14d87a483lm * as this transmit thread already holds that lock as a reader
3af08d828975d7e2581b6829e0eecff14d87a483lm * in vnet_m_tx(). See comments in vnet_modify_fdb() in vnet.c.
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldcsend: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm * Second arg is TRUE, as we know that
3af08d828975d7e2581b6829e0eecff14d87a483lm * the caller of this function - vnet_m_tx(),
3af08d828975d7e2581b6829e0eecff14d87a483lm * already holds fdb-rwlock as a reader.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable/disable a multicast address */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If handshake is done, send a msg to vsw to add/remove
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the multicast address.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the flag to send a msg to vsw after handshake is done */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* expand multicast table if necessary */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo sizeof (struct ether_addr));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* add address to the table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* delete address from the table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If there's more than one address in this
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * table, delete the unwanted one by moving
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the last one in the list over top of it;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * otherwise, just remove it.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* set or clear promiscuous mode on the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* set the unicast mac address of the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* get device statistics */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen internal functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* detach all ports from the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * detach the given port.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_port_detach: enter: port_num(%d)\n", port_num));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* remove it from port list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* detach channels from this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* add a port to port list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* remove a port from port list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) &&
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* lookup a port in the list based on port_num */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_port_lookup(vgen_portlist_t *plistp, int port_num)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable ports for transmit/receive */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Create fdb entry in vnet, corresponding to the mac
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * address of this port. Note that the port specified
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * is vsw-port. This is done so that vsw-port acts
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * as the route to reach this macaddr, until the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channel for this port comes up (LDC_UP) and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * handshake is done successfully.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * eg, if the peer is OBP-vnet, it may not bring the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channel up for this port and may communicate via
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vsw to reach this port.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Later, when Solaris-vnet comes up at the other end
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * of the channel for this port and brings up the channel,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * it is an indication that peer vnet is capable of
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * distributed switching, so the direct route through this
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * port is specified in fdb, using vnet_modify_fdb(macaddr);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * create the default route entry in vnet's fdb.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This is the entry used by vnet to reach
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * unknown destinations, which basically goes
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * through vsw on domain0 and out through the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * physical device bound to vsw.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Bring up the channels of this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* disable transmit/receive on ports */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* delete the entry in vnet's fdb for this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if this is vsw-port, then delete the default
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * route entry in vnet's fdb.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* register with MD event generator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (i == -1) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * NOTE: The instance here refers to the value of "reg" property and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * not the dev_info instance (ddi_get_instance()) of vnet.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save parentp in vgen_t */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n"));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save mdeg handle in vgen_t */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* unregister with MD event generator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* callback function registered with MD event generator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * find vsw_port and add it first, because other ports need
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * this when adding fdb entry (see vgen_port_init()).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (val == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This port is connected to the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vsw on dom0.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "can't find vsw_port\n"));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* add a new port to the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read "id" property to get the port number */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Find the channel endpoint node(s) under this port node.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_add_port: invalid number of nodes found (%d)",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate space for node list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_add_port: can't find %s nodes", channel_propname));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < num_ldcs; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read channel ids */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_add_port: prop(%s) not found\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_add_port: prop(%s) not found\n", rmacaddr_propname));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_add_port: invalid address size (%d)\n", addrsz));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (val == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* This port is connected to the vsw on dom0 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* remove a port from the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* read "id" property to get the port number */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_remove_port: prop(%s) not found\n", id_propname));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* attach a port to the device based on mdeg data */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < num_ids; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* link it into the list of ports */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* This port is connected to the vsw on domain0 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vgenp->flags & VGEN_STARTED) { /* interface is configured */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* detach a port from the device based on mdeg data */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* stop the port if needed */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex))
3af08d828975d7e2581b6829e0eecff14d87a483lm /* NOTE: TBD */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* attach the channel corresponding to the given ldc_id to the port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_reg_callback failed, id (%lx) rv (%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate transmit resources */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* allocate receive resources */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan status = vio_create_mblks(ldcp->num_rbufs, VGEN_DBLK_SZ,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Setup kstats for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize vgen_versions supported */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* link it into the list of channels for this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* detach a channel from the port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* invalid ldcp? */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* free receive resources */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * if we cannot reclaim all mblks, put this
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * on the list of pools to be reclaimed when the
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * device gets detached (see vgen_uninit()).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free transmit resources */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* unlink it from the list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This function allocates transmit resources for the channel.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The resources consist of a transmit descriptor ring and an associated
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * transmit buffer ring.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate transmit buffer ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* create transmit descriptor ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the addr of descripror ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Free transmit resources for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free transmit descriptor ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free transmit buffer ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable transmit/receive on the channels for the port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* stop transmit/receive on the channels for the port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable transmit/receive on the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
7636cb21f250f0485ca6052ffadc80ace93e6358lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm DWARN((vnetp, "vgen_ldc_init: ldc_set_cb_mode failed: id(%lx) "
8e6a2a040587479821d1e682a28bcef7e75f19a6lm "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm DWARN((vnetp, "vgen_ldc_init: id(%lx) status(%d) is UP\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize transmit watchdog timeout */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if channel is already UP - start handshake */
3af08d828975d7e2581b6829e0eecff14d87a483lm * modify fdb entry to use this port as the
3af08d828975d7e2581b6829e0eecff14d87a483lm * channel is up, instead of going through the
3af08d828975d7e2581b6829e0eecff14d87a483lm * vsw-port (see comments in vgen_port_init())
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initialize local session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* clear peer session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initiate Handshake process with peer ldc endpoint */
7636cb21f250f0485ca6052ffadc80ace93e6358lm (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* stop transmit/receive on the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* disable further callbacks */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* clear handshake done bit and wait for pending tx and cb to finish */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset transmit watchdog timeout */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Initialize the transmit buffer ring for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP);
8e6a2a040587479821d1e682a28bcef7e75f19a6lm * for each private descriptor, allocate a ldc mem_handle which is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * required to map the data during transmit, set the flags
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to free (available for use by transmit routine).
8e6a2a040587479821d1e682a28bcef7e75f19a6lm * bind ldc memhandle to the corresponding transmit buffer.
8e6a2a040587479821d1e682a28bcef7e75f19a6lm if (rv != 0) {
8e6a2a040587479821d1e682a28bcef7e75f19a6lm * successful in binding the handle to tx data buffer.
8e6a2a040587479821d1e682a28bcef7e75f19a6lm * set datap in the private descr to this buffer.
8e6a2a040587479821d1e682a28bcef7e75f19a6lm if ((ncookies == 0) ||
8e6a2a040587479821d1e682a28bcef7e75f19a6lm if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset tbuf walking pointers */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize tx seqnum and index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Uninitialize transmit buffer ring for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* for each tbuf (priv_desc), free ldc mem_handle */
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* prealloc'd tx data buffer */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ);
7636cb21f250f0485ca6052ffadc80ace93e6358lm bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds));
7636cb21f250f0485ca6052ffadc80ace93e6358lm bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* clobber tx descriptor ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset tbuf walking pointers */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset tx seqnum and index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* clobber receive descriptor ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* initialize receive descriptor ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * sucessfully mapped, now try to
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * get info about the mapped dring
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * save ring address, number of descriptors.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* get channel statistics */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* stats not relevant to ldc, return 0 */
3af08d828975d7e2581b6829e0eecff14d87a483lm * LDC channel is UP, start handshake process with peer.
3af08d828975d7e2581b6829e0eecff14d87a483lm * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
3af08d828975d7e2581b6829e0eecff14d87a483lm * function is being called from transmit routine, otherwise B_FALSE.
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void
3af08d828975d7e2581b6829e0eecff14d87a483lm DBG1((vnetp, "vgen_handle_evt_up: enter: id(%lx)\n", ldcp->ldc_id));
3af08d828975d7e2581b6829e0eecff14d87a483lm * modify fdb entry to use this port as the
3af08d828975d7e2581b6829e0eecff14d87a483lm * channel is up, instead of going through the
3af08d828975d7e2581b6829e0eecff14d87a483lm * vsw-port (see comments in vgen_port_init())
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initialize local session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* clear peer session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initiate Handshake process with peer ldc endpoint */
3af08d828975d7e2581b6829e0eecff14d87a483lm DBG1((vnetp, "vgen_handle_evt_up: exit: id(%lx)\n", ldcp->ldc_id));
3af08d828975d7e2581b6829e0eecff14d87a483lm * LDC channel is Reset, terminate connection with peer and try to
3af08d828975d7e2581b6829e0eecff14d87a483lm * bring the channel up again.
3af08d828975d7e2581b6829e0eecff14d87a483lm * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
3af08d828975d7e2581b6829e0eecff14d87a483lm * function is being called from transmit routine, otherwise B_FALSE.
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void
3af08d828975d7e2581b6829e0eecff14d87a483lm DBG1((vnetp, "vgen_handle_evt_reset: enter: id(%lx)\n", ldcp->ldc_id));
3af08d828975d7e2581b6829e0eecff14d87a483lm * modify fdb entry to use vsw-port as the
3af08d828975d7e2581b6829e0eecff14d87a483lm * channel is reset and we don't have a direct
3af08d828975d7e2581b6829e0eecff14d87a483lm * link to the destination (see comments
3af08d828975d7e2581b6829e0eecff14d87a483lm * in vgen_port_init()).
3af08d828975d7e2581b6829e0eecff14d87a483lm /* try to bring the channel up */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_handle_evt_reset: ldc_up err id(%lx) rv(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_handle_evt_reset: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if channel is already UP - restart handshake */
3af08d828975d7e2581b6829e0eecff14d87a483lm DBG1((vnetp, "vgen_handle_evt_reset: exit: id(%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Interrupt handler for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm * NOTE: not using switch() as event could be triggered by
3af08d828975d7e2581b6829e0eecff14d87a483lm * a state change and a read request. Also the ordering of the
3af08d828975d7e2581b6829e0eecff14d87a483lm * check for the event types is deliberate.
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: id(%lx) event(%lx) UP, status(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: id(%lx) event(%lx) READ, status(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: id(%lx) event(%lx) RESET/DOWN, status(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if event is LDC_EVT_READ, receive all packets */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (msglen == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * check sid only after we have received peer's sid
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in the version negotiate msg.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* simulate bad sid condition */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If sid mismatch is detected,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * reset the channel.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* build a chain of received packets */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_ldc_cb: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm } else if (rv) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send up the received packets to MAC layer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen handshake functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* change the hphase for the channel to the next phase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check whether the given version is supported or not and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * return VGEN_SUCCESS if supported.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo while (i < VGEN_NUM_VER) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Given a version, return VGEN_SUCCESS if a lower version is supported.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo while (i < VGEN_NUM_VER) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if we support a lower minor version within the same major
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * version, or if we support a lower major version,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * update the verp parameter with this lower version and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * return success.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * wrapper routine to send the given message over ldc using ldc_write().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen,
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* send version negotiate message to the peer over ldc */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get version msg payload from ldcp->local */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* send attr info message to the peer over ldc */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get attr msg payload from ldcp->local */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* send descriptor ring register message to the peer over ldc */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get dring info msg payload from ldcp->local */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * dring_ident is set to 0. After mapping the dring, peer sets this
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * value and sends it in the ack, which is saved in
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_handle_dring_reg().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* send descriptor ring data message to the peer over ldc */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* send multicast addr info message to vsw */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err"
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Initiate Phase 2 of handshake */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* simulate out of state condition */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* simulate timeout condition */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Bind descriptor ring to the channel */
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
3af08d828975d7e2581b6829e0eecff14d87a483lm LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_mem_dring_bind failed rv(%x)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
3af08d828975d7e2581b6829e0eecff14d87a483lm /* update local dring_info params */
3af08d828975d7e2581b6829e0eecff14d87a483lm bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
3af08d828975d7e2581b6829e0eecff14d87a483lm ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This can happen after a channel comes up (status: LDC_UP) or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * when handshake gets terminated due to various conditions.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset hstate and hphase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset handshake watchdog timeout */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Unbind tx descriptor ring from the channel */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_reset_hphase: ldc_mem_dring_unbind "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Unmap peer's dring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * clear local handshake params and initialize.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set version to the highest version supported */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set attr_info params */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */
3af08d828975d7e2581b6829e0eecff14d87a483lm * Note: dring is created, but not bound yet.
3af08d828975d7e2581b6829e0eecff14d87a483lm * local dring_info params will be updated when we bind the dring in
3af08d828975d7e2581b6829e0eecff14d87a483lm * vgen_handshake_phase2().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * dring_ident is set to 0. After mapping the dring, peer sets this
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * value and sends it in the ack, which is saved in
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_handle_dring_reg().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* clear peer_hparams */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset the channel if required */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_reset_hphase: id (%lx), Reset Done,ldc_status(%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* clear sids */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* try to bring the channel up */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_reset_hphase: ldc_up err id(%lx) rv(%d)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_reset_hphase: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if channel is already UP - restart handshake */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initialize local session id */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* wrapper function for vgen_reset_hphase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Initiate handshake with the peer by sending various messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * based on the handshake-phase that the channel is currently in.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * start timer, for entire handshake process, turn this timer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * off if all phases of handshake complete successfully and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * hphase goes to VH_DONE(below) or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_reset_hphase() gets called or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channel is reset due to errors or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_ldc_uninit() is invoked(vgen_stop).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Phase 1 involves negotiating the version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset handshake watchdog timeout */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* need to sync multicast table with vsw */
3af08d828975d7e2581b6829e0eecff14d87a483lm * Check if mac layer should be notified to restart
3af08d828975d7e2581b6829e0eecff14d87a483lm * transmissions. This can happen if the channel got
3af08d828975d7e2581b6829e0eecff14d87a483lm * reset and vgen_clobber_tbufs() is called, while
3af08d828975d7e2581b6829e0eecff14d87a483lm * need_resched is set.
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_handshake: ldc_status err id(%lx)\n"));
3af08d828975d7e2581b6829e0eecff14d87a483lm } else if (rv) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check if the current handshake phase has completed successfully and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * return the status.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Phase1 is done, if version negotiation
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * completed successfully.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Phase 2 is done, if attr info and dring info
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * have been exchanged successfully.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Phase 3 is done, if rdx msg has been exchanged */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* retry handshake on failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset handshake phase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vgen_max_hretries) { /* handshake retry is specified */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Handle a version info msg from the peer or an ACK/NACK from the peer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to a version info msg that we sent.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_handle_version_negotiate: enter\n"));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Cache sid of peer if this is the first time */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_version_negotiate: id (%lx) Caching"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If we are not already in VH_PHASE1, reset to
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * pre-handshake state, and initiate handshake
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to the peer too.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save peer's requested values */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* unsupported dev_class, send NACK */
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_handle_version_negotiate: Version"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD,"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* nack with next lower version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* major version match - ACK version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * lower minor version to the one this endpt
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * supports, if necessary
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* no version match - send NACK */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " Version Negotiation Failed id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* VER_ACK_SENT and VER_ACK_RCVD */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* local and peer versions match? */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move to the next phase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* This should not happen. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_version_negotiate:"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* SUCCESS - we have agreed on a version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* VER_ACK_SENT and VER_ACK_RCVD */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* local and peer versions match? */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move to the next phase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* This should not happen. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_version_negotiate:"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if version in NACK is zero */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Version Negotiation has failed.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " Version Negotiation Failed id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* select next lower version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* major version match */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * no version match.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Version Negotiation has failed.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " Version Negotiation Failed id (%lx)\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG1((vnetp, "vgen_handle_version_negotiate: exit\n"));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Check if the attributes are supported */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * currently, we support these attr values:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * mtu of ethernet, addr_type of mac, xfer_mode of
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * ldc shared memory, ack_freq of 0 (data is acked if
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the ack bit is set in the descriptor) and the address should
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * match the address in the port node.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppocmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to an attr info msg that we sent.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save peer's values */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* unsupported attr, send NACK */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* failed */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Check if the dring info msg is ok */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if msg contents are ok */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size <
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the peer to a dring register msg that we sent.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* dring_info can be rcvd in any of the phases after Phase1 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * verified dring info msg to be ok,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * now try to map the remote dring.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* now we can ack the peer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ack == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* failed, send NACK */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save peer's dring_info values */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set dring_ident for the peer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* return the dring_ident in ack msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* local dring is now ready */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save dring_ident acked by peer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Handle a rdx info msg from the peer or an ACK/NACK
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * from the peer to a rdx info msg that we sent.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Handle ACK/NACK from vsw to a set multicast msg that we sent */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* success adding/removing multicast addr */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* multicast remove request failed */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* multicast add request failed */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* delete address from the table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* handler for control messages received from the peer ldc end-point */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* handler for data messages received from the peer ldc end-point */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
3af08d828975d7e2581b6829e0eecff14d87a483lm rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg "
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * received a data msg, which contains the start and end
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * indeces of the descriptors within the rx ring holding data,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the seq_num of data packet corresponding to the start index,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and the dring_ident.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * We can now read the contents of each of these descriptors
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and gather data from it.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate rx start and end indeces */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* drop the message if invalid index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate dring_ident */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* invalid dring_ident, drop the msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* drop this msg to simulate lost pkts for debugging */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* receive start index doesn't match expected index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "next_rxi(%d) != start(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* calculate the number of pkts lost */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sequence number of dring data message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * is less than the next sequence number that
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * is expected:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * drop the message and the corresponding packets.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "dropping pkts, expected rxseq(0x%lx) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "> recvd(0x%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * duplicate/multiple retransmissions from
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * sender?? drop this msg.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sequence number of dring data message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * is greater than the next expected sequence number
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * send a NACK back to the peer to indicate lost
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* indicate the range of lost descriptors */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* dring ident is left unchanged */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: id(%lx) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_sendmsg failed, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * stop further processing until peer
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * retransmits with the right index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * update next_rxseq expected.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#else /* VGEN_REXMIT */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * treat this range of descrs/pkts as dropped
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and set the new expected values for next_rxi
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and next_rxseq. continue(below) to process
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * from the new start index.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* VGEN_REXMIT */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * expected and received seqnums match, but
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the descriptor indeces don't?
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * restart handshake with peer.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: id(%lx) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* expected and start dring indeces match */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* seqnums don't match */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: id(%lx) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* VGEN_HANDLE_LOST_PKTS */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * start processing the descriptors from the specified
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * start index, up to the index a descriptor is not ready
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * to be processed or we process the entire descriptor ring
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and wrap around upto the start index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* need to set the start index of descriptors to be ack'd */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* index upto which we have ack'd */
3af08d828975d7e2581b6829e0eecff14d87a483lmvgen_recv_retry: rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi);
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_mem_dring_acquire() failed"
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * descriptor is not ready.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * retry descriptor acquire, stop processing
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * after max # retries.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * initialize the start index of the range
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * of descriptors to be ack'd.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Try to allocate an mblk from the free pool
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * of recv mblks for the channel.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * If this fails, use allocb().
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * The data buffer returned by
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * allocb(9F) is 8byte aligned. We
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * allocate extra 8 bytes to ensure
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * size is multiple of 8 bytes for
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ldc_mem_copy().
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * rxd_err or allocb() failure,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * drop this packet, get next.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set descriptor done bit */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_mem_dring_release err id(%lx)"
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sender needs ack for this packet,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ack pkts upto this index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* need to set new ack start index */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if ldc_mem_copy() failed */
3af08d828975d7e2581b6829e0eecff14d87a483lm "vgen_handle_dring_data: ldc_mem_copy err "
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_mem_dring_release err id(%lx)"
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sender needs ack for this packet,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ack pkts upto this index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* need to set new ack start index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: id(%lx) "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* point to the actual end of data */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* update stats */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* build a chain of received packets */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* first pkt */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* update end index of range of descrs to be ack'd */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* update the next index to be processed */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * processed the entire descriptor ring upto
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * the index at which we started.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } while (1);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * send an ack message to peer indicating that we have stopped
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * processing descriptors.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * We have ack'd upto some index and we have not
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * processed any descriptors beyond that index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Use the last ack'd index as both the start and
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * end of range of descrs being ack'd.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Note: This results in acking the last index twice
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and should be harmless.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* save new recv index and expected seqnum of next dring msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * received an ack corresponding to a specific descriptor for
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * which we had set the ACK bit in the descriptor (during
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * transmit). This enables us to reclaim descriptors.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: ACK: start(%d), end(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate start and end indeces in the tx ack msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* drop the message if invalid index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate dring_ident */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* invalid dring_ident, drop the msg */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* reclaim descriptors that are done */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * receiver continued processing descriptors after
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sending us the ack.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* receiver stopped processing descriptors */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * determine if there are any pending tx descriptors
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ready to be processed by the receiver(peer) and if so,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * send a message to the peer to restart receiving.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * using the end index of the descriptor range for which
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * we received the ack, check if the next descriptor is
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * descr next to the end of ack'd descr range is not
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * starting from the current reclaim index, check
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * if any descriptor is ready.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * we have tx descriptor(s) ready to be
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * processed by the receiver.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * send a message to the peer with the start index
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * of ready descriptors.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * no ready tx descriptors. set the flag to send a
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * message to peer when tx descriptors are ready in
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * transmit routine.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * peer sent a NACK msg to indicate lost packets.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The start and end correspond to the range of descriptors
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * for which the peer didn't receive a dring data msg and so
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * didn't receive the corresponding data.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: NACK: start(%d), end(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate start and end indeces in the tx nack msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* drop the message if invalid index */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* validate dring_ident */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* invalid dring_ident, drop the msg */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* no busy descriptors, bogus nack ? */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send a new dring data msg including the lost descrs */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * vgen_send_dring_data() error: drop all packets
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in this descr range
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_send_dring_data failed :"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* update next pointer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#else /* VGEN_REXMIT */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* we just mark the descrs as done so they can be reclaimed */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* VGEN_REXMIT */
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * transmit reclaim function. starting from the current reclaim index
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * look for descriptors marked DONE and reclaim the descriptor and the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * corresponding buffers (tbuf).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check if mac layer should be notified to restart transmissions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* return the number of pending transmits for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* cur_tbufp > next_tbufp */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (n);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* determine if the transmit descriptor ring is full */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* determine if timeout condition has occured */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* transmit watchdog timeout handler */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* tx timeout triggered for debugging */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* MIB II kstat variables */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Tx stats */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Rx stats */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kstat_named_init(&ldckp->rx_allocb_fail, "rx_allocb_fail",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan kstat_named_init(&ldckp->rx_vio_allocb_fail, "rx_vio_allocb_fail",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kstat_named_init(&ldckp->rx_lost_pkts, "rx_lost_pkts",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Interrupt stats */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo kstat_named_init(&ldckp->dring_data_acks, "dring_data_acks",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan kstat_named_init(&ldckp->dring_stopped_acks, "dring_stopped_acks",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan kstat_named_init(&ldckp->dring_data_msgs, "dring_data_msgs",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldckp->ipackets.value.ul = (uint32_t)statsp->ipackets;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldckp->opackets.value.ul = (uint32_t)statsp->opackets;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * MIB II kstat variables
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldckp->rx_allocb_fail.value.ul = statsp->rx_allocb_fail;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldckp->dring_data_acks.value.ul = statsp->dring_data_acks;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan ldckp->dring_data_msgs.value.ul = statsp->dring_data_msgs;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * MIB II kstat variables
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo statsp->rx_allocb_fail = ldckp->rx_allocb_fail.value.ul;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo statsp->dring_data_acks = ldckp->dring_data_acks.value.ul;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan statsp->dring_data_msgs = ldckp->dring_data_msgs.value.ul;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* handler for error messages received from the peer ldc end-point */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Check if the session id in the received message is valid */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "sid mismatch: expected(%x), rcvd(%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* convert mac address from string to uint64_t */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < ETHERADDRL; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* convert mac address from uint64_t to string */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Handshake watchdog timeout handler */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "\thphase: 0x%x, hstate: 0x%x\n",