11ae08745Sheppo /*
21ae08745Sheppo * CDDL HEADER START
31ae08745Sheppo *
41ae08745Sheppo * The contents of this file are subject to the terms of the
51ae08745Sheppo * Common Development and Distribution License (the "License").
61ae08745Sheppo * You may not use this file except in compliance with the License.
71ae08745Sheppo *
81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo * See the License for the specific language governing permissions
111ae08745Sheppo * and limitations under the License.
121ae08745Sheppo *
131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo *
191ae08745Sheppo * CDDL HEADER END
201ae08745Sheppo */
211ae08745Sheppo
221ae08745Sheppo /*
23a862df29SSriharsha Basavapatna * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241ae08745Sheppo */
251ae08745Sheppo
261ae08745Sheppo #include <sys/types.h>
271ae08745Sheppo #include <sys/errno.h>
287b1f684aSSriharsha Basavapatna #include <sys/sysmacros.h>
291ae08745Sheppo #include <sys/param.h>
307bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h>
311ae08745Sheppo #include <sys/stream.h>
32844e62a3Sraghuram #include <sys/strsubr.h>
331ae08745Sheppo #include <sys/kmem.h>
341ae08745Sheppo #include <sys/conf.h>
351ae08745Sheppo #include <sys/devops.h>
361ae08745Sheppo #include <sys/ksynch.h>
371ae08745Sheppo #include <sys/stat.h>
381ae08745Sheppo #include <sys/modctl.h>
391ae08745Sheppo #include <sys/debug.h>
401ae08745Sheppo #include <sys/ethernet.h>
411ae08745Sheppo #include <sys/ddi.h>
421ae08745Sheppo #include <sys/sunddi.h>
431ae08745Sheppo #include <sys/strsun.h>
441ae08745Sheppo #include <sys/note.h>
45da14cebeSEric Cheng #include <sys/mac_provider.h>
46ba2e4443Sseb #include <sys/mac_ether.h>
471ae08745Sheppo #include <sys/ldc.h>
481ae08745Sheppo #include <sys/mach_descrip.h>
491ae08745Sheppo #include <sys/mdeg.h>
50844e62a3Sraghuram #include <net/if.h>
51844e62a3Sraghuram #include <sys/vnet.h>
521ae08745Sheppo #include <sys/vio_mailbox.h>
531ae08745Sheppo #include <sys/vio_common.h>
541ae08745Sheppo #include <sys/vnet_common.h>
551ae08745Sheppo #include <sys/vnet_mailbox.h>
56d10e4ef2Snarayan #include <sys/vio_util.h>
57d10e4ef2Snarayan #include <sys/vnet_gen.h>
58f0ca1d9aSsb155480 #include <sys/atomic.h>
59844e62a3Sraghuram #include <sys/callb.h>
60844e62a3Sraghuram #include <sys/sdt.h>
61844e62a3Sraghuram #include <sys/intr.h>
62844e62a3Sraghuram #include <sys/pattr.h>
63c1c61f44Ssb155480 #include <sys/vlan.h>
641ae08745Sheppo
651ae08745Sheppo /*
667bd3a2e2SSriharsha Basavapatna * Implementation of the mac provider functionality for vnet using the
671ae08745Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
681ae08745Sheppo */
691ae08745Sheppo
707bd3a2e2SSriharsha Basavapatna /* Entry Points */
71678453a8Sspeer int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
72678453a8Sspeer const uint8_t *macaddr, void **vgenhdl);
7363f531d1SSriharsha Basavapatna int vgen_init_mdeg(void *arg);
743ab636deSWENTAO YANG void vgen_uninit(void *arg);
75678453a8Sspeer int vgen_dds_tx(void *arg, void *dmsg);
7663f531d1SSriharsha Basavapatna int vgen_enable_intr(void *arg);
7763f531d1SSriharsha Basavapatna int vgen_disable_intr(void *arg);
787bd3a2e2SSriharsha Basavapatna mblk_t *vgen_rx_poll(void *arg, int bytes_to_pickup);
791ae08745Sheppo static int vgen_start(void *arg);
801ae08745Sheppo static void vgen_stop(void *arg);
811ae08745Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
821ae08745Sheppo static int vgen_multicst(void *arg, boolean_t add,
831ae08745Sheppo const uint8_t *mca);
841ae08745Sheppo static int vgen_promisc(void *arg, boolean_t on);
851ae08745Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
86ba2e4443Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
871107ea93SSriharsha Basavapatna static void vgen_ioctl(void *arg, queue_t *q, mblk_t *mp);
881107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG
891107ea93SSriharsha Basavapatna static int vgen_force_link_state(vgen_port_t *portp, int link_state);
901107ea93SSriharsha Basavapatna #endif
911ae08745Sheppo
927bd3a2e2SSriharsha Basavapatna /* Port/LDC Configuration */
93c1c61f44Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp);
94c1c61f44Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
95c1c61f44Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp,
96c1c61f44Ssb155480 mde_cookie_t node);
977b1f684aSSriharsha Basavapatna static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
987b1f684aSSriharsha Basavapatna uint32_t *mtu);
991107ea93SSriharsha Basavapatna static void vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
1001107ea93SSriharsha Basavapatna boolean_t *pls);
1011ae08745Sheppo static void vgen_detach_ports(vgen_t *vgenp);
1021ae08745Sheppo static void vgen_port_detach(vgen_port_t *portp);
1031ae08745Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
1041ae08745Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
1051ae08745Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1061ae08745Sheppo int port_num);
1071ae08745Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
1081ae08745Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
1091ae08745Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
110c1c61f44Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
1111ae08745Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
112c1c61f44Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
113c1c61f44Ssb155480 mde_cookie_t mdex);
1141ae08745Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
115c1c61f44Ssb155480 static int vgen_port_attach(vgen_port_t *portp);
116c1c61f44Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp);
1171ae08745Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1181ae08745Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
119ba2e4443Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat);
1201107ea93SSriharsha Basavapatna static void vgen_port_reset(vgen_port_t *portp);
1211107ea93SSriharsha Basavapatna static void vgen_reset_vsw_port(vgen_t *vgenp);
1227bd3a2e2SSriharsha Basavapatna static int vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
1237bd3a2e2SSriharsha Basavapatna static void vgen_ldc_up(vgen_ldc_t *ldcp);
1241ae08745Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1251ae08745Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1261ae08745Sheppo static void vgen_port_init(vgen_port_t *portp);
1271ae08745Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1281ae08745Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1291ae08745Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
130ba2e4443Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
1317bd3a2e2SSriharsha Basavapatna
1327bd3a2e2SSriharsha Basavapatna /* I/O Processing */
1331ae08745Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
134f0ca1d9aSsb155480 static int vgen_ldcsend(void *arg, mblk_t *mp);
135f0ca1d9aSsb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp);
1367bd3a2e2SSriharsha Basavapatna static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
1377bd3a2e2SSriharsha Basavapatna static void vgen_tx_watchdog(void *arg);
1381ae08745Sheppo
1397bd3a2e2SSriharsha Basavapatna /* Dring Configuration */
1407bd3a2e2SSriharsha Basavapatna static int vgen_create_dring(vgen_ldc_t *ldcp);
1417bd3a2e2SSriharsha Basavapatna static void vgen_destroy_dring(vgen_ldc_t *ldcp);
1427bd3a2e2SSriharsha Basavapatna static int vgen_map_dring(vgen_ldc_t *ldcp, void *pkt);
1437bd3a2e2SSriharsha Basavapatna static void vgen_unmap_dring(vgen_ldc_t *ldcp);
144*34f94fbcSWENTAO YANG static int vgen_mapin_avail(vgen_ldc_t *ldcp);
1457bd3a2e2SSriharsha Basavapatna
1467bd3a2e2SSriharsha Basavapatna /* VIO Message Processing */
1477bd3a2e2SSriharsha Basavapatna static int vgen_handshake(vgen_ldc_t *ldcp);
1487bd3a2e2SSriharsha Basavapatna static int vgen_handshake_done(vgen_ldc_t *ldcp);
1491ae08745Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
1507bd3a2e2SSriharsha Basavapatna static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
1517bd3a2e2SSriharsha Basavapatna static int vgen_handshake_phase3(vgen_ldc_t *ldcp);
1527bd3a2e2SSriharsha Basavapatna static void vgen_setup_handshake_params(vgen_ldc_t *ldcp);
1531ae08745Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1541ae08745Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
1557bd3a2e2SSriharsha Basavapatna static int vgen_send_rx_dring_reg(vgen_ldc_t *ldcp);
1567bd3a2e2SSriharsha Basavapatna static int vgen_send_tx_dring_reg(vgen_ldc_t *ldcp);
1577bd3a2e2SSriharsha Basavapatna static void vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
1587bd3a2e2SSriharsha Basavapatna uint8_t option);
1591ae08745Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
1607bd3a2e2SSriharsha Basavapatna static int vgen_send_dringdata(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1611ae08745Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1623af08d82Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1631ae08745Sheppo vio_msg_tag_t *tagp);
1647bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1657bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
1667bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
1673af08d82Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1687bd3a2e2SSriharsha Basavapatna static int vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1697bd3a2e2SSriharsha Basavapatna static int vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1703af08d82Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1713af08d82Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1723af08d82Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
173f0ca1d9aSsb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen);
174f0ca1d9aSsb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
175f0ca1d9aSsb155480 uint32_t msglen);
1761ae08745Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1777bd3a2e2SSriharsha Basavapatna static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
178678453a8Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp);
1797bd3a2e2SSriharsha Basavapatna static int vgen_process_reset(vgen_ldc_t *ldcp, int flags);
1801ae08745Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1811ae08745Sheppo static void vgen_hwatchdog(void *arg);
182f0ca1d9aSsb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp);
183f0ca1d9aSsb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp);
1841107ea93SSriharsha Basavapatna static void vgen_link_update(vgen_t *vgenp, link_state_t link_state);
1851ae08745Sheppo
1867bd3a2e2SSriharsha Basavapatna /* VLANs */
187c1c61f44Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp,
188c1c61f44Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp,
189c1c61f44Ssb155480 uint16_t *nvidsp, uint16_t *default_idp);
190c1c61f44Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp);
191c1c61f44Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp);
192c1c61f44Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp);
193c1c61f44Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp);
194c1c61f44Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
195c1c61f44Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp,
196c1c61f44Ssb155480 uint16_t *vidp);
197c1c61f44Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp,
198c1c61f44Ssb155480 boolean_t is_tagged, uint16_t vid);
199c1c61f44Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp);
200c1c61f44Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp);
201678453a8Sspeer
2027bd3a2e2SSriharsha Basavapatna /* Exported functions */
2037bd3a2e2SSriharsha Basavapatna int vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller);
2047bd3a2e2SSriharsha Basavapatna int vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
2057bd3a2e2SSriharsha Basavapatna void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
2067bd3a2e2SSriharsha Basavapatna void vgen_destroy_rxpools(void *arg);
2077bd3a2e2SSriharsha Basavapatna
2087bd3a2e2SSriharsha Basavapatna /* Externs */
209678453a8Sspeer extern void vnet_dds_rx(void *arg, void *dmsg);
2106d6de4eeSWENTAO YANG extern void vnet_dds_cleanup_hio(vnet_t *vnetp);
2117b1f684aSSriharsha Basavapatna extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
2121107ea93SSriharsha Basavapatna extern void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
2137bd3a2e2SSriharsha Basavapatna extern int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen,
2147bd3a2e2SSriharsha Basavapatna boolean_t caller_holds_lock);
2157bd3a2e2SSriharsha Basavapatna extern void vgen_stop_msg_thread(vgen_ldc_t *ldcp);
2167bd3a2e2SSriharsha Basavapatna extern int vgen_create_tx_dring(vgen_ldc_t *ldcp);
2177bd3a2e2SSriharsha Basavapatna extern void vgen_destroy_tx_dring(vgen_ldc_t *ldcp);
2187bd3a2e2SSriharsha Basavapatna extern int vgen_map_rx_dring(vgen_ldc_t *ldcp, void *pkt);
2197bd3a2e2SSriharsha Basavapatna extern void vgen_unmap_rx_dring(vgen_ldc_t *ldcp);
2207bd3a2e2SSriharsha Basavapatna extern int vgen_create_rx_dring(vgen_ldc_t *ldcp);
2217bd3a2e2SSriharsha Basavapatna extern void vgen_destroy_rx_dring(vgen_ldc_t *ldcp);
2227bd3a2e2SSriharsha Basavapatna extern int vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt);
2237bd3a2e2SSriharsha Basavapatna extern void vgen_unmap_tx_dring(vgen_ldc_t *ldcp);
2247bd3a2e2SSriharsha Basavapatna extern int vgen_map_data(vgen_ldc_t *ldcp, void *pkt);
2257bd3a2e2SSriharsha Basavapatna extern int vgen_handle_dringdata_shm(void *arg1, void *arg2);
2267bd3a2e2SSriharsha Basavapatna extern int vgen_handle_dringdata(void *arg1, void *arg2);
2277bd3a2e2SSriharsha Basavapatna extern int vgen_dringsend_shm(void *arg, mblk_t *mp);
2287bd3a2e2SSriharsha Basavapatna extern int vgen_dringsend(void *arg, mblk_t *mp);
2297bd3a2e2SSriharsha Basavapatna extern void vgen_ldc_msg_worker(void *arg);
2307bd3a2e2SSriharsha Basavapatna extern int vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
2317bd3a2e2SSriharsha Basavapatna uint32_t start, int32_t end, uint8_t pstate);
2327bd3a2e2SSriharsha Basavapatna extern mblk_t *vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup);
2337bd3a2e2SSriharsha Basavapatna extern mblk_t *vgen_poll_rcv(vgen_ldc_t *ldcp, int bytes_to_pickup);
2347bd3a2e2SSriharsha Basavapatna extern int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
2351ae08745Sheppo
236f0ca1d9aSsb155480 #define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0)
237f0ca1d9aSsb155480
2381ae08745Sheppo #define LDC_LOCK(ldcp) \
2391ae08745Sheppo mutex_enter(&((ldcp)->cblock));\
240844e62a3Sraghuram mutex_enter(&((ldcp)->rxlock));\
241844e62a3Sraghuram mutex_enter(&((ldcp)->wrlock));\
2421ae08745Sheppo mutex_enter(&((ldcp)->txlock));\
2431ae08745Sheppo mutex_enter(&((ldcp)->tclock));
2441ae08745Sheppo #define LDC_UNLOCK(ldcp) \
2451ae08745Sheppo mutex_exit(&((ldcp)->tclock));\
2461ae08745Sheppo mutex_exit(&((ldcp)->txlock));\
247844e62a3Sraghuram mutex_exit(&((ldcp)->wrlock));\
248844e62a3Sraghuram mutex_exit(&((ldcp)->rxlock));\
2491ae08745Sheppo mutex_exit(&((ldcp)->cblock));
2501ae08745Sheppo
251c1c61f44Ssb155480 #define VGEN_VER_EQ(ldcp, major, minor) \
252c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
253c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor == (minor))
254c1c61f44Ssb155480
255c1c61f44Ssb155480 #define VGEN_VER_LT(ldcp, major, minor) \
256c1c61f44Ssb155480 (((ldcp)->local_hparams.ver_major < (major)) || \
257c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
258c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor < (minor)))
259c1c61f44Ssb155480
260c1c61f44Ssb155480 #define VGEN_VER_GTEQ(ldcp, major, minor) \
261c1c61f44Ssb155480 (((ldcp)->local_hparams.ver_major > (major)) || \
262c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
263c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor >= (minor)))
264c1c61f44Ssb155480
2651ae08745Sheppo /*
2661ae08745Sheppo * Property names
2671ae08745Sheppo */
2681ae08745Sheppo static char macaddr_propname[] = "mac-address";
2691ae08745Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2701ae08745Sheppo static char channel_propname[] = "channel-endpoint";
2711ae08745Sheppo static char reg_propname[] = "reg";
2721ae08745Sheppo static char port_propname[] = "port";
2731ae08745Sheppo static char swport_propname[] = "switch-port";
2741ae08745Sheppo static char id_propname[] = "id";
275f0ca1d9aSsb155480 static char vdev_propname[] = "virtual-device";
276f0ca1d9aSsb155480 static char vnet_propname[] = "network";
277f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types";
278c1c61f44Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id";
279c1c61f44Ssb155480 static char vgen_vid_propname[] = "vlan-id";
280c1c61f44Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id";
281c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id";
282c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id";
2837b1f684aSSriharsha Basavapatna static char vgen_mtu_propname[] = "mtu";
2841107ea93SSriharsha Basavapatna static char vgen_linkprop_propname[] = "linkprop";
2851ae08745Sheppo
2861107ea93SSriharsha Basavapatna /*
2871107ea93SSriharsha Basavapatna * VIO Protocol Version Info:
2881107ea93SSriharsha Basavapatna *
2891107ea93SSriharsha Basavapatna * The version specified below represents the version of protocol currently
2901107ea93SSriharsha Basavapatna * supported in the driver. It means the driver can negotiate with peers with
2911107ea93SSriharsha Basavapatna * versions <= this version. Here is a summary of the feature(s) that are
2921107ea93SSriharsha Basavapatna * supported at each version of the protocol:
2931107ea93SSriharsha Basavapatna *
2941107ea93SSriharsha Basavapatna * 1.0 Basic VIO protocol.
2951107ea93SSriharsha Basavapatna * 1.1 vDisk protocol update (no virtual network update).
2961107ea93SSriharsha Basavapatna * 1.2 Support for priority frames (priority-ether-types).
2971107ea93SSriharsha Basavapatna * 1.3 VLAN and HybridIO support.
2981107ea93SSriharsha Basavapatna * 1.4 Jumbo Frame support.
2991107ea93SSriharsha Basavapatna * 1.5 Link State Notification support with optional support
3001107ea93SSriharsha Basavapatna * for Physical Link information.
3017bd3a2e2SSriharsha Basavapatna * 1.6 Support for RxDringData mode.
3021107ea93SSriharsha Basavapatna */
3037bd3a2e2SSriharsha Basavapatna static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 6} };
3041ae08745Sheppo
3051ae08745Sheppo /* Tunables */
30619b65a69Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */
3071ae08745Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */
3088e6a2a04Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */
309195ce4e5SSriharsha Basavapatna uint32_t vgen_ldccl_retries = 5; /* max # of ldc_close() retries */
31061a70d81Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */
3117bd3a2e2SSriharsha Basavapatna uint32_t vgen_ldc_mtu = VGEN_LDC_MTU; /* ldc mtu */
3127bd3a2e2SSriharsha Basavapatna uint32_t vgen_txwd_interval = VGEN_TXWD_INTERVAL; /* watchdog freq in msec */
3137bd3a2e2SSriharsha Basavapatna uint32_t vgen_txwd_timeout = VGEN_TXWD_TIMEOUT; /* tx timeout in msec */
3146f09f0feSWENTAO YANG
315844e62a3Sraghuram /*
3167bd3a2e2SSriharsha Basavapatna * Max # of channel resets allowed during handshake.
3177bd3a2e2SSriharsha Basavapatna */
3187bd3a2e2SSriharsha Basavapatna uint32_t vgen_ldc_max_resets = 5;
3197bd3a2e2SSriharsha Basavapatna
3207bd3a2e2SSriharsha Basavapatna /*
3217bd3a2e2SSriharsha Basavapatna * See comments in vsw.c for details on the dring modes supported.
3227bd3a2e2SSriharsha Basavapatna * In RxDringData mode, # of buffers is determined by multiplying the # of
3237bd3a2e2SSriharsha Basavapatna * descriptors with the factor below. Note that the factor must be > 1; i.e,
3247bd3a2e2SSriharsha Basavapatna * the # of buffers must always be > # of descriptors. This is needed because,
3257bd3a2e2SSriharsha Basavapatna * while the shared memory buffers are sent up the stack on the receiver, the
3267bd3a2e2SSriharsha Basavapatna * sender needs additional buffers that can be used for further transmits.
3277bd3a2e2SSriharsha Basavapatna * See vgen_create_rx_dring() for details.
3287bd3a2e2SSriharsha Basavapatna */
3297bd3a2e2SSriharsha Basavapatna uint32_t vgen_nrbufs_factor = 2;
3307bd3a2e2SSriharsha Basavapatna
3317bd3a2e2SSriharsha Basavapatna /*
3327bd3a2e2SSriharsha Basavapatna * Retry delay used while destroying rx mblk pools. Used in both Dring modes.
3337bd3a2e2SSriharsha Basavapatna */
3347bd3a2e2SSriharsha Basavapatna int vgen_rxpool_cleanup_delay = 100000; /* 100ms */
3357bd3a2e2SSriharsha Basavapatna
3367bd3a2e2SSriharsha Basavapatna /*
3377bd3a2e2SSriharsha Basavapatna * Delay when rx descr not ready; used in TxDring mode only.
3387bd3a2e2SSriharsha Basavapatna */
3397bd3a2e2SSriharsha Basavapatna uint32_t vgen_recv_delay = 1;
3407bd3a2e2SSriharsha Basavapatna
3417bd3a2e2SSriharsha Basavapatna /*
3427bd3a2e2SSriharsha Basavapatna * Retry when rx descr not ready; used in TxDring mode only.
3437bd3a2e2SSriharsha Basavapatna */
3447bd3a2e2SSriharsha Basavapatna uint32_t vgen_recv_retries = 10;
3457bd3a2e2SSriharsha Basavapatna
3467bd3a2e2SSriharsha Basavapatna /*
3477bd3a2e2SSriharsha Basavapatna * Max # of packets accumulated prior to sending them up. It is best
3487bd3a2e2SSriharsha Basavapatna * to keep this at 60% of the number of receive buffers. Used in TxDring mode
3497bd3a2e2SSriharsha Basavapatna * by the msg worker thread. Used in RxDringData mode while in interrupt mode
3507bd3a2e2SSriharsha Basavapatna * (not used in polled mode).
351844e62a3Sraghuram */
352844e62a3Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6);
353844e62a3Sraghuram
354844e62a3Sraghuram /*
3557b1f684aSSriharsha Basavapatna * Internal tunables for receive buffer pools, that is, the size and number of
3567b1f684aSSriharsha Basavapatna * mblks for each pool. At least 3 sizes must be specified if these are used.
3577b1f684aSSriharsha Basavapatna * The sizes must be specified in increasing order. Non-zero value of the first
3587b1f684aSSriharsha Basavapatna * size will be used as a hint to use these values instead of the algorithm
3597bd3a2e2SSriharsha Basavapatna * that determines the sizes based on MTU. Used in TxDring mode only.
360844e62a3Sraghuram */
3617b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz1 = 0;
3627b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz2 = 0;
3637b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz3 = 0;
3647b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz4 = 0;
365844e62a3Sraghuram
366844e62a3Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS;
367844e62a3Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS;
368844e62a3Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS;
3697b1f684aSSriharsha Basavapatna uint32_t vgen_nrbufs4 = VGEN_NRBUFS;
370844e62a3Sraghuram
371f0ca1d9aSsb155480 /*
372f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following
373f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype.
374f0ca1d9aSsb155480 */
375f0ca1d9aSsb155480 uint64_t vgen_pri_eth_type = 0;
376f0ca1d9aSsb155480
377f0ca1d9aSsb155480 /*
378f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device.
379f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission
380f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks().
381f0ca1d9aSsb155480 */
382f0ca1d9aSsb155480 uint32_t vgen_pri_tx_nmblks = 64;
383f0ca1d9aSsb155480
384c1c61f44Ssb155480 uint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */
385c1c61f44Ssb155480
386c1c61f44Ssb155480 /*
387c1c61f44Ssb155480 * Matching criteria passed to the MDEG to register interest
388c1c61f44Ssb155480 * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified
389c1c61f44Ssb155480 * by their 'name' and 'cfg-handle' properties.
390c1c61f44Ssb155480 */
391c1c61f44Ssb155480 static md_prop_match_t vdev_prop_match[] = {
392c1c61f44Ssb155480 { MDET_PROP_STR, "name" },
393c1c61f44Ssb155480 { MDET_PROP_VAL, "cfg-handle" },
394c1c61f44Ssb155480 { MDET_LIST_END, NULL }
395c1c61f44Ssb155480 };
396c1c61f44Ssb155480
397c1c61f44Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device",
398c1c61f44Ssb155480 vdev_prop_match };
399c1c61f44Ssb155480
4001ae08745Sheppo /* MD update matching structure */
4011ae08745Sheppo static md_prop_match_t vport_prop_match[] = {
4021ae08745Sheppo { MDET_PROP_VAL, "id" },
4031ae08745Sheppo { MDET_LIST_END, NULL }
4041ae08745Sheppo };
4051ae08745Sheppo
4061ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
4071ae08745Sheppo vport_prop_match };
4081ae08745Sheppo
4097bd3a2e2SSriharsha Basavapatna /* Template for matching a particular vnet instance */
4101ae08745Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
4111ae08745Sheppo { MDET_PROP_STR, "name", "network" },
4121ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL },
4131ae08745Sheppo { MDET_LIST_END, NULL, NULL }
4141ae08745Sheppo };
4151ae08745Sheppo
4161ae08745Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val)
4171ae08745Sheppo
418c1c61f44Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
4191ae08745Sheppo
4201107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG
4211107ea93SSriharsha Basavapatna #define VGEN_M_CALLBACK_FLAGS (MC_IOCTL)
4221107ea93SSriharsha Basavapatna #else
4231107ea93SSriharsha Basavapatna #define VGEN_M_CALLBACK_FLAGS (0)
4241107ea93SSriharsha Basavapatna #endif
4251107ea93SSriharsha Basavapatna
426ba2e4443Sseb static mac_callbacks_t vgen_m_callbacks = {
4271107ea93SSriharsha Basavapatna VGEN_M_CALLBACK_FLAGS,
428ba2e4443Sseb vgen_stat,
429ba2e4443Sseb vgen_start,
430ba2e4443Sseb vgen_stop,
431ba2e4443Sseb vgen_promisc,
432ba2e4443Sseb vgen_multicst,
433ba2e4443Sseb vgen_unicst,
434ba2e4443Sseb vgen_tx,
4350dc2366fSVenugopal Iyer NULL,
4361107ea93SSriharsha Basavapatna vgen_ioctl,
437ba2e4443Sseb NULL,
438ba2e4443Sseb NULL
439ba2e4443Sseb };
440ba2e4443Sseb
4417bd3a2e2SSriharsha Basavapatna /* Externs */
442844e62a3Sraghuram extern pri_t maxclsyspri;
443844e62a3Sraghuram extern proc_t p0;
444c1c61f44Ssb155480 extern uint32_t vnet_ethermtu;
445c1c61f44Ssb155480 extern uint16_t vnet_default_vlan_id;
446*34f94fbcSWENTAO YANG extern uint32_t vnet_num_descriptors;
4471ae08745Sheppo
4481ae08745Sheppo #ifdef DEBUG
4491ae08745Sheppo
4507bd3a2e2SSriharsha Basavapatna #define DEBUG_PRINTF vgen_debug_printf
4517bd3a2e2SSriharsha Basavapatna
452844e62a3Sraghuram extern int vnet_dbglevel;
4537bd3a2e2SSriharsha Basavapatna
4547bd3a2e2SSriharsha Basavapatna void vgen_debug_printf(const char *fname, vgen_t *vgenp,
455844e62a3Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...);
4561ae08745Sheppo
457844e62a3Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */
458844e62a3Sraghuram int vgendbg_ldcid = -1;
4591ae08745Sheppo
4607bd3a2e2SSriharsha Basavapatna /* Flags to simulate error conditions for debugging */
4617bd3a2e2SSriharsha Basavapatna int vgen_inject_err_flag = 0;
4627bd3a2e2SSriharsha Basavapatna
4637bd3a2e2SSriharsha Basavapatna
4647bd3a2e2SSriharsha Basavapatna boolean_t
vgen_inject_error(vgen_ldc_t * ldcp,int error)4657bd3a2e2SSriharsha Basavapatna vgen_inject_error(vgen_ldc_t *ldcp, int error)
4667bd3a2e2SSriharsha Basavapatna {
4677bd3a2e2SSriharsha Basavapatna if ((vgendbg_ldcid == ldcp->ldc_id) &&
4687bd3a2e2SSriharsha Basavapatna (vgen_inject_err_flag & error)) {
4697bd3a2e2SSriharsha Basavapatna return (B_TRUE);
4707bd3a2e2SSriharsha Basavapatna }
4717bd3a2e2SSriharsha Basavapatna return (B_FALSE);
4727bd3a2e2SSriharsha Basavapatna }
4731ae08745Sheppo
4741ae08745Sheppo #endif
4751ae08745Sheppo
4761ae08745Sheppo /*
4771ae08745Sheppo * vgen_init() is called by an instance of vnet driver to initialize the
4787bd3a2e2SSriharsha Basavapatna * corresponding generic transport layer. This layer uses Logical Domain
4797bd3a2e2SSriharsha Basavapatna * Channels (LDCs) to communicate with the virtual switch in the service domain
4807bd3a2e2SSriharsha Basavapatna * and also with peer vnets in other guest domains in the system.
4817bd3a2e2SSriharsha Basavapatna *
4827bd3a2e2SSriharsha Basavapatna * Arguments:
4837bd3a2e2SSriharsha Basavapatna * vnetp: an opaque pointer to the vnet instance
4847bd3a2e2SSriharsha Basavapatna * regprop: frame to be transmitted
4857bd3a2e2SSriharsha Basavapatna * vnetdip: dip of the vnet device
4867bd3a2e2SSriharsha Basavapatna * macaddr: mac address of the vnet device
4877bd3a2e2SSriharsha Basavapatna *
4887bd3a2e2SSriharsha Basavapatna * Returns:
4897bd3a2e2SSriharsha Basavapatna * Sucess: a handle to the vgen instance (vgen_t)
4907bd3a2e2SSriharsha Basavapatna * Failure: NULL
4911ae08745Sheppo */
4921ae08745Sheppo int
vgen_init(void * vnetp,uint64_t regprop,dev_info_t * vnetdip,const uint8_t * macaddr,void ** vgenhdl)493678453a8Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
494678453a8Sspeer const uint8_t *macaddr, void **vgenhdl)
4951ae08745Sheppo {
4961ae08745Sheppo vgen_t *vgenp;
4971ae08745Sheppo int instance;
498f0ca1d9aSsb155480 int rv;
4997bd3a2e2SSriharsha Basavapatna char qname[TASKQ_NAMELEN];
5001ae08745Sheppo
501ba2e4443Sseb if ((vnetp == NULL) || (vnetdip == NULL))
5021ae08745Sheppo return (DDI_FAILURE);
5031ae08745Sheppo
5041ae08745Sheppo instance = ddi_get_instance(vnetdip);
5051ae08745Sheppo
50606db247cSraghuram DBG1(NULL, NULL, "vnet(%d): enter\n", instance);
5071ae08745Sheppo
5081ae08745Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
5091ae08745Sheppo
5101ae08745Sheppo vgenp->vnetp = vnetp;
511678453a8Sspeer vgenp->instance = instance;
512678453a8Sspeer vgenp->regprop = regprop;
5131ae08745Sheppo vgenp->vnetdip = vnetdip;
5141ae08745Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
5151107ea93SSriharsha Basavapatna vgenp->phys_link_state = LINK_STATE_UNKNOWN;
5161ae08745Sheppo
5171ae08745Sheppo /* allocate multicast table */
5181ae08745Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
5191ae08745Sheppo sizeof (struct ether_addr), KM_SLEEP);
5201ae08745Sheppo vgenp->mccount = 0;
5211ae08745Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
5221ae08745Sheppo
5231ae08745Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
52493b13a42Swentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL);
5251ae08745Sheppo
5267bd3a2e2SSriharsha Basavapatna (void) snprintf(qname, TASKQ_NAMELEN, "rxpool_taskq%d",
5277bd3a2e2SSriharsha Basavapatna instance);
5287bd3a2e2SSriharsha Basavapatna if ((vgenp->rxp_taskq = ddi_taskq_create(vnetdip, qname, 1,
5297bd3a2e2SSriharsha Basavapatna TASKQ_DEFAULTPRI, 0)) == NULL) {
5307bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "!vnet%d: Unable to create rx pool task queue",
5317bd3a2e2SSriharsha Basavapatna instance);
5327bd3a2e2SSriharsha Basavapatna goto vgen_init_fail;
5337bd3a2e2SSriharsha Basavapatna }
5347bd3a2e2SSriharsha Basavapatna
535f0ca1d9aSsb155480 rv = vgen_read_mdprops(vgenp);
536f0ca1d9aSsb155480 if (rv != 0) {
537f0ca1d9aSsb155480 goto vgen_init_fail;
538f0ca1d9aSsb155480 }
539678453a8Sspeer *vgenhdl = (void *)vgenp;
5401ae08745Sheppo
54106db247cSraghuram DBG1(NULL, NULL, "vnet(%d): exit\n", instance);
5421ae08745Sheppo return (DDI_SUCCESS);
543f0ca1d9aSsb155480
544f0ca1d9aSsb155480 vgen_init_fail:
545f0ca1d9aSsb155480 rw_destroy(&vgenp->vgenports.rwlock);
546f0ca1d9aSsb155480 mutex_destroy(&vgenp->lock);
547f0ca1d9aSsb155480 kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
548f0ca1d9aSsb155480 sizeof (struct ether_addr));
549f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
550f0ca1d9aSsb155480 kmem_free(vgenp->pri_types,
551f0ca1d9aSsb155480 sizeof (uint16_t) * vgenp->pri_num_types);
552f0ca1d9aSsb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp);
553f0ca1d9aSsb155480 }
5547bd3a2e2SSriharsha Basavapatna if (vgenp->rxp_taskq != NULL) {
5557bd3a2e2SSriharsha Basavapatna ddi_taskq_destroy(vgenp->rxp_taskq);
5567bd3a2e2SSriharsha Basavapatna vgenp->rxp_taskq = NULL;
5577bd3a2e2SSriharsha Basavapatna }
558f0ca1d9aSsb155480 KMEM_FREE(vgenp);
559f0ca1d9aSsb155480 return (DDI_FAILURE);
5601ae08745Sheppo }
5611ae08745Sheppo
56263f531d1SSriharsha Basavapatna int
vgen_init_mdeg(void * arg)56363f531d1SSriharsha Basavapatna vgen_init_mdeg(void *arg)
56463f531d1SSriharsha Basavapatna {
56563f531d1SSriharsha Basavapatna vgen_t *vgenp = (vgen_t *)arg;
56663f531d1SSriharsha Basavapatna
56763f531d1SSriharsha Basavapatna /* register with MD event generator */
56863f531d1SSriharsha Basavapatna return (vgen_mdeg_reg(vgenp));
56963f531d1SSriharsha Basavapatna }
57063f531d1SSriharsha Basavapatna
5711ae08745Sheppo /*
5721ae08745Sheppo * Called by vnet to undo the initializations done by vgen_init().
5731ae08745Sheppo * The handle provided by generic transport during vgen_init() is the argument.
5741ae08745Sheppo */
5753ab636deSWENTAO YANG void
vgen_uninit(void * arg)5761ae08745Sheppo vgen_uninit(void *arg)
5771ae08745Sheppo {
5781ae08745Sheppo vgen_t *vgenp = (vgen_t *)arg;
5791ae08745Sheppo
580d10e4ef2Snarayan if (vgenp == NULL) {
5813ab636deSWENTAO YANG return;
582d10e4ef2Snarayan }
5831ae08745Sheppo
584844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n");
5851ae08745Sheppo
5867bd3a2e2SSriharsha Basavapatna /* Unregister with MD event generator */
5871ae08745Sheppo vgen_mdeg_unreg(vgenp);
5881ae08745Sheppo
5891ae08745Sheppo mutex_enter(&vgenp->lock);
5901ae08745Sheppo
5917bd3a2e2SSriharsha Basavapatna /*
5927bd3a2e2SSriharsha Basavapatna * Detach all ports from the device; note that the device should have
5937bd3a2e2SSriharsha Basavapatna * been unplumbed by this time (See vnet_unattach() for the sequence)
5947bd3a2e2SSriharsha Basavapatna * and thus vgen_stop() has already been invoked on all the ports.
5957bd3a2e2SSriharsha Basavapatna */
5961ae08745Sheppo vgen_detach_ports(vgenp);
5971ae08745Sheppo
598d10e4ef2Snarayan /*
5997bd3a2e2SSriharsha Basavapatna * We now destroy the taskq used to clean up rx mblk pools that
6007bd3a2e2SSriharsha Basavapatna * couldn't be destroyed when the ports/channels were detached.
6017bd3a2e2SSriharsha Basavapatna * We implicitly wait for those tasks to complete in
6027bd3a2e2SSriharsha Basavapatna * ddi_taskq_destroy().
603d10e4ef2Snarayan */
6047bd3a2e2SSriharsha Basavapatna if (vgenp->rxp_taskq != NULL) {
6057bd3a2e2SSriharsha Basavapatna ddi_taskq_destroy(vgenp->rxp_taskq);
6067bd3a2e2SSriharsha Basavapatna vgenp->rxp_taskq = NULL;
607d10e4ef2Snarayan }
608d10e4ef2Snarayan
6097bd3a2e2SSriharsha Basavapatna /* Free multicast table */
6101ae08745Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
6111ae08745Sheppo
6127bd3a2e2SSriharsha Basavapatna /* Free pri_types table */
613f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
614f0ca1d9aSsb155480 kmem_free(vgenp->pri_types,
615f0ca1d9aSsb155480 sizeof (uint16_t) * vgenp->pri_num_types);
616f0ca1d9aSsb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp);
617f0ca1d9aSsb155480 }
618f0ca1d9aSsb155480
6191ae08745Sheppo mutex_exit(&vgenp->lock);
62093b13a42Swentaoy rw_destroy(&vgenp->vgenports.rwlock);
6211ae08745Sheppo mutex_destroy(&vgenp->lock);
6221ae08745Sheppo
623844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n");
62452bca946SWENTAO YANG KMEM_FREE(vgenp);
6251ae08745Sheppo }
6261ae08745Sheppo
6271ae08745Sheppo /* enable transmit/receive for the device */
628ba2e4443Sseb int
vgen_start(void * arg)6291ae08745Sheppo vgen_start(void *arg)
6301ae08745Sheppo {
631678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
632678453a8Sspeer vgen_t *vgenp = portp->vgenp;
6331ae08745Sheppo
634844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n");
635678453a8Sspeer mutex_enter(&portp->lock);
636678453a8Sspeer vgen_port_init(portp);
637678453a8Sspeer portp->flags |= VGEN_STARTED;
638678453a8Sspeer mutex_exit(&portp->lock);
639844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n");
640678453a8Sspeer
6411ae08745Sheppo return (DDI_SUCCESS);
6421ae08745Sheppo }
6431ae08745Sheppo
6441ae08745Sheppo /* stop transmit/receive */
645ba2e4443Sseb void
vgen_stop(void * arg)6461ae08745Sheppo vgen_stop(void *arg)
6471ae08745Sheppo {
648678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
649678453a8Sspeer vgen_t *vgenp = portp->vgenp;
6501ae08745Sheppo
651844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n");
6521ae08745Sheppo
653678453a8Sspeer mutex_enter(&portp->lock);
6540c4606f0SWENTAO YANG if (portp->flags & VGEN_STARTED) {
655678453a8Sspeer vgen_port_uninit(portp);
656678453a8Sspeer portp->flags &= ~(VGEN_STARTED);
6570c4606f0SWENTAO YANG }
658678453a8Sspeer mutex_exit(&portp->lock);
659844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n");
660678453a8Sspeer
6611ae08745Sheppo }
6621ae08745Sheppo
6631ae08745Sheppo /* vgen transmit function */
6641ae08745Sheppo static mblk_t *
vgen_tx(void * arg,mblk_t * mp)6651ae08745Sheppo vgen_tx(void *arg, mblk_t *mp)
6661ae08745Sheppo {
6671ae08745Sheppo vgen_port_t *portp;
6687bd3a2e2SSriharsha Basavapatna int status;
6691ae08745Sheppo
6701ae08745Sheppo portp = (vgen_port_t *)arg;
6711ae08745Sheppo status = vgen_portsend(portp, mp);
6721ae08745Sheppo if (status != VGEN_SUCCESS) {
6731ae08745Sheppo /* failure */
6741ae08745Sheppo return (mp);
6751ae08745Sheppo }
6761ae08745Sheppo /* success */
6771ae08745Sheppo return (NULL);
6781ae08745Sheppo }
6791ae08745Sheppo
680c1c61f44Ssb155480 /*
681c1c61f44Ssb155480 * This function provides any necessary tagging/untagging of the frames
682c1c61f44Ssb155480 * that are being transmitted over the port. It first verifies the vlan
683c1c61f44Ssb155480 * membership of the destination(port) and drops the packet if the
684c1c61f44Ssb155480 * destination doesn't belong to the given vlan.
685c1c61f44Ssb155480 *
686c1c61f44Ssb155480 * Arguments:
687c1c61f44Ssb155480 * portp: port over which the frames should be transmitted
688c1c61f44Ssb155480 * mp: frame to be transmitted
689c1c61f44Ssb155480 * is_tagged:
690c1c61f44Ssb155480 * B_TRUE: indicates frame header contains the vlan tag already.
691c1c61f44Ssb155480 * B_FALSE: indicates frame is untagged.
692c1c61f44Ssb155480 * vid: vlan in which the frame should be transmitted.
693c1c61f44Ssb155480 *
694c1c61f44Ssb155480 * Returns:
695c1c61f44Ssb155480 * Sucess: frame(mblk_t *) after doing the necessary tag/untag.
696c1c61f44Ssb155480 * Failure: NULL
697c1c61f44Ssb155480 */
698c1c61f44Ssb155480 static mblk_t *
vgen_vlan_frame_fixtag(vgen_port_t * portp,mblk_t * mp,boolean_t is_tagged,uint16_t vid)699c1c61f44Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged,
700c1c61f44Ssb155480 uint16_t vid)
701c1c61f44Ssb155480 {
702c1c61f44Ssb155480 vgen_t *vgenp;
703c1c61f44Ssb155480 boolean_t dst_tagged;
704c1c61f44Ssb155480 int rv;
705c1c61f44Ssb155480
706c1c61f44Ssb155480 vgenp = portp->vgenp;
707c1c61f44Ssb155480
708c1c61f44Ssb155480 /*
709c1c61f44Ssb155480 * If the packet is going to a vnet:
710c1c61f44Ssb155480 * Check if the destination vnet is in the same vlan.
711c1c61f44Ssb155480 * Check the frame header if tag or untag is needed.
712c1c61f44Ssb155480 *
713c1c61f44Ssb155480 * We do not check the above conditions if the packet is going to vsw:
714c1c61f44Ssb155480 * vsw must be present implicitly in all the vlans that a vnet device
715c1c61f44Ssb155480 * is configured into; even if vsw itself is not assigned to those
716c1c61f44Ssb155480 * vlans as an interface. For instance, the packet might be destined
717c1c61f44Ssb155480 * to another vnet(indirectly through vsw) or to an external host
718c1c61f44Ssb155480 * which is in the same vlan as this vnet and vsw itself may not be
719c1c61f44Ssb155480 * present in that vlan. Similarly packets going to vsw must be
720c1c61f44Ssb155480 * always tagged(unless in the default-vlan) if not already tagged,
721c1c61f44Ssb155480 * as we do not know the final destination. This is needed because
722c1c61f44Ssb155480 * vsw must always invoke its switching function only after tagging
723c1c61f44Ssb155480 * the packet; otherwise after switching function determines the
724c1c61f44Ssb155480 * destination we cannot figure out if the destination belongs to the
725c1c61f44Ssb155480 * the same vlan that the frame originated from and if it needs tag/
726c1c61f44Ssb155480 * untag. Note that vsw will tag the packet itself when it receives
727c1c61f44Ssb155480 * it over the channel from a client if needed. However, that is
728c1c61f44Ssb155480 * needed only in the case of vlan unaware clients such as obp or
729c1c61f44Ssb155480 * earlier versions of vnet.
730c1c61f44Ssb155480 *
731c1c61f44Ssb155480 */
732c1c61f44Ssb155480 if (portp != vgenp->vsw_portp) {
733c1c61f44Ssb155480 /*
734c1c61f44Ssb155480 * Packet going to a vnet. Check if the destination vnet is in
735c1c61f44Ssb155480 * the same vlan. Then check the frame header if tag/untag is
736c1c61f44Ssb155480 * needed.
737c1c61f44Ssb155480 */
738c1c61f44Ssb155480 rv = vgen_vlan_lookup(portp->vlan_hashp, vid);
739c1c61f44Ssb155480 if (rv == B_FALSE) {
740c1c61f44Ssb155480 /* drop the packet */
741c1c61f44Ssb155480 freemsg(mp);
742c1c61f44Ssb155480 return (NULL);
743c1c61f44Ssb155480 }
744c1c61f44Ssb155480
745c1c61f44Ssb155480 /* is the destination tagged or untagged in this vlan? */
746c1c61f44Ssb155480 (vid == portp->pvid) ? (dst_tagged = B_FALSE) :
747c1c61f44Ssb155480 (dst_tagged = B_TRUE);
748c1c61f44Ssb155480
749c1c61f44Ssb155480 if (is_tagged == dst_tagged) {
750c1c61f44Ssb155480 /* no tagging/untagging needed */
751c1c61f44Ssb155480 return (mp);
752c1c61f44Ssb155480 }
753c1c61f44Ssb155480
754c1c61f44Ssb155480 if (is_tagged == B_TRUE) {
755c1c61f44Ssb155480 /* frame is tagged; destination needs untagged */
756c1c61f44Ssb155480 mp = vnet_vlan_remove_tag(mp);
757c1c61f44Ssb155480 return (mp);
758c1c61f44Ssb155480 }
759c1c61f44Ssb155480
760c1c61f44Ssb155480 /* (is_tagged == B_FALSE): fallthru to tag tx packet: */
761c1c61f44Ssb155480 }
762c1c61f44Ssb155480
763c1c61f44Ssb155480 /*
764c1c61f44Ssb155480 * Packet going to a vnet needs tagging.
765c1c61f44Ssb155480 * OR
766c1c61f44Ssb155480 * If the packet is going to vsw, then it must be tagged in all cases:
767c1c61f44Ssb155480 * unknown unicast, broadcast/multicast or to vsw interface.
768c1c61f44Ssb155480 */
769c1c61f44Ssb155480
770c1c61f44Ssb155480 if (is_tagged == B_FALSE) {
771c1c61f44Ssb155480 mp = vnet_vlan_insert_tag(mp, vid);
772c1c61f44Ssb155480 }
773c1c61f44Ssb155480
774c1c61f44Ssb155480 return (mp);
775c1c61f44Ssb155480 }
776c1c61f44Ssb155480
7771ae08745Sheppo /* transmit packets over the given port */
7781ae08745Sheppo static int
vgen_portsend(vgen_port_t * portp,mblk_t * mp)7791ae08745Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
7801ae08745Sheppo {
7811ae08745Sheppo vgen_ldc_t *ldcp;
7821ae08745Sheppo int status;
78361a70d81Sraghuram int rv = VGEN_SUCCESS;
784678453a8Sspeer vgen_t *vgenp = portp->vgenp;
785678453a8Sspeer vnet_t *vnetp = vgenp->vnetp;
786c1c61f44Ssb155480 boolean_t is_tagged;
787678453a8Sspeer boolean_t dec_refcnt = B_FALSE;
788c1c61f44Ssb155480 uint16_t vlan_id;
789c1c61f44Ssb155480 struct ether_header *ehp;
790c1c61f44Ssb155480
7917bd3a2e2SSriharsha Basavapatna if (portp == NULL) {
7927bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
7937bd3a2e2SSriharsha Basavapatna }
7947bd3a2e2SSriharsha Basavapatna
795678453a8Sspeer if (portp->use_vsw_port) {
796678453a8Sspeer (void) atomic_inc_32(&vgenp->vsw_port_refcnt);
797678453a8Sspeer portp = portp->vgenp->vsw_portp;
7987bd3a2e2SSriharsha Basavapatna ASSERT(portp != NULL);
799678453a8Sspeer dec_refcnt = B_TRUE;
800678453a8Sspeer }
801c1c61f44Ssb155480
802c1c61f44Ssb155480 /*
803c1c61f44Ssb155480 * Determine the vlan id that the frame belongs to.
804c1c61f44Ssb155480 */
805c1c61f44Ssb155480 ehp = (struct ether_header *)mp->b_rptr;
806c1c61f44Ssb155480 is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id);
807c1c61f44Ssb155480
808c1c61f44Ssb155480 if (vlan_id == vnetp->default_vlan_id) {
809c1c61f44Ssb155480
810c1c61f44Ssb155480 /* Frames in default vlan must be untagged */
811c1c61f44Ssb155480 ASSERT(is_tagged == B_FALSE);
812c1c61f44Ssb155480
813c1c61f44Ssb155480 /*
814c1c61f44Ssb155480 * If the destination is a vnet-port verify it belongs to the
815c1c61f44Ssb155480 * default vlan; otherwise drop the packet. We do not need
816c1c61f44Ssb155480 * this check for vsw-port, as it should implicitly belong to
817c1c61f44Ssb155480 * this vlan; see comments in vgen_vlan_frame_fixtag().
818c1c61f44Ssb155480 */
819c1c61f44Ssb155480 if (portp != vgenp->vsw_portp &&
820c1c61f44Ssb155480 portp->pvid != vnetp->default_vlan_id) {
821c1c61f44Ssb155480 freemsg(mp);
822678453a8Sspeer goto portsend_ret;
823c1c61f44Ssb155480 }
824c1c61f44Ssb155480
825c1c61f44Ssb155480 } else { /* frame not in default-vlan */
826c1c61f44Ssb155480
827c1c61f44Ssb155480 mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id);
828c1c61f44Ssb155480 if (mp == NULL) {
829678453a8Sspeer goto portsend_ret;
830c1c61f44Ssb155480 }
831c1c61f44Ssb155480
832c1c61f44Ssb155480 }
8331ae08745Sheppo
8347bd3a2e2SSriharsha Basavapatna ldcp = portp->ldcp;
835f0ca1d9aSsb155480 status = ldcp->tx(ldcp, mp);
83661a70d81Sraghuram
83761a70d81Sraghuram if (status != VGEN_TX_SUCCESS) {
83861a70d81Sraghuram rv = VGEN_FAILURE;
83961a70d81Sraghuram }
840678453a8Sspeer
841678453a8Sspeer portsend_ret:
842678453a8Sspeer if (dec_refcnt == B_TRUE) {
843678453a8Sspeer (void) atomic_dec_32(&vgenp->vsw_port_refcnt);
844678453a8Sspeer }
84561a70d81Sraghuram return (rv);
8461ae08745Sheppo }
8471ae08745Sheppo
848f0ca1d9aSsb155480 /*
849f0ca1d9aSsb155480 * Wrapper function to transmit normal and/or priority frames over the channel.
850f0ca1d9aSsb155480 */
8511ae08745Sheppo static int
vgen_ldcsend(void * arg,mblk_t * mp)852f0ca1d9aSsb155480 vgen_ldcsend(void *arg, mblk_t *mp)
8531ae08745Sheppo {
854f0ca1d9aSsb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
855f0ca1d9aSsb155480 int status;
856f0ca1d9aSsb155480 struct ether_header *ehp;
857f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
858f0ca1d9aSsb155480 uint32_t num_types;
859f0ca1d9aSsb155480 uint16_t *types;
860f0ca1d9aSsb155480 int i;
861f0ca1d9aSsb155480
862f0ca1d9aSsb155480 ASSERT(VGEN_PRI_ETH_DEFINED(vgenp));
863f0ca1d9aSsb155480
864f0ca1d9aSsb155480 num_types = vgenp->pri_num_types;
865f0ca1d9aSsb155480 types = vgenp->pri_types;
866f0ca1d9aSsb155480 ehp = (struct ether_header *)mp->b_rptr;
867f0ca1d9aSsb155480
868f0ca1d9aSsb155480 for (i = 0; i < num_types; i++) {
869f0ca1d9aSsb155480
870f0ca1d9aSsb155480 if (ehp->ether_type == types[i]) {
871f0ca1d9aSsb155480 /* priority frame, use pri tx function */
872f0ca1d9aSsb155480 vgen_ldcsend_pkt(ldcp, mp);
873f0ca1d9aSsb155480 return (VGEN_SUCCESS);
874f0ca1d9aSsb155480 }
875f0ca1d9aSsb155480
876f0ca1d9aSsb155480 }
877f0ca1d9aSsb155480
8787bd3a2e2SSriharsha Basavapatna if (ldcp->tx_dringdata == NULL) {
8797bd3a2e2SSriharsha Basavapatna freemsg(mp);
8807bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
8817bd3a2e2SSriharsha Basavapatna }
882f0ca1d9aSsb155480
8837bd3a2e2SSriharsha Basavapatna status = ldcp->tx_dringdata(ldcp, mp);
884f0ca1d9aSsb155480 return (status);
885f0ca1d9aSsb155480 }
886f0ca1d9aSsb155480
887f0ca1d9aSsb155480 /*
888f0ca1d9aSsb155480 * This function transmits the frame in the payload of a raw data
889f0ca1d9aSsb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
890f0ca1d9aSsb155480 * send special frames with high priorities, without going through
891f0ca1d9aSsb155480 * the normal data path which uses descriptor ring mechanism.
892f0ca1d9aSsb155480 */
893f0ca1d9aSsb155480 static void
vgen_ldcsend_pkt(void * arg,mblk_t * mp)894f0ca1d9aSsb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp)
895f0ca1d9aSsb155480 {
896f0ca1d9aSsb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
897f0ca1d9aSsb155480 vio_raw_data_msg_t *pkt;
898f0ca1d9aSsb155480 mblk_t *bp;
899f0ca1d9aSsb155480 mblk_t *nmp = NULL;
9007bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp;
901f0ca1d9aSsb155480 caddr_t dst;
902f0ca1d9aSsb155480 uint32_t mblksz;
903f0ca1d9aSsb155480 uint32_t size;
904f0ca1d9aSsb155480 uint32_t nbytes;
905f0ca1d9aSsb155480 int rv;
906f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
907f0ca1d9aSsb155480 vgen_stats_t *statsp = &ldcp->stats;
908f0ca1d9aSsb155480
909f0ca1d9aSsb155480 /* drop the packet if ldc is not up or handshake is not done */
910f0ca1d9aSsb155480 if (ldcp->ldc_status != LDC_UP) {
911f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
912f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
913f0ca1d9aSsb155480 ldcp->ldc_status);
914f0ca1d9aSsb155480 goto send_pkt_exit;
915f0ca1d9aSsb155480 }
916f0ca1d9aSsb155480
917f0ca1d9aSsb155480 if (ldcp->hphase != VH_DONE) {
918f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
919f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
920f0ca1d9aSsb155480 ldcp->hphase);
921f0ca1d9aSsb155480 goto send_pkt_exit;
922f0ca1d9aSsb155480 }
923f0ca1d9aSsb155480
924f0ca1d9aSsb155480 size = msgsize(mp);
925f0ca1d9aSsb155480
926f0ca1d9aSsb155480 /* frame size bigger than available payload len of raw data msg ? */
927f0ca1d9aSsb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
928f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
929f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
930f0ca1d9aSsb155480 goto send_pkt_exit;
931f0ca1d9aSsb155480 }
932f0ca1d9aSsb155480
933f0ca1d9aSsb155480 if (size < ETHERMIN)
934f0ca1d9aSsb155480 size = ETHERMIN;
935f0ca1d9aSsb155480
936f0ca1d9aSsb155480 /* alloc space for a raw data message */
9377bd3a2e2SSriharsha Basavapatna vmp = vio_allocb(vgenp->pri_tx_vmp);
9387bd3a2e2SSriharsha Basavapatna if (vmp == NULL) {
939f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
940f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "vio_allocb failed\n");
941f0ca1d9aSsb155480 goto send_pkt_exit;
9427bd3a2e2SSriharsha Basavapatna } else {
9437bd3a2e2SSriharsha Basavapatna nmp = vmp->mp;
944f0ca1d9aSsb155480 }
945f0ca1d9aSsb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
946f0ca1d9aSsb155480
947f0ca1d9aSsb155480 /* copy frame into the payload of raw data message */
948f0ca1d9aSsb155480 dst = (caddr_t)pkt->data;
949f0ca1d9aSsb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) {
950f0ca1d9aSsb155480 mblksz = MBLKL(bp);
951f0ca1d9aSsb155480 bcopy(bp->b_rptr, dst, mblksz);
952f0ca1d9aSsb155480 dst += mblksz;
953f0ca1d9aSsb155480 }
954f0ca1d9aSsb155480
9557bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA;
9567bd3a2e2SSriharsha Basavapatna
957f0ca1d9aSsb155480 /* setup the raw data msg */
958f0ca1d9aSsb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA;
959f0ca1d9aSsb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
960f0ca1d9aSsb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA;
961f0ca1d9aSsb155480 pkt->tag.vio_sid = ldcp->local_sid;
962f0ca1d9aSsb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size;
963f0ca1d9aSsb155480
964f0ca1d9aSsb155480 /* send the msg over ldc */
965f0ca1d9aSsb155480 rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE);
966f0ca1d9aSsb155480 if (rv != VGEN_SUCCESS) {
967f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
968f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "Error sending priority frame\n");
969f0ca1d9aSsb155480 if (rv == ECONNRESET) {
9707bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, VGEN_OTHER);
971f0ca1d9aSsb155480 }
972f0ca1d9aSsb155480 goto send_pkt_exit;
973f0ca1d9aSsb155480 }
974f0ca1d9aSsb155480
975f0ca1d9aSsb155480 /* update stats */
976f0ca1d9aSsb155480 (void) atomic_inc_64(&statsp->tx_pri_packets);
977f0ca1d9aSsb155480 (void) atomic_add_64(&statsp->tx_pri_bytes, size);
978f0ca1d9aSsb155480
979f0ca1d9aSsb155480 send_pkt_exit:
980f0ca1d9aSsb155480 if (nmp != NULL)
981f0ca1d9aSsb155480 freemsg(nmp);
982f0ca1d9aSsb155480 freemsg(mp);
983f0ca1d9aSsb155480 }
984f0ca1d9aSsb155480
985f0ca1d9aSsb155480 /*
9860c4606f0SWENTAO YANG * enable/disable a multicast address
9870c4606f0SWENTAO YANG * note that the cblock of the ldc channel connected to the vsw is used for
9880c4606f0SWENTAO YANG * synchronization of the mctab.
9890c4606f0SWENTAO YANG */
990ba2e4443Sseb int
vgen_multicst(void * arg,boolean_t add,const uint8_t * mca)9911ae08745Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
9921ae08745Sheppo {
9931ae08745Sheppo vgen_t *vgenp;
9941ae08745Sheppo vnet_mcast_msg_t mcastmsg;
9951ae08745Sheppo vio_msg_tag_t *tagp;
9961ae08745Sheppo vgen_port_t *portp;
9971ae08745Sheppo vgen_ldc_t *ldcp;
9981ae08745Sheppo struct ether_addr *addrp;
999bd8f0338Snarayan int rv = DDI_FAILURE;
10001ae08745Sheppo uint32_t i;
10011ae08745Sheppo
1002678453a8Sspeer portp = (vgen_port_t *)arg;
1003678453a8Sspeer vgenp = portp->vgenp;
1004678453a8Sspeer
10050c4606f0SWENTAO YANG if (portp->is_vsw_port != B_TRUE) {
1006678453a8Sspeer return (DDI_SUCCESS);
1007678453a8Sspeer }
1008678453a8Sspeer
10091ae08745Sheppo addrp = (struct ether_addr *)mca;
10101ae08745Sheppo tagp = &mcastmsg.tag;
10111ae08745Sheppo bzero(&mcastmsg, sizeof (mcastmsg));
10121ae08745Sheppo
10137bd3a2e2SSriharsha Basavapatna ldcp = portp->ldcp;
10140c4606f0SWENTAO YANG if (ldcp == NULL) {
10150c4606f0SWENTAO YANG return (DDI_FAILURE);
10160c4606f0SWENTAO YANG }
10171ae08745Sheppo
10181ae08745Sheppo mutex_enter(&ldcp->cblock);
10191ae08745Sheppo
10201ae08745Sheppo if (ldcp->hphase == VH_DONE) {
10211ae08745Sheppo /*
10221ae08745Sheppo * If handshake is done, send a msg to vsw to add/remove
102319b65a69Ssb155480 * the multicast address. Otherwise, we just update this
102419b65a69Ssb155480 * mcast address in our table and the table will be sync'd
102519b65a69Ssb155480 * with vsw when handshake completes.
10261ae08745Sheppo */
10271ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
10281ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
10291ae08745Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO;
10301ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
10311ae08745Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
10321ae08745Sheppo mcastmsg.set = add;
10331ae08745Sheppo mcastmsg.count = 1;
1034bd8f0338Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
1035bd8f0338Snarayan B_FALSE) != VGEN_SUCCESS) {
1036844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
10370c4606f0SWENTAO YANG rv = DDI_FAILURE;
1038bd8f0338Snarayan goto vgen_mcast_exit;
10391ae08745Sheppo }
10401ae08745Sheppo }
10411ae08745Sheppo
10421ae08745Sheppo if (add) {
10431ae08745Sheppo
10441ae08745Sheppo /* expand multicast table if necessary */
10451ae08745Sheppo if (vgenp->mccount >= vgenp->mcsize) {
10461ae08745Sheppo struct ether_addr *newtab;
10471ae08745Sheppo uint32_t newsize;
10481ae08745Sheppo
10491ae08745Sheppo
10501ae08745Sheppo newsize = vgenp->mcsize * 2;
10511ae08745Sheppo
10521ae08745Sheppo newtab = kmem_zalloc(newsize *
10531ae08745Sheppo sizeof (struct ether_addr), KM_NOSLEEP);
1054bd8f0338Snarayan if (newtab == NULL)
1055bd8f0338Snarayan goto vgen_mcast_exit;
10561ae08745Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize *
10571ae08745Sheppo sizeof (struct ether_addr));
10581ae08745Sheppo kmem_free(vgenp->mctab,
10591ae08745Sheppo vgenp->mcsize * sizeof (struct ether_addr));
10601ae08745Sheppo
10611ae08745Sheppo vgenp->mctab = newtab;
10621ae08745Sheppo vgenp->mcsize = newsize;
10631ae08745Sheppo }
10641ae08745Sheppo
10651ae08745Sheppo /* add address to the table */
10661ae08745Sheppo vgenp->mctab[vgenp->mccount++] = *addrp;
10671ae08745Sheppo
10681ae08745Sheppo } else {
10691ae08745Sheppo
10701ae08745Sheppo /* delete address from the table */
10711ae08745Sheppo for (i = 0; i < vgenp->mccount; i++) {
10721ae08745Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
10731ae08745Sheppo
10741ae08745Sheppo /*
10751ae08745Sheppo * If there's more than one address in this
10761ae08745Sheppo * table, delete the unwanted one by moving
10771ae08745Sheppo * the last one in the list over top of it;
10781ae08745Sheppo * otherwise, just remove it.
10791ae08745Sheppo */
10801ae08745Sheppo if (vgenp->mccount > 1) {
10811ae08745Sheppo vgenp->mctab[i] =
10821ae08745Sheppo vgenp->mctab[vgenp->mccount-1];
10831ae08745Sheppo }
10841ae08745Sheppo vgenp->mccount--;
10851ae08745Sheppo break;
10861ae08745Sheppo }
10871ae08745Sheppo }
10881ae08745Sheppo }
10891ae08745Sheppo
1090bd8f0338Snarayan rv = DDI_SUCCESS;
1091bd8f0338Snarayan
1092bd8f0338Snarayan vgen_mcast_exit:
10931ae08745Sheppo
10947bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
1095bd8f0338Snarayan return (rv);
10961ae08745Sheppo }
10971ae08745Sheppo
10981ae08745Sheppo /* set or clear promiscuous mode on the device */
10991ae08745Sheppo static int
vgen_promisc(void * arg,boolean_t on)11001ae08745Sheppo vgen_promisc(void *arg, boolean_t on)
11011ae08745Sheppo {
11021ae08745Sheppo _NOTE(ARGUNUSED(arg, on))
11031ae08745Sheppo return (DDI_SUCCESS);
11041ae08745Sheppo }
11051ae08745Sheppo
11061ae08745Sheppo /* set the unicast mac address of the device */
11071ae08745Sheppo static int
vgen_unicst(void * arg,const uint8_t * mca)11081ae08745Sheppo vgen_unicst(void *arg, const uint8_t *mca)
11091ae08745Sheppo {
11101ae08745Sheppo _NOTE(ARGUNUSED(arg, mca))
11111ae08745Sheppo return (DDI_SUCCESS);
11121ae08745Sheppo }
11131ae08745Sheppo
11141ae08745Sheppo /* get device statistics */
1115ba2e4443Sseb int
vgen_stat(void * arg,uint_t stat,uint64_t * val)1116ba2e4443Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
11171ae08745Sheppo {
1118678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
11191ae08745Sheppo
1120678453a8Sspeer *val = vgen_port_stat(portp, stat);
1121ba2e4443Sseb return (0);
11221ae08745Sheppo }
11231ae08745Sheppo
11241ae08745Sheppo /* vgen internal functions */
11251ae08745Sheppo /* detach all ports from the device */
11261ae08745Sheppo static void
vgen_detach_ports(vgen_t * vgenp)11271ae08745Sheppo vgen_detach_ports(vgen_t *vgenp)
11281ae08745Sheppo {
11291ae08745Sheppo vgen_port_t *portp;
11301ae08745Sheppo vgen_portlist_t *plistp;
11311ae08745Sheppo
11321ae08745Sheppo plistp = &(vgenp->vgenports);
11331ae08745Sheppo WRITE_ENTER(&plistp->rwlock);
11341ae08745Sheppo while ((portp = plistp->headp) != NULL) {
11351ae08745Sheppo vgen_port_detach(portp);
11361ae08745Sheppo }
11371ae08745Sheppo RW_EXIT(&plistp->rwlock);
11381ae08745Sheppo }
11391ae08745Sheppo
11401ae08745Sheppo /*
11411ae08745Sheppo * detach the given port.
11421ae08745Sheppo */
11431ae08745Sheppo static void
vgen_port_detach(vgen_port_t * portp)11441ae08745Sheppo vgen_port_detach(vgen_port_t *portp)
11451ae08745Sheppo {
11461ae08745Sheppo vgen_t *vgenp;
11471ae08745Sheppo int port_num;
11481ae08745Sheppo
11491ae08745Sheppo vgenp = portp->vgenp;
11501ae08745Sheppo port_num = portp->port_num;
11511ae08745Sheppo
1152844e62a3Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num);
11531ae08745Sheppo
1154678453a8Sspeer /*
1155678453a8Sspeer * If this port is connected to the vswitch, then
1156678453a8Sspeer * potentially there could be ports that may be using
1157678453a8Sspeer * this port to transmit packets. To address this do
1158678453a8Sspeer * the following:
1159678453a8Sspeer * - First set vgenp->vsw_portp to NULL, so that
1160678453a8Sspeer * its not used after that.
1161678453a8Sspeer * - Then wait for the refcnt to go down to 0.
1162678453a8Sspeer * - Now we can safely detach this port.
1163678453a8Sspeer */
1164678453a8Sspeer if (vgenp->vsw_portp == portp) {
1165678453a8Sspeer vgenp->vsw_portp = NULL;
1166678453a8Sspeer while (vgenp->vsw_port_refcnt > 0) {
1167678453a8Sspeer delay(drv_usectohz(vgen_tx_delay));
1168678453a8Sspeer }
1169678453a8Sspeer (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
1170678453a8Sspeer }
1171678453a8Sspeer
1172678453a8Sspeer if (portp->vhp != NULL) {
1173678453a8Sspeer vio_net_resource_unreg(portp->vhp);
1174678453a8Sspeer portp->vhp = NULL;
1175678453a8Sspeer }
1176678453a8Sspeer
1177c1c61f44Ssb155480 vgen_vlan_destroy_hash(portp);
1178c1c61f44Ssb155480
11791ae08745Sheppo /* remove it from port list */
11801ae08745Sheppo vgen_port_list_remove(portp);
11811ae08745Sheppo
11821ae08745Sheppo /* detach channels from this port */
11837bd3a2e2SSriharsha Basavapatna vgen_ldc_detach(portp->ldcp);
11841ae08745Sheppo
1185c1c61f44Ssb155480 if (portp->num_ldcs != 0) {
1186c1c61f44Ssb155480 kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t));
1187c1c61f44Ssb155480 portp->num_ldcs = 0;
1188c1c61f44Ssb155480 }
1189c1c61f44Ssb155480
1190678453a8Sspeer mutex_destroy(&portp->lock);
11911ae08745Sheppo KMEM_FREE(portp);
11921ae08745Sheppo
1193844e62a3Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num);
11941ae08745Sheppo }
11951ae08745Sheppo
11961ae08745Sheppo /* add a port to port list */
11971ae08745Sheppo static void
vgen_port_list_insert(vgen_port_t * portp)11981ae08745Sheppo vgen_port_list_insert(vgen_port_t *portp)
11991ae08745Sheppo {
12001ae08745Sheppo vgen_portlist_t *plistp;
12011ae08745Sheppo vgen_t *vgenp;
12021ae08745Sheppo
12031ae08745Sheppo vgenp = portp->vgenp;
12041ae08745Sheppo plistp = &(vgenp->vgenports);
12051ae08745Sheppo
12061ae08745Sheppo if (plistp->headp == NULL) {
12071ae08745Sheppo plistp->headp = portp;
12081ae08745Sheppo } else {
12091ae08745Sheppo plistp->tailp->nextp = portp;
12101ae08745Sheppo }
12111ae08745Sheppo plistp->tailp = portp;
12121ae08745Sheppo portp->nextp = NULL;
12131ae08745Sheppo }
12141ae08745Sheppo
12151ae08745Sheppo /* remove a port from port list */
12161ae08745Sheppo static void
vgen_port_list_remove(vgen_port_t * portp)12171ae08745Sheppo vgen_port_list_remove(vgen_port_t *portp)
12181ae08745Sheppo {
12191ae08745Sheppo vgen_port_t *prevp;
12201ae08745Sheppo vgen_port_t *nextp;
12211ae08745Sheppo vgen_portlist_t *plistp;
12221ae08745Sheppo vgen_t *vgenp;
12231ae08745Sheppo
12241ae08745Sheppo vgenp = portp->vgenp;
12251ae08745Sheppo
12261ae08745Sheppo plistp = &(vgenp->vgenports);
12271ae08745Sheppo
12281ae08745Sheppo if (plistp->headp == NULL)
12291ae08745Sheppo return;
12301ae08745Sheppo
12311ae08745Sheppo if (portp == plistp->headp) {
12321ae08745Sheppo plistp->headp = portp->nextp;
12331ae08745Sheppo if (portp == plistp->tailp)
12341ae08745Sheppo plistp->tailp = plistp->headp;
12351ae08745Sheppo } else {
1236b4d0458eSraghuram for (prevp = plistp->headp;
1237b4d0458eSraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp);
1238b4d0458eSraghuram prevp = nextp)
1239b4d0458eSraghuram ;
12401ae08745Sheppo if (nextp == portp) {
12411ae08745Sheppo prevp->nextp = portp->nextp;
12421ae08745Sheppo }
12431ae08745Sheppo if (portp == plistp->tailp)
12441ae08745Sheppo plistp->tailp = prevp;
12451ae08745Sheppo }
12461ae08745Sheppo }
12471ae08745Sheppo
12481ae08745Sheppo /* lookup a port in the list based on port_num */
12491ae08745Sheppo static vgen_port_t *
vgen_port_lookup(vgen_portlist_t * plistp,int port_num)12501ae08745Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
12511ae08745Sheppo {
12521ae08745Sheppo vgen_port_t *portp = NULL;
12531ae08745Sheppo
12541ae08745Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
12551ae08745Sheppo if (portp->port_num == port_num) {
12561ae08745Sheppo break;
12571ae08745Sheppo }
12581ae08745Sheppo }
12591ae08745Sheppo
12601ae08745Sheppo return (portp);
12611ae08745Sheppo }
12621ae08745Sheppo
12631ae08745Sheppo static void
vgen_port_init(vgen_port_t * portp)12641ae08745Sheppo vgen_port_init(vgen_port_t *portp)
12651ae08745Sheppo {
1266c1c61f44Ssb155480 /* Add the port to the specified vlans */
1267c1c61f44Ssb155480 vgen_vlan_add_ids(portp);
12681ae08745Sheppo
12697bd3a2e2SSriharsha Basavapatna /* Bring up the channel */
12707bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_init(portp->ldcp);
12711ae08745Sheppo }
12721ae08745Sheppo
12731ae08745Sheppo static void
vgen_port_uninit(vgen_port_t * portp)12741ae08745Sheppo vgen_port_uninit(vgen_port_t *portp)
12751ae08745Sheppo {
12767bd3a2e2SSriharsha Basavapatna vgen_ldc_uninit(portp->ldcp);
1277c1c61f44Ssb155480
1278c1c61f44Ssb155480 /* remove the port from vlans it has been assigned to */
1279c1c61f44Ssb155480 vgen_vlan_remove_ids(portp);
12801ae08745Sheppo }
12811ae08745Sheppo
1282f0ca1d9aSsb155480 /*
1283f0ca1d9aSsb155480 * Scan the machine description for this instance of vnet
1284f0ca1d9aSsb155480 * and read its properties. Called only from vgen_init().
1285f0ca1d9aSsb155480 * Returns: 0 on success, 1 on failure.
1286f0ca1d9aSsb155480 */
1287f0ca1d9aSsb155480 static int
vgen_read_mdprops(vgen_t * vgenp)1288f0ca1d9aSsb155480 vgen_read_mdprops(vgen_t *vgenp)
1289f0ca1d9aSsb155480 {
1290c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp;
1291f0ca1d9aSsb155480 md_t *mdp = NULL;
1292f0ca1d9aSsb155480 mde_cookie_t rootnode;
1293f0ca1d9aSsb155480 mde_cookie_t *listp = NULL;
1294f0ca1d9aSsb155480 uint64_t cfgh;
1295f0ca1d9aSsb155480 char *name;
1296f0ca1d9aSsb155480 int rv = 1;
1297f0ca1d9aSsb155480 int num_nodes = 0;
1298f0ca1d9aSsb155480 int num_devs = 0;
1299f0ca1d9aSsb155480 int listsz = 0;
1300f0ca1d9aSsb155480 int i;
1301f0ca1d9aSsb155480
1302f0ca1d9aSsb155480 if ((mdp = md_get_handle()) == NULL) {
1303f0ca1d9aSsb155480 return (rv);
1304f0ca1d9aSsb155480 }
1305f0ca1d9aSsb155480
1306f0ca1d9aSsb155480 num_nodes = md_node_count(mdp);
1307f0ca1d9aSsb155480 ASSERT(num_nodes > 0);
1308f0ca1d9aSsb155480
1309f0ca1d9aSsb155480 listsz = num_nodes * sizeof (mde_cookie_t);
1310f0ca1d9aSsb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
1311f0ca1d9aSsb155480
1312f0ca1d9aSsb155480 rootnode = md_root_node(mdp);
1313f0ca1d9aSsb155480
1314f0ca1d9aSsb155480 /* search for all "virtual_device" nodes */
1315f0ca1d9aSsb155480 num_devs = md_scan_dag(mdp, rootnode,
1316f0ca1d9aSsb155480 md_find_name(mdp, vdev_propname),
1317f0ca1d9aSsb155480 md_find_name(mdp, "fwd"), listp);
1318f0ca1d9aSsb155480 if (num_devs <= 0) {
1319f0ca1d9aSsb155480 goto vgen_readmd_exit;
1320f0ca1d9aSsb155480 }
1321f0ca1d9aSsb155480
1322f0ca1d9aSsb155480 /*
1323f0ca1d9aSsb155480 * Now loop through the list of virtual-devices looking for
1324f0ca1d9aSsb155480 * devices with name "network" and for each such device compare
1325f0ca1d9aSsb155480 * its instance with what we have from the 'reg' property to
1326f0ca1d9aSsb155480 * find the right node in MD and then read all its properties.
1327f0ca1d9aSsb155480 */
1328f0ca1d9aSsb155480 for (i = 0; i < num_devs; i++) {
1329f0ca1d9aSsb155480
1330f0ca1d9aSsb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) {
1331f0ca1d9aSsb155480 goto vgen_readmd_exit;
1332f0ca1d9aSsb155480 }
1333f0ca1d9aSsb155480
1334f0ca1d9aSsb155480 /* is this a "network" device? */
1335f0ca1d9aSsb155480 if (strcmp(name, vnet_propname) != 0)
1336f0ca1d9aSsb155480 continue;
1337f0ca1d9aSsb155480
1338f0ca1d9aSsb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) {
1339f0ca1d9aSsb155480 goto vgen_readmd_exit;
1340f0ca1d9aSsb155480 }
1341f0ca1d9aSsb155480
1342f0ca1d9aSsb155480 /* is this the required instance of vnet? */
1343678453a8Sspeer if (vgenp->regprop != cfgh)
1344f0ca1d9aSsb155480 continue;
1345f0ca1d9aSsb155480
13467b1f684aSSriharsha Basavapatna /*
13471107ea93SSriharsha Basavapatna * Read the 'linkprop' property to know if this vnet
13481107ea93SSriharsha Basavapatna * device should get physical link updates from vswitch.
13491107ea93SSriharsha Basavapatna */
13501107ea93SSriharsha Basavapatna vgen_linkprop_read(vgenp, mdp, listp[i],
13511107ea93SSriharsha Basavapatna &vnetp->pls_update);
13521107ea93SSriharsha Basavapatna
13531107ea93SSriharsha Basavapatna /*
13547b1f684aSSriharsha Basavapatna * Read the mtu. Note that we set the mtu of vnet device within
13557b1f684aSSriharsha Basavapatna * this routine itself, after validating the range.
13567b1f684aSSriharsha Basavapatna */
13577b1f684aSSriharsha Basavapatna vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu);
13587b1f684aSSriharsha Basavapatna if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) {
13597b1f684aSSriharsha Basavapatna vnetp->mtu = ETHERMTU;
13607b1f684aSSriharsha Basavapatna }
13617b1f684aSSriharsha Basavapatna vgenp->max_frame_size = vnetp->mtu +
13627b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ;
13637b1f684aSSriharsha Basavapatna
13647b1f684aSSriharsha Basavapatna /* read priority ether types */
1365f0ca1d9aSsb155480 vgen_read_pri_eth_types(vgenp, mdp, listp[i]);
1366c1c61f44Ssb155480
1367c1c61f44Ssb155480 /* read vlan id properties of this vnet instance */
1368c1c61f44Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i],
1369c1c61f44Ssb155480 &vnetp->pvid, &vnetp->vids, &vnetp->nvids,
1370c1c61f44Ssb155480 &vnetp->default_vlan_id);
1371c1c61f44Ssb155480
1372f0ca1d9aSsb155480 rv = 0;
1373f0ca1d9aSsb155480 break;
1374f0ca1d9aSsb155480 }
1375f0ca1d9aSsb155480
1376f0ca1d9aSsb155480 vgen_readmd_exit:
1377f0ca1d9aSsb155480
1378f0ca1d9aSsb155480 kmem_free(listp, listsz);
1379f0ca1d9aSsb155480 (void) md_fini_handle(mdp);
1380f0ca1d9aSsb155480 return (rv);
1381f0ca1d9aSsb155480 }
1382f0ca1d9aSsb155480
1383f0ca1d9aSsb155480 /*
1384c1c61f44Ssb155480 * Read vlan id properties of the given MD node.
1385c1c61f44Ssb155480 * Arguments:
1386c1c61f44Ssb155480 * arg: device argument(vnet device or a port)
1387c1c61f44Ssb155480 * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port)
1388c1c61f44Ssb155480 * mdp: machine description
1389c1c61f44Ssb155480 * node: md node cookie
1390c1c61f44Ssb155480 *
1391c1c61f44Ssb155480 * Returns:
1392c1c61f44Ssb155480 * pvidp: port-vlan-id of the node
1393c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node
1394c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list
1395c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vnet device)
1396c1c61f44Ssb155480 */
1397c1c61f44Ssb155480 static void
vgen_vlan_read_ids(void * arg,int type,md_t * mdp,mde_cookie_t node,uint16_t * pvidp,uint16_t ** vidspp,uint16_t * nvidsp,uint16_t * default_idp)1398c1c61f44Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node,
1399c1c61f44Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp,
1400c1c61f44Ssb155480 uint16_t *default_idp)
1401c1c61f44Ssb155480 {
1402c1c61f44Ssb155480 vgen_t *vgenp;
1403c1c61f44Ssb155480 vnet_t *vnetp;
1404c1c61f44Ssb155480 vgen_port_t *portp;
1405c1c61f44Ssb155480 char *pvid_propname;
1406c1c61f44Ssb155480 char *vid_propname;
1407c1c61f44Ssb155480 uint_t nvids;
1408c1c61f44Ssb155480 uint32_t vids_size;
1409c1c61f44Ssb155480 int rv;
1410c1c61f44Ssb155480 int i;
1411c1c61f44Ssb155480 uint64_t *data;
1412c1c61f44Ssb155480 uint64_t val;
1413c1c61f44Ssb155480 int size;
1414c1c61f44Ssb155480 int inst;
1415c1c61f44Ssb155480
1416c1c61f44Ssb155480 if (type == VGEN_LOCAL) {
1417c1c61f44Ssb155480
1418c1c61f44Ssb155480 vgenp = (vgen_t *)arg;
1419c1c61f44Ssb155480 vnetp = vgenp->vnetp;
1420c1c61f44Ssb155480 pvid_propname = vgen_pvid_propname;
1421c1c61f44Ssb155480 vid_propname = vgen_vid_propname;
1422c1c61f44Ssb155480 inst = vnetp->instance;
1423c1c61f44Ssb155480
1424c1c61f44Ssb155480 } else if (type == VGEN_PEER) {
1425c1c61f44Ssb155480
1426c1c61f44Ssb155480 portp = (vgen_port_t *)arg;
1427c1c61f44Ssb155480 vgenp = portp->vgenp;
1428c1c61f44Ssb155480 vnetp = vgenp->vnetp;
1429c1c61f44Ssb155480 pvid_propname = port_pvid_propname;
1430c1c61f44Ssb155480 vid_propname = port_vid_propname;
1431c1c61f44Ssb155480 inst = portp->port_num;
1432c1c61f44Ssb155480
1433c1c61f44Ssb155480 } else {
1434c1c61f44Ssb155480 return;
1435c1c61f44Ssb155480 }
1436c1c61f44Ssb155480
1437c1c61f44Ssb155480 if (type == VGEN_LOCAL && default_idp != NULL) {
1438c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val);
1439c1c61f44Ssb155480 if (rv != 0) {
1440c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found",
1441c1c61f44Ssb155480 vgen_dvid_propname);
1442c1c61f44Ssb155480
1443c1c61f44Ssb155480 *default_idp = vnet_default_vlan_id;
1444c1c61f44Ssb155480 } else {
1445c1c61f44Ssb155480 *default_idp = val & 0xFFF;
1446c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname,
1447c1c61f44Ssb155480 inst, *default_idp);
1448c1c61f44Ssb155480 }
1449c1c61f44Ssb155480 }
1450c1c61f44Ssb155480
1451c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val);
1452c1c61f44Ssb155480 if (rv != 0) {
1453c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname);
1454c1c61f44Ssb155480 *pvidp = vnet_default_vlan_id;
1455c1c61f44Ssb155480 } else {
1456c1c61f44Ssb155480
1457c1c61f44Ssb155480 *pvidp = val & 0xFFF;
1458c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n",
1459c1c61f44Ssb155480 pvid_propname, inst, *pvidp);
1460c1c61f44Ssb155480 }
1461c1c61f44Ssb155480
1462c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data,
1463c1c61f44Ssb155480 &size);
1464c1c61f44Ssb155480 if (rv != 0) {
1465c1c61f44Ssb155480 DBG2(vgenp, NULL, "prop(%s) not found", vid_propname);
1466c1c61f44Ssb155480 size = 0;
1467c1c61f44Ssb155480 } else {
1468c1c61f44Ssb155480 size /= sizeof (uint64_t);
1469c1c61f44Ssb155480 }
1470c1c61f44Ssb155480 nvids = size;
1471c1c61f44Ssb155480
1472c1c61f44Ssb155480 if (nvids != 0) {
1473c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst);
1474c1c61f44Ssb155480 vids_size = sizeof (uint16_t) * nvids;
1475c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP);
1476c1c61f44Ssb155480 for (i = 0; i < nvids; i++) {
1477c1c61f44Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF;
1478c1c61f44Ssb155480 DBG2(vgenp, NULL, " %d ", (*vidspp)[i]);
1479c1c61f44Ssb155480 }
1480c1c61f44Ssb155480 DBG2(vgenp, NULL, "\n");
1481c1c61f44Ssb155480 }
1482c1c61f44Ssb155480
1483c1c61f44Ssb155480 *nvidsp = nvids;
1484c1c61f44Ssb155480 }
1485c1c61f44Ssb155480
1486c1c61f44Ssb155480 /*
1487c1c61f44Ssb155480 * Create a vlan id hash table for the given port.
1488c1c61f44Ssb155480 */
1489c1c61f44Ssb155480 static void
vgen_vlan_create_hash(vgen_port_t * portp)1490c1c61f44Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp)
1491c1c61f44Ssb155480 {
1492c1c61f44Ssb155480 char hashname[MAXNAMELEN];
1493c1c61f44Ssb155480
1494c1c61f44Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
1495c1c61f44Ssb155480 portp->port_num);
1496c1c61f44Ssb155480
1497c1c61f44Ssb155480 portp->vlan_nchains = vgen_vlan_nchains;
1498c1c61f44Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname,
1499c1c61f44Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor);
1500c1c61f44Ssb155480 }
1501c1c61f44Ssb155480
1502c1c61f44Ssb155480 /*
1503c1c61f44Ssb155480 * Destroy the vlan id hash table in the given port.
1504c1c61f44Ssb155480 */
1505c1c61f44Ssb155480 static void
vgen_vlan_destroy_hash(vgen_port_t * portp)1506c1c61f44Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp)
1507c1c61f44Ssb155480 {
1508c1c61f44Ssb155480 if (portp->vlan_hashp != NULL) {
1509c1c61f44Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp);
1510c1c61f44Ssb155480 portp->vlan_hashp = NULL;
1511c1c61f44Ssb155480 portp->vlan_nchains = 0;
1512c1c61f44Ssb155480 }
1513c1c61f44Ssb155480 }
1514c1c61f44Ssb155480
1515c1c61f44Ssb155480 /*
1516c1c61f44Ssb155480 * Add a port to the vlans specified in its port properites.
1517c1c61f44Ssb155480 */
1518c1c61f44Ssb155480 static void
vgen_vlan_add_ids(vgen_port_t * portp)1519c1c61f44Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp)
1520c1c61f44Ssb155480 {
1521c1c61f44Ssb155480 int rv;
1522c1c61f44Ssb155480 int i;
1523c1c61f44Ssb155480
1524c1c61f44Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
1525c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
1526c1c61f44Ssb155480 (mod_hash_val_t)B_TRUE);
1527c1c61f44Ssb155480 ASSERT(rv == 0);
1528c1c61f44Ssb155480
1529c1c61f44Ssb155480 for (i = 0; i < portp->nvids; i++) {
1530c1c61f44Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
1531c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
1532c1c61f44Ssb155480 (mod_hash_val_t)B_TRUE);
1533c1c61f44Ssb155480 ASSERT(rv == 0);
1534c1c61f44Ssb155480 }
1535c1c61f44Ssb155480 }
1536c1c61f44Ssb155480
1537c1c61f44Ssb155480 /*
1538c1c61f44Ssb155480 * Remove a port from the vlans it has been assigned to.
1539c1c61f44Ssb155480 */
1540c1c61f44Ssb155480 static void
vgen_vlan_remove_ids(vgen_port_t * portp)1541c1c61f44Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp)
1542c1c61f44Ssb155480 {
1543c1c61f44Ssb155480 int rv;
1544c1c61f44Ssb155480 int i;
1545c1c61f44Ssb155480 mod_hash_val_t vp;
1546c1c61f44Ssb155480
1547c1c61f44Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
1548c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
1549c1c61f44Ssb155480 (mod_hash_val_t *)&vp);
1550c1c61f44Ssb155480 ASSERT(rv == 0);
1551c1c61f44Ssb155480
1552c1c61f44Ssb155480 for (i = 0; i < portp->nvids; i++) {
1553c1c61f44Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
1554c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
1555c1c61f44Ssb155480 (mod_hash_val_t *)&vp);
1556c1c61f44Ssb155480 ASSERT(rv == 0);
1557c1c61f44Ssb155480 }
1558c1c61f44Ssb155480 }
1559c1c61f44Ssb155480
1560c1c61f44Ssb155480 /*
1561c1c61f44Ssb155480 * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame,
1562c1c61f44Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is
1563c1c61f44Ssb155480 * implicitly obtained from the port-vlan-id of the vnet device.
1564c1c61f44Ssb155480 * The vlan id determined is returned in vidp.
1565c1c61f44Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
1566c1c61f44Ssb155480 */
1567c1c61f44Ssb155480 static boolean_t
vgen_frame_lookup_vid(vnet_t * vnetp,struct ether_header * ehp,uint16_t * vidp)1568c1c61f44Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp)
1569c1c61f44Ssb155480 {
1570c1c61f44Ssb155480 struct ether_vlan_header *evhp;
1571c1c61f44Ssb155480
1572c1c61f44Ssb155480 /* If it's a tagged frame, get the vlan id from vlan header */
1573c1c61f44Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) {
1574c1c61f44Ssb155480
1575c1c61f44Ssb155480 evhp = (struct ether_vlan_header *)ehp;
1576c1c61f44Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci));
1577c1c61f44Ssb155480 return (B_TRUE);
1578c1c61f44Ssb155480 }
1579c1c61f44Ssb155480
1580c1c61f44Ssb155480 /* Untagged frame, vlan-id is the pvid of vnet device */
1581c1c61f44Ssb155480 *vidp = vnetp->pvid;
1582c1c61f44Ssb155480 return (B_FALSE);
1583c1c61f44Ssb155480 }
1584c1c61f44Ssb155480
1585c1c61f44Ssb155480 /*
1586c1c61f44Ssb155480 * Find the given vlan id in the hash table.
1587c1c61f44Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found.
1588c1c61f44Ssb155480 */
1589c1c61f44Ssb155480 static boolean_t
vgen_vlan_lookup(mod_hash_t * vlan_hashp,uint16_t vid)1590c1c61f44Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
1591c1c61f44Ssb155480 {
1592c1c61f44Ssb155480 int rv;
1593c1c61f44Ssb155480 mod_hash_val_t vp;
1594c1c61f44Ssb155480
1595c1c61f44Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
1596c1c61f44Ssb155480
1597c1c61f44Ssb155480 if (rv != 0)
1598c1c61f44Ssb155480 return (B_FALSE);
1599c1c61f44Ssb155480
1600c1c61f44Ssb155480 return (B_TRUE);
1601c1c61f44Ssb155480 }
1602c1c61f44Ssb155480
1603c1c61f44Ssb155480 /*
1604f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property
1605f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need
1606f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from
1607f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing
1608f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed.
1609f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor
1610f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size,
1611f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc.
1612f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames
1613f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the
1614f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of
1615f0ca1d9aSsb155480 * frames to the peer.
1616f0ca1d9aSsb155480 */
1617f0ca1d9aSsb155480 static void
vgen_read_pri_eth_types(vgen_t * vgenp,md_t * mdp,mde_cookie_t node)1618f0ca1d9aSsb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node)
1619f0ca1d9aSsb155480 {
1620f0ca1d9aSsb155480 int rv;
1621f0ca1d9aSsb155480 uint16_t *types;
1622f0ca1d9aSsb155480 uint64_t *data;
1623f0ca1d9aSsb155480 int size;
1624f0ca1d9aSsb155480 int i;
1625f0ca1d9aSsb155480 size_t mblk_sz;
1626f0ca1d9aSsb155480
1627f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname,
1628f0ca1d9aSsb155480 (uint8_t **)&data, &size);
1629f0ca1d9aSsb155480 if (rv != 0) {
1630f0ca1d9aSsb155480 /*
1631f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w.
1632f0ca1d9aSsb155480 * Check if 'vgen_pri_eth_type' has been set in that case.
1633f0ca1d9aSsb155480 */
1634f0ca1d9aSsb155480 if (vgen_pri_eth_type != 0) {
1635f0ca1d9aSsb155480 size = sizeof (vgen_pri_eth_type);
1636f0ca1d9aSsb155480 data = &vgen_pri_eth_type;
1637f0ca1d9aSsb155480 } else {
1638678453a8Sspeer DBG2(vgenp, NULL,
1639f0ca1d9aSsb155480 "prop(%s) not found", pri_types_propname);
1640f0ca1d9aSsb155480 size = 0;
1641f0ca1d9aSsb155480 }
1642f0ca1d9aSsb155480 }
1643f0ca1d9aSsb155480
1644f0ca1d9aSsb155480 if (size == 0) {
1645f0ca1d9aSsb155480 vgenp->pri_num_types = 0;
1646f0ca1d9aSsb155480 return;
1647f0ca1d9aSsb155480 }
1648f0ca1d9aSsb155480
1649f0ca1d9aSsb155480 /*
1650f0ca1d9aSsb155480 * we have some priority-ether-types defined;
1651f0ca1d9aSsb155480 * allocate a table of these types and also
1652f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these
1653f0ca1d9aSsb155480 * priority packets.
1654f0ca1d9aSsb155480 */
1655f0ca1d9aSsb155480 size /= sizeof (uint64_t);
1656f0ca1d9aSsb155480 vgenp->pri_num_types = size;
1657f0ca1d9aSsb155480 vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP);
1658f0ca1d9aSsb155480 for (i = 0, types = vgenp->pri_types; i < size; i++) {
1659f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF;
1660f0ca1d9aSsb155480 }
1661c1c61f44Ssb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7;
16627bd3a2e2SSriharsha Basavapatna (void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, NULL,
1663f0ca1d9aSsb155480 &vgenp->pri_tx_vmp);
1664f0ca1d9aSsb155480 }
1665f0ca1d9aSsb155480
16667b1f684aSSriharsha Basavapatna static void
vgen_mtu_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,uint32_t * mtu)16677b1f684aSSriharsha Basavapatna vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu)
16687b1f684aSSriharsha Basavapatna {
16697b1f684aSSriharsha Basavapatna int rv;
16707b1f684aSSriharsha Basavapatna uint64_t val;
16717b1f684aSSriharsha Basavapatna char *mtu_propname;
16727b1f684aSSriharsha Basavapatna
16737b1f684aSSriharsha Basavapatna mtu_propname = vgen_mtu_propname;
16747b1f684aSSriharsha Basavapatna
16757b1f684aSSriharsha Basavapatna rv = md_get_prop_val(mdp, node, mtu_propname, &val);
16767b1f684aSSriharsha Basavapatna if (rv != 0) {
16777b1f684aSSriharsha Basavapatna DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname);
16787b1f684aSSriharsha Basavapatna *mtu = vnet_ethermtu;
16797b1f684aSSriharsha Basavapatna } else {
16807b1f684aSSriharsha Basavapatna
16817b1f684aSSriharsha Basavapatna *mtu = val & 0xFFFF;
16827b1f684aSSriharsha Basavapatna DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname,
16837b1f684aSSriharsha Basavapatna vgenp->instance, *mtu);
16847b1f684aSSriharsha Basavapatna }
16857b1f684aSSriharsha Basavapatna }
16867b1f684aSSriharsha Basavapatna
16871107ea93SSriharsha Basavapatna static void
vgen_linkprop_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,boolean_t * pls)16881107ea93SSriharsha Basavapatna vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
16891107ea93SSriharsha Basavapatna boolean_t *pls)
16901107ea93SSriharsha Basavapatna {
16911107ea93SSriharsha Basavapatna int rv;
16921107ea93SSriharsha Basavapatna uint64_t val;
16931107ea93SSriharsha Basavapatna char *linkpropname;
16941107ea93SSriharsha Basavapatna
16951107ea93SSriharsha Basavapatna linkpropname = vgen_linkprop_propname;
16961107ea93SSriharsha Basavapatna
16971107ea93SSriharsha Basavapatna rv = md_get_prop_val(mdp, node, linkpropname, &val);
16981107ea93SSriharsha Basavapatna if (rv != 0) {
16991107ea93SSriharsha Basavapatna DWARN(vgenp, NULL, "prop(%s) not found", linkpropname);
17001107ea93SSriharsha Basavapatna *pls = B_FALSE;
17011107ea93SSriharsha Basavapatna } else {
17021107ea93SSriharsha Basavapatna
17031107ea93SSriharsha Basavapatna *pls = (val & 0x1) ? B_TRUE : B_FALSE;
17041107ea93SSriharsha Basavapatna DBG2(vgenp, NULL, "%s(%d): (%d)\n", linkpropname,
17051107ea93SSriharsha Basavapatna vgenp->instance, *pls);
17061107ea93SSriharsha Basavapatna }
17071107ea93SSriharsha Basavapatna }
17081107ea93SSriharsha Basavapatna
17091ae08745Sheppo /* register with MD event generator */
17101ae08745Sheppo static int
vgen_mdeg_reg(vgen_t * vgenp)17111ae08745Sheppo vgen_mdeg_reg(vgen_t *vgenp)
17121ae08745Sheppo {
17131ae08745Sheppo mdeg_prop_spec_t *pspecp;
17141ae08745Sheppo mdeg_node_spec_t *parentp;
17151ae08745Sheppo uint_t templatesz;
17161ae08745Sheppo int rv;
1717c1c61f44Ssb155480 mdeg_handle_t dev_hdl = NULL;
1718c1c61f44Ssb155480 mdeg_handle_t port_hdl = NULL;
17191ae08745Sheppo
17201ae08745Sheppo templatesz = sizeof (vgen_prop_template);
17211ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
17221ae08745Sheppo if (pspecp == NULL) {
17231ae08745Sheppo return (DDI_FAILURE);
17241ae08745Sheppo }
17251ae08745Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
17261ae08745Sheppo if (parentp == NULL) {
17271ae08745Sheppo kmem_free(pspecp, templatesz);
17281ae08745Sheppo return (DDI_FAILURE);
17291ae08745Sheppo }
17301ae08745Sheppo
17311ae08745Sheppo bcopy(vgen_prop_template, pspecp, templatesz);
17321ae08745Sheppo
17331ae08745Sheppo /*
17341ae08745Sheppo * NOTE: The instance here refers to the value of "reg" property and
17351ae08745Sheppo * not the dev_info instance (ddi_get_instance()) of vnet.
17361ae08745Sheppo */
1737c1c61f44Ssb155480 VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop);
17381ae08745Sheppo
17391ae08745Sheppo parentp->namep = "virtual-device";
17401ae08745Sheppo parentp->specp = pspecp;
17411ae08745Sheppo
17421ae08745Sheppo /* save parentp in vgen_t */
17431ae08745Sheppo vgenp->mdeg_parentp = parentp;
17441ae08745Sheppo
1745c1c61f44Ssb155480 /*
1746c1c61f44Ssb155480 * Register an interest in 'virtual-device' nodes with a
1747c1c61f44Ssb155480 * 'name' property of 'network'
1748c1c61f44Ssb155480 */
1749c1c61f44Ssb155480 rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl);
17501ae08745Sheppo if (rv != MDEG_SUCCESS) {
1751844e62a3Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n");
1752c1c61f44Ssb155480 goto mdeg_reg_fail;
1753c1c61f44Ssb155480 }
1754c1c61f44Ssb155480
1755c1c61f44Ssb155480 /* Register an interest in 'port' nodes */
1756c1c61f44Ssb155480 rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp,
1757c1c61f44Ssb155480 &port_hdl);
1758c1c61f44Ssb155480 if (rv != MDEG_SUCCESS) {
1759c1c61f44Ssb155480 DERR(vgenp, NULL, "mdeg_register failed\n");
1760c1c61f44Ssb155480 goto mdeg_reg_fail;
1761c1c61f44Ssb155480 }
1762c1c61f44Ssb155480
1763c1c61f44Ssb155480 /* save mdeg handle in vgen_t */
1764c1c61f44Ssb155480 vgenp->mdeg_dev_hdl = dev_hdl;
1765c1c61f44Ssb155480 vgenp->mdeg_port_hdl = port_hdl;
1766c1c61f44Ssb155480
1767c1c61f44Ssb155480 return (DDI_SUCCESS);
1768c1c61f44Ssb155480
1769c1c61f44Ssb155480 mdeg_reg_fail:
1770c1c61f44Ssb155480 if (dev_hdl != NULL) {
1771c1c61f44Ssb155480 (void) mdeg_unregister(dev_hdl);
1772c1c61f44Ssb155480 }
17731ae08745Sheppo KMEM_FREE(parentp);
17741ae08745Sheppo kmem_free(pspecp, templatesz);
17751ae08745Sheppo vgenp->mdeg_parentp = NULL;
17761ae08745Sheppo return (DDI_FAILURE);
17771ae08745Sheppo }
17781ae08745Sheppo
17791ae08745Sheppo /* unregister with MD event generator */
17801ae08745Sheppo static void
vgen_mdeg_unreg(vgen_t * vgenp)17811ae08745Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
17821ae08745Sheppo {
178363f531d1SSriharsha Basavapatna if (vgenp->mdeg_dev_hdl != NULL) {
1784c1c61f44Ssb155480 (void) mdeg_unregister(vgenp->mdeg_dev_hdl);
178563f531d1SSriharsha Basavapatna vgenp->mdeg_dev_hdl = NULL;
178663f531d1SSriharsha Basavapatna }
178763f531d1SSriharsha Basavapatna if (vgenp->mdeg_port_hdl != NULL) {
1788c1c61f44Ssb155480 (void) mdeg_unregister(vgenp->mdeg_port_hdl);
178963f531d1SSriharsha Basavapatna vgenp->mdeg_port_hdl = NULL;
179063f531d1SSriharsha Basavapatna }
179163f531d1SSriharsha Basavapatna
179263f531d1SSriharsha Basavapatna if (vgenp->mdeg_parentp != NULL) {
179363f531d1SSriharsha Basavapatna kmem_free(vgenp->mdeg_parentp->specp,
179463f531d1SSriharsha Basavapatna sizeof (vgen_prop_template));
17951ae08745Sheppo KMEM_FREE(vgenp->mdeg_parentp);
17961ae08745Sheppo vgenp->mdeg_parentp = NULL;
179763f531d1SSriharsha Basavapatna }
17981ae08745Sheppo }
17991ae08745Sheppo
1800c1c61f44Ssb155480 /* mdeg callback function for the port node */
18011ae08745Sheppo static int
vgen_mdeg_port_cb(void * cb_argp,mdeg_result_t * resp)1802c1c61f44Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp)
18031ae08745Sheppo {
18041ae08745Sheppo int idx;
18051ae08745Sheppo int vsw_idx = -1;
18061ae08745Sheppo uint64_t val;
18071ae08745Sheppo vgen_t *vgenp;
18081ae08745Sheppo
18091ae08745Sheppo if ((resp == NULL) || (cb_argp == NULL)) {
18101ae08745Sheppo return (MDEG_FAILURE);
18111ae08745Sheppo }
18121ae08745Sheppo
18131ae08745Sheppo vgenp = (vgen_t *)cb_argp;
1814844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n");
18151ae08745Sheppo
18161ae08745Sheppo mutex_enter(&vgenp->lock);
18171ae08745Sheppo
1818844e62a3Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), "
1819844e62a3Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem,
1820844e62a3Sraghuram resp->added.nelem, resp->match_curr.nelem);
18211ae08745Sheppo
18221ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) {
18231ae08745Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp,
18241ae08745Sheppo resp->removed.mdep[idx]);
18251ae08745Sheppo }
18261ae08745Sheppo
18271ae08745Sheppo if (vgenp->vsw_portp == NULL) {
18281ae08745Sheppo /*
18291ae08745Sheppo * find vsw_port and add it first, because other ports need
18301ae08745Sheppo * this when adding fdb entry (see vgen_port_init()).
18311ae08745Sheppo */
18321ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) {
18331ae08745Sheppo if (!(md_get_prop_val(resp->added.mdp,
18341ae08745Sheppo resp->added.mdep[idx], swport_propname, &val))) {
18351ae08745Sheppo if (val == 0) {
18361ae08745Sheppo /*
18371ae08745Sheppo * This port is connected to the
1838c1c61f44Ssb155480 * vsw on service domain.
18391ae08745Sheppo */
18401ae08745Sheppo vsw_idx = idx;
1841ca7ee4f9Szk194757 if (vgen_add_port(vgenp,
18421ae08745Sheppo resp->added.mdp,
1843ca7ee4f9Szk194757 resp->added.mdep[idx]) !=
1844ca7ee4f9Szk194757 DDI_SUCCESS) {
1845ca7ee4f9Szk194757 cmn_err(CE_NOTE, "vnet%d Could "
1846ca7ee4f9Szk194757 "not initialize virtual "
1847ca7ee4f9Szk194757 "switch port.",
1848678453a8Sspeer vgenp->instance);
1849ca7ee4f9Szk194757 mutex_exit(&vgenp->lock);
1850ca7ee4f9Szk194757 return (MDEG_FAILURE);
1851ca7ee4f9Szk194757 }
18521ae08745Sheppo break;
18531ae08745Sheppo }
18541ae08745Sheppo }
18551ae08745Sheppo }
1856c198d18eSzk194757 if (vsw_idx == -1) {
1857844e62a3Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n");
1858ca7ee4f9Szk194757 mutex_exit(&vgenp->lock);
18591ae08745Sheppo return (MDEG_FAILURE);
18601ae08745Sheppo }
18611ae08745Sheppo }
18621ae08745Sheppo
18631ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) {
18641ae08745Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
18651ae08745Sheppo continue;
1866ca7ee4f9Szk194757
1867ca7ee4f9Szk194757 /* If this port can't be added just skip it. */
18681ae08745Sheppo (void) vgen_add_port(vgenp, resp->added.mdp,
18691ae08745Sheppo resp->added.mdep[idx]);
18701ae08745Sheppo }
18711ae08745Sheppo
18721ae08745Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) {
18731ae08745Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp,
18741ae08745Sheppo resp->match_curr.mdep[idx],
18751ae08745Sheppo resp->match_prev.mdp,
18761ae08745Sheppo resp->match_prev.mdep[idx]);
18771ae08745Sheppo }
18781ae08745Sheppo
18791ae08745Sheppo mutex_exit(&vgenp->lock);
1880844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n");
18811ae08745Sheppo return (MDEG_SUCCESS);
18821ae08745Sheppo }
18831ae08745Sheppo
1884c1c61f44Ssb155480 /* mdeg callback function for the vnet node */
1885c1c61f44Ssb155480 static int
vgen_mdeg_cb(void * cb_argp,mdeg_result_t * resp)1886c1c61f44Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
1887c1c61f44Ssb155480 {
1888c1c61f44Ssb155480 vgen_t *vgenp;
1889c1c61f44Ssb155480 vnet_t *vnetp;
1890c1c61f44Ssb155480 md_t *mdp;
1891c1c61f44Ssb155480 mde_cookie_t node;
1892c1c61f44Ssb155480 uint64_t inst;
1893c1c61f44Ssb155480 char *node_name = NULL;
1894c1c61f44Ssb155480
1895c1c61f44Ssb155480 if ((resp == NULL) || (cb_argp == NULL)) {
1896c1c61f44Ssb155480 return (MDEG_FAILURE);
1897c1c61f44Ssb155480 }
1898c1c61f44Ssb155480
1899c1c61f44Ssb155480 vgenp = (vgen_t *)cb_argp;
1900c1c61f44Ssb155480 vnetp = vgenp->vnetp;
1901c1c61f44Ssb155480
190252bca946SWENTAO YANG DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d"
1903c1c61f44Ssb155480 " : prev matched %d", resp->added.nelem, resp->removed.nelem,
1904c1c61f44Ssb155480 resp->match_curr.nelem, resp->match_prev.nelem);
1905c1c61f44Ssb155480
1906c1c61f44Ssb155480 mutex_enter(&vgenp->lock);
1907c1c61f44Ssb155480
1908c1c61f44Ssb155480 /*
1909c1c61f44Ssb155480 * We get an initial callback for this node as 'added' after
1910c1c61f44Ssb155480 * registering with mdeg. Note that we would have already gathered
1911c1c61f44Ssb155480 * information about this vnet node by walking MD earlier during attach
1912c1c61f44Ssb155480 * (in vgen_read_mdprops()). So, there is a window where the properties
1913c1c61f44Ssb155480 * of this node might have changed when we get this initial 'added'
1914c1c61f44Ssb155480 * callback. We handle this as if an update occured and invoke the same
1915c1c61f44Ssb155480 * function which handles updates to the properties of this vnet-node
1916c1c61f44Ssb155480 * if any. A non-zero 'match' value indicates that the MD has been
1917c1c61f44Ssb155480 * updated and that a 'network' node is present which may or may not
1918c1c61f44Ssb155480 * have been updated. It is up to the clients to examine their own
1919c1c61f44Ssb155480 * nodes and determine if they have changed.
1920c1c61f44Ssb155480 */
1921c1c61f44Ssb155480 if (resp->added.nelem != 0) {
1922c1c61f44Ssb155480
1923c1c61f44Ssb155480 if (resp->added.nelem != 1) {
1924c1c61f44Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes added "
1925c1c61f44Ssb155480 "invalid: %d\n", vnetp->instance,
1926c1c61f44Ssb155480 resp->added.nelem);
1927c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1928c1c61f44Ssb155480 }
1929c1c61f44Ssb155480
1930c1c61f44Ssb155480 mdp = resp->added.mdp;
1931c1c61f44Ssb155480 node = resp->added.mdep[0];
1932c1c61f44Ssb155480
1933c1c61f44Ssb155480 } else if (resp->match_curr.nelem != 0) {
1934c1c61f44Ssb155480
1935c1c61f44Ssb155480 if (resp->match_curr.nelem != 1) {
1936c1c61f44Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes updated "
1937c1c61f44Ssb155480 "invalid: %d\n", vnetp->instance,
1938c1c61f44Ssb155480 resp->match_curr.nelem);
1939c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1940c1c61f44Ssb155480 }
1941c1c61f44Ssb155480
1942c1c61f44Ssb155480 mdp = resp->match_curr.mdp;
1943c1c61f44Ssb155480 node = resp->match_curr.mdep[0];
1944c1c61f44Ssb155480
1945c1c61f44Ssb155480 } else {
1946c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1947c1c61f44Ssb155480 }
1948c1c61f44Ssb155480
1949c1c61f44Ssb155480 /* Validate name and instance */
1950c1c61f44Ssb155480 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
1951c1c61f44Ssb155480 DERR(vgenp, NULL, "unable to get node name\n");
1952c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1953c1c61f44Ssb155480 }
1954c1c61f44Ssb155480
1955c1c61f44Ssb155480 /* is this a virtual-network device? */
1956c1c61f44Ssb155480 if (strcmp(node_name, vnet_propname) != 0) {
1957c1c61f44Ssb155480 DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name);
1958c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1959c1c61f44Ssb155480 }
1960c1c61f44Ssb155480
1961c1c61f44Ssb155480 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
1962c1c61f44Ssb155480 DERR(vgenp, NULL, "prop(cfg-handle) not found\n");
1963c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1964c1c61f44Ssb155480 }
1965c1c61f44Ssb155480
1966678453a8Sspeer /* is this the right instance of vnet? */
1967c1c61f44Ssb155480 if (inst != vgenp->regprop) {
1968c1c61f44Ssb155480 DERR(vgenp, NULL, "Invalid cfg-handle: %lx\n", inst);
1969c1c61f44Ssb155480 goto vgen_mdeg_cb_err;
1970c1c61f44Ssb155480 }
1971c1c61f44Ssb155480
1972c1c61f44Ssb155480 vgen_update_md_prop(vgenp, mdp, node);
1973c1c61f44Ssb155480
1974c1c61f44Ssb155480 mutex_exit(&vgenp->lock);
1975c1c61f44Ssb155480 return (MDEG_SUCCESS);
1976c1c61f44Ssb155480
1977c1c61f44Ssb155480 vgen_mdeg_cb_err:
1978c1c61f44Ssb155480 mutex_exit(&vgenp->lock);
1979c1c61f44Ssb155480 return (MDEG_FAILURE);
1980c1c61f44Ssb155480 }
1981c1c61f44Ssb155480
1982c1c61f44Ssb155480 /*
1983c1c61f44Ssb155480 * Check to see if the relevant properties in the specified node have
1984c1c61f44Ssb155480 * changed, and if so take the appropriate action.
1985c1c61f44Ssb155480 */
1986c1c61f44Ssb155480 static void
vgen_update_md_prop(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)1987c1c61f44Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
1988c1c61f44Ssb155480 {
1989c1c61f44Ssb155480 uint16_t pvid;
1990c1c61f44Ssb155480 uint16_t *vids;
1991c1c61f44Ssb155480 uint16_t nvids;
1992c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp;
19937b1f684aSSriharsha Basavapatna uint32_t mtu;
19941107ea93SSriharsha Basavapatna boolean_t pls_update;
19957b1f684aSSriharsha Basavapatna enum { MD_init = 0x1,
19967b1f684aSSriharsha Basavapatna MD_vlans = 0x2,
19971107ea93SSriharsha Basavapatna MD_mtu = 0x4,
19981107ea93SSriharsha Basavapatna MD_pls = 0x8 } updated;
19997b1f684aSSriharsha Basavapatna int rv;
20007b1f684aSSriharsha Basavapatna
20017b1f684aSSriharsha Basavapatna updated = MD_init;
2002c1c61f44Ssb155480
2003c1c61f44Ssb155480 /* Read the vlan ids */
2004c1c61f44Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids,
2005c1c61f44Ssb155480 &nvids, NULL);
2006c1c61f44Ssb155480
2007c1c61f44Ssb155480 /* Determine if there are any vlan id updates */
2008c1c61f44Ssb155480 if ((pvid != vnetp->pvid) || /* pvid changed? */
2009c1c61f44Ssb155480 (nvids != vnetp->nvids) || /* # of vids changed? */
2010c1c61f44Ssb155480 ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */
2011c1c61f44Ssb155480 bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) {
20127b1f684aSSriharsha Basavapatna updated |= MD_vlans;
2013c1c61f44Ssb155480 }
2014c1c61f44Ssb155480
20157b1f684aSSriharsha Basavapatna /* Read mtu */
20167b1f684aSSriharsha Basavapatna vgen_mtu_read(vgenp, mdp, mdex, &mtu);
20177b1f684aSSriharsha Basavapatna if (mtu != vnetp->mtu) {
20187b1f684aSSriharsha Basavapatna if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) {
20197b1f684aSSriharsha Basavapatna updated |= MD_mtu;
20207b1f684aSSriharsha Basavapatna } else {
20217b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update"
20227b1f684aSSriharsha Basavapatna " as the specified value:%d is invalid\n",
20237b1f684aSSriharsha Basavapatna vnetp->instance, mtu);
2024c1c61f44Ssb155480 }
2025c1c61f44Ssb155480 }
2026c1c61f44Ssb155480
20271107ea93SSriharsha Basavapatna /*
20281107ea93SSriharsha Basavapatna * Read the 'linkprop' property.
20291107ea93SSriharsha Basavapatna */
20301107ea93SSriharsha Basavapatna vgen_linkprop_read(vgenp, mdp, mdex, &pls_update);
20311107ea93SSriharsha Basavapatna if (pls_update != vnetp->pls_update) {
20321107ea93SSriharsha Basavapatna updated |= MD_pls;
20331107ea93SSriharsha Basavapatna }
20341107ea93SSriharsha Basavapatna
20357b1f684aSSriharsha Basavapatna /* Now process the updated props */
20367b1f684aSSriharsha Basavapatna
20377b1f684aSSriharsha Basavapatna if (updated & MD_vlans) {
20387b1f684aSSriharsha Basavapatna
2039c1c61f44Ssb155480 /* save the new vlan ids */
2040c1c61f44Ssb155480 vnetp->pvid = pvid;
2041c1c61f44Ssb155480 if (vnetp->nvids != 0) {
20427b1f684aSSriharsha Basavapatna kmem_free(vnetp->vids,
20437b1f684aSSriharsha Basavapatna sizeof (uint16_t) * vnetp->nvids);
2044c1c61f44Ssb155480 vnetp->nvids = 0;
2045c1c61f44Ssb155480 }
2046c1c61f44Ssb155480 if (nvids != 0) {
2047c1c61f44Ssb155480 vnetp->nvids = nvids;
2048c1c61f44Ssb155480 vnetp->vids = vids;
2049c1c61f44Ssb155480 }
2050c1c61f44Ssb155480
2051c1c61f44Ssb155480 /* reset vlan-unaware peers (ver < 1.3) and restart handshake */
2052c1c61f44Ssb155480 vgen_reset_vlan_unaware_ports(vgenp);
20537b1f684aSSriharsha Basavapatna
20547b1f684aSSriharsha Basavapatna } else {
20557b1f684aSSriharsha Basavapatna
20567b1f684aSSriharsha Basavapatna if (nvids != 0) {
20577b1f684aSSriharsha Basavapatna kmem_free(vids, sizeof (uint16_t) * nvids);
20587b1f684aSSriharsha Basavapatna }
20597b1f684aSSriharsha Basavapatna }
20607b1f684aSSriharsha Basavapatna
20617b1f684aSSriharsha Basavapatna if (updated & MD_mtu) {
20627b1f684aSSriharsha Basavapatna
20637b1f684aSSriharsha Basavapatna DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n",
20647b1f684aSSriharsha Basavapatna vnetp->mtu, mtu);
20657b1f684aSSriharsha Basavapatna
20667b1f684aSSriharsha Basavapatna rv = vnet_mtu_update(vnetp, mtu);
20677b1f684aSSriharsha Basavapatna if (rv == 0) {
20687b1f684aSSriharsha Basavapatna vgenp->max_frame_size = mtu +
20697b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ;
20707b1f684aSSriharsha Basavapatna }
20717b1f684aSSriharsha Basavapatna }
20721107ea93SSriharsha Basavapatna
20731107ea93SSriharsha Basavapatna if (updated & MD_pls) {
20741107ea93SSriharsha Basavapatna /* enable/disable physical link state updates */
20751107ea93SSriharsha Basavapatna vnetp->pls_update = pls_update;
20766d6de4eeSWENTAO YANG mutex_exit(&vgenp->lock);
20771107ea93SSriharsha Basavapatna
20781107ea93SSriharsha Basavapatna /* reset vsw-port to re-negotiate with the updated prop. */
20791107ea93SSriharsha Basavapatna vgen_reset_vsw_port(vgenp);
20806d6de4eeSWENTAO YANG
20816d6de4eeSWENTAO YANG mutex_enter(&vgenp->lock);
20821107ea93SSriharsha Basavapatna }
2083c1c61f44Ssb155480 }
2084c1c61f44Ssb155480
20851ae08745Sheppo /* add a new port to the device */
20861ae08745Sheppo static int
vgen_add_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)20871ae08745Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
20881ae08745Sheppo {
2089c1c61f44Ssb155480 vgen_port_t *portp;
2090c1c61f44Ssb155480 int rv;
2091c1c61f44Ssb155480
2092c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP);
2093c1c61f44Ssb155480
2094c1c61f44Ssb155480 rv = vgen_port_read_props(portp, vgenp, mdp, mdex);
2095c1c61f44Ssb155480 if (rv != DDI_SUCCESS) {
2096c1c61f44Ssb155480 KMEM_FREE(portp);
2097c1c61f44Ssb155480 return (DDI_FAILURE);
2098c1c61f44Ssb155480 }
2099c1c61f44Ssb155480
2100c1c61f44Ssb155480 rv = vgen_port_attach(portp);
2101c1c61f44Ssb155480 if (rv != DDI_SUCCESS) {
2102c1c61f44Ssb155480 return (DDI_FAILURE);
2103c1c61f44Ssb155480 }
2104c1c61f44Ssb155480
2105c1c61f44Ssb155480 return (DDI_SUCCESS);
2106c1c61f44Ssb155480 }
2107c1c61f44Ssb155480
2108c1c61f44Ssb155480 /* read properties of the port from its md node */
2109c1c61f44Ssb155480 static int
vgen_port_read_props(vgen_port_t * portp,vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)2110c1c61f44Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
2111c1c61f44Ssb155480 mde_cookie_t mdex)
2112c1c61f44Ssb155480 {
21131ae08745Sheppo uint64_t port_num;
21141ae08745Sheppo uint64_t *ldc_ids;
21151ae08745Sheppo uint64_t macaddr;
21161ae08745Sheppo uint64_t val;
21171ae08745Sheppo int num_ldcs;
21181ae08745Sheppo int i;
21191ae08745Sheppo int addrsz;
21201ae08745Sheppo int num_nodes = 0;
21211ae08745Sheppo int listsz = 0;
21221ae08745Sheppo mde_cookie_t *listp = NULL;
21231ae08745Sheppo uint8_t *addrp;
21241ae08745Sheppo struct ether_addr ea;
21251ae08745Sheppo
21261ae08745Sheppo /* read "id" property to get the port number */
21271ae08745Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
2128844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
21291ae08745Sheppo return (DDI_FAILURE);
21301ae08745Sheppo }
21311ae08745Sheppo
21321ae08745Sheppo /*
21331ae08745Sheppo * Find the channel endpoint node(s) under this port node.
21341ae08745Sheppo */
21351ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) {
2136844e62a3Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
2137844e62a3Sraghuram num_nodes);
21381ae08745Sheppo return (DDI_FAILURE);
21391ae08745Sheppo }
21401ae08745Sheppo
21411ae08745Sheppo /* allocate space for node list */
21421ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
21431ae08745Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP);
21441ae08745Sheppo if (listp == NULL)
21451ae08745Sheppo return (DDI_FAILURE);
21461ae08745Sheppo
21471ae08745Sheppo num_ldcs = md_scan_dag(mdp, mdex,
21481ae08745Sheppo md_find_name(mdp, channel_propname),
21491ae08745Sheppo md_find_name(mdp, "fwd"), listp);
21501ae08745Sheppo
21511ae08745Sheppo if (num_ldcs <= 0) {
2152844e62a3Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
21531ae08745Sheppo kmem_free(listp, listsz);
21541ae08745Sheppo return (DDI_FAILURE);
21551ae08745Sheppo }
21561ae08745Sheppo
21577bd3a2e2SSriharsha Basavapatna if (num_ldcs > 1) {
21587bd3a2e2SSriharsha Basavapatna DWARN(vgenp, NULL, "Port %d: Number of channels %d > 1\n",
21597bd3a2e2SSriharsha Basavapatna port_num, num_ldcs);
21607bd3a2e2SSriharsha Basavapatna }
21611ae08745Sheppo
21621ae08745Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
21631ae08745Sheppo if (ldc_ids == NULL) {
21641ae08745Sheppo kmem_free(listp, listsz);
21651ae08745Sheppo return (DDI_FAILURE);
21661ae08745Sheppo }
21671ae08745Sheppo
21681ae08745Sheppo for (i = 0; i < num_ldcs; i++) {
21691ae08745Sheppo /* read channel ids */
21701ae08745Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
2171844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n",
2172844e62a3Sraghuram id_propname);
21731ae08745Sheppo kmem_free(listp, listsz);
21741ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21751ae08745Sheppo return (DDI_FAILURE);
21761ae08745Sheppo }
2177844e62a3Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]);
21781ae08745Sheppo }
21791ae08745Sheppo
21801ae08745Sheppo kmem_free(listp, listsz);
21811ae08745Sheppo
21821ae08745Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
21831ae08745Sheppo &addrsz)) {
2184844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
21851ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21861ae08745Sheppo return (DDI_FAILURE);
21871ae08745Sheppo }
21881ae08745Sheppo
21891ae08745Sheppo if (addrsz < ETHERADDRL) {
2190844e62a3Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
21911ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21921ae08745Sheppo return (DDI_FAILURE);
21931ae08745Sheppo }
21941ae08745Sheppo
21951ae08745Sheppo macaddr = *((uint64_t *)addrp);
21961ae08745Sheppo
2197844e62a3Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
21981ae08745Sheppo
21991ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) {
22001ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF;
22011ae08745Sheppo macaddr >>= 8;
22021ae08745Sheppo }
22031ae08745Sheppo
22041ae08745Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
22051ae08745Sheppo if (val == 0) {
22061107ea93SSriharsha Basavapatna /* This port is connected to the vswitch */
22071107ea93SSriharsha Basavapatna portp->is_vsw_port = B_TRUE;
22081107ea93SSriharsha Basavapatna } else {
22091107ea93SSriharsha Basavapatna portp->is_vsw_port = B_FALSE;
22101ae08745Sheppo }
22111ae08745Sheppo }
2212c1c61f44Ssb155480
2213c1c61f44Ssb155480 /* now update all properties into the port */
2214c1c61f44Ssb155480 portp->vgenp = vgenp;
2215c1c61f44Ssb155480 portp->port_num = port_num;
2216c1c61f44Ssb155480 ether_copy(&ea, &portp->macaddr);
2217c1c61f44Ssb155480 portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP);
2218c1c61f44Ssb155480 bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs);
2219c1c61f44Ssb155480 portp->num_ldcs = num_ldcs;
2220c1c61f44Ssb155480
2221c1c61f44Ssb155480 /* read vlan id properties of this port node */
2222c1c61f44Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid,
2223c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL);
22241ae08745Sheppo
22251ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
22261ae08745Sheppo
2227c1c61f44Ssb155480 return (DDI_SUCCESS);
22281ae08745Sheppo }
22291ae08745Sheppo
22301ae08745Sheppo /* remove a port from the device */
22311ae08745Sheppo static int
vgen_remove_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)22321ae08745Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
22331ae08745Sheppo {
22341ae08745Sheppo uint64_t port_num;
22351ae08745Sheppo vgen_port_t *portp;
22361ae08745Sheppo vgen_portlist_t *plistp;
22371ae08745Sheppo
22381ae08745Sheppo /* read "id" property to get the port number */
22391ae08745Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
2240844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
22411ae08745Sheppo return (DDI_FAILURE);
22421ae08745Sheppo }
22431ae08745Sheppo
22441ae08745Sheppo plistp = &(vgenp->vgenports);
22451ae08745Sheppo
22461ae08745Sheppo WRITE_ENTER(&plistp->rwlock);
22471ae08745Sheppo portp = vgen_port_lookup(plistp, (int)port_num);
22481ae08745Sheppo if (portp == NULL) {
2249844e62a3Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
22501ae08745Sheppo RW_EXIT(&plistp->rwlock);
22511ae08745Sheppo return (DDI_FAILURE);
22521ae08745Sheppo }
22531ae08745Sheppo
22541ae08745Sheppo vgen_port_detach_mdeg(portp);
22551ae08745Sheppo RW_EXIT(&plistp->rwlock);
22561ae08745Sheppo
22571ae08745Sheppo return (DDI_SUCCESS);
22581ae08745Sheppo }
22591ae08745Sheppo
22601ae08745Sheppo /* attach a port to the device based on mdeg data */
22611ae08745Sheppo static int
vgen_port_attach(vgen_port_t * portp)2262c1c61f44Ssb155480 vgen_port_attach(vgen_port_t *portp)
22631ae08745Sheppo {
2264c1c61f44Ssb155480 vgen_portlist_t *plistp;
2265c1c61f44Ssb155480 vgen_t *vgenp;
2266c1c61f44Ssb155480 uint64_t *ldcids;
2267678453a8Sspeer mac_register_t *macp;
2268678453a8Sspeer vio_net_res_type_t type;
2269678453a8Sspeer int rv;
22701ae08745Sheppo
2271c1c61f44Ssb155480 ASSERT(portp != NULL);
2272c1c61f44Ssb155480 vgenp = portp->vgenp;
2273c1c61f44Ssb155480 ldcids = portp->ldc_ids;
22741ae08745Sheppo
22757bd3a2e2SSriharsha Basavapatna DBG2(vgenp, NULL, "port_num(%d), ldcid(%lx)\n",
22767bd3a2e2SSriharsha Basavapatna portp->port_num, ldcids[0]);
22771ae08745Sheppo
2278678453a8Sspeer mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL);
22791ae08745Sheppo
22807bd3a2e2SSriharsha Basavapatna /*
22817bd3a2e2SSriharsha Basavapatna * attach the channel under the port using its channel id;
22827bd3a2e2SSriharsha Basavapatna * note that we only support one channel per port for now.
22837bd3a2e2SSriharsha Basavapatna */
22847bd3a2e2SSriharsha Basavapatna if (vgen_ldc_attach(portp, ldcids[0]) == DDI_FAILURE) {
2285ca7ee4f9Szk194757 vgen_port_detach(portp);
2286ca7ee4f9Szk194757 return (DDI_FAILURE);
2287ca7ee4f9Szk194757 }
22881ae08745Sheppo
2289c1c61f44Ssb155480 /* create vlan id hash table */
2290c1c61f44Ssb155480 vgen_vlan_create_hash(portp);
2291c1c61f44Ssb155480
22921107ea93SSriharsha Basavapatna if (portp->is_vsw_port == B_TRUE) {
2293678453a8Sspeer /* This port is connected to the switch port */
2294678453a8Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_FALSE);
2295678453a8Sspeer type = VIO_NET_RES_LDC_SERVICE;
2296678453a8Sspeer } else {
2297678453a8Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
2298678453a8Sspeer type = VIO_NET_RES_LDC_GUEST;
2299678453a8Sspeer }
2300678453a8Sspeer
2301678453a8Sspeer if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
2302678453a8Sspeer vgen_port_detach(portp);
2303678453a8Sspeer return (DDI_FAILURE);
2304678453a8Sspeer }
2305678453a8Sspeer macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2306678453a8Sspeer macp->m_driver = portp;
2307678453a8Sspeer macp->m_dip = vgenp->vnetdip;
2308678453a8Sspeer macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
2309678453a8Sspeer macp->m_callbacks = &vgen_m_callbacks;
2310678453a8Sspeer macp->m_min_sdu = 0;
2311678453a8Sspeer macp->m_max_sdu = ETHERMTU;
2312678453a8Sspeer
2313678453a8Sspeer mutex_enter(&portp->lock);
2314678453a8Sspeer rv = vio_net_resource_reg(macp, type, vgenp->macaddr,
2315678453a8Sspeer portp->macaddr, &portp->vhp, &portp->vcb);
2316678453a8Sspeer mutex_exit(&portp->lock);
2317678453a8Sspeer mac_free(macp);
2318678453a8Sspeer
2319678453a8Sspeer if (rv == 0) {
23201ae08745Sheppo /* link it into the list of ports */
23211ae08745Sheppo plistp = &(vgenp->vgenports);
23221ae08745Sheppo WRITE_ENTER(&plistp->rwlock);
23231ae08745Sheppo vgen_port_list_insert(portp);
23241ae08745Sheppo RW_EXIT(&plistp->rwlock);
23251107ea93SSriharsha Basavapatna
23261107ea93SSriharsha Basavapatna if (portp->is_vsw_port == B_TRUE) {
23271107ea93SSriharsha Basavapatna /* We now have the vswitch port attached */
23281107ea93SSriharsha Basavapatna vgenp->vsw_portp = portp;
23291107ea93SSriharsha Basavapatna (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
23301107ea93SSriharsha Basavapatna }
2331678453a8Sspeer } else {
2332678453a8Sspeer DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p",
2333678453a8Sspeer portp);
2334678453a8Sspeer vgen_port_detach(portp);
23351ae08745Sheppo }
23361ae08745Sheppo
2337844e62a3Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23381ae08745Sheppo return (DDI_SUCCESS);
23391ae08745Sheppo }
23401ae08745Sheppo
23411ae08745Sheppo /* detach a port from the device based on mdeg data */
23421ae08745Sheppo static void
vgen_port_detach_mdeg(vgen_port_t * portp)23431ae08745Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
23441ae08745Sheppo {
23451ae08745Sheppo vgen_t *vgenp = portp->vgenp;
23461ae08745Sheppo
2347844e62a3Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
2348678453a8Sspeer
2349678453a8Sspeer mutex_enter(&portp->lock);
2350678453a8Sspeer
23511ae08745Sheppo /* stop the port if needed */
2352678453a8Sspeer if (portp->flags & VGEN_STARTED) {
23531ae08745Sheppo vgen_port_uninit(portp);
23540c4606f0SWENTAO YANG portp->flags &= ~(VGEN_STARTED);
23551ae08745Sheppo }
2356678453a8Sspeer
2357678453a8Sspeer mutex_exit(&portp->lock);
23581ae08745Sheppo vgen_port_detach(portp);
23591ae08745Sheppo
2360844e62a3Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23611ae08745Sheppo }
23621ae08745Sheppo
23631ae08745Sheppo static int
vgen_update_port(vgen_t * vgenp,md_t * curr_mdp,mde_cookie_t curr_mdex,md_t * prev_mdp,mde_cookie_t prev_mdex)23641ae08745Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
23651ae08745Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex)
23661ae08745Sheppo {
2367c1c61f44Ssb155480 uint64_t cport_num;
2368c1c61f44Ssb155480 uint64_t pport_num;
2369c1c61f44Ssb155480 vgen_portlist_t *plistp;
2370c1c61f44Ssb155480 vgen_port_t *portp;
2371c1c61f44Ssb155480 boolean_t updated_vlans = B_FALSE;
2372c1c61f44Ssb155480 uint16_t pvid;
2373c1c61f44Ssb155480 uint16_t *vids;
2374c1c61f44Ssb155480 uint16_t nvids;
23751ae08745Sheppo
2376c1c61f44Ssb155480 /*
2377c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed.
2378c1c61f44Ssb155480 * We read the port num and do some sanity check.
2379c1c61f44Ssb155480 */
2380c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) {
2381c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2382c1c61f44Ssb155480 return (DDI_FAILURE);
2383c1c61f44Ssb155480 }
2384c1c61f44Ssb155480
2385c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) {
2386c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2387c1c61f44Ssb155480 return (DDI_FAILURE);
2388c1c61f44Ssb155480 }
2389c1c61f44Ssb155480 if (cport_num != pport_num)
2390c1c61f44Ssb155480 return (DDI_FAILURE);
2391c1c61f44Ssb155480
2392c1c61f44Ssb155480 plistp = &(vgenp->vgenports);
2393c1c61f44Ssb155480
2394c1c61f44Ssb155480 READ_ENTER(&plistp->rwlock);
2395c1c61f44Ssb155480
2396c1c61f44Ssb155480 portp = vgen_port_lookup(plistp, (int)cport_num);
2397c1c61f44Ssb155480 if (portp == NULL) {
2398c1c61f44Ssb155480 DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num);
2399c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock);
2400c1c61f44Ssb155480 return (DDI_FAILURE);
2401c1c61f44Ssb155480 }
2402c1c61f44Ssb155480
2403c1c61f44Ssb155480 /* Read the vlan ids */
2404c1c61f44Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids,
2405c1c61f44Ssb155480 &nvids, NULL);
2406c1c61f44Ssb155480
2407c1c61f44Ssb155480 /* Determine if there are any vlan id updates */
2408c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */
2409c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */
2410c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */
2411c1c61f44Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) {
2412c1c61f44Ssb155480 updated_vlans = B_TRUE;
2413c1c61f44Ssb155480 }
2414c1c61f44Ssb155480
2415c1c61f44Ssb155480 if (updated_vlans == B_FALSE) {
2416c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock);
2417c1c61f44Ssb155480 return (DDI_FAILURE);
2418c1c61f44Ssb155480 }
2419c1c61f44Ssb155480
2420c1c61f44Ssb155480 /* remove the port from vlans it has been assigned to */
2421c1c61f44Ssb155480 vgen_vlan_remove_ids(portp);
2422c1c61f44Ssb155480
2423c1c61f44Ssb155480 /* save the new vlan ids */
2424c1c61f44Ssb155480 portp->pvid = pvid;
2425c1c61f44Ssb155480 if (portp->nvids != 0) {
2426c1c61f44Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids);
2427c1c61f44Ssb155480 portp->nvids = 0;
2428c1c61f44Ssb155480 }
2429c1c61f44Ssb155480 if (nvids != 0) {
2430c1c61f44Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP);
2431c1c61f44Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids);
2432c1c61f44Ssb155480 portp->nvids = nvids;
2433c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids);
2434c1c61f44Ssb155480 }
2435c1c61f44Ssb155480
2436c1c61f44Ssb155480 /* add port to the new vlans */
2437c1c61f44Ssb155480 vgen_vlan_add_ids(portp);
2438c1c61f44Ssb155480
2439c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */
2440c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(portp);
2441c1c61f44Ssb155480
2442c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock);
2443c1c61f44Ssb155480
24441ae08745Sheppo return (DDI_SUCCESS);
24451ae08745Sheppo }
24461ae08745Sheppo
24471ae08745Sheppo static uint64_t
vgen_port_stat(vgen_port_t * portp,uint_t stat)2448ba2e4443Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
24491ae08745Sheppo {
24507bd3a2e2SSriharsha Basavapatna return (vgen_ldc_stat(portp->ldcp, stat));
24517b1f684aSSriharsha Basavapatna }
24527b1f684aSSriharsha Basavapatna
24531ae08745Sheppo /* attach the channel corresponding to the given ldc_id to the port */
24541ae08745Sheppo static int
vgen_ldc_attach(vgen_port_t * portp,uint64_t ldc_id)24551ae08745Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
24561ae08745Sheppo {
24571ae08745Sheppo vgen_t *vgenp;
24587bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp;
24591ae08745Sheppo ldc_attr_t attr;
24601ae08745Sheppo int status;
24611ae08745Sheppo ldc_status_t istatus;
246206db247cSraghuram char kname[MAXNAMELEN];
246306db247cSraghuram int instance;
24641ae08745Sheppo enum {AST_init = 0x0, AST_ldc_alloc = 0x1,
24651ae08745Sheppo AST_mutex_init = 0x2, AST_ldc_init = 0x4,
24667bd3a2e2SSriharsha Basavapatna AST_ldc_reg_cb = 0x8 } attach_state;
24671ae08745Sheppo
24681ae08745Sheppo attach_state = AST_init;
24691ae08745Sheppo vgenp = portp->vgenp;
24701ae08745Sheppo
24711ae08745Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
24721ae08745Sheppo if (ldcp == NULL) {
24731ae08745Sheppo goto ldc_attach_failed;
24741ae08745Sheppo }
24751ae08745Sheppo ldcp->ldc_id = ldc_id;
24761ae08745Sheppo ldcp->portp = portp;
24771ae08745Sheppo
24781ae08745Sheppo attach_state |= AST_ldc_alloc;
24791ae08745Sheppo
24801ae08745Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
24811ae08745Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
24821ae08745Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
2483844e62a3Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
2484844e62a3Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
248563f531d1SSriharsha Basavapatna mutex_init(&ldcp->pollq_lock, NULL, MUTEX_DRIVER, NULL);
24867bd3a2e2SSriharsha Basavapatna mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL);
24877bd3a2e2SSriharsha Basavapatna cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL);
24881ae08745Sheppo
24891ae08745Sheppo attach_state |= AST_mutex_init;
24901ae08745Sheppo
24911ae08745Sheppo attr.devclass = LDC_DEV_NT;
2492678453a8Sspeer attr.instance = vgenp->instance;
24931ae08745Sheppo attr.mode = LDC_MODE_UNRELIABLE;
24947bd3a2e2SSriharsha Basavapatna attr.mtu = vgen_ldc_mtu;
24951ae08745Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
24961ae08745Sheppo if (status != 0) {
2497844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
24981ae08745Sheppo goto ldc_attach_failed;
24991ae08745Sheppo }
25001ae08745Sheppo attach_state |= AST_ldc_init;
25011ae08745Sheppo
25021ae08745Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
25031ae08745Sheppo if (status != 0) {
2504844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
2505844e62a3Sraghuram status);
25061ae08745Sheppo goto ldc_attach_failed;
25071ae08745Sheppo }
2508f0ca1d9aSsb155480 /*
2509f0ca1d9aSsb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and
2510f0ca1d9aSsb155480 * data msgs, including raw data msgs used to recv priority frames.
2511f0ca1d9aSsb155480 */
2512c1c61f44Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size;
2513f0ca1d9aSsb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
25141ae08745Sheppo attach_state |= AST_ldc_reg_cb;
25151ae08745Sheppo
25161ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
25171ae08745Sheppo ASSERT(istatus == LDC_INIT);
25181ae08745Sheppo ldcp->ldc_status = istatus;
25191ae08745Sheppo
25201ae08745Sheppo /* Setup kstats for the channel */
2521678453a8Sspeer instance = vgenp->instance;
252206db247cSraghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id);
252306db247cSraghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats);
252406db247cSraghuram if (ldcp->ksp == NULL) {
25251ae08745Sheppo goto ldc_attach_failed;
25261ae08745Sheppo }
25271ae08745Sheppo
25281ae08745Sheppo /* initialize vgen_versions supported */
25291ae08745Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
2530f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(ldcp);
25311ae08745Sheppo
25327bd3a2e2SSriharsha Basavapatna /* Link this channel to the port */
25337bd3a2e2SSriharsha Basavapatna portp->ldcp = ldcp;
25341ae08745Sheppo
25351107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_UNKNOWN;
25361107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG
25371107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_FALSE;
25381107ea93SSriharsha Basavapatna #endif
25391ae08745Sheppo ldcp->flags |= CHANNEL_ATTACHED;
25401ae08745Sheppo return (DDI_SUCCESS);
25411ae08745Sheppo
25421ae08745Sheppo ldc_attach_failed:
2543844e62a3Sraghuram if (attach_state & AST_ldc_reg_cb) {
2544844e62a3Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle);
2545f0ca1d9aSsb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen);
2546844e62a3Sraghuram }
25477bd3a2e2SSriharsha Basavapatna
25481ae08745Sheppo if (attach_state & AST_ldc_init) {
25491ae08745Sheppo (void) ldc_fini(ldcp->ldc_handle);
25501ae08745Sheppo }
25511ae08745Sheppo if (attach_state & AST_mutex_init) {
25521ae08745Sheppo mutex_destroy(&ldcp->tclock);
25531ae08745Sheppo mutex_destroy(&ldcp->txlock);
25541ae08745Sheppo mutex_destroy(&ldcp->cblock);
2555844e62a3Sraghuram mutex_destroy(&ldcp->wrlock);
2556844e62a3Sraghuram mutex_destroy(&ldcp->rxlock);
255763f531d1SSriharsha Basavapatna mutex_destroy(&ldcp->pollq_lock);
25581ae08745Sheppo }
25591ae08745Sheppo if (attach_state & AST_ldc_alloc) {
25601ae08745Sheppo KMEM_FREE(ldcp);
25611ae08745Sheppo }
25621ae08745Sheppo return (DDI_FAILURE);
25631ae08745Sheppo }
25641ae08745Sheppo
25651ae08745Sheppo /* detach a channel from the port */
25661ae08745Sheppo static void
vgen_ldc_detach(vgen_ldc_t * ldcp)25671ae08745Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
25681ae08745Sheppo {
25691ae08745Sheppo vgen_port_t *portp;
25701ae08745Sheppo vgen_t *vgenp;
25717bd3a2e2SSriharsha Basavapatna
25727bd3a2e2SSriharsha Basavapatna ASSERT(ldcp != NULL);
25731ae08745Sheppo
25741ae08745Sheppo portp = ldcp->portp;
25751ae08745Sheppo vgenp = portp->vgenp;
25761ae08745Sheppo
25771ae08745Sheppo if (ldcp->ldc_status != LDC_INIT) {
2578844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n");
25791ae08745Sheppo }
25801ae08745Sheppo
25811ae08745Sheppo if (ldcp->flags & CHANNEL_ATTACHED) {
25821ae08745Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED);
25831ae08745Sheppo
2584844e62a3Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle);
25857bd3a2e2SSriharsha Basavapatna (void) ldc_fini(ldcp->ldc_handle);
2586d10e4ef2Snarayan
25877bd3a2e2SSriharsha Basavapatna kmem_free(ldcp->ldcmsg, ldcp->msglen);
258806db247cSraghuram vgen_destroy_kstats(ldcp->ksp);
258906db247cSraghuram ldcp->ksp = NULL;
25901ae08745Sheppo mutex_destroy(&ldcp->tclock);
25911ae08745Sheppo mutex_destroy(&ldcp->txlock);
25921ae08745Sheppo mutex_destroy(&ldcp->cblock);
2593844e62a3Sraghuram mutex_destroy(&ldcp->wrlock);
2594844e62a3Sraghuram mutex_destroy(&ldcp->rxlock);
259563f531d1SSriharsha Basavapatna mutex_destroy(&ldcp->pollq_lock);
25967bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->msg_thr_lock);
25977bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->msg_thr_cv);
25981ae08745Sheppo
25991ae08745Sheppo KMEM_FREE(ldcp);
26001ae08745Sheppo }
26011ae08745Sheppo }
26021ae08745Sheppo
26031ae08745Sheppo /* enable transmit/receive on the channel */
26041ae08745Sheppo static int
vgen_ldc_init(vgen_ldc_t * ldcp)26051ae08745Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
26061ae08745Sheppo {
2607844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
26081ae08745Sheppo ldc_status_t istatus;
26091ae08745Sheppo int rv;
2610844e62a3Sraghuram enum { ST_init = 0x0, ST_ldc_open = 0x1,
26117bd3a2e2SSriharsha Basavapatna ST_cb_enable = 0x2} init_state;
26127bd3a2e2SSriharsha Basavapatna int flag = 0;
26137bd3a2e2SSriharsha Basavapatna
26141ae08745Sheppo init_state = ST_init;
26151ae08745Sheppo
2616844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
26171ae08745Sheppo LDC_LOCK(ldcp);
26181ae08745Sheppo
26191ae08745Sheppo rv = ldc_open(ldcp->ldc_handle);
26201ae08745Sheppo if (rv != 0) {
2621844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
26221ae08745Sheppo goto ldcinit_failed;
26231ae08745Sheppo }
26241ae08745Sheppo init_state |= ST_ldc_open;
26251ae08745Sheppo
26261ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
26271ae08745Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) {
2628844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
26291ae08745Sheppo goto ldcinit_failed;
26301ae08745Sheppo }
26311ae08745Sheppo ldcp->ldc_status = istatus;
26321ae08745Sheppo
26337636cb21Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
26347636cb21Slm66018 if (rv != 0) {
2635844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
26367636cb21Slm66018 goto ldcinit_failed;
26377636cb21Slm66018 }
26387636cb21Slm66018
26397636cb21Slm66018 init_state |= ST_cb_enable;
26407636cb21Slm66018
26417bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp);
26421ae08745Sheppo
26431ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
26443af08d82Slm66018 if (istatus == LDC_UP) {
2645844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus);
26461ae08745Sheppo }
26473af08d82Slm66018
26481ae08745Sheppo ldcp->ldc_status = istatus;
26491ae08745Sheppo
26507bd3a2e2SSriharsha Basavapatna ldcp->hphase = VH_PHASE0;
26517bd3a2e2SSriharsha Basavapatna ldcp->hstate = 0;
26521ae08745Sheppo ldcp->flags |= CHANNEL_STARTED;
26531ae08745Sheppo
26547bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(ldcp);
26557bd3a2e2SSriharsha Basavapatna
26563af08d82Slm66018 /* if channel is already UP - start handshake */
26573af08d82Slm66018 if (istatus == LDC_UP) {
26583af08d82Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
26593af08d82Slm66018 if (ldcp->portp != vgenp->vsw_portp) {
26603af08d82Slm66018 /*
2661678453a8Sspeer * As the channel is up, use this port from now on.
26623af08d82Slm66018 */
2663678453a8Sspeer (void) atomic_swap_32(
2664678453a8Sspeer &ldcp->portp->use_vsw_port, B_FALSE);
26653af08d82Slm66018 }
26663af08d82Slm66018
26673af08d82Slm66018 /* Initialize local session id */
26683af08d82Slm66018 ldcp->local_sid = ddi_get_lbolt();
26693af08d82Slm66018
26703af08d82Slm66018 /* clear peer session id */
26713af08d82Slm66018 ldcp->peer_sid = 0;
26723af08d82Slm66018
26733af08d82Slm66018 mutex_exit(&ldcp->tclock);
26743af08d82Slm66018 mutex_exit(&ldcp->txlock);
2675844e62a3Sraghuram mutex_exit(&ldcp->wrlock);
2676844e62a3Sraghuram mutex_exit(&ldcp->rxlock);
26777bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
26783af08d82Slm66018 mutex_exit(&ldcp->cblock);
26797bd3a2e2SSriharsha Basavapatna if (rv != 0) {
26807bd3a2e2SSriharsha Basavapatna flag = (rv == ECONNRESET) ? VGEN_FLAG_EVT_RESET :
26817bd3a2e2SSriharsha Basavapatna VGEN_FLAG_NEED_LDCRESET;
26827bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, flag);
26837bd3a2e2SSriharsha Basavapatna }
26843af08d82Slm66018 } else {
26851ae08745Sheppo LDC_UNLOCK(ldcp);
26863af08d82Slm66018 }
26873af08d82Slm66018
26881ae08745Sheppo return (DDI_SUCCESS);
26891ae08745Sheppo
26901ae08745Sheppo ldcinit_failed:
26917636cb21Slm66018 if (init_state & ST_cb_enable) {
26927636cb21Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
26937636cb21Slm66018 }
26941ae08745Sheppo if (init_state & ST_ldc_open) {
26951ae08745Sheppo (void) ldc_close(ldcp->ldc_handle);
26961ae08745Sheppo }
26971ae08745Sheppo LDC_UNLOCK(ldcp);
2698844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
26991ae08745Sheppo return (DDI_FAILURE);
27001ae08745Sheppo }
27011ae08745Sheppo
27021ae08745Sheppo /* stop transmit/receive on the channel */
27031ae08745Sheppo static void
vgen_ldc_uninit(vgen_ldc_t * ldcp)27041ae08745Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
27051ae08745Sheppo {
2706844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
27071ae08745Sheppo
2708844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
27097bd3a2e2SSriharsha Basavapatna
27101ae08745Sheppo LDC_LOCK(ldcp);
27111ae08745Sheppo
27121ae08745Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) {
27131ae08745Sheppo LDC_UNLOCK(ldcp);
2714844e62a3Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
27151ae08745Sheppo return;
27161ae08745Sheppo }
27171ae08745Sheppo
27181ae08745Sheppo LDC_UNLOCK(ldcp);
27191ae08745Sheppo
27207bd3a2e2SSriharsha Basavapatna while (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
27217bd3a2e2SSriharsha Basavapatna delay(drv_usectohz(VGEN_LDC_UNINIT_DELAY));
27225460ddbdSSriharsha Basavapatna }
27235460ddbdSSriharsha Basavapatna
27247bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, VGEN_FLAG_UNINIT);
27251ae08745Sheppo
2726844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
27271ae08745Sheppo }
27281ae08745Sheppo
27297b1f684aSSriharsha Basavapatna /*
27307bd3a2e2SSriharsha Basavapatna * Create a descriptor ring, that will be exported to the peer for mapping.
27317b1f684aSSriharsha Basavapatna */
27327bd3a2e2SSriharsha Basavapatna static int
vgen_create_dring(vgen_ldc_t * ldcp)27337bd3a2e2SSriharsha Basavapatna vgen_create_dring(vgen_ldc_t *ldcp)
27347bd3a2e2SSriharsha Basavapatna {
27357bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
27367bd3a2e2SSriharsha Basavapatna int rv;
27377bd3a2e2SSriharsha Basavapatna
27387bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
27397bd3a2e2SSriharsha Basavapatna rv = vgen_create_rx_dring(ldcp);
27407b1f684aSSriharsha Basavapatna } else {
27417bd3a2e2SSriharsha Basavapatna rv = vgen_create_tx_dring(ldcp);
27427b1f684aSSriharsha Basavapatna }
27437b1f684aSSriharsha Basavapatna
27447bd3a2e2SSriharsha Basavapatna return (rv);
27451ae08745Sheppo }
27468e6a2a04Slm66018
27478e6a2a04Slm66018 /*
27487bd3a2e2SSriharsha Basavapatna * Destroy the descriptor ring.
27498e6a2a04Slm66018 */
27507bd3a2e2SSriharsha Basavapatna static void
vgen_destroy_dring(vgen_ldc_t * ldcp)27517bd3a2e2SSriharsha Basavapatna vgen_destroy_dring(vgen_ldc_t *ldcp)
27527bd3a2e2SSriharsha Basavapatna {
27537bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
27547bd3a2e2SSriharsha Basavapatna
27557bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
27567bd3a2e2SSriharsha Basavapatna vgen_destroy_rx_dring(ldcp);
27577bd3a2e2SSriharsha Basavapatna } else {
27587bd3a2e2SSriharsha Basavapatna vgen_destroy_tx_dring(ldcp);
27597bd3a2e2SSriharsha Basavapatna }
27608e6a2a04Slm66018 }
27618e6a2a04Slm66018
27628e6a2a04Slm66018 /*
27637bd3a2e2SSriharsha Basavapatna * Map the descriptor ring exported by the peer.
27648e6a2a04Slm66018 */
27651ae08745Sheppo static int
vgen_map_dring(vgen_ldc_t * ldcp,void * pkt)27667bd3a2e2SSriharsha Basavapatna vgen_map_dring(vgen_ldc_t *ldcp, void *pkt)
27671ae08745Sheppo {
27681ae08745Sheppo int rv;
27697bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
27701ae08745Sheppo
27717bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
27727bd3a2e2SSriharsha Basavapatna /*
27737bd3a2e2SSriharsha Basavapatna * In RxDringData mode, dring that we map in
27747bd3a2e2SSriharsha Basavapatna * becomes our transmit descriptor ring.
27757bd3a2e2SSriharsha Basavapatna */
27767bd3a2e2SSriharsha Basavapatna rv = vgen_map_tx_dring(ldcp, pkt);
27777bd3a2e2SSriharsha Basavapatna } else {
27787bd3a2e2SSriharsha Basavapatna
27797bd3a2e2SSriharsha Basavapatna /*
27807bd3a2e2SSriharsha Basavapatna * In TxDring mode, dring that we map in
27817bd3a2e2SSriharsha Basavapatna * becomes our receive descriptor ring.
27827bd3a2e2SSriharsha Basavapatna */
27837bd3a2e2SSriharsha Basavapatna rv = vgen_map_rx_dring(ldcp, pkt);
27847bd3a2e2SSriharsha Basavapatna }
27857bd3a2e2SSriharsha Basavapatna
27867bd3a2e2SSriharsha Basavapatna return (rv);
27871ae08745Sheppo }
27881ae08745Sheppo
27891ae08745Sheppo /*
27907bd3a2e2SSriharsha Basavapatna * Unmap the descriptor ring exported by the peer.
27911ae08745Sheppo */
27927bd3a2e2SSriharsha Basavapatna static void
vgen_unmap_dring(vgen_ldc_t * ldcp)27937bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(vgen_ldc_t *ldcp)
27947bd3a2e2SSriharsha Basavapatna {
27957bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
27967bd3a2e2SSriharsha Basavapatna
27977bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
27987bd3a2e2SSriharsha Basavapatna vgen_unmap_tx_dring(ldcp);
27997bd3a2e2SSriharsha Basavapatna } else {
28007bd3a2e2SSriharsha Basavapatna vgen_unmap_rx_dring(ldcp);
28017bd3a2e2SSriharsha Basavapatna }
28021ae08745Sheppo }
28031ae08745Sheppo
28047bd3a2e2SSriharsha Basavapatna void
vgen_destroy_rxpools(void * arg)28057bd3a2e2SSriharsha Basavapatna vgen_destroy_rxpools(void *arg)
28067bd3a2e2SSriharsha Basavapatna {
28077bd3a2e2SSriharsha Basavapatna vio_mblk_pool_t *poolp = (vio_mblk_pool_t *)arg;
28087bd3a2e2SSriharsha Basavapatna vio_mblk_pool_t *npoolp;
28091ae08745Sheppo
28107bd3a2e2SSriharsha Basavapatna while (poolp != NULL) {
28117bd3a2e2SSriharsha Basavapatna npoolp = poolp->nextp;
28127bd3a2e2SSriharsha Basavapatna while (vio_destroy_mblks(poolp) != 0) {
2813a862df29SSriharsha Basavapatna delay(drv_usectohz(vgen_rxpool_cleanup_delay));
28147bd3a2e2SSriharsha Basavapatna }
28157bd3a2e2SSriharsha Basavapatna poolp = npoolp;
28167bd3a2e2SSriharsha Basavapatna }
28171ae08745Sheppo }
28181ae08745Sheppo
28191ae08745Sheppo /* get channel statistics */
28201ae08745Sheppo static uint64_t
vgen_ldc_stat(vgen_ldc_t * ldcp,uint_t stat)2821ba2e4443Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
28221ae08745Sheppo {
28231ae08745Sheppo vgen_stats_t *statsp;
28241ae08745Sheppo uint64_t val;
28251ae08745Sheppo
28261ae08745Sheppo val = 0;
282706db247cSraghuram statsp = &ldcp->stats;
28281ae08745Sheppo switch (stat) {
28291ae08745Sheppo
28301ae08745Sheppo case MAC_STAT_MULTIRCV:
28311ae08745Sheppo val = statsp->multircv;
28321ae08745Sheppo break;
28331ae08745Sheppo
28341ae08745Sheppo case MAC_STAT_BRDCSTRCV:
28351ae08745Sheppo val = statsp->brdcstrcv;
28361ae08745Sheppo break;
28371ae08745Sheppo
28381ae08745Sheppo case MAC_STAT_MULTIXMT:
28391ae08745Sheppo val = statsp->multixmt;
28401ae08745Sheppo break;
28411ae08745Sheppo
28421ae08745Sheppo case MAC_STAT_BRDCSTXMT:
28431ae08745Sheppo val = statsp->brdcstxmt;
28441ae08745Sheppo break;
28451ae08745Sheppo
28461ae08745Sheppo case MAC_STAT_NORCVBUF:
28471ae08745Sheppo val = statsp->norcvbuf;
28481ae08745Sheppo break;
28491ae08745Sheppo
28501ae08745Sheppo case MAC_STAT_IERRORS:
28511ae08745Sheppo val = statsp->ierrors;
28521ae08745Sheppo break;
28531ae08745Sheppo
28541ae08745Sheppo case MAC_STAT_NOXMTBUF:
28551ae08745Sheppo val = statsp->noxmtbuf;
28561ae08745Sheppo break;
28571ae08745Sheppo
28581ae08745Sheppo case MAC_STAT_OERRORS:
28591ae08745Sheppo val = statsp->oerrors;
28601ae08745Sheppo break;
28611ae08745Sheppo
28621ae08745Sheppo case MAC_STAT_COLLISIONS:
28631ae08745Sheppo break;
28641ae08745Sheppo
28651ae08745Sheppo case MAC_STAT_RBYTES:
28661ae08745Sheppo val = statsp->rbytes;
28671ae08745Sheppo break;
28681ae08745Sheppo
28691ae08745Sheppo case MAC_STAT_IPACKETS:
28701ae08745Sheppo val = statsp->ipackets;
28711ae08745Sheppo break;
28721ae08745Sheppo
28731ae08745Sheppo case MAC_STAT_OBYTES:
28741ae08745Sheppo val = statsp->obytes;
28751ae08745Sheppo break;
28761ae08745Sheppo
28771ae08745Sheppo case MAC_STAT_OPACKETS:
28781ae08745Sheppo val = statsp->opackets;
28791ae08745Sheppo break;
28801ae08745Sheppo
28811ae08745Sheppo /* stats not relevant to ldc, return 0 */
28821ae08745Sheppo case MAC_STAT_IFSPEED:
2883ba2e4443Sseb case ETHER_STAT_ALIGN_ERRORS:
2884ba2e4443Sseb case ETHER_STAT_FCS_ERRORS:
2885ba2e4443Sseb case ETHER_STAT_FIRST_COLLISIONS:
2886ba2e4443Sseb case ETHER_STAT_MULTI_COLLISIONS:
2887ba2e4443Sseb case ETHER_STAT_DEFER_XMTS:
2888ba2e4443Sseb case ETHER_STAT_TX_LATE_COLLISIONS:
2889ba2e4443Sseb case ETHER_STAT_EX_COLLISIONS:
2890ba2e4443Sseb case ETHER_STAT_MACXMT_ERRORS:
2891ba2e4443Sseb case ETHER_STAT_CARRIER_ERRORS:
2892ba2e4443Sseb case ETHER_STAT_TOOLONG_ERRORS:
2893ba2e4443Sseb case ETHER_STAT_XCVR_ADDR:
2894ba2e4443Sseb case ETHER_STAT_XCVR_ID:
2895ba2e4443Sseb case ETHER_STAT_XCVR_INUSE:
2896ba2e4443Sseb case ETHER_STAT_CAP_1000FDX:
2897ba2e4443Sseb case ETHER_STAT_CAP_1000HDX:
2898ba2e4443Sseb case ETHER_STAT_CAP_100FDX:
2899ba2e4443Sseb case ETHER_STAT_CAP_100HDX:
2900ba2e4443Sseb case ETHER_STAT_CAP_10FDX:
2901ba2e4443Sseb case ETHER_STAT_CAP_10HDX:
2902ba2e4443Sseb case ETHER_STAT_CAP_ASMPAUSE:
2903ba2e4443Sseb case ETHER_STAT_CAP_PAUSE:
2904ba2e4443Sseb case ETHER_STAT_CAP_AUTONEG:
2905ba2e4443Sseb case ETHER_STAT_ADV_CAP_1000FDX:
2906ba2e4443Sseb case ETHER_STAT_ADV_CAP_1000HDX:
2907ba2e4443Sseb case ETHER_STAT_ADV_CAP_100FDX:
2908ba2e4443Sseb case ETHER_STAT_ADV_CAP_100HDX:
2909ba2e4443Sseb case ETHER_STAT_ADV_CAP_10FDX:
2910ba2e4443Sseb case ETHER_STAT_ADV_CAP_10HDX:
2911ba2e4443Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE:
2912ba2e4443Sseb case ETHER_STAT_ADV_CAP_PAUSE:
2913ba2e4443Sseb case ETHER_STAT_ADV_CAP_AUTONEG:
2914ba2e4443Sseb case ETHER_STAT_LP_CAP_1000FDX:
2915ba2e4443Sseb case ETHER_STAT_LP_CAP_1000HDX:
2916ba2e4443Sseb case ETHER_STAT_LP_CAP_100FDX:
2917ba2e4443Sseb case ETHER_STAT_LP_CAP_100HDX:
2918ba2e4443Sseb case ETHER_STAT_LP_CAP_10FDX:
2919ba2e4443Sseb case ETHER_STAT_LP_CAP_10HDX:
2920ba2e4443Sseb case ETHER_STAT_LP_CAP_ASMPAUSE:
2921ba2e4443Sseb case ETHER_STAT_LP_CAP_PAUSE:
2922ba2e4443Sseb case ETHER_STAT_LP_CAP_AUTONEG:
2923ba2e4443Sseb case ETHER_STAT_LINK_ASMPAUSE:
2924ba2e4443Sseb case ETHER_STAT_LINK_PAUSE:
2925ba2e4443Sseb case ETHER_STAT_LINK_AUTONEG:
2926ba2e4443Sseb case ETHER_STAT_LINK_DUPLEX:
29271ae08745Sheppo default:
29281ae08745Sheppo val = 0;
29291ae08745Sheppo break;
29301ae08745Sheppo
29311ae08745Sheppo }
29321ae08745Sheppo return (val);
29331ae08745Sheppo }
29341ae08745Sheppo
29353af08d82Slm66018 /*
2936678453a8Sspeer * LDC channel is UP, start handshake process with peer.
29373af08d82Slm66018 */
29383af08d82Slm66018 static void
vgen_handle_evt_up(vgen_ldc_t * ldcp)2939678453a8Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp)
29403af08d82Slm66018 {
29413af08d82Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
29423af08d82Slm66018
2943844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
29443af08d82Slm66018
29453af08d82Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock));
29463af08d82Slm66018
29473af08d82Slm66018 if (ldcp->portp != vgenp->vsw_portp) {
29483af08d82Slm66018 /*
2949678453a8Sspeer * As the channel is up, use this port from now on.
29503af08d82Slm66018 */
2951678453a8Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE);
29523af08d82Slm66018 }
29533af08d82Slm66018
29543af08d82Slm66018 /* Initialize local session id */
29553af08d82Slm66018 ldcp->local_sid = ddi_get_lbolt();
29563af08d82Slm66018
29573af08d82Slm66018 /* clear peer session id */
29583af08d82Slm66018 ldcp->peer_sid = 0;
29593af08d82Slm66018
29603af08d82Slm66018 /* Initiate Handshake process with peer ldc endpoint */
29617bd3a2e2SSriharsha Basavapatna (void) vgen_handshake(vh_nextphase(ldcp));
29623af08d82Slm66018
2963844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
29643af08d82Slm66018 }
29653af08d82Slm66018
29663af08d82Slm66018 /*
29673af08d82Slm66018 * LDC channel is Reset, terminate connection with peer and try to
29683af08d82Slm66018 * bring the channel up again.
29693af08d82Slm66018 */
29707bd3a2e2SSriharsha Basavapatna int
vgen_handle_evt_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)29717bd3a2e2SSriharsha Basavapatna vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
29723af08d82Slm66018 {
29737bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
29743af08d82Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock));
2975678453a8Sspeer }
2976678453a8Sspeer
29777bd3a2e2SSriharsha Basavapatna /* Set the flag to indicate reset is in progress */
29787bd3a2e2SSriharsha Basavapatna if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
29797bd3a2e2SSriharsha Basavapatna /* another thread is already in the process of resetting */
29807bd3a2e2SSriharsha Basavapatna return (EBUSY);
29813af08d82Slm66018 }
29823af08d82Slm66018
29837bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
29847bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
29853af08d82Slm66018 }
29863af08d82Slm66018
29877bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, VGEN_FLAG_EVT_RESET);
29883af08d82Slm66018
29897bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
29907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
29913af08d82Slm66018 }
29923af08d82Slm66018
29937bd3a2e2SSriharsha Basavapatna return (0);
29943af08d82Slm66018 }
29953af08d82Slm66018
29961ae08745Sheppo /* Interrupt handler for the channel */
29971ae08745Sheppo static uint_t
vgen_ldc_cb(uint64_t event,caddr_t arg)29981ae08745Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
29991ae08745Sheppo {
30001ae08745Sheppo _NOTE(ARGUNUSED(event))
30011ae08745Sheppo vgen_ldc_t *ldcp;
30021ae08745Sheppo vgen_t *vgenp;
30031ae08745Sheppo ldc_status_t istatus;
30041ae08745Sheppo vgen_stats_t *statsp;
300552bca946SWENTAO YANG uint_t ret = LDC_SUCCESS;
30061ae08745Sheppo
30071ae08745Sheppo ldcp = (vgen_ldc_t *)arg;
30081ae08745Sheppo vgenp = LDC_TO_VGEN(ldcp);
300906db247cSraghuram statsp = &ldcp->stats;
30101ae08745Sheppo
3011844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
30121ae08745Sheppo
30131ae08745Sheppo mutex_enter(&ldcp->cblock);
30141ae08745Sheppo statsp->callbacks++;
30151ae08745Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
3016844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n",
3017844e62a3Sraghuram ldcp->ldc_status);
30181ae08745Sheppo mutex_exit(&ldcp->cblock);
30191ae08745Sheppo return (LDC_SUCCESS);
30201ae08745Sheppo }
30211ae08745Sheppo
30221ae08745Sheppo /*
30233af08d82Slm66018 * NOTE: not using switch() as event could be triggered by
30243af08d82Slm66018 * a state change and a read request. Also the ordering of the
30253af08d82Slm66018 * check for the event types is deliberate.
30261ae08745Sheppo */
30273af08d82Slm66018 if (event & LDC_EVT_UP) {
30283af08d82Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3029844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n");
30307062b44aSraghuram /* status couldn't be determined */
303152bca946SWENTAO YANG ret = LDC_FAILURE;
303252bca946SWENTAO YANG goto ldc_cb_ret;
30331ae08745Sheppo }
30347062b44aSraghuram ldcp->ldc_status = istatus;
30357062b44aSraghuram if (ldcp->ldc_status != LDC_UP) {
30367062b44aSraghuram DWARN(vgenp, ldcp, "LDC_EVT_UP received "
30377062b44aSraghuram " but ldc status is not UP(0x%x)\n",
30387062b44aSraghuram ldcp->ldc_status);
30397062b44aSraghuram /* spurious interrupt, return success */
304052bca946SWENTAO YANG goto ldc_cb_ret;
30417062b44aSraghuram }
3042844e62a3Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n",
3043844e62a3Sraghuram event, ldcp->ldc_status);
30443af08d82Slm66018
3045678453a8Sspeer vgen_handle_evt_up(ldcp);
30463af08d82Slm66018
30473af08d82Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
30481ae08745Sheppo }
30491ae08745Sheppo
30507062b44aSraghuram /* Handle RESET/DOWN before READ event */
30517062b44aSraghuram if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
30527062b44aSraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
30537062b44aSraghuram DWARN(vgenp, ldcp, "ldc_status error\n");
30547062b44aSraghuram /* status couldn't be determined */
305552bca946SWENTAO YANG ret = LDC_FAILURE;
305652bca946SWENTAO YANG goto ldc_cb_ret;
30577062b44aSraghuram }
30587062b44aSraghuram ldcp->ldc_status = istatus;
30597062b44aSraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
30607062b44aSraghuram event, ldcp->ldc_status);
30617062b44aSraghuram
30627bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, VGEN_LDC_CB);
30637062b44aSraghuram
30647062b44aSraghuram /*
30657062b44aSraghuram * As the channel is down/reset, ignore READ event
30667062b44aSraghuram * but print a debug warning message.
30677062b44aSraghuram */
30687062b44aSraghuram if (event & LDC_EVT_READ) {
30697062b44aSraghuram DWARN(vgenp, ldcp,
30707062b44aSraghuram "LDC_EVT_READ set along with RESET/DOWN\n");
30717062b44aSraghuram event &= ~LDC_EVT_READ;
30727062b44aSraghuram }
30737062b44aSraghuram }
30747062b44aSraghuram
30753af08d82Slm66018 if (event & LDC_EVT_READ) {
3076844e62a3Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n",
3077844e62a3Sraghuram event, ldcp->ldc_status);
30783af08d82Slm66018
30793af08d82Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
3080844e62a3Sraghuram
30817bd3a2e2SSriharsha Basavapatna if (ldcp->msg_thread != NULL) {
3082844e62a3Sraghuram /*
3083844e62a3Sraghuram * If the receive thread is enabled, then
3084844e62a3Sraghuram * wakeup the receive thread to process the
3085844e62a3Sraghuram * LDC messages.
3086844e62a3Sraghuram */
3087844e62a3Sraghuram mutex_exit(&ldcp->cblock);
30887bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock);
30897bd3a2e2SSriharsha Basavapatna if (!(ldcp->msg_thr_flags & VGEN_WTHR_DATARCVD)) {
30907bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags |= VGEN_WTHR_DATARCVD;
30917bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->msg_thr_cv);
3092844e62a3Sraghuram }
30937bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->msg_thr_lock);
3094844e62a3Sraghuram mutex_enter(&ldcp->cblock);
3095844e62a3Sraghuram } else {
30967bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_read(ldcp, VGEN_LDC_CB);
3097844e62a3Sraghuram }
30983af08d82Slm66018 }
309952bca946SWENTAO YANG
310052bca946SWENTAO YANG ldc_cb_ret:
31011ae08745Sheppo mutex_exit(&ldcp->cblock);
3102844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
310352bca946SWENTAO YANG return (ret);
3104844e62a3Sraghuram }
3105844e62a3Sraghuram
31067bd3a2e2SSriharsha Basavapatna int
vgen_handle_evt_read(vgen_ldc_t * ldcp,vgen_caller_t caller)31077bd3a2e2SSriharsha Basavapatna vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller)
3108844e62a3Sraghuram {
3109844e62a3Sraghuram int rv;
3110f0ca1d9aSsb155480 uint64_t *ldcmsg;
3111844e62a3Sraghuram size_t msglen;
3112844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3113844e62a3Sraghuram vio_msg_tag_t *tagp;
3114844e62a3Sraghuram ldc_status_t istatus;
3115844e62a3Sraghuram boolean_t has_data;
3116844e62a3Sraghuram
3117844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
3118844e62a3Sraghuram
31197bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB) {
31207bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock));
31217bd3a2e2SSriharsha Basavapatna } else if (caller == VGEN_MSG_THR) {
3122844e62a3Sraghuram mutex_enter(&ldcp->cblock);
3123844e62a3Sraghuram } else {
31247bd3a2e2SSriharsha Basavapatna return (EINVAL);
3125844e62a3Sraghuram }
3126844e62a3Sraghuram
31277bd3a2e2SSriharsha Basavapatna ldcmsg = ldcp->ldcmsg;
31287bd3a2e2SSriharsha Basavapatna
31297bd3a2e2SSriharsha Basavapatna vgen_evtread:
31301ae08745Sheppo do {
3131f0ca1d9aSsb155480 msglen = ldcp->msglen;
3132f0ca1d9aSsb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
31331ae08745Sheppo
31341ae08745Sheppo if (rv != 0) {
31357bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_read() failed "
31367bd3a2e2SSriharsha Basavapatna "rv(%d) len(%d)\n", rv, msglen);
31373af08d82Slm66018 if (rv == ECONNRESET)
3138844e62a3Sraghuram goto vgen_evtread_error;
31391ae08745Sheppo break;
31401ae08745Sheppo }
31411ae08745Sheppo if (msglen == 0) {
3142844e62a3Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA");
31431ae08745Sheppo break;
31441ae08745Sheppo }
3145844e62a3Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen);
31461ae08745Sheppo
31471ae08745Sheppo tagp = (vio_msg_tag_t *)ldcmsg;
31481ae08745Sheppo
31491ae08745Sheppo if (ldcp->peer_sid) {
31501ae08745Sheppo /*
31511ae08745Sheppo * check sid only after we have received peer's sid
31521ae08745Sheppo * in the version negotiate msg.
31531ae08745Sheppo */
31541ae08745Sheppo #ifdef DEBUG
31557bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HSID)) {
31561ae08745Sheppo /* simulate bad sid condition */
31571ae08745Sheppo tagp->vio_sid = 0;
31587bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HSID);
31591ae08745Sheppo }
31601ae08745Sheppo #endif
31613af08d82Slm66018 rv = vgen_check_sid(ldcp, tagp);
31623af08d82Slm66018 if (rv != VGEN_SUCCESS) {
31631ae08745Sheppo /*
31641ae08745Sheppo * If sid mismatch is detected,
31651ae08745Sheppo * reset the channel.
31661ae08745Sheppo */
31677bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_check_sid() failed\n");
3168844e62a3Sraghuram goto vgen_evtread_error;
31691ae08745Sheppo }
31701ae08745Sheppo }
31711ae08745Sheppo
31721ae08745Sheppo switch (tagp->vio_msgtype) {
31731ae08745Sheppo case VIO_TYPE_CTRL:
31743af08d82Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp);
31757bd3a2e2SSriharsha Basavapatna if (rv != 0) {
31767bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_handle_ctrlmsg()"
31777bd3a2e2SSriharsha Basavapatna " failed rv(%d)\n", rv);
31787bd3a2e2SSriharsha Basavapatna }
31791ae08745Sheppo break;
31801ae08745Sheppo
31811ae08745Sheppo case VIO_TYPE_DATA:
3182f0ca1d9aSsb155480 rv = vgen_handle_datamsg(ldcp, tagp, msglen);
31837bd3a2e2SSriharsha Basavapatna if (rv != 0) {
31847bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_handle_datamsg()"
31857bd3a2e2SSriharsha Basavapatna " failed rv(%d)\n", rv);
31867bd3a2e2SSriharsha Basavapatna }
31871ae08745Sheppo break;
31881ae08745Sheppo
31891ae08745Sheppo case VIO_TYPE_ERR:
31901ae08745Sheppo vgen_handle_errmsg(ldcp, tagp);
31911ae08745Sheppo break;
31921ae08745Sheppo
31931ae08745Sheppo default:
3194844e62a3Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n",
3195844e62a3Sraghuram tagp->vio_msgtype);
31961ae08745Sheppo break;
31971ae08745Sheppo }
31981ae08745Sheppo
3199844e62a3Sraghuram /*
3200844e62a3Sraghuram * If an error is encountered, stop processing and
3201844e62a3Sraghuram * handle the error.
3202844e62a3Sraghuram */
3203844e62a3Sraghuram if (rv != 0) {
3204844e62a3Sraghuram goto vgen_evtread_error;
32053af08d82Slm66018 }
32063af08d82Slm66018
32071ae08745Sheppo } while (msglen);
32081ae08745Sheppo
3209844e62a3Sraghuram /* check once more before exiting */
3210844e62a3Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data);
3211844e62a3Sraghuram if ((rv == 0) && (has_data == B_TRUE)) {
32127bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(vgen_chkq, vgen_ldc_t *, ldcp);
32137bd3a2e2SSriharsha Basavapatna goto vgen_evtread;
32141ae08745Sheppo }
3215bd8f0338Snarayan
3216844e62a3Sraghuram vgen_evtread_error:
32177bd3a2e2SSriharsha Basavapatna if (rv != 0) {
32187bd3a2e2SSriharsha Basavapatna /*
32197bd3a2e2SSriharsha Basavapatna * We handle the error and then return the error value. If we
32207bd3a2e2SSriharsha Basavapatna * are running in the context of the msg worker, the error
32217bd3a2e2SSriharsha Basavapatna * tells the worker thread to exit, as the channel would have
32227bd3a2e2SSriharsha Basavapatna * been reset.
32237bd3a2e2SSriharsha Basavapatna */
3224844e62a3Sraghuram if (rv == ECONNRESET) {
3225844e62a3Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3226844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n");
3227844e62a3Sraghuram } else {
3228844e62a3Sraghuram ldcp->ldc_status = istatus;
3229844e62a3Sraghuram }
32307bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, caller);
32317bd3a2e2SSriharsha Basavapatna } else {
32327bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Calling vgen_ldc_reset()...\n");
32337bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, caller);
32347bd3a2e2SSriharsha Basavapatna }
3235844e62a3Sraghuram }
3236844e62a3Sraghuram
32377bd3a2e2SSriharsha Basavapatna if (caller == VGEN_MSG_THR) {
3238844e62a3Sraghuram mutex_exit(&ldcp->cblock);
3239844e62a3Sraghuram }
32401ae08745Sheppo
3241844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
32427bd3a2e2SSriharsha Basavapatna return (rv);
32431ae08745Sheppo }
32441ae08745Sheppo
32451ae08745Sheppo /* vgen handshake functions */
32461ae08745Sheppo
32471ae08745Sheppo /* change the hphase for the channel to the next phase */
32481ae08745Sheppo static vgen_ldc_t *
vh_nextphase(vgen_ldc_t * ldcp)32491ae08745Sheppo vh_nextphase(vgen_ldc_t *ldcp)
32501ae08745Sheppo {
32517bd3a2e2SSriharsha Basavapatna if (ldcp->hphase == VH_PHASE4) {
32521ae08745Sheppo ldcp->hphase = VH_DONE;
32531ae08745Sheppo } else {
32541ae08745Sheppo ldcp->hphase++;
32551ae08745Sheppo }
32561ae08745Sheppo return (ldcp);
32571ae08745Sheppo }
32581ae08745Sheppo
32591ae08745Sheppo /* send version negotiate message to the peer over ldc */
32601ae08745Sheppo static int
vgen_send_version_negotiate(vgen_ldc_t * ldcp)32611ae08745Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
32621ae08745Sheppo {
3263844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
32641ae08745Sheppo vio_ver_msg_t vermsg;
32651ae08745Sheppo vio_msg_tag_t *tagp = &vermsg.tag;
32661ae08745Sheppo int rv;
32671ae08745Sheppo
32681ae08745Sheppo bzero(&vermsg, sizeof (vermsg));
32691ae08745Sheppo
32701ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
32711ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
32721ae08745Sheppo tagp->vio_subtype_env = VIO_VER_INFO;
32731ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
32741ae08745Sheppo
32751ae08745Sheppo /* get version msg payload from ldcp->local */
32761ae08745Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major;
32771ae08745Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor;
32781ae08745Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class;
32791ae08745Sheppo
32801ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
32811ae08745Sheppo if (rv != VGEN_SUCCESS) {
3282844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
32833af08d82Slm66018 return (rv);
32841ae08745Sheppo }
32851ae08745Sheppo
32861ae08745Sheppo ldcp->hstate |= VER_INFO_SENT;
3287844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n",
3288844e62a3Sraghuram vermsg.ver_major, vermsg.ver_minor);
32891ae08745Sheppo
32901ae08745Sheppo return (VGEN_SUCCESS);
32911ae08745Sheppo }
32921ae08745Sheppo
32931ae08745Sheppo /* send attr info message to the peer over ldc */
32941ae08745Sheppo static int
vgen_send_attr_info(vgen_ldc_t * ldcp)32951ae08745Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
32961ae08745Sheppo {
3297844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
32981ae08745Sheppo vnet_attr_msg_t attrmsg;
32991ae08745Sheppo vio_msg_tag_t *tagp = &attrmsg.tag;
33001ae08745Sheppo int rv;
33011ae08745Sheppo
33021ae08745Sheppo bzero(&attrmsg, sizeof (attrmsg));
33031ae08745Sheppo
33041ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
33051ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
33061ae08745Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO;
33071ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
33081ae08745Sheppo
33091ae08745Sheppo /* get attr msg payload from ldcp->local */
33101ae08745Sheppo attrmsg.mtu = ldcp->local_hparams.mtu;
33111ae08745Sheppo attrmsg.addr = ldcp->local_hparams.addr;
33121ae08745Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type;
33131ae08745Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
33141ae08745Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
33151107ea93SSriharsha Basavapatna attrmsg.physlink_update = ldcp->local_hparams.physlink_update;
33167bd3a2e2SSriharsha Basavapatna attrmsg.options = ldcp->local_hparams.dring_mode;
33171ae08745Sheppo
33181ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
33191ae08745Sheppo if (rv != VGEN_SUCCESS) {
3320844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
33213af08d82Slm66018 return (rv);
33221ae08745Sheppo }
33231ae08745Sheppo
33241ae08745Sheppo ldcp->hstate |= ATTR_INFO_SENT;
3325844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n");
33261ae08745Sheppo
33271ae08745Sheppo return (VGEN_SUCCESS);
33281ae08745Sheppo }
33291ae08745Sheppo
33307bd3a2e2SSriharsha Basavapatna /*
33317bd3a2e2SSriharsha Basavapatna * Send descriptor ring register message to the peer over ldc.
33327bd3a2e2SSriharsha Basavapatna * Invoked in RxDringData mode.
33337bd3a2e2SSriharsha Basavapatna */
33341ae08745Sheppo static int
vgen_send_rx_dring_reg(vgen_ldc_t * ldcp)33357bd3a2e2SSriharsha Basavapatna vgen_send_rx_dring_reg(vgen_ldc_t *ldcp)
33367bd3a2e2SSriharsha Basavapatna {
33377bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
33387bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *msg;
33397bd3a2e2SSriharsha Basavapatna vio_dring_reg_ext_msg_t *emsg;
33407bd3a2e2SSriharsha Basavapatna int rv;
33417bd3a2e2SSriharsha Basavapatna uint8_t *buf;
33427bd3a2e2SSriharsha Basavapatna uint_t msgsize;
33437bd3a2e2SSriharsha Basavapatna
33447bd3a2e2SSriharsha Basavapatna msgsize = VNET_DRING_REG_EXT_MSG_SIZE(ldcp->rx_data_ncookies);
33457bd3a2e2SSriharsha Basavapatna msg = kmem_zalloc(msgsize, KM_SLEEP);
33467bd3a2e2SSriharsha Basavapatna
33477bd3a2e2SSriharsha Basavapatna /* Initialize the common part of dring reg msg */
33487bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(ldcp, msg, VIO_RX_DRING_DATA);
33497bd3a2e2SSriharsha Basavapatna
33507bd3a2e2SSriharsha Basavapatna /* skip over dring cookies at the tail of common section */
33517bd3a2e2SSriharsha Basavapatna buf = (uint8_t *)msg->cookie;
33527bd3a2e2SSriharsha Basavapatna ASSERT(msg->ncookies == 1);
33537bd3a2e2SSriharsha Basavapatna buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
33547bd3a2e2SSriharsha Basavapatna
33557bd3a2e2SSriharsha Basavapatna /* Now setup the extended part, specific to RxDringData mode */
33567bd3a2e2SSriharsha Basavapatna emsg = (vio_dring_reg_ext_msg_t *)buf;
33577bd3a2e2SSriharsha Basavapatna
33587bd3a2e2SSriharsha Basavapatna /* copy data_ncookies in the msg */
33597bd3a2e2SSriharsha Basavapatna emsg->data_ncookies = ldcp->rx_data_ncookies;
33607bd3a2e2SSriharsha Basavapatna
33617bd3a2e2SSriharsha Basavapatna /* copy data area size in the msg */
33627bd3a2e2SSriharsha Basavapatna emsg->data_area_size = ldcp->rx_data_sz;
33637bd3a2e2SSriharsha Basavapatna
33647bd3a2e2SSriharsha Basavapatna /* copy data area cookies in the msg */
33657bd3a2e2SSriharsha Basavapatna bcopy(ldcp->rx_data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie,
33667bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t) * ldcp->rx_data_ncookies);
33677bd3a2e2SSriharsha Basavapatna
33687bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)msg, msgsize, B_FALSE);
33697bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
33707bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
33717bd3a2e2SSriharsha Basavapatna kmem_free(msg, msgsize);
33727bd3a2e2SSriharsha Basavapatna return (rv);
33737bd3a2e2SSriharsha Basavapatna }
33747bd3a2e2SSriharsha Basavapatna
33757bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_INFO_SENT;
33767bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
33777bd3a2e2SSriharsha Basavapatna
33787bd3a2e2SSriharsha Basavapatna kmem_free(msg, msgsize);
33797bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
33807bd3a2e2SSriharsha Basavapatna }
33817bd3a2e2SSriharsha Basavapatna
33827bd3a2e2SSriharsha Basavapatna /*
33837bd3a2e2SSriharsha Basavapatna * Send descriptor ring register message to the peer over ldc.
33847bd3a2e2SSriharsha Basavapatna * Invoked in TxDring mode.
33857bd3a2e2SSriharsha Basavapatna */
33867bd3a2e2SSriharsha Basavapatna static int
vgen_send_tx_dring_reg(vgen_ldc_t * ldcp)33877bd3a2e2SSriharsha Basavapatna vgen_send_tx_dring_reg(vgen_ldc_t *ldcp)
33881ae08745Sheppo {
3389844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
33901ae08745Sheppo vio_dring_reg_msg_t msg;
33911ae08745Sheppo int rv;
33921ae08745Sheppo
33931ae08745Sheppo bzero(&msg, sizeof (msg));
33941ae08745Sheppo
33951ae08745Sheppo /*
33967bd3a2e2SSriharsha Basavapatna * Initialize only the common part of dring reg msg in TxDring mode.
33971ae08745Sheppo */
33987bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(ldcp, &msg, VIO_TX_DRING);
33991ae08745Sheppo
34007bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)&msg, sizeof (msg), B_FALSE);
34011ae08745Sheppo if (rv != VGEN_SUCCESS) {
3402844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34033af08d82Slm66018 return (rv);
34041ae08745Sheppo }
34051ae08745Sheppo
34061ae08745Sheppo ldcp->hstate |= DRING_INFO_SENT;
3407844e62a3Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
34081ae08745Sheppo
34091ae08745Sheppo return (VGEN_SUCCESS);
34101ae08745Sheppo }
34111ae08745Sheppo
34121ae08745Sheppo static int
vgen_send_rdx_info(vgen_ldc_t * ldcp)34131ae08745Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
34141ae08745Sheppo {
3415844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
34161ae08745Sheppo vio_rdx_msg_t rdxmsg;
34171ae08745Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag;
34181ae08745Sheppo int rv;
34191ae08745Sheppo
34201ae08745Sheppo bzero(&rdxmsg, sizeof (rdxmsg));
34211ae08745Sheppo
34221ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
34231ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
34241ae08745Sheppo tagp->vio_subtype_env = VIO_RDX;
34251ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
34261ae08745Sheppo
34271ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
34281ae08745Sheppo if (rv != VGEN_SUCCESS) {
3429844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34303af08d82Slm66018 return (rv);
34311ae08745Sheppo }
34321ae08745Sheppo
34331ae08745Sheppo ldcp->hstate |= RDX_INFO_SENT;
3434844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n");
34351ae08745Sheppo
34361ae08745Sheppo return (VGEN_SUCCESS);
34371ae08745Sheppo }
34381ae08745Sheppo
34391ae08745Sheppo /* send multicast addr info message to vsw */
34401ae08745Sheppo static int
vgen_send_mcast_info(vgen_ldc_t * ldcp)34411ae08745Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
34421ae08745Sheppo {
34431ae08745Sheppo vnet_mcast_msg_t mcastmsg;
34441ae08745Sheppo vnet_mcast_msg_t *msgp;
34451ae08745Sheppo vio_msg_tag_t *tagp;
34461ae08745Sheppo vgen_t *vgenp;
34471ae08745Sheppo struct ether_addr *mca;
34481ae08745Sheppo int rv;
34491ae08745Sheppo int i;
34501ae08745Sheppo uint32_t size;
34511ae08745Sheppo uint32_t mccount;
34521ae08745Sheppo uint32_t n;
34531ae08745Sheppo
34541ae08745Sheppo msgp = &mcastmsg;
34551ae08745Sheppo tagp = &msgp->tag;
34561ae08745Sheppo vgenp = LDC_TO_VGEN(ldcp);
34571ae08745Sheppo
34581ae08745Sheppo mccount = vgenp->mccount;
34591ae08745Sheppo i = 0;
34601ae08745Sheppo
34611ae08745Sheppo do {
34621ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
34631ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
34641ae08745Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO;
34651ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
34661ae08745Sheppo
34671ae08745Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
34681ae08745Sheppo size = n * sizeof (struct ether_addr);
34691ae08745Sheppo
34701ae08745Sheppo mca = &(vgenp->mctab[i]);
34711ae08745Sheppo bcopy(mca, (msgp->mca), size);
34721ae08745Sheppo msgp->set = B_TRUE;
34731ae08745Sheppo msgp->count = n;
34741ae08745Sheppo
34751ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
34761ae08745Sheppo B_FALSE);
34771ae08745Sheppo if (rv != VGEN_SUCCESS) {
3478844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv);
34793af08d82Slm66018 return (rv);
34801ae08745Sheppo }
34811ae08745Sheppo
34821ae08745Sheppo mccount -= n;
34831ae08745Sheppo i += n;
34841ae08745Sheppo
34851ae08745Sheppo } while (mccount);
34861ae08745Sheppo
34871ae08745Sheppo return (VGEN_SUCCESS);
34881ae08745Sheppo }
34891ae08745Sheppo
34907bd3a2e2SSriharsha Basavapatna /*
34917bd3a2e2SSriharsha Basavapatna * vgen_dds_rx -- post DDS messages to vnet.
34927bd3a2e2SSriharsha Basavapatna */
34937bd3a2e2SSriharsha Basavapatna static int
vgen_dds_rx(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)34947bd3a2e2SSriharsha Basavapatna vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
34957bd3a2e2SSriharsha Basavapatna {
34967bd3a2e2SSriharsha Basavapatna vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp;
34977bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
34987bd3a2e2SSriharsha Basavapatna
34997bd3a2e2SSriharsha Basavapatna if (dmsg->dds_class != DDS_VNET_NIU) {
35007bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Unknown DDS class, dropping");
35017bd3a2e2SSriharsha Basavapatna return (EBADMSG);
35027bd3a2e2SSriharsha Basavapatna }
35037bd3a2e2SSriharsha Basavapatna vnet_dds_rx(vgenp->vnetp, dmsg);
35047bd3a2e2SSriharsha Basavapatna return (0);
35057bd3a2e2SSriharsha Basavapatna }
35067bd3a2e2SSriharsha Basavapatna
35077bd3a2e2SSriharsha Basavapatna /*
35087bd3a2e2SSriharsha Basavapatna * vgen_dds_tx -- an interface called by vnet to send DDS messages.
35097bd3a2e2SSriharsha Basavapatna */
35107bd3a2e2SSriharsha Basavapatna int
vgen_dds_tx(void * arg,void * msg)35117bd3a2e2SSriharsha Basavapatna vgen_dds_tx(void *arg, void *msg)
35127bd3a2e2SSriharsha Basavapatna {
35137bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = arg;
35147bd3a2e2SSriharsha Basavapatna vio_dds_msg_t *dmsg = msg;
35157bd3a2e2SSriharsha Basavapatna vgen_portlist_t *plistp = &vgenp->vgenports;
35167bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp;
35177bd3a2e2SSriharsha Basavapatna int rv = EIO;
35187bd3a2e2SSriharsha Basavapatna
35197bd3a2e2SSriharsha Basavapatna READ_ENTER(&plistp->rwlock);
35207bd3a2e2SSriharsha Basavapatna ldcp = vgenp->vsw_portp->ldcp;
35217bd3a2e2SSriharsha Basavapatna if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) {
35227bd3a2e2SSriharsha Basavapatna goto vgen_dsend_exit;
35237bd3a2e2SSriharsha Basavapatna }
35247bd3a2e2SSriharsha Basavapatna
35257bd3a2e2SSriharsha Basavapatna dmsg->tag.vio_sid = ldcp->local_sid;
35267bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE);
35277bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
35287bd3a2e2SSriharsha Basavapatna rv = EIO;
35297bd3a2e2SSriharsha Basavapatna } else {
35307bd3a2e2SSriharsha Basavapatna rv = 0;
35317bd3a2e2SSriharsha Basavapatna }
35327bd3a2e2SSriharsha Basavapatna
35337bd3a2e2SSriharsha Basavapatna vgen_dsend_exit:
35347bd3a2e2SSriharsha Basavapatna RW_EXIT(&plistp->rwlock);
35357bd3a2e2SSriharsha Basavapatna return (rv);
35367bd3a2e2SSriharsha Basavapatna
35377bd3a2e2SSriharsha Basavapatna }
35387bd3a2e2SSriharsha Basavapatna
35391ae08745Sheppo /* Initiate Phase 2 of handshake */
35401ae08745Sheppo static int
vgen_handshake_phase2(vgen_ldc_t * ldcp)35411ae08745Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
35421ae08745Sheppo {
35431ae08745Sheppo int rv;
3544844e62a3Sraghuram
35451ae08745Sheppo #ifdef DEBUG
35467bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HSTATE)) {
35471ae08745Sheppo /* simulate out of state condition */
35487bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HSTATE);
35491ae08745Sheppo rv = vgen_send_rdx_info(ldcp);
35501ae08745Sheppo return (rv);
35511ae08745Sheppo }
35527bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HTIMEOUT)) {
35531ae08745Sheppo /* simulate timeout condition */
35547bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HTIMEOUT);
35551ae08745Sheppo return (VGEN_SUCCESS);
35561ae08745Sheppo }
35571ae08745Sheppo #endif
35583af08d82Slm66018 rv = vgen_send_attr_info(ldcp);
35593af08d82Slm66018 if (rv != VGEN_SUCCESS) {
35601ae08745Sheppo return (rv);
35611ae08745Sheppo }
35623af08d82Slm66018
35637bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
35643af08d82Slm66018 }
35657bd3a2e2SSriharsha Basavapatna
35667bd3a2e2SSriharsha Basavapatna static int
vgen_handshake_phase3(vgen_ldc_t * ldcp)35677bd3a2e2SSriharsha Basavapatna vgen_handshake_phase3(vgen_ldc_t *ldcp)
35687bd3a2e2SSriharsha Basavapatna {
35697bd3a2e2SSriharsha Basavapatna int rv;
35707bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
35717bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
35727bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->stats;
35737bd3a2e2SSriharsha Basavapatna
35747bd3a2e2SSriharsha Basavapatna /* dring mode has been negotiated in attr phase; save in stats */
35757bd3a2e2SSriharsha Basavapatna statsp->dring_mode = lp->dring_mode;
35767bd3a2e2SSriharsha Basavapatna
35777bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { /* RxDringData mode */
35787bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata_shm;
35797bd3a2e2SSriharsha Basavapatna ldcp->tx_dringdata = vgen_dringsend_shm;
35807bd3a2e2SSriharsha Basavapatna if (!VGEN_PRI_ETH_DEFINED(vgenp)) {
35817bd3a2e2SSriharsha Basavapatna /*
35827bd3a2e2SSriharsha Basavapatna * If priority frames are not in use, we don't need a
35837bd3a2e2SSriharsha Basavapatna * separate wrapper function for 'tx', so we set it to
35847bd3a2e2SSriharsha Basavapatna * 'tx_dringdata'. If priority frames are configured,
35857bd3a2e2SSriharsha Basavapatna * we leave the 'tx' pointer as is (initialized in
35867bd3a2e2SSriharsha Basavapatna * vgen_set_vnet_proto_ops()).
35877bd3a2e2SSriharsha Basavapatna */
35887bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata;
35897bd3a2e2SSriharsha Basavapatna }
35907bd3a2e2SSriharsha Basavapatna } else { /* TxDring mode */
35917bd3a2e2SSriharsha Basavapatna ldcp->msg_thread = thread_create(NULL,
35927bd3a2e2SSriharsha Basavapatna 2 * DEFAULTSTKSZ, vgen_ldc_msg_worker, ldcp, 0,
35937bd3a2e2SSriharsha Basavapatna &p0, TS_RUN, maxclsyspri);
35947bd3a2e2SSriharsha Basavapatna }
35957bd3a2e2SSriharsha Basavapatna
35967bd3a2e2SSriharsha Basavapatna rv = vgen_create_dring(ldcp);
35977bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
35987bd3a2e2SSriharsha Basavapatna return (rv);
35993af08d82Slm66018 }
36003af08d82Slm66018
36013af08d82Slm66018 /* update local dring_info params */
36027bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
36037bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->rx_dring_cookie),
36047bd3a2e2SSriharsha Basavapatna &(ldcp->local_hparams.dring_cookie),
36053af08d82Slm66018 sizeof (ldc_mem_cookie_t));
36067bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ncookies = ldcp->rx_dring_ncookies;
36077bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.num_desc = ldcp->num_rxds;
36087bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.desc_size =
36097bd3a2e2SSriharsha Basavapatna sizeof (vnet_rx_dringdata_desc_t);
36107bd3a2e2SSriharsha Basavapatna rv = vgen_send_rx_dring_reg(ldcp);
36117bd3a2e2SSriharsha Basavapatna } else {
36127bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->tx_dring_cookie),
36137bd3a2e2SSriharsha Basavapatna &(ldcp->local_hparams.dring_cookie),
36147bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t));
36157bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ncookies = ldcp->tx_dring_ncookies;
36163af08d82Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds;
36173af08d82Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
36187bd3a2e2SSriharsha Basavapatna rv = vgen_send_tx_dring_reg(ldcp);
36197bd3a2e2SSriharsha Basavapatna }
36203af08d82Slm66018
36213af08d82Slm66018 if (rv != VGEN_SUCCESS) {
36221ae08745Sheppo return (rv);
36231ae08745Sheppo }
36241ae08745Sheppo
36251ae08745Sheppo return (VGEN_SUCCESS);
36261ae08745Sheppo }
36271ae08745Sheppo
36281ae08745Sheppo /*
3629f0ca1d9aSsb155480 * Set vnet-protocol-version dependent functions based on version.
3630f0ca1d9aSsb155480 */
3631f0ca1d9aSsb155480 static void
vgen_set_vnet_proto_ops(vgen_ldc_t * ldcp)3632f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp)
3633f0ca1d9aSsb155480 {
3634f0ca1d9aSsb155480 vgen_hparams_t *lp = &ldcp->local_hparams;
3635f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3636f0ca1d9aSsb155480
36377bd3a2e2SSriharsha Basavapatna /*
36387bd3a2e2SSriharsha Basavapatna * Setup the appropriate dring data processing routine and any
36397bd3a2e2SSriharsha Basavapatna * associated thread based on the version.
36407bd3a2e2SSriharsha Basavapatna *
36417bd3a2e2SSriharsha Basavapatna * In versions < 1.6, we only support TxDring mode. In this mode, the
36427bd3a2e2SSriharsha Basavapatna * msg worker thread processes all types of VIO msgs (ctrl and data).
36437bd3a2e2SSriharsha Basavapatna *
36447bd3a2e2SSriharsha Basavapatna * In versions >= 1.6, we also support RxDringData mode. In this mode,
36457bd3a2e2SSriharsha Basavapatna * all msgs including dring data messages are handled directly by the
36467bd3a2e2SSriharsha Basavapatna * callback (intr) thread. The dring data msgs (msgtype: VIO_TYPE_DATA,
36477bd3a2e2SSriharsha Basavapatna * subtype: VIO_SUBTYPE_INFO, subtype_env: VIO_DRING_DATA) can also be
36487bd3a2e2SSriharsha Basavapatna * disabled while the polling thread is active, in which case the
36497bd3a2e2SSriharsha Basavapatna * polling thread processes the rcv descriptor ring.
36507bd3a2e2SSriharsha Basavapatna *
36517bd3a2e2SSriharsha Basavapatna * However, for versions >= 1.6, we can force to only use TxDring mode.
36527bd3a2e2SSriharsha Basavapatna * This could happen if RxDringData mode has been disabled (see
3653*34f94fbcSWENTAO YANG * below) on this guest or on the peer guest. This info is determined
3654*34f94fbcSWENTAO YANG * as part of attr exchange phase of handshake. Hence, we setup these
3655*34f94fbcSWENTAO YANG * pointers for v1.6 after attr msg phase completes during handshake.
36567bd3a2e2SSriharsha Basavapatna */
36577bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) { /* Ver >= 1.6 */
36587bd3a2e2SSriharsha Basavapatna /*
36597bd3a2e2SSriharsha Basavapatna * Set data dring mode for vgen_send_attr_info().
36607bd3a2e2SSriharsha Basavapatna */
3661*34f94fbcSWENTAO YANG if (vgen_mapin_avail(ldcp) == B_TRUE) {
36627bd3a2e2SSriharsha Basavapatna lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING);
36637bd3a2e2SSriharsha Basavapatna } else {
36647bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING;
36657bd3a2e2SSriharsha Basavapatna }
36667bd3a2e2SSriharsha Basavapatna } else { /* Ver <= 1.5 */
36677bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING;
36687bd3a2e2SSriharsha Basavapatna }
36697bd3a2e2SSriharsha Basavapatna
36701107ea93SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 5)) {
36711107ea93SSriharsha Basavapatna vgen_port_t *portp = ldcp->portp;
36721107ea93SSriharsha Basavapatna vnet_t *vnetp = vgenp->vnetp;
36731107ea93SSriharsha Basavapatna /*
36741107ea93SSriharsha Basavapatna * If the version negotiated with vswitch is >= 1.5 (link
36751107ea93SSriharsha Basavapatna * status update support), set the required bits in our
36761107ea93SSriharsha Basavapatna * attributes if this vnet device has been configured to get
36771107ea93SSriharsha Basavapatna * physical link state updates.
36781107ea93SSriharsha Basavapatna */
36791107ea93SSriharsha Basavapatna if (portp == vgenp->vsw_portp && vnetp->pls_update == B_TRUE) {
36801107ea93SSriharsha Basavapatna lp->physlink_update = PHYSLINK_UPDATE_STATE;
36811107ea93SSriharsha Basavapatna } else {
36821107ea93SSriharsha Basavapatna lp->physlink_update = PHYSLINK_UPDATE_NONE;
36831107ea93SSriharsha Basavapatna }
36841107ea93SSriharsha Basavapatna }
36851107ea93SSriharsha Basavapatna
36867b1f684aSSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
3687c1c61f44Ssb155480 /*
36887b1f684aSSriharsha Basavapatna * If the version negotiated with peer is >= 1.4(Jumbo Frame
36897b1f684aSSriharsha Basavapatna * Support), set the mtu in our attributes to max_frame_size.
3690c1c61f44Ssb155480 */
3691c1c61f44Ssb155480 lp->mtu = vgenp->max_frame_size;
36927b1f684aSSriharsha Basavapatna } else if (VGEN_VER_EQ(ldcp, 1, 3)) {
36937b1f684aSSriharsha Basavapatna /*
36947b1f684aSSriharsha Basavapatna * If the version negotiated with peer is == 1.3 (Vlan Tag
36957b1f684aSSriharsha Basavapatna * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ.
36967b1f684aSSriharsha Basavapatna */
36977b1f684aSSriharsha Basavapatna lp->mtu = ETHERMAX + VLAN_TAGSZ;
3698c1c61f44Ssb155480 } else {
3699c1c61f44Ssb155480 vgen_port_t *portp = ldcp->portp;
3700c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp;
3701c1c61f44Ssb155480 /*
3702c1c61f44Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX.
3703c1c61f44Ssb155480 * We can negotiate that size with those peers provided the
3704c1c61f44Ssb155480 * following conditions are true:
3705c1c61f44Ssb155480 * - Only pvid is defined for our peer and there are no vids.
3706c1c61f44Ssb155480 * - pvids are equal.
3707c1c61f44Ssb155480 * If the above conditions are true, then we can send/recv only
3708c1c61f44Ssb155480 * untagged frames of max size ETHERMAX.
3709c1c61f44Ssb155480 */
37107b1f684aSSriharsha Basavapatna if (portp->nvids == 0 && portp->pvid == vnetp->pvid) {
3711c1c61f44Ssb155480 lp->mtu = ETHERMAX;
3712c1c61f44Ssb155480 }
3713c1c61f44Ssb155480 }
3714c1c61f44Ssb155480
37157bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 2)) { /* Versions >= 1.2 */
37167bd3a2e2SSriharsha Basavapatna /*
37177bd3a2e2SSriharsha Basavapatna * Starting v1.2 we support priority frames; so set the
37187bd3a2e2SSriharsha Basavapatna * dring processing routines and xfer modes based on the
37197bd3a2e2SSriharsha Basavapatna * version. Note that the dring routines could be changed after
37207bd3a2e2SSriharsha Basavapatna * attribute handshake phase for versions >= 1.6 (See
37217bd3a2e2SSriharsha Basavapatna * vgen_handshake_phase3())
37227bd3a2e2SSriharsha Basavapatna */
37237bd3a2e2SSriharsha Basavapatna ldcp->tx_dringdata = vgen_dringsend;
37247bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata;
3725f0ca1d9aSsb155480
3726f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
3727f0ca1d9aSsb155480 /*
37287bd3a2e2SSriharsha Basavapatna * Enable priority routines and pkt mode only if
3729f0ca1d9aSsb155480 * at least one pri-eth-type is specified in MD.
3730f0ca1d9aSsb155480 */
3731f0ca1d9aSsb155480 ldcp->tx = vgen_ldcsend;
3732f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data;
3733f0ca1d9aSsb155480
3734f0ca1d9aSsb155480 /* set xfer mode for vgen_send_attr_info() */
3735f0ca1d9aSsb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
3736f0ca1d9aSsb155480 } else {
37377bd3a2e2SSriharsha Basavapatna /* No priority eth types defined in MD */
37387bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata;
3739f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
3740f0ca1d9aSsb155480
37417bd3a2e2SSriharsha Basavapatna /* Set xfer mode for vgen_send_attr_info() */
3742f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2;
3743f0ca1d9aSsb155480 }
37447bd3a2e2SSriharsha Basavapatna } else { /* Versions prior to 1.2 */
3745f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(ldcp);
3746f0ca1d9aSsb155480 }
3747f0ca1d9aSsb155480 }
3748f0ca1d9aSsb155480
3749f0ca1d9aSsb155480 /*
3750f0ca1d9aSsb155480 * Reset vnet-protocol-version dependent functions to pre-v1.2.
3751f0ca1d9aSsb155480 */
3752f0ca1d9aSsb155480 static void
vgen_reset_vnet_proto_ops(vgen_ldc_t * ldcp)3753f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp)
3754f0ca1d9aSsb155480 {
3755f0ca1d9aSsb155480 vgen_hparams_t *lp = &ldcp->local_hparams;
3756f0ca1d9aSsb155480
37577bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata = vgen_dringsend;
37587bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata;
3759f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
3760f0ca1d9aSsb155480
3761f0ca1d9aSsb155480 /* set xfer mode for vgen_send_attr_info() */
3762f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0;
3763f0ca1d9aSsb155480 }
3764f0ca1d9aSsb155480
3765c1c61f44Ssb155480 static void
vgen_vlan_unaware_port_reset(vgen_port_t * portp)3766c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp)
3767c1c61f44Ssb155480 {
37687bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp;
3769c1c61f44Ssb155480 vgen_t *vgenp = portp->vgenp;
3770c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp;
37717bd3a2e2SSriharsha Basavapatna boolean_t need_reset = B_FALSE;
3772c1c61f44Ssb155480
3773c1c61f44Ssb155480 mutex_enter(&ldcp->cblock);
3774c1c61f44Ssb155480
3775c1c61f44Ssb155480 /*
3776c1c61f44Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
3777c1c61f44Ssb155480 * the connection. See comments in vgen_set_vnet_proto_ops().
3778c1c61f44Ssb155480 */
3779c1c61f44Ssb155480 if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) &&
3780c1c61f44Ssb155480 (portp->nvids != 0 || portp->pvid != vnetp->pvid)) {
37817bd3a2e2SSriharsha Basavapatna need_reset = B_TRUE;
3782c1c61f44Ssb155480 }
3783c1c61f44Ssb155480 mutex_exit(&ldcp->cblock);
3784c1c61f44Ssb155480
37857bd3a2e2SSriharsha Basavapatna if (need_reset == B_TRUE) {
37867bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, VGEN_OTHER);
37877bd3a2e2SSriharsha Basavapatna }
3788c1c61f44Ssb155480 }
3789c1c61f44Ssb155480
3790c1c61f44Ssb155480 static void
vgen_port_reset(vgen_port_t * portp)37911107ea93SSriharsha Basavapatna vgen_port_reset(vgen_port_t *portp)
37921107ea93SSriharsha Basavapatna {
37937bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(portp->ldcp, VGEN_OTHER);
37941107ea93SSriharsha Basavapatna }
37951107ea93SSriharsha Basavapatna
37961107ea93SSriharsha Basavapatna static void
vgen_reset_vlan_unaware_ports(vgen_t * vgenp)3797c1c61f44Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp)
3798c1c61f44Ssb155480 {
3799c1c61f44Ssb155480 vgen_port_t *portp;
3800c1c61f44Ssb155480 vgen_portlist_t *plistp;
3801c1c61f44Ssb155480
3802c1c61f44Ssb155480 plistp = &(vgenp->vgenports);
3803c1c61f44Ssb155480 READ_ENTER(&plistp->rwlock);
3804c1c61f44Ssb155480
3805c1c61f44Ssb155480 for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
3806c1c61f44Ssb155480
3807c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(portp);
3808c1c61f44Ssb155480
3809c1c61f44Ssb155480 }
3810c1c61f44Ssb155480
3811c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock);
3812c1c61f44Ssb155480 }
3813c1c61f44Ssb155480
38141107ea93SSriharsha Basavapatna static void
vgen_reset_vsw_port(vgen_t * vgenp)38151107ea93SSriharsha Basavapatna vgen_reset_vsw_port(vgen_t *vgenp)
38161107ea93SSriharsha Basavapatna {
38171107ea93SSriharsha Basavapatna vgen_port_t *portp;
38181107ea93SSriharsha Basavapatna
38191107ea93SSriharsha Basavapatna if ((portp = vgenp->vsw_portp) != NULL) {
38201107ea93SSriharsha Basavapatna vgen_port_reset(portp);
38211107ea93SSriharsha Basavapatna }
38221107ea93SSriharsha Basavapatna }
38231107ea93SSriharsha Basavapatna
38241ae08745Sheppo static void
vgen_setup_handshake_params(vgen_ldc_t * ldcp)38257bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(vgen_ldc_t *ldcp)
38261ae08745Sheppo {
38271ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp);
38281ae08745Sheppo
38291ae08745Sheppo /*
38301ae08745Sheppo * clear local handshake params and initialize.
38311ae08745Sheppo */
38321ae08745Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
38331ae08745Sheppo
38341ae08745Sheppo /* set version to the highest version supported */
38351ae08745Sheppo ldcp->local_hparams.ver_major =
38361ae08745Sheppo ldcp->vgen_versions[0].ver_major;
38371ae08745Sheppo ldcp->local_hparams.ver_minor =
38381ae08745Sheppo ldcp->vgen_versions[0].ver_minor;
38391ae08745Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK;
38401ae08745Sheppo
38411ae08745Sheppo /* set attr_info params */
3842c1c61f44Ssb155480 ldcp->local_hparams.mtu = vgenp->max_frame_size;
38431ae08745Sheppo ldcp->local_hparams.addr =
3844f2b610cfSwentaoy vnet_macaddr_strtoul(vgenp->macaddr);
38451ae08745Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
3846f0ca1d9aSsb155480 ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0;
38471ae08745Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */
38481107ea93SSriharsha Basavapatna ldcp->local_hparams.physlink_update = PHYSLINK_UPDATE_NONE;
38491ae08745Sheppo
38507bd3a2e2SSriharsha Basavapatna /* reset protocol version specific function pointers */
38517bd3a2e2SSriharsha Basavapatna vgen_reset_vnet_proto_ops(ldcp);
38521ae08745Sheppo ldcp->local_hparams.dring_ident = 0;
38537bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ready = B_FALSE;
38541ae08745Sheppo
38551ae08745Sheppo /* clear peer_hparams */
38561ae08745Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
38577bd3a2e2SSriharsha Basavapatna ldcp->peer_hparams.dring_ready = B_FALSE;
38583af08d82Slm66018 }
38593af08d82Slm66018
38607bd3a2e2SSriharsha Basavapatna /*
38617bd3a2e2SSriharsha Basavapatna * Process Channel Reset. We tear down the resources (timers, threads,
38627bd3a2e2SSriharsha Basavapatna * descriptor rings etc) associated with the channel and reinitialize the
38637bd3a2e2SSriharsha Basavapatna * channel based on the flags.
38647bd3a2e2SSriharsha Basavapatna *
38657bd3a2e2SSriharsha Basavapatna * Arguments:
38667bd3a2e2SSriharsha Basavapatna * ldcp: The channel being processed.
38677bd3a2e2SSriharsha Basavapatna *
38687bd3a2e2SSriharsha Basavapatna * flags:
38697bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_EVT_RESET:
38707bd3a2e2SSriharsha Basavapatna * A ECONNRESET error occured while doing ldc operations such as
38717bd3a2e2SSriharsha Basavapatna * ldc_read() or ldc_write(); the channel is already reset and it
38727bd3a2e2SSriharsha Basavapatna * needs to be handled.
38737bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_NEED_LDCRESET:
38747bd3a2e2SSriharsha Basavapatna * Some other errors occured and the error handling code needs to
38757bd3a2e2SSriharsha Basavapatna * explicitly reset the channel and restart handshake with the
38767bd3a2e2SSriharsha Basavapatna * peer. The error could be either in ldc operations or other
38777bd3a2e2SSriharsha Basavapatna * parts of the code such as timeouts or mdeg events etc.
38787bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_UNINIT:
38797bd3a2e2SSriharsha Basavapatna * The channel is being torn down; no need to bring up the channel
38807bd3a2e2SSriharsha Basavapatna * after resetting.
38817bd3a2e2SSriharsha Basavapatna */
38827bd3a2e2SSriharsha Basavapatna static int
vgen_process_reset(vgen_ldc_t * ldcp,int flags)38837bd3a2e2SSriharsha Basavapatna vgen_process_reset(vgen_ldc_t *ldcp, int flags)
38841ae08745Sheppo {
38851107ea93SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
38867bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = ldcp->portp;
38877bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
38887bd3a2e2SSriharsha Basavapatna boolean_t is_vsw_port = B_FALSE;
38897bd3a2e2SSriharsha Basavapatna boolean_t link_update = B_FALSE;
38907bd3a2e2SSriharsha Basavapatna ldc_status_t istatus;
38917bd3a2e2SSriharsha Basavapatna int rv;
38927bd3a2e2SSriharsha Basavapatna uint_t retries = 0;
38937bd3a2e2SSriharsha Basavapatna timeout_id_t htid = 0;
38947bd3a2e2SSriharsha Basavapatna timeout_id_t wd_tid = 0;
38951107ea93SSriharsha Basavapatna
38967bd3a2e2SSriharsha Basavapatna if (portp == vgenp->vsw_portp) { /* vswitch port ? */
38977bd3a2e2SSriharsha Basavapatna is_vsw_port = B_TRUE;
38987bd3a2e2SSriharsha Basavapatna }
38991ae08745Sheppo
39007bd3a2e2SSriharsha Basavapatna /*
39017bd3a2e2SSriharsha Basavapatna * Report that the channel is being reset; it ensures that any HybridIO
39027bd3a2e2SSriharsha Basavapatna * configuration is torn down before we reset the channel if it is not
39037bd3a2e2SSriharsha Basavapatna * already reset (flags == VGEN_FLAG_NEED_LDCRESET).
39047bd3a2e2SSriharsha Basavapatna */
39057bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_TRUE) {
39067bd3a2e2SSriharsha Basavapatna vio_net_report_err_t rep_err = portp->vcb.vio_net_report_err;
39077bd3a2e2SSriharsha Basavapatna rep_err(portp->vhp, VIO_NET_RES_DOWN);
39087bd3a2e2SSriharsha Basavapatna }
39091ae08745Sheppo
39107bd3a2e2SSriharsha Basavapatna again:
39117bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
39127bd3a2e2SSriharsha Basavapatna
39137bd3a2e2SSriharsha Basavapatna /* Clear hstate and hphase */
39147bd3a2e2SSriharsha Basavapatna ldcp->hstate = 0;
39157bd3a2e2SSriharsha Basavapatna ldcp->hphase = VH_PHASE0;
39167bd3a2e2SSriharsha Basavapatna if (flags == VGEN_FLAG_NEED_LDCRESET || flags == VGEN_FLAG_UNINIT) {
39177bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Doing Channel Reset...\n");
39187bd3a2e2SSriharsha Basavapatna (void) ldc_down(ldcp->ldc_handle);
39197bd3a2e2SSriharsha Basavapatna (void) ldc_status(ldcp->ldc_handle, &istatus);
39207bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Reset Done, ldc_status(%d)\n", istatus);
39217bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = istatus;
39227bd3a2e2SSriharsha Basavapatna
39237bd3a2e2SSriharsha Basavapatna if (flags == VGEN_FLAG_UNINIT) {
39247bd3a2e2SSriharsha Basavapatna /* disable further callbacks */
39257bd3a2e2SSriharsha Basavapatna rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
39267bd3a2e2SSriharsha Basavapatna if (rv != 0) {
39277bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n");
39287bd3a2e2SSriharsha Basavapatna }
39297bd3a2e2SSriharsha Basavapatna }
39307bd3a2e2SSriharsha Basavapatna
39317bd3a2e2SSriharsha Basavapatna } else {
39327bd3a2e2SSriharsha Basavapatna /* flags == VGEN_FLAG_EVT_RESET */
39337bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc status(%d)\n", ldcp->ldc_status);
39347bd3a2e2SSriharsha Basavapatna }
39351107ea93SSriharsha Basavapatna
39361107ea93SSriharsha Basavapatna /*
39371107ea93SSriharsha Basavapatna * As the connection is now reset, mark the channel
39381107ea93SSriharsha Basavapatna * link_state as 'down' and notify the stack if needed.
39391107ea93SSriharsha Basavapatna */
39401107ea93SSriharsha Basavapatna if (ldcp->link_state != LINK_STATE_DOWN) {
39411107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_DOWN;
39421107ea93SSriharsha Basavapatna
39437bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_TRUE) { /* vswitch port ? */
39441107ea93SSriharsha Basavapatna /*
39451107ea93SSriharsha Basavapatna * As the channel link is down, mark physical link also
39461107ea93SSriharsha Basavapatna * as down. After the channel comes back up and
39471107ea93SSriharsha Basavapatna * handshake completes, we will get an update on the
39481107ea93SSriharsha Basavapatna * physlink state from vswitch (if this device has been
39491107ea93SSriharsha Basavapatna * configured to get phys link updates).
39501107ea93SSriharsha Basavapatna */
39511107ea93SSriharsha Basavapatna vgenp->phys_link_state = LINK_STATE_DOWN;
39527bd3a2e2SSriharsha Basavapatna link_update = B_TRUE;
39531107ea93SSriharsha Basavapatna
39547bd3a2e2SSriharsha Basavapatna }
39557bd3a2e2SSriharsha Basavapatna }
39567bd3a2e2SSriharsha Basavapatna
39577bd3a2e2SSriharsha Basavapatna if (ldcp->htid != 0) {
39587bd3a2e2SSriharsha Basavapatna htid = ldcp->htid;
39597bd3a2e2SSriharsha Basavapatna ldcp->htid = 0;
39607bd3a2e2SSriharsha Basavapatna }
39617bd3a2e2SSriharsha Basavapatna
39627bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid != 0) {
39637bd3a2e2SSriharsha Basavapatna wd_tid = ldcp->wd_tid;
39647bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = 0;
39657bd3a2e2SSriharsha Basavapatna }
39667bd3a2e2SSriharsha Basavapatna
39671107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
39687bd3a2e2SSriharsha Basavapatna
39697bd3a2e2SSriharsha Basavapatna /* Update link state to the stack */
39707bd3a2e2SSriharsha Basavapatna if (link_update == B_TRUE) {
39711107ea93SSriharsha Basavapatna vgen_link_update(vgenp, ldcp->link_state);
39721107ea93SSriharsha Basavapatna }
39737bd3a2e2SSriharsha Basavapatna
39747bd3a2e2SSriharsha Basavapatna /*
39757bd3a2e2SSriharsha Basavapatna * As the channel is being reset, redirect traffic to the peer through
39767bd3a2e2SSriharsha Basavapatna * vswitch, until the channel becomes ready to be used again.
39777bd3a2e2SSriharsha Basavapatna */
39787bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_FALSE && vgenp->vsw_portp != NULL) {
39797bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
39801107ea93SSriharsha Basavapatna }
39817bd3a2e2SSriharsha Basavapatna
39827bd3a2e2SSriharsha Basavapatna /* Cancel handshake watchdog timeout */
39837bd3a2e2SSriharsha Basavapatna if (htid) {
39847bd3a2e2SSriharsha Basavapatna (void) untimeout(htid);
39857bd3a2e2SSriharsha Basavapatna }
39867bd3a2e2SSriharsha Basavapatna
39877bd3a2e2SSriharsha Basavapatna /* Cancel transmit watchdog timeout */
39887bd3a2e2SSriharsha Basavapatna if (wd_tid) {
39897bd3a2e2SSriharsha Basavapatna (void) untimeout(wd_tid);
39907bd3a2e2SSriharsha Basavapatna }
39917bd3a2e2SSriharsha Basavapatna
39927bd3a2e2SSriharsha Basavapatna /* Stop the msg worker thread */
39937bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING && curthread != ldcp->msg_thread) {
39947bd3a2e2SSriharsha Basavapatna vgen_stop_msg_thread(ldcp);
39957bd3a2e2SSriharsha Basavapatna }
39967bd3a2e2SSriharsha Basavapatna
39977bd3a2e2SSriharsha Basavapatna /* Grab all locks while we tear down tx/rx resources */
39987bd3a2e2SSriharsha Basavapatna LDC_LOCK(ldcp);
39997bd3a2e2SSriharsha Basavapatna
40007bd3a2e2SSriharsha Basavapatna /* Destroy the local dring which is exported to the peer */
40017bd3a2e2SSriharsha Basavapatna vgen_destroy_dring(ldcp);
40027bd3a2e2SSriharsha Basavapatna
40037bd3a2e2SSriharsha Basavapatna /* Unmap the remote dring which is imported from the peer */
40047bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(ldcp);
40057bd3a2e2SSriharsha Basavapatna
40067bd3a2e2SSriharsha Basavapatna /*
40077bd3a2e2SSriharsha Basavapatna * Bring up the channel and restart handshake
40087bd3a2e2SSriharsha Basavapatna * only if the channel is not being torn down.
40097bd3a2e2SSriharsha Basavapatna */
40107bd3a2e2SSriharsha Basavapatna if (flags != VGEN_FLAG_UNINIT) {
40117bd3a2e2SSriharsha Basavapatna
40127bd3a2e2SSriharsha Basavapatna /* Setup handshake parameters to restart a new handshake */
40137bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(ldcp);
40147bd3a2e2SSriharsha Basavapatna
40157bd3a2e2SSriharsha Basavapatna /* Bring the channel up */
40167bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp);
40177bd3a2e2SSriharsha Basavapatna
40187bd3a2e2SSriharsha Basavapatna if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
40197bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_status err\n");
40207bd3a2e2SSriharsha Basavapatna } else {
40217bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = istatus;
40227bd3a2e2SSriharsha Basavapatna }
40237bd3a2e2SSriharsha Basavapatna
40247bd3a2e2SSriharsha Basavapatna /* If the channel is UP, start handshake */
40257bd3a2e2SSriharsha Basavapatna if (ldcp->ldc_status == LDC_UP) {
40267bd3a2e2SSriharsha Basavapatna
40277bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_FALSE) {
40287bd3a2e2SSriharsha Basavapatna /*
40297bd3a2e2SSriharsha Basavapatna * Channel is up; use this port from now on.
40307bd3a2e2SSriharsha Basavapatna */
40317bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&portp->use_vsw_port,
40327bd3a2e2SSriharsha Basavapatna B_FALSE);
40337bd3a2e2SSriharsha Basavapatna }
40347bd3a2e2SSriharsha Basavapatna
40357bd3a2e2SSriharsha Basavapatna /* Initialize local session id */
40367bd3a2e2SSriharsha Basavapatna ldcp->local_sid = ddi_get_lbolt();
40377bd3a2e2SSriharsha Basavapatna
40387bd3a2e2SSriharsha Basavapatna /* clear peer session id */
40397bd3a2e2SSriharsha Basavapatna ldcp->peer_sid = 0;
40407bd3a2e2SSriharsha Basavapatna
40417bd3a2e2SSriharsha Basavapatna /*
40427bd3a2e2SSriharsha Basavapatna * Initiate Handshake process with peer ldc endpoint by
40437bd3a2e2SSriharsha Basavapatna * sending version info vio message. If that fails we
40447bd3a2e2SSriharsha Basavapatna * go back to the top of this function to process the
40457bd3a2e2SSriharsha Basavapatna * error again. Note that we can be in this loop for
40467bd3a2e2SSriharsha Basavapatna * 'vgen_ldc_max_resets' times, after which the channel
40477bd3a2e2SSriharsha Basavapatna * is not brought up.
40487bd3a2e2SSriharsha Basavapatna */
40497bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->tclock);
40507bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->txlock);
40517bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->wrlock);
40527bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock);
40537bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
40547bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
40557bd3a2e2SSriharsha Basavapatna if (rv != 0) {
40567bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET) {
40577bd3a2e2SSriharsha Basavapatna flags = VGEN_FLAG_EVT_RESET;
40587bd3a2e2SSriharsha Basavapatna } else {
40597bd3a2e2SSriharsha Basavapatna flags = VGEN_FLAG_NEED_LDCRESET;
40607bd3a2e2SSriharsha Basavapatna }
40617bd3a2e2SSriharsha Basavapatna
40627bd3a2e2SSriharsha Basavapatna /*
40637bd3a2e2SSriharsha Basavapatna * We still hold 'reset_in_progress'; so we can
40647bd3a2e2SSriharsha Basavapatna * just loop back to the top to restart error
40657bd3a2e2SSriharsha Basavapatna * processing.
40667bd3a2e2SSriharsha Basavapatna */
40677bd3a2e2SSriharsha Basavapatna goto again;
40687bd3a2e2SSriharsha Basavapatna }
40697bd3a2e2SSriharsha Basavapatna } else {
40707bd3a2e2SSriharsha Basavapatna LDC_UNLOCK(ldcp);
40717bd3a2e2SSriharsha Basavapatna }
40727bd3a2e2SSriharsha Basavapatna
40737bd3a2e2SSriharsha Basavapatna } else { /* flags == VGEN_FLAG_UNINIT */
40747bd3a2e2SSriharsha Basavapatna
40757bd3a2e2SSriharsha Basavapatna /* Close the channel - retry on EAGAIN */
40767bd3a2e2SSriharsha Basavapatna while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) {
40777bd3a2e2SSriharsha Basavapatna if (++retries > vgen_ldccl_retries) {
40787bd3a2e2SSriharsha Basavapatna break;
40797bd3a2e2SSriharsha Basavapatna }
40807bd3a2e2SSriharsha Basavapatna drv_usecwait(VGEN_LDC_CLOSE_DELAY);
40817bd3a2e2SSriharsha Basavapatna }
40827bd3a2e2SSriharsha Basavapatna if (rv != 0) {
40837bd3a2e2SSriharsha Basavapatna cmn_err(CE_NOTE,
40847bd3a2e2SSriharsha Basavapatna "!vnet%d: Error(%d) closing the channel(0x%lx)\n",
40857bd3a2e2SSriharsha Basavapatna vgenp->instance, rv, ldcp->ldc_id);
40867bd3a2e2SSriharsha Basavapatna }
40877bd3a2e2SSriharsha Basavapatna
40887bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count = 0;
40897bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = LDC_INIT;
40907bd3a2e2SSriharsha Basavapatna ldcp->flags &= ~(CHANNEL_STARTED);
40917bd3a2e2SSriharsha Basavapatna
40927bd3a2e2SSriharsha Basavapatna LDC_UNLOCK(ldcp);
40937bd3a2e2SSriharsha Basavapatna }
40947bd3a2e2SSriharsha Basavapatna
40957bd3a2e2SSriharsha Basavapatna /* Done processing channel reset; clear the atomic flag */
40967bd3a2e2SSriharsha Basavapatna ldcp->reset_in_progress = 0;
40977bd3a2e2SSriharsha Basavapatna return (0);
40981ae08745Sheppo }
40991ae08745Sheppo
41001ae08745Sheppo /*
41011ae08745Sheppo * Initiate handshake with the peer by sending various messages
41021ae08745Sheppo * based on the handshake-phase that the channel is currently in.
41031ae08745Sheppo */
41047bd3a2e2SSriharsha Basavapatna static int
vgen_handshake(vgen_ldc_t * ldcp)41051ae08745Sheppo vgen_handshake(vgen_ldc_t *ldcp)
41061ae08745Sheppo {
41071ae08745Sheppo uint32_t hphase = ldcp->hphase;
41081ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp);
41093af08d82Slm66018 int rv = 0;
41107bd3a2e2SSriharsha Basavapatna timeout_id_t htid;
41111ae08745Sheppo
41121ae08745Sheppo switch (hphase) {
41131ae08745Sheppo
41141ae08745Sheppo case VH_PHASE1:
41151ae08745Sheppo
41161ae08745Sheppo /*
41171ae08745Sheppo * start timer, for entire handshake process, turn this timer
41181ae08745Sheppo * off if all phases of handshake complete successfully and
41197bd3a2e2SSriharsha Basavapatna * hphase goes to VH_DONE(below) or channel is reset due to
41207bd3a2e2SSriharsha Basavapatna * errors or vgen_ldc_uninit() is invoked(vgen_stop).
41211ae08745Sheppo */
412252bca946SWENTAO YANG ASSERT(ldcp->htid == 0);
41231ae08745Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
412419b65a69Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC));
41251ae08745Sheppo
41261ae08745Sheppo /* Phase 1 involves negotiating the version */
41273af08d82Slm66018 rv = vgen_send_version_negotiate(ldcp);
41281ae08745Sheppo break;
41291ae08745Sheppo
41301ae08745Sheppo case VH_PHASE2:
41313af08d82Slm66018 rv = vgen_handshake_phase2(ldcp);
41321ae08745Sheppo break;
41331ae08745Sheppo
41341ae08745Sheppo case VH_PHASE3:
41357bd3a2e2SSriharsha Basavapatna rv = vgen_handshake_phase3(ldcp);
41367bd3a2e2SSriharsha Basavapatna break;
41377bd3a2e2SSriharsha Basavapatna
41387bd3a2e2SSriharsha Basavapatna case VH_PHASE4:
41393af08d82Slm66018 rv = vgen_send_rdx_info(ldcp);
41401ae08745Sheppo break;
41411ae08745Sheppo
41421ae08745Sheppo case VH_DONE:
41437bd3a2e2SSriharsha Basavapatna
41447bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count = 0;
41457bd3a2e2SSriharsha Basavapatna
4146844e62a3Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n");
41471ae08745Sheppo
41481107ea93SSriharsha Basavapatna /*
41491107ea93SSriharsha Basavapatna * The channel is up and handshake is done successfully. Now we
41501107ea93SSriharsha Basavapatna * can mark the channel link_state as 'up'. We also notify the
41511107ea93SSriharsha Basavapatna * stack if the channel is connected to vswitch.
41521107ea93SSriharsha Basavapatna */
41531107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_UP;
41541107ea93SSriharsha Basavapatna
415519b65a69Ssb155480 if (ldcp->portp == vgenp->vsw_portp) {
415619b65a69Ssb155480 /*
415719b65a69Ssb155480 * If this channel(port) is connected to vsw,
415819b65a69Ssb155480 * need to sync multicast table with vsw.
415919b65a69Ssb155480 */
41603af08d82Slm66018 rv = vgen_send_mcast_info(ldcp);
41617bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS)
41620c4606f0SWENTAO YANG break;
41631ae08745Sheppo
41641107ea93SSriharsha Basavapatna if (vgenp->pls_negotiated == B_FALSE) {
41651107ea93SSriharsha Basavapatna /*
41661107ea93SSriharsha Basavapatna * We haven't negotiated with vswitch to get
41671107ea93SSriharsha Basavapatna * physical link state updates. We can update
41681107ea93SSriharsha Basavapatna * update the stack at this point as the
41691107ea93SSriharsha Basavapatna * channel to vswitch is up and the handshake
41701107ea93SSriharsha Basavapatna * is done successfully.
41711107ea93SSriharsha Basavapatna *
41721107ea93SSriharsha Basavapatna * If we have negotiated to get physical link
41731107ea93SSriharsha Basavapatna * state updates, then we won't notify the
41741107ea93SSriharsha Basavapatna * the stack here; we do that as soon as
41751107ea93SSriharsha Basavapatna * vswitch sends us the initial phys link state
41761107ea93SSriharsha Basavapatna * (see vgen_handle_physlink_info()).
41771107ea93SSriharsha Basavapatna */
41780c4606f0SWENTAO YANG mutex_exit(&ldcp->cblock);
41791107ea93SSriharsha Basavapatna vgen_link_update(vgenp, ldcp->link_state);
41800c4606f0SWENTAO YANG mutex_enter(&ldcp->cblock);
41811107ea93SSriharsha Basavapatna }
41827bd3a2e2SSriharsha Basavapatna }
41831107ea93SSriharsha Basavapatna
41847bd3a2e2SSriharsha Basavapatna if (ldcp->htid != 0) {
41857bd3a2e2SSriharsha Basavapatna htid = ldcp->htid;
41867bd3a2e2SSriharsha Basavapatna ldcp->htid = 0;
41877bd3a2e2SSriharsha Basavapatna
41887bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
41897bd3a2e2SSriharsha Basavapatna (void) untimeout(htid);
41907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
41911ae08745Sheppo }
41923af08d82Slm66018
41933af08d82Slm66018 /*
41943af08d82Slm66018 * Check if mac layer should be notified to restart
41953af08d82Slm66018 * transmissions. This can happen if the channel got
41967bd3a2e2SSriharsha Basavapatna * reset and while tx_blocked is set.
41973af08d82Slm66018 */
41983af08d82Slm66018 mutex_enter(&ldcp->tclock);
41997bd3a2e2SSriharsha Basavapatna if (ldcp->tx_blocked) {
4200678453a8Sspeer vio_net_tx_update_t vtx_update =
4201678453a8Sspeer ldcp->portp->vcb.vio_net_tx_update;
4202678453a8Sspeer
42037bd3a2e2SSriharsha Basavapatna ldcp->tx_blocked = B_FALSE;
4204678453a8Sspeer vtx_update(ldcp->portp->vhp);
42053af08d82Slm66018 }
42063af08d82Slm66018 mutex_exit(&ldcp->tclock);
42073af08d82Slm66018
42087bd3a2e2SSriharsha Basavapatna /* start transmit watchdog timer */
42097bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
42107bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_interval * 1000));
42117bd3a2e2SSriharsha Basavapatna
42121ae08745Sheppo break;
42131ae08745Sheppo
42141ae08745Sheppo default:
42151ae08745Sheppo break;
42161ae08745Sheppo }
42173af08d82Slm66018
42187bd3a2e2SSriharsha Basavapatna return (rv);
42191ae08745Sheppo }
42201ae08745Sheppo
42211ae08745Sheppo /*
42221ae08745Sheppo * Check if the current handshake phase has completed successfully and
42231ae08745Sheppo * return the status.
42241ae08745Sheppo */
42251ae08745Sheppo static int
vgen_handshake_done(vgen_ldc_t * ldcp)42261ae08745Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
42271ae08745Sheppo {
4228844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
42291ae08745Sheppo uint32_t hphase = ldcp->hphase;
42301ae08745Sheppo int status = 0;
42311ae08745Sheppo
42321ae08745Sheppo switch (hphase) {
42331ae08745Sheppo
42341ae08745Sheppo case VH_PHASE1:
42351ae08745Sheppo /*
42361ae08745Sheppo * Phase1 is done, if version negotiation
42371ae08745Sheppo * completed successfully.
42381ae08745Sheppo */
42391ae08745Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) ==
42401ae08745Sheppo VER_NEGOTIATED);
42411ae08745Sheppo break;
42421ae08745Sheppo
42431ae08745Sheppo case VH_PHASE2:
42441ae08745Sheppo /*
42457bd3a2e2SSriharsha Basavapatna * Phase 2 is done, if attr info
42467bd3a2e2SSriharsha Basavapatna * has been exchanged successfully.
42471ae08745Sheppo */
42487bd3a2e2SSriharsha Basavapatna status = ((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
42497bd3a2e2SSriharsha Basavapatna ATTR_INFO_EXCHANGED);
42501ae08745Sheppo break;
42511ae08745Sheppo
42521ae08745Sheppo case VH_PHASE3:
42537bd3a2e2SSriharsha Basavapatna /*
42547bd3a2e2SSriharsha Basavapatna * Phase 3 is done, if dring registration
42557bd3a2e2SSriharsha Basavapatna * has been exchanged successfully.
42567bd3a2e2SSriharsha Basavapatna */
42577bd3a2e2SSriharsha Basavapatna status = ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
42587bd3a2e2SSriharsha Basavapatna DRING_INFO_EXCHANGED);
42597bd3a2e2SSriharsha Basavapatna break;
42607bd3a2e2SSriharsha Basavapatna
42617bd3a2e2SSriharsha Basavapatna case VH_PHASE4:
42627bd3a2e2SSriharsha Basavapatna /* Phase 4 is done, if rdx msg has been exchanged */
42631ae08745Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) ==
42641ae08745Sheppo RDX_EXCHANGED);
42651ae08745Sheppo break;
42661ae08745Sheppo
42671ae08745Sheppo default:
42681ae08745Sheppo break;
42691ae08745Sheppo }
42701ae08745Sheppo
42711ae08745Sheppo if (status == 0) {
42721ae08745Sheppo return (VGEN_FAILURE);
42731ae08745Sheppo }
4274844e62a3Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase);
42751ae08745Sheppo return (VGEN_SUCCESS);
42761ae08745Sheppo }
42771ae08745Sheppo
42781107ea93SSriharsha Basavapatna /*
42791107ea93SSriharsha Basavapatna * Link State Update Notes:
42801107ea93SSriharsha Basavapatna * The link state of the channel connected to vswitch is reported as the link
42811107ea93SSriharsha Basavapatna * state of the vnet device, by default. If the channel is down or reset, then
42821107ea93SSriharsha Basavapatna * the link state is marked 'down'. If the channel is 'up' *and* handshake
42831107ea93SSriharsha Basavapatna * between the vnet and vswitch is successful, then the link state is marked
42841107ea93SSriharsha Basavapatna * 'up'. If physical network link state is desired, then the vnet device must
42851107ea93SSriharsha Basavapatna * be configured to get physical link updates and the 'linkprop' property
42861107ea93SSriharsha Basavapatna * in the virtual-device MD node indicates this. As part of attribute exchange
42871107ea93SSriharsha Basavapatna * the vnet device negotiates with the vswitch to obtain physical link state
42881107ea93SSriharsha Basavapatna * updates. If it successfully negotiates, vswitch sends an initial physlink
42891107ea93SSriharsha Basavapatna * msg once the handshake is done and further whenever the physical link state
42901107ea93SSriharsha Basavapatna * changes. Currently we don't have mac layer interfaces to report two distinct
42911107ea93SSriharsha Basavapatna * link states - virtual and physical. Thus, if the vnet has been configured to
42921107ea93SSriharsha Basavapatna * get physical link updates, then the link status will be reported as 'up'
42931107ea93SSriharsha Basavapatna * only when both the virtual and physical links are up.
42941107ea93SSriharsha Basavapatna */
42951107ea93SSriharsha Basavapatna static void
vgen_link_update(vgen_t * vgenp,link_state_t link_state)42961107ea93SSriharsha Basavapatna vgen_link_update(vgen_t *vgenp, link_state_t link_state)
42971107ea93SSriharsha Basavapatna {
42981107ea93SSriharsha Basavapatna vnet_link_update(vgenp->vnetp, link_state);
42991107ea93SSriharsha Basavapatna }
43001107ea93SSriharsha Basavapatna
43011ae08745Sheppo /*
43021ae08745Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer
43031ae08745Sheppo * to a version info msg that we sent.
43041ae08745Sheppo */
43053af08d82Slm66018 static int
vgen_handle_version_negotiate(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)43061ae08745Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
43071ae08745Sheppo {
4308844e62a3Sraghuram vgen_t *vgenp;
43091ae08745Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp;
43101ae08745Sheppo int ack = 0;
43111ae08745Sheppo int failed = 0;
43121ae08745Sheppo int idx;
43131ae08745Sheppo vgen_ver_t *versions = ldcp->vgen_versions;
43143af08d82Slm66018 int rv = 0;
43151ae08745Sheppo
4316844e62a3Sraghuram vgenp = LDC_TO_VGEN(ldcp);
4317844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
43181ae08745Sheppo switch (tagp->vio_subtype) {
43191ae08745Sheppo case VIO_SUBTYPE_INFO:
43201ae08745Sheppo
43211ae08745Sheppo /* Cache sid of peer if this is the first time */
43221ae08745Sheppo if (ldcp->peer_sid == 0) {
4323844e62a3Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n",
4324844e62a3Sraghuram tagp->vio_sid);
43251ae08745Sheppo ldcp->peer_sid = tagp->vio_sid;
43261ae08745Sheppo }
43271ae08745Sheppo
43281ae08745Sheppo if (ldcp->hphase != VH_PHASE1) {
43291ae08745Sheppo /*
43301ae08745Sheppo * If we are not already in VH_PHASE1, reset to
43311ae08745Sheppo * pre-handshake state, and initiate handshake
43321ae08745Sheppo * to the peer too.
43331ae08745Sheppo */
43347bd3a2e2SSriharsha Basavapatna return (EINVAL);
43351ae08745Sheppo }
43367bd3a2e2SSriharsha Basavapatna
43371ae08745Sheppo ldcp->hstate |= VER_INFO_RCVD;
43381ae08745Sheppo
43391ae08745Sheppo /* save peer's requested values */
43401ae08745Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major;
43411ae08745Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
43421ae08745Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class;
43431ae08745Sheppo
43441ae08745Sheppo if ((vermsg->dev_class != VDEV_NETWORK) &&
43451ae08745Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
43461ae08745Sheppo /* unsupported dev_class, send NACK */
43471ae08745Sheppo
4348844e62a3Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
43493af08d82Slm66018
43503af08d82Slm66018 tagp->vio_subtype = VIO_SUBTYPE_NACK;
43513af08d82Slm66018 tagp->vio_sid = ldcp->local_sid;
43523af08d82Slm66018 /* send reply msg back to peer */
43533af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
43543af08d82Slm66018 sizeof (*vermsg), B_FALSE);
43553af08d82Slm66018 if (rv != VGEN_SUCCESS) {
43563af08d82Slm66018 return (rv);
43573af08d82Slm66018 }
43583af08d82Slm66018 return (VGEN_FAILURE);
43591ae08745Sheppo }
43601ae08745Sheppo
4361844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n",
4362844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor);
43631ae08745Sheppo
43641ae08745Sheppo idx = 0;
43651ae08745Sheppo
43661ae08745Sheppo for (;;) {
43671ae08745Sheppo
43681ae08745Sheppo if (vermsg->ver_major > versions[idx].ver_major) {
43691ae08745Sheppo
43701ae08745Sheppo /* nack with next lower version */
43711ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK;
43721ae08745Sheppo vermsg->ver_major = versions[idx].ver_major;
43731ae08745Sheppo vermsg->ver_minor = versions[idx].ver_minor;
43741ae08745Sheppo break;
43751ae08745Sheppo }
43761ae08745Sheppo
43771ae08745Sheppo if (vermsg->ver_major == versions[idx].ver_major) {
43781ae08745Sheppo
43791ae08745Sheppo /* major version match - ACK version */
43801ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
43811ae08745Sheppo ack = 1;
43821ae08745Sheppo
43831ae08745Sheppo /*
43841ae08745Sheppo * lower minor version to the one this endpt
43851ae08745Sheppo * supports, if necessary
43861ae08745Sheppo */
43871ae08745Sheppo if (vermsg->ver_minor >
43881ae08745Sheppo versions[idx].ver_minor) {
43891ae08745Sheppo vermsg->ver_minor =
43901ae08745Sheppo versions[idx].ver_minor;
43911ae08745Sheppo ldcp->peer_hparams.ver_minor =
43921ae08745Sheppo versions[idx].ver_minor;
43931ae08745Sheppo }
43941ae08745Sheppo break;
43951ae08745Sheppo }
43961ae08745Sheppo
43971ae08745Sheppo idx++;
43981ae08745Sheppo
43991ae08745Sheppo if (idx == VGEN_NUM_VER) {
44001ae08745Sheppo
44011ae08745Sheppo /* no version match - send NACK */
44021ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK;
44031ae08745Sheppo vermsg->ver_major = 0;
44041ae08745Sheppo vermsg->ver_minor = 0;
44051ae08745Sheppo failed = 1;
44061ae08745Sheppo break;
44071ae08745Sheppo }
44081ae08745Sheppo
44091ae08745Sheppo }
44101ae08745Sheppo
44111ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
44121ae08745Sheppo
44131ae08745Sheppo /* send reply msg back to peer */
44143af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
44153af08d82Slm66018 B_FALSE);
44163af08d82Slm66018 if (rv != VGEN_SUCCESS) {
44173af08d82Slm66018 return (rv);
44181ae08745Sheppo }
44191ae08745Sheppo
44201ae08745Sheppo if (ack) {
44211ae08745Sheppo ldcp->hstate |= VER_ACK_SENT;
4422844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n",
4423844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor);
44241ae08745Sheppo }
44251ae08745Sheppo if (failed) {
4426844e62a3Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n");
44273af08d82Slm66018 return (VGEN_FAILURE);
44281ae08745Sheppo }
44291ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44301ae08745Sheppo
44311ae08745Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */
44321ae08745Sheppo
44331ae08745Sheppo /* local and peer versions match? */
44341ae08745Sheppo ASSERT((ldcp->local_hparams.ver_major ==
44351ae08745Sheppo ldcp->peer_hparams.ver_major) &&
44361ae08745Sheppo (ldcp->local_hparams.ver_minor ==
44371ae08745Sheppo ldcp->peer_hparams.ver_minor));
44381ae08745Sheppo
4439f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(ldcp);
4440f0ca1d9aSsb155480
44411ae08745Sheppo /* move to the next phase */
44427bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
44437bd3a2e2SSriharsha Basavapatna if (rv != 0) {
44447bd3a2e2SSriharsha Basavapatna return (rv);
44457bd3a2e2SSriharsha Basavapatna }
44461ae08745Sheppo }
44471ae08745Sheppo
44481ae08745Sheppo break;
44491ae08745Sheppo
44501ae08745Sheppo case VIO_SUBTYPE_ACK:
44511ae08745Sheppo
44521ae08745Sheppo if (ldcp->hphase != VH_PHASE1) {
44531ae08745Sheppo /* This should not happen. */
4454844e62a3Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
44553af08d82Slm66018 return (VGEN_FAILURE);
44561ae08745Sheppo }
44571ae08745Sheppo
44581ae08745Sheppo /* SUCCESS - we have agreed on a version */
44591ae08745Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major;
44601ae08745Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor;
44611ae08745Sheppo ldcp->hstate |= VER_ACK_RCVD;
44621ae08745Sheppo
4463844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n",
4464844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor);
44651ae08745Sheppo
44661ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44671ae08745Sheppo
44681ae08745Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */
44691ae08745Sheppo
44701ae08745Sheppo /* local and peer versions match? */
44711ae08745Sheppo ASSERT((ldcp->local_hparams.ver_major ==
44721ae08745Sheppo ldcp->peer_hparams.ver_major) &&
44731ae08745Sheppo (ldcp->local_hparams.ver_minor ==
44741ae08745Sheppo ldcp->peer_hparams.ver_minor));
44751ae08745Sheppo
4476f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(ldcp);
4477f0ca1d9aSsb155480
44781ae08745Sheppo /* move to the next phase */
44797bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
44807bd3a2e2SSriharsha Basavapatna if (rv != 0) {
44817bd3a2e2SSriharsha Basavapatna return (rv);
44827bd3a2e2SSriharsha Basavapatna }
44831ae08745Sheppo }
44841ae08745Sheppo break;
44851ae08745Sheppo
44861ae08745Sheppo case VIO_SUBTYPE_NACK:
44871ae08745Sheppo
44881ae08745Sheppo if (ldcp->hphase != VH_PHASE1) {
44891ae08745Sheppo /* This should not happen. */
4490844e62a3Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid "
4491844e62a3Sraghuram "Phase(%u)\n", ldcp->hphase);
44923af08d82Slm66018 return (VGEN_FAILURE);
44931ae08745Sheppo }
44941ae08745Sheppo
4495844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n",
4496844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor);
44971ae08745Sheppo
44981ae08745Sheppo /* check if version in NACK is zero */
44991ae08745Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
45001ae08745Sheppo /*
45011ae08745Sheppo * Version Negotiation has failed.
45021ae08745Sheppo */
4503844e62a3Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
45043af08d82Slm66018 return (VGEN_FAILURE);
45051ae08745Sheppo }
45061ae08745Sheppo
45071ae08745Sheppo idx = 0;
45081ae08745Sheppo
45091ae08745Sheppo for (;;) {
45101ae08745Sheppo
45111ae08745Sheppo if (vermsg->ver_major > versions[idx].ver_major) {
45121ae08745Sheppo /* select next lower version */
45131ae08745Sheppo
45141ae08745Sheppo ldcp->local_hparams.ver_major =
45151ae08745Sheppo versions[idx].ver_major;
45161ae08745Sheppo ldcp->local_hparams.ver_minor =
45171ae08745Sheppo versions[idx].ver_minor;
45181ae08745Sheppo break;
45191ae08745Sheppo }
45201ae08745Sheppo
45211ae08745Sheppo if (vermsg->ver_major == versions[idx].ver_major) {
45221ae08745Sheppo /* major version match */
45231ae08745Sheppo
45241ae08745Sheppo ldcp->local_hparams.ver_major =
45251ae08745Sheppo versions[idx].ver_major;
45261ae08745Sheppo
45271ae08745Sheppo ldcp->local_hparams.ver_minor =
45281ae08745Sheppo versions[idx].ver_minor;
45291ae08745Sheppo break;
45301ae08745Sheppo }
45311ae08745Sheppo
45321ae08745Sheppo idx++;
45331ae08745Sheppo
45341ae08745Sheppo if (idx == VGEN_NUM_VER) {
45351ae08745Sheppo /*
45361ae08745Sheppo * no version match.
45371ae08745Sheppo * Version Negotiation has failed.
45381ae08745Sheppo */
4539844e62a3Sraghuram DWARN(vgenp, ldcp,
4540844e62a3Sraghuram "Version Negotiation Failed\n");
45413af08d82Slm66018 return (VGEN_FAILURE);
45421ae08745Sheppo }
45431ae08745Sheppo
45441ae08745Sheppo }
45451ae08745Sheppo
45463af08d82Slm66018 rv = vgen_send_version_negotiate(ldcp);
45473af08d82Slm66018 if (rv != VGEN_SUCCESS) {
45483af08d82Slm66018 return (rv);
45491ae08745Sheppo }
45501ae08745Sheppo
45511ae08745Sheppo break;
45521ae08745Sheppo }
45533af08d82Slm66018
4554844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
45553af08d82Slm66018 return (VGEN_SUCCESS);
45561ae08745Sheppo }
45571ae08745Sheppo
45581ae08745Sheppo static int
vgen_handle_attr_info(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)45597bd3a2e2SSriharsha Basavapatna vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
45601ae08745Sheppo {
4561844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
45627b1f684aSSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
45637b1f684aSSriharsha Basavapatna vgen_hparams_t *rp = &ldcp->peer_hparams;
45647b1f684aSSriharsha Basavapatna uint32_t mtu;
45657bd3a2e2SSriharsha Basavapatna uint8_t dring_mode;
45661ae08745Sheppo
45671ae08745Sheppo ldcp->hstate |= ATTR_INFO_RCVD;
45681ae08745Sheppo
45691ae08745Sheppo /* save peer's values */
45707b1f684aSSriharsha Basavapatna rp->mtu = msg->mtu;
45717b1f684aSSriharsha Basavapatna rp->addr = msg->addr;
45727b1f684aSSriharsha Basavapatna rp->addr_type = msg->addr_type;
45737b1f684aSSriharsha Basavapatna rp->xfer_mode = msg->xfer_mode;
45747b1f684aSSriharsha Basavapatna rp->ack_freq = msg->ack_freq;
45757bd3a2e2SSriharsha Basavapatna rp->dring_mode = msg->options;
45767b1f684aSSriharsha Basavapatna
45777b1f684aSSriharsha Basavapatna /*
45787bd3a2e2SSriharsha Basavapatna * Process address type, ack frequency and transfer mode attributes.
45797b1f684aSSriharsha Basavapatna */
45807bd3a2e2SSriharsha Basavapatna if ((msg->addr_type != ADDR_TYPE_MAC) ||
45817bd3a2e2SSriharsha Basavapatna (msg->ack_freq > 64) ||
45827bd3a2e2SSriharsha Basavapatna (msg->xfer_mode != lp->xfer_mode)) {
45837bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
45847bd3a2e2SSriharsha Basavapatna }
45857bd3a2e2SSriharsha Basavapatna
45867bd3a2e2SSriharsha Basavapatna /*
45877bd3a2e2SSriharsha Basavapatna * Process dring mode attribute.
45887bd3a2e2SSriharsha Basavapatna */
45897bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
45907bd3a2e2SSriharsha Basavapatna /*
45917bd3a2e2SSriharsha Basavapatna * Versions >= 1.6:
45927bd3a2e2SSriharsha Basavapatna * Though we are operating in v1.6 mode, it is possible that
45937bd3a2e2SSriharsha Basavapatna * RxDringData mode has been disabled either on this guest or
45947bd3a2e2SSriharsha Basavapatna * on the peer guest. If so, we revert to pre v1.6 behavior of
45957bd3a2e2SSriharsha Basavapatna * TxDring mode. But this must be agreed upon in both
45967bd3a2e2SSriharsha Basavapatna * directions of attr exchange. We first determine the mode
45977bd3a2e2SSriharsha Basavapatna * that can be negotiated.
45987bd3a2e2SSriharsha Basavapatna */
45997bd3a2e2SSriharsha Basavapatna if ((msg->options & VIO_RX_DRING_DATA) != 0 &&
4600*34f94fbcSWENTAO YANG vgen_mapin_avail(ldcp) == B_TRUE) {
46017bd3a2e2SSriharsha Basavapatna /*
46027bd3a2e2SSriharsha Basavapatna * We are capable of handling RxDringData AND the peer
46037bd3a2e2SSriharsha Basavapatna * is also capable of it; we enable RxDringData mode on
46047bd3a2e2SSriharsha Basavapatna * this channel.
46057bd3a2e2SSriharsha Basavapatna */
46067bd3a2e2SSriharsha Basavapatna dring_mode = VIO_RX_DRING_DATA;
46077bd3a2e2SSriharsha Basavapatna } else if ((msg->options & VIO_TX_DRING) != 0) {
46087bd3a2e2SSriharsha Basavapatna /*
46097bd3a2e2SSriharsha Basavapatna * If the peer is capable of TxDring mode, we
46107bd3a2e2SSriharsha Basavapatna * negotiate TxDring mode on this channel.
46117bd3a2e2SSriharsha Basavapatna */
46127bd3a2e2SSriharsha Basavapatna dring_mode = VIO_TX_DRING;
46137bd3a2e2SSriharsha Basavapatna } else {
46147bd3a2e2SSriharsha Basavapatna /*
46157bd3a2e2SSriharsha Basavapatna * We support only VIO_TX_DRING and VIO_RX_DRING_DATA
46167bd3a2e2SSriharsha Basavapatna * modes. We don't support VIO_RX_DRING mode.
46177bd3a2e2SSriharsha Basavapatna */
46187bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
46197bd3a2e2SSriharsha Basavapatna }
46207bd3a2e2SSriharsha Basavapatna
46217bd3a2e2SSriharsha Basavapatna /*
46227bd3a2e2SSriharsha Basavapatna * If we have received an ack for the attr info that we sent,
46237bd3a2e2SSriharsha Basavapatna * then check if the dring mode matches what the peer had ack'd
46247bd3a2e2SSriharsha Basavapatna * (saved in local hparams). If they don't match, we fail the
46257bd3a2e2SSriharsha Basavapatna * handshake.
46267bd3a2e2SSriharsha Basavapatna */
46277bd3a2e2SSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_RCVD) {
46287bd3a2e2SSriharsha Basavapatna if (msg->options != lp->dring_mode) {
46297bd3a2e2SSriharsha Basavapatna /* send NACK */
46307bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
46317bd3a2e2SSriharsha Basavapatna }
46327bd3a2e2SSriharsha Basavapatna } else {
46337bd3a2e2SSriharsha Basavapatna /*
46347bd3a2e2SSriharsha Basavapatna * Save the negotiated dring mode in our attr
46357bd3a2e2SSriharsha Basavapatna * parameters, so it gets sent in the attr info from us
46367bd3a2e2SSriharsha Basavapatna * to the peer.
46377bd3a2e2SSriharsha Basavapatna */
46387bd3a2e2SSriharsha Basavapatna lp->dring_mode = dring_mode;
46397bd3a2e2SSriharsha Basavapatna }
46407bd3a2e2SSriharsha Basavapatna
46417bd3a2e2SSriharsha Basavapatna /* save the negotiated dring mode in the msg to be replied */
46427bd3a2e2SSriharsha Basavapatna msg->options = dring_mode;
46437bd3a2e2SSriharsha Basavapatna }
46447bd3a2e2SSriharsha Basavapatna
46457bd3a2e2SSriharsha Basavapatna /*
46467bd3a2e2SSriharsha Basavapatna * Process MTU attribute.
46477bd3a2e2SSriharsha Basavapatna */
46487bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
46497bd3a2e2SSriharsha Basavapatna /*
46507bd3a2e2SSriharsha Basavapatna * Versions >= 1.4:
46517bd3a2e2SSriharsha Basavapatna * Validate mtu of the peer is at least ETHERMAX. Then, the mtu
46527bd3a2e2SSriharsha Basavapatna * is negotiated down to the minimum of our mtu and peer's mtu.
46537bd3a2e2SSriharsha Basavapatna */
46547bd3a2e2SSriharsha Basavapatna if (msg->mtu < ETHERMAX) {
46557bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
46567bd3a2e2SSriharsha Basavapatna }
46577bd3a2e2SSriharsha Basavapatna
46587b1f684aSSriharsha Basavapatna mtu = MIN(msg->mtu, vgenp->max_frame_size);
46597b1f684aSSriharsha Basavapatna
46607b1f684aSSriharsha Basavapatna /*
46617b1f684aSSriharsha Basavapatna * If we have received an ack for the attr info
46627b1f684aSSriharsha Basavapatna * that we sent, then check if the mtu computed
46637b1f684aSSriharsha Basavapatna * above matches the mtu that the peer had ack'd
46647b1f684aSSriharsha Basavapatna * (saved in local hparams). If they don't
46657b1f684aSSriharsha Basavapatna * match, we fail the handshake.
46667b1f684aSSriharsha Basavapatna */
46677b1f684aSSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_RCVD) {
46687b1f684aSSriharsha Basavapatna if (mtu != lp->mtu) {
46697b1f684aSSriharsha Basavapatna /* send NACK */
46707bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
46717b1f684aSSriharsha Basavapatna }
46727b1f684aSSriharsha Basavapatna } else {
46737b1f684aSSriharsha Basavapatna /*
46747b1f684aSSriharsha Basavapatna * Save the mtu computed above in our
46757b1f684aSSriharsha Basavapatna * attr parameters, so it gets sent in
46767b1f684aSSriharsha Basavapatna * the attr info from us to the peer.
46777b1f684aSSriharsha Basavapatna */
46787b1f684aSSriharsha Basavapatna lp->mtu = mtu;
46797b1f684aSSriharsha Basavapatna }
46807b1f684aSSriharsha Basavapatna
46817b1f684aSSriharsha Basavapatna /* save the MIN mtu in the msg to be replied */
46827b1f684aSSriharsha Basavapatna msg->mtu = mtu;
46837b1f684aSSriharsha Basavapatna
46847b1f684aSSriharsha Basavapatna } else {
46857bd3a2e2SSriharsha Basavapatna /* versions < 1.4, mtu must match */
46867bd3a2e2SSriharsha Basavapatna if (msg->mtu != lp->mtu) {
46877bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
46881ae08745Sheppo }
46891ae08745Sheppo }
46901ae08745Sheppo
46917bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
46927bd3a2e2SSriharsha Basavapatna }
46937bd3a2e2SSriharsha Basavapatna
46947bd3a2e2SSriharsha Basavapatna static int
vgen_handle_attr_ack(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)46957bd3a2e2SSriharsha Basavapatna vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
46967bd3a2e2SSriharsha Basavapatna {
46977bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
46987bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
46997bd3a2e2SSriharsha Basavapatna
47007bd3a2e2SSriharsha Basavapatna /*
47017bd3a2e2SSriharsha Basavapatna * Process dring mode attribute.
47027bd3a2e2SSriharsha Basavapatna */
47037bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
47047bd3a2e2SSriharsha Basavapatna /*
47057bd3a2e2SSriharsha Basavapatna * Versions >= 1.6:
47067bd3a2e2SSriharsha Basavapatna * The ack msg sent by the peer contains the negotiated dring
47077bd3a2e2SSriharsha Basavapatna * mode between our capability (that we had sent in our attr
47087bd3a2e2SSriharsha Basavapatna * info) and the peer's capability.
47097bd3a2e2SSriharsha Basavapatna */
47107bd3a2e2SSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_SENT) {
47117bd3a2e2SSriharsha Basavapatna /*
47127bd3a2e2SSriharsha Basavapatna * If we have sent an ack for the attr info msg from
47137bd3a2e2SSriharsha Basavapatna * the peer, check if the dring mode that was
47147bd3a2e2SSriharsha Basavapatna * negotiated then (saved in local hparams) matches the
47157bd3a2e2SSriharsha Basavapatna * mode that the peer has ack'd. If they don't match,
47167bd3a2e2SSriharsha Basavapatna * we fail the handshake.
47177bd3a2e2SSriharsha Basavapatna */
47187bd3a2e2SSriharsha Basavapatna if (lp->dring_mode != msg->options) {
47197bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
47207bd3a2e2SSriharsha Basavapatna }
47211ae08745Sheppo } else {
47227bd3a2e2SSriharsha Basavapatna if ((msg->options & lp->dring_mode) == 0) {
47237bd3a2e2SSriharsha Basavapatna /*
47247bd3a2e2SSriharsha Basavapatna * Peer ack'd with a mode that we don't
47257bd3a2e2SSriharsha Basavapatna * support; we fail the handshake.
47267bd3a2e2SSriharsha Basavapatna */
47277bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
47287bd3a2e2SSriharsha Basavapatna }
47297bd3a2e2SSriharsha Basavapatna if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA))
47307bd3a2e2SSriharsha Basavapatna == (VIO_TX_DRING|VIO_RX_DRING_DATA)) {
47317bd3a2e2SSriharsha Basavapatna /*
47327bd3a2e2SSriharsha Basavapatna * Peer must ack with only one negotiated mode.
47337bd3a2e2SSriharsha Basavapatna * Otherwise fail handshake.
47347bd3a2e2SSriharsha Basavapatna */
47353af08d82Slm66018 return (VGEN_FAILURE);
47361ae08745Sheppo }
47371ae08745Sheppo
47387bd3a2e2SSriharsha Basavapatna /*
47397bd3a2e2SSriharsha Basavapatna * Save the negotiated mode, so we can validate it when
47407bd3a2e2SSriharsha Basavapatna * we receive attr info from the peer.
47417bd3a2e2SSriharsha Basavapatna */
47427bd3a2e2SSriharsha Basavapatna lp->dring_mode = msg->options;
47437bd3a2e2SSriharsha Basavapatna }
47441ae08745Sheppo }
47451ae08745Sheppo
47467bd3a2e2SSriharsha Basavapatna /*
47477bd3a2e2SSriharsha Basavapatna * Process Physical Link Update attribute.
47487bd3a2e2SSriharsha Basavapatna */
47491107ea93SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 5) &&
47501107ea93SSriharsha Basavapatna ldcp->portp == vgenp->vsw_portp) {
47511107ea93SSriharsha Basavapatna /*
47521107ea93SSriharsha Basavapatna * Versions >= 1.5:
47531107ea93SSriharsha Basavapatna * If the vnet device has been configured to get
47541107ea93SSriharsha Basavapatna * physical link state updates, check the corresponding
47551107ea93SSriharsha Basavapatna * bits in the ack msg, if the peer is vswitch.
47561107ea93SSriharsha Basavapatna */
47577bd3a2e2SSriharsha Basavapatna if (((lp->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
47581107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE) &&
47597bd3a2e2SSriharsha Basavapatna ((msg->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
47601107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_ACK)) {
47611107ea93SSriharsha Basavapatna vgenp->pls_negotiated = B_TRUE;
47621107ea93SSriharsha Basavapatna } else {
47631107ea93SSriharsha Basavapatna vgenp->pls_negotiated = B_FALSE;
47641107ea93SSriharsha Basavapatna }
47651107ea93SSriharsha Basavapatna }
47661107ea93SSriharsha Basavapatna
47677bd3a2e2SSriharsha Basavapatna /*
47687bd3a2e2SSriharsha Basavapatna * Process MTU attribute.
47697bd3a2e2SSriharsha Basavapatna */
47707b1f684aSSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
47717b1f684aSSriharsha Basavapatna /*
47727b1f684aSSriharsha Basavapatna * Versions >= 1.4:
47737b1f684aSSriharsha Basavapatna * The ack msg sent by the peer contains the minimum of
47747b1f684aSSriharsha Basavapatna * our mtu (that we had sent in our attr info) and the
47757b1f684aSSriharsha Basavapatna * peer's mtu.
47767b1f684aSSriharsha Basavapatna *
47777b1f684aSSriharsha Basavapatna * If we have sent an ack for the attr info msg from
47787b1f684aSSriharsha Basavapatna * the peer, check if the mtu that was computed then
47797b1f684aSSriharsha Basavapatna * (saved in local hparams) matches the mtu that the
47807b1f684aSSriharsha Basavapatna * peer has ack'd. If they don't match, we fail the
47817b1f684aSSriharsha Basavapatna * handshake.
47827b1f684aSSriharsha Basavapatna */
47837b1f684aSSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_SENT) {
47847b1f684aSSriharsha Basavapatna if (lp->mtu != msg->mtu) {
47857b1f684aSSriharsha Basavapatna return (VGEN_FAILURE);
47867b1f684aSSriharsha Basavapatna }
47877b1f684aSSriharsha Basavapatna } else {
47887b1f684aSSriharsha Basavapatna /*
47897b1f684aSSriharsha Basavapatna * If the mtu ack'd by the peer is > our mtu
47907b1f684aSSriharsha Basavapatna * fail handshake. Otherwise, save the mtu, so
47917b1f684aSSriharsha Basavapatna * we can validate it when we receive attr info
47927b1f684aSSriharsha Basavapatna * from our peer.
47937b1f684aSSriharsha Basavapatna */
47947b1f684aSSriharsha Basavapatna if (msg->mtu > lp->mtu) {
47957b1f684aSSriharsha Basavapatna return (VGEN_FAILURE);
47967b1f684aSSriharsha Basavapatna }
47977b1f684aSSriharsha Basavapatna if (msg->mtu <= lp->mtu) {
47987b1f684aSSriharsha Basavapatna lp->mtu = msg->mtu;
47997b1f684aSSriharsha Basavapatna }
48007b1f684aSSriharsha Basavapatna }
48017b1f684aSSriharsha Basavapatna }
48027b1f684aSSriharsha Basavapatna
48037bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
48047bd3a2e2SSriharsha Basavapatna }
48051ae08745Sheppo
48067bd3a2e2SSriharsha Basavapatna
48077bd3a2e2SSriharsha Basavapatna /*
48087bd3a2e2SSriharsha Basavapatna * Handle an attribute info msg from the peer or an ACK/NACK from the peer
48097bd3a2e2SSriharsha Basavapatna * to an attr info msg that we sent.
48107bd3a2e2SSriharsha Basavapatna */
48117bd3a2e2SSriharsha Basavapatna static int
vgen_handle_attr_msg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)48127bd3a2e2SSriharsha Basavapatna vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48137bd3a2e2SSriharsha Basavapatna {
48147bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
48157bd3a2e2SSriharsha Basavapatna vnet_attr_msg_t *msg = (vnet_attr_msg_t *)tagp;
48167bd3a2e2SSriharsha Basavapatna int rv = 0;
48177bd3a2e2SSriharsha Basavapatna
48187bd3a2e2SSriharsha Basavapatna DBG1(vgenp, ldcp, "enter\n");
48197bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_PHASE2) {
48207bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d),"
48217bd3a2e2SSriharsha Basavapatna " Invalid Phase(%u)\n",
48227bd3a2e2SSriharsha Basavapatna tagp->vio_subtype, ldcp->hphase);
48237bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE);
48247bd3a2e2SSriharsha Basavapatna }
48257bd3a2e2SSriharsha Basavapatna switch (tagp->vio_subtype) {
48267bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO:
48277bd3a2e2SSriharsha Basavapatna
48287bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_info(ldcp, msg);
48297bd3a2e2SSriharsha Basavapatna if (rv == VGEN_SUCCESS) {
48307bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_ACK;
48317bd3a2e2SSriharsha Basavapatna } else {
48327bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_NACK;
48337bd3a2e2SSriharsha Basavapatna }
48347bd3a2e2SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid;
48357bd3a2e2SSriharsha Basavapatna
48367bd3a2e2SSriharsha Basavapatna /* send reply msg back to peer */
48377bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
48387bd3a2e2SSriharsha Basavapatna B_FALSE);
48397bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
48407bd3a2e2SSriharsha Basavapatna return (rv);
48417bd3a2e2SSriharsha Basavapatna }
48427bd3a2e2SSriharsha Basavapatna
48437bd3a2e2SSriharsha Basavapatna if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
48447bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ATTR_NACK_SENT");
48457bd3a2e2SSriharsha Basavapatna break;
48467bd3a2e2SSriharsha Basavapatna }
48477bd3a2e2SSriharsha Basavapatna
48487bd3a2e2SSriharsha Basavapatna ldcp->hstate |= ATTR_ACK_SENT;
48497bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n");
48507bd3a2e2SSriharsha Basavapatna if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
48517bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
48527bd3a2e2SSriharsha Basavapatna if (rv != 0) {
48537bd3a2e2SSriharsha Basavapatna return (rv);
48547bd3a2e2SSriharsha Basavapatna }
48557bd3a2e2SSriharsha Basavapatna }
48567bd3a2e2SSriharsha Basavapatna
48577bd3a2e2SSriharsha Basavapatna break;
48587bd3a2e2SSriharsha Basavapatna
48597bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
48607bd3a2e2SSriharsha Basavapatna
48617bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_ack(ldcp, msg);
48627bd3a2e2SSriharsha Basavapatna if (rv == VGEN_FAILURE) {
48637bd3a2e2SSriharsha Basavapatna break;
48647bd3a2e2SSriharsha Basavapatna }
48657bd3a2e2SSriharsha Basavapatna
48667bd3a2e2SSriharsha Basavapatna ldcp->hstate |= ATTR_ACK_RCVD;
4867844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n");
48681ae08745Sheppo
48691ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
48707bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
48717bd3a2e2SSriharsha Basavapatna if (rv != 0) {
48727bd3a2e2SSriharsha Basavapatna return (rv);
48737bd3a2e2SSriharsha Basavapatna }
48741ae08745Sheppo }
48751ae08745Sheppo break;
48761ae08745Sheppo
48771ae08745Sheppo case VIO_SUBTYPE_NACK:
48781ae08745Sheppo
4879844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n");
48803af08d82Slm66018 return (VGEN_FAILURE);
48811ae08745Sheppo }
4882844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
48833af08d82Slm66018 return (VGEN_SUCCESS);
48841ae08745Sheppo }
48851ae08745Sheppo
48861ae08745Sheppo static int
vgen_handle_dring_reg_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)48877bd3a2e2SSriharsha Basavapatna vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48881ae08745Sheppo {
48897bd3a2e2SSriharsha Basavapatna int rv = 0;
48907bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
48917bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
48927bd3a2e2SSriharsha Basavapatna
48937bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_INFO_RCVD");
48947bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_INFO_RCVD;
48957bd3a2e2SSriharsha Basavapatna
48967bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6) &&
48977bd3a2e2SSriharsha Basavapatna (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
48987bd3a2e2SSriharsha Basavapatna /*
48997bd3a2e2SSriharsha Basavapatna * The earlier version of Solaris vnet driver doesn't set the
49007bd3a2e2SSriharsha Basavapatna * option (VIO_TX_DRING in its case) correctly in its dring reg
49017bd3a2e2SSriharsha Basavapatna * message. We workaround that here by doing the check only
49027bd3a2e2SSriharsha Basavapatna * for versions >= v1.6.
49037bd3a2e2SSriharsha Basavapatna */
49047bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp,
49057bd3a2e2SSriharsha Basavapatna "Rcvd dring reg option (%d), negotiated mode (%d)\n",
49067bd3a2e2SSriharsha Basavapatna ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode);
49071ae08745Sheppo return (VGEN_FAILURE);
49081ae08745Sheppo }
49097bd3a2e2SSriharsha Basavapatna
49107bd3a2e2SSriharsha Basavapatna /*
49117bd3a2e2SSriharsha Basavapatna * Map dring exported by the peer.
49127bd3a2e2SSriharsha Basavapatna */
49137bd3a2e2SSriharsha Basavapatna rv = vgen_map_dring(ldcp, (void *)tagp);
49147bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
49157bd3a2e2SSriharsha Basavapatna return (rv);
49167bd3a2e2SSriharsha Basavapatna }
49177bd3a2e2SSriharsha Basavapatna
49187bd3a2e2SSriharsha Basavapatna /*
49197bd3a2e2SSriharsha Basavapatna * Map data buffers exported by the peer if we are in RxDringData mode.
49207bd3a2e2SSriharsha Basavapatna */
49217bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
49227bd3a2e2SSriharsha Basavapatna rv = vgen_map_data(ldcp, (void *)tagp);
49237bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
49247bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(ldcp);
49257bd3a2e2SSriharsha Basavapatna return (rv);
49267bd3a2e2SSriharsha Basavapatna }
49277bd3a2e2SSriharsha Basavapatna }
49287bd3a2e2SSriharsha Basavapatna
49297bd3a2e2SSriharsha Basavapatna if (ldcp->peer_hparams.dring_ready == B_FALSE) {
49307bd3a2e2SSriharsha Basavapatna ldcp->peer_hparams.dring_ready = B_TRUE;
49317bd3a2e2SSriharsha Basavapatna }
49327bd3a2e2SSriharsha Basavapatna
49337bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
49347bd3a2e2SSriharsha Basavapatna }
49357bd3a2e2SSriharsha Basavapatna
49367bd3a2e2SSriharsha Basavapatna static int
vgen_handle_dring_reg_ack(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)49377bd3a2e2SSriharsha Basavapatna vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
49387bd3a2e2SSriharsha Basavapatna {
49397bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
49407bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
49417bd3a2e2SSriharsha Basavapatna
49427bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_ACK_RCVD");
49437bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_ACK_RCVD;
49447bd3a2e2SSriharsha Basavapatna
49457bd3a2e2SSriharsha Basavapatna if (lp->dring_ready) {
49467bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS);
49477bd3a2e2SSriharsha Basavapatna }
49487bd3a2e2SSriharsha Basavapatna
49497bd3a2e2SSriharsha Basavapatna /* save dring_ident acked by peer */
49507bd3a2e2SSriharsha Basavapatna lp->dring_ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
49517bd3a2e2SSriharsha Basavapatna
49527bd3a2e2SSriharsha Basavapatna /* local dring is now ready */
49537bd3a2e2SSriharsha Basavapatna lp->dring_ready = B_TRUE;
49547bd3a2e2SSriharsha Basavapatna
49551ae08745Sheppo return (VGEN_SUCCESS);
49561ae08745Sheppo }
49571ae08745Sheppo
49581ae08745Sheppo /*
49591ae08745Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from
49601ae08745Sheppo * the peer to a dring register msg that we sent.
49611ae08745Sheppo */
49623af08d82Slm66018 static int
vgen_handle_dring_reg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)49631ae08745Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
49641ae08745Sheppo {
4965844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
49661ae08745Sheppo int rv = 0;
49677bd3a2e2SSriharsha Basavapatna int msgsize;
49687bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
49691ae08745Sheppo
4970844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
49711ae08745Sheppo if (ldcp->hphase < VH_PHASE2) {
49721ae08745Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */
4973844e62a3Sraghuram DWARN(vgenp, ldcp,
4974844e62a3Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n",
4975844e62a3Sraghuram tagp->vio_subtype, ldcp->hphase);
49763af08d82Slm66018 return (VGEN_FAILURE);
49771ae08745Sheppo }
49787bd3a2e2SSriharsha Basavapatna
49791ae08745Sheppo switch (tagp->vio_subtype) {
49801ae08745Sheppo case VIO_SUBTYPE_INFO:
49811ae08745Sheppo
49827bd3a2e2SSriharsha Basavapatna rv = vgen_handle_dring_reg_info(ldcp, tagp);
49837bd3a2e2SSriharsha Basavapatna if (rv == VGEN_SUCCESS) {
49841ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
49857bd3a2e2SSriharsha Basavapatna } else {
49867bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_NACK;
49871ae08745Sheppo }
49887bd3a2e2SSriharsha Basavapatna
49891ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
49907bd3a2e2SSriharsha Basavapatna
49917bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
49927bd3a2e2SSriharsha Basavapatna msgsize =
49937bd3a2e2SSriharsha Basavapatna VNET_DRING_REG_EXT_MSG_SIZE(ldcp->tx_data_ncookies);
49947bd3a2e2SSriharsha Basavapatna } else {
49957bd3a2e2SSriharsha Basavapatna msgsize = sizeof (vio_dring_reg_msg_t);
49967bd3a2e2SSriharsha Basavapatna }
49977bd3a2e2SSriharsha Basavapatna
49981ae08745Sheppo /* send reply msg back to peer */
49997bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp, msgsize,
50003af08d82Slm66018 B_FALSE);
50013af08d82Slm66018 if (rv != VGEN_SUCCESS) {
50023af08d82Slm66018 return (rv);
50031ae08745Sheppo }
50041ae08745Sheppo
50057bd3a2e2SSriharsha Basavapatna if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
5006844e62a3Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT");
50073af08d82Slm66018 return (VGEN_FAILURE);
50081ae08745Sheppo }
50091ae08745Sheppo
50107bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_ACK_SENT;
50117bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_ACK_SENT");
50121ae08745Sheppo
50137bd3a2e2SSriharsha Basavapatna if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
50147bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
50157bd3a2e2SSriharsha Basavapatna if (rv != 0) {
50167bd3a2e2SSriharsha Basavapatna return (rv);
50177bd3a2e2SSriharsha Basavapatna }
50187bd3a2e2SSriharsha Basavapatna }
50191ae08745Sheppo break;
50201ae08745Sheppo
50211ae08745Sheppo case VIO_SUBTYPE_ACK:
50221ae08745Sheppo
50237bd3a2e2SSriharsha Basavapatna rv = vgen_handle_dring_reg_ack(ldcp, tagp);
50247bd3a2e2SSriharsha Basavapatna if (rv == VGEN_FAILURE) {
50257bd3a2e2SSriharsha Basavapatna return (rv);
50261ae08745Sheppo }
50271ae08745Sheppo
50281ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
50297bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
50307bd3a2e2SSriharsha Basavapatna if (rv != 0) {
50317bd3a2e2SSriharsha Basavapatna return (rv);
50327bd3a2e2SSriharsha Basavapatna }
50331ae08745Sheppo }
50341ae08745Sheppo
50351ae08745Sheppo break;
50361ae08745Sheppo
50371ae08745Sheppo case VIO_SUBTYPE_NACK:
50381ae08745Sheppo
50397bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "DRING_NACK_RCVD");
50403af08d82Slm66018 return (VGEN_FAILURE);
50411ae08745Sheppo }
5042844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
50433af08d82Slm66018 return (VGEN_SUCCESS);
50441ae08745Sheppo }
50451ae08745Sheppo
50461ae08745Sheppo /*
50471ae08745Sheppo * Handle a rdx info msg from the peer or an ACK/NACK
50481ae08745Sheppo * from the peer to a rdx info msg that we sent.
50491ae08745Sheppo */
50503af08d82Slm66018 static int
vgen_handle_rdx_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)50511ae08745Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
50521ae08745Sheppo {
50533af08d82Slm66018 int rv = 0;
5054844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
50551ae08745Sheppo
5056844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
50577bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_PHASE4) {
5058844e62a3Sraghuram DWARN(vgenp, ldcp,
5059844e62a3Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n",
5060844e62a3Sraghuram tagp->vio_subtype, ldcp->hphase);
50613af08d82Slm66018 return (VGEN_FAILURE);
50621ae08745Sheppo }
50631ae08745Sheppo switch (tagp->vio_subtype) {
50641ae08745Sheppo case VIO_SUBTYPE_INFO:
50651ae08745Sheppo
5066844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n");
50671ae08745Sheppo ldcp->hstate |= RDX_INFO_RCVD;
50681ae08745Sheppo
50691ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
50701ae08745Sheppo tagp->vio_sid = ldcp->local_sid;
50711ae08745Sheppo /* send reply msg back to peer */
50723af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
50733af08d82Slm66018 B_FALSE);
50743af08d82Slm66018 if (rv != VGEN_SUCCESS) {
50753af08d82Slm66018 return (rv);
50761ae08745Sheppo }
50771ae08745Sheppo
50781ae08745Sheppo ldcp->hstate |= RDX_ACK_SENT;
5079844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n");
50801ae08745Sheppo
50811ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
50827bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
50837bd3a2e2SSriharsha Basavapatna if (rv != 0) {
50847bd3a2e2SSriharsha Basavapatna return (rv);
50857bd3a2e2SSriharsha Basavapatna }
50861ae08745Sheppo }
50871ae08745Sheppo
50881ae08745Sheppo break;
50891ae08745Sheppo
50901ae08745Sheppo case VIO_SUBTYPE_ACK:
50911ae08745Sheppo
50921ae08745Sheppo ldcp->hstate |= RDX_ACK_RCVD;
50931ae08745Sheppo
5094844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n");
50951ae08745Sheppo
50961ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
50977bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp));
50987bd3a2e2SSriharsha Basavapatna if (rv != 0) {
50997bd3a2e2SSriharsha Basavapatna return (rv);
51007bd3a2e2SSriharsha Basavapatna }
51011ae08745Sheppo }
51021ae08745Sheppo break;
51031ae08745Sheppo
51041ae08745Sheppo case VIO_SUBTYPE_NACK:
51051ae08745Sheppo
5106844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n");
51073af08d82Slm66018 return (VGEN_FAILURE);
51081ae08745Sheppo }
5109844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
51103af08d82Slm66018 return (VGEN_SUCCESS);
51111ae08745Sheppo }
51121ae08745Sheppo
51131ae08745Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
51143af08d82Slm66018 static int
vgen_handle_mcast_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51151ae08745Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51161ae08745Sheppo {
51171ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp);
51181ae08745Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
51191ae08745Sheppo struct ether_addr *addrp;
51201ae08745Sheppo int count;
51211ae08745Sheppo int i;
51221ae08745Sheppo
5123844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
51241ae08745Sheppo switch (tagp->vio_subtype) {
51251ae08745Sheppo
51261ae08745Sheppo case VIO_SUBTYPE_INFO:
51271ae08745Sheppo
51281ae08745Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */
5129844e62a3Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n");
51301ae08745Sheppo break;
51311ae08745Sheppo
51321ae08745Sheppo case VIO_SUBTYPE_ACK:
51331ae08745Sheppo
51341ae08745Sheppo /* success adding/removing multicast addr */
5135844e62a3Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n");
51361ae08745Sheppo break;
51371ae08745Sheppo
51381ae08745Sheppo case VIO_SUBTYPE_NACK:
51391ae08745Sheppo
5140844e62a3Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n");
51411ae08745Sheppo if (!(msgp->set)) {
51421ae08745Sheppo /* multicast remove request failed */
51431ae08745Sheppo break;
51441ae08745Sheppo }
51451ae08745Sheppo
51461ae08745Sheppo /* multicast add request failed */
51471ae08745Sheppo for (count = 0; count < msgp->count; count++) {
51481ae08745Sheppo addrp = &(msgp->mca[count]);
51491ae08745Sheppo
51501ae08745Sheppo /* delete address from the table */
51511ae08745Sheppo for (i = 0; i < vgenp->mccount; i++) {
51521ae08745Sheppo if (ether_cmp(addrp,
51531ae08745Sheppo &(vgenp->mctab[i])) == 0) {
51541ae08745Sheppo if (vgenp->mccount > 1) {
5155844e62a3Sraghuram int t = vgenp->mccount - 1;
51561ae08745Sheppo vgenp->mctab[i] =
5157844e62a3Sraghuram vgenp->mctab[t];
51581ae08745Sheppo }
51591ae08745Sheppo vgenp->mccount--;
51601ae08745Sheppo break;
51611ae08745Sheppo }
51621ae08745Sheppo }
51631ae08745Sheppo }
51641ae08745Sheppo break;
51651ae08745Sheppo
51661ae08745Sheppo }
5167844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n");
51683af08d82Slm66018
51693af08d82Slm66018 return (VGEN_SUCCESS);
51701ae08745Sheppo }
51711ae08745Sheppo
51721107ea93SSriharsha Basavapatna /*
51731107ea93SSriharsha Basavapatna * Physical link information message from the peer. Only vswitch should send
51741107ea93SSriharsha Basavapatna * us this message; if the vnet device has been configured to get physical link
51751107ea93SSriharsha Basavapatna * state updates. Note that we must have already negotiated this with the
51761107ea93SSriharsha Basavapatna * vswitch during attribute exchange phase of handshake.
51771107ea93SSriharsha Basavapatna */
51781107ea93SSriharsha Basavapatna static int
vgen_handle_physlink_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51791107ea93SSriharsha Basavapatna vgen_handle_physlink_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51801107ea93SSriharsha Basavapatna {
51811107ea93SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
51821107ea93SSriharsha Basavapatna vnet_physlink_msg_t *msgp = (vnet_physlink_msg_t *)tagp;
51831107ea93SSriharsha Basavapatna link_state_t link_state;
51841107ea93SSriharsha Basavapatna int rv;
51851107ea93SSriharsha Basavapatna
51861107ea93SSriharsha Basavapatna if (ldcp->portp != vgenp->vsw_portp) {
51871107ea93SSriharsha Basavapatna /*
51881107ea93SSriharsha Basavapatna * drop the message and don't process; as we should
51891107ea93SSriharsha Basavapatna * receive physlink_info message from only vswitch.
51901107ea93SSriharsha Basavapatna */
51911107ea93SSriharsha Basavapatna return (VGEN_SUCCESS);
51921107ea93SSriharsha Basavapatna }
51931107ea93SSriharsha Basavapatna
51941107ea93SSriharsha Basavapatna if (vgenp->pls_negotiated == B_FALSE) {
51951107ea93SSriharsha Basavapatna /*
51961107ea93SSriharsha Basavapatna * drop the message and don't process; as we should receive
51971107ea93SSriharsha Basavapatna * physlink_info message only if physlink update is enabled for
51981107ea93SSriharsha Basavapatna * the device and negotiated with vswitch.
51991107ea93SSriharsha Basavapatna */
52001107ea93SSriharsha Basavapatna return (VGEN_SUCCESS);
52011107ea93SSriharsha Basavapatna }
52021107ea93SSriharsha Basavapatna
52031107ea93SSriharsha Basavapatna switch (tagp->vio_subtype) {
52041107ea93SSriharsha Basavapatna
52051107ea93SSriharsha Basavapatna case VIO_SUBTYPE_INFO:
52061107ea93SSriharsha Basavapatna
52071107ea93SSriharsha Basavapatna if ((msgp->physlink_info & VNET_PHYSLINK_STATE_MASK) ==
52081107ea93SSriharsha Basavapatna VNET_PHYSLINK_STATE_UP) {
52091107ea93SSriharsha Basavapatna link_state = LINK_STATE_UP;
52101107ea93SSriharsha Basavapatna } else {
52111107ea93SSriharsha Basavapatna link_state = LINK_STATE_DOWN;
52121107ea93SSriharsha Basavapatna }
52131107ea93SSriharsha Basavapatna
52141107ea93SSriharsha Basavapatna if (vgenp->phys_link_state != link_state) {
52151107ea93SSriharsha Basavapatna vgenp->phys_link_state = link_state;
52161107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
52171107ea93SSriharsha Basavapatna
52181107ea93SSriharsha Basavapatna /* Now update the stack */
52191107ea93SSriharsha Basavapatna vgen_link_update(vgenp, link_state);
52201107ea93SSriharsha Basavapatna
52211107ea93SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
52221107ea93SSriharsha Basavapatna }
52231107ea93SSriharsha Basavapatna
52241107ea93SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_ACK;
52251107ea93SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid;
52261107ea93SSriharsha Basavapatna
52271107ea93SSriharsha Basavapatna /* send reply msg back to peer */
52281107ea93SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
52291107ea93SSriharsha Basavapatna sizeof (vnet_physlink_msg_t), B_FALSE);
52301107ea93SSriharsha Basavapatna if (rv != VGEN_SUCCESS) {
52311107ea93SSriharsha Basavapatna return (rv);
52321107ea93SSriharsha Basavapatna }
52331107ea93SSriharsha Basavapatna break;
52341107ea93SSriharsha Basavapatna
52351107ea93SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
52361107ea93SSriharsha Basavapatna
52371107ea93SSriharsha Basavapatna /* vnet shouldn't recv physlink acks */
52381107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "rcvd PHYSLINK_ACK \n");
52391107ea93SSriharsha Basavapatna break;
52401107ea93SSriharsha Basavapatna
52411107ea93SSriharsha Basavapatna case VIO_SUBTYPE_NACK:
52421107ea93SSriharsha Basavapatna
52431107ea93SSriharsha Basavapatna /* vnet shouldn't recv physlink nacks */
52441107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "rcvd PHYSLINK_NACK \n");
52451107ea93SSriharsha Basavapatna break;
52461107ea93SSriharsha Basavapatna
52471107ea93SSriharsha Basavapatna }
52481107ea93SSriharsha Basavapatna DBG1(vgenp, ldcp, "exit\n");
52491107ea93SSriharsha Basavapatna
52501107ea93SSriharsha Basavapatna return (VGEN_SUCCESS);
52511107ea93SSriharsha Basavapatna }
52521107ea93SSriharsha Basavapatna
52531ae08745Sheppo /* handler for control messages received from the peer ldc end-point */
52543af08d82Slm66018 static int
vgen_handle_ctrlmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)52551ae08745Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
52561ae08745Sheppo {
52573af08d82Slm66018 int rv = 0;
5258844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
52591ae08745Sheppo
5260844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
52611ae08745Sheppo switch (tagp->vio_subtype_env) {
52621ae08745Sheppo
52631ae08745Sheppo case VIO_VER_INFO:
52643af08d82Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp);
52651ae08745Sheppo break;
52661ae08745Sheppo
52671ae08745Sheppo case VIO_ATTR_INFO:
52687bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_msg(ldcp, tagp);
52691ae08745Sheppo break;
52701ae08745Sheppo
52711ae08745Sheppo case VIO_DRING_REG:
52723af08d82Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp);
52731ae08745Sheppo break;
52741ae08745Sheppo
52751ae08745Sheppo case VIO_RDX:
52763af08d82Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp);
52771ae08745Sheppo break;
52781ae08745Sheppo
52791ae08745Sheppo case VNET_MCAST_INFO:
52803af08d82Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp);
52811ae08745Sheppo break;
52821ae08745Sheppo
5283678453a8Sspeer case VIO_DDS_INFO:
52846d6de4eeSWENTAO YANG /*
52856d6de4eeSWENTAO YANG * If we are in the process of resetting the vswitch channel,
52866d6de4eeSWENTAO YANG * drop the dds message. A new handshake will be initiated
52876d6de4eeSWENTAO YANG * when the channel comes back up after the reset and dds
52886d6de4eeSWENTAO YANG * negotiation can then continue.
52896d6de4eeSWENTAO YANG */
52907bd3a2e2SSriharsha Basavapatna if (ldcp->reset_in_progress == 1) {
52916d6de4eeSWENTAO YANG break;
52926d6de4eeSWENTAO YANG }
5293678453a8Sspeer rv = vgen_dds_rx(ldcp, tagp);
5294678453a8Sspeer break;
52951107ea93SSriharsha Basavapatna
52961107ea93SSriharsha Basavapatna case VNET_PHYSLINK_INFO:
52971107ea93SSriharsha Basavapatna rv = vgen_handle_physlink_info(ldcp, tagp);
52981107ea93SSriharsha Basavapatna break;
52991ae08745Sheppo }
53003af08d82Slm66018
5301844e62a3Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
53023af08d82Slm66018 return (rv);
53031ae08745Sheppo }
53041ae08745Sheppo
53057bd3a2e2SSriharsha Basavapatna /* handler for error messages received from the peer ldc end-point */
53067bd3a2e2SSriharsha Basavapatna static void
vgen_handle_errmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)53077bd3a2e2SSriharsha Basavapatna vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
53087bd3a2e2SSriharsha Basavapatna {
53097bd3a2e2SSriharsha Basavapatna _NOTE(ARGUNUSED(ldcp, tagp))
53107bd3a2e2SSriharsha Basavapatna }
53117bd3a2e2SSriharsha Basavapatna
53127bd3a2e2SSriharsha Basavapatna /*
53137bd3a2e2SSriharsha Basavapatna * This function handles raw pkt data messages received over the channel.
53147bd3a2e2SSriharsha Basavapatna * Currently, only priority-eth-type frames are received through this mechanism.
53157bd3a2e2SSriharsha Basavapatna * In this case, the frame(data) is present within the message itself which
53167bd3a2e2SSriharsha Basavapatna * is copied into an mblk before sending it up the stack.
53177bd3a2e2SSriharsha Basavapatna */
53187bd3a2e2SSriharsha Basavapatna void
vgen_handle_pkt_data(void * arg1,void * arg2,uint32_t msglen)53197bd3a2e2SSriharsha Basavapatna vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen)
53207bd3a2e2SSriharsha Basavapatna {
53217bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1;
53227bd3a2e2SSriharsha Basavapatna vio_raw_data_msg_t *pkt = (vio_raw_data_msg_t *)arg2;
53237bd3a2e2SSriharsha Basavapatna uint32_t size;
53247bd3a2e2SSriharsha Basavapatna mblk_t *mp;
53257bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp;
53267bd3a2e2SSriharsha Basavapatna vio_net_rx_cb_t vrx_cb = NULL;
53277bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp);
53287bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->stats;
53297bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
53307bd3a2e2SSriharsha Basavapatna uint_t dring_mode = lp->dring_mode;
53317bd3a2e2SSriharsha Basavapatna
53327bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock));
53337bd3a2e2SSriharsha Basavapatna
53347bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
53357bd3a2e2SSriharsha Basavapatna
53367bd3a2e2SSriharsha Basavapatna size = msglen - VIO_PKT_DATA_HDRSIZE;
53377bd3a2e2SSriharsha Basavapatna if (size < ETHERMIN || size > lp->mtu) {
53387bd3a2e2SSriharsha Basavapatna (void) atomic_inc_32(&statsp->rx_pri_fail);
53397bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
53407bd3a2e2SSriharsha Basavapatna return;
53417bd3a2e2SSriharsha Basavapatna }
53427bd3a2e2SSriharsha Basavapatna
53437bd3a2e2SSriharsha Basavapatna vmp = vio_multipool_allocb(&ldcp->vmp, size);
53447bd3a2e2SSriharsha Basavapatna if (vmp == NULL) {
53457bd3a2e2SSriharsha Basavapatna mp = allocb(size, BPRI_MED);
53467bd3a2e2SSriharsha Basavapatna if (mp == NULL) {
53477bd3a2e2SSriharsha Basavapatna (void) atomic_inc_32(&statsp->rx_pri_fail);
53487bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "allocb failure, "
53497bd3a2e2SSriharsha Basavapatna "unable to process priority frame\n");
53507bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
53517bd3a2e2SSriharsha Basavapatna return;
53527bd3a2e2SSriharsha Basavapatna }
53537bd3a2e2SSriharsha Basavapatna } else {
53547bd3a2e2SSriharsha Basavapatna mp = vmp->mp;
53557bd3a2e2SSriharsha Basavapatna }
53567bd3a2e2SSriharsha Basavapatna
53577bd3a2e2SSriharsha Basavapatna /* copy the frame from the payload of raw data msg into the mblk */
53587bd3a2e2SSriharsha Basavapatna bcopy(pkt->data, mp->b_rptr, size);
53597bd3a2e2SSriharsha Basavapatna mp->b_wptr = mp->b_rptr + size;
53607bd3a2e2SSriharsha Basavapatna
53617bd3a2e2SSriharsha Basavapatna if (vmp != NULL) {
53627bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA;
53637bd3a2e2SSriharsha Basavapatna }
53647bd3a2e2SSriharsha Basavapatna
53657bd3a2e2SSriharsha Basavapatna /* update stats */
53667bd3a2e2SSriharsha Basavapatna (void) atomic_inc_64(&statsp->rx_pri_packets);
53677bd3a2e2SSriharsha Basavapatna (void) atomic_add_64(&statsp->rx_pri_bytes, size);
53687bd3a2e2SSriharsha Basavapatna
53697bd3a2e2SSriharsha Basavapatna /*
53707bd3a2e2SSriharsha Basavapatna * If polling is currently enabled, add the packet to the priority
53717bd3a2e2SSriharsha Basavapatna * packets list and return. It will be picked up by the polling thread.
53727bd3a2e2SSriharsha Basavapatna */
53737bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_RX_DRING_DATA) {
53747bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock);
53757bd3a2e2SSriharsha Basavapatna } else {
53767bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock);
53777bd3a2e2SSriharsha Basavapatna }
53787bd3a2e2SSriharsha Basavapatna
53797bd3a2e2SSriharsha Basavapatna if (ldcp->polling_on == B_TRUE) {
53807bd3a2e2SSriharsha Basavapatna if (ldcp->rx_pri_tail != NULL) {
53817bd3a2e2SSriharsha Basavapatna ldcp->rx_pri_tail->b_next = mp;
53827bd3a2e2SSriharsha Basavapatna } else {
53837bd3a2e2SSriharsha Basavapatna ldcp->rx_pri_head = ldcp->rx_pri_tail = mp;
53847bd3a2e2SSriharsha Basavapatna }
53857bd3a2e2SSriharsha Basavapatna } else {
53867bd3a2e2SSriharsha Basavapatna vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
53877bd3a2e2SSriharsha Basavapatna }
53887bd3a2e2SSriharsha Basavapatna
53897bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_RX_DRING_DATA) {
53907bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock);
53917bd3a2e2SSriharsha Basavapatna } else {
53927bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock);
53937bd3a2e2SSriharsha Basavapatna }
53947bd3a2e2SSriharsha Basavapatna
53957bd3a2e2SSriharsha Basavapatna if (vrx_cb != NULL) {
53967bd3a2e2SSriharsha Basavapatna vrx_cb(ldcp->portp->vhp, mp);
53977bd3a2e2SSriharsha Basavapatna }
53987bd3a2e2SSriharsha Basavapatna
53997bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
54007bd3a2e2SSriharsha Basavapatna }
54017bd3a2e2SSriharsha Basavapatna
54027bd3a2e2SSriharsha Basavapatna /*
54037bd3a2e2SSriharsha Basavapatna * dummy pkt data handler function for vnet protocol version 1.0
54047bd3a2e2SSriharsha Basavapatna */
54057bd3a2e2SSriharsha Basavapatna static void
vgen_handle_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)54067bd3a2e2SSriharsha Basavapatna vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
54077bd3a2e2SSriharsha Basavapatna {
54087bd3a2e2SSriharsha Basavapatna _NOTE(ARGUNUSED(arg1, arg2, msglen))
54097bd3a2e2SSriharsha Basavapatna }
54107bd3a2e2SSriharsha Basavapatna
54111ae08745Sheppo /* handler for data messages received from the peer ldc end-point */
54123af08d82Slm66018 static int
vgen_handle_datamsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp,uint32_t msglen)5413f0ca1d9aSsb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen)
54141ae08745Sheppo {
54153af08d82Slm66018 int rv = 0;
5416844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
54177bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
54181ae08745Sheppo
5419844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n");
54201ae08745Sheppo
54217bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_DONE) {
54227bd3a2e2SSriharsha Basavapatna return (0);
54237bd3a2e2SSriharsha Basavapatna }
5424f0ca1d9aSsb155480
54257bd3a2e2SSriharsha Basavapatna /*
54267bd3a2e2SSriharsha Basavapatna * We check the data msg seqnum. This is needed only in TxDring mode.
54277bd3a2e2SSriharsha Basavapatna */
54287bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING &&
54297bd3a2e2SSriharsha Basavapatna tagp->vio_subtype == VIO_SUBTYPE_INFO) {
5430f0ca1d9aSsb155480 rv = vgen_check_datamsg_seq(ldcp, tagp);
5431f0ca1d9aSsb155480 if (rv != 0) {
5432f0ca1d9aSsb155480 return (rv);
5433f0ca1d9aSsb155480 }
5434f0ca1d9aSsb155480 }
5435f0ca1d9aSsb155480
54361ae08745Sheppo switch (tagp->vio_subtype_env) {
54371ae08745Sheppo case VIO_DRING_DATA:
54387bd3a2e2SSriharsha Basavapatna rv = ldcp->rx_dringdata((void *)ldcp, (void *)tagp);
54391ae08745Sheppo break;
5440f0ca1d9aSsb155480
5441f0ca1d9aSsb155480 case VIO_PKT_DATA:
5442f0ca1d9aSsb155480 ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen);
5443f0ca1d9aSsb155480 break;
54441ae08745Sheppo default:
54451ae08745Sheppo break;
54461ae08745Sheppo }
54471ae08745Sheppo
5448844e62a3Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
54493af08d82Slm66018 return (rv);
54501ae08745Sheppo }
54511ae08745Sheppo
54527bd3a2e2SSriharsha Basavapatna
54537bd3a2e2SSriharsha Basavapatna static int
vgen_ldc_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)54547bd3a2e2SSriharsha Basavapatna vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
5455f0ca1d9aSsb155480 {
54567bd3a2e2SSriharsha Basavapatna int rv;
54577bd3a2e2SSriharsha Basavapatna
54587bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
54597bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock));
5460f0ca1d9aSsb155480 }
5461f0ca1d9aSsb155480
54627bd3a2e2SSriharsha Basavapatna /* Set the flag to indicate reset is in progress */
54637bd3a2e2SSriharsha Basavapatna if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
54647bd3a2e2SSriharsha Basavapatna /* another thread is already in the process of resetting */
54657bd3a2e2SSriharsha Basavapatna return (EBUSY);
54667bd3a2e2SSriharsha Basavapatna }
54677bd3a2e2SSriharsha Basavapatna
54687bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
54697bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
54707bd3a2e2SSriharsha Basavapatna }
54717bd3a2e2SSriharsha Basavapatna
54727bd3a2e2SSriharsha Basavapatna rv = vgen_process_reset(ldcp, VGEN_FLAG_NEED_LDCRESET);
54737bd3a2e2SSriharsha Basavapatna
54747bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
54757bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
54767bd3a2e2SSriharsha Basavapatna }
54777bd3a2e2SSriharsha Basavapatna
54787bd3a2e2SSriharsha Basavapatna return (rv);
54797bd3a2e2SSriharsha Basavapatna }
54807bd3a2e2SSriharsha Basavapatna
5481f0ca1d9aSsb155480 static void
vgen_ldc_up(vgen_ldc_t * ldcp)54827bd3a2e2SSriharsha Basavapatna vgen_ldc_up(vgen_ldc_t *ldcp)
5483f0ca1d9aSsb155480 {
54847bd3a2e2SSriharsha Basavapatna int rv;
54857bd3a2e2SSriharsha Basavapatna uint32_t retries = 0;
5486f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5487f0ca1d9aSsb155480
5488f0ca1d9aSsb155480 ASSERT(MUTEX_HELD(&ldcp->cblock));
5489f0ca1d9aSsb155480
54901ae08745Sheppo /*
54917bd3a2e2SSriharsha Basavapatna * If the channel has been reset max # of times, without successfully
54927bd3a2e2SSriharsha Basavapatna * completing handshake, stop and do not bring the channel up.
5493844e62a3Sraghuram */
54947bd3a2e2SSriharsha Basavapatna if (ldcp->ldc_reset_count == vgen_ldc_max_resets) {
54957bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "!vnet%d: exceeded number of permitted"
54967bd3a2e2SSriharsha Basavapatna " handshake attempts (%d) on channel %ld",
54977bd3a2e2SSriharsha Basavapatna vgenp->instance, vgen_ldc_max_resets, ldcp->ldc_id);
54987bd3a2e2SSriharsha Basavapatna return;
5499844e62a3Sraghuram }
55007bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count++;
55017bd3a2e2SSriharsha Basavapatna
55027bd3a2e2SSriharsha Basavapatna do {
55037bd3a2e2SSriharsha Basavapatna rv = ldc_up(ldcp->ldc_handle);
55047bd3a2e2SSriharsha Basavapatna if ((rv != 0) && (rv == EWOULDBLOCK)) {
55057bd3a2e2SSriharsha Basavapatna drv_usecwait(VGEN_LDC_UP_DELAY);
55067bd3a2e2SSriharsha Basavapatna }
55077bd3a2e2SSriharsha Basavapatna if (retries++ >= vgen_ldcup_retries)
55087bd3a2e2SSriharsha Basavapatna break;
55097bd3a2e2SSriharsha Basavapatna } while (rv == EWOULDBLOCK);
55107bd3a2e2SSriharsha Basavapatna
55117bd3a2e2SSriharsha Basavapatna if (rv != 0) {
55127bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
55137bd3a2e2SSriharsha Basavapatna }
5514844e62a3Sraghuram }
5515844e62a3Sraghuram
55167bd3a2e2SSriharsha Basavapatna int
vgen_enable_intr(void * arg)55177bd3a2e2SSriharsha Basavapatna vgen_enable_intr(void *arg)
5518844e62a3Sraghuram {
55197bd3a2e2SSriharsha Basavapatna uint32_t end_ix;
55207bd3a2e2SSriharsha Basavapatna vio_dring_msg_t msg;
55217bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg;
55227bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp;
55237b1f684aSSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
5524844e62a3Sraghuram
55257bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
55267bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock);
5527844e62a3Sraghuram
55287bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_FALSE;
55291ae08745Sheppo /*
55307bd3a2e2SSriharsha Basavapatna * We send a stopped message to peer (sender) as we are turning
55317bd3a2e2SSriharsha Basavapatna * off polled mode. This effectively restarts data interrupts
55327bd3a2e2SSriharsha Basavapatna * by allowing the peer to send further dring data msgs to us.
55331ae08745Sheppo */
55347bd3a2e2SSriharsha Basavapatna end_ix = ldcp->next_rxi;
55357bd3a2e2SSriharsha Basavapatna DECR_RXI(end_ix, ldcp);
55367bd3a2e2SSriharsha Basavapatna msg.dring_ident = ldcp->peer_hparams.dring_ident;
55377bd3a2e2SSriharsha Basavapatna (void) vgen_send_dringack_shm(ldcp, (vio_msg_tag_t *)&msg,
55387bd3a2e2SSriharsha Basavapatna VNET_START_IDX_UNSPEC, end_ix, VIO_DP_STOPPED);
5539d10e4ef2Snarayan
55407bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock);
55411ae08745Sheppo } else {
55427bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock);
55437bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_FALSE;
55447bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock);
55451ae08745Sheppo }
55461ae08745Sheppo
55477bd3a2e2SSriharsha Basavapatna return (0);
55483af08d82Slm66018 }
5549d10e4ef2Snarayan
55507bd3a2e2SSriharsha Basavapatna int
vgen_disable_intr(void * arg)55517bd3a2e2SSriharsha Basavapatna vgen_disable_intr(void *arg)
5552844e62a3Sraghuram {
55537bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg;
55547bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp;
55557bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
5556844e62a3Sraghuram
55577bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
55587bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock);
55597bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_TRUE;
55607bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock);
5561d10e4ef2Snarayan } else {
55627bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock);
55637bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_TRUE;
55647bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock);
5565d10e4ef2Snarayan }
5566d10e4ef2Snarayan
55677bd3a2e2SSriharsha Basavapatna return (0);
5568844e62a3Sraghuram }
5569844e62a3Sraghuram
55707bd3a2e2SSriharsha Basavapatna mblk_t *
vgen_rx_poll(void * arg,int bytes_to_pickup)55717bd3a2e2SSriharsha Basavapatna vgen_rx_poll(void *arg, int bytes_to_pickup)
55727bd3a2e2SSriharsha Basavapatna {
55737bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg;
55747bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp;
55757bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams;
55767bd3a2e2SSriharsha Basavapatna mblk_t *mp = NULL;
55777bd3a2e2SSriharsha Basavapatna
55787bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
55797bd3a2e2SSriharsha Basavapatna mp = vgen_poll_rcv_shm(ldcp, bytes_to_pickup);
5580d10e4ef2Snarayan } else {
55817bd3a2e2SSriharsha Basavapatna mp = vgen_poll_rcv(ldcp, bytes_to_pickup);
5582d10e4ef2Snarayan }
5583d10e4ef2Snarayan
55847bd3a2e2SSriharsha Basavapatna return (mp);
55851ae08745Sheppo }
55861ae08745Sheppo
55871ae08745Sheppo /* transmit watchdog timeout handler */
55881ae08745Sheppo static void
vgen_tx_watchdog(void * arg)55897bd3a2e2SSriharsha Basavapatna vgen_tx_watchdog(void *arg)
55901ae08745Sheppo {
55911ae08745Sheppo vgen_ldc_t *ldcp;
5592d10e4ef2Snarayan vgen_t *vgenp;
55931ae08745Sheppo int rv;
55947bd3a2e2SSriharsha Basavapatna boolean_t tx_blocked;
55957bd3a2e2SSriharsha Basavapatna clock_t tx_blocked_lbolt;
55961ae08745Sheppo
55971ae08745Sheppo ldcp = (vgen_ldc_t *)arg;
5598d10e4ef2Snarayan vgenp = LDC_TO_VGEN(ldcp);
55991ae08745Sheppo
56007bd3a2e2SSriharsha Basavapatna tx_blocked = ldcp->tx_blocked;
56017bd3a2e2SSriharsha Basavapatna tx_blocked_lbolt = ldcp->tx_blocked_lbolt;
56027bd3a2e2SSriharsha Basavapatna
56037bd3a2e2SSriharsha Basavapatna if (vgen_txwd_timeout &&
56047bd3a2e2SSriharsha Basavapatna (tx_blocked == B_TRUE) &&
56057bd3a2e2SSriharsha Basavapatna ((ddi_get_lbolt() - tx_blocked_lbolt) >
56067bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_timeout * 1000))) {
56077bd3a2e2SSriharsha Basavapatna /*
56087bd3a2e2SSriharsha Basavapatna * Something is wrong; the peer is not picking up the packets
56097bd3a2e2SSriharsha Basavapatna * in the transmit dring. We now go ahead and reset the channel
56107bd3a2e2SSriharsha Basavapatna * to break out of this condition.
56117bd3a2e2SSriharsha Basavapatna */
56127bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "transmit timeout lbolt(%lx), "
56137bd3a2e2SSriharsha Basavapatna "tx_blocked_lbolt(%lx)\n",
56147bd3a2e2SSriharsha Basavapatna ddi_get_lbolt(), tx_blocked_lbolt);
56157bd3a2e2SSriharsha Basavapatna
56161ae08745Sheppo #ifdef DEBUG
56177bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_TXTIMEOUT)) {
56181ae08745Sheppo /* tx timeout triggered for debugging */
56197bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_TXTIMEOUT);
56201ae08745Sheppo }
56211ae08745Sheppo #endif
56227bd3a2e2SSriharsha Basavapatna
56237bd3a2e2SSriharsha Basavapatna /*
56247bd3a2e2SSriharsha Basavapatna * Clear tid before invoking vgen_ldc_reset(). Otherwise,
56257bd3a2e2SSriharsha Basavapatna * it will result in a deadlock when vgen_process_reset() tries
56267bd3a2e2SSriharsha Basavapatna * to untimeout() on seeing a non-zero tid, but it is being
56277bd3a2e2SSriharsha Basavapatna * invoked by the timer itself in this case.
56287bd3a2e2SSriharsha Basavapatna */
56291ae08745Sheppo mutex_enter(&ldcp->cblock);
56307bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid == 0) {
56317bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */
56321ae08745Sheppo mutex_exit(&ldcp->cblock);
56337bd3a2e2SSriharsha Basavapatna return;
56347bd3a2e2SSriharsha Basavapatna }
56357bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = 0;
56367bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
56377bd3a2e2SSriharsha Basavapatna
56387bd3a2e2SSriharsha Basavapatna /*
56397bd3a2e2SSriharsha Basavapatna * Now reset the channel.
56407bd3a2e2SSriharsha Basavapatna */
56417bd3a2e2SSriharsha Basavapatna rv = vgen_ldc_reset(ldcp, VGEN_OTHER);
56427bd3a2e2SSriharsha Basavapatna if (rv == 0) {
56437bd3a2e2SSriharsha Basavapatna /*
56447bd3a2e2SSriharsha Basavapatna * We have successfully reset the channel. If we are
56457bd3a2e2SSriharsha Basavapatna * in tx flow controlled state, clear it now and enable
56467bd3a2e2SSriharsha Basavapatna * transmit in the upper layer.
56477bd3a2e2SSriharsha Basavapatna */
56487bd3a2e2SSriharsha Basavapatna if (ldcp->tx_blocked) {
5649678453a8Sspeer vio_net_tx_update_t vtx_update =
5650678453a8Sspeer ldcp->portp->vcb.vio_net_tx_update;
5651678453a8Sspeer
56527bd3a2e2SSriharsha Basavapatna ldcp->tx_blocked = B_FALSE;
5653678453a8Sspeer vtx_update(ldcp->portp->vhp);
56541ae08745Sheppo }
56551ae08745Sheppo }
56561ae08745Sheppo
56577bd3a2e2SSriharsha Basavapatna /*
56587bd3a2e2SSriharsha Basavapatna * Channel has been reset by us or some other thread is already
56597bd3a2e2SSriharsha Basavapatna * in the process of resetting. In either case, we return
56607bd3a2e2SSriharsha Basavapatna * without restarting the timer. When handshake completes and
56617bd3a2e2SSriharsha Basavapatna * the channel is ready for data transmit/receive we start a
56627bd3a2e2SSriharsha Basavapatna * new watchdog timer.
56637bd3a2e2SSriharsha Basavapatna */
56647bd3a2e2SSriharsha Basavapatna return;
56651ae08745Sheppo }
56661ae08745Sheppo
56677bd3a2e2SSriharsha Basavapatna restart_timer:
56687bd3a2e2SSriharsha Basavapatna /* Restart the timer */
56697bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
56707bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid == 0) {
56717bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */
56727bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
56737bd3a2e2SSriharsha Basavapatna return;
56747bd3a2e2SSriharsha Basavapatna }
56757bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
56767bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_interval * 1000));
56777bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
56787bd3a2e2SSriharsha Basavapatna }
56797bd3a2e2SSriharsha Basavapatna
56807bd3a2e2SSriharsha Basavapatna /* Handshake watchdog timeout handler */
56811ae08745Sheppo static void
vgen_hwatchdog(void * arg)56827bd3a2e2SSriharsha Basavapatna vgen_hwatchdog(void *arg)
56831ae08745Sheppo {
56847bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
5685f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5686f0ca1d9aSsb155480
56877bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "handshake timeout phase(%x) state(%x)\n",
56887bd3a2e2SSriharsha Basavapatna ldcp->hphase, ldcp->hstate);
56897bd3a2e2SSriharsha Basavapatna
56907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
56917bd3a2e2SSriharsha Basavapatna if (ldcp->htid == 0) {
56927bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */
56937bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
56947bd3a2e2SSriharsha Basavapatna return;
5695f0ca1d9aSsb155480 }
56967bd3a2e2SSriharsha Basavapatna ldcp->htid = 0;
56977bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
5698f0ca1d9aSsb155480
56997bd3a2e2SSriharsha Basavapatna /*
57007bd3a2e2SSriharsha Basavapatna * Something is wrong; handshake with the peer seems to be hung. We now
57017bd3a2e2SSriharsha Basavapatna * go ahead and reset the channel to break out of this condition.
57027bd3a2e2SSriharsha Basavapatna */
57037bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, VGEN_OTHER);
5704f0ca1d9aSsb155480 }
5705f0ca1d9aSsb155480
57061ae08745Sheppo /* Check if the session id in the received message is valid */
57071ae08745Sheppo static int
vgen_check_sid(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)57081ae08745Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
57091ae08745Sheppo {
5710844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5711844e62a3Sraghuram
57121ae08745Sheppo if (tagp->vio_sid != ldcp->peer_sid) {
5713844e62a3Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
5714844e62a3Sraghuram ldcp->peer_sid, tagp->vio_sid);
57151ae08745Sheppo return (VGEN_FAILURE);
57161ae08745Sheppo }
57171ae08745Sheppo else
57181ae08745Sheppo return (VGEN_SUCCESS);
57191ae08745Sheppo }
57201ae08745Sheppo
5721844e62a3Sraghuram /*
57227bd3a2e2SSriharsha Basavapatna * Initialize the common part of dring registration
57237bd3a2e2SSriharsha Basavapatna * message; used in both TxDring and RxDringData modes.
5724844e62a3Sraghuram */
5725844e62a3Sraghuram static void
vgen_init_dring_reg_msg(vgen_ldc_t * ldcp,vio_dring_reg_msg_t * msg,uint8_t option)57267bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
57277bd3a2e2SSriharsha Basavapatna uint8_t option)
5728844e62a3Sraghuram {
57297bd3a2e2SSriharsha Basavapatna vio_msg_tag_t *tagp;
5730844e62a3Sraghuram
57317bd3a2e2SSriharsha Basavapatna tagp = &msg->tag;
57327bd3a2e2SSriharsha Basavapatna tagp->vio_msgtype = VIO_TYPE_CTRL;
57337bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_INFO;
57347bd3a2e2SSriharsha Basavapatna tagp->vio_subtype_env = VIO_DRING_REG;
57357bd3a2e2SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid;
573663f531d1SSriharsha Basavapatna
57377bd3a2e2SSriharsha Basavapatna /* get dring info msg payload from ldcp->local */
57387bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->local_hparams.dring_cookie), &(msg->cookie[0]),
57397bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t));
57407bd3a2e2SSriharsha Basavapatna msg->ncookies = ldcp->local_hparams.dring_ncookies;
57417bd3a2e2SSriharsha Basavapatna msg->num_descriptors = ldcp->local_hparams.num_desc;
57427bd3a2e2SSriharsha Basavapatna msg->descriptor_size = ldcp->local_hparams.desc_size;
574363f531d1SSriharsha Basavapatna
57447bd3a2e2SSriharsha Basavapatna msg->options = option;
574563f531d1SSriharsha Basavapatna
574663f531d1SSriharsha Basavapatna /*
57477bd3a2e2SSriharsha Basavapatna * dring_ident is set to 0. After mapping the dring, peer sets this
57487bd3a2e2SSriharsha Basavapatna * value and sends it in the ack, which is saved in
57497bd3a2e2SSriharsha Basavapatna * vgen_handle_dring_reg().
575063f531d1SSriharsha Basavapatna */
57517bd3a2e2SSriharsha Basavapatna msg->dring_ident = 0;
575263f531d1SSriharsha Basavapatna }
575363f531d1SSriharsha Basavapatna
5754*34f94fbcSWENTAO YANG static int
vgen_mapin_avail(vgen_ldc_t * ldcp)5755*34f94fbcSWENTAO YANG vgen_mapin_avail(vgen_ldc_t *ldcp)
5756*34f94fbcSWENTAO YANG {
5757*34f94fbcSWENTAO YANG int rv;
5758*34f94fbcSWENTAO YANG ldc_info_t info;
5759*34f94fbcSWENTAO YANG uint64_t mapin_sz_req;
5760*34f94fbcSWENTAO YANG uint64_t dblk_sz;
5761*34f94fbcSWENTAO YANG vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5762*34f94fbcSWENTAO YANG
5763*34f94fbcSWENTAO YANG rv = ldc_info(ldcp->ldc_handle, &info);
5764*34f94fbcSWENTAO YANG if (rv != 0) {
5765*34f94fbcSWENTAO YANG return (B_FALSE);
5766*34f94fbcSWENTAO YANG }
5767*34f94fbcSWENTAO YANG
5768*34f94fbcSWENTAO YANG dblk_sz = RXDRING_DBLK_SZ(vgenp->max_frame_size);
5769*34f94fbcSWENTAO YANG mapin_sz_req = (VGEN_RXDRING_NRBUFS * dblk_sz);
5770*34f94fbcSWENTAO YANG
5771*34f94fbcSWENTAO YANG if (info.direct_map_size_max >= mapin_sz_req) {
5772*34f94fbcSWENTAO YANG return (B_TRUE);
5773*34f94fbcSWENTAO YANG }
5774*34f94fbcSWENTAO YANG
5775*34f94fbcSWENTAO YANG return (B_FALSE);
5776*34f94fbcSWENTAO YANG }
5777*34f94fbcSWENTAO YANG
5778844e62a3Sraghuram #if DEBUG
5779844e62a3Sraghuram
5780844e62a3Sraghuram /*
5781844e62a3Sraghuram * Print debug messages - set to 0xf to enable all msgs
5782844e62a3Sraghuram */
57837bd3a2e2SSriharsha Basavapatna void
vgen_debug_printf(const char * fname,vgen_t * vgenp,vgen_ldc_t * ldcp,const char * fmt,...)57847bd3a2e2SSriharsha Basavapatna vgen_debug_printf(const char *fname, vgen_t *vgenp,
5785844e62a3Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...)
5786844e62a3Sraghuram {
5787844e62a3Sraghuram char buf[256];
5788844e62a3Sraghuram char *bufp = buf;
5789844e62a3Sraghuram va_list ap;
5790844e62a3Sraghuram
5791844e62a3Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) {
5792844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:",
5793844e62a3Sraghuram ((vnet_t *)(vgenp->vnetp))->instance);
5794844e62a3Sraghuram bufp += strlen(bufp);
5795844e62a3Sraghuram }
5796844e62a3Sraghuram if (ldcp != NULL) {
5797844e62a3Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id);
5798844e62a3Sraghuram bufp += strlen(bufp);
5799844e62a3Sraghuram }
5800844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname);
5801844e62a3Sraghuram bufp += strlen(bufp);
5802844e62a3Sraghuram
5803844e62a3Sraghuram va_start(ap, fmt);
5804844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap);
5805844e62a3Sraghuram va_end(ap);
5806844e62a3Sraghuram
5807844e62a3Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) ||
5808844e62a3Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) {
5809844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf);
5810844e62a3Sraghuram }
5811844e62a3Sraghuram }
5812844e62a3Sraghuram #endif
58131107ea93SSriharsha Basavapatna
58141107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG
58151107ea93SSriharsha Basavapatna
58161107ea93SSriharsha Basavapatna static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)58171107ea93SSriharsha Basavapatna vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
58181107ea93SSriharsha Basavapatna {
58191107ea93SSriharsha Basavapatna struct iocblk *iocp;
58201107ea93SSriharsha Basavapatna vgen_port_t *portp;
58211107ea93SSriharsha Basavapatna enum ioc_reply {
58221107ea93SSriharsha Basavapatna IOC_INVAL = -1, /* bad, NAK with EINVAL */
58231107ea93SSriharsha Basavapatna IOC_ACK /* OK, just send ACK */
58241107ea93SSriharsha Basavapatna } status;
58251107ea93SSriharsha Basavapatna int rv;
58261107ea93SSriharsha Basavapatna
58271107ea93SSriharsha Basavapatna iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
58281107ea93SSriharsha Basavapatna iocp->ioc_error = 0;
58291107ea93SSriharsha Basavapatna portp = (vgen_port_t *)arg;
58301107ea93SSriharsha Basavapatna
58311107ea93SSriharsha Basavapatna if (portp == NULL) {
58321107ea93SSriharsha Basavapatna status = IOC_INVAL;
58331107ea93SSriharsha Basavapatna goto vgen_ioc_exit;
58341107ea93SSriharsha Basavapatna }
58351107ea93SSriharsha Basavapatna
58361107ea93SSriharsha Basavapatna mutex_enter(&portp->lock);
58371107ea93SSriharsha Basavapatna
58381107ea93SSriharsha Basavapatna switch (iocp->ioc_cmd) {
58391107ea93SSriharsha Basavapatna
58401107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_DOWN:
58411107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_UP:
58421107ea93SSriharsha Basavapatna rv = vgen_force_link_state(portp, iocp->ioc_cmd);
58431107ea93SSriharsha Basavapatna (rv == 0) ? (status = IOC_ACK) : (status = IOC_INVAL);
58441107ea93SSriharsha Basavapatna break;
58451107ea93SSriharsha Basavapatna
58461107ea93SSriharsha Basavapatna default:
58471107ea93SSriharsha Basavapatna status = IOC_INVAL;
58481107ea93SSriharsha Basavapatna break;
58491107ea93SSriharsha Basavapatna
58501107ea93SSriharsha Basavapatna }
58511107ea93SSriharsha Basavapatna
58521107ea93SSriharsha Basavapatna mutex_exit(&portp->lock);
58531107ea93SSriharsha Basavapatna
58541107ea93SSriharsha Basavapatna vgen_ioc_exit:
58551107ea93SSriharsha Basavapatna
58561107ea93SSriharsha Basavapatna switch (status) {
58571107ea93SSriharsha Basavapatna default:
58581107ea93SSriharsha Basavapatna case IOC_INVAL:
58591107ea93SSriharsha Basavapatna /* Error, reply with a NAK and EINVAL error */
58601107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL);
58611107ea93SSriharsha Basavapatna break;
58621107ea93SSriharsha Basavapatna case IOC_ACK:
58631107ea93SSriharsha Basavapatna /* OK, reply with an ACK */
58641107ea93SSriharsha Basavapatna miocack(q, mp, 0, 0);
58651107ea93SSriharsha Basavapatna break;
58661107ea93SSriharsha Basavapatna }
58671107ea93SSriharsha Basavapatna }
58681107ea93SSriharsha Basavapatna
58691107ea93SSriharsha Basavapatna static int
vgen_force_link_state(vgen_port_t * portp,int cmd)58701107ea93SSriharsha Basavapatna vgen_force_link_state(vgen_port_t *portp, int cmd)
58711107ea93SSriharsha Basavapatna {
58721107ea93SSriharsha Basavapatna ldc_status_t istatus;
58731107ea93SSriharsha Basavapatna int rv;
58747bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp;
58757bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = portp->vgenp;
58761107ea93SSriharsha Basavapatna
58771107ea93SSriharsha Basavapatna mutex_enter(&ldcp->cblock);
58781107ea93SSriharsha Basavapatna
58791107ea93SSriharsha Basavapatna switch (cmd) {
58801107ea93SSriharsha Basavapatna
58811107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_DOWN:
58821107ea93SSriharsha Basavapatna (void) ldc_down(ldcp->ldc_handle);
58831107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_TRUE;
58841107ea93SSriharsha Basavapatna break;
58851107ea93SSriharsha Basavapatna
58861107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_UP:
58877bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp);
58881107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_FALSE;
58891107ea93SSriharsha Basavapatna
58901107ea93SSriharsha Basavapatna if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
58911107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_status err\n");
58921107ea93SSriharsha Basavapatna } else {
58931107ea93SSriharsha Basavapatna ldcp->ldc_status = istatus;
58941107ea93SSriharsha Basavapatna }
58951107ea93SSriharsha Basavapatna
58961107ea93SSriharsha Basavapatna /* if channel is already UP - restart handshake */
58971107ea93SSriharsha Basavapatna if (ldcp->ldc_status == LDC_UP) {
58981107ea93SSriharsha Basavapatna vgen_handle_evt_up(ldcp);
58991107ea93SSriharsha Basavapatna }
59001107ea93SSriharsha Basavapatna break;
59011107ea93SSriharsha Basavapatna
59021107ea93SSriharsha Basavapatna }
59031107ea93SSriharsha Basavapatna
59041107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock);
59051107ea93SSriharsha Basavapatna
59061107ea93SSriharsha Basavapatna return (0);
59071107ea93SSriharsha Basavapatna }
59081107ea93SSriharsha Basavapatna
59091107ea93SSriharsha Basavapatna #else
59101107ea93SSriharsha Basavapatna
59111107ea93SSriharsha Basavapatna static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)59121107ea93SSriharsha Basavapatna vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
59131107ea93SSriharsha Basavapatna {
59141107ea93SSriharsha Basavapatna vgen_port_t *portp;
59151107ea93SSriharsha Basavapatna
59161107ea93SSriharsha Basavapatna portp = (vgen_port_t *)arg;
59171107ea93SSriharsha Basavapatna
59181107ea93SSriharsha Basavapatna if (portp == NULL) {
59191107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL);
59201107ea93SSriharsha Basavapatna return;
59211107ea93SSriharsha Basavapatna }
59221107ea93SSriharsha Basavapatna
59231107ea93SSriharsha Basavapatna miocnak(q, mp, 0, ENOTSUP);
59241107ea93SSriharsha Basavapatna }
59251107ea93SSriharsha Basavapatna
59261107ea93SSriharsha Basavapatna #endif
5927