vnet_gen.c revision c1c61f44e88f4c8c155272ee56d868043146096a
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
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Copyright 2008 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 */
c1c61f44e88f4c8c155272ee56d868043146096asbint vgen_init(vnet_t *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 */
c1c61f44e88f4c8c155272ee56d868043146096asbextern void vnet_fdbe_add(vnet_t *vnetp, struct ether_addr *macaddr,
c1c61f44e88f4c8c155272ee56d868043146096asbextern void vnet_fdbe_del(vnet_t *vnetp, struct ether_addr *eaddr);
c1c61f44e88f4c8c155272ee56d868043146096asbextern void vnet_fdbe_modify(vnet_t *vnetp, struct ether_addr *macaddr,
c1c61f44e88f4c8c155272ee56d868043146096asbextern void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen internal functions */
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
c1c61f44e88f4c8c155272ee56d868043146096asbstatic int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
c1c61f44e88f4c8c155272ee56d868043146096asbstatic int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void vgen_fdbe_modify(vgen_port_t *portp, boolean_t use_vsw_port,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
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_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);
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen);
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
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,
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic 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);
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
c1c61f44e88f4c8c155272ee56d868043146096asb/* VLAN routines */
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void vgen_vlan_read_ids(void *arg, int type, md_t *mdp,
c1c61f44e88f4c8c155272ee56d868043146096asbstatic boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
c1c61f44e88f4c8c155272ee56d868043146096asbstatic boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp,
c1c61f44e88f4c8c155272ee56d868043146096asbstatic mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp,
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void vgen_vlan_unaware_port_reset(vgen_port_t *portp);
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),
f0ca1d9a12d54d304791bc74525e2010ca924726sb#define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * MIB II broadcast/multicast packets
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Property names
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic char rmacaddr_propname[] = "remote-mac-address";
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic char pri_types_propname[] = "priority-ether-types";
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* versions supported - in decreasing order */
c1c61f44e88f4c8c155272ee56d868043146096asbstatic vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 3} };
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Tunables */
19b65a69adc64b3289ccb2fc32b805782e3f4540sbuint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */
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 */
61a70d81555b002d961400e93b444d97fc467f13raghuramuint32_t vgen_tx_retries = 0x4; /* retry when tx descr not available */
61a70d81555b002d961400e93b444d97fc467f13raghuramuint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */
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.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * In the absence of "priority-ether-types" property in MD, the following
f0ca1d9a12d54d304791bc74525e2010ca924726sb * internal tunable can be set to specify a single priority ethertype.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Number of transmit priority buffers that are preallocated per device.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This number is chosen to be a small value to throttle transmission
f0ca1d9a12d54d304791bc74525e2010ca924726sb * of priority packets. Note: Must be a power of 2 for vio_create_mblks().
c1c61f44e88f4c8c155272ee56d868043146096asbuint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* flags to simulate error conditions for debugging */
c1c61f44e88f4c8c155272ee56d868043146096asb * Matching criteria passed to the MDEG to register interest
c1c61f44e88f4c8c155272ee56d868043146096asb * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified
c1c61f44e88f4c8c155272ee56d868043146096asb * by their 'name' and 'cfg-handle' properties.
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)
c1c61f44e88f4c8c155272ee56d868043146096asbstatic int vgen_mdeg_port_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.
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_init(vnet_t *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate multicast table */
c1c61f44e88f4c8c155272ee56d868043146096asb vgenp->max_frame_size = vnet_ethermtu + sizeof (struct ether_header)
93b13a42237cddf986044511610fa8eddef1bd09wentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL);
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* register with MD event generator */
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb /* register macp of this vgen_t with vnet */
f0ca1d9a12d54d304791bc74525e2010ca924726sb sizeof (struct ether_addr));
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));
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* free pri_types table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* enable transmit/receive for the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* vgen transmit function */
61a70d81555b002d961400e93b444d97fc467f13raghuram * Retry so that we avoid reporting a failure
61a70d81555b002d961400e93b444d97fc467f13raghuram * to the upper layer. Returning a failure may cause the
61a70d81555b002d961400e93b444d97fc467f13raghuram * upper layer to go into single threaded mode there by
61a70d81555b002d961400e93b444d97fc467f13raghuram * causing performance degradation, especially for a large
61a70d81555b002d961400e93b444d97fc467f13raghuram * number of connections.
61a70d81555b002d961400e93b444d97fc467f13raghuram for (i = 0; i < vgen_tx_retries; ) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* success */
c1c61f44e88f4c8c155272ee56d868043146096asb * This function provides any necessary tagging/untagging of the frames
c1c61f44e88f4c8c155272ee56d868043146096asb * that are being transmitted over the port. It first verifies the vlan
c1c61f44e88f4c8c155272ee56d868043146096asb * membership of the destination(port) and drops the packet if the
c1c61f44e88f4c8c155272ee56d868043146096asb * destination doesn't belong to the given vlan.
c1c61f44e88f4c8c155272ee56d868043146096asb * Arguments:
c1c61f44e88f4c8c155272ee56d868043146096asb * portp: port over which the frames should be transmitted
c1c61f44e88f4c8c155272ee56d868043146096asb * mp: frame to be transmitted
c1c61f44e88f4c8c155272ee56d868043146096asb * is_tagged:
c1c61f44e88f4c8c155272ee56d868043146096asb * B_TRUE: indicates frame header contains the vlan tag already.
c1c61f44e88f4c8c155272ee56d868043146096asb * B_FALSE: indicates frame is untagged.
c1c61f44e88f4c8c155272ee56d868043146096asb * vid: vlan in which the frame should be transmitted.
c1c61f44e88f4c8c155272ee56d868043146096asb * Returns:
c1c61f44e88f4c8c155272ee56d868043146096asb * Sucess: frame(mblk_t *) after doing the necessary tag/untag.
c1c61f44e88f4c8c155272ee56d868043146096asb * Failure: NULL
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged,
c1c61f44e88f4c8c155272ee56d868043146096asb * If the packet is going to a vnet:
c1c61f44e88f4c8c155272ee56d868043146096asb * Check if the destination vnet is in the same vlan.
c1c61f44e88f4c8c155272ee56d868043146096asb * Check the frame header if tag or untag is needed.
c1c61f44e88f4c8c155272ee56d868043146096asb * We do not check the above conditions if the packet is going to vsw:
c1c61f44e88f4c8c155272ee56d868043146096asb * vsw must be present implicitly in all the vlans that a vnet device
c1c61f44e88f4c8c155272ee56d868043146096asb * is configured into; even if vsw itself is not assigned to those
c1c61f44e88f4c8c155272ee56d868043146096asb * vlans as an interface. For instance, the packet might be destined
c1c61f44e88f4c8c155272ee56d868043146096asb * to another vnet(indirectly through vsw) or to an external host
c1c61f44e88f4c8c155272ee56d868043146096asb * which is in the same vlan as this vnet and vsw itself may not be
c1c61f44e88f4c8c155272ee56d868043146096asb * present in that vlan. Similarly packets going to vsw must be
c1c61f44e88f4c8c155272ee56d868043146096asb * always tagged(unless in the default-vlan) if not already tagged,
c1c61f44e88f4c8c155272ee56d868043146096asb * as we do not know the final destination. This is needed because
c1c61f44e88f4c8c155272ee56d868043146096asb * vsw must always invoke its switching function only after tagging
c1c61f44e88f4c8c155272ee56d868043146096asb * the packet; otherwise after switching function determines the
c1c61f44e88f4c8c155272ee56d868043146096asb * destination we cannot figure out if the destination belongs to the
c1c61f44e88f4c8c155272ee56d868043146096asb * the same vlan that the frame originated from and if it needs tag/
c1c61f44e88f4c8c155272ee56d868043146096asb * untag. Note that vsw will tag the packet itself when it receives
c1c61f44e88f4c8c155272ee56d868043146096asb * it over the channel from a client if needed. However, that is
c1c61f44e88f4c8c155272ee56d868043146096asb * needed only in the case of vlan unaware clients such as obp or
c1c61f44e88f4c8c155272ee56d868043146096asb * earlier versions of vnet.
c1c61f44e88f4c8c155272ee56d868043146096asb * Packet going to a vnet. Check if the destination vnet is in
c1c61f44e88f4c8c155272ee56d868043146096asb * the same vlan. Then check the frame header if tag/untag is
c1c61f44e88f4c8c155272ee56d868043146096asb /* drop the packet */
c1c61f44e88f4c8c155272ee56d868043146096asb /* is the destination tagged or untagged in this vlan? */
c1c61f44e88f4c8c155272ee56d868043146096asb /* no tagging/untagging needed */
c1c61f44e88f4c8c155272ee56d868043146096asb return (mp);
c1c61f44e88f4c8c155272ee56d868043146096asb /* frame is tagged; destination needs untagged */
c1c61f44e88f4c8c155272ee56d868043146096asb return (mp);
c1c61f44e88f4c8c155272ee56d868043146096asb /* (is_tagged == B_FALSE): fallthru to tag tx packet: */
c1c61f44e88f4c8c155272ee56d868043146096asb * Packet going to a vnet needs tagging.
c1c61f44e88f4c8c155272ee56d868043146096asb * If the packet is going to vsw, then it must be tagged in all cases:
c1c61f44e88f4c8c155272ee56d868043146096asb * unknown unicast, broadcast/multicast or to vsw interface.
c1c61f44e88f4c8c155272ee56d868043146096asb return (mp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* transmit packets over the given port */
c1c61f44e88f4c8c155272ee56d868043146096asb * Determine the vlan id that the frame belongs to.
c1c61f44e88f4c8c155272ee56d868043146096asb /* Frames in default vlan must be untagged */
c1c61f44e88f4c8c155272ee56d868043146096asb * If the destination is a vnet-port verify it belongs to the
c1c61f44e88f4c8c155272ee56d868043146096asb * default vlan; otherwise drop the packet. We do not need
c1c61f44e88f4c8c155272ee56d868043146096asb * this check for vsw-port, as it should implicitly belong to
c1c61f44e88f4c8c155272ee56d868043146096asb * this vlan; see comments in vgen_vlan_frame_fixtag().
c1c61f44e88f4c8c155272ee56d868043146096asb } else { /* frame not in default-vlan */
c1c61f44e88f4c8c155272ee56d868043146096asb mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * NOTE: for now, we will assume we have a single channel.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Wrapper function to transmit normal and/or priority frames over the channel.
f0ca1d9a12d54d304791bc74525e2010ca924726sb for (i = 0; i < num_types; i++) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* priority frame, use pri tx function */
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This functions handles ldc channel reset while in the context
f0ca1d9a12d54d304791bc74525e2010ca924726sb * of transmit routines: vgen_ldcsend_pkt() or vgen_ldcsend_dring().
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * Calling mutex_enter() will result in a deadlock, if the other thread
c1c61f44e88f4c8c155272ee56d868043146096asb * already holds cblock and is waiting for all references on the fdbe
c1c61f44e88f4c8c155272ee56d868043146096asb * to be dropped in vnet_fdbe_modify() which is called from
c1c61f44e88f4c8c155272ee56d868043146096asb * vgen_handle_evt_reset(). This transmit thread holds a reference to
c1c61f44e88f4c8c155272ee56d868043146096asb * that fdb entry and will not drop its reference unless it gets cblock
c1c61f44e88f4c8c155272ee56d868043146096asb * here, completes processing and returns.
c1c61f44e88f4c8c155272ee56d868043146096asb * To avoid this race condition, we check if either callback thread
c1c61f44e88f4c8c155272ee56d868043146096asb * or another tx thread is already holding cblock, if so just return
c1c61f44e88f4c8c155272ee56d868043146096asb * and the thread which already holds it will handle the reset.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Second arg is TRUE, as we know that
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the caller of this function - vnet_m_tx(),
c1c61f44e88f4c8c155272ee56d868043146096asb * already has a ref on the fdb entry.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This function transmits the frame in the payload of a raw data
f0ca1d9a12d54d304791bc74525e2010ca924726sb * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
f0ca1d9a12d54d304791bc74525e2010ca924726sb * send special frames with high priorities, without going through
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the normal data path which uses descriptor ring mechanism.
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* drop the packet if ldc is not up or handshake is not done */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* frame size bigger than available payload len of raw data msg ? */
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* alloc space for a raw data message */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* copy frame into the payload of raw data message */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* setup the raw data msg */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* send the msg over ldc */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* update stats */
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This function transmits normal (non-priority) data frames over
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the channel. It queues the frame into the transmit descriptor ring
f0ca1d9a12d54d304791bc74525e2010ca924726sb * and sends a VIO_DRING_DATA message if needed, to wake up the
f0ca1d9a12d54d304791bc74525e2010ca924726sb * peer to (re)start processing.
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",
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
19b65a69adc64b3289ccb2fc32b805782e3f4540sb * the multicast address. Otherwise, we just update this
19b65a69adc64b3289ccb2fc32b805782e3f4540sb * mcast address in our table and the table will be sync'd
19b65a69adc64b3289ccb2fc32b805782e3f4540sb * with vsw when handshake completes.
bd8f0338e0109a8df4e34499bdf42e592c77eedanarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
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 */
c1c61f44e88f4c8c155272ee56d868043146096asb kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t));
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) {
c1c61f44e88f4c8c155272ee56d868043146096asb * Add the mac address of the port into the fdb of the vnet device.
c1c61f44e88f4c8c155272ee56d868043146096asb * If the port being added is a vnet-port:
c1c61f44e88f4c8c155272ee56d868043146096asb * In this case the tx_port arg specified to vnet_fdbe_add() is
c1c61f44e88f4c8c155272ee56d868043146096asb * vsw-port. This is done so that vsw-port acts as the route to reach
c1c61f44e88f4c8c155272ee56d868043146096asb * the macaddr corresponding to this port, until the channel for this
c1c61f44e88f4c8c155272ee56d868043146096asb * port comes up (LDC_UP) and handshake is done successfully. eg, if
c1c61f44e88f4c8c155272ee56d868043146096asb * the peer is OBP-vnet, it may not bring the channel up for this port
c1c61f44e88f4c8c155272ee56d868043146096asb * and may communicate via vsw to reach this port. Later, when
c1c61f44e88f4c8c155272ee56d868043146096asb * Solaris-vnet comes up at the other end of the channel for this port
c1c61f44e88f4c8c155272ee56d868043146096asb * and brings up the channel, it is an indication that peer vnet is
c1c61f44e88f4c8c155272ee56d868043146096asb * capable of distributed switching, so the direct route through this
c1c61f44e88f4c8c155272ee56d868043146096asb * port is specified in fdb (see func vgen_fdbe_modify()).
c1c61f44e88f4c8c155272ee56d868043146096asb /* Add entry for the port's mac address into fdb */
c1c61f44e88f4c8c155272ee56d868043146096asb vnet_fdbe_add(vgenp->vnetp, &portp->macaddr, type, vgen_tx, tx_portp);
c1c61f44e88f4c8c155272ee56d868043146096asb /* Add the port to the specified vlans */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Bring up the channels of this port */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* disable transmit/receive on ports */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* delete the entry in vnet's fdb for this macaddr/port */
c1c61f44e88f4c8c155272ee56d868043146096asb /* remove the port from vlans it has been assigned to */
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Scan the machine description for this instance of vnet
f0ca1d9a12d54d304791bc74525e2010ca924726sb * and read its properties. Called only from vgen_init().
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Returns: 0 on success, 1 on failure.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * In each 'virtual-device' node in the MD there is a
f0ca1d9a12d54d304791bc74525e2010ca924726sb * 'cfg-handle' property which is the MD's concept of
f0ca1d9a12d54d304791bc74525e2010ca924726sb * an instance number (this may be completely different from
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the device drivers instance #). OBP reads that value and
f0ca1d9a12d54d304791bc74525e2010ca924726sb * stores it in the 'reg' property of the appropriate node in
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the device tree. We first read this reg property and use this
f0ca1d9a12d54d304791bc74525e2010ca924726sb * to compare against the 'cfg-handle' property of vnet nodes
f0ca1d9a12d54d304791bc74525e2010ca924726sb * in MD to get to this specific vnet instance and then read
f0ca1d9a12d54d304791bc74525e2010ca924726sb * other properties that we are interested in.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * We also cache the value of 'reg' property and use it later
f0ca1d9a12d54d304791bc74525e2010ca924726sb * to register callbacks with mdeg (see vgen_mdeg_reg())
f0ca1d9a12d54d304791bc74525e2010ca924726sb return (rv);
f0ca1d9a12d54d304791bc74525e2010ca924726sb return (rv);
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* search for all "virtual_device" nodes */
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (num_devs <= 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Now loop through the list of virtual-devices looking for
f0ca1d9a12d54d304791bc74525e2010ca924726sb * devices with name "network" and for each such device compare
f0ca1d9a12d54d304791bc74525e2010ca924726sb * its instance with what we have from the 'reg' property to
f0ca1d9a12d54d304791bc74525e2010ca924726sb * find the right node in MD and then read all its properties.
f0ca1d9a12d54d304791bc74525e2010ca924726sb for (i = 0; i < num_devs; i++) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* is this a "network" device? */
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* is this the required instance of vnet? */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* now read all properties of this vnet instance */
c1c61f44e88f4c8c155272ee56d868043146096asb /* read vlan id properties of this vnet instance */
f0ca1d9a12d54d304791bc74525e2010ca924726sb return (rv);
c1c61f44e88f4c8c155272ee56d868043146096asb * Read vlan id properties of the given MD node.
c1c61f44e88f4c8c155272ee56d868043146096asb * Arguments:
c1c61f44e88f4c8c155272ee56d868043146096asb * arg: device argument(vnet device or a port)
c1c61f44e88f4c8c155272ee56d868043146096asb * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port)
c1c61f44e88f4c8c155272ee56d868043146096asb * mdp: machine description
c1c61f44e88f4c8c155272ee56d868043146096asb * node: md node cookie
c1c61f44e88f4c8c155272ee56d868043146096asb * Returns:
c1c61f44e88f4c8c155272ee56d868043146096asb * pvidp: port-vlan-id of the node
c1c61f44e88f4c8c155272ee56d868043146096asb * vidspp: list of vlan-ids of the node
c1c61f44e88f4c8c155272ee56d868043146096asb * nvidsp: # of vlan-ids in the list
c1c61f44e88f4c8c155272ee56d868043146096asb * default_idp: default-vlan-id of the node(if node is vnet device)
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node,
c1c61f44e88f4c8c155272ee56d868043146096asb rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val);
c1c61f44e88f4c8c155272ee56d868043146096asb if (rv != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb if (rv != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data,
c1c61f44e88f4c8c155272ee56d868043146096asb if (rv != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb if (nvids != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb for (i = 0; i < nvids; i++) {
c1c61f44e88f4c8c155272ee56d868043146096asb * Create a vlan id hash table for the given port.
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
c1c61f44e88f4c8c155272ee56d868043146096asb * Destroy the vlan id hash table in the given port.
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * Add a port to the vlans specified in its port properites.
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * Remove a port from the vlans it has been assigned to.
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame,
c1c61f44e88f4c8c155272ee56d868043146096asb * then the vlan-id is available in the tag; otherwise, its vlan id is
c1c61f44e88f4c8c155272ee56d868043146096asb * implicitly obtained from the port-vlan-id of the vnet device.
c1c61f44e88f4c8c155272ee56d868043146096asb * The vlan id determined is returned in vidp.
c1c61f44e88f4c8c155272ee56d868043146096asb * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp)
c1c61f44e88f4c8c155272ee56d868043146096asb /* If it's a tagged frame, get the vlan id from vlan header */
c1c61f44e88f4c8c155272ee56d868043146096asb /* Untagged frame, vlan-id is the pvid of vnet device */
c1c61f44e88f4c8c155272ee56d868043146096asb * Find the given vlan id in the hash table.
c1c61f44e88f4c8c155272ee56d868043146096asb * Return: B_TRUE if the id is found; B_FALSE if not found.
c1c61f44e88f4c8c155272ee56d868043146096asb rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
c1c61f44e88f4c8c155272ee56d868043146096asb if (rv != 0)
c1c61f44e88f4c8c155272ee56d868043146096asb * Modify fdb entries corresponding to the port's macaddr, to use a different
c1c61f44e88f4c8c155272ee56d868043146096asb * port. This is done when the port's ldc channel goes down or comes up. When
c1c61f44e88f4c8c155272ee56d868043146096asb * the channel state changes to RESET/DOWN, we modify the fdb entry for the
c1c61f44e88f4c8c155272ee56d868043146096asb * port by specifying vsw-port as the port to be used for transmits.
c1c61f44e88f4c8c155272ee56d868043146096asb * Similarly when the channel state changes to UP, we restore its fdb entry to
c1c61f44e88f4c8c155272ee56d868043146096asb * start using the actual vnet-port for transmits.
c1c61f44e88f4c8c155272ee56d868043146096asb * Arguments:
c1c61f44e88f4c8c155272ee56d868043146096asb * portp: port for which fdb entry is being updated
c1c61f44e88f4c8c155272ee56d868043146096asb * use_vsw_port:
c1c61f44e88f4c8c155272ee56d868043146096asb * B_TRUE: update fdb entry to use vsw-port for transmits
c1c61f44e88f4c8c155272ee56d868043146096asb * B_FALSE: update fdb entry to use the port itself for tx
c1c61f44e88f4c8c155272ee56d868043146096asb * flag: provides context info
c1c61f44e88f4c8c155272ee56d868043146096asb * B_TRUE: this func is being called from transmit routine
c1c61f44e88f4c8c155272ee56d868043146096asb * B_FALSE: other contexts (callbacks)
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_fdbe_modify(vgen_port_t *portp, boolean_t use_vsw_port,
c1c61f44e88f4c8c155272ee56d868043146096asb (use_vsw_port == B_TRUE) ? (pp = vgenp->vsw_portp) : (pp = portp);
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This function reads "priority-ether-types" property from md. This property
f0ca1d9a12d54d304791bc74525e2010ca924726sb * is used to enable support for priority frames. Applications which need
f0ca1d9a12d54d304791bc74525e2010ca924726sb * guaranteed and timely delivery of certain high priority frames to/from
f0ca1d9a12d54d304791bc74525e2010ca924726sb * a vnet or vsw within ldoms, should configure this property by providing
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the ether type(s) for which the priority facility is needed.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Normal data frames are delivered over a ldc channel using the descriptor
f0ca1d9a12d54d304791bc74525e2010ca924726sb * ring mechanism which is constrained by factors such as descriptor ring size,
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the rate at which the ring is processed at the peer ldc end point, etc.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * The priority mechanism provides an Out-Of-Band path to send/receive frames
f0ca1d9a12d54d304791bc74525e2010ca924726sb * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the
f0ca1d9a12d54d304791bc74525e2010ca924726sb * descriptor ring path and enables a more reliable and timely delivery of
f0ca1d9a12d54d304791bc74525e2010ca924726sb * frames to the peer.
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
f0ca1d9a12d54d304791bc74525e2010ca924726sbvgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node)
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (rv != 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Property may not exist if we are running pre-ldoms1.1 f/w.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Check if 'vgen_pri_eth_type' has been set in that case.
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (size == 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb * we have some priority-ether-types defined;
f0ca1d9a12d54d304791bc74525e2010ca924726sb * allocate a table of these types and also
f0ca1d9a12d54d304791bc74525e2010ca924726sb * allocate a pool of mblks to transmit these
f0ca1d9a12d54d304791bc74525e2010ca924726sb * priority packets.
f0ca1d9a12d54d304791bc74525e2010ca924726sb vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP);
c1c61f44e88f4c8c155272ee56d868043146096asb mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* register with MD event generator */
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 */
c1c61f44e88f4c8c155272ee56d868043146096asb * Register an interest in 'virtual-device' nodes with a
c1c61f44e88f4c8c155272ee56d868043146096asb * 'name' property of 'network'
c1c61f44e88f4c8c155272ee56d868043146096asb rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl);
c1c61f44e88f4c8c155272ee56d868043146096asb /* Register an interest in 'port' nodes */
c1c61f44e88f4c8c155272ee56d868043146096asb rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save mdeg handle in vgen_t */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* unregister with MD event generator */
445b4c2ed2d52ef648ae6b36e4f5e14ff3d234afsb kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template));
c1c61f44e88f4c8c155272ee56d868043146096asb/* mdeg callback function for the port node */
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
c1c61f44e88f4c8c155272ee56d868043146096asb * vsw on service domain.
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. */
c1c61f44e88f4c8c155272ee56d868043146096asb/* mdeg callback function for the vnet node */
c1c61f44e88f4c8c155272ee56d868043146096asb DBG1(vgenp, NULL, "%s: added %d : removed %d : curr matched %d"
c1c61f44e88f4c8c155272ee56d868043146096asb " : prev matched %d", resp->added.nelem, resp->removed.nelem,
c1c61f44e88f4c8c155272ee56d868043146096asb * We get an initial callback for this node as 'added' after
c1c61f44e88f4c8c155272ee56d868043146096asb * registering with mdeg. Note that we would have already gathered
c1c61f44e88f4c8c155272ee56d868043146096asb * information about this vnet node by walking MD earlier during attach
c1c61f44e88f4c8c155272ee56d868043146096asb * (in vgen_read_mdprops()). So, there is a window where the properties
c1c61f44e88f4c8c155272ee56d868043146096asb * of this node might have changed when we get this initial 'added'
c1c61f44e88f4c8c155272ee56d868043146096asb * callback. We handle this as if an update occured and invoke the same
c1c61f44e88f4c8c155272ee56d868043146096asb * function which handles updates to the properties of this vnet-node
c1c61f44e88f4c8c155272ee56d868043146096asb * if any. A non-zero 'match' value indicates that the MD has been
c1c61f44e88f4c8c155272ee56d868043146096asb * updated and that a 'network' node is present which may or may not
c1c61f44e88f4c8c155272ee56d868043146096asb * have been updated. It is up to the clients to examine their own
c1c61f44e88f4c8c155272ee56d868043146096asb * nodes and determine if they have changed.
c1c61f44e88f4c8c155272ee56d868043146096asb /* Validate name and instance */
c1c61f44e88f4c8c155272ee56d868043146096asb if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* is this a virtual-network device? */
c1c61f44e88f4c8c155272ee56d868043146096asb DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name);
c1c61f44e88f4c8c155272ee56d868043146096asb /* is this the right instance of vsw? */
c1c61f44e88f4c8c155272ee56d868043146096asb * Check to see if the relevant properties in the specified node have
c1c61f44e88f4c8c155272ee56d868043146096asb * changed, and if so take the appropriate action.
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
c1c61f44e88f4c8c155272ee56d868043146096asb /* Read the vlan ids */
c1c61f44e88f4c8c155272ee56d868043146096asb vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids,
c1c61f44e88f4c8c155272ee56d868043146096asb /* Determine if there are any vlan id updates */
c1c61f44e88f4c8c155272ee56d868043146096asb ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */
c1c61f44e88f4c8c155272ee56d868043146096asb if (nvids != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* save the new vlan ids */
c1c61f44e88f4c8c155272ee56d868043146096asb kmem_free(vnetp->vids, sizeof (uint16_t) * vnetp->nvids);
c1c61f44e88f4c8c155272ee56d868043146096asb if (nvids != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* reset vlan-unaware peers (ver < 1.3) and restart handshake */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* add a new port to the device */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
c1c61f44e88f4c8c155272ee56d868043146096asb/* read properties of the port from its md node */
c1c61f44e88f4c8c155272ee56d868043146096asbvgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
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) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* This port is connected to the vsw */
c1c61f44e88f4c8c155272ee56d868043146096asb /* now update all properties into the port */
c1c61f44e88f4c8c155272ee56d868043146096asb portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP);
c1c61f44e88f4c8c155272ee56d868043146096asb bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs);
c1c61f44e88f4c8c155272ee56d868043146096asb /* read vlan id properties of this port node */
c1c61f44e88f4c8c155272ee56d868043146096asb vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid,
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 */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
c1c61f44e88f4c8c155272ee56d868043146096asb for (i = 0; i < num_ldcs; i++) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* create vlan id hash table */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* link it into the list of ports */
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,
c1c61f44e88f4c8c155272ee56d868043146096asb * For now, we get port updates only if vlan ids changed.
c1c61f44e88f4c8c155272ee56d868043146096asb * We read the port num and do some sanity check.
c1c61f44e88f4c8c155272ee56d868043146096asb if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) {
c1c61f44e88f4c8c155272ee56d868043146096asb if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) {
c1c61f44e88f4c8c155272ee56d868043146096asb /* Read the vlan ids */
c1c61f44e88f4c8c155272ee56d868043146096asb vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids,
c1c61f44e88f4c8c155272ee56d868043146096asb /* Determine if there are any vlan id updates */
c1c61f44e88f4c8c155272ee56d868043146096asb ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */
c1c61f44e88f4c8c155272ee56d868043146096asb /* remove the port from vlans it has been assigned to */
c1c61f44e88f4c8c155272ee56d868043146096asb /* save the new vlan ids */
c1c61f44e88f4c8c155272ee56d868043146096asb kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids);
c1c61f44e88f4c8c155272ee56d868043146096asb if (nvids != 0) {
c1c61f44e88f4c8c155272ee56d868043146096asb portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP);
c1c61f44e88f4c8c155272ee56d868043146096asb /* add port to the new vlans */
c1c61f44e88f4c8c155272ee56d868043146096asb /* reset the port if it is vlan unaware (ver < 1.3) */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* attach the channel corresponding to the given ldc_id to the port */
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 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",
f0ca1d9a12d54d304791bc74525e2010ca924726sb * allocate a message for ldc_read()s, big enough to hold ctrl and
f0ca1d9a12d54d304791bc74525e2010ca924726sb * data msgs, including raw data msgs used to recv priority frames.
c1c61f44e88f4c8c155272ee56d868043146096asb ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size;
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 */
06db247c678f0e3956535e8a6dec31d6c2108827raghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id);
06db247c678f0e3956535e8a6dec31d6c2108827raghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats);
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 * 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 */
c1c61f44e88f4c8c155272ee56d868043146096asb * modify fdb entry to use this port as the channel is
c1c61f44e88f4c8c155272ee56d868043146096asb * up, instead of going through the vsw-port (see
c1c61f44e88f4c8c155272ee56d868043146096asb * 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));
c1c61f44e88f4c8c155272ee56d868043146096asb data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN;
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 */
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 */
c1c61f44e88f4c8c155272ee56d868043146096asb * LDC channel is UP, start handshake process with peer. Flag tells
c1c61f44e88f4c8c155272ee56d868043146096asb * vnet_fdbe_modify() about the context: set to B_TRUE if this
3af08d828975d7e2581b6829e0eecff14d87a483lm * function is being called from transmit routine, otherwise B_FALSE.
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * modify fdb entry to use this port as the channel is up,
c1c61f44e88f4c8c155272ee56d868043146096asb * instead of going through the vsw-port (see comments in
c1c61f44e88f4c8c155272ee56d868043146096asb * vgen_port_init())
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.
c1c61f44e88f4c8c155272ee56d868043146096asb * Flag tells vnet_fdbe_modify() about the context: set to B_TRUE if this
3af08d828975d7e2581b6829e0eecff14d87a483lm * function is being called from transmit routine, otherwise B_FALSE.
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * modify fdb entry to use vsw-port as the channel is reset
c1c61f44e88f4c8c155272ee56d868043146096asb * and we don't have a direct link to the destination (see
c1c61f44e88f4c8c155272ee56d868043146096asb * comments in vgen_port_init()).
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.
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram /* status couldn't be determined */
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram " but ldc status is not UP(0x%x)\n",
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram /* spurious interrupt, return success */
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram /* Handle RESET/DOWN before READ event */
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram /* status couldn't be determined */
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram * As the channel is down/reset, ignore READ event
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram * but print a debug warning message.
7062b44a173ea4621ab043112cbf2d9977480fa9raghuram "LDC_EVT_READ set along with RESET/DOWN\n");
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * If the receive thread is enabled, then
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * wakeup the receive thread to process the
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram * LDC messages.
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.
f0ca1d9a12d54d304791bc74525e2010ca924726sb 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 * 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);
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Set vnet-protocol-version dependent functions based on version.
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * If the version negotiated with peer is >= 1.3,
c1c61f44e88f4c8c155272ee56d868043146096asb * set the mtu in our attributes to max_frame_size.
c1c61f44e88f4c8c155272ee56d868043146096asb * Pre-1.3 peers expect max frame size of ETHERMAX.
c1c61f44e88f4c8c155272ee56d868043146096asb * We can negotiate that size with those peers provided the
c1c61f44e88f4c8c155272ee56d868043146096asb * following conditions are true:
c1c61f44e88f4c8c155272ee56d868043146096asb * - Our max_frame_size is greater only by VLAN_TAGSZ (4).
c1c61f44e88f4c8c155272ee56d868043146096asb * - Only pvid is defined for our peer and there are no vids.
c1c61f44e88f4c8c155272ee56d868043146096asb * - pvids are equal.
c1c61f44e88f4c8c155272ee56d868043146096asb * If the above conditions are true, then we can send/recv only
c1c61f44e88f4c8c155272ee56d868043146096asb * untagged frames of max size ETHERMAX.
c1c61f44e88f4c8c155272ee56d868043146096asb /* Versions >= 1.2 */
f0ca1d9a12d54d304791bc74525e2010ca924726sb * enable priority routines and pkt mode only if
f0ca1d9a12d54d304791bc74525e2010ca924726sb * at least one pri-eth-type is specified in MD.
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* set xfer mode for vgen_send_attr_info() */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* no priority eth types defined in MD */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* set xfer mode for vgen_send_attr_info() */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* Versions prior to 1.2 */
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Reset vnet-protocol-version dependent functions to pre-v1.2.
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* set xfer mode for vgen_send_attr_info() */
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb * NOTE: for now, we will assume we have a single channel.
c1c61f44e88f4c8c155272ee56d868043146096asb * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
c1c61f44e88f4c8c155272ee56d868043146096asb * the connection. See comments in vgen_set_vnet_proto_ops().
c1c61f44e88f4c8c155272ee56d868043146096asb if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) &&
c1c61f44e88f4c8c155272ee56d868043146096asbstatic void
c1c61f44e88f4c8c155272ee56d868043146096asb for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
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.
19b65a69adc64b3289ccb2fc32b805782e3f4540sb * If this channel(port) is connected to vsw,
19b65a69adc64b3289ccb2fc32b805782e3f4540sb * 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 * 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 */
f0ca1d9a12d54d304791bc74525e2010ca924726sbvgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen)
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
f0ca1d9a12d54d304791bc74525e2010ca924726sb if (rv != 0) {
f0ca1d9a12d54d304791bc74525e2010ca924726sb return (rv);
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
f0ca1d9a12d54d304791bc74525e2010ca924726sb * dummy pkt data handler function for vnet protocol version 1.0
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
f0ca1d9a12d54d304791bc74525e2010ca924726sbvgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
f0ca1d9a12d54d304791bc74525e2010ca924726sb * This function handles raw pkt data messages received over the channel.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Currently, only priority-eth-type frames are received through this mechanism.
f0ca1d9a12d54d304791bc74525e2010ca924726sb * In this case, the frame(data) is present within the message itself which
f0ca1d9a12d54d304791bc74525e2010ca924726sb * is copied into an mblk before sending it up the stack.
f0ca1d9a12d54d304791bc74525e2010ca924726sbstatic void
f0ca1d9a12d54d304791bc74525e2010ca924726sbvgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen)
f0ca1d9a12d54d304791bc74525e2010ca924726sb "unable to process priority frame\n");
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* copy the frame from the payload of raw data msg into the mblk */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* update stats */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* send up; call vnet_rx() as cblock is already released */
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 */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* indicate the range of lost descriptors */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* dring ident is left unchanged */
f0ca1d9a12d54d304791bc74525e2010ca924726sb "vgen_sendmsg failed, stype:NACK\n");
f0ca1d9a12d54d304791bc74525e2010ca924726sb * treat this range of descrs/pkts as dropped
f0ca1d9a12d54d304791bc74525e2010ca924726sb * and set the new expected value of next_rxi
f0ca1d9a12d54d304791bc74525e2010ca924726sb * and continue(below) to process from the new
f0ca1d9a12d54d304791bc74525e2010ca924726sb * start index.
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"
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Before waiting and retry here, send up
f0ca1d9a12d54d304791bc74525e2010ca924726sb * the packets that are received already
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,
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* save new recv index of next dring msg */
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* send up 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 /* we just mark the descrs as done so they can be reclaimed */
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/* handler for error messages received from the peer ldc end-point */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppovgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
f0ca1d9a12d54d304791bc74525e2010ca924726sbvgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
f0ca1d9a12d54d304791bc74525e2010ca924726sb /* seqnums don't match */
f0ca1d9a12d54d304791bc74525e2010ca924726sb "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
f0ca1d9a12d54d304791bc74525e2010ca924726sb return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Check if the session id in the received message is valid */
844e62a3ec8c8ff5175bb35d1c38446e060730f6raghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
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",
f0ca1d9a12d54d304791bc74525e2010ca924726sb * Send received packets up the stack.
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 * Print debug messages - set to 0xf to enable all msgs