vnet_gen.c revision c198d18e90b390e955c8766a91af6e2db1fccd57
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
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * Copyright 2007 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);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic 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);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic uint_t vgen_ldc_rcv_softintr(caddr_t arg1, caddr_t arg2);
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 */
445b4c2ed2d52ef648ae6b36e4f5e14ff3d234afsbuint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # 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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramint vgen_rcv_thread_enabled = 1; /* Enable Recieve thread */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * max # of packets accumulated prior to sending them up. It is best
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * to keep this at 60% of the number of recieve buffers.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Tunables for each receive buffer size and number of buffers for
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * each buffer size.
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramstatic void debug_printf(const char *fname, vgen_t *vgenp,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram/* -1 for all LDCs info, or ldc_id for a specific LDC info */
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,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(NULL, NULL, "vnet(%d):%s: enter\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 * 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 /* 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/* 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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* retry ldc_up() if needed */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* drop the packet if ldc is not up or handshake is not done */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * allocate a descriptor
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* Try reclaiming now */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* Now we are really out of tbuf/txds */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* update next available tbuf in the ring and update tx index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* Mark the buffer busy before releasing the lock */
8e6a2a040587479821d1e682a28bcef7e75f19a6lm /* copy data into pre-allocated transmit buffer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the corresponding public descriptor (txd) */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the flags not set to BUSY, it implies that the clobber
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * was done while we were copying the data. In such case,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * discard the packet and return.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* update stats */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* send dring datamsg to the peer */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* error: drop the packet */
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram "failed: rv(%d) len(%d)\n",
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 * 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/* 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.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan if (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 /* 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 */
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp);
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 /* save mdeg handle in vgen_t */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* unregister with MD event generator */
445b4c2ed2d52ef648ae6b36e4f5e14ff3d234afsb kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* callback function registered with MD event generator */
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.
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk "not initialize virtual "
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk "switch port.",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk /* If this port can't be added just skip it. */
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)) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Find the channel endpoint node(s) under this port node.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate space for node list */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
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 if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
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 */
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk if (vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk cmn_err(CE_NOTE, "vnet%d failed to attach port %d remote MAC "
ca7ee4f955b3b075d0cc91d95f3515ee04c16a79zk return (rv);
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)) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
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);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(vgenp, NULL, "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 /* 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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* detach a port from the device based on mdeg data */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* stop the port if needed */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(vgenp, NULL, "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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram AST_create_rxmblks = 0x20, AST_add_softintr = 0x40,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "add_softint failed, rv (%d)\n",
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram * Initialize the soft_lock with the same priority as
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram * the soft interrupt to protect from the soft interrupt.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Failed to create worker thread");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate transmit resources */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* allocate receive resources */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS,
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? */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* First stop the receive thread */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* Free any queued messages */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * if we cannot reclaim all mblks, put this
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * on the list of pools(vgenp->rmp) to be reclaimed when the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * 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,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the addr of descripror ring */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n");
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
7636cb21f250f0485ca6052ffadc80ace93e6358lm if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* disable further callbacks */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * clear handshake done bit and wait for pending tx and cb to finish.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * release locks before untimeout(9F) is invoked to cancel timeouts.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan /* cancel handshake watchdog timeout */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan /* cancel transmit watchdog timeout */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan /* acquire locks again; any pending transmits and callbacks are done */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Initialize the transmit buffer ring for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram datap = kmem_zalloc(ldcp->num_txds * VGEN_TXDBLK_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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_TXDBLK_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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone);
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 * 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())
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr,
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initialize local session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* clear peer session id */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Initiate Handshake process with peer ldc endpoint */
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 * 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()).
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr,
3af08d828975d7e2581b6829e0eecff14d87a483lm /* try to bring the channel up */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm /* if channel is already UP - restart handshake */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Interrupt handler for the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
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.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is enabled, then
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * wakeup the receive thread to process the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * LDC messages.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* send up the received packets to MAC layer */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Cancel handshake timer.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * untimeout(9F) will not return until the pending callback is
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * cancelled or has run. No problems will result from calling
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * untimeout if the handler has already completed.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the timeout handler did run, then it would just
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * return as cancel_htid is set.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is enabled, then the cblock
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * need to be acquired here. If not, the vgen_ldc_cb()
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * calls this function with cblock held already.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (msglen == 0) {
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.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If an error is encountered, stop processing and
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * handle the error.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* check once more before exiting */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram } else if (rv) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is not enabled, then cancel the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * handshake timeout here.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Cancel handshake timer. untimeout(9F) will
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * not return until the pending callback is cancelled
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * or has run. No problems will result from calling
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * untimeout if the handler has already completed.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the timeout handler did run, then it would just
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * return as cancel_htid is set.
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 return (rv);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n",
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);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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),
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 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 /* reset hstate and hphase */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * Save the id of pending handshake timer in cancel_htid.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * This will be checked in vgen_ldc_cb() and the handshake timer will
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * be cancelled after releasing cblock.
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Unbind tx descriptor ring from the channel */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n");
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* clear sids */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* try to bring the channel up */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
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 */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * Save the id of pending handshake timer in cancel_htid.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * This will be checked in vgen_ldc_cb() and the handshake
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan * timer will be cancelled after releasing cblock.
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 } 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/* retry handshake on failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset handshake phase */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan /* handshake retry is specified and the channel is UP */
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) {
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 /* Cache sid of peer if this is the first time */
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send reply msg back to peer */
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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 and VER_ACK_RCVD */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* local and peer versions match? */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move to the next phase */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* This should not happen. */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* SUCCESS - we have agreed on a version */
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. */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD 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.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* select next lower version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* major version match */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * no version match.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Version Negotiation has failed.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "Version Negotiation Failed\n");
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
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.
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)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram " Invalid Phase(%u)\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/* 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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\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 /* 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)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\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/* 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 /* success adding/removing multicast addr */
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_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);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * To reduce the locking contention, release the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * cblock here and re-acquire it once we are done
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * receiving packets.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * received a data msg, which contains the start and end
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * indices of the descriptors within the rx ring holding data,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * the seq_num of data packet corresponding to the start index,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and the dring_ident.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * We can now read the contents of each of these descriptors
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and gather data from it.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate rx start and end indeces */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* drop the message if invalid index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate dring_ident */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* invalid dring_ident, drop the msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* drop this msg to simulate lost pkts for debugging */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* receive start index doesn't match expected index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* calculate the number of pkts lost */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * sequence number of dring data message
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * is less than the next sequence number that
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * is expected:
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * drop the message and the corresponding packets.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "rxseq(0x%lx) > recvd(0x%lx)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * duplicate/multiple retransmissions from
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * sender?? drop this msg.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * sequence number of dring data message
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * is greater than the next expected sequence number
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * send a NACK back to the peer to indicate lost
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* indicate the range of lost descriptors */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* dring ident is left unchanged */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "vgen_sendmsg failed, stype:NACK\n");
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * stop further processing until peer
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * retransmits with the right index.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * update next_rxseq expected.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#else /* VGEN_REXMIT */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * treat this range of descrs/pkts as dropped
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and set the new expected values for next_rxi
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and next_rxseq. continue(below) to process
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * from the new start index.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* VGEN_REXMIT */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram } else if (dringmsg->seq_num == ldcp->next_rxseq) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * expected and received seqnums match, but
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * the descriptor indeces don't?
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * restart handshake with peer.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* expected and start dring indeces match */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* seqnums don't match */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#endif /* VGEN_HANDLE_LOST_PKTS */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* Now receive messages */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * start processing the descriptors from the specified
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * start index, up to the index a descriptor is not ready
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * to be processed or we process the entire descriptor ring
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and wrap around upto the start index.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* need to set the start index of descriptors to be ack'd */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* index upto which we have ack'd */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed"
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Before waiting and retry here, queue
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * the messages that are received already.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * This will help the soft interrupt to
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * send them up with less latency.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * descriptor is not ready.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * retry descriptor acquire, stop processing
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * after max # retries.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * initialize the start index of the range
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * of descriptors to be ack'd.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Try to allocate an mblk from the free pool
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * of recv mblks for the channel.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If this fails, use allocb().
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * The data buffer returned by
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * allocb(9F) is 8byte aligned. We
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * allocate extra 8 bytes to ensure
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * size is multiple of 8 bytes for
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * ldc_mem_copy().
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * rxd_err or allocb() failure,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * drop this packet, get next.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* set descriptor done bit */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * sender needs ack for this packet,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ack pkts upto this index.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* need to set new ack start index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* if ldc_mem_copy() failed */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram rv = ldc_mem_dring_release(ldcp->rx_dhandle, rxi, rxi);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * sender needs ack for this packet,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * ack pkts upto this index.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* need to set new ack start index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* point to the actual end of data */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* update stats */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* build a chain of received packets */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* first pkt */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* update end index of range of descrs to be ack'd */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* update the next index to be processed */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * processed the entire descriptor ring upto
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * the index at which we started.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram } while (1);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * send an ack message to peer indicating that we have stopped
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * processing descriptors.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * We have ack'd upto some index and we have not
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * processed any descriptors beyond that index.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Use the last ack'd index as both the start and
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * end of range of descrs being ack'd.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Note: This results in acking the last index twice
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * and should be harmless.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* save new recv index and expected seqnum of next dring msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* queue the packets received so far */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * received an ack corresponding to a specific descriptor for
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * which we had set the ACK bit in the descriptor (during
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * transmit). This enables us to reclaim descriptors.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "ACK: start(%d), end(%d)\n", start, end);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate start and end indeces in the tx ack msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* drop the message if invalid index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate dring_ident */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* invalid dring_ident, drop the msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* reclaim descriptors that are done */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * receiver continued processing descriptors after
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * sending us the ack.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* receiver stopped processing descriptors */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * determine if there are any pending tx descriptors
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * ready to be processed by the receiver(peer) and if so,
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * send a message to the peer to restart receiving.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * using the end index of the descriptor range for which
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * we received the ack, check if the next descriptor is
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * descr next to the end of ack'd descr range is not
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * starting from the current reclaim index, check
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * if any descriptor is ready.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * we have tx descriptor(s) ready to be
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * processed by the receiver.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * send a message to the peer with the start index
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * of ready descriptors.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * no ready tx descriptors. set the flag to send a
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * message to peer when tx descriptors are ready in
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * transmit routine.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp;
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * peer sent a NACK msg to indicate lost packets.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * The start and end correspond to the range of descriptors
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * for which the peer didn't receive a dring data msg and so
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * didn't receive the corresponding data.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate start and end indeces in the tx nack msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* drop the message if invalid index */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* validate dring_ident */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* invalid dring_ident, drop the msg */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* no busy descriptors, bogus nack ? */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* send a new dring data msg including the lost descrs */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram if (rv != 0) {
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * vgen_send_dring_data() error: drop all packets
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * in this descr range
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "vgen_send_dring_data failed: rv(%d)\n", rv);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* update next pointer */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "rexmit: start(%d) end(%d)\n", start, end);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram#else /* VGEN_REXMIT */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram /* we just mark the descrs as done so they can be reclaimed */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram#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 /* 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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "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 */
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Handshake watchdog timeout handler */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram "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",
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * vgen_ldc_queue_data -- Queue data in the LDC.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuramvgen_ldc_queue_data(vgen_ldc_t *ldcp, mblk_t *rhead, mblk_t *rtail)
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is enabled, then the queue
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * is protected by the soft_lock. After queuing, trigger
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * the soft interrupt so that the interrupt handler sends these
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * messages up the stack.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is not enabled, then the list is
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * automatically protected by the cblock lock, so no need
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * to hold any additional locks.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram (void) ddi_intr_trigger_softint(ldcp->soft_handle, NULL);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * This thread is woken up by the LDC interrupt handler to process
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * LDC packets and receive data.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr,
b4d0458e18abef7b5e036915e96807c219ec1d58raghuram "vnet_rcv_thread");
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Wait until the data is received or a stop
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * request is received.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * First process the stop request.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n");
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Update the run status and wakeup the thread that
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * has sent the stop request.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram/* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Send a stop request by setting the stop flag and
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * wait until the receive thread stops.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * vgen_ldc_rcv_softintr -- LDC Soft interrupt handler function.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Its job is to pickup the recieved packets that are queued in the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * LDC and send them up.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * NOTE: An interrupt handler is being used to handle the upper
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * layer(s) requirement to send up only at interrupt context.
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram/* ARGSUSED */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DTRACE_PROBE1(vgen_soft_intr, uint64_t, ldcp->ldc_id);
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * Print debug messages - set to 0xf to enable all msgs