xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_gen.c (revision 13098:496fd9979cfc)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
2312300SSriharsha.Basavapatna@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241991Sheppo  */
251991Sheppo 
261991Sheppo #include <sys/types.h>
271991Sheppo #include <sys/errno.h>
287529SSriharsha.Basavapatna@Sun.COM #include <sys/sysmacros.h>
291991Sheppo #include <sys/param.h>
3012011SSriharsha.Basavapatna@Sun.COM #include <sys/machsystm.h>
311991Sheppo #include <sys/stream.h>
324647Sraghuram #include <sys/strsubr.h>
331991Sheppo #include <sys/kmem.h>
341991Sheppo #include <sys/conf.h>
351991Sheppo #include <sys/devops.h>
361991Sheppo #include <sys/ksynch.h>
371991Sheppo #include <sys/stat.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/ddi.h>
421991Sheppo #include <sys/sunddi.h>
431991Sheppo #include <sys/strsun.h>
441991Sheppo #include <sys/note.h>
458275SEric Cheng #include <sys/mac_provider.h>
462311Sseb #include <sys/mac_ether.h>
471991Sheppo #include <sys/ldc.h>
481991Sheppo #include <sys/mach_descrip.h>
491991Sheppo #include <sys/mdeg.h>
504647Sraghuram #include <net/if.h>
514647Sraghuram #include <sys/vnet.h>
521991Sheppo #include <sys/vio_mailbox.h>
531991Sheppo #include <sys/vio_common.h>
541991Sheppo #include <sys/vnet_common.h>
552336Snarayan #include <sys/vnet_mailbox.h>
562336Snarayan #include <sys/vio_util.h>
571991Sheppo #include <sys/vnet_gen.h>
585935Ssb155480 #include <sys/atomic.h>
594647Sraghuram #include <sys/callb.h>
604647Sraghuram #include <sys/sdt.h>
614647Sraghuram #include <sys/intr.h>
624647Sraghuram #include <sys/pattr.h>
636419Ssb155480 #include <sys/vlan.h>
641991Sheppo 
651991Sheppo /*
6612011SSriharsha.Basavapatna@Sun.COM  * Implementation of the mac provider functionality for vnet using the
671991Sheppo  * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
681991Sheppo  */
691991Sheppo 
7012011SSriharsha.Basavapatna@Sun.COM /* Entry Points */
716495Sspeer int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
726495Sspeer     const uint8_t *macaddr, void **vgenhdl);
7310309SSriharsha.Basavapatna@Sun.COM int vgen_init_mdeg(void *arg);
749235SWentao.Yang@Sun.COM void vgen_uninit(void *arg);
756495Sspeer int vgen_dds_tx(void *arg, void *dmsg);
7610309SSriharsha.Basavapatna@Sun.COM int vgen_enable_intr(void *arg);
7710309SSriharsha.Basavapatna@Sun.COM int vgen_disable_intr(void *arg);
7812011SSriharsha.Basavapatna@Sun.COM mblk_t *vgen_rx_poll(void *arg, int bytes_to_pickup);
791991Sheppo static int vgen_start(void *arg);
801991Sheppo static void vgen_stop(void *arg);
811991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
821991Sheppo static int vgen_multicst(void *arg, boolean_t add,
831991Sheppo 	const uint8_t *mca);
841991Sheppo static int vgen_promisc(void *arg, boolean_t on);
851991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
862311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
879336SSriharsha.Basavapatna@Sun.COM static void vgen_ioctl(void *arg, queue_t *q, mblk_t *mp);
889336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
899336SSriharsha.Basavapatna@Sun.COM static int vgen_force_link_state(vgen_port_t *portp, int link_state);
909336SSriharsha.Basavapatna@Sun.COM #endif
911991Sheppo 
9212011SSriharsha.Basavapatna@Sun.COM /* Port/LDC Configuration */
936419Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp);
946419Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
956419Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp,
966419Ssb155480 	mde_cookie_t node);
977529SSriharsha.Basavapatna@Sun.COM static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
987529SSriharsha.Basavapatna@Sun.COM 	uint32_t *mtu);
999336SSriharsha.Basavapatna@Sun.COM static void vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
1009336SSriharsha.Basavapatna@Sun.COM 	boolean_t *pls);
1011991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
1021991Sheppo static void vgen_port_detach(vgen_port_t *portp);
1031991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
1041991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
1051991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1061991Sheppo 	int port_num);
1071991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
1081991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
1091991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1106419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
1111991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1126419Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
1136419Ssb155480 	mde_cookie_t mdex);
1141991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1156419Ssb155480 static int vgen_port_attach(vgen_port_t *portp);
1166419Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp);
1171991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1181991Sheppo 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
1192311Sseb static uint64_t	vgen_port_stat(vgen_port_t *portp, uint_t stat);
1209336SSriharsha.Basavapatna@Sun.COM static void vgen_port_reset(vgen_port_t *portp);
1219336SSriharsha.Basavapatna@Sun.COM static void vgen_reset_vsw_port(vgen_t *vgenp);
12212011SSriharsha.Basavapatna@Sun.COM static int vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
12312011SSriharsha.Basavapatna@Sun.COM static void vgen_ldc_up(vgen_ldc_t *ldcp);
1241991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1251991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1261991Sheppo static void vgen_port_init(vgen_port_t *portp);
1271991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1281991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1291991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
1302311Sseb static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
13112011SSriharsha.Basavapatna@Sun.COM 
13212011SSriharsha.Basavapatna@Sun.COM /* I/O Processing */
1331991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1345935Ssb155480 static int vgen_ldcsend(void *arg, mblk_t *mp);
1355935Ssb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp);
13612011SSriharsha.Basavapatna@Sun.COM static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
13712011SSriharsha.Basavapatna@Sun.COM static void vgen_tx_watchdog(void *arg);
13812011SSriharsha.Basavapatna@Sun.COM 
13912011SSriharsha.Basavapatna@Sun.COM /*  Dring Configuration */
14012011SSriharsha.Basavapatna@Sun.COM static int vgen_create_dring(vgen_ldc_t *ldcp);
14112011SSriharsha.Basavapatna@Sun.COM static void vgen_destroy_dring(vgen_ldc_t *ldcp);
14212011SSriharsha.Basavapatna@Sun.COM static int vgen_map_dring(vgen_ldc_t *ldcp, void *pkt);
14312011SSriharsha.Basavapatna@Sun.COM static void vgen_unmap_dring(vgen_ldc_t *ldcp);
144*13098SWentao.Yang@Sun.COM static int vgen_mapin_avail(vgen_ldc_t *ldcp);
14512011SSriharsha.Basavapatna@Sun.COM 
14612011SSriharsha.Basavapatna@Sun.COM /* VIO Message Processing */
14712011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake(vgen_ldc_t *ldcp);
14812011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_done(vgen_ldc_t *ldcp);
1491991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
15012011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
15112011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_phase3(vgen_ldc_t *ldcp);
15212011SSriharsha.Basavapatna@Sun.COM static void vgen_setup_handshake_params(vgen_ldc_t *ldcp);
1531991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1541991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
15512011SSriharsha.Basavapatna@Sun.COM static int vgen_send_rx_dring_reg(vgen_ldc_t *ldcp);
15612011SSriharsha.Basavapatna@Sun.COM static int vgen_send_tx_dring_reg(vgen_ldc_t *ldcp);
15712011SSriharsha.Basavapatna@Sun.COM static void vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
15812011SSriharsha.Basavapatna@Sun.COM 	uint8_t option);
1591991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
16012011SSriharsha.Basavapatna@Sun.COM static int vgen_send_dringdata(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1611991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1622793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1631991Sheppo 	vio_msg_tag_t *tagp);
16412011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16512011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
16612011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
1672793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16812011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16912011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1702793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1712793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1722793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1735935Ssb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen);
1745935Ssb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1755935Ssb155480 	uint32_t msglen);
1761991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
17712011SSriharsha.Basavapatna@Sun.COM static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1786495Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp);
17912011SSriharsha.Basavapatna@Sun.COM static int vgen_process_reset(vgen_ldc_t *ldcp, int flags);
1801991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1811991Sheppo static void vgen_hwatchdog(void *arg);
1825935Ssb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp);
1835935Ssb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp);
1849336SSriharsha.Basavapatna@Sun.COM static void vgen_link_update(vgen_t *vgenp, link_state_t link_state);
1851991Sheppo 
18612011SSriharsha.Basavapatna@Sun.COM /* VLANs */
1876419Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp,
1886419Ssb155480 	mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp,
1896419Ssb155480 	uint16_t *nvidsp, uint16_t *default_idp);
1906419Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp);
1916419Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp);
1926419Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp);
1936419Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp);
1946419Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
1956419Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp,
1966419Ssb155480 	uint16_t *vidp);
1976419Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp,
1986419Ssb155480 	boolean_t is_tagged, uint16_t vid);
1996419Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp);
2006419Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp);
20112011SSriharsha.Basavapatna@Sun.COM 
20212011SSriharsha.Basavapatna@Sun.COM /* Exported functions */
20312011SSriharsha.Basavapatna@Sun.COM int vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller);
20412011SSriharsha.Basavapatna@Sun.COM int vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
20512011SSriharsha.Basavapatna@Sun.COM void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
20612011SSriharsha.Basavapatna@Sun.COM void vgen_destroy_rxpools(void *arg);
20712011SSriharsha.Basavapatna@Sun.COM 
20812011SSriharsha.Basavapatna@Sun.COM /* Externs */
2096495Sspeer extern void vnet_dds_rx(void *arg, void *dmsg);
2109647SWentao.Yang@Sun.COM extern void vnet_dds_cleanup_hio(vnet_t *vnetp);
2117529SSriharsha.Basavapatna@Sun.COM extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
2129336SSriharsha.Basavapatna@Sun.COM extern void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
21312011SSriharsha.Basavapatna@Sun.COM extern int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
21412011SSriharsha.Basavapatna@Sun.COM     boolean_t caller_holds_lock);
21512011SSriharsha.Basavapatna@Sun.COM extern void vgen_stop_msg_thread(vgen_ldc_t *ldcp);
21612011SSriharsha.Basavapatna@Sun.COM extern int vgen_create_tx_dring(vgen_ldc_t *ldcp);
21712011SSriharsha.Basavapatna@Sun.COM extern void vgen_destroy_tx_dring(vgen_ldc_t *ldcp);
21812011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_rx_dring(vgen_ldc_t *ldcp, void *pkt);
21912011SSriharsha.Basavapatna@Sun.COM extern void vgen_unmap_rx_dring(vgen_ldc_t *ldcp);
22012011SSriharsha.Basavapatna@Sun.COM extern int vgen_create_rx_dring(vgen_ldc_t *ldcp);
22112011SSriharsha.Basavapatna@Sun.COM extern void vgen_destroy_rx_dring(vgen_ldc_t *ldcp);
22212011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt);
22312011SSriharsha.Basavapatna@Sun.COM extern void vgen_unmap_tx_dring(vgen_ldc_t *ldcp);
22412011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_data(vgen_ldc_t *ldcp, void *pkt);
22512011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_dringdata_shm(void *arg1, void *arg2);
22612011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_dringdata(void *arg1, void *arg2);
22712011SSriharsha.Basavapatna@Sun.COM extern int vgen_dringsend_shm(void *arg, mblk_t *mp);
22812011SSriharsha.Basavapatna@Sun.COM extern int vgen_dringsend(void *arg, mblk_t *mp);
22912011SSriharsha.Basavapatna@Sun.COM extern void vgen_ldc_msg_worker(void *arg);
23012011SSriharsha.Basavapatna@Sun.COM extern int vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
23112011SSriharsha.Basavapatna@Sun.COM     uint32_t start, int32_t end, uint8_t pstate);
23212011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup);
23312011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll_rcv(vgen_ldc_t *ldcp, int bytes_to_pickup);
23412011SSriharsha.Basavapatna@Sun.COM extern int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
2351991Sheppo 
2365935Ssb155480 #define	VGEN_PRI_ETH_DEFINED(vgenp)	((vgenp)->pri_num_types != 0)
2375935Ssb155480 
2381991Sheppo #define	LDC_LOCK(ldcp)	\
2391991Sheppo 				mutex_enter(&((ldcp)->cblock));\
2404647Sraghuram 				mutex_enter(&((ldcp)->rxlock));\
2414647Sraghuram 				mutex_enter(&((ldcp)->wrlock));\
2421991Sheppo 				mutex_enter(&((ldcp)->txlock));\
2431991Sheppo 				mutex_enter(&((ldcp)->tclock));
2441991Sheppo #define	LDC_UNLOCK(ldcp)	\
2451991Sheppo 				mutex_exit(&((ldcp)->tclock));\
2461991Sheppo 				mutex_exit(&((ldcp)->txlock));\
2474647Sraghuram 				mutex_exit(&((ldcp)->wrlock));\
2484647Sraghuram 				mutex_exit(&((ldcp)->rxlock));\
2491991Sheppo 				mutex_exit(&((ldcp)->cblock));
2501991Sheppo 
2516419Ssb155480 #define	VGEN_VER_EQ(ldcp, major, minor)	\
2526419Ssb155480 	((ldcp)->local_hparams.ver_major == (major) &&	\
2536419Ssb155480 	    (ldcp)->local_hparams.ver_minor == (minor))
2546419Ssb155480 
2556419Ssb155480 #define	VGEN_VER_LT(ldcp, major, minor)	\
2566419Ssb155480 	(((ldcp)->local_hparams.ver_major < (major)) ||	\
2576419Ssb155480 	    ((ldcp)->local_hparams.ver_major == (major) &&	\
2586419Ssb155480 	    (ldcp)->local_hparams.ver_minor < (minor)))
2596419Ssb155480 
2606419Ssb155480 #define	VGEN_VER_GTEQ(ldcp, major, minor)	\
2616419Ssb155480 	(((ldcp)->local_hparams.ver_major > (major)) ||	\
2626419Ssb155480 	    ((ldcp)->local_hparams.ver_major == (major) &&	\
2636419Ssb155480 	    (ldcp)->local_hparams.ver_minor >= (minor)))
2646419Ssb155480 
2651991Sheppo /*
2661991Sheppo  * Property names
2671991Sheppo  */
2681991Sheppo static char macaddr_propname[] = "mac-address";
2691991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2701991Sheppo static char channel_propname[] = "channel-endpoint";
2711991Sheppo static char reg_propname[] = "reg";
2721991Sheppo static char port_propname[] = "port";
2731991Sheppo static char swport_propname[] = "switch-port";
2741991Sheppo static char id_propname[] = "id";
2755935Ssb155480 static char vdev_propname[] = "virtual-device";
2765935Ssb155480 static char vnet_propname[] = "network";
2775935Ssb155480 static char pri_types_propname[] = "priority-ether-types";
2786419Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id";
2796419Ssb155480 static char vgen_vid_propname[] = "vlan-id";
2806419Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id";
2816419Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id";
2826419Ssb155480 static char port_vid_propname[] = "remote-vlan-id";
2837529SSriharsha.Basavapatna@Sun.COM static char vgen_mtu_propname[] = "mtu";
2849336SSriharsha.Basavapatna@Sun.COM static char vgen_linkprop_propname[] = "linkprop";
2859336SSriharsha.Basavapatna@Sun.COM 
2869336SSriharsha.Basavapatna@Sun.COM /*
2879336SSriharsha.Basavapatna@Sun.COM  * VIO Protocol Version Info:
2889336SSriharsha.Basavapatna@Sun.COM  *
2899336SSriharsha.Basavapatna@Sun.COM  * The version specified below represents the version of protocol currently
2909336SSriharsha.Basavapatna@Sun.COM  * supported in the driver. It means the driver can negotiate with peers with
2919336SSriharsha.Basavapatna@Sun.COM  * versions <= this version. Here is a summary of the feature(s) that are
2929336SSriharsha.Basavapatna@Sun.COM  * supported at each version of the protocol:
2939336SSriharsha.Basavapatna@Sun.COM  *
2949336SSriharsha.Basavapatna@Sun.COM  * 1.0			Basic VIO protocol.
2959336SSriharsha.Basavapatna@Sun.COM  * 1.1			vDisk protocol update (no virtual network update).
2969336SSriharsha.Basavapatna@Sun.COM  * 1.2			Support for priority frames (priority-ether-types).
2979336SSriharsha.Basavapatna@Sun.COM  * 1.3			VLAN and HybridIO support.
2989336SSriharsha.Basavapatna@Sun.COM  * 1.4			Jumbo Frame support.
2999336SSriharsha.Basavapatna@Sun.COM  * 1.5			Link State Notification support with optional support
3009336SSriharsha.Basavapatna@Sun.COM  * 			for Physical Link information.
30112011SSriharsha.Basavapatna@Sun.COM  * 1.6			Support for RxDringData mode.
3029336SSriharsha.Basavapatna@Sun.COM  */
30312011SSriharsha.Basavapatna@Sun.COM static vgen_ver_t vgen_versions[VGEN_NUM_VER] =  { {1, 6} };
3041991Sheppo 
3051991Sheppo /* Tunables */
3065171Ssb155480 uint32_t vgen_hwd_interval = 5;		/* handshake watchdog freq in sec */
3071991Sheppo uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
3082109Slm66018 uint32_t vgen_ldcup_retries = 5;	/* max # of ldc_up() retries */
3098623SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldccl_retries = 5;	/* max # of ldc_close() retries */
3105022Sraghuram uint32_t vgen_tx_delay = 0x30;		/* delay when tx descr not available */
31112011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldc_mtu = VGEN_LDC_MTU;		/* ldc mtu */
31212011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_txwd_interval = VGEN_TXWD_INTERVAL; /* watchdog freq in msec */
31312011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_txwd_timeout = VGEN_TXWD_TIMEOUT;   /* tx timeout in msec */
31412011SSriharsha.Basavapatna@Sun.COM 
31512011SSriharsha.Basavapatna@Sun.COM /*
31612011SSriharsha.Basavapatna@Sun.COM  * Max # of channel resets allowed during handshake.
31712011SSriharsha.Basavapatna@Sun.COM  */
31812011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldc_max_resets = 5;
31912011SSriharsha.Basavapatna@Sun.COM 
32012011SSriharsha.Basavapatna@Sun.COM /*
32112011SSriharsha.Basavapatna@Sun.COM  * See comments in vsw.c for details on the dring modes supported.
32212011SSriharsha.Basavapatna@Sun.COM  * In RxDringData mode, # of buffers is determined by multiplying the # of
32312011SSriharsha.Basavapatna@Sun.COM  * descriptors with the factor below. Note that the factor must be > 1; i.e,
32412011SSriharsha.Basavapatna@Sun.COM  * the # of buffers must always be > # of descriptors. This is needed because,
32512011SSriharsha.Basavapatna@Sun.COM  * while the shared memory buffers are sent up the stack on the receiver, the
32612011SSriharsha.Basavapatna@Sun.COM  * sender needs additional buffers that can be used for further transmits.
32712011SSriharsha.Basavapatna@Sun.COM  * See vgen_create_rx_dring() for details.
32812011SSriharsha.Basavapatna@Sun.COM  */
32912011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs_factor = 2;
33012011SSriharsha.Basavapatna@Sun.COM 
33112011SSriharsha.Basavapatna@Sun.COM /*
33212011SSriharsha.Basavapatna@Sun.COM  * Retry delay used while destroying rx mblk pools. Used in both Dring modes.
33312011SSriharsha.Basavapatna@Sun.COM  */
33412011SSriharsha.Basavapatna@Sun.COM int vgen_rxpool_cleanup_delay = 100000;	/* 100ms */
33512011SSriharsha.Basavapatna@Sun.COM 
33612011SSriharsha.Basavapatna@Sun.COM /*
33712011SSriharsha.Basavapatna@Sun.COM  * Delay when rx descr not ready; used in TxDring mode only.
33812011SSriharsha.Basavapatna@Sun.COM  */
33912011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_recv_delay = 1;
34012011SSriharsha.Basavapatna@Sun.COM 
34112011SSriharsha.Basavapatna@Sun.COM /*
34212011SSriharsha.Basavapatna@Sun.COM  * Retry when rx descr not ready; used in TxDring mode only.
34312011SSriharsha.Basavapatna@Sun.COM  */
34412011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_recv_retries = 10;
34512011SSriharsha.Basavapatna@Sun.COM 
34612011SSriharsha.Basavapatna@Sun.COM /*
34712011SSriharsha.Basavapatna@Sun.COM  * Max # of packets accumulated prior to sending them up. It is best
34812011SSriharsha.Basavapatna@Sun.COM  * to keep this at 60% of the number of receive buffers. Used in TxDring mode
34912011SSriharsha.Basavapatna@Sun.COM  * by the msg worker thread. Used in RxDringData mode while in interrupt mode
35012011SSriharsha.Basavapatna@Sun.COM  * (not used in polled mode).
3514647Sraghuram  */
3524647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6);
3534647Sraghuram 
3544647Sraghuram /*
3557529SSriharsha.Basavapatna@Sun.COM  * Internal tunables for receive buffer pools, that is,  the size and number of
3567529SSriharsha.Basavapatna@Sun.COM  * mblks for each pool. At least 3 sizes must be specified if these are used.
3577529SSriharsha.Basavapatna@Sun.COM  * The sizes must be specified in increasing order. Non-zero value of the first
3587529SSriharsha.Basavapatna@Sun.COM  * size will be used as a hint to use these values instead of the algorithm
35912011SSriharsha.Basavapatna@Sun.COM  * that determines the sizes based on MTU. Used in TxDring mode only.
3604647Sraghuram  */
3617529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz1 = 0;
3627529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz2 = 0;
3637529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz3 = 0;
3647529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz4 = 0;
3654647Sraghuram 
3664647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS;
3674647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS;
3684647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS;
3697529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs4 = VGEN_NRBUFS;
3704647Sraghuram 
3715935Ssb155480 /*
3725935Ssb155480  * In the absence of "priority-ether-types" property in MD, the following
3735935Ssb155480  * internal tunable can be set to specify a single priority ethertype.
3745935Ssb155480  */
3755935Ssb155480 uint64_t vgen_pri_eth_type = 0;
3765935Ssb155480 
3775935Ssb155480 /*
3785935Ssb155480  * Number of transmit priority buffers that are preallocated per device.
3795935Ssb155480  * This number is chosen to be a small value to throttle transmission
3805935Ssb155480  * of priority packets. Note: Must be a power of 2 for vio_create_mblks().
3815935Ssb155480  */
3825935Ssb155480 uint32_t vgen_pri_tx_nmblks = 64;
3835935Ssb155480 
3846419Ssb155480 uint32_t	vgen_vlan_nchains = 4;	/* # of chains in vlan id hash table */
3856419Ssb155480 
3866419Ssb155480 /*
3876419Ssb155480  * Matching criteria passed to the MDEG to register interest
3886419Ssb155480  * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified
3896419Ssb155480  * by their 'name' and 'cfg-handle' properties.
3906419Ssb155480  */
3916419Ssb155480 static md_prop_match_t vdev_prop_match[] = {
3926419Ssb155480 	{ MDET_PROP_STR,    "name"   },
3936419Ssb155480 	{ MDET_PROP_VAL,    "cfg-handle" },
3946419Ssb155480 	{ MDET_LIST_END,    NULL    }
3956419Ssb155480 };
3966419Ssb155480 
3976419Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device",
3986419Ssb155480 						vdev_prop_match };
3996419Ssb155480 
4001991Sheppo /* MD update matching structure */
4011991Sheppo static md_prop_match_t	vport_prop_match[] = {
4021991Sheppo 	{ MDET_PROP_VAL,	"id" },
4031991Sheppo 	{ MDET_LIST_END,	NULL }
4041991Sheppo };
4051991Sheppo 
4061991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
4071991Sheppo 					vport_prop_match };
4081991Sheppo 
40912011SSriharsha.Basavapatna@Sun.COM /* Template for matching a particular vnet instance */
4101991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
4111991Sheppo 	{ MDET_PROP_STR,	"name",		"network" },
4121991Sheppo 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
4131991Sheppo 	{ MDET_LIST_END,	NULL,		NULL }
4141991Sheppo };
4151991Sheppo 
4161991Sheppo #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
4171991Sheppo 
4186419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
4191991Sheppo 
4209336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
4219336SSriharsha.Basavapatna@Sun.COM #define	VGEN_M_CALLBACK_FLAGS	(MC_IOCTL)
4229336SSriharsha.Basavapatna@Sun.COM #else
4239336SSriharsha.Basavapatna@Sun.COM #define	VGEN_M_CALLBACK_FLAGS	(0)
4249336SSriharsha.Basavapatna@Sun.COM #endif
4259336SSriharsha.Basavapatna@Sun.COM 
4262311Sseb static mac_callbacks_t vgen_m_callbacks = {
4279336SSriharsha.Basavapatna@Sun.COM 	VGEN_M_CALLBACK_FLAGS,
4282311Sseb 	vgen_stat,
4292311Sseb 	vgen_start,
4302311Sseb 	vgen_stop,
4312311Sseb 	vgen_promisc,
4322311Sseb 	vgen_multicst,
4332311Sseb 	vgen_unicst,
4342311Sseb 	vgen_tx,
43511878SVenu.Iyer@Sun.COM 	NULL,
4369336SSriharsha.Basavapatna@Sun.COM 	vgen_ioctl,
4372311Sseb 	NULL,
4382311Sseb 	NULL
4392311Sseb };
4402311Sseb 
44112011SSriharsha.Basavapatna@Sun.COM /* Externs */
4424647Sraghuram extern pri_t	maxclsyspri;
4434647Sraghuram extern proc_t	p0;
4446419Ssb155480 extern uint32_t	vnet_ethermtu;
4456419Ssb155480 extern uint16_t	vnet_default_vlan_id;
446*13098SWentao.Yang@Sun.COM extern uint32_t vnet_num_descriptors;
4471991Sheppo 
4481991Sheppo #ifdef DEBUG
4491991Sheppo 
45012011SSriharsha.Basavapatna@Sun.COM #define	DEBUG_PRINTF	vgen_debug_printf
45112011SSriharsha.Basavapatna@Sun.COM 
4524647Sraghuram extern int vnet_dbglevel;
45312011SSriharsha.Basavapatna@Sun.COM 
45412011SSriharsha.Basavapatna@Sun.COM void vgen_debug_printf(const char *fname, vgen_t *vgenp,
4554647Sraghuram 	vgen_ldc_t *ldcp, const char *fmt, ...);
4564647Sraghuram 
4574647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */
4584647Sraghuram int vgendbg_ldcid = -1;
4591991Sheppo 
46012011SSriharsha.Basavapatna@Sun.COM /* Flags to simulate error conditions for debugging */
46112011SSriharsha.Basavapatna@Sun.COM int vgen_inject_err_flag = 0;
46212011SSriharsha.Basavapatna@Sun.COM 
46312011SSriharsha.Basavapatna@Sun.COM 
46412011SSriharsha.Basavapatna@Sun.COM boolean_t
vgen_inject_error(vgen_ldc_t * ldcp,int error)46512011SSriharsha.Basavapatna@Sun.COM vgen_inject_error(vgen_ldc_t *ldcp, int error)
46612011SSriharsha.Basavapatna@Sun.COM {
46712011SSriharsha.Basavapatna@Sun.COM 	if ((vgendbg_ldcid == ldcp->ldc_id) &&
46812011SSriharsha.Basavapatna@Sun.COM 	    (vgen_inject_err_flag & error)) {
46912011SSriharsha.Basavapatna@Sun.COM 		return (B_TRUE);
47012011SSriharsha.Basavapatna@Sun.COM 	}
47112011SSriharsha.Basavapatna@Sun.COM 	return (B_FALSE);
47212011SSriharsha.Basavapatna@Sun.COM }
4731991Sheppo 
4741991Sheppo #endif
4751991Sheppo 
4761991Sheppo /*
4771991Sheppo  * vgen_init() is called by an instance of vnet driver to initialize the
47812011SSriharsha.Basavapatna@Sun.COM  * corresponding generic transport layer. This layer uses Logical Domain
47912011SSriharsha.Basavapatna@Sun.COM  * Channels (LDCs) to communicate with the virtual switch in the service domain
48012011SSriharsha.Basavapatna@Sun.COM  * and also with peer vnets in other guest domains in the system.
48112011SSriharsha.Basavapatna@Sun.COM  *
48212011SSriharsha.Basavapatna@Sun.COM  * Arguments:
48312011SSriharsha.Basavapatna@Sun.COM  *   vnetp:   an opaque pointer to the vnet instance
48412011SSriharsha.Basavapatna@Sun.COM  *   regprop: frame to be transmitted
48512011SSriharsha.Basavapatna@Sun.COM  *   vnetdip: dip of the vnet device
48612011SSriharsha.Basavapatna@Sun.COM  *   macaddr: mac address of the vnet device
48712011SSriharsha.Basavapatna@Sun.COM  *
48812011SSriharsha.Basavapatna@Sun.COM  * Returns:
48912011SSriharsha.Basavapatna@Sun.COM  *	Sucess:  a handle to the vgen instance (vgen_t)
49012011SSriharsha.Basavapatna@Sun.COM  *	Failure: NULL
4911991Sheppo  */
4921991Sheppo int
vgen_init(void * vnetp,uint64_t regprop,dev_info_t * vnetdip,const uint8_t * macaddr,void ** vgenhdl)4936495Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
4946495Sspeer     const uint8_t *macaddr, void **vgenhdl)
4951991Sheppo {
49612011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp;
49712011SSriharsha.Basavapatna@Sun.COM 	int	instance;
49812011SSriharsha.Basavapatna@Sun.COM 	int	rv;
49912011SSriharsha.Basavapatna@Sun.COM 	char	qname[TASKQ_NAMELEN];
5001991Sheppo 
5012311Sseb 	if ((vnetp == NULL) || (vnetdip == NULL))
5021991Sheppo 		return (DDI_FAILURE);
5031991Sheppo 
5041991Sheppo 	instance = ddi_get_instance(vnetdip);
5051991Sheppo 
5065373Sraghuram 	DBG1(NULL, NULL, "vnet(%d): enter\n", instance);
5071991Sheppo 
5081991Sheppo 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
5091991Sheppo 
5101991Sheppo 	vgenp->vnetp = vnetp;
5116495Sspeer 	vgenp->instance = instance;
5126495Sspeer 	vgenp->regprop = regprop;
5131991Sheppo 	vgenp->vnetdip = vnetdip;
5141991Sheppo 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
5159336SSriharsha.Basavapatna@Sun.COM 	vgenp->phys_link_state = LINK_STATE_UNKNOWN;
5161991Sheppo 
5171991Sheppo 	/* allocate multicast table */
5181991Sheppo 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
5191991Sheppo 	    sizeof (struct ether_addr), KM_SLEEP);
5201991Sheppo 	vgenp->mccount = 0;
5211991Sheppo 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
5221991Sheppo 
5231991Sheppo 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
5245641Swentaoy 	rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL);
5251991Sheppo 
52612011SSriharsha.Basavapatna@Sun.COM 	(void) snprintf(qname, TASKQ_NAMELEN, "rxpool_taskq%d",
52712011SSriharsha.Basavapatna@Sun.COM 	    instance);
52812011SSriharsha.Basavapatna@Sun.COM 	if ((vgenp->rxp_taskq = ddi_taskq_create(vnetdip, qname, 1,
52912011SSriharsha.Basavapatna@Sun.COM 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
53012011SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN, "!vnet%d: Unable to create rx pool task queue",
53112011SSriharsha.Basavapatna@Sun.COM 		    instance);
53212011SSriharsha.Basavapatna@Sun.COM 		goto vgen_init_fail;
53312011SSriharsha.Basavapatna@Sun.COM 	}
53412011SSriharsha.Basavapatna@Sun.COM 
5355935Ssb155480 	rv = vgen_read_mdprops(vgenp);
5365935Ssb155480 	if (rv != 0) {
5375935Ssb155480 		goto vgen_init_fail;
5385935Ssb155480 	}
5396495Sspeer 	*vgenhdl = (void *)vgenp;
5401991Sheppo 
5415373Sraghuram 	DBG1(NULL, NULL, "vnet(%d): exit\n", instance);
5421991Sheppo 	return (DDI_SUCCESS);
5435935Ssb155480 
5445935Ssb155480 vgen_init_fail:
5455935Ssb155480 	rw_destroy(&vgenp->vgenports.rwlock);
5465935Ssb155480 	mutex_destroy(&vgenp->lock);
5475935Ssb155480 	kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
5485935Ssb155480 	    sizeof (struct ether_addr));
5495935Ssb155480 	if (VGEN_PRI_ETH_DEFINED(vgenp)) {
5505935Ssb155480 		kmem_free(vgenp->pri_types,
5515935Ssb155480 		    sizeof (uint16_t) * vgenp->pri_num_types);
5525935Ssb155480 		(void) vio_destroy_mblks(vgenp->pri_tx_vmp);
5535935Ssb155480 	}
55412011SSriharsha.Basavapatna@Sun.COM 	if (vgenp->rxp_taskq != NULL) {
55512011SSriharsha.Basavapatna@Sun.COM 		ddi_taskq_destroy(vgenp->rxp_taskq);
55612011SSriharsha.Basavapatna@Sun.COM 		vgenp->rxp_taskq = NULL;
55712011SSriharsha.Basavapatna@Sun.COM 	}
5585935Ssb155480 	KMEM_FREE(vgenp);
5595935Ssb155480 	return (DDI_FAILURE);
5601991Sheppo }
5611991Sheppo 
56210309SSriharsha.Basavapatna@Sun.COM int
vgen_init_mdeg(void * arg)56310309SSriharsha.Basavapatna@Sun.COM vgen_init_mdeg(void *arg)
56410309SSriharsha.Basavapatna@Sun.COM {
56510309SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = (vgen_t *)arg;
56610309SSriharsha.Basavapatna@Sun.COM 
56710309SSriharsha.Basavapatna@Sun.COM 	/* register with MD event generator */
56810309SSriharsha.Basavapatna@Sun.COM 	return (vgen_mdeg_reg(vgenp));
56910309SSriharsha.Basavapatna@Sun.COM }
57010309SSriharsha.Basavapatna@Sun.COM 
5711991Sheppo /*
5721991Sheppo  * Called by vnet to undo the initializations done by vgen_init().
5731991Sheppo  * The handle provided by generic transport during vgen_init() is the argument.
5741991Sheppo  */
5759235SWentao.Yang@Sun.COM void
vgen_uninit(void * arg)5761991Sheppo vgen_uninit(void *arg)
5771991Sheppo {
57812011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = (vgen_t *)arg;
5792336Snarayan 
5802336Snarayan 	if (vgenp == NULL) {
5819235SWentao.Yang@Sun.COM 		return;
5822336Snarayan 	}
5831991Sheppo 
5844647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
5851991Sheppo 
58612011SSriharsha.Basavapatna@Sun.COM 	/* Unregister with MD event generator */
5871991Sheppo 	vgen_mdeg_unreg(vgenp);
5881991Sheppo 
5891991Sheppo 	mutex_enter(&vgenp->lock);
5901991Sheppo 
59112011SSriharsha.Basavapatna@Sun.COM 	/*
59212011SSriharsha.Basavapatna@Sun.COM 	 * Detach all ports from the device; note that the device should have
59312011SSriharsha.Basavapatna@Sun.COM 	 * been unplumbed by this time (See vnet_unattach() for the sequence)
59412011SSriharsha.Basavapatna@Sun.COM 	 * and thus vgen_stop() has already been invoked on all the ports.
59512011SSriharsha.Basavapatna@Sun.COM 	 */
5961991Sheppo 	vgen_detach_ports(vgenp);
5971991Sheppo 
5982336Snarayan 	/*
59912011SSriharsha.Basavapatna@Sun.COM 	 * We now destroy the taskq used to clean up rx mblk pools that
60012011SSriharsha.Basavapatna@Sun.COM 	 * couldn't be destroyed when the ports/channels were detached.
60112011SSriharsha.Basavapatna@Sun.COM 	 * We implicitly wait for those tasks to complete in
60212011SSriharsha.Basavapatna@Sun.COM 	 * ddi_taskq_destroy().
6032336Snarayan 	 */
60412011SSriharsha.Basavapatna@Sun.COM 	if (vgenp->rxp_taskq != NULL) {
60512011SSriharsha.Basavapatna@Sun.COM 		ddi_taskq_destroy(vgenp->rxp_taskq);
60612011SSriharsha.Basavapatna@Sun.COM 		vgenp->rxp_taskq = NULL;
60712011SSriharsha.Basavapatna@Sun.COM 	}
60812011SSriharsha.Basavapatna@Sun.COM 
60912011SSriharsha.Basavapatna@Sun.COM 	/* Free multicast table */
6101991Sheppo 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
6111991Sheppo 
61212011SSriharsha.Basavapatna@Sun.COM 	/* Free pri_types table */
6135935Ssb155480 	if (VGEN_PRI_ETH_DEFINED(vgenp)) {
6145935Ssb155480 		kmem_free(vgenp->pri_types,
6155935Ssb155480 		    sizeof (uint16_t) * vgenp->pri_num_types);
6165935Ssb155480 		(void) vio_destroy_mblks(vgenp->pri_tx_vmp);
6175935Ssb155480 	}
6185935Ssb155480 
6191991Sheppo 	mutex_exit(&vgenp->lock);
6205641Swentaoy 	rw_destroy(&vgenp->vgenports.rwlock);
6211991Sheppo 	mutex_destroy(&vgenp->lock);
6221991Sheppo 
6237572SWentao.Yang@Sun.COM 	DBG1(vgenp, NULL, "exit\n");
6241991Sheppo 	KMEM_FREE(vgenp);
6251991Sheppo }
6261991Sheppo 
6271991Sheppo /* enable transmit/receive for the device */
6282311Sseb int
vgen_start(void * arg)6291991Sheppo vgen_start(void *arg)
6301991Sheppo {
6316495Sspeer 	vgen_port_t	*portp = (vgen_port_t *)arg;
6326495Sspeer 	vgen_t		*vgenp = portp->vgenp;
6331991Sheppo 
6344647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
6356495Sspeer 	mutex_enter(&portp->lock);
6366495Sspeer 	vgen_port_init(portp);
6376495Sspeer 	portp->flags |= VGEN_STARTED;
6386495Sspeer 	mutex_exit(&portp->lock);
6394647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
6406495Sspeer 
6411991Sheppo 	return (DDI_SUCCESS);
6421991Sheppo }
6431991Sheppo 
6441991Sheppo /* stop transmit/receive */
6452311Sseb void
vgen_stop(void * arg)6461991Sheppo vgen_stop(void *arg)
6471991Sheppo {
6486495Sspeer 	vgen_port_t	*portp = (vgen_port_t *)arg;
6496495Sspeer 	vgen_t		*vgenp = portp->vgenp;
6501991Sheppo 
6514647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
6521991Sheppo 
6536495Sspeer 	mutex_enter(&portp->lock);
65411543SWentao.Yang@Sun.COM 	if (portp->flags & VGEN_STARTED) {
65511543SWentao.Yang@Sun.COM 		vgen_port_uninit(portp);
65611543SWentao.Yang@Sun.COM 		portp->flags &= ~(VGEN_STARTED);
65711543SWentao.Yang@Sun.COM 	}
6586495Sspeer 	mutex_exit(&portp->lock);
6594647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
6606495Sspeer 
6611991Sheppo }
6621991Sheppo 
6631991Sheppo /* vgen transmit function */
6641991Sheppo static mblk_t *
vgen_tx(void * arg,mblk_t * mp)6651991Sheppo vgen_tx(void *arg, mblk_t *mp)
6661991Sheppo {
66712011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*portp;
66812011SSriharsha.Basavapatna@Sun.COM 	int		status;
6691991Sheppo 
6701991Sheppo 	portp = (vgen_port_t *)arg;
67112011SSriharsha.Basavapatna@Sun.COM 	status = vgen_portsend(portp, mp);
6721991Sheppo 	if (status != VGEN_SUCCESS) {
6731991Sheppo 		/* failure */
6741991Sheppo 		return (mp);
6751991Sheppo 	}
6761991Sheppo 	/* success */
6771991Sheppo 	return (NULL);
6781991Sheppo }
6791991Sheppo 
6806419Ssb155480 /*
6816419Ssb155480  * This function provides any necessary tagging/untagging of the frames
6826419Ssb155480  * that are being transmitted over the port. It first verifies the vlan
6836419Ssb155480  * membership of the destination(port) and drops the packet if the
6846419Ssb155480  * destination doesn't belong to the given vlan.
6856419Ssb155480  *
6866419Ssb155480  * Arguments:
6876419Ssb155480  *   portp:     port over which the frames should be transmitted
6886419Ssb155480  *   mp:        frame to be transmitted
6896419Ssb155480  *   is_tagged:
6906419Ssb155480  *              B_TRUE: indicates frame header contains the vlan tag already.
6916419Ssb155480  *              B_FALSE: indicates frame is untagged.
6926419Ssb155480  *   vid:       vlan in which the frame should be transmitted.
6936419Ssb155480  *
6946419Ssb155480  * Returns:
6956419Ssb155480  *              Sucess: frame(mblk_t *) after doing the necessary tag/untag.
6966419Ssb155480  *              Failure: NULL
6976419Ssb155480  */
6986419Ssb155480 static mblk_t *
vgen_vlan_frame_fixtag(vgen_port_t * portp,mblk_t * mp,boolean_t is_tagged,uint16_t vid)6996419Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged,
7006419Ssb155480 	uint16_t vid)
7016419Ssb155480 {
70212011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp;
70312011SSriharsha.Basavapatna@Sun.COM 	boolean_t	dst_tagged;
70412011SSriharsha.Basavapatna@Sun.COM 	int		rv;
7056419Ssb155480 
7066419Ssb155480 	vgenp = portp->vgenp;
7076419Ssb155480 
7086419Ssb155480 	/*
7096419Ssb155480 	 * If the packet is going to a vnet:
7106419Ssb155480 	 *   Check if the destination vnet is in the same vlan.
7116419Ssb155480 	 *   Check the frame header if tag or untag is needed.
7126419Ssb155480 	 *
7136419Ssb155480 	 * We do not check the above conditions if the packet is going to vsw:
7146419Ssb155480 	 *   vsw must be present implicitly in all the vlans that a vnet device
7156419Ssb155480 	 *   is configured into; even if vsw itself is not assigned to those
7166419Ssb155480 	 *   vlans as an interface. For instance, the packet might be destined
7176419Ssb155480 	 *   to another vnet(indirectly through vsw) or to an external host
7186419Ssb155480 	 *   which is in the same vlan as this vnet and vsw itself may not be
7196419Ssb155480 	 *   present in that vlan. Similarly packets going to vsw must be
7206419Ssb155480 	 *   always tagged(unless in the default-vlan) if not already tagged,
7216419Ssb155480 	 *   as we do not know the final destination. This is needed because
7226419Ssb155480 	 *   vsw must always invoke its switching function only after tagging
7236419Ssb155480 	 *   the packet; otherwise after switching function determines the
7246419Ssb155480 	 *   destination we cannot figure out if the destination belongs to the
7256419Ssb155480 	 *   the same vlan that the frame originated from and if it needs tag/
7266419Ssb155480 	 *   untag. Note that vsw will tag the packet itself when it receives
7276419Ssb155480 	 *   it over the channel from a client if needed. However, that is
7286419Ssb155480 	 *   needed only in the case of vlan unaware clients such as obp or
7296419Ssb155480 	 *   earlier versions of vnet.
7306419Ssb155480 	 *
7316419Ssb155480 	 */
7326419Ssb155480 	if (portp != vgenp->vsw_portp) {
7336419Ssb155480 		/*
7346419Ssb155480 		 * Packet going to a vnet. Check if the destination vnet is in
7356419Ssb155480 		 * the same vlan. Then check the frame header if tag/untag is
7366419Ssb155480 		 * needed.
7376419Ssb155480 		 */
7386419Ssb155480 		rv = vgen_vlan_lookup(portp->vlan_hashp, vid);
7396419Ssb155480 		if (rv == B_FALSE) {
7406419Ssb155480 			/* drop the packet */
7416419Ssb155480 			freemsg(mp);
7426419Ssb155480 			return (NULL);
7436419Ssb155480 		}
7446419Ssb155480 
7456419Ssb155480 		/* is the destination tagged or untagged in this vlan? */
7466419Ssb155480 		(vid == portp->pvid) ? (dst_tagged = B_FALSE) :
7476419Ssb155480 		    (dst_tagged = B_TRUE);
7486419Ssb155480 
7496419Ssb155480 		if (is_tagged == dst_tagged) {
7506419Ssb155480 			/* no tagging/untagging needed */
7516419Ssb155480 			return (mp);
7526419Ssb155480 		}
7536419Ssb155480 
7546419Ssb155480 		if (is_tagged == B_TRUE) {
7556419Ssb155480 			/* frame is tagged; destination needs untagged */
7566419Ssb155480 			mp = vnet_vlan_remove_tag(mp);
7576419Ssb155480 			return (mp);
7586419Ssb155480 		}
7596419Ssb155480 
7606419Ssb155480 		/* (is_tagged == B_FALSE): fallthru to tag tx packet: */
7616419Ssb155480 	}
7626419Ssb155480 
7636419Ssb155480 	/*
7646419Ssb155480 	 * Packet going to a vnet needs tagging.
7656419Ssb155480 	 * OR
7666419Ssb155480 	 * If the packet is going to vsw, then it must be tagged in all cases:
7676419Ssb155480 	 * unknown unicast, broadcast/multicast or to vsw interface.
7686419Ssb155480 	 */
7696419Ssb155480 
7706419Ssb155480 	if (is_tagged == B_FALSE) {
7716419Ssb155480 		mp = vnet_vlan_insert_tag(mp, vid);
7726419Ssb155480 	}
7736419Ssb155480 
7746419Ssb155480 	return (mp);
7756419Ssb155480 }
7766419Ssb155480 
7771991Sheppo /* transmit packets over the given port */
7781991Sheppo static int
vgen_portsend(vgen_port_t * portp,mblk_t * mp)7791991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
7801991Sheppo {
7816419Ssb155480 	vgen_ldc_t		*ldcp;
7826419Ssb155480 	int			status;
7836419Ssb155480 	int			rv = VGEN_SUCCESS;
7846495Sspeer 	vgen_t			*vgenp = portp->vgenp;
7856495Sspeer 	vnet_t			*vnetp = vgenp->vnetp;
7866419Ssb155480 	boolean_t		is_tagged;
7876495Sspeer 	boolean_t		dec_refcnt = B_FALSE;
7886419Ssb155480 	uint16_t		vlan_id;
7896419Ssb155480 	struct ether_header	*ehp;
7906419Ssb155480 
79112011SSriharsha.Basavapatna@Sun.COM 	if (portp == NULL) {
79212011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
79312011SSriharsha.Basavapatna@Sun.COM 	}
79412011SSriharsha.Basavapatna@Sun.COM 
7956495Sspeer 	if (portp->use_vsw_port) {
7966495Sspeer 		(void) atomic_inc_32(&vgenp->vsw_port_refcnt);
7976495Sspeer 		portp = portp->vgenp->vsw_portp;
79812011SSriharsha.Basavapatna@Sun.COM 		ASSERT(portp != NULL);
7996495Sspeer 		dec_refcnt = B_TRUE;
8006495Sspeer 	}
8016419Ssb155480 
8026419Ssb155480 	/*
8036419Ssb155480 	 * Determine the vlan id that the frame belongs to.
8046419Ssb155480 	 */
8056419Ssb155480 	ehp = (struct ether_header *)mp->b_rptr;
8066419Ssb155480 	is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id);
8076419Ssb155480 
8086419Ssb155480 	if (vlan_id == vnetp->default_vlan_id) {
8096419Ssb155480 
8106419Ssb155480 		/* Frames in default vlan must be untagged */
8116419Ssb155480 		ASSERT(is_tagged == B_FALSE);
8126419Ssb155480 
8136419Ssb155480 		/*
8146419Ssb155480 		 * If the destination is a vnet-port verify it belongs to the
8156419Ssb155480 		 * default vlan; otherwise drop the packet. We do not need
8166419Ssb155480 		 * this check for vsw-port, as it should implicitly belong to
8176419Ssb155480 		 * this vlan; see comments in vgen_vlan_frame_fixtag().
8186419Ssb155480 		 */
8196419Ssb155480 		if (portp != vgenp->vsw_portp &&
8206419Ssb155480 		    portp->pvid != vnetp->default_vlan_id) {
8216419Ssb155480 			freemsg(mp);
8226495Sspeer 			goto portsend_ret;
8236419Ssb155480 		}
8246419Ssb155480 
8256419Ssb155480 	} else {	/* frame not in default-vlan */
8266419Ssb155480 
8276419Ssb155480 		mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id);
8286419Ssb155480 		if (mp == NULL) {
8296495Sspeer 			goto portsend_ret;
8306419Ssb155480 		}
8316419Ssb155480 
8326419Ssb155480 	}
8331991Sheppo 
83412011SSriharsha.Basavapatna@Sun.COM 	ldcp = portp->ldcp;
8355935Ssb155480 	status = ldcp->tx(ldcp, mp);
8365022Sraghuram 
8375022Sraghuram 	if (status != VGEN_TX_SUCCESS) {
8385022Sraghuram 		rv = VGEN_FAILURE;
8395022Sraghuram 	}
8406495Sspeer 
8416495Sspeer portsend_ret:
8426495Sspeer 	if (dec_refcnt == B_TRUE) {
8436495Sspeer 		(void) atomic_dec_32(&vgenp->vsw_port_refcnt);
8446495Sspeer 	}
8455022Sraghuram 	return (rv);
8461991Sheppo }
8471991Sheppo 
8485935Ssb155480 /*
8495935Ssb155480  * Wrapper function to transmit normal and/or priority frames over the channel.
8505935Ssb155480  */
8511991Sheppo static int
vgen_ldcsend(void * arg,mblk_t * mp)8525935Ssb155480 vgen_ldcsend(void *arg, mblk_t *mp)
8535935Ssb155480 {
8545935Ssb155480 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg;
8555935Ssb155480 	int			status;
8565935Ssb155480 	struct ether_header	*ehp;
8575935Ssb155480 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
8585935Ssb155480 	uint32_t		num_types;
8595935Ssb155480 	uint16_t		*types;
8605935Ssb155480 	int			i;
8615935Ssb155480 
8625935Ssb155480 	ASSERT(VGEN_PRI_ETH_DEFINED(vgenp));
8635935Ssb155480 
8645935Ssb155480 	num_types = vgenp->pri_num_types;
8655935Ssb155480 	types = vgenp->pri_types;
8665935Ssb155480 	ehp = (struct ether_header *)mp->b_rptr;
8675935Ssb155480 
8685935Ssb155480 	for (i = 0; i < num_types; i++) {
8695935Ssb155480 
8705935Ssb155480 		if (ehp->ether_type == types[i]) {
8715935Ssb155480 			/* priority frame, use pri tx function */
8725935Ssb155480 			vgen_ldcsend_pkt(ldcp, mp);
8735935Ssb155480 			return (VGEN_SUCCESS);
8745935Ssb155480 		}
8755935Ssb155480 
8765935Ssb155480 	}
8775935Ssb155480 
87812011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_dringdata == NULL) {
87912011SSriharsha.Basavapatna@Sun.COM 		freemsg(mp);
88012011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_SUCCESS);
88112011SSriharsha.Basavapatna@Sun.COM 	}
88212011SSriharsha.Basavapatna@Sun.COM 
88312011SSriharsha.Basavapatna@Sun.COM 	status  = ldcp->tx_dringdata(ldcp, mp);
8845935Ssb155480 	return (status);
8855935Ssb155480 }
8865935Ssb155480 
8875935Ssb155480 /*
8885935Ssb155480  * This function transmits the frame in the payload of a raw data
8895935Ssb155480  * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
8905935Ssb155480  * send special frames with high priorities, without going through
8915935Ssb155480  * the normal data path which uses descriptor ring mechanism.
8925935Ssb155480  */
8935935Ssb155480 static void
vgen_ldcsend_pkt(void * arg,mblk_t * mp)8945935Ssb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp)
8951991Sheppo {
8965935Ssb155480 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg;
8975935Ssb155480 	vio_raw_data_msg_t	*pkt;
8985935Ssb155480 	mblk_t			*bp;
8995935Ssb155480 	mblk_t			*nmp = NULL;
90012011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t		*vmp;
9015935Ssb155480 	caddr_t			dst;
9025935Ssb155480 	uint32_t		mblksz;
9035935Ssb155480 	uint32_t		size;
9045935Ssb155480 	uint32_t		nbytes;
9055935Ssb155480 	int			rv;
9065935Ssb155480 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
9075935Ssb155480 	vgen_stats_t		*statsp = &ldcp->stats;
9085935Ssb155480 
9095935Ssb155480 	/* drop the packet if ldc is not up or handshake is not done */
9105935Ssb155480 	if (ldcp->ldc_status != LDC_UP) {
9115935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
9125935Ssb155480 		DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
9135935Ssb155480 		    ldcp->ldc_status);
9145935Ssb155480 		goto send_pkt_exit;
9155935Ssb155480 	}
9165935Ssb155480 
9175935Ssb155480 	if (ldcp->hphase != VH_DONE) {
9185935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
9195935Ssb155480 		DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
9205935Ssb155480 		    ldcp->hphase);
9215935Ssb155480 		goto send_pkt_exit;
9225935Ssb155480 	}
9235935Ssb155480 
9245935Ssb155480 	size = msgsize(mp);
9255935Ssb155480 
9265935Ssb155480 	/* frame size bigger than available payload len of raw data msg ? */
9275935Ssb155480 	if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
9285935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
9295935Ssb155480 		DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
9305935Ssb155480 		goto send_pkt_exit;
9315935Ssb155480 	}
9325935Ssb155480 
9335935Ssb155480 	if (size < ETHERMIN)
9345935Ssb155480 		size = ETHERMIN;
9355935Ssb155480 
9365935Ssb155480 	/* alloc space for a raw data message */
93712011SSriharsha.Basavapatna@Sun.COM 	vmp = vio_allocb(vgenp->pri_tx_vmp);
93812011SSriharsha.Basavapatna@Sun.COM 	if (vmp == NULL) {
9395935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
9405935Ssb155480 		DWARN(vgenp, ldcp, "vio_allocb failed\n");
9415935Ssb155480 		goto send_pkt_exit;
94212011SSriharsha.Basavapatna@Sun.COM 	} else {
94312011SSriharsha.Basavapatna@Sun.COM 		nmp = vmp->mp;
9445935Ssb155480 	}
9455935Ssb155480 	pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
9465935Ssb155480 
9475935Ssb155480 	/* copy frame into the payload of raw data message */
9485935Ssb155480 	dst = (caddr_t)pkt->data;
9495935Ssb155480 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
9505935Ssb155480 		mblksz = MBLKL(bp);
9515935Ssb155480 		bcopy(bp->b_rptr, dst, mblksz);
9525935Ssb155480 		dst += mblksz;
9535935Ssb155480 	}
9545935Ssb155480 
95512011SSriharsha.Basavapatna@Sun.COM 	vmp->state = VIO_MBLK_HAS_DATA;
95612011SSriharsha.Basavapatna@Sun.COM 
9575935Ssb155480 	/* setup the raw data msg */
9585935Ssb155480 	pkt->tag.vio_msgtype = VIO_TYPE_DATA;
9595935Ssb155480 	pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
9605935Ssb155480 	pkt->tag.vio_subtype_env = VIO_PKT_DATA;
9615935Ssb155480 	pkt->tag.vio_sid = ldcp->local_sid;
9625935Ssb155480 	nbytes = VIO_PKT_DATA_HDRSIZE + size;
9635935Ssb155480 
9645935Ssb155480 	/* send the msg over ldc */
9655935Ssb155480 	rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE);
9665935Ssb155480 	if (rv != VGEN_SUCCESS) {
9675935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
9685935Ssb155480 		DWARN(vgenp, ldcp, "Error sending priority frame\n");
9695935Ssb155480 		if (rv == ECONNRESET) {
97012011SSriharsha.Basavapatna@Sun.COM 			(void) vgen_handle_evt_reset(ldcp, VGEN_OTHER);
9715935Ssb155480 		}
9725935Ssb155480 		goto send_pkt_exit;
9735935Ssb155480 	}
9745935Ssb155480 
9755935Ssb155480 	/* update stats */
9765935Ssb155480 	(void) atomic_inc_64(&statsp->tx_pri_packets);
9775935Ssb155480 	(void) atomic_add_64(&statsp->tx_pri_bytes, size);
9785935Ssb155480 
9795935Ssb155480 send_pkt_exit:
9805935Ssb155480 	if (nmp != NULL)
9815935Ssb155480 		freemsg(nmp);
9825935Ssb155480 	freemsg(mp);
9835935Ssb155480 }
9845935Ssb155480 
9855935Ssb155480 /*
98611543SWentao.Yang@Sun.COM  * enable/disable a multicast address
98711543SWentao.Yang@Sun.COM  * note that the cblock of the ldc channel connected to the vsw is used for
98811543SWentao.Yang@Sun.COM  * synchronization of the mctab.
98911543SWentao.Yang@Sun.COM  */
9902311Sseb int
vgen_multicst(void * arg,boolean_t add,const uint8_t * mca)9911991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
9921991Sheppo {
9931991Sheppo 	vgen_t			*vgenp;
9941991Sheppo 	vnet_mcast_msg_t	mcastmsg;
9951991Sheppo 	vio_msg_tag_t		*tagp;
9961991Sheppo 	vgen_port_t		*portp;
9971991Sheppo 	vgen_ldc_t		*ldcp;
9981991Sheppo 	struct ether_addr	*addrp;
9993653Snarayan 	int			rv = DDI_FAILURE;
10001991Sheppo 	uint32_t		i;
10011991Sheppo 
10026495Sspeer 	portp = (vgen_port_t *)arg;
10036495Sspeer 	vgenp = portp->vgenp;
10046495Sspeer 
100511543SWentao.Yang@Sun.COM 	if (portp->is_vsw_port != B_TRUE) {
10066495Sspeer 		return (DDI_SUCCESS);
10076495Sspeer 	}
10086495Sspeer 
10091991Sheppo 	addrp = (struct ether_addr *)mca;
10101991Sheppo 	tagp = &mcastmsg.tag;
10111991Sheppo 	bzero(&mcastmsg, sizeof (mcastmsg));
10121991Sheppo 
101312011SSriharsha.Basavapatna@Sun.COM 	ldcp = portp->ldcp;
101411543SWentao.Yang@Sun.COM 	if (ldcp == NULL) {
101511543SWentao.Yang@Sun.COM 		return (DDI_FAILURE);
101611543SWentao.Yang@Sun.COM 	}
10171991Sheppo 
10181991Sheppo 	mutex_enter(&ldcp->cblock);
10191991Sheppo 
10201991Sheppo 	if (ldcp->hphase == VH_DONE) {
10211991Sheppo 		/*
10221991Sheppo 		 * If handshake is done, send a msg to vsw to add/remove
10235171Ssb155480 		 * the multicast address. Otherwise, we just update this
10245171Ssb155480 		 * mcast address in our table and the table will be sync'd
10255171Ssb155480 		 * with vsw when handshake completes.
10261991Sheppo 		 */
10271991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
10281991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
10291991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
10301991Sheppo 		tagp->vio_sid = ldcp->local_sid;
10311991Sheppo 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
10321991Sheppo 		mcastmsg.set = add;
10331991Sheppo 		mcastmsg.count = 1;
10343653Snarayan 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
10353653Snarayan 		    B_FALSE) != VGEN_SUCCESS) {
10364647Sraghuram 			DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
103711543SWentao.Yang@Sun.COM 			rv = DDI_FAILURE;
10383653Snarayan 			goto vgen_mcast_exit;
10391991Sheppo 		}
10401991Sheppo 	}
10411991Sheppo 
10421991Sheppo 	if (add) {
10431991Sheppo 
10441991Sheppo 		/* expand multicast table if necessary */
10451991Sheppo 		if (vgenp->mccount >= vgenp->mcsize) {
10461991Sheppo 			struct ether_addr	*newtab;
10471991Sheppo 			uint32_t		newsize;
10481991Sheppo 
10491991Sheppo 
10501991Sheppo 			newsize = vgenp->mcsize * 2;
10511991Sheppo 
10521991Sheppo 			newtab = kmem_zalloc(newsize *
10531991Sheppo 			    sizeof (struct ether_addr), KM_NOSLEEP);
10543653Snarayan 			if (newtab == NULL)
10553653Snarayan 				goto vgen_mcast_exit;
10561991Sheppo 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
10571991Sheppo 			    sizeof (struct ether_addr));
10581991Sheppo 			kmem_free(vgenp->mctab,
10591991Sheppo 			    vgenp->mcsize * sizeof (struct ether_addr));
10601991Sheppo 
10611991Sheppo 			vgenp->mctab = newtab;
10621991Sheppo 			vgenp->mcsize = newsize;
10631991Sheppo 		}
10641991Sheppo 
10651991Sheppo 		/* add address to the table */
10661991Sheppo 		vgenp->mctab[vgenp->mccount++] = *addrp;
10671991Sheppo 
10681991Sheppo 	} else {
10691991Sheppo 
10701991Sheppo 		/* delete address from the table */
10711991Sheppo 		for (i = 0; i < vgenp->mccount; i++) {
10721991Sheppo 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
10731991Sheppo 
10741991Sheppo 				/*
10751991Sheppo 				 * If there's more than one address in this
10761991Sheppo 				 * table, delete the unwanted one by moving
10771991Sheppo 				 * the last one in the list over top of it;
10781991Sheppo 				 * otherwise, just remove it.
10791991Sheppo 				 */
10801991Sheppo 				if (vgenp->mccount > 1) {
10811991Sheppo 					vgenp->mctab[i] =
10824650Sraghuram 					    vgenp->mctab[vgenp->mccount-1];
10831991Sheppo 				}
10841991Sheppo 				vgenp->mccount--;
10851991Sheppo 				break;
10861991Sheppo 			}
10871991Sheppo 		}
10881991Sheppo 	}
10891991Sheppo 
10903653Snarayan 	rv = DDI_SUCCESS;
10913653Snarayan 
10923653Snarayan vgen_mcast_exit:
109312011SSriharsha.Basavapatna@Sun.COM 
109411543SWentao.Yang@Sun.COM 	mutex_exit(&ldcp->cblock);
10953653Snarayan 	return (rv);
10961991Sheppo }
10971991Sheppo 
10981991Sheppo /* set or clear promiscuous mode on the device */
10991991Sheppo static int
vgen_promisc(void * arg,boolean_t on)11001991Sheppo vgen_promisc(void *arg, boolean_t on)
11011991Sheppo {
11021991Sheppo 	_NOTE(ARGUNUSED(arg, on))
11031991Sheppo 	return (DDI_SUCCESS);
11041991Sheppo }
11051991Sheppo 
11061991Sheppo /* set the unicast mac address of the device */
11071991Sheppo static int
vgen_unicst(void * arg,const uint8_t * mca)11081991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
11091991Sheppo {
11101991Sheppo 	_NOTE(ARGUNUSED(arg, mca))
11111991Sheppo 	return (DDI_SUCCESS);
11121991Sheppo }
11131991Sheppo 
11141991Sheppo /* get device statistics */
11152311Sseb int
vgen_stat(void * arg,uint_t stat,uint64_t * val)11162311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
11171991Sheppo {
11186495Sspeer 	vgen_port_t	*portp = (vgen_port_t *)arg;
11196495Sspeer 
11206495Sspeer 	*val = vgen_port_stat(portp, stat);
11212311Sseb 	return (0);
11221991Sheppo }
11231991Sheppo 
11241991Sheppo /* vgen internal functions */
11251991Sheppo /* detach all ports from the device */
11261991Sheppo static void
vgen_detach_ports(vgen_t * vgenp)11271991Sheppo vgen_detach_ports(vgen_t *vgenp)
11281991Sheppo {
11291991Sheppo 	vgen_port_t	*portp;
11301991Sheppo 	vgen_portlist_t	*plistp;
11311991Sheppo 
11321991Sheppo 	plistp = &(vgenp->vgenports);
11331991Sheppo 	WRITE_ENTER(&plistp->rwlock);
11341991Sheppo 	while ((portp = plistp->headp) != NULL) {
11351991Sheppo 		vgen_port_detach(portp);
11361991Sheppo 	}
11371991Sheppo 	RW_EXIT(&plistp->rwlock);
11381991Sheppo }
11391991Sheppo 
11401991Sheppo /*
11411991Sheppo  * detach the given port.
11421991Sheppo  */
11431991Sheppo static void
vgen_port_detach(vgen_port_t * portp)11441991Sheppo vgen_port_detach(vgen_port_t *portp)
11451991Sheppo {
11461991Sheppo 	vgen_t		*vgenp;
11471991Sheppo 	int		port_num;
11481991Sheppo 
11491991Sheppo 	vgenp = portp->vgenp;
11501991Sheppo 	port_num = portp->port_num;
11511991Sheppo 
11524647Sraghuram 	DBG1(vgenp, NULL, "port(%d):enter\n", port_num);
11531991Sheppo 
11546495Sspeer 	/*
11556495Sspeer 	 * If this port is connected to the vswitch, then
11566495Sspeer 	 * potentially there could be ports that may be using
11576495Sspeer 	 * this port to transmit packets. To address this do
11586495Sspeer 	 * the following:
11596495Sspeer 	 *	- First set vgenp->vsw_portp to NULL, so that
11606495Sspeer 	 *	  its not used after that.
11616495Sspeer 	 *	- Then wait for the refcnt to go down to 0.
11626495Sspeer 	 *	- Now we can safely detach this port.
11636495Sspeer 	 */
11646495Sspeer 	if (vgenp->vsw_portp == portp) {
11656495Sspeer 		vgenp->vsw_portp = NULL;
11666495Sspeer 		while (vgenp->vsw_port_refcnt > 0) {
11676495Sspeer 			delay(drv_usectohz(vgen_tx_delay));
11686495Sspeer 		}
11696495Sspeer 		(void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
11706495Sspeer 	}
11716495Sspeer 
11726495Sspeer 	if (portp->vhp != NULL) {
11736495Sspeer 		vio_net_resource_unreg(portp->vhp);
11746495Sspeer 		portp->vhp = NULL;
11756495Sspeer 	}
11766495Sspeer 
11776419Ssb155480 	vgen_vlan_destroy_hash(portp);
11786419Ssb155480 
11791991Sheppo 	/* remove it from port list */
11801991Sheppo 	vgen_port_list_remove(portp);
11811991Sheppo 
11821991Sheppo 	/* detach channels from this port */
118312011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_detach(portp->ldcp);
11841991Sheppo 
11856419Ssb155480 	if (portp->num_ldcs != 0) {
11866419Ssb155480 		kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t));
11876419Ssb155480 		portp->num_ldcs = 0;
11886419Ssb155480 	}
11896419Ssb155480 
11906495Sspeer 	mutex_destroy(&portp->lock);
11911991Sheppo 	KMEM_FREE(portp);
11921991Sheppo 
11934647Sraghuram 	DBG1(vgenp, NULL, "port(%d):exit\n", port_num);
11941991Sheppo }
11951991Sheppo 
11961991Sheppo /* add a port to port list */
11971991Sheppo static void
vgen_port_list_insert(vgen_port_t * portp)11981991Sheppo vgen_port_list_insert(vgen_port_t *portp)
11991991Sheppo {
120012011SSriharsha.Basavapatna@Sun.COM 	vgen_portlist_t	*plistp;
120112011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp;
12021991Sheppo 
12031991Sheppo 	vgenp = portp->vgenp;
12041991Sheppo 	plistp = &(vgenp->vgenports);
12051991Sheppo 
12061991Sheppo 	if (plistp->headp == NULL) {
12071991Sheppo 		plistp->headp = portp;
12081991Sheppo 	} else {
12091991Sheppo 		plistp->tailp->nextp = portp;
12101991Sheppo 	}
12111991Sheppo 	plistp->tailp = portp;
12121991Sheppo 	portp->nextp = NULL;
12131991Sheppo }
12141991Sheppo 
12151991Sheppo /* remove a port from port list */
12161991Sheppo static void
vgen_port_list_remove(vgen_port_t * portp)12171991Sheppo vgen_port_list_remove(vgen_port_t *portp)
12181991Sheppo {
121912011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*prevp;
122012011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*nextp;
122112011SSriharsha.Basavapatna@Sun.COM 	vgen_portlist_t	*plistp;
122212011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp;
12231991Sheppo 
12241991Sheppo 	vgenp = portp->vgenp;
12251991Sheppo 
12261991Sheppo 	plistp = &(vgenp->vgenports);
12271991Sheppo 
12281991Sheppo 	if (plistp->headp == NULL)
12291991Sheppo 		return;
12301991Sheppo 
12311991Sheppo 	if (portp == plistp->headp) {
12321991Sheppo 		plistp->headp = portp->nextp;
12331991Sheppo 		if (portp == plistp->tailp)
12341991Sheppo 			plistp->tailp = plistp->headp;
12351991Sheppo 	} else {
12364650Sraghuram 		for (prevp = plistp->headp;
12374650Sraghuram 		    ((nextp = prevp->nextp) != NULL) && (nextp != portp);
12384650Sraghuram 		    prevp = nextp)
12394650Sraghuram 			;
12401991Sheppo 		if (nextp == portp) {
12411991Sheppo 			prevp->nextp = portp->nextp;
12421991Sheppo 		}
12431991Sheppo 		if (portp == plistp->tailp)
12441991Sheppo 			plistp->tailp = prevp;
12451991Sheppo 	}
12461991Sheppo }
12471991Sheppo 
12481991Sheppo /* lookup a port in the list based on port_num */
12491991Sheppo static vgen_port_t *
vgen_port_lookup(vgen_portlist_t * plistp,int port_num)12501991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
12511991Sheppo {
12521991Sheppo 	vgen_port_t *portp = NULL;
12531991Sheppo 
12541991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
12551991Sheppo 		if (portp->port_num == port_num) {
12561991Sheppo 			break;
12571991Sheppo 		}
12581991Sheppo 	}
12591991Sheppo 
12601991Sheppo 	return (portp);
12611991Sheppo }
12621991Sheppo 
12631991Sheppo static void
vgen_port_init(vgen_port_t * portp)12641991Sheppo vgen_port_init(vgen_port_t *portp)
12651991Sheppo {
12666419Ssb155480 	/* Add the port to the specified vlans */
12676419Ssb155480 	vgen_vlan_add_ids(portp);
12681991Sheppo 
126912011SSriharsha.Basavapatna@Sun.COM 	/* Bring up the channel */
127012011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_ldc_init(portp->ldcp);
12711991Sheppo }
12721991Sheppo 
12731991Sheppo static void
vgen_port_uninit(vgen_port_t * portp)12741991Sheppo vgen_port_uninit(vgen_port_t *portp)
12751991Sheppo {
127612011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_uninit(portp->ldcp);
12776419Ssb155480 
12786419Ssb155480 	/* remove the port from vlans it has been assigned to */
12796419Ssb155480 	vgen_vlan_remove_ids(portp);
12801991Sheppo }
12811991Sheppo 
12825935Ssb155480 /*
12835935Ssb155480  * Scan the machine description for this instance of vnet
12845935Ssb155480  * and read its properties. Called only from vgen_init().
12855935Ssb155480  * Returns: 0 on success, 1 on failure.
12865935Ssb155480  */
12875935Ssb155480 static int
vgen_read_mdprops(vgen_t * vgenp)12885935Ssb155480 vgen_read_mdprops(vgen_t *vgenp)
12895935Ssb155480 {
12906419Ssb155480 	vnet_t		*vnetp = vgenp->vnetp;
12915935Ssb155480 	md_t		*mdp = NULL;
12925935Ssb155480 	mde_cookie_t	rootnode;
12935935Ssb155480 	mde_cookie_t	*listp = NULL;
12945935Ssb155480 	uint64_t	cfgh;
12955935Ssb155480 	char		*name;
12965935Ssb155480 	int		rv = 1;
12975935Ssb155480 	int		num_nodes = 0;
12985935Ssb155480 	int		num_devs = 0;
12995935Ssb155480 	int		listsz = 0;
13005935Ssb155480 	int		i;
13015935Ssb155480 
13025935Ssb155480 	if ((mdp = md_get_handle()) == NULL) {
13035935Ssb155480 		return (rv);
13045935Ssb155480 	}
13055935Ssb155480 
13065935Ssb155480 	num_nodes = md_node_count(mdp);
13075935Ssb155480 	ASSERT(num_nodes > 0);
13085935Ssb155480 
13095935Ssb155480 	listsz = num_nodes * sizeof (mde_cookie_t);
13105935Ssb155480 	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
13115935Ssb155480 
13125935Ssb155480 	rootnode = md_root_node(mdp);
13135935Ssb155480 
13145935Ssb155480 	/* search for all "virtual_device" nodes */
13155935Ssb155480 	num_devs = md_scan_dag(mdp, rootnode,
13165935Ssb155480 	    md_find_name(mdp, vdev_propname),
13175935Ssb155480 	    md_find_name(mdp, "fwd"), listp);
13185935Ssb155480 	if (num_devs <= 0) {
13195935Ssb155480 		goto vgen_readmd_exit;
13205935Ssb155480 	}
13215935Ssb155480 
13225935Ssb155480 	/*
13235935Ssb155480 	 * Now loop through the list of virtual-devices looking for
13245935Ssb155480 	 * devices with name "network" and for each such device compare
13255935Ssb155480 	 * its instance with what we have from the 'reg' property to
13265935Ssb155480 	 * find the right node in MD and then read all its properties.
13275935Ssb155480 	 */
13285935Ssb155480 	for (i = 0; i < num_devs; i++) {
13295935Ssb155480 
13305935Ssb155480 		if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) {
13315935Ssb155480 			goto vgen_readmd_exit;
13325935Ssb155480 		}
13335935Ssb155480 
13345935Ssb155480 		/* is this a "network" device? */
13355935Ssb155480 		if (strcmp(name, vnet_propname) != 0)
13365935Ssb155480 			continue;
13375935Ssb155480 
13385935Ssb155480 		if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) {
13395935Ssb155480 			goto vgen_readmd_exit;
13405935Ssb155480 		}
13415935Ssb155480 
13425935Ssb155480 		/* is this the required instance of vnet? */
13436495Sspeer 		if (vgenp->regprop != cfgh)
13445935Ssb155480 			continue;
13455935Ssb155480 
13467529SSriharsha.Basavapatna@Sun.COM 		/*
13479336SSriharsha.Basavapatna@Sun.COM 		 * Read the 'linkprop' property to know if this vnet
13489336SSriharsha.Basavapatna@Sun.COM 		 * device should get physical link updates from vswitch.
13499336SSriharsha.Basavapatna@Sun.COM 		 */
13509336SSriharsha.Basavapatna@Sun.COM 		vgen_linkprop_read(vgenp, mdp, listp[i],
13519336SSriharsha.Basavapatna@Sun.COM 		    &vnetp->pls_update);
13529336SSriharsha.Basavapatna@Sun.COM 
13539336SSriharsha.Basavapatna@Sun.COM 		/*
13547529SSriharsha.Basavapatna@Sun.COM 		 * Read the mtu. Note that we set the mtu of vnet device within
13557529SSriharsha.Basavapatna@Sun.COM 		 * this routine itself, after validating the range.
13567529SSriharsha.Basavapatna@Sun.COM 		 */
13577529SSriharsha.Basavapatna@Sun.COM 		vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu);
13587529SSriharsha.Basavapatna@Sun.COM 		if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) {
13597529SSriharsha.Basavapatna@Sun.COM 			vnetp->mtu = ETHERMTU;
13607529SSriharsha.Basavapatna@Sun.COM 		}
13617529SSriharsha.Basavapatna@Sun.COM 		vgenp->max_frame_size = vnetp->mtu +
13627529SSriharsha.Basavapatna@Sun.COM 		    sizeof (struct ether_header) + VLAN_TAGSZ;
13637529SSriharsha.Basavapatna@Sun.COM 
13647529SSriharsha.Basavapatna@Sun.COM 		/* read priority ether types */
13655935Ssb155480 		vgen_read_pri_eth_types(vgenp, mdp, listp[i]);
13666419Ssb155480 
13676419Ssb155480 		/* read vlan id properties of this vnet instance */
13686419Ssb155480 		vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i],
13696419Ssb155480 		    &vnetp->pvid, &vnetp->vids, &vnetp->nvids,
13706419Ssb155480 		    &vnetp->default_vlan_id);
13716419Ssb155480 
13725935Ssb155480 		rv = 0;
13735935Ssb155480 		break;
13745935Ssb155480 	}
13755935Ssb155480 
13765935Ssb155480 vgen_readmd_exit:
13775935Ssb155480 
13785935Ssb155480 	kmem_free(listp, listsz);
13795935Ssb155480 	(void) md_fini_handle(mdp);
13805935Ssb155480 	return (rv);
13815935Ssb155480 }
13825935Ssb155480 
13835935Ssb155480 /*
13846419Ssb155480  * Read vlan id properties of the given MD node.
13856419Ssb155480  * Arguments:
13866419Ssb155480  *   arg:          device argument(vnet device or a port)
13876419Ssb155480  *   type:         type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port)
13886419Ssb155480  *   mdp:          machine description
13896419Ssb155480  *   node:         md node cookie
13906419Ssb155480  *
13916419Ssb155480  * Returns:
13926419Ssb155480  *   pvidp:        port-vlan-id of the node
13936419Ssb155480  *   vidspp:       list of vlan-ids of the node
13946419Ssb155480  *   nvidsp:       # of vlan-ids in the list
13956419Ssb155480  *   default_idp:  default-vlan-id of the node(if node is vnet device)
13966419Ssb155480  */
13976419Ssb155480 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)13986419Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node,
13996419Ssb155480 	uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp,
14006419Ssb155480 	uint16_t *default_idp)
14016419Ssb155480 {
14026419Ssb155480 	vgen_t		*vgenp;
14036419Ssb155480 	vnet_t		*vnetp;
14046419Ssb155480 	vgen_port_t	*portp;
14056419Ssb155480 	char		*pvid_propname;
14066419Ssb155480 	char		*vid_propname;
14076419Ssb155480 	uint_t		nvids;
14086419Ssb155480 	uint32_t	vids_size;
14096419Ssb155480 	int		rv;
14106419Ssb155480 	int		i;
14116419Ssb155480 	uint64_t	*data;
14126419Ssb155480 	uint64_t	val;
14136419Ssb155480 	int		size;
14146419Ssb155480 	int		inst;
14156419Ssb155480 
14166419Ssb155480 	if (type == VGEN_LOCAL) {
14176419Ssb155480 
14186419Ssb155480 		vgenp = (vgen_t *)arg;
14196419Ssb155480 		vnetp = vgenp->vnetp;
14206419Ssb155480 		pvid_propname = vgen_pvid_propname;
14216419Ssb155480 		vid_propname = vgen_vid_propname;
14226419Ssb155480 		inst = vnetp->instance;
14236419Ssb155480 
14246419Ssb155480 	} else if (type == VGEN_PEER) {
14256419Ssb155480 
14266419Ssb155480 		portp = (vgen_port_t *)arg;
14276419Ssb155480 		vgenp = portp->vgenp;
14286419Ssb155480 		vnetp = vgenp->vnetp;
14296419Ssb155480 		pvid_propname = port_pvid_propname;
14306419Ssb155480 		vid_propname = port_vid_propname;
14316419Ssb155480 		inst = portp->port_num;
14326419Ssb155480 
14336419Ssb155480 	} else {
14346419Ssb155480 		return;
14356419Ssb155480 	}
14366419Ssb155480 
14376419Ssb155480 	if (type == VGEN_LOCAL && default_idp != NULL) {
14386419Ssb155480 		rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val);
14396419Ssb155480 		if (rv != 0) {
14406419Ssb155480 			DWARN(vgenp, NULL, "prop(%s) not found",
14416419Ssb155480 			    vgen_dvid_propname);
14426419Ssb155480 
14436419Ssb155480 			*default_idp = vnet_default_vlan_id;
14446419Ssb155480 		} else {
14456419Ssb155480 			*default_idp = val & 0xFFF;
14466419Ssb155480 			DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname,
14476419Ssb155480 			    inst, *default_idp);
14486419Ssb155480 		}
14496419Ssb155480 	}
14506419Ssb155480 
14516419Ssb155480 	rv = md_get_prop_val(mdp, node, pvid_propname, &val);
14526419Ssb155480 	if (rv != 0) {
14536419Ssb155480 		DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname);
14546419Ssb155480 		*pvidp = vnet_default_vlan_id;
14556419Ssb155480 	} else {
14566419Ssb155480 
14576419Ssb155480 		*pvidp = val & 0xFFF;
14586419Ssb155480 		DBG2(vgenp, NULL, "%s(%d): (%d)\n",
14596419Ssb155480 		    pvid_propname, inst, *pvidp);
14606419Ssb155480 	}
14616419Ssb155480 
14626419Ssb155480 	rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data,
14636419Ssb155480 	    &size);
14646419Ssb155480 	if (rv != 0) {
14656419Ssb155480 		DBG2(vgenp, NULL, "prop(%s) not found", vid_propname);
14666419Ssb155480 		size = 0;
14676419Ssb155480 	} else {
14686419Ssb155480 		size /= sizeof (uint64_t);
14696419Ssb155480 	}
14706419Ssb155480 	nvids = size;
14716419Ssb155480 
14726419Ssb155480 	if (nvids != 0) {
14736419Ssb155480 		DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst);
14746419Ssb155480 		vids_size = sizeof (uint16_t) * nvids;
14756419Ssb155480 		*vidspp = kmem_zalloc(vids_size, KM_SLEEP);
14766419Ssb155480 		for (i = 0; i < nvids; i++) {
14776419Ssb155480 			(*vidspp)[i] = data[i] & 0xFFFF;
14786419Ssb155480 			DBG2(vgenp, NULL, " %d ", (*vidspp)[i]);
14796419Ssb155480 		}
14806419Ssb155480 		DBG2(vgenp, NULL, "\n");
14816419Ssb155480 	}
14826419Ssb155480 
14836419Ssb155480 	*nvidsp = nvids;
14846419Ssb155480 }
14856419Ssb155480 
14866419Ssb155480 /*
14876419Ssb155480  * Create a vlan id hash table for the given port.
14886419Ssb155480  */
14896419Ssb155480 static void
vgen_vlan_create_hash(vgen_port_t * portp)14906419Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp)
14916419Ssb155480 {
14926419Ssb155480 	char		hashname[MAXNAMELEN];
14936419Ssb155480 
14946419Ssb155480 	(void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
14956419Ssb155480 	    portp->port_num);
14966419Ssb155480 
14976419Ssb155480 	portp->vlan_nchains = vgen_vlan_nchains;
14986419Ssb155480 	portp->vlan_hashp = mod_hash_create_idhash(hashname,
14996419Ssb155480 	    portp->vlan_nchains, mod_hash_null_valdtor);
15006419Ssb155480 }
15016419Ssb155480 
15026419Ssb155480 /*
15036419Ssb155480  * Destroy the vlan id hash table in the given port.
15046419Ssb155480  */
15056419Ssb155480 static void
vgen_vlan_destroy_hash(vgen_port_t * portp)15066419Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp)
15076419Ssb155480 {
15086419Ssb155480 	if (portp->vlan_hashp != NULL) {
15096419Ssb155480 		mod_hash_destroy_hash(portp->vlan_hashp);
15106419Ssb155480 		portp->vlan_hashp = NULL;
15116419Ssb155480 		portp->vlan_nchains = 0;
15126419Ssb155480 	}
15136419Ssb155480 }
15146419Ssb155480 
15156419Ssb155480 /*
15166419Ssb155480  * Add a port to the vlans specified in its port properites.
15176419Ssb155480  */
15186419Ssb155480 static void
vgen_vlan_add_ids(vgen_port_t * portp)15196419Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp)
15206419Ssb155480 {
15216419Ssb155480 	int		rv;
15226419Ssb155480 	int		i;
15236419Ssb155480 
15246419Ssb155480 	rv = mod_hash_insert(portp->vlan_hashp,
15256419Ssb155480 	    (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
15266419Ssb155480 	    (mod_hash_val_t)B_TRUE);
15276419Ssb155480 	ASSERT(rv == 0);
15286419Ssb155480 
15296419Ssb155480 	for (i = 0; i < portp->nvids; i++) {
15306419Ssb155480 		rv = mod_hash_insert(portp->vlan_hashp,
15316419Ssb155480 		    (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
15326419Ssb155480 		    (mod_hash_val_t)B_TRUE);
15336419Ssb155480 		ASSERT(rv == 0);
15346419Ssb155480 	}
15356419Ssb155480 }
15366419Ssb155480 
15376419Ssb155480 /*
15386419Ssb155480  * Remove a port from the vlans it has been assigned to.
15396419Ssb155480  */
15406419Ssb155480 static void
vgen_vlan_remove_ids(vgen_port_t * portp)15416419Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp)
15426419Ssb155480 {
15436419Ssb155480 	int		rv;
15446419Ssb155480 	int		i;
15456419Ssb155480 	mod_hash_val_t	vp;
15466419Ssb155480 
15476419Ssb155480 	rv = mod_hash_remove(portp->vlan_hashp,
15486419Ssb155480 	    (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
15496419Ssb155480 	    (mod_hash_val_t *)&vp);
15506419Ssb155480 	ASSERT(rv == 0);
15516419Ssb155480 
15526419Ssb155480 	for (i = 0; i < portp->nvids; i++) {
15536419Ssb155480 		rv = mod_hash_remove(portp->vlan_hashp,
15546419Ssb155480 		    (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
15556419Ssb155480 		    (mod_hash_val_t *)&vp);
15566419Ssb155480 		ASSERT(rv == 0);
15576419Ssb155480 	}
15586419Ssb155480 }
15596419Ssb155480 
15606419Ssb155480 /*
15616419Ssb155480  * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame,
15626419Ssb155480  * then the vlan-id is available in the tag; otherwise, its vlan id is
15636419Ssb155480  * implicitly obtained from the port-vlan-id of the vnet device.
15646419Ssb155480  * The vlan id determined is returned in vidp.
15656419Ssb155480  * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
15666419Ssb155480  */
15676419Ssb155480 static boolean_t
vgen_frame_lookup_vid(vnet_t * vnetp,struct ether_header * ehp,uint16_t * vidp)15686419Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp)
15696419Ssb155480 {
15706419Ssb155480 	struct ether_vlan_header	*evhp;
15716419Ssb155480 
15726419Ssb155480 	/* If it's a tagged frame, get the vlan id from vlan header */
15736419Ssb155480 	if (ehp->ether_type == ETHERTYPE_VLAN) {
15746419Ssb155480 
15756419Ssb155480 		evhp = (struct ether_vlan_header *)ehp;
15766419Ssb155480 		*vidp = VLAN_ID(ntohs(evhp->ether_tci));
15776419Ssb155480 		return (B_TRUE);
15786419Ssb155480 	}
15796419Ssb155480 
15806419Ssb155480 	/* Untagged frame, vlan-id is the pvid of vnet device */
15816419Ssb155480 	*vidp = vnetp->pvid;
15826419Ssb155480 	return (B_FALSE);
15836419Ssb155480 }
15846419Ssb155480 
15856419Ssb155480 /*
15866419Ssb155480  * Find the given vlan id in the hash table.
15876419Ssb155480  * Return: B_TRUE if the id is found; B_FALSE if not found.
15886419Ssb155480  */
15896419Ssb155480 static boolean_t
vgen_vlan_lookup(mod_hash_t * vlan_hashp,uint16_t vid)15906419Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
15916419Ssb155480 {
15926419Ssb155480 	int		rv;
15936419Ssb155480 	mod_hash_val_t	vp;
15946419Ssb155480 
15956419Ssb155480 	rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
15966419Ssb155480 
15976419Ssb155480 	if (rv != 0)
15986419Ssb155480 		return (B_FALSE);
15996419Ssb155480 
16006419Ssb155480 	return (B_TRUE);
16016419Ssb155480 }
16026419Ssb155480 
16036419Ssb155480 /*
16045935Ssb155480  * This function reads "priority-ether-types" property from md. This property
16055935Ssb155480  * is used to enable support for priority frames. Applications which need
16065935Ssb155480  * guaranteed and timely delivery of certain high priority frames to/from
16075935Ssb155480  * a vnet or vsw within ldoms, should configure this property by providing
16085935Ssb155480  * the ether type(s) for which the priority facility is needed.
16095935Ssb155480  * Normal data frames are delivered over a ldc channel using the descriptor
16105935Ssb155480  * ring mechanism which is constrained by factors such as descriptor ring size,
16115935Ssb155480  * the rate at which the ring is processed at the peer ldc end point, etc.
16125935Ssb155480  * The priority mechanism provides an Out-Of-Band path to send/receive frames
16135935Ssb155480  * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the
16145935Ssb155480  * descriptor ring path and enables a more reliable and timely delivery of
16155935Ssb155480  * frames to the peer.
16165935Ssb155480  */
16175935Ssb155480 static void
vgen_read_pri_eth_types(vgen_t * vgenp,md_t * mdp,mde_cookie_t node)16185935Ssb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node)
16195935Ssb155480 {
16205935Ssb155480 	int		rv;
16215935Ssb155480 	uint16_t	*types;
16225935Ssb155480 	uint64_t	*data;
16235935Ssb155480 	int		size;
16245935Ssb155480 	int		i;
16255935Ssb155480 	size_t		mblk_sz;
16265935Ssb155480 
16275935Ssb155480 	rv = md_get_prop_data(mdp, node, pri_types_propname,
16285935Ssb155480 	    (uint8_t **)&data, &size);
16295935Ssb155480 	if (rv != 0) {
16305935Ssb155480 		/*
16315935Ssb155480 		 * Property may not exist if we are running pre-ldoms1.1 f/w.
16325935Ssb155480 		 * Check if 'vgen_pri_eth_type' has been set in that case.
16335935Ssb155480 		 */
16345935Ssb155480 		if (vgen_pri_eth_type != 0) {
16355935Ssb155480 			size = sizeof (vgen_pri_eth_type);
16365935Ssb155480 			data = &vgen_pri_eth_type;
16375935Ssb155480 		} else {
16386495Sspeer 			DBG2(vgenp, NULL,
16395935Ssb155480 			    "prop(%s) not found", pri_types_propname);
16405935Ssb155480 			size = 0;
16415935Ssb155480 		}
16425935Ssb155480 	}
16435935Ssb155480 
16445935Ssb155480 	if (size == 0) {
16455935Ssb155480 		vgenp->pri_num_types = 0;
16465935Ssb155480 		return;
16475935Ssb155480 	}
16485935Ssb155480 
16495935Ssb155480 	/*
16505935Ssb155480 	 * we have some priority-ether-types defined;
16515935Ssb155480 	 * allocate a table of these types and also
16525935Ssb155480 	 * allocate a pool of mblks to transmit these
16535935Ssb155480 	 * priority packets.
16545935Ssb155480 	 */
16555935Ssb155480 	size /= sizeof (uint64_t);
16565935Ssb155480 	vgenp->pri_num_types = size;
16575935Ssb155480 	vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP);
16585935Ssb155480 	for (i = 0, types = vgenp->pri_types; i < size; i++) {
16595935Ssb155480 		types[i] = data[i] & 0xFFFF;
16605935Ssb155480 	}
16616419Ssb155480 	mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7;
166212011SSriharsha.Basavapatna@Sun.COM 	(void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, NULL,
16635935Ssb155480 	    &vgenp->pri_tx_vmp);
16645935Ssb155480 }
16655935Ssb155480 
16667529SSriharsha.Basavapatna@Sun.COM static void
vgen_mtu_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,uint32_t * mtu)16677529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu)
16687529SSriharsha.Basavapatna@Sun.COM {
16697529SSriharsha.Basavapatna@Sun.COM 	int		rv;
16707529SSriharsha.Basavapatna@Sun.COM 	uint64_t	val;
16717529SSriharsha.Basavapatna@Sun.COM 	char		*mtu_propname;
16727529SSriharsha.Basavapatna@Sun.COM 
16737529SSriharsha.Basavapatna@Sun.COM 	mtu_propname = vgen_mtu_propname;
16747529SSriharsha.Basavapatna@Sun.COM 
16757529SSriharsha.Basavapatna@Sun.COM 	rv = md_get_prop_val(mdp, node, mtu_propname, &val);
16767529SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
16777529SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname);
16787529SSriharsha.Basavapatna@Sun.COM 		*mtu = vnet_ethermtu;
16797529SSriharsha.Basavapatna@Sun.COM 	} else {
16807529SSriharsha.Basavapatna@Sun.COM 
16817529SSriharsha.Basavapatna@Sun.COM 		*mtu = val & 0xFFFF;
16827529SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname,
16837529SSriharsha.Basavapatna@Sun.COM 		    vgenp->instance, *mtu);
16847529SSriharsha.Basavapatna@Sun.COM 	}
16857529SSriharsha.Basavapatna@Sun.COM }
16867529SSriharsha.Basavapatna@Sun.COM 
16879336SSriharsha.Basavapatna@Sun.COM static void
vgen_linkprop_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,boolean_t * pls)16889336SSriharsha.Basavapatna@Sun.COM vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
16899336SSriharsha.Basavapatna@Sun.COM 	boolean_t *pls)
16909336SSriharsha.Basavapatna@Sun.COM {
16919336SSriharsha.Basavapatna@Sun.COM 	int		rv;
16929336SSriharsha.Basavapatna@Sun.COM 	uint64_t	val;
16939336SSriharsha.Basavapatna@Sun.COM 	char		*linkpropname;
16949336SSriharsha.Basavapatna@Sun.COM 
16959336SSriharsha.Basavapatna@Sun.COM 	linkpropname = vgen_linkprop_propname;
16969336SSriharsha.Basavapatna@Sun.COM 
16979336SSriharsha.Basavapatna@Sun.COM 	rv = md_get_prop_val(mdp, node, linkpropname, &val);
16989336SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
16999336SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, NULL, "prop(%s) not found", linkpropname);
17009336SSriharsha.Basavapatna@Sun.COM 		*pls = B_FALSE;
17019336SSriharsha.Basavapatna@Sun.COM 	} else {
17029336SSriharsha.Basavapatna@Sun.COM 
17039336SSriharsha.Basavapatna@Sun.COM 		*pls = (val & 0x1) ?  B_TRUE : B_FALSE;
17049336SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, NULL, "%s(%d): (%d)\n", linkpropname,
17059336SSriharsha.Basavapatna@Sun.COM 		    vgenp->instance, *pls);
17069336SSriharsha.Basavapatna@Sun.COM 	}
17079336SSriharsha.Basavapatna@Sun.COM }
17089336SSriharsha.Basavapatna@Sun.COM 
17091991Sheppo /* register with MD event generator */
17101991Sheppo static int
vgen_mdeg_reg(vgen_t * vgenp)17111991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
17121991Sheppo {
17131991Sheppo 	mdeg_prop_spec_t	*pspecp;
17141991Sheppo 	mdeg_node_spec_t	*parentp;
17151991Sheppo 	uint_t			templatesz;
17161991Sheppo 	int			rv;
17176419Ssb155480 	mdeg_handle_t		dev_hdl = NULL;
17186419Ssb155480 	mdeg_handle_t		port_hdl = NULL;
17196419Ssb155480 
17201991Sheppo 	templatesz = sizeof (vgen_prop_template);
17211991Sheppo 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
17221991Sheppo 	if (pspecp == NULL) {
17231991Sheppo 		return (DDI_FAILURE);
17241991Sheppo 	}
17251991Sheppo 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
17261991Sheppo 	if (parentp == NULL) {
17271991Sheppo 		kmem_free(pspecp, templatesz);
17281991Sheppo 		return (DDI_FAILURE);
17291991Sheppo 	}
17301991Sheppo 
17311991Sheppo 	bcopy(vgen_prop_template, pspecp, templatesz);
17321991Sheppo 
17331991Sheppo 	/*
17341991Sheppo 	 * NOTE: The instance here refers to the value of "reg" property and
17351991Sheppo 	 * not the dev_info instance (ddi_get_instance()) of vnet.
17361991Sheppo 	 */
17376419Ssb155480 	VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop);
17381991Sheppo 
17391991Sheppo 	parentp->namep = "virtual-device";
17401991Sheppo 	parentp->specp = pspecp;
17411991Sheppo 
17421991Sheppo 	/* save parentp in vgen_t */
17431991Sheppo 	vgenp->mdeg_parentp = parentp;
17441991Sheppo 
17456419Ssb155480 	/*
17466419Ssb155480 	 * Register an interest in 'virtual-device' nodes with a
17476419Ssb155480 	 * 'name' property of 'network'
17486419Ssb155480 	 */
17496419Ssb155480 	rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl);
17501991Sheppo 	if (rv != MDEG_SUCCESS) {
17514647Sraghuram 		DERR(vgenp, NULL, "mdeg_register failed\n");
17526419Ssb155480 		goto mdeg_reg_fail;
17536419Ssb155480 	}
17546419Ssb155480 
17556419Ssb155480 	/* Register an interest in 'port' nodes */
17566419Ssb155480 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp,
17576419Ssb155480 	    &port_hdl);
17586419Ssb155480 	if (rv != MDEG_SUCCESS) {
17596419Ssb155480 		DERR(vgenp, NULL, "mdeg_register failed\n");
17606419Ssb155480 		goto mdeg_reg_fail;
17611991Sheppo 	}
17621991Sheppo 
17631991Sheppo 	/* save mdeg handle in vgen_t */
17646419Ssb155480 	vgenp->mdeg_dev_hdl = dev_hdl;
17656419Ssb155480 	vgenp->mdeg_port_hdl = port_hdl;
17661991Sheppo 
17671991Sheppo 	return (DDI_SUCCESS);
17686419Ssb155480 
17696419Ssb155480 mdeg_reg_fail:
17706419Ssb155480 	if (dev_hdl != NULL) {
17716419Ssb155480 		(void) mdeg_unregister(dev_hdl);
17726419Ssb155480 	}
17736419Ssb155480 	KMEM_FREE(parentp);
17746419Ssb155480 	kmem_free(pspecp, templatesz);
17756419Ssb155480 	vgenp->mdeg_parentp = NULL;
17766419Ssb155480 	return (DDI_FAILURE);
17771991Sheppo }
17781991Sheppo 
17791991Sheppo /* unregister with MD event generator */
17801991Sheppo static void
vgen_mdeg_unreg(vgen_t * vgenp)17811991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
17821991Sheppo {
178310309SSriharsha.Basavapatna@Sun.COM 	if (vgenp->mdeg_dev_hdl != NULL) {
178410309SSriharsha.Basavapatna@Sun.COM 		(void) mdeg_unregister(vgenp->mdeg_dev_hdl);
178510309SSriharsha.Basavapatna@Sun.COM 		vgenp->mdeg_dev_hdl = NULL;
178610309SSriharsha.Basavapatna@Sun.COM 	}
178710309SSriharsha.Basavapatna@Sun.COM 	if (vgenp->mdeg_port_hdl != NULL) {
178810309SSriharsha.Basavapatna@Sun.COM 		(void) mdeg_unregister(vgenp->mdeg_port_hdl);
178910309SSriharsha.Basavapatna@Sun.COM 		vgenp->mdeg_port_hdl = NULL;
179010309SSriharsha.Basavapatna@Sun.COM 	}
179110309SSriharsha.Basavapatna@Sun.COM 
179210309SSriharsha.Basavapatna@Sun.COM 	if (vgenp->mdeg_parentp != NULL) {
179310309SSriharsha.Basavapatna@Sun.COM 		kmem_free(vgenp->mdeg_parentp->specp,
179410309SSriharsha.Basavapatna@Sun.COM 		    sizeof (vgen_prop_template));
179510309SSriharsha.Basavapatna@Sun.COM 		KMEM_FREE(vgenp->mdeg_parentp);
179610309SSriharsha.Basavapatna@Sun.COM 		vgenp->mdeg_parentp = NULL;
179710309SSriharsha.Basavapatna@Sun.COM 	}
17981991Sheppo }
17991991Sheppo 
18006419Ssb155480 /* mdeg callback function for the port node */
18011991Sheppo static int
vgen_mdeg_port_cb(void * cb_argp,mdeg_result_t * resp)18026419Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp)
18031991Sheppo {
180412011SSriharsha.Basavapatna@Sun.COM 	int		idx;
180512011SSriharsha.Basavapatna@Sun.COM 	int		vsw_idx = -1;
180612011SSriharsha.Basavapatna@Sun.COM 	uint64_t 	val;
180712011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp;
18081991Sheppo 
18091991Sheppo 	if ((resp == NULL) || (cb_argp == NULL)) {
18101991Sheppo 		return (MDEG_FAILURE);
18111991Sheppo 	}
18121991Sheppo 
18131991Sheppo 	vgenp = (vgen_t *)cb_argp;
18144647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
18151991Sheppo 
18161991Sheppo 	mutex_enter(&vgenp->lock);
18171991Sheppo 
18184647Sraghuram 	DBG1(vgenp, NULL, "ports: removed(%x), "
18194647Sraghuram 	"added(%x), updated(%x)\n", resp->removed.nelem,
18204647Sraghuram 	    resp->added.nelem, resp->match_curr.nelem);
18211991Sheppo 
18221991Sheppo 	for (idx = 0; idx < resp->removed.nelem; idx++) {
18231991Sheppo 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
18241991Sheppo 		    resp->removed.mdep[idx]);
18251991Sheppo 	}
18261991Sheppo 
18271991Sheppo 	if (vgenp->vsw_portp == NULL) {
18281991Sheppo 		/*
18291991Sheppo 		 * find vsw_port and add it first, because other ports need
18301991Sheppo 		 * this when adding fdb entry (see vgen_port_init()).
18311991Sheppo 		 */
18321991Sheppo 		for (idx = 0; idx < resp->added.nelem; idx++) {
18331991Sheppo 			if (!(md_get_prop_val(resp->added.mdp,
18341991Sheppo 			    resp->added.mdep[idx], swport_propname, &val))) {
18351991Sheppo 				if (val == 0) {
18361991Sheppo 					/*
18371991Sheppo 					 * This port is connected to the
18386419Ssb155480 					 * vsw on service domain.
18391991Sheppo 					 */
18401991Sheppo 					vsw_idx = idx;
18414663Szk194757 					if (vgen_add_port(vgenp,
18421991Sheppo 					    resp->added.mdp,
18434663Szk194757 					    resp->added.mdep[idx]) !=
18444663Szk194757 					    DDI_SUCCESS) {
18454663Szk194757 						cmn_err(CE_NOTE, "vnet%d Could "
18464663Szk194757 						    "not initialize virtual "
18474663Szk194757 						    "switch port.",
18486495Sspeer 						    vgenp->instance);
18494663Szk194757 						mutex_exit(&vgenp->lock);
18504663Szk194757 						return (MDEG_FAILURE);
18514663Szk194757 					}
18521991Sheppo 					break;
18531991Sheppo 				}
18541991Sheppo 			}
18551991Sheppo 		}
18564666Szk194757 		if (vsw_idx == -1) {
18574647Sraghuram 			DWARN(vgenp, NULL, "can't find vsw_port\n");
18584663Szk194757 			mutex_exit(&vgenp->lock);
18591991Sheppo 			return (MDEG_FAILURE);
18601991Sheppo 		}
18611991Sheppo 	}
18621991Sheppo 
18631991Sheppo 	for (idx = 0; idx < resp->added.nelem; idx++) {
18641991Sheppo 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
18651991Sheppo 			continue;
18664663Szk194757 
18674663Szk194757 		/* If this port can't be added just skip it. */
18681991Sheppo 		(void) vgen_add_port(vgenp, resp->added.mdp,
18691991Sheppo 		    resp->added.mdep[idx]);
18701991Sheppo 	}
18711991Sheppo 
18721991Sheppo 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
18731991Sheppo 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
18741991Sheppo 		    resp->match_curr.mdep[idx],
18751991Sheppo 		    resp->match_prev.mdp,
18761991Sheppo 		    resp->match_prev.mdep[idx]);
18771991Sheppo 	}
18781991Sheppo 
18791991Sheppo 	mutex_exit(&vgenp->lock);
18804647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
18811991Sheppo 	return (MDEG_SUCCESS);
18821991Sheppo }
18831991Sheppo 
18846419Ssb155480 /* mdeg callback function for the vnet node */
18856419Ssb155480 static int
vgen_mdeg_cb(void * cb_argp,mdeg_result_t * resp)18866419Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
18876419Ssb155480 {
18886419Ssb155480 	vgen_t		*vgenp;
18896419Ssb155480 	vnet_t		*vnetp;
18906419Ssb155480 	md_t		*mdp;
18916419Ssb155480 	mde_cookie_t	node;
18926419Ssb155480 	uint64_t	inst;
18936419Ssb155480 	char		*node_name = NULL;
18946419Ssb155480 
18956419Ssb155480 	if ((resp == NULL) || (cb_argp == NULL)) {
18966419Ssb155480 		return (MDEG_FAILURE);
18976419Ssb155480 	}
18986419Ssb155480 
18996419Ssb155480 	vgenp = (vgen_t *)cb_argp;
19006419Ssb155480 	vnetp = vgenp->vnetp;
19016419Ssb155480 
19027572SWentao.Yang@Sun.COM 	DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d"
19036419Ssb155480 	    " : prev matched %d", resp->added.nelem, resp->removed.nelem,
19046419Ssb155480 	    resp->match_curr.nelem, resp->match_prev.nelem);
19056419Ssb155480 
19066419Ssb155480 	mutex_enter(&vgenp->lock);
19076419Ssb155480 
19086419Ssb155480 	/*
19096419Ssb155480 	 * We get an initial callback for this node as 'added' after
19106419Ssb155480 	 * registering with mdeg. Note that we would have already gathered
19116419Ssb155480 	 * information about this vnet node by walking MD earlier during attach
19126419Ssb155480 	 * (in vgen_read_mdprops()). So, there is a window where the properties
19136419Ssb155480 	 * of this node might have changed when we get this initial 'added'
19146419Ssb155480 	 * callback. We handle this as if an update occured and invoke the same
19156419Ssb155480 	 * function which handles updates to the properties of this vnet-node
19166419Ssb155480 	 * if any. A non-zero 'match' value indicates that the MD has been
19176419Ssb155480 	 * updated and that a 'network' node is present which may or may not
19186419Ssb155480 	 * have been updated. It is up to the clients to examine their own
19196419Ssb155480 	 * nodes and determine if they have changed.
19206419Ssb155480 	 */
19216419Ssb155480 	if (resp->added.nelem != 0) {
19226419Ssb155480 
19236419Ssb155480 		if (resp->added.nelem != 1) {
19246419Ssb155480 			cmn_err(CE_NOTE, "!vnet%d: number of nodes added "
19256419Ssb155480 			    "invalid: %d\n", vnetp->instance,
19266419Ssb155480 			    resp->added.nelem);
19276419Ssb155480 			goto vgen_mdeg_cb_err;
19286419Ssb155480 		}
19296419Ssb155480 
19306419Ssb155480 		mdp = resp->added.mdp;
19316419Ssb155480 		node = resp->added.mdep[0];
19326419Ssb155480 
19336419Ssb155480 	} else if (resp->match_curr.nelem != 0) {
19346419Ssb155480 
19356419Ssb155480 		if (resp->match_curr.nelem != 1) {
19366419Ssb155480 			cmn_err(CE_NOTE, "!vnet%d: number of nodes updated "
19376419Ssb155480 			    "invalid: %d\n", vnetp->instance,
19386419Ssb155480 			    resp->match_curr.nelem);
19396419Ssb155480 			goto vgen_mdeg_cb_err;
19406419Ssb155480 		}
19416419Ssb155480 
19426419Ssb155480 		mdp = resp->match_curr.mdp;
19436419Ssb155480 		node = resp->match_curr.mdep[0];
19446419Ssb155480 
19456419Ssb155480 	} else {
19466419Ssb155480 		goto vgen_mdeg_cb_err;
19476419Ssb155480 	}
19486419Ssb155480 
19496419Ssb155480 	/* Validate name and instance */
19506419Ssb155480 	if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
19516419Ssb155480 		DERR(vgenp, NULL, "unable to get node name\n");
19526419Ssb155480 		goto vgen_mdeg_cb_err;
19536419Ssb155480 	}
19546419Ssb155480 
19556419Ssb155480 	/* is this a virtual-network device? */
19566419Ssb155480 	if (strcmp(node_name, vnet_propname) != 0) {
19576419Ssb155480 		DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name);
19586419Ssb155480 		goto vgen_mdeg_cb_err;
19596419Ssb155480 	}
19606419Ssb155480 
19616419Ssb155480 	if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
19626419Ssb155480 		DERR(vgenp, NULL, "prop(cfg-handle) not found\n");
19636419Ssb155480 		goto vgen_mdeg_cb_err;
19646419Ssb155480 	}
19656419Ssb155480 
19666495Sspeer 	/* is this the right instance of vnet? */
19676419Ssb155480 	if (inst != vgenp->regprop) {
19686419Ssb155480 		DERR(vgenp, NULL,  "Invalid cfg-handle: %lx\n", inst);
19696419Ssb155480 		goto vgen_mdeg_cb_err;
19706419Ssb155480 	}
19716419Ssb155480 
19726419Ssb155480 	vgen_update_md_prop(vgenp, mdp, node);
19736419Ssb155480 
19746419Ssb155480 	mutex_exit(&vgenp->lock);
19756419Ssb155480 	return (MDEG_SUCCESS);
19766419Ssb155480 
19776419Ssb155480 vgen_mdeg_cb_err:
19786419Ssb155480 	mutex_exit(&vgenp->lock);
19796419Ssb155480 	return (MDEG_FAILURE);
19806419Ssb155480 }
19816419Ssb155480 
19826419Ssb155480 /*
19836419Ssb155480  * Check to see if the relevant properties in the specified node have
19846419Ssb155480  * changed, and if so take the appropriate action.
19856419Ssb155480  */
19866419Ssb155480 static void
vgen_update_md_prop(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)19876419Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
19886419Ssb155480 {
19896419Ssb155480 	uint16_t	pvid;
19906419Ssb155480 	uint16_t	*vids;
19916419Ssb155480 	uint16_t	nvids;
19926419Ssb155480 	vnet_t		*vnetp = vgenp->vnetp;
19937529SSriharsha.Basavapatna@Sun.COM 	uint32_t	mtu;
19949336SSriharsha.Basavapatna@Sun.COM 	boolean_t	pls_update;
19957529SSriharsha.Basavapatna@Sun.COM 	enum		{ MD_init = 0x1,
19967529SSriharsha.Basavapatna@Sun.COM 			    MD_vlans = 0x2,
19979336SSriharsha.Basavapatna@Sun.COM 			    MD_mtu = 0x4,
19989336SSriharsha.Basavapatna@Sun.COM 			    MD_pls = 0x8 } updated;
19997529SSriharsha.Basavapatna@Sun.COM 	int		rv;
20007529SSriharsha.Basavapatna@Sun.COM 
20017529SSriharsha.Basavapatna@Sun.COM 	updated = MD_init;
20026419Ssb155480 
20036419Ssb155480 	/* Read the vlan ids */
20046419Ssb155480 	vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids,
20056419Ssb155480 	    &nvids, NULL);
20066419Ssb155480 
20076419Ssb155480 	/* Determine if there are any vlan id updates */
20086419Ssb155480 	if ((pvid != vnetp->pvid) ||		/* pvid changed? */
20096419Ssb155480 	    (nvids != vnetp->nvids) ||		/* # of vids changed? */
20106419Ssb155480 	    ((nvids != 0) && (vnetp->nvids != 0) &&	/* vids changed? */
20116419Ssb155480 	    bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) {
20127529SSriharsha.Basavapatna@Sun.COM 		updated |= MD_vlans;
20137529SSriharsha.Basavapatna@Sun.COM 	}
20147529SSriharsha.Basavapatna@Sun.COM 
20157529SSriharsha.Basavapatna@Sun.COM 	/* Read mtu */
20167529SSriharsha.Basavapatna@Sun.COM 	vgen_mtu_read(vgenp, mdp, mdex, &mtu);
20177529SSriharsha.Basavapatna@Sun.COM 	if (mtu != vnetp->mtu) {
20187529SSriharsha.Basavapatna@Sun.COM 		if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) {
20197529SSriharsha.Basavapatna@Sun.COM 			updated |= MD_mtu;
20207529SSriharsha.Basavapatna@Sun.COM 		} else {
20217529SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update"
20227529SSriharsha.Basavapatna@Sun.COM 			    " as the specified value:%d is invalid\n",
20237529SSriharsha.Basavapatna@Sun.COM 			    vnetp->instance, mtu);
20247529SSriharsha.Basavapatna@Sun.COM 		}
20257529SSriharsha.Basavapatna@Sun.COM 	}
20267529SSriharsha.Basavapatna@Sun.COM 
20279336SSriharsha.Basavapatna@Sun.COM 	/*
20289336SSriharsha.Basavapatna@Sun.COM 	 * Read the 'linkprop' property.
20299336SSriharsha.Basavapatna@Sun.COM 	 */
20309336SSriharsha.Basavapatna@Sun.COM 	vgen_linkprop_read(vgenp, mdp, mdex, &pls_update);
20319336SSriharsha.Basavapatna@Sun.COM 	if (pls_update != vnetp->pls_update) {
20329336SSriharsha.Basavapatna@Sun.COM 		updated |= MD_pls;
20339336SSriharsha.Basavapatna@Sun.COM 	}
20349336SSriharsha.Basavapatna@Sun.COM 
20357529SSriharsha.Basavapatna@Sun.COM 	/* Now process the updated props */
20367529SSriharsha.Basavapatna@Sun.COM 
20377529SSriharsha.Basavapatna@Sun.COM 	if (updated & MD_vlans) {
20387529SSriharsha.Basavapatna@Sun.COM 
20397529SSriharsha.Basavapatna@Sun.COM 		/* save the new vlan ids */
20407529SSriharsha.Basavapatna@Sun.COM 		vnetp->pvid = pvid;
20417529SSriharsha.Basavapatna@Sun.COM 		if (vnetp->nvids != 0) {
20427529SSriharsha.Basavapatna@Sun.COM 			kmem_free(vnetp->vids,
20437529SSriharsha.Basavapatna@Sun.COM 			    sizeof (uint16_t) * vnetp->nvids);
20447529SSriharsha.Basavapatna@Sun.COM 			vnetp->nvids = 0;
20457529SSriharsha.Basavapatna@Sun.COM 		}
20467529SSriharsha.Basavapatna@Sun.COM 		if (nvids != 0) {
20477529SSriharsha.Basavapatna@Sun.COM 			vnetp->nvids = nvids;
20487529SSriharsha.Basavapatna@Sun.COM 			vnetp->vids = vids;
20497529SSriharsha.Basavapatna@Sun.COM 		}
20507529SSriharsha.Basavapatna@Sun.COM 
20517529SSriharsha.Basavapatna@Sun.COM 		/* reset vlan-unaware peers (ver < 1.3) and restart handshake */
20527529SSriharsha.Basavapatna@Sun.COM 		vgen_reset_vlan_unaware_ports(vgenp);
20537529SSriharsha.Basavapatna@Sun.COM 
20547529SSriharsha.Basavapatna@Sun.COM 	} else {
20557529SSriharsha.Basavapatna@Sun.COM 
20566419Ssb155480 		if (nvids != 0) {
20576419Ssb155480 			kmem_free(vids, sizeof (uint16_t) * nvids);
20586419Ssb155480 		}
20597529SSriharsha.Basavapatna@Sun.COM 	}
20607529SSriharsha.Basavapatna@Sun.COM 
20617529SSriharsha.Basavapatna@Sun.COM 	if (updated & MD_mtu) {
20627529SSriharsha.Basavapatna@Sun.COM 
20637529SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n",
20647529SSriharsha.Basavapatna@Sun.COM 		    vnetp->mtu, mtu);
20657529SSriharsha.Basavapatna@Sun.COM 
20667529SSriharsha.Basavapatna@Sun.COM 		rv = vnet_mtu_update(vnetp, mtu);
20677529SSriharsha.Basavapatna@Sun.COM 		if (rv == 0) {
20687529SSriharsha.Basavapatna@Sun.COM 			vgenp->max_frame_size = mtu +
20697529SSriharsha.Basavapatna@Sun.COM 			    sizeof (struct ether_header) + VLAN_TAGSZ;
20707529SSriharsha.Basavapatna@Sun.COM 		}
20717529SSriharsha.Basavapatna@Sun.COM 	}
20729336SSriharsha.Basavapatna@Sun.COM 
20739336SSriharsha.Basavapatna@Sun.COM 	if (updated & MD_pls) {
20749336SSriharsha.Basavapatna@Sun.COM 		/* enable/disable physical link state updates */
20759336SSriharsha.Basavapatna@Sun.COM 		vnetp->pls_update = pls_update;
20769647SWentao.Yang@Sun.COM 		mutex_exit(&vgenp->lock);
20779336SSriharsha.Basavapatna@Sun.COM 
20789336SSriharsha.Basavapatna@Sun.COM 		/* reset vsw-port to re-negotiate with the updated prop. */
20799336SSriharsha.Basavapatna@Sun.COM 		vgen_reset_vsw_port(vgenp);
20809647SWentao.Yang@Sun.COM 
20819647SWentao.Yang@Sun.COM 		mutex_enter(&vgenp->lock);
20829336SSriharsha.Basavapatna@Sun.COM 	}
20836419Ssb155480 }
20846419Ssb155480 
20851991Sheppo /* add a new port to the device */
20861991Sheppo static int
vgen_add_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)20871991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
20881991Sheppo {
20896419Ssb155480 	vgen_port_t	*portp;
20906419Ssb155480 	int		rv;
20916419Ssb155480 
20926419Ssb155480 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP);
20936419Ssb155480 
20946419Ssb155480 	rv = vgen_port_read_props(portp, vgenp, mdp, mdex);
20956419Ssb155480 	if (rv != DDI_SUCCESS) {
20966419Ssb155480 		KMEM_FREE(portp);
20976419Ssb155480 		return (DDI_FAILURE);
20986419Ssb155480 	}
20996419Ssb155480 
21006419Ssb155480 	rv = vgen_port_attach(portp);
21016419Ssb155480 	if (rv != DDI_SUCCESS) {
21026419Ssb155480 		return (DDI_FAILURE);
21036419Ssb155480 	}
21046419Ssb155480 
21056419Ssb155480 	return (DDI_SUCCESS);
21066419Ssb155480 }
21076419Ssb155480 
21086419Ssb155480 /* read properties of the port from its md node */
21096419Ssb155480 static int
vgen_port_read_props(vgen_port_t * portp,vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)21106419Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
21116419Ssb155480 	mde_cookie_t mdex)
21126419Ssb155480 {
21136419Ssb155480 	uint64_t		port_num;
21146419Ssb155480 	uint64_t		*ldc_ids;
21156419Ssb155480 	uint64_t		macaddr;
21166419Ssb155480 	uint64_t		val;
21176419Ssb155480 	int			num_ldcs;
21186419Ssb155480 	int			i;
21196419Ssb155480 	int			addrsz;
21206419Ssb155480 	int			num_nodes = 0;
21216419Ssb155480 	int			listsz = 0;
21226419Ssb155480 	mde_cookie_t		*listp = NULL;
21236419Ssb155480 	uint8_t			*addrp;
21241991Sheppo 	struct ether_addr	ea;
21251991Sheppo 
21261991Sheppo 	/* read "id" property to get the port number */
21271991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
21284647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
21291991Sheppo 		return (DDI_FAILURE);
21301991Sheppo 	}
21311991Sheppo 
21321991Sheppo 	/*
21331991Sheppo 	 * Find the channel endpoint node(s) under this port node.
21341991Sheppo 	 */
21351991Sheppo 	if ((num_nodes = md_node_count(mdp)) <= 0) {
21364647Sraghuram 		DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
21374647Sraghuram 		    num_nodes);
21381991Sheppo 		return (DDI_FAILURE);
21391991Sheppo 	}
21401991Sheppo 
21411991Sheppo 	/* allocate space for node list */
21421991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
21431991Sheppo 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
21441991Sheppo 	if (listp == NULL)
21451991Sheppo 		return (DDI_FAILURE);
21461991Sheppo 
21471991Sheppo 	num_ldcs = md_scan_dag(mdp, mdex,
21484650Sraghuram 	    md_find_name(mdp, channel_propname),
21494650Sraghuram 	    md_find_name(mdp, "fwd"), listp);
21501991Sheppo 
21511991Sheppo 	if (num_ldcs <= 0) {
21524647Sraghuram 		DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
21531991Sheppo 		kmem_free(listp, listsz);
21541991Sheppo 		return (DDI_FAILURE);
21551991Sheppo 	}
21561991Sheppo 
215712011SSriharsha.Basavapatna@Sun.COM 	if (num_ldcs > 1) {
215812011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, NULL, "Port %d: Number of channels %d > 1\n",
215912011SSriharsha.Basavapatna@Sun.COM 		    port_num, num_ldcs);
216012011SSriharsha.Basavapatna@Sun.COM 	}
21611991Sheppo 
21621991Sheppo 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
21631991Sheppo 	if (ldc_ids == NULL) {
21641991Sheppo 		kmem_free(listp, listsz);
21651991Sheppo 		return (DDI_FAILURE);
21661991Sheppo 	}
21671991Sheppo 
21681991Sheppo 	for (i = 0; i < num_ldcs; i++) {
21691991Sheppo 		/* read channel ids */
21701991Sheppo 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
21714647Sraghuram 			DWARN(vgenp, NULL, "prop(%s) not found\n",
21724647Sraghuram 			    id_propname);
21731991Sheppo 			kmem_free(listp, listsz);
21741991Sheppo 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21751991Sheppo 			return (DDI_FAILURE);
21761991Sheppo 		}
21774647Sraghuram 		DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]);
21781991Sheppo 	}
21791991Sheppo 
21801991Sheppo 	kmem_free(listp, listsz);
21811991Sheppo 
21821991Sheppo 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
21831991Sheppo 	    &addrsz)) {
21844647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
21851991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21861991Sheppo 		return (DDI_FAILURE);
21871991Sheppo 	}
21881991Sheppo 
21891991Sheppo 	if (addrsz < ETHERADDRL) {
21904647Sraghuram 		DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
21911991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21921991Sheppo 		return (DDI_FAILURE);
21931991Sheppo 	}
21941991Sheppo 
21951991Sheppo 	macaddr = *((uint64_t *)addrp);
21961991Sheppo 
21974647Sraghuram 	DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
21981991Sheppo 
21991991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
22001991Sheppo 		ea.ether_addr_octet[i] = macaddr & 0xFF;
22011991Sheppo 		macaddr >>= 8;
22021991Sheppo 	}
22031991Sheppo 
22049336SSriharsha.Basavapatna@Sun.COM 	if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
22059336SSriharsha.Basavapatna@Sun.COM 		if (val == 0) {
22069336SSriharsha.Basavapatna@Sun.COM 			/* This port is connected to the vswitch */
22079336SSriharsha.Basavapatna@Sun.COM 			portp->is_vsw_port = B_TRUE;
22089336SSriharsha.Basavapatna@Sun.COM 		} else {
22099336SSriharsha.Basavapatna@Sun.COM 			portp->is_vsw_port = B_FALSE;
22101991Sheppo 		}
22111991Sheppo 	}
22126419Ssb155480 
22136419Ssb155480 	/* now update all properties into the port */
22146419Ssb155480 	portp->vgenp = vgenp;
22156419Ssb155480 	portp->port_num = port_num;
22166419Ssb155480 	ether_copy(&ea, &portp->macaddr);
22176419Ssb155480 	portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP);
22186419Ssb155480 	bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs);
22196419Ssb155480 	portp->num_ldcs = num_ldcs;
22206419Ssb155480 
22216419Ssb155480 	/* read vlan id properties of this port node */
22226419Ssb155480 	vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid,
22236419Ssb155480 	    &portp->vids, &portp->nvids, NULL);
22241991Sheppo 
22251991Sheppo 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
22261991Sheppo 
22276419Ssb155480 	return (DDI_SUCCESS);
22281991Sheppo }
22291991Sheppo 
22301991Sheppo /* remove a port from the device */
22311991Sheppo static int
vgen_remove_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)22321991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
22331991Sheppo {
22341991Sheppo 	uint64_t	port_num;
22351991Sheppo 	vgen_port_t	*portp;
22361991Sheppo 	vgen_portlist_t	*plistp;
22371991Sheppo 
22381991Sheppo 	/* read "id" property to get the port number */
22391991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
22404647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
22411991Sheppo 		return (DDI_FAILURE);
22421991Sheppo 	}
22431991Sheppo 
22441991Sheppo 	plistp = &(vgenp->vgenports);
22451991Sheppo 
22461991Sheppo 	WRITE_ENTER(&plistp->rwlock);
22471991Sheppo 	portp = vgen_port_lookup(plistp, (int)port_num);
22481991Sheppo 	if (portp == NULL) {
22494647Sraghuram 		DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
22501991Sheppo 		RW_EXIT(&plistp->rwlock);
22511991Sheppo 		return (DDI_FAILURE);
22521991Sheppo 	}
22531991Sheppo 
22541991Sheppo 	vgen_port_detach_mdeg(portp);
22551991Sheppo 	RW_EXIT(&plistp->rwlock);
22561991Sheppo 
22571991Sheppo 	return (DDI_SUCCESS);
22581991Sheppo }
22591991Sheppo 
22601991Sheppo /* attach a port to the device based on mdeg data */
22611991Sheppo static int
vgen_port_attach(vgen_port_t * portp)22626419Ssb155480 vgen_port_attach(vgen_port_t *portp)
22631991Sheppo {
22646419Ssb155480 	vgen_portlist_t		*plistp;
22656419Ssb155480 	vgen_t			*vgenp;
22666419Ssb155480 	uint64_t		*ldcids;
22676495Sspeer 	mac_register_t		*macp;
22686495Sspeer 	vio_net_res_type_t	type;
22696495Sspeer 	int			rv;
22706419Ssb155480 
22716419Ssb155480 	ASSERT(portp != NULL);
22726419Ssb155480 	vgenp = portp->vgenp;
22736419Ssb155480 	ldcids = portp->ldc_ids;
227412011SSriharsha.Basavapatna@Sun.COM 
227512011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, NULL, "port_num(%d), ldcid(%lx)\n",
227612011SSriharsha.Basavapatna@Sun.COM 	    portp->port_num, ldcids[0]);
22771991Sheppo 
22786495Sspeer 	mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL);
227912011SSriharsha.Basavapatna@Sun.COM 
228012011SSriharsha.Basavapatna@Sun.COM 	/*
228112011SSriharsha.Basavapatna@Sun.COM 	 * attach the channel under the port using its channel id;
228212011SSriharsha.Basavapatna@Sun.COM 	 * note that we only support one channel per port for now.
228312011SSriharsha.Basavapatna@Sun.COM 	 */
228412011SSriharsha.Basavapatna@Sun.COM 	if (vgen_ldc_attach(portp, ldcids[0]) == DDI_FAILURE) {
228512011SSriharsha.Basavapatna@Sun.COM 		vgen_port_detach(portp);
228612011SSriharsha.Basavapatna@Sun.COM 		return (DDI_FAILURE);
22871991Sheppo 	}
22881991Sheppo 
22896419Ssb155480 	/* create vlan id hash table */
22906419Ssb155480 	vgen_vlan_create_hash(portp);
22916419Ssb155480 
22929336SSriharsha.Basavapatna@Sun.COM 	if (portp->is_vsw_port == B_TRUE) {
22936495Sspeer 		/* This port is connected to the switch port */
22946495Sspeer 		(void) atomic_swap_32(&portp->use_vsw_port, B_FALSE);
22956495Sspeer 		type = VIO_NET_RES_LDC_SERVICE;
22966495Sspeer 	} else {
22976495Sspeer 		(void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
22986495Sspeer 		type = VIO_NET_RES_LDC_GUEST;
22996495Sspeer 	}
23006495Sspeer 
23016495Sspeer 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
23026495Sspeer 		vgen_port_detach(portp);
23036495Sspeer 		return (DDI_FAILURE);
23046495Sspeer 	}
23056495Sspeer 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
23066495Sspeer 	macp->m_driver = portp;
23076495Sspeer 	macp->m_dip = vgenp->vnetdip;
23086495Sspeer 	macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
23096495Sspeer 	macp->m_callbacks = &vgen_m_callbacks;
23106495Sspeer 	macp->m_min_sdu = 0;
23116495Sspeer 	macp->m_max_sdu = ETHERMTU;
23126495Sspeer 
23136495Sspeer 	mutex_enter(&portp->lock);
23146495Sspeer 	rv = vio_net_resource_reg(macp, type, vgenp->macaddr,
23156495Sspeer 	    portp->macaddr, &portp->vhp, &portp->vcb);
23166495Sspeer 	mutex_exit(&portp->lock);
23176495Sspeer 	mac_free(macp);
23186495Sspeer 
23196495Sspeer 	if (rv == 0) {
23206495Sspeer 		/* link it into the list of ports */
23216495Sspeer 		plistp = &(vgenp->vgenports);
23226495Sspeer 		WRITE_ENTER(&plistp->rwlock);
23236495Sspeer 		vgen_port_list_insert(portp);
23246495Sspeer 		RW_EXIT(&plistp->rwlock);
23259336SSriharsha.Basavapatna@Sun.COM 
23269336SSriharsha.Basavapatna@Sun.COM 		if (portp->is_vsw_port == B_TRUE) {
23279336SSriharsha.Basavapatna@Sun.COM 			/* We now have the vswitch port attached */
23289336SSriharsha.Basavapatna@Sun.COM 			vgenp->vsw_portp = portp;
23299336SSriharsha.Basavapatna@Sun.COM 			(void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
23309336SSriharsha.Basavapatna@Sun.COM 		}
23316495Sspeer 	} else {
23326495Sspeer 		DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p",
23336495Sspeer 		    portp);
23346495Sspeer 		vgen_port_detach(portp);
23351991Sheppo 	}
23361991Sheppo 
23374647Sraghuram 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23381991Sheppo 	return (DDI_SUCCESS);
23391991Sheppo }
23401991Sheppo 
23411991Sheppo /* detach a port from the device based on mdeg data */
23421991Sheppo static void
vgen_port_detach_mdeg(vgen_port_t * portp)23431991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
23441991Sheppo {
23451991Sheppo 	vgen_t *vgenp = portp->vgenp;
23461991Sheppo 
23474647Sraghuram 	DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
23486495Sspeer 
23496495Sspeer 	mutex_enter(&portp->lock);
23506495Sspeer 
23511991Sheppo 	/* stop the port if needed */
23526495Sspeer 	if (portp->flags & VGEN_STARTED) {
23531991Sheppo 		vgen_port_uninit(portp);
235411543SWentao.Yang@Sun.COM 		portp->flags &= ~(VGEN_STARTED);
23551991Sheppo 	}
23566495Sspeer 
23576495Sspeer 	mutex_exit(&portp->lock);
23581991Sheppo 	vgen_port_detach(portp);
23591991Sheppo 
23604647Sraghuram 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23611991Sheppo }
23621991Sheppo 
23631991Sheppo 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)23641991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
23651991Sheppo 	md_t *prev_mdp, mde_cookie_t prev_mdex)
23661991Sheppo {
23676419Ssb155480 	uint64_t	cport_num;
23686419Ssb155480 	uint64_t	pport_num;
23696419Ssb155480 	vgen_portlist_t	*plistp;
23706419Ssb155480 	vgen_port_t	*portp;
23716419Ssb155480 	boolean_t	updated_vlans = B_FALSE;
23726419Ssb155480 	uint16_t	pvid;
23736419Ssb155480 	uint16_t	*vids;
23746419Ssb155480 	uint16_t	nvids;
23756419Ssb155480 
23766419Ssb155480 	/*
23776419Ssb155480 	 * For now, we get port updates only if vlan ids changed.
23786419Ssb155480 	 * We read the port num and do some sanity check.
23796419Ssb155480 	 */
23806419Ssb155480 	if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) {
23816419Ssb155480 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
23826419Ssb155480 		return (DDI_FAILURE);
23836419Ssb155480 	}
23846419Ssb155480 
23856419Ssb155480 	if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) {
23866419Ssb155480 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
23876419Ssb155480 		return (DDI_FAILURE);
23886419Ssb155480 	}
23896419Ssb155480 	if (cport_num != pport_num)
23906419Ssb155480 		return (DDI_FAILURE);
23916419Ssb155480 
23926419Ssb155480 	plistp = &(vgenp->vgenports);
23936419Ssb155480 
23946419Ssb155480 	READ_ENTER(&plistp->rwlock);
23956419Ssb155480 
23966419Ssb155480 	portp = vgen_port_lookup(plistp, (int)cport_num);
23976419Ssb155480 	if (portp == NULL) {
23986419Ssb155480 		DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num);
23996419Ssb155480 		RW_EXIT(&plistp->rwlock);
24006419Ssb155480 		return (DDI_FAILURE);
24016419Ssb155480 	}
24026419Ssb155480 
24036419Ssb155480 	/* Read the vlan ids */
24046419Ssb155480 	vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids,
24056419Ssb155480 	    &nvids, NULL);
24066419Ssb155480 
24076419Ssb155480 	/* Determine if there are any vlan id updates */
24086419Ssb155480 	if ((pvid != portp->pvid) ||		/* pvid changed? */
24096419Ssb155480 	    (nvids != portp->nvids) ||		/* # of vids changed? */
24106419Ssb155480 	    ((nvids != 0) && (portp->nvids != 0) &&	/* vids changed? */
24116419Ssb155480 	    bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) {
24126419Ssb155480 		updated_vlans = B_TRUE;
24136419Ssb155480 	}
24146419Ssb155480 
24156419Ssb155480 	if (updated_vlans == B_FALSE) {
24166419Ssb155480 		RW_EXIT(&plistp->rwlock);
24176419Ssb155480 		return (DDI_FAILURE);
24186419Ssb155480 	}
24196419Ssb155480 
24206419Ssb155480 	/* remove the port from vlans it has been assigned to */
24216419Ssb155480 	vgen_vlan_remove_ids(portp);
24226419Ssb155480 
24236419Ssb155480 	/* save the new vlan ids */
24246419Ssb155480 	portp->pvid = pvid;
24256419Ssb155480 	if (portp->nvids != 0) {
24266419Ssb155480 		kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids);
24276419Ssb155480 		portp->nvids = 0;
24286419Ssb155480 	}
24296419Ssb155480 	if (nvids != 0) {
24306419Ssb155480 		portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP);
24316419Ssb155480 		bcopy(vids, portp->vids, sizeof (uint16_t) * nvids);
24326419Ssb155480 		portp->nvids = nvids;
24336419Ssb155480 		kmem_free(vids, sizeof (uint16_t) * nvids);
24346419Ssb155480 	}
24356419Ssb155480 
24366419Ssb155480 	/* add port to the new vlans */
24376419Ssb155480 	vgen_vlan_add_ids(portp);
24386419Ssb155480 
24396419Ssb155480 	/* reset the port if it is vlan unaware (ver < 1.3) */
24406419Ssb155480 	vgen_vlan_unaware_port_reset(portp);
24416419Ssb155480 
24426419Ssb155480 	RW_EXIT(&plistp->rwlock);
24436419Ssb155480 
24441991Sheppo 	return (DDI_SUCCESS);
24451991Sheppo }
24461991Sheppo 
24471991Sheppo static uint64_t
vgen_port_stat(vgen_port_t * portp,uint_t stat)24482311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
24491991Sheppo {
245012011SSriharsha.Basavapatna@Sun.COM 	return (vgen_ldc_stat(portp->ldcp, stat));
24517529SSriharsha.Basavapatna@Sun.COM }
24527529SSriharsha.Basavapatna@Sun.COM 
24531991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
24541991Sheppo static int
vgen_ldc_attach(vgen_port_t * portp,uint64_t ldc_id)24551991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
24561991Sheppo {
24571991Sheppo 	vgen_t 		*vgenp;
245812011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t 	*ldcp;
24591991Sheppo 	ldc_attr_t 	attr;
24601991Sheppo 	int 		status;
24611991Sheppo 	ldc_status_t	istatus;
24625373Sraghuram 	char		kname[MAXNAMELEN];
24635373Sraghuram 	int		instance;
24644647Sraghuram 	enum	{AST_init = 0x0, AST_ldc_alloc = 0x1,
24654647Sraghuram 		AST_mutex_init = 0x2, AST_ldc_init = 0x4,
246612011SSriharsha.Basavapatna@Sun.COM 		AST_ldc_reg_cb = 0x8 } attach_state;
24671991Sheppo 
24681991Sheppo 	attach_state = AST_init;
24691991Sheppo 	vgenp = portp->vgenp;
24701991Sheppo 
24711991Sheppo 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
24721991Sheppo 	if (ldcp == NULL) {
24731991Sheppo 		goto ldc_attach_failed;
24741991Sheppo 	}
24751991Sheppo 	ldcp->ldc_id = ldc_id;
24761991Sheppo 	ldcp->portp = portp;
24771991Sheppo 
24781991Sheppo 	attach_state |= AST_ldc_alloc;
24791991Sheppo 
24801991Sheppo 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
24811991Sheppo 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
24821991Sheppo 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
24834647Sraghuram 	mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
24844647Sraghuram 	mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
248510309SSriharsha.Basavapatna@Sun.COM 	mutex_init(&ldcp->pollq_lock, NULL, MUTEX_DRIVER, NULL);
248612011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL);
248712011SSriharsha.Basavapatna@Sun.COM 	cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL);
24881991Sheppo 
24891991Sheppo 	attach_state |= AST_mutex_init;
24901991Sheppo 
24911991Sheppo 	attr.devclass = LDC_DEV_NT;
24926495Sspeer 	attr.instance = vgenp->instance;
24931991Sheppo 	attr.mode = LDC_MODE_UNRELIABLE;
249412011SSriharsha.Basavapatna@Sun.COM 	attr.mtu = vgen_ldc_mtu;
24951991Sheppo 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
24961991Sheppo 	if (status != 0) {
24974647Sraghuram 		DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
24981991Sheppo 		goto ldc_attach_failed;
24991991Sheppo 	}
25001991Sheppo 	attach_state |= AST_ldc_init;
25011991Sheppo 
25021991Sheppo 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
25031991Sheppo 	if (status != 0) {
25044647Sraghuram 		DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
25054647Sraghuram 		    status);
25061991Sheppo 		goto ldc_attach_failed;
25071991Sheppo 	}
25085935Ssb155480 	/*
25095935Ssb155480 	 * allocate a message for ldc_read()s, big enough to hold ctrl and
25105935Ssb155480 	 * data msgs, including raw data msgs used to recv priority frames.
25115935Ssb155480 	 */
25126419Ssb155480 	ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size;
25135935Ssb155480 	ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
25141991Sheppo 	attach_state |= AST_ldc_reg_cb;
25151991Sheppo 
25161991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
25171991Sheppo 	ASSERT(istatus == LDC_INIT);
25181991Sheppo 	ldcp->ldc_status = istatus;
25191991Sheppo 
25201991Sheppo 	/* Setup kstats for the channel */
25216495Sspeer 	instance = vgenp->instance;
25225373Sraghuram 	(void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id);
25235373Sraghuram 	ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats);
25245373Sraghuram 	if (ldcp->ksp == NULL) {
25251991Sheppo 		goto ldc_attach_failed;
25261991Sheppo 	}
25271991Sheppo 
25281991Sheppo 	/* initialize vgen_versions supported */
25291991Sheppo 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
25305935Ssb155480 	vgen_reset_vnet_proto_ops(ldcp);
25311991Sheppo 
253212011SSriharsha.Basavapatna@Sun.COM 	/* Link this channel to the port */
253312011SSriharsha.Basavapatna@Sun.COM 	portp->ldcp = ldcp;
25341991Sheppo 
25359336SSriharsha.Basavapatna@Sun.COM 	ldcp->link_state = LINK_STATE_UNKNOWN;
25369336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
25379336SSriharsha.Basavapatna@Sun.COM 	ldcp->link_down_forced = B_FALSE;
25389336SSriharsha.Basavapatna@Sun.COM #endif
25391991Sheppo 	ldcp->flags |= CHANNEL_ATTACHED;
25401991Sheppo 	return (DDI_SUCCESS);
25411991Sheppo 
25421991Sheppo ldc_attach_failed:
25434647Sraghuram 	if (attach_state & AST_ldc_reg_cb) {
25444647Sraghuram 		(void) ldc_unreg_callback(ldcp->ldc_handle);
25455935Ssb155480 		kmem_free(ldcp->ldcmsg, ldcp->msglen);
25464647Sraghuram 	}
254712011SSriharsha.Basavapatna@Sun.COM 
25481991Sheppo 	if (attach_state & AST_ldc_init) {
25491991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
25501991Sheppo 	}
25511991Sheppo 	if (attach_state & AST_mutex_init) {
25521991Sheppo 		mutex_destroy(&ldcp->tclock);
25531991Sheppo 		mutex_destroy(&ldcp->txlock);
25541991Sheppo 		mutex_destroy(&ldcp->cblock);
25554647Sraghuram 		mutex_destroy(&ldcp->wrlock);
25564647Sraghuram 		mutex_destroy(&ldcp->rxlock);
255710309SSriharsha.Basavapatna@Sun.COM 		mutex_destroy(&ldcp->pollq_lock);
25581991Sheppo 	}
25591991Sheppo 	if (attach_state & AST_ldc_alloc) {
25601991Sheppo 		KMEM_FREE(ldcp);
25611991Sheppo 	}
25621991Sheppo 	return (DDI_FAILURE);
25631991Sheppo }
25641991Sheppo 
25651991Sheppo /* detach a channel from the port */
25661991Sheppo static void
vgen_ldc_detach(vgen_ldc_t * ldcp)25671991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
25681991Sheppo {
25691991Sheppo 	vgen_port_t	*portp;
25701991Sheppo 	vgen_t 		*vgenp;
257112011SSriharsha.Basavapatna@Sun.COM 
257212011SSriharsha.Basavapatna@Sun.COM 	ASSERT(ldcp != NULL);
25731991Sheppo 
25741991Sheppo 	portp = ldcp->portp;
25751991Sheppo 	vgenp = portp->vgenp;
25761991Sheppo 
25771991Sheppo 	if (ldcp->ldc_status != LDC_INIT) {
25784647Sraghuram 		DWARN(vgenp, ldcp, "ldc_status is not INIT\n");
25791991Sheppo 	}
25801991Sheppo 
25811991Sheppo 	if (ldcp->flags & CHANNEL_ATTACHED) {
25821991Sheppo 		ldcp->flags &= ~(CHANNEL_ATTACHED);
25831991Sheppo 
25844647Sraghuram 		(void) ldc_unreg_callback(ldcp->ldc_handle);
258512011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_fini(ldcp->ldc_handle);
258612011SSriharsha.Basavapatna@Sun.COM 
25875935Ssb155480 		kmem_free(ldcp->ldcmsg, ldcp->msglen);
25885373Sraghuram 		vgen_destroy_kstats(ldcp->ksp);
25895373Sraghuram 		ldcp->ksp = NULL;
25901991Sheppo 		mutex_destroy(&ldcp->tclock);
25911991Sheppo 		mutex_destroy(&ldcp->txlock);
25921991Sheppo 		mutex_destroy(&ldcp->cblock);
25934647Sraghuram 		mutex_destroy(&ldcp->wrlock);
25944647Sraghuram 		mutex_destroy(&ldcp->rxlock);
259510309SSriharsha.Basavapatna@Sun.COM 		mutex_destroy(&ldcp->pollq_lock);
259612011SSriharsha.Basavapatna@Sun.COM 		mutex_destroy(&ldcp->msg_thr_lock);
259712011SSriharsha.Basavapatna@Sun.COM 		cv_destroy(&ldcp->msg_thr_cv);
259812011SSriharsha.Basavapatna@Sun.COM 
25991991Sheppo 		KMEM_FREE(ldcp);
26001991Sheppo 	}
26011991Sheppo }
26021991Sheppo 
26031991Sheppo /* enable transmit/receive on the channel */
26041991Sheppo static int
vgen_ldc_init(vgen_ldc_t * ldcp)26051991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
26061991Sheppo {
260712011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
26081991Sheppo 	ldc_status_t	istatus;
26091991Sheppo 	int		rv;
261012011SSriharsha.Basavapatna@Sun.COM 	enum		{ ST_init = 0x0, ST_ldc_open = 0x1,
261112011SSriharsha.Basavapatna@Sun.COM 			    ST_cb_enable = 0x2} init_state;
261212011SSriharsha.Basavapatna@Sun.COM 	int		flag = 0;
261312011SSriharsha.Basavapatna@Sun.COM 
26141991Sheppo 	init_state = ST_init;
26151991Sheppo 
26164647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
26171991Sheppo 	LDC_LOCK(ldcp);
26181991Sheppo 
26191991Sheppo 	rv = ldc_open(ldcp->ldc_handle);
26201991Sheppo 	if (rv != 0) {
26214647Sraghuram 		DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
26221991Sheppo 		goto ldcinit_failed;
26231991Sheppo 	}
26241991Sheppo 	init_state |= ST_ldc_open;
26251991Sheppo 
26261991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
26271991Sheppo 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
26284647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
26291991Sheppo 		goto ldcinit_failed;
26301991Sheppo 	}
26311991Sheppo 	ldcp->ldc_status = istatus;
26321991Sheppo 
26332748Slm66018 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
26342748Slm66018 	if (rv != 0) {
26354647Sraghuram 		DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
26362748Slm66018 		goto ldcinit_failed;
26372748Slm66018 	}
26382748Slm66018 
26392748Slm66018 	init_state |= ST_cb_enable;
26402748Slm66018 
264112011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_up(ldcp);
26421991Sheppo 
26431991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
26442793Slm66018 	if (istatus == LDC_UP) {
26454647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus);
26461991Sheppo 	}
26472793Slm66018 
26481991Sheppo 	ldcp->ldc_status = istatus;
26491991Sheppo 
265012011SSriharsha.Basavapatna@Sun.COM 	ldcp->hphase = VH_PHASE0;
265112011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate = 0;
26521991Sheppo 	ldcp->flags |= CHANNEL_STARTED;
26531991Sheppo 
265412011SSriharsha.Basavapatna@Sun.COM 	vgen_setup_handshake_params(ldcp);
265512011SSriharsha.Basavapatna@Sun.COM 
26562793Slm66018 	/* if channel is already UP - start handshake */
26572793Slm66018 	if (istatus == LDC_UP) {
26582793Slm66018 		vgen_t *vgenp = LDC_TO_VGEN(ldcp);
26592793Slm66018 		if (ldcp->portp != vgenp->vsw_portp) {
26602793Slm66018 			/*
26616495Sspeer 			 * As the channel is up, use this port from now on.
26622793Slm66018 			 */
26636495Sspeer 			(void) atomic_swap_32(
26646495Sspeer 			    &ldcp->portp->use_vsw_port, B_FALSE);
26652793Slm66018 		}
26662793Slm66018 
26672793Slm66018 		/* Initialize local session id */
26682793Slm66018 		ldcp->local_sid = ddi_get_lbolt();
26692793Slm66018 
26702793Slm66018 		/* clear peer session id */
26712793Slm66018 		ldcp->peer_sid = 0;
26722793Slm66018 
26732793Slm66018 		mutex_exit(&ldcp->tclock);
26742793Slm66018 		mutex_exit(&ldcp->txlock);
26754647Sraghuram 		mutex_exit(&ldcp->wrlock);
26765708Sraghuram 		mutex_exit(&ldcp->rxlock);
267712011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handshake(vh_nextphase(ldcp));
26782793Slm66018 		mutex_exit(&ldcp->cblock);
267912011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
268012011SSriharsha.Basavapatna@Sun.COM 			flag = (rv == ECONNRESET) ? VGEN_FLAG_EVT_RESET :
268112011SSriharsha.Basavapatna@Sun.COM 			    VGEN_FLAG_NEED_LDCRESET;
268212011SSriharsha.Basavapatna@Sun.COM 			(void) vgen_process_reset(ldcp, flag);
268312011SSriharsha.Basavapatna@Sun.COM 		}
26842793Slm66018 	} else {
26852793Slm66018 		LDC_UNLOCK(ldcp);
26862793Slm66018 	}
26872793Slm66018 
26881991Sheppo 	return (DDI_SUCCESS);
26891991Sheppo 
26901991Sheppo ldcinit_failed:
26912748Slm66018 	if (init_state & ST_cb_enable) {
26922748Slm66018 		(void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
26932748Slm66018 	}
26941991Sheppo 	if (init_state & ST_ldc_open) {
26951991Sheppo 		(void) ldc_close(ldcp->ldc_handle);
26961991Sheppo 	}
26971991Sheppo 	LDC_UNLOCK(ldcp);
26984647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
26991991Sheppo 	return (DDI_FAILURE);
27001991Sheppo }
27011991Sheppo 
27021991Sheppo /* stop transmit/receive on the channel */
27031991Sheppo static void
vgen_ldc_uninit(vgen_ldc_t * ldcp)27041991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
27051991Sheppo {
27064647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
27071991Sheppo 
27084647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
270912011SSriharsha.Basavapatna@Sun.COM 
27101991Sheppo 	LDC_LOCK(ldcp);
27111991Sheppo 
27121991Sheppo 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
27131991Sheppo 		LDC_UNLOCK(ldcp);
27144647Sraghuram 		DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
27151991Sheppo 		return;
27161991Sheppo 	}
27171991Sheppo 
27181991Sheppo 	LDC_UNLOCK(ldcp);
27193653Snarayan 
272012011SSriharsha.Basavapatna@Sun.COM 	while (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
272112011SSriharsha.Basavapatna@Sun.COM 		delay(drv_usectohz(VGEN_LDC_UNINIT_DELAY));
272212011SSriharsha.Basavapatna@Sun.COM 	}
272312011SSriharsha.Basavapatna@Sun.COM 
272412011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_process_reset(ldcp, VGEN_FLAG_UNINIT);
27251991Sheppo 
27264647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
27271991Sheppo }
27281991Sheppo 
272912011SSriharsha.Basavapatna@Sun.COM /*
273012011SSriharsha.Basavapatna@Sun.COM  * Create a descriptor ring, that will be exported to the peer for mapping.
273112011SSriharsha.Basavapatna@Sun.COM  */
27321991Sheppo static int
vgen_create_dring(vgen_ldc_t * ldcp)273312011SSriharsha.Basavapatna@Sun.COM vgen_create_dring(vgen_ldc_t *ldcp)
27341991Sheppo {
273512011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
273612011SSriharsha.Basavapatna@Sun.COM 	int		rv;
273712011SSriharsha.Basavapatna@Sun.COM 
273812011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
273912011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_create_rx_dring(ldcp);
27407529SSriharsha.Basavapatna@Sun.COM 	} else {
274112011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_create_tx_dring(ldcp);
274212011SSriharsha.Basavapatna@Sun.COM 	}
274312011SSriharsha.Basavapatna@Sun.COM 
274412011SSriharsha.Basavapatna@Sun.COM 	return (rv);
274512011SSriharsha.Basavapatna@Sun.COM }
274612011SSriharsha.Basavapatna@Sun.COM 
274712011SSriharsha.Basavapatna@Sun.COM /*
274812011SSriharsha.Basavapatna@Sun.COM  * Destroy the descriptor ring.
274912011SSriharsha.Basavapatna@Sun.COM  */
275012011SSriharsha.Basavapatna@Sun.COM static void
vgen_destroy_dring(vgen_ldc_t * ldcp)275112011SSriharsha.Basavapatna@Sun.COM vgen_destroy_dring(vgen_ldc_t *ldcp)
275212011SSriharsha.Basavapatna@Sun.COM {
275312011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
275412011SSriharsha.Basavapatna@Sun.COM 
275512011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
275612011SSriharsha.Basavapatna@Sun.COM 		vgen_destroy_rx_dring(ldcp);
275712011SSriharsha.Basavapatna@Sun.COM 	} else {
275812011SSriharsha.Basavapatna@Sun.COM 		vgen_destroy_tx_dring(ldcp);
275912011SSriharsha.Basavapatna@Sun.COM 	}
276012011SSriharsha.Basavapatna@Sun.COM }
276112011SSriharsha.Basavapatna@Sun.COM 
276212011SSriharsha.Basavapatna@Sun.COM /*
276312011SSriharsha.Basavapatna@Sun.COM  * Map the descriptor ring exported by the peer.
276412011SSriharsha.Basavapatna@Sun.COM  */
276512011SSriharsha.Basavapatna@Sun.COM static int
vgen_map_dring(vgen_ldc_t * ldcp,void * pkt)276612011SSriharsha.Basavapatna@Sun.COM vgen_map_dring(vgen_ldc_t *ldcp, void *pkt)
276712011SSriharsha.Basavapatna@Sun.COM {
276812011SSriharsha.Basavapatna@Sun.COM 	int		rv;
276912011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
277012011SSriharsha.Basavapatna@Sun.COM 
277112011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
27722109Slm66018 		/*
277312011SSriharsha.Basavapatna@Sun.COM 		 * In RxDringData mode, dring that we map in
277412011SSriharsha.Basavapatna@Sun.COM 		 * becomes our transmit descriptor ring.
27752109Slm66018 		 */
277612011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_map_tx_dring(ldcp, pkt);
277712011SSriharsha.Basavapatna@Sun.COM 	} else {
27782109Slm66018 
27792109Slm66018 		/*
278012011SSriharsha.Basavapatna@Sun.COM 		 * In TxDring mode, dring that we map in
278112011SSriharsha.Basavapatna@Sun.COM 		 * becomes our receive descriptor ring.
27822109Slm66018 		 */
278312011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_map_rx_dring(ldcp, pkt);
278412011SSriharsha.Basavapatna@Sun.COM 	}
278512011SSriharsha.Basavapatna@Sun.COM 
278612011SSriharsha.Basavapatna@Sun.COM 	return (rv);
27871991Sheppo }
27881991Sheppo 
278912011SSriharsha.Basavapatna@Sun.COM /*
279012011SSriharsha.Basavapatna@Sun.COM  * Unmap the descriptor ring exported by the peer.
279112011SSriharsha.Basavapatna@Sun.COM  */
27921991Sheppo static void
vgen_unmap_dring(vgen_ldc_t * ldcp)279312011SSriharsha.Basavapatna@Sun.COM vgen_unmap_dring(vgen_ldc_t *ldcp)
27941991Sheppo {
279512011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
279612011SSriharsha.Basavapatna@Sun.COM 
279712011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
279812011SSriharsha.Basavapatna@Sun.COM 		vgen_unmap_tx_dring(ldcp);
279912011SSriharsha.Basavapatna@Sun.COM 	} else {
280012011SSriharsha.Basavapatna@Sun.COM 		vgen_unmap_rx_dring(ldcp);
280112011SSriharsha.Basavapatna@Sun.COM 	}
28021991Sheppo }
28031991Sheppo 
280412011SSriharsha.Basavapatna@Sun.COM void
vgen_destroy_rxpools(void * arg)280512011SSriharsha.Basavapatna@Sun.COM vgen_destroy_rxpools(void *arg)
28061991Sheppo {
280712011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_pool_t	*poolp = (vio_mblk_pool_t *)arg;
280812011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_pool_t	*npoolp;
280912011SSriharsha.Basavapatna@Sun.COM 
281012011SSriharsha.Basavapatna@Sun.COM 	while (poolp != NULL) {
281112011SSriharsha.Basavapatna@Sun.COM 		npoolp =  poolp->nextp;
281212011SSriharsha.Basavapatna@Sun.COM 		while (vio_destroy_mblks(poolp) != 0) {
281312300SSriharsha.Basavapatna@Sun.COM 			delay(drv_usectohz(vgen_rxpool_cleanup_delay));
281412011SSriharsha.Basavapatna@Sun.COM 		}
281512011SSriharsha.Basavapatna@Sun.COM 		poolp = npoolp;
281612011SSriharsha.Basavapatna@Sun.COM 	}
28171991Sheppo }
28181991Sheppo 
28191991Sheppo /* get channel statistics */
28201991Sheppo static uint64_t
vgen_ldc_stat(vgen_ldc_t * ldcp,uint_t stat)28212311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
28221991Sheppo {
282312011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp;
282412011SSriharsha.Basavapatna@Sun.COM 	uint64_t	val;
28251991Sheppo 
28261991Sheppo 	val = 0;
28275373Sraghuram 	statsp = &ldcp->stats;
28281991Sheppo 	switch (stat) {
28291991Sheppo 
28301991Sheppo 	case MAC_STAT_MULTIRCV:
28311991Sheppo 		val = statsp->multircv;
28321991Sheppo 		break;
28331991Sheppo 
28341991Sheppo 	case MAC_STAT_BRDCSTRCV:
28351991Sheppo 		val = statsp->brdcstrcv;
28361991Sheppo 		break;
28371991Sheppo 
28381991Sheppo 	case MAC_STAT_MULTIXMT:
28391991Sheppo 		val = statsp->multixmt;
28401991Sheppo 		break;
28411991Sheppo 
28421991Sheppo 	case MAC_STAT_BRDCSTXMT:
28431991Sheppo 		val = statsp->brdcstxmt;
28441991Sheppo 		break;
28451991Sheppo 
28461991Sheppo 	case MAC_STAT_NORCVBUF:
28471991Sheppo 		val = statsp->norcvbuf;
28481991Sheppo 		break;
28491991Sheppo 
28501991Sheppo 	case MAC_STAT_IERRORS:
28511991Sheppo 		val = statsp->ierrors;
28521991Sheppo 		break;
28531991Sheppo 
28541991Sheppo 	case MAC_STAT_NOXMTBUF:
28551991Sheppo 		val = statsp->noxmtbuf;
28561991Sheppo 		break;
28571991Sheppo 
28581991Sheppo 	case MAC_STAT_OERRORS:
28591991Sheppo 		val = statsp->oerrors;
28601991Sheppo 		break;
28611991Sheppo 
28621991Sheppo 	case MAC_STAT_COLLISIONS:
28631991Sheppo 		break;
28641991Sheppo 
28651991Sheppo 	case MAC_STAT_RBYTES:
28661991Sheppo 		val = statsp->rbytes;
28671991Sheppo 		break;
28681991Sheppo 
28691991Sheppo 	case MAC_STAT_IPACKETS:
28701991Sheppo 		val = statsp->ipackets;
28711991Sheppo 		break;
28721991Sheppo 
28731991Sheppo 	case MAC_STAT_OBYTES:
28741991Sheppo 		val = statsp->obytes;
28751991Sheppo 		break;
28761991Sheppo 
28771991Sheppo 	case MAC_STAT_OPACKETS:
28781991Sheppo 		val = statsp->opackets;
28791991Sheppo 		break;
28801991Sheppo 
28811991Sheppo 	/* stats not relevant to ldc, return 0 */
28821991Sheppo 	case MAC_STAT_IFSPEED:
28832311Sseb 	case ETHER_STAT_ALIGN_ERRORS:
28842311Sseb 	case ETHER_STAT_FCS_ERRORS:
28852311Sseb 	case ETHER_STAT_FIRST_COLLISIONS:
28862311Sseb 	case ETHER_STAT_MULTI_COLLISIONS:
28872311Sseb 	case ETHER_STAT_DEFER_XMTS:
28882311Sseb 	case ETHER_STAT_TX_LATE_COLLISIONS:
28892311Sseb 	case ETHER_STAT_EX_COLLISIONS:
28902311Sseb 	case ETHER_STAT_MACXMT_ERRORS:
28912311Sseb 	case ETHER_STAT_CARRIER_ERRORS:
28922311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
28932311Sseb 	case ETHER_STAT_XCVR_ADDR:
28942311Sseb 	case ETHER_STAT_XCVR_ID:
28952311Sseb 	case ETHER_STAT_XCVR_INUSE:
28962311Sseb 	case ETHER_STAT_CAP_1000FDX:
28972311Sseb 	case ETHER_STAT_CAP_1000HDX:
28982311Sseb 	case ETHER_STAT_CAP_100FDX:
28992311Sseb 	case ETHER_STAT_CAP_100HDX:
29002311Sseb 	case ETHER_STAT_CAP_10FDX:
29012311Sseb 	case ETHER_STAT_CAP_10HDX:
29022311Sseb 	case ETHER_STAT_CAP_ASMPAUSE:
29032311Sseb 	case ETHER_STAT_CAP_PAUSE:
29042311Sseb 	case ETHER_STAT_CAP_AUTONEG:
29052311Sseb 	case ETHER_STAT_ADV_CAP_1000FDX:
29062311Sseb 	case ETHER_STAT_ADV_CAP_1000HDX:
29072311Sseb 	case ETHER_STAT_ADV_CAP_100FDX:
29082311Sseb 	case ETHER_STAT_ADV_CAP_100HDX:
29092311Sseb 	case ETHER_STAT_ADV_CAP_10FDX:
29102311Sseb 	case ETHER_STAT_ADV_CAP_10HDX:
29112311Sseb 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
29122311Sseb 	case ETHER_STAT_ADV_CAP_PAUSE:
29132311Sseb 	case ETHER_STAT_ADV_CAP_AUTONEG:
29142311Sseb 	case ETHER_STAT_LP_CAP_1000FDX:
29152311Sseb 	case ETHER_STAT_LP_CAP_1000HDX:
29162311Sseb 	case ETHER_STAT_LP_CAP_100FDX:
29172311Sseb 	case ETHER_STAT_LP_CAP_100HDX:
29182311Sseb 	case ETHER_STAT_LP_CAP_10FDX:
29192311Sseb 	case ETHER_STAT_LP_CAP_10HDX:
29202311Sseb 	case ETHER_STAT_LP_CAP_ASMPAUSE:
29212311Sseb 	case ETHER_STAT_LP_CAP_PAUSE:
29222311Sseb 	case ETHER_STAT_LP_CAP_AUTONEG:
29232311Sseb 	case ETHER_STAT_LINK_ASMPAUSE:
29242311Sseb 	case ETHER_STAT_LINK_PAUSE:
29252311Sseb 	case ETHER_STAT_LINK_AUTONEG:
29262311Sseb 	case ETHER_STAT_LINK_DUPLEX:
29271991Sheppo 	default:
29281991Sheppo 		val = 0;
29291991Sheppo 		break;
29301991Sheppo 
29311991Sheppo 	}
29321991Sheppo 	return (val);
29331991Sheppo }
29341991Sheppo 
29352793Slm66018 /*
29366495Sspeer  * LDC channel is UP, start handshake process with peer.
29372793Slm66018  */
29382793Slm66018 static void
vgen_handle_evt_up(vgen_ldc_t * ldcp)29396495Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp)
29402793Slm66018 {
29412793Slm66018 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
29424647Sraghuram 
29434647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
29442793Slm66018 
29452793Slm66018 	ASSERT(MUTEX_HELD(&ldcp->cblock));
29462793Slm66018 
29472793Slm66018 	if (ldcp->portp != vgenp->vsw_portp) {
29482793Slm66018 		/*
29496495Sspeer 		 * As the channel is up, use this port from now on.
29502793Slm66018 		 */
29516495Sspeer 		(void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE);
29522793Slm66018 	}
29532793Slm66018 
29542793Slm66018 	/* Initialize local session id */
29552793Slm66018 	ldcp->local_sid = ddi_get_lbolt();
29562793Slm66018 
29572793Slm66018 	/* clear peer session id */
29582793Slm66018 	ldcp->peer_sid = 0;
29592793Slm66018 
29602793Slm66018 	/* Initiate Handshake process with peer ldc endpoint */
296112011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_handshake(vh_nextphase(ldcp));
29622793Slm66018 
29634647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
29642793Slm66018 }
29652793Slm66018 
29662793Slm66018 /*
29672793Slm66018  * LDC channel is Reset, terminate connection with peer and try to
29682793Slm66018  * bring the channel up again.
29692793Slm66018  */
297012011SSriharsha.Basavapatna@Sun.COM int
vgen_handle_evt_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)297112011SSriharsha.Basavapatna@Sun.COM vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
29722793Slm66018 {
297312011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
297412011SSriharsha.Basavapatna@Sun.COM 		ASSERT(MUTEX_HELD(&ldcp->cblock));
297512011SSriharsha.Basavapatna@Sun.COM 	}
297612011SSriharsha.Basavapatna@Sun.COM 
297712011SSriharsha.Basavapatna@Sun.COM 	/* Set the flag to indicate reset is in progress */
297812011SSriharsha.Basavapatna@Sun.COM 	if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
297912011SSriharsha.Basavapatna@Sun.COM 		/* another thread is already in the process of resetting */
298012011SSriharsha.Basavapatna@Sun.COM 		return (EBUSY);
298112011SSriharsha.Basavapatna@Sun.COM 	}
298212011SSriharsha.Basavapatna@Sun.COM 
298312011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
298412011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
298512011SSriharsha.Basavapatna@Sun.COM 	}
298612011SSriharsha.Basavapatna@Sun.COM 
298712011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_process_reset(ldcp, VGEN_FLAG_EVT_RESET);
298812011SSriharsha.Basavapatna@Sun.COM 
298912011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
299012011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->cblock);
299112011SSriharsha.Basavapatna@Sun.COM 	}
299212011SSriharsha.Basavapatna@Sun.COM 
299312011SSriharsha.Basavapatna@Sun.COM 	return (0);
29942793Slm66018 }
29952793Slm66018 
29961991Sheppo /* Interrupt handler for the channel */
29971991Sheppo static uint_t
vgen_ldc_cb(uint64_t event,caddr_t arg)29981991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
29991991Sheppo {
30001991Sheppo 	_NOTE(ARGUNUSED(event))
30011991Sheppo 	vgen_ldc_t	*ldcp;
30021991Sheppo 	vgen_t		*vgenp;
30031991Sheppo 	ldc_status_t 	istatus;
30041991Sheppo 	vgen_stats_t	*statsp;
30057572SWentao.Yang@Sun.COM 	uint_t		ret = LDC_SUCCESS;
30061991Sheppo 
30071991Sheppo 	ldcp = (vgen_ldc_t *)arg;
30081991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
30095373Sraghuram 	statsp = &ldcp->stats;
30101991Sheppo 
30114647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
30121991Sheppo 
30131991Sheppo 	mutex_enter(&ldcp->cblock);
30141991Sheppo 	statsp->callbacks++;
30151991Sheppo 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
30164647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n",
30174647Sraghuram 		    ldcp->ldc_status);
30181991Sheppo 		mutex_exit(&ldcp->cblock);
30191991Sheppo 		return (LDC_SUCCESS);
30201991Sheppo 	}
30211991Sheppo 
30222793Slm66018 	/*
30232793Slm66018 	 * NOTE: not using switch() as event could be triggered by
30242793Slm66018 	 * a state change and a read request. Also the ordering	of the
30252793Slm66018 	 * check for the event types is deliberate.
30262793Slm66018 	 */
30272793Slm66018 	if (event & LDC_EVT_UP) {
30282793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
30294647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status err\n");
30305708Sraghuram 			/* status couldn't be determined */
30317572SWentao.Yang@Sun.COM 			ret = LDC_FAILURE;
30327572SWentao.Yang@Sun.COM 			goto ldc_cb_ret;
30332793Slm66018 		}
30345708Sraghuram 		ldcp->ldc_status = istatus;
30355708Sraghuram 		if (ldcp->ldc_status != LDC_UP) {
30365708Sraghuram 			DWARN(vgenp, ldcp, "LDC_EVT_UP received "
30375708Sraghuram 			    " but ldc status is not UP(0x%x)\n",
30385708Sraghuram 			    ldcp->ldc_status);
30395708Sraghuram 			/* spurious interrupt, return success */
30407572SWentao.Yang@Sun.COM 			goto ldc_cb_ret;
30415708Sraghuram 		}
30424647Sraghuram 		DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n",
30434647Sraghuram 		    event, ldcp->ldc_status);
30442793Slm66018 
30456495Sspeer 		vgen_handle_evt_up(ldcp);
30462793Slm66018 
30472793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
30482793Slm66018 	}
30492793Slm66018 
30505708Sraghuram 	/* Handle RESET/DOWN before READ event */
30515708Sraghuram 	if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
30525708Sraghuram 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
30535708Sraghuram 			DWARN(vgenp, ldcp, "ldc_status error\n");
30545708Sraghuram 			/* status couldn't be determined */
30557572SWentao.Yang@Sun.COM 			ret = LDC_FAILURE;
30567572SWentao.Yang@Sun.COM 			goto ldc_cb_ret;
30575708Sraghuram 		}
30585708Sraghuram 		ldcp->ldc_status = istatus;
30595708Sraghuram 		DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
30605708Sraghuram 		    event, ldcp->ldc_status);
30615708Sraghuram 
306212011SSriharsha.Basavapatna@Sun.COM 		(void) vgen_handle_evt_reset(ldcp, VGEN_LDC_CB);
30635708Sraghuram 
30645708Sraghuram 		/*
30655708Sraghuram 		 * As the channel is down/reset, ignore READ event
30665708Sraghuram 		 * but print a debug warning message.
30675708Sraghuram 		 */
30685708Sraghuram 		if (event & LDC_EVT_READ) {
30695708Sraghuram 			DWARN(vgenp, ldcp,
30705708Sraghuram 			    "LDC_EVT_READ set along with RESET/DOWN\n");
30715708Sraghuram 			event &= ~LDC_EVT_READ;
30725708Sraghuram 		}
30735708Sraghuram 	}
30745708Sraghuram 
30752793Slm66018 	if (event & LDC_EVT_READ) {
30764647Sraghuram 		DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n",
30774647Sraghuram 		    event, ldcp->ldc_status);
30782793Slm66018 
30792793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
30804647Sraghuram 
308112011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->msg_thread != NULL) {
30824647Sraghuram 			/*
30834647Sraghuram 			 * If the receive thread is enabled, then
30844647Sraghuram 			 * wakeup the receive thread to process the
30854647Sraghuram 			 * LDC messages.
30864647Sraghuram 			 */
30874647Sraghuram 			mutex_exit(&ldcp->cblock);
308812011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->msg_thr_lock);
308912011SSriharsha.Basavapatna@Sun.COM 			if (!(ldcp->msg_thr_flags & VGEN_WTHR_DATARCVD)) {
309012011SSriharsha.Basavapatna@Sun.COM 				ldcp->msg_thr_flags |= VGEN_WTHR_DATARCVD;
309112011SSriharsha.Basavapatna@Sun.COM 				cv_signal(&ldcp->msg_thr_cv);
30924647Sraghuram 			}
309312011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->msg_thr_lock);
30944647Sraghuram 			mutex_enter(&ldcp->cblock);
30954647Sraghuram 		} else  {
309612011SSriharsha.Basavapatna@Sun.COM 			(void) vgen_handle_evt_read(ldcp, VGEN_LDC_CB);
30974647Sraghuram 		}
30982793Slm66018 	}
30997572SWentao.Yang@Sun.COM 
31007572SWentao.Yang@Sun.COM ldc_cb_ret:
31012793Slm66018 	mutex_exit(&ldcp->cblock);
31024647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
31037572SWentao.Yang@Sun.COM 	return (ret);
31044647Sraghuram }
31054647Sraghuram 
310612011SSriharsha.Basavapatna@Sun.COM int
vgen_handle_evt_read(vgen_ldc_t * ldcp,vgen_caller_t caller)310712011SSriharsha.Basavapatna@Sun.COM vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller)
31084647Sraghuram {
31094647Sraghuram 	int		rv;
31105935Ssb155480 	uint64_t	*ldcmsg;
31114647Sraghuram 	size_t		msglen;
31124647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
31134647Sraghuram 	vio_msg_tag_t	*tagp;
31144647Sraghuram 	ldc_status_t 	istatus;
31154647Sraghuram 	boolean_t 	has_data;
31164647Sraghuram 
31174647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
31184647Sraghuram 
311912011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB) {
312012011SSriharsha.Basavapatna@Sun.COM 		ASSERT(MUTEX_HELD(&ldcp->cblock));
312112011SSriharsha.Basavapatna@Sun.COM 	} else if (caller == VGEN_MSG_THR) {
31224647Sraghuram 		mutex_enter(&ldcp->cblock);
31234647Sraghuram 	} else {
312412011SSriharsha.Basavapatna@Sun.COM 		return (EINVAL);
312512011SSriharsha.Basavapatna@Sun.COM 	}
312612011SSriharsha.Basavapatna@Sun.COM 
312712011SSriharsha.Basavapatna@Sun.COM 	ldcmsg = ldcp->ldcmsg;
312812011SSriharsha.Basavapatna@Sun.COM 
312912011SSriharsha.Basavapatna@Sun.COM vgen_evtread:
31301991Sheppo 	do {
31315935Ssb155480 		msglen = ldcp->msglen;
31325935Ssb155480 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
31331991Sheppo 
31341991Sheppo 		if (rv != 0) {
313512011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "ldc_read() failed "
313612011SSriharsha.Basavapatna@Sun.COM 			    "rv(%d) len(%d)\n", rv, msglen);
31372793Slm66018 			if (rv == ECONNRESET)
31384647Sraghuram 				goto vgen_evtread_error;
31391991Sheppo 			break;
31401991Sheppo 		}
31411991Sheppo 		if (msglen == 0) {
31424647Sraghuram 			DBG2(vgenp, ldcp, "ldc_read NODATA");
31431991Sheppo 			break;
31441991Sheppo 		}
31454647Sraghuram 		DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen);
31461991Sheppo 
31471991Sheppo 		tagp = (vio_msg_tag_t *)ldcmsg;
31481991Sheppo 
31491991Sheppo 		if (ldcp->peer_sid) {
31501991Sheppo 			/*
31511991Sheppo 			 * check sid only after we have received peer's sid
31521991Sheppo 			 * in the version negotiate msg.
31531991Sheppo 			 */
31541991Sheppo #ifdef DEBUG
315512011SSriharsha.Basavapatna@Sun.COM 			if (vgen_inject_error(ldcp, VGEN_ERR_HSID)) {
31561991Sheppo 				/* simulate bad sid condition */
31571991Sheppo 				tagp->vio_sid = 0;
315812011SSriharsha.Basavapatna@Sun.COM 				vgen_inject_err_flag &= ~(VGEN_ERR_HSID);
31591991Sheppo 			}
31601991Sheppo #endif
31612793Slm66018 			rv = vgen_check_sid(ldcp, tagp);
31622793Slm66018 			if (rv != VGEN_SUCCESS) {
31631991Sheppo 				/*
31641991Sheppo 				 * If sid mismatch is detected,
31651991Sheppo 				 * reset the channel.
31661991Sheppo 				 */
316712011SSriharsha.Basavapatna@Sun.COM 				DWARN(vgenp, ldcp, "vgen_check_sid() failed\n");
31684647Sraghuram 				goto vgen_evtread_error;
31691991Sheppo 			}
31701991Sheppo 		}
31711991Sheppo 
31721991Sheppo 		switch (tagp->vio_msgtype) {
31731991Sheppo 		case VIO_TYPE_CTRL:
31742793Slm66018 			rv = vgen_handle_ctrlmsg(ldcp, tagp);
317512011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
317612011SSriharsha.Basavapatna@Sun.COM 				DWARN(vgenp, ldcp, "vgen_handle_ctrlmsg()"
317712011SSriharsha.Basavapatna@Sun.COM 				    " failed rv(%d)\n", rv);
317812011SSriharsha.Basavapatna@Sun.COM 			}
31791991Sheppo 			break;
31801991Sheppo 
31811991Sheppo 		case VIO_TYPE_DATA:
31825935Ssb155480 			rv = vgen_handle_datamsg(ldcp, tagp, msglen);
318312011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
318412011SSriharsha.Basavapatna@Sun.COM 				DWARN(vgenp, ldcp, "vgen_handle_datamsg()"
318512011SSriharsha.Basavapatna@Sun.COM 				    " failed rv(%d)\n", rv);
318612011SSriharsha.Basavapatna@Sun.COM 			}
31871991Sheppo 			break;
31881991Sheppo 
31891991Sheppo 		case VIO_TYPE_ERR:
31901991Sheppo 			vgen_handle_errmsg(ldcp, tagp);
31911991Sheppo 			break;
31921991Sheppo 
31931991Sheppo 		default:
31944647Sraghuram 			DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n",
31954647Sraghuram 			    tagp->vio_msgtype);
31961991Sheppo 			break;
31971991Sheppo 		}
31981991Sheppo 
31994647Sraghuram 		/*
32004647Sraghuram 		 * If an error is encountered, stop processing and
32014647Sraghuram 		 * handle the error.
32024647Sraghuram 		 */
32034647Sraghuram 		if (rv != 0) {
32044647Sraghuram 			goto vgen_evtread_error;
32052793Slm66018 		}
32062793Slm66018 
32071991Sheppo 	} while (msglen);
32081991Sheppo 
32094647Sraghuram 	/* check once more before exiting */
32104647Sraghuram 	rv = ldc_chkq(ldcp->ldc_handle, &has_data);
32114647Sraghuram 	if ((rv == 0) && (has_data == B_TRUE)) {
321212011SSriharsha.Basavapatna@Sun.COM 		DTRACE_PROBE1(vgen_chkq, vgen_ldc_t *, ldcp);
321312011SSriharsha.Basavapatna@Sun.COM 		goto vgen_evtread;
32144647Sraghuram 	}
32154647Sraghuram 
32164647Sraghuram vgen_evtread_error:
321712011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
321812011SSriharsha.Basavapatna@Sun.COM 		/*
321912011SSriharsha.Basavapatna@Sun.COM 		 * We handle the error and then return the error value. If we
322012011SSriharsha.Basavapatna@Sun.COM 		 * are running in the context of the msg worker, the error
322112011SSriharsha.Basavapatna@Sun.COM 		 * tells the worker thread to exit, as the channel would have
322212011SSriharsha.Basavapatna@Sun.COM 		 * been reset.
322312011SSriharsha.Basavapatna@Sun.COM 		 */
322412011SSriharsha.Basavapatna@Sun.COM 		if (rv == ECONNRESET) {
322512011SSriharsha.Basavapatna@Sun.COM 			if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
322612011SSriharsha.Basavapatna@Sun.COM 				DWARN(vgenp, ldcp, "ldc_status err\n");
322712011SSriharsha.Basavapatna@Sun.COM 			} else {
322812011SSriharsha.Basavapatna@Sun.COM 				ldcp->ldc_status = istatus;
322912011SSriharsha.Basavapatna@Sun.COM 			}
323012011SSriharsha.Basavapatna@Sun.COM 			(void) vgen_handle_evt_reset(ldcp, caller);
32314647Sraghuram 		} else {
323212011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "Calling vgen_ldc_reset()...\n");
323312011SSriharsha.Basavapatna@Sun.COM 			(void) vgen_ldc_reset(ldcp, caller);
32344647Sraghuram 		}
323512011SSriharsha.Basavapatna@Sun.COM 	}
323612011SSriharsha.Basavapatna@Sun.COM 
323712011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_MSG_THR) {
32384647Sraghuram 		mutex_exit(&ldcp->cblock);
32394647Sraghuram 	}
32404647Sraghuram 
32414647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
324212011SSriharsha.Basavapatna@Sun.COM 	return (rv);
32431991Sheppo }
32441991Sheppo 
32451991Sheppo /* vgen handshake functions */
32461991Sheppo 
32471991Sheppo /* change the hphase for the channel to the next phase */
32481991Sheppo static vgen_ldc_t *
vh_nextphase(vgen_ldc_t * ldcp)32491991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
32501991Sheppo {
325112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase == VH_PHASE4) {
32521991Sheppo 		ldcp->hphase = VH_DONE;
32531991Sheppo 	} else {
32541991Sheppo 		ldcp->hphase++;
32551991Sheppo 	}
32561991Sheppo 	return (ldcp);
32571991Sheppo }
32581991Sheppo 
32591991Sheppo /* send version negotiate message to the peer over ldc */
32601991Sheppo static int
vgen_send_version_negotiate(vgen_ldc_t * ldcp)32611991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
32621991Sheppo {
32634647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
32641991Sheppo 	vio_ver_msg_t	vermsg;
32651991Sheppo 	vio_msg_tag_t	*tagp = &vermsg.tag;
32661991Sheppo 	int		rv;
32671991Sheppo 
32681991Sheppo 	bzero(&vermsg, sizeof (vermsg));
32691991Sheppo 
32701991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
32711991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
32721991Sheppo 	tagp->vio_subtype_env = VIO_VER_INFO;
32731991Sheppo 	tagp->vio_sid = ldcp->local_sid;
32741991Sheppo 
32751991Sheppo 	/* get version msg payload from ldcp->local */
32761991Sheppo 	vermsg.ver_major = ldcp->local_hparams.ver_major;
32771991Sheppo 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
32781991Sheppo 	vermsg.dev_class = ldcp->local_hparams.dev_class;
32791991Sheppo 
32801991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
32811991Sheppo 	if (rv != VGEN_SUCCESS) {
32824647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
32832793Slm66018 		return (rv);
32841991Sheppo 	}
32851991Sheppo 
32861991Sheppo 	ldcp->hstate |= VER_INFO_SENT;
32874647Sraghuram 	DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n",
32884647Sraghuram 	    vermsg.ver_major, vermsg.ver_minor);
32891991Sheppo 
32901991Sheppo 	return (VGEN_SUCCESS);
32911991Sheppo }
32921991Sheppo 
32931991Sheppo /* send attr info message to the peer over ldc */
32941991Sheppo static int
vgen_send_attr_info(vgen_ldc_t * ldcp)32951991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
32961991Sheppo {
32974647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
32981991Sheppo 	vnet_attr_msg_t	attrmsg;
32991991Sheppo 	vio_msg_tag_t	*tagp = &attrmsg.tag;
33001991Sheppo 	int		rv;
33011991Sheppo 
33021991Sheppo 	bzero(&attrmsg, sizeof (attrmsg));
33031991Sheppo 
33041991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
33051991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
33061991Sheppo 	tagp->vio_subtype_env = VIO_ATTR_INFO;
33071991Sheppo 	tagp->vio_sid = ldcp->local_sid;
33081991Sheppo 
33091991Sheppo 	/* get attr msg payload from ldcp->local */
33101991Sheppo 	attrmsg.mtu = ldcp->local_hparams.mtu;
33111991Sheppo 	attrmsg.addr = ldcp->local_hparams.addr;
33121991Sheppo 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
33131991Sheppo 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
33141991Sheppo 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
33159336SSriharsha.Basavapatna@Sun.COM 	attrmsg.physlink_update = ldcp->local_hparams.physlink_update;
331612011SSriharsha.Basavapatna@Sun.COM 	attrmsg.options = ldcp->local_hparams.dring_mode;
33171991Sheppo 
33181991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
33191991Sheppo 	if (rv != VGEN_SUCCESS) {
33204647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
33212793Slm66018 		return (rv);
33221991Sheppo 	}
33231991Sheppo 
33241991Sheppo 	ldcp->hstate |= ATTR_INFO_SENT;
33254647Sraghuram 	DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n");
33261991Sheppo 
33271991Sheppo 	return (VGEN_SUCCESS);
33281991Sheppo }
33291991Sheppo 
333012011SSriharsha.Basavapatna@Sun.COM /*
333112011SSriharsha.Basavapatna@Sun.COM  * Send descriptor ring register message to the peer over ldc.
333212011SSriharsha.Basavapatna@Sun.COM  * Invoked in RxDringData mode.
333312011SSriharsha.Basavapatna@Sun.COM  */
33341991Sheppo static int
vgen_send_rx_dring_reg(vgen_ldc_t * ldcp)333512011SSriharsha.Basavapatna@Sun.COM vgen_send_rx_dring_reg(vgen_ldc_t *ldcp)
333612011SSriharsha.Basavapatna@Sun.COM {
333712011SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
333812011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t	*msg;
333912011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_ext_msg_t	*emsg;
334012011SSriharsha.Basavapatna@Sun.COM 	int			rv;
334112011SSriharsha.Basavapatna@Sun.COM 	uint8_t			*buf;
334212011SSriharsha.Basavapatna@Sun.COM 	uint_t			msgsize;
334312011SSriharsha.Basavapatna@Sun.COM 
334412011SSriharsha.Basavapatna@Sun.COM 	msgsize = VNET_DRING_REG_EXT_MSG_SIZE(ldcp->rx_data_ncookies);
334512011SSriharsha.Basavapatna@Sun.COM 	msg = kmem_zalloc(msgsize, KM_SLEEP);
334612011SSriharsha.Basavapatna@Sun.COM 
334712011SSriharsha.Basavapatna@Sun.COM 	/* Initialize the common part of dring reg msg */
334812011SSriharsha.Basavapatna@Sun.COM 	vgen_init_dring_reg_msg(ldcp, msg, VIO_RX_DRING_DATA);
334912011SSriharsha.Basavapatna@Sun.COM 
335012011SSriharsha.Basavapatna@Sun.COM 	/* skip over dring cookies at the tail of common section */
335112011SSriharsha.Basavapatna@Sun.COM 	buf = (uint8_t *)msg->cookie;
335212011SSriharsha.Basavapatna@Sun.COM 	ASSERT(msg->ncookies == 1);
335312011SSriharsha.Basavapatna@Sun.COM 	buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
335412011SSriharsha.Basavapatna@Sun.COM 
335512011SSriharsha.Basavapatna@Sun.COM 	/* Now setup the extended part, specific to RxDringData mode */
335612011SSriharsha.Basavapatna@Sun.COM 	emsg = (vio_dring_reg_ext_msg_t *)buf;
335712011SSriharsha.Basavapatna@Sun.COM 
335812011SSriharsha.Basavapatna@Sun.COM 	/* copy data_ncookies in the msg */
335912011SSriharsha.Basavapatna@Sun.COM 	emsg->data_ncookies = ldcp->rx_data_ncookies;
336012011SSriharsha.Basavapatna@Sun.COM 
336112011SSriharsha.Basavapatna@Sun.COM 	/* copy data area size in the msg */
336212011SSriharsha.Basavapatna@Sun.COM 	emsg->data_area_size = ldcp->rx_data_sz;
336312011SSriharsha.Basavapatna@Sun.COM 
336412011SSriharsha.Basavapatna@Sun.COM 	/* copy data area cookies in the msg */
336512011SSriharsha.Basavapatna@Sun.COM 	bcopy(ldcp->rx_data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie,
336612011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t) * ldcp->rx_data_ncookies);
336712011SSriharsha.Basavapatna@Sun.COM 
336812011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_sendmsg(ldcp, (caddr_t)msg, msgsize, B_FALSE);
336912011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
337012011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
337112011SSriharsha.Basavapatna@Sun.COM 		kmem_free(msg, msgsize);
337212011SSriharsha.Basavapatna@Sun.COM 		return (rv);
337312011SSriharsha.Basavapatna@Sun.COM 	}
337412011SSriharsha.Basavapatna@Sun.COM 
337512011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate |= DRING_INFO_SENT;
337612011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
337712011SSriharsha.Basavapatna@Sun.COM 
337812011SSriharsha.Basavapatna@Sun.COM 	kmem_free(msg, msgsize);
337912011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
338012011SSriharsha.Basavapatna@Sun.COM }
338112011SSriharsha.Basavapatna@Sun.COM 
338212011SSriharsha.Basavapatna@Sun.COM /*
338312011SSriharsha.Basavapatna@Sun.COM  * Send descriptor ring register message to the peer over ldc.
338412011SSriharsha.Basavapatna@Sun.COM  * Invoked in TxDring mode.
338512011SSriharsha.Basavapatna@Sun.COM  */
338612011SSriharsha.Basavapatna@Sun.COM static int
vgen_send_tx_dring_reg(vgen_ldc_t * ldcp)338712011SSriharsha.Basavapatna@Sun.COM vgen_send_tx_dring_reg(vgen_ldc_t *ldcp)
33881991Sheppo {
33894647Sraghuram 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
33901991Sheppo 	vio_dring_reg_msg_t	msg;
339112011SSriharsha.Basavapatna@Sun.COM 	int			rv;
33921991Sheppo 
33931991Sheppo 	bzero(&msg, sizeof (msg));
33941991Sheppo 
33951991Sheppo 	/*
339612011SSriharsha.Basavapatna@Sun.COM 	 * Initialize only the common part of dring reg msg in TxDring mode.
33971991Sheppo 	 */
339812011SSriharsha.Basavapatna@Sun.COM 	vgen_init_dring_reg_msg(ldcp, &msg, VIO_TX_DRING);
339912011SSriharsha.Basavapatna@Sun.COM 
340012011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_sendmsg(ldcp, (caddr_t)&msg, sizeof (msg), B_FALSE);
34011991Sheppo 	if (rv != VGEN_SUCCESS) {
34024647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34032793Slm66018 		return (rv);
34041991Sheppo 	}
34051991Sheppo 
34061991Sheppo 	ldcp->hstate |= DRING_INFO_SENT;
34074647Sraghuram 	DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
34081991Sheppo 
34091991Sheppo 	return (VGEN_SUCCESS);
34101991Sheppo }
34111991Sheppo 
34121991Sheppo static int
vgen_send_rdx_info(vgen_ldc_t * ldcp)34131991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
34141991Sheppo {
34154647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
34161991Sheppo 	vio_rdx_msg_t	rdxmsg;
34171991Sheppo 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
34181991Sheppo 	int		rv;
34191991Sheppo 
34201991Sheppo 	bzero(&rdxmsg, sizeof (rdxmsg));
34211991Sheppo 
34221991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
34231991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
34241991Sheppo 	tagp->vio_subtype_env = VIO_RDX;
34251991Sheppo 	tagp->vio_sid = ldcp->local_sid;
34261991Sheppo 
34271991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
34281991Sheppo 	if (rv != VGEN_SUCCESS) {
34294647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34302793Slm66018 		return (rv);
34311991Sheppo 	}
34321991Sheppo 
34331991Sheppo 	ldcp->hstate |= RDX_INFO_SENT;
34344647Sraghuram 	DBG2(vgenp, ldcp, "RDX_INFO_SENT\n");
34351991Sheppo 
34361991Sheppo 	return (VGEN_SUCCESS);
34371991Sheppo }
34381991Sheppo 
34391991Sheppo /* send multicast addr info message to vsw */
34401991Sheppo static int
vgen_send_mcast_info(vgen_ldc_t * ldcp)34411991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
34421991Sheppo {
34431991Sheppo 	vnet_mcast_msg_t	mcastmsg;
34441991Sheppo 	vnet_mcast_msg_t	*msgp;
34451991Sheppo 	vio_msg_tag_t		*tagp;
34461991Sheppo 	vgen_t			*vgenp;
34471991Sheppo 	struct ether_addr	*mca;
34481991Sheppo 	int			rv;
34491991Sheppo 	int			i;
34501991Sheppo 	uint32_t		size;
34511991Sheppo 	uint32_t		mccount;
34521991Sheppo 	uint32_t		n;
34531991Sheppo 
34541991Sheppo 	msgp = &mcastmsg;
34551991Sheppo 	tagp = &msgp->tag;
34561991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
34571991Sheppo 
34581991Sheppo 	mccount = vgenp->mccount;
34591991Sheppo 	i = 0;
34601991Sheppo 
34611991Sheppo 	do {
34621991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
34631991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
34641991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
34651991Sheppo 		tagp->vio_sid = ldcp->local_sid;
34661991Sheppo 
34671991Sheppo 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
34681991Sheppo 		size = n * sizeof (struct ether_addr);
34691991Sheppo 
34701991Sheppo 		mca = &(vgenp->mctab[i]);
34711991Sheppo 		bcopy(mca, (msgp->mca), size);
34721991Sheppo 		msgp->set = B_TRUE;
34731991Sheppo 		msgp->count = n;
34741991Sheppo 
34751991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
34761991Sheppo 		    B_FALSE);
34771991Sheppo 		if (rv != VGEN_SUCCESS) {
34784647Sraghuram 			DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv);
34792793Slm66018 			return (rv);
34801991Sheppo 		}
34811991Sheppo 
34821991Sheppo 		mccount -= n;
34831991Sheppo 		i += n;
34841991Sheppo 
34851991Sheppo 	} while (mccount);
34861991Sheppo 
34871991Sheppo 	return (VGEN_SUCCESS);
34881991Sheppo }
34891991Sheppo 
349012011SSriharsha.Basavapatna@Sun.COM /*
349112011SSriharsha.Basavapatna@Sun.COM  * vgen_dds_rx -- post DDS messages to vnet.
349212011SSriharsha.Basavapatna@Sun.COM  */
349312011SSriharsha.Basavapatna@Sun.COM static int
vgen_dds_rx(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)349412011SSriharsha.Basavapatna@Sun.COM vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
349512011SSriharsha.Basavapatna@Sun.COM {
349612011SSriharsha.Basavapatna@Sun.COM 	vio_dds_msg_t	*dmsg = (vio_dds_msg_t *)tagp;
349712011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
349812011SSriharsha.Basavapatna@Sun.COM 
349912011SSriharsha.Basavapatna@Sun.COM 	if (dmsg->dds_class != DDS_VNET_NIU) {
350012011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Unknown DDS class, dropping");
350112011SSriharsha.Basavapatna@Sun.COM 		return (EBADMSG);
350212011SSriharsha.Basavapatna@Sun.COM 	}
350312011SSriharsha.Basavapatna@Sun.COM 	vnet_dds_rx(vgenp->vnetp, dmsg);
350412011SSriharsha.Basavapatna@Sun.COM 	return (0);
350512011SSriharsha.Basavapatna@Sun.COM }
350612011SSriharsha.Basavapatna@Sun.COM 
350712011SSriharsha.Basavapatna@Sun.COM /*
350812011SSriharsha.Basavapatna@Sun.COM  * vgen_dds_tx -- an interface called by vnet to send DDS messages.
350912011SSriharsha.Basavapatna@Sun.COM  */
351012011SSriharsha.Basavapatna@Sun.COM int
vgen_dds_tx(void * arg,void * msg)351112011SSriharsha.Basavapatna@Sun.COM vgen_dds_tx(void *arg, void *msg)
351212011SSriharsha.Basavapatna@Sun.COM {
351312011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = arg;
351412011SSriharsha.Basavapatna@Sun.COM 	vio_dds_msg_t	*dmsg = msg;
351512011SSriharsha.Basavapatna@Sun.COM 	vgen_portlist_t	*plistp = &vgenp->vgenports;
351612011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp;
351712011SSriharsha.Basavapatna@Sun.COM 	int		rv = EIO;
351812011SSriharsha.Basavapatna@Sun.COM 
351912011SSriharsha.Basavapatna@Sun.COM 	READ_ENTER(&plistp->rwlock);
352012011SSriharsha.Basavapatna@Sun.COM 	ldcp = vgenp->vsw_portp->ldcp;
352112011SSriharsha.Basavapatna@Sun.COM 	if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) {
352212011SSriharsha.Basavapatna@Sun.COM 		goto vgen_dsend_exit;
352312011SSriharsha.Basavapatna@Sun.COM 	}
352412011SSriharsha.Basavapatna@Sun.COM 
352512011SSriharsha.Basavapatna@Sun.COM 	dmsg->tag.vio_sid = ldcp->local_sid;
352612011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE);
352712011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
352812011SSriharsha.Basavapatna@Sun.COM 		rv = EIO;
352912011SSriharsha.Basavapatna@Sun.COM 	} else {
353012011SSriharsha.Basavapatna@Sun.COM 		rv = 0;
353112011SSriharsha.Basavapatna@Sun.COM 	}
353212011SSriharsha.Basavapatna@Sun.COM 
353312011SSriharsha.Basavapatna@Sun.COM vgen_dsend_exit:
353412011SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&plistp->rwlock);
353512011SSriharsha.Basavapatna@Sun.COM 	return (rv);
353612011SSriharsha.Basavapatna@Sun.COM 
353712011SSriharsha.Basavapatna@Sun.COM }
353812011SSriharsha.Basavapatna@Sun.COM 
35391991Sheppo /* Initiate Phase 2 of handshake */
35401991Sheppo static int
vgen_handshake_phase2(vgen_ldc_t * ldcp)35411991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
35421991Sheppo {
354312011SSriharsha.Basavapatna@Sun.COM 	int	rv;
35444647Sraghuram 
35451991Sheppo #ifdef DEBUG
354612011SSriharsha.Basavapatna@Sun.COM 	if (vgen_inject_error(ldcp, VGEN_ERR_HSTATE)) {
35471991Sheppo 		/* simulate out of state condition */
354812011SSriharsha.Basavapatna@Sun.COM 		vgen_inject_err_flag &= ~(VGEN_ERR_HSTATE);
35491991Sheppo 		rv = vgen_send_rdx_info(ldcp);
35501991Sheppo 		return (rv);
35511991Sheppo 	}
355212011SSriharsha.Basavapatna@Sun.COM 	if (vgen_inject_error(ldcp, VGEN_ERR_HTIMEOUT)) {
35531991Sheppo 		/* simulate timeout condition */
355412011SSriharsha.Basavapatna@Sun.COM 		vgen_inject_err_flag &= ~(VGEN_ERR_HTIMEOUT);
35551991Sheppo 		return (VGEN_SUCCESS);
35561991Sheppo 	}
35571991Sheppo #endif
35582793Slm66018 	rv = vgen_send_attr_info(ldcp);
35592793Slm66018 	if (rv != VGEN_SUCCESS) {
35601991Sheppo 		return (rv);
35611991Sheppo 	}
35622793Slm66018 
356312011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
356412011SSriharsha.Basavapatna@Sun.COM }
356512011SSriharsha.Basavapatna@Sun.COM 
356612011SSriharsha.Basavapatna@Sun.COM static int
vgen_handshake_phase3(vgen_ldc_t * ldcp)356712011SSriharsha.Basavapatna@Sun.COM vgen_handshake_phase3(vgen_ldc_t *ldcp)
356812011SSriharsha.Basavapatna@Sun.COM {
356912011SSriharsha.Basavapatna@Sun.COM 	int		rv;
357012011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
357112011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
357212011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->stats;
357312011SSriharsha.Basavapatna@Sun.COM 
357412011SSriharsha.Basavapatna@Sun.COM 	/* dring mode has been negotiated in attr phase; save in stats */
357512011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_mode = lp->dring_mode;
357612011SSriharsha.Basavapatna@Sun.COM 
357712011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {	/* RxDringData mode */
357812011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dringdata = vgen_handle_dringdata_shm;
357912011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_dringdata = vgen_dringsend_shm;
358012011SSriharsha.Basavapatna@Sun.COM 		if (!VGEN_PRI_ETH_DEFINED(vgenp)) {
358112011SSriharsha.Basavapatna@Sun.COM 			/*
358212011SSriharsha.Basavapatna@Sun.COM 			 * If priority frames are not in use, we don't need a
358312011SSriharsha.Basavapatna@Sun.COM 			 * separate wrapper function for 'tx', so we set it to
358412011SSriharsha.Basavapatna@Sun.COM 			 * 'tx_dringdata'. If priority frames are configured,
358512011SSriharsha.Basavapatna@Sun.COM 			 * we leave the 'tx' pointer as is (initialized in
358612011SSriharsha.Basavapatna@Sun.COM 			 * vgen_set_vnet_proto_ops()).
358712011SSriharsha.Basavapatna@Sun.COM 			 */
358812011SSriharsha.Basavapatna@Sun.COM 			ldcp->tx = ldcp->tx_dringdata;
35892793Slm66018 		}
359012011SSriharsha.Basavapatna@Sun.COM 	} else {					/* TxDring mode */
359112011SSriharsha.Basavapatna@Sun.COM 		ldcp->msg_thread = thread_create(NULL,
359212011SSriharsha.Basavapatna@Sun.COM 		    2 * DEFAULTSTKSZ, vgen_ldc_msg_worker, ldcp, 0,
359312011SSriharsha.Basavapatna@Sun.COM 		    &p0, TS_RUN, maxclsyspri);
359412011SSriharsha.Basavapatna@Sun.COM 	}
359512011SSriharsha.Basavapatna@Sun.COM 
359612011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_create_dring(ldcp);
359712011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
359812011SSriharsha.Basavapatna@Sun.COM 		return (rv);
35992793Slm66018 	}
36002793Slm66018 
36012793Slm66018 	/* update local dring_info params */
360212011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
360312011SSriharsha.Basavapatna@Sun.COM 		bcopy(&(ldcp->rx_dring_cookie),
360412011SSriharsha.Basavapatna@Sun.COM 		    &(ldcp->local_hparams.dring_cookie),
360512011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
360612011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.dring_ncookies = ldcp->rx_dring_ncookies;
360712011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.num_desc = ldcp->num_rxds;
360812011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.desc_size =
360912011SSriharsha.Basavapatna@Sun.COM 		    sizeof (vnet_rx_dringdata_desc_t);
361012011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_send_rx_dring_reg(ldcp);
361112011SSriharsha.Basavapatna@Sun.COM 	} else {
361212011SSriharsha.Basavapatna@Sun.COM 		bcopy(&(ldcp->tx_dring_cookie),
361312011SSriharsha.Basavapatna@Sun.COM 		    &(ldcp->local_hparams.dring_cookie),
361412011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
361512011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.dring_ncookies = ldcp->tx_dring_ncookies;
361612011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.num_desc = ldcp->num_txds;
361712011SSriharsha.Basavapatna@Sun.COM 		ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
361812011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_send_tx_dring_reg(ldcp);
361912011SSriharsha.Basavapatna@Sun.COM 	}
362012011SSriharsha.Basavapatna@Sun.COM 
36212793Slm66018 	if (rv != VGEN_SUCCESS) {
36221991Sheppo 		return (rv);
36231991Sheppo 	}
36241991Sheppo 
36251991Sheppo 	return (VGEN_SUCCESS);
36261991Sheppo }
36271991Sheppo 
36281991Sheppo /*
36295935Ssb155480  * Set vnet-protocol-version dependent functions based on version.
36305935Ssb155480  */
36315935Ssb155480 static void
vgen_set_vnet_proto_ops(vgen_ldc_t * ldcp)36325935Ssb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp)
36335935Ssb155480 {
36345935Ssb155480 	vgen_hparams_t	*lp = &ldcp->local_hparams;
36355935Ssb155480 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
36365935Ssb155480 
363712011SSriharsha.Basavapatna@Sun.COM 	/*
363812011SSriharsha.Basavapatna@Sun.COM 	 * Setup the appropriate dring data processing routine and any
363912011SSriharsha.Basavapatna@Sun.COM 	 * associated thread based on the version.
364012011SSriharsha.Basavapatna@Sun.COM 	 *
364112011SSriharsha.Basavapatna@Sun.COM 	 * In versions < 1.6, we only support TxDring mode. In this mode, the
364212011SSriharsha.Basavapatna@Sun.COM 	 * msg worker thread processes all types of VIO msgs (ctrl and data).
364312011SSriharsha.Basavapatna@Sun.COM 	 *
364412011SSriharsha.Basavapatna@Sun.COM 	 * In versions >= 1.6, we also support RxDringData mode. In this mode,
364512011SSriharsha.Basavapatna@Sun.COM 	 * all msgs including dring data messages are handled directly by the
364612011SSriharsha.Basavapatna@Sun.COM 	 * callback (intr) thread. The dring data msgs (msgtype: VIO_TYPE_DATA,
364712011SSriharsha.Basavapatna@Sun.COM 	 * subtype: VIO_SUBTYPE_INFO, subtype_env: VIO_DRING_DATA) can also be
364812011SSriharsha.Basavapatna@Sun.COM 	 * disabled while the polling thread is active, in which case the
364912011SSriharsha.Basavapatna@Sun.COM 	 * polling thread processes the rcv descriptor ring.
365012011SSriharsha.Basavapatna@Sun.COM 	 *
365112011SSriharsha.Basavapatna@Sun.COM 	 * However, for versions >= 1.6, we can force to only use TxDring mode.
365212011SSriharsha.Basavapatna@Sun.COM 	 * This could happen if RxDringData mode has been disabled (see
3653*13098SWentao.Yang@Sun.COM 	 * below) on this guest or on the peer guest. This info is determined
3654*13098SWentao.Yang@Sun.COM 	 * as part of attr exchange phase of handshake. Hence, we setup these
3655*13098SWentao.Yang@Sun.COM 	 * pointers for v1.6 after attr msg phase completes during handshake.
365612011SSriharsha.Basavapatna@Sun.COM 	 */
365712011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 6)) {	/* Ver >= 1.6 */
365812011SSriharsha.Basavapatna@Sun.COM 		/*
365912011SSriharsha.Basavapatna@Sun.COM 		 * Set data dring mode for vgen_send_attr_info().
366012011SSriharsha.Basavapatna@Sun.COM 		 */
3661*13098SWentao.Yang@Sun.COM 		if (vgen_mapin_avail(ldcp) == B_TRUE) {
366212011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING);
366312011SSriharsha.Basavapatna@Sun.COM 		} else {
366412011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = VIO_TX_DRING;
366512011SSriharsha.Basavapatna@Sun.COM 		}
366612011SSriharsha.Basavapatna@Sun.COM 	} else {				/* Ver <= 1.5 */
366712011SSriharsha.Basavapatna@Sun.COM 		lp->dring_mode = VIO_TX_DRING;
366812011SSriharsha.Basavapatna@Sun.COM 	}
366912011SSriharsha.Basavapatna@Sun.COM 
36709336SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 5)) {
36719336SSriharsha.Basavapatna@Sun.COM 		vgen_port_t	*portp = ldcp->portp;
36729336SSriharsha.Basavapatna@Sun.COM 		vnet_t		*vnetp = vgenp->vnetp;
36739336SSriharsha.Basavapatna@Sun.COM 		/*
36749336SSriharsha.Basavapatna@Sun.COM 		 * If the version negotiated with vswitch is >= 1.5 (link
36759336SSriharsha.Basavapatna@Sun.COM 		 * status update support), set the required bits in our
36769336SSriharsha.Basavapatna@Sun.COM 		 * attributes if this vnet device has been configured to get
36779336SSriharsha.Basavapatna@Sun.COM 		 * physical link state updates.
36789336SSriharsha.Basavapatna@Sun.COM 		 */
36799336SSriharsha.Basavapatna@Sun.COM 		if (portp == vgenp->vsw_portp && vnetp->pls_update == B_TRUE) {
36809336SSriharsha.Basavapatna@Sun.COM 			lp->physlink_update = PHYSLINK_UPDATE_STATE;
36819336SSriharsha.Basavapatna@Sun.COM 		} else {
36829336SSriharsha.Basavapatna@Sun.COM 			lp->physlink_update = PHYSLINK_UPDATE_NONE;
36839336SSriharsha.Basavapatna@Sun.COM 		}
36849336SSriharsha.Basavapatna@Sun.COM 	}
36859336SSriharsha.Basavapatna@Sun.COM 
36867529SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
36876419Ssb155480 		/*
36887529SSriharsha.Basavapatna@Sun.COM 		 * If the version negotiated with peer is >= 1.4(Jumbo Frame
36897529SSriharsha.Basavapatna@Sun.COM 		 * Support), set the mtu in our attributes to max_frame_size.
36906419Ssb155480 		 */
36916419Ssb155480 		lp->mtu = vgenp->max_frame_size;
36927529SSriharsha.Basavapatna@Sun.COM 	} else  if (VGEN_VER_EQ(ldcp, 1, 3)) {
36937529SSriharsha.Basavapatna@Sun.COM 		/*
36947529SSriharsha.Basavapatna@Sun.COM 		 * If the version negotiated with peer is == 1.3 (Vlan Tag
36957529SSriharsha.Basavapatna@Sun.COM 		 * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ.
36967529SSriharsha.Basavapatna@Sun.COM 		 */
36977529SSriharsha.Basavapatna@Sun.COM 		lp->mtu = ETHERMAX + VLAN_TAGSZ;
36986419Ssb155480 	} else {
36996419Ssb155480 		vgen_port_t	*portp = ldcp->portp;
37006419Ssb155480 		vnet_t		*vnetp = vgenp->vnetp;
37016419Ssb155480 		/*
37026419Ssb155480 		 * Pre-1.3 peers expect max frame size of ETHERMAX.
37036419Ssb155480 		 * We can negotiate that size with those peers provided the
37046419Ssb155480 		 * following conditions are true:
37056419Ssb155480 		 * - Only pvid is defined for our peer and there are no vids.
37066419Ssb155480 		 * - pvids are equal.
37076419Ssb155480 		 * If the above conditions are true, then we can send/recv only
37086419Ssb155480 		 * untagged frames of max size ETHERMAX.
37096419Ssb155480 		 */
37107529SSriharsha.Basavapatna@Sun.COM 		if (portp->nvids == 0 && portp->pvid == vnetp->pvid) {
37116419Ssb155480 			lp->mtu = ETHERMAX;
37126419Ssb155480 		}
37136419Ssb155480 	}
37146419Ssb155480 
371512011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 2)) {	/* Versions >= 1.2 */
371612011SSriharsha.Basavapatna@Sun.COM 		/*
371712011SSriharsha.Basavapatna@Sun.COM 		 * Starting v1.2 we support priority frames; so set the
371812011SSriharsha.Basavapatna@Sun.COM 		 * dring processing routines and xfer modes based on the
371912011SSriharsha.Basavapatna@Sun.COM 		 * version. Note that the dring routines could be changed after
372012011SSriharsha.Basavapatna@Sun.COM 		 * attribute handshake phase for versions >= 1.6 (See
372112011SSriharsha.Basavapatna@Sun.COM 		 * vgen_handshake_phase3())
372212011SSriharsha.Basavapatna@Sun.COM 		 */
372312011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_dringdata = vgen_dringsend;
372412011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dringdata = vgen_handle_dringdata;
37255935Ssb155480 
37265935Ssb155480 		if (VGEN_PRI_ETH_DEFINED(vgenp)) {
37275935Ssb155480 			/*
372812011SSriharsha.Basavapatna@Sun.COM 			 * Enable priority routines and pkt mode only if
37295935Ssb155480 			 * at least one pri-eth-type is specified in MD.
37305935Ssb155480 			 */
37315935Ssb155480 			ldcp->tx = vgen_ldcsend;
37325935Ssb155480 			ldcp->rx_pktdata = vgen_handle_pkt_data;
37335935Ssb155480 
37345935Ssb155480 			/* set xfer mode for vgen_send_attr_info() */
37355935Ssb155480 			lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
37365935Ssb155480 		} else {
373712011SSriharsha.Basavapatna@Sun.COM 			/* No priority eth types defined in MD */
373812011SSriharsha.Basavapatna@Sun.COM 			ldcp->tx = ldcp->tx_dringdata;
37395935Ssb155480 			ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
37405935Ssb155480 
374112011SSriharsha.Basavapatna@Sun.COM 			/* Set xfer mode for vgen_send_attr_info() */
37425935Ssb155480 			lp->xfer_mode = VIO_DRING_MODE_V1_2;
37435935Ssb155480 		}
374412011SSriharsha.Basavapatna@Sun.COM 	} else { /* Versions prior to 1.2  */
37455935Ssb155480 		vgen_reset_vnet_proto_ops(ldcp);
37465935Ssb155480 	}
37475935Ssb155480 }
37485935Ssb155480 
37495935Ssb155480 /*
37505935Ssb155480  * Reset vnet-protocol-version dependent functions to pre-v1.2.
37515935Ssb155480  */
37525935Ssb155480 static void
vgen_reset_vnet_proto_ops(vgen_ldc_t * ldcp)37535935Ssb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp)
37545935Ssb155480 {
37555935Ssb155480 	vgen_hparams_t	*lp = &ldcp->local_hparams;
37565935Ssb155480 
375712011SSriharsha.Basavapatna@Sun.COM 	ldcp->tx = ldcp->tx_dringdata = vgen_dringsend;
375812011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_dringdata = vgen_handle_dringdata;
37595935Ssb155480 	ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
37605935Ssb155480 
37615935Ssb155480 	/* set xfer mode for vgen_send_attr_info() */
37625935Ssb155480 	lp->xfer_mode = VIO_DRING_MODE_V1_0;
37635935Ssb155480 }
37645935Ssb155480 
37656419Ssb155480 static void
vgen_vlan_unaware_port_reset(vgen_port_t * portp)37666419Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp)
37676419Ssb155480 {
376812011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp = portp->ldcp;
37696419Ssb155480 	vgen_t		*vgenp = portp->vgenp;
37706419Ssb155480 	vnet_t		*vnetp = vgenp->vnetp;
377112011SSriharsha.Basavapatna@Sun.COM 	boolean_t	need_reset = B_FALSE;
37726419Ssb155480 
37736419Ssb155480 	mutex_enter(&ldcp->cblock);
37746419Ssb155480 
37756419Ssb155480 	/*
37766419Ssb155480 	 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
37776419Ssb155480 	 * the connection. See comments in vgen_set_vnet_proto_ops().
37786419Ssb155480 	 */
37796419Ssb155480 	if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) &&
37806419Ssb155480 	    (portp->nvids != 0 || portp->pvid != vnetp->pvid)) {
378112011SSriharsha.Basavapatna@Sun.COM 		need_reset = B_TRUE;
378212011SSriharsha.Basavapatna@Sun.COM 	}
37836419Ssb155480 	mutex_exit(&ldcp->cblock);
37846419Ssb155480 
378512011SSriharsha.Basavapatna@Sun.COM 	if (need_reset == B_TRUE) {
378612011SSriharsha.Basavapatna@Sun.COM 		(void) vgen_ldc_reset(ldcp, VGEN_OTHER);
378712011SSriharsha.Basavapatna@Sun.COM 	}
37886419Ssb155480 }
37896419Ssb155480 
37906419Ssb155480 static void
vgen_port_reset(vgen_port_t * portp)37919336SSriharsha.Basavapatna@Sun.COM vgen_port_reset(vgen_port_t *portp)
37929336SSriharsha.Basavapatna@Sun.COM {
379312011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_ldc_reset(portp->ldcp, VGEN_OTHER);
37949336SSriharsha.Basavapatna@Sun.COM }
37959336SSriharsha.Basavapatna@Sun.COM 
37969336SSriharsha.Basavapatna@Sun.COM static void
vgen_reset_vlan_unaware_ports(vgen_t * vgenp)37976419Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp)
37986419Ssb155480 {
37996419Ssb155480 	vgen_port_t	*portp;
38006419Ssb155480 	vgen_portlist_t	*plistp;
38016419Ssb155480 
38026419Ssb155480 	plistp = &(vgenp->vgenports);
38036419Ssb155480 	READ_ENTER(&plistp->rwlock);
38046419Ssb155480 
38056419Ssb155480 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
38066419Ssb155480 
38076419Ssb155480 		vgen_vlan_unaware_port_reset(portp);
38086419Ssb155480 
38096419Ssb155480 	}
38106419Ssb155480 
38116419Ssb155480 	RW_EXIT(&plistp->rwlock);
38126419Ssb155480 }
38136419Ssb155480 
38149336SSriharsha.Basavapatna@Sun.COM static void
vgen_reset_vsw_port(vgen_t * vgenp)38159336SSriharsha.Basavapatna@Sun.COM vgen_reset_vsw_port(vgen_t *vgenp)
38169336SSriharsha.Basavapatna@Sun.COM {
38179336SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*portp;
38189336SSriharsha.Basavapatna@Sun.COM 
38199336SSriharsha.Basavapatna@Sun.COM 	if ((portp = vgenp->vsw_portp) != NULL) {
38209336SSriharsha.Basavapatna@Sun.COM 		vgen_port_reset(portp);
38219336SSriharsha.Basavapatna@Sun.COM 	}
38229336SSriharsha.Basavapatna@Sun.COM }
38239336SSriharsha.Basavapatna@Sun.COM 
38241991Sheppo static void
vgen_setup_handshake_params(vgen_ldc_t * ldcp)382512011SSriharsha.Basavapatna@Sun.COM vgen_setup_handshake_params(vgen_ldc_t *ldcp)
38261991Sheppo {
382712011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
38281991Sheppo 
38291991Sheppo 	/*
38301991Sheppo 	 * clear local handshake params and initialize.
38311991Sheppo 	 */
38321991Sheppo 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
38331991Sheppo 
38341991Sheppo 	/* set version to the highest version supported */
38351991Sheppo 	ldcp->local_hparams.ver_major =
38364650Sraghuram 	    ldcp->vgen_versions[0].ver_major;
38371991Sheppo 	ldcp->local_hparams.ver_minor =
38384650Sraghuram 	    ldcp->vgen_versions[0].ver_minor;
38391991Sheppo 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
38401991Sheppo 
38411991Sheppo 	/* set attr_info params */
38426419Ssb155480 	ldcp->local_hparams.mtu = vgenp->max_frame_size;
38431991Sheppo 	ldcp->local_hparams.addr =
38445462Swentaoy 	    vnet_macaddr_strtoul(vgenp->macaddr);
38451991Sheppo 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
38465935Ssb155480 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0;
38471991Sheppo 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
38489336SSriharsha.Basavapatna@Sun.COM 	ldcp->local_hparams.physlink_update = PHYSLINK_UPDATE_NONE;
38491991Sheppo 
385012011SSriharsha.Basavapatna@Sun.COM 	/* reset protocol version specific function pointers */
385112011SSriharsha.Basavapatna@Sun.COM 	vgen_reset_vnet_proto_ops(ldcp);
38521991Sheppo 	ldcp->local_hparams.dring_ident = 0;
385312011SSriharsha.Basavapatna@Sun.COM 	ldcp->local_hparams.dring_ready = B_FALSE;
38541991Sheppo 
38551991Sheppo 	/* clear peer_hparams */
38561991Sheppo 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
385712011SSriharsha.Basavapatna@Sun.COM 	ldcp->peer_hparams.dring_ready = B_FALSE;
385812011SSriharsha.Basavapatna@Sun.COM }
385912011SSriharsha.Basavapatna@Sun.COM 
386012011SSriharsha.Basavapatna@Sun.COM /*
386112011SSriharsha.Basavapatna@Sun.COM  * Process Channel Reset. We tear down the resources (timers, threads,
386212011SSriharsha.Basavapatna@Sun.COM  * descriptor rings etc) associated with the channel and reinitialize the
386312011SSriharsha.Basavapatna@Sun.COM  * channel based on the flags.
386412011SSriharsha.Basavapatna@Sun.COM  *
386512011SSriharsha.Basavapatna@Sun.COM  * Arguments:
386612011SSriharsha.Basavapatna@Sun.COM  *    ldcp:	The channel being processed.
386712011SSriharsha.Basavapatna@Sun.COM  *
386812011SSriharsha.Basavapatna@Sun.COM  *    flags:
386912011SSriharsha.Basavapatna@Sun.COM  *	VGEN_FLAG_EVT_RESET:
387012011SSriharsha.Basavapatna@Sun.COM  *		A ECONNRESET error occured while doing ldc operations such as
387112011SSriharsha.Basavapatna@Sun.COM  *		ldc_read() or ldc_write(); the channel is already reset and it
387212011SSriharsha.Basavapatna@Sun.COM  *		needs to be handled.
387312011SSriharsha.Basavapatna@Sun.COM  *	VGEN_FLAG_NEED_LDCRESET:
387412011SSriharsha.Basavapatna@Sun.COM  *		Some other errors occured and the error handling code needs to
387512011SSriharsha.Basavapatna@Sun.COM  *		explicitly reset the channel and restart handshake with the
387612011SSriharsha.Basavapatna@Sun.COM  *		peer. The error could be either in ldc operations or other
387712011SSriharsha.Basavapatna@Sun.COM  *		parts of the code such as timeouts or mdeg events etc.
387812011SSriharsha.Basavapatna@Sun.COM  *	VGEN_FLAG_UNINIT:
387912011SSriharsha.Basavapatna@Sun.COM  *		The channel is being torn down; no need to bring up the channel
388012011SSriharsha.Basavapatna@Sun.COM  *		after resetting.
388112011SSriharsha.Basavapatna@Sun.COM  */
388212011SSriharsha.Basavapatna@Sun.COM static int
vgen_process_reset(vgen_ldc_t * ldcp,int flags)388312011SSriharsha.Basavapatna@Sun.COM vgen_process_reset(vgen_ldc_t *ldcp, int flags)
388412011SSriharsha.Basavapatna@Sun.COM {
388512011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
388612011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*portp = ldcp->portp;
388712011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t  *lp = &ldcp->local_hparams;
388812011SSriharsha.Basavapatna@Sun.COM 	boolean_t	is_vsw_port = B_FALSE;
388912011SSriharsha.Basavapatna@Sun.COM 	boolean_t	link_update = B_FALSE;
389012011SSriharsha.Basavapatna@Sun.COM 	ldc_status_t	istatus;
389112011SSriharsha.Basavapatna@Sun.COM 	int		rv;
389212011SSriharsha.Basavapatna@Sun.COM 	uint_t		retries = 0;
389312011SSriharsha.Basavapatna@Sun.COM 	timeout_id_t	htid = 0;
389412011SSriharsha.Basavapatna@Sun.COM 	timeout_id_t	wd_tid = 0;
389512011SSriharsha.Basavapatna@Sun.COM 
389612011SSriharsha.Basavapatna@Sun.COM 	if (portp == vgenp->vsw_portp) { /* vswitch port ? */
389712011SSriharsha.Basavapatna@Sun.COM 		is_vsw_port = B_TRUE;
389812011SSriharsha.Basavapatna@Sun.COM 	}
389912011SSriharsha.Basavapatna@Sun.COM 
390012011SSriharsha.Basavapatna@Sun.COM 	/*
390112011SSriharsha.Basavapatna@Sun.COM 	 * Report that the channel is being reset; it ensures that any HybridIO
390212011SSriharsha.Basavapatna@Sun.COM 	 * configuration is torn down before we reset the channel if it is not
390312011SSriharsha.Basavapatna@Sun.COM 	 * already reset (flags == VGEN_FLAG_NEED_LDCRESET).
390412011SSriharsha.Basavapatna@Sun.COM 	 */
390512011SSriharsha.Basavapatna@Sun.COM 	if (is_vsw_port == B_TRUE) {
390612011SSriharsha.Basavapatna@Sun.COM 		vio_net_report_err_t rep_err = portp->vcb.vio_net_report_err;
390712011SSriharsha.Basavapatna@Sun.COM 		rep_err(portp->vhp, VIO_NET_RES_DOWN);
390812011SSriharsha.Basavapatna@Sun.COM 	}
390912011SSriharsha.Basavapatna@Sun.COM 
391012011SSriharsha.Basavapatna@Sun.COM again:
391112011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->cblock);
391212011SSriharsha.Basavapatna@Sun.COM 
391312011SSriharsha.Basavapatna@Sun.COM 	/* Clear hstate and hphase */
391412011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate = 0;
391512011SSriharsha.Basavapatna@Sun.COM 	ldcp->hphase = VH_PHASE0;
391612011SSriharsha.Basavapatna@Sun.COM 	if (flags == VGEN_FLAG_NEED_LDCRESET || flags == VGEN_FLAG_UNINIT) {
39174647Sraghuram 		DWARN(vgenp, ldcp, "Doing Channel Reset...\n");
39182410Slm66018 		(void) ldc_down(ldcp->ldc_handle);
39191991Sheppo 		(void) ldc_status(ldcp->ldc_handle, &istatus);
392012011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Reset Done, ldc_status(%d)\n", istatus);
39211991Sheppo 		ldcp->ldc_status = istatus;
39222793Slm66018 
392312011SSriharsha.Basavapatna@Sun.COM 		if (flags == VGEN_FLAG_UNINIT) {
392412011SSriharsha.Basavapatna@Sun.COM 			/* disable further callbacks */
392512011SSriharsha.Basavapatna@Sun.COM 			rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
392612011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
392712011SSriharsha.Basavapatna@Sun.COM 				DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n");
392812011SSriharsha.Basavapatna@Sun.COM 			}
39292793Slm66018 		}
393012011SSriharsha.Basavapatna@Sun.COM 
393112011SSriharsha.Basavapatna@Sun.COM 	} else {
393212011SSriharsha.Basavapatna@Sun.COM 		/* flags == VGEN_FLAG_EVT_RESET */
393312011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc status(%d)\n", ldcp->ldc_status);
393412011SSriharsha.Basavapatna@Sun.COM 	}
39359336SSriharsha.Basavapatna@Sun.COM 
39369336SSriharsha.Basavapatna@Sun.COM 	/*
39379336SSriharsha.Basavapatna@Sun.COM 	 * As the connection is now reset, mark the channel
39389336SSriharsha.Basavapatna@Sun.COM 	 * link_state as 'down' and notify the stack if needed.
39399336SSriharsha.Basavapatna@Sun.COM 	 */
39409336SSriharsha.Basavapatna@Sun.COM 	if (ldcp->link_state != LINK_STATE_DOWN) {
39419336SSriharsha.Basavapatna@Sun.COM 		ldcp->link_state = LINK_STATE_DOWN;
39429336SSriharsha.Basavapatna@Sun.COM 
394312011SSriharsha.Basavapatna@Sun.COM 		if (is_vsw_port == B_TRUE) { /* vswitch port ? */
39449336SSriharsha.Basavapatna@Sun.COM 			/*
39459336SSriharsha.Basavapatna@Sun.COM 			 * As the channel link is down, mark physical link also
39469336SSriharsha.Basavapatna@Sun.COM 			 * as down. After the channel comes back up and
39479336SSriharsha.Basavapatna@Sun.COM 			 * handshake completes, we will get an update on the
39489336SSriharsha.Basavapatna@Sun.COM 			 * physlink state from vswitch (if this device has been
39499336SSriharsha.Basavapatna@Sun.COM 			 * configured to get phys link updates).
39509336SSriharsha.Basavapatna@Sun.COM 			 */
39519336SSriharsha.Basavapatna@Sun.COM 			vgenp->phys_link_state = LINK_STATE_DOWN;
395212011SSriharsha.Basavapatna@Sun.COM 			link_update = B_TRUE;
395312011SSriharsha.Basavapatna@Sun.COM 
395412011SSriharsha.Basavapatna@Sun.COM 		}
395512011SSriharsha.Basavapatna@Sun.COM 	}
395612011SSriharsha.Basavapatna@Sun.COM 
395712011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->htid != 0) {
395812011SSriharsha.Basavapatna@Sun.COM 		htid = ldcp->htid;
395912011SSriharsha.Basavapatna@Sun.COM 		ldcp->htid = 0;
396012011SSriharsha.Basavapatna@Sun.COM 	}
396112011SSriharsha.Basavapatna@Sun.COM 
396212011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->wd_tid != 0) {
396312011SSriharsha.Basavapatna@Sun.COM 		wd_tid = ldcp->wd_tid;
396412011SSriharsha.Basavapatna@Sun.COM 		ldcp->wd_tid = 0;
396512011SSriharsha.Basavapatna@Sun.COM 	}
396612011SSriharsha.Basavapatna@Sun.COM 
396712011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->cblock);
396812011SSriharsha.Basavapatna@Sun.COM 
396912011SSriharsha.Basavapatna@Sun.COM 	/* Update link state to the stack */
397012011SSriharsha.Basavapatna@Sun.COM 	if (link_update == B_TRUE) {
397112011SSriharsha.Basavapatna@Sun.COM 		vgen_link_update(vgenp, ldcp->link_state);
397212011SSriharsha.Basavapatna@Sun.COM 	}
397312011SSriharsha.Basavapatna@Sun.COM 
397412011SSriharsha.Basavapatna@Sun.COM 	/*
397512011SSriharsha.Basavapatna@Sun.COM 	 * As the channel is being reset, redirect traffic to the peer through
397612011SSriharsha.Basavapatna@Sun.COM 	 * vswitch, until the channel becomes ready to be used again.
397712011SSriharsha.Basavapatna@Sun.COM 	 */
397812011SSriharsha.Basavapatna@Sun.COM 	if (is_vsw_port == B_FALSE && vgenp->vsw_portp != NULL) {
397912011SSriharsha.Basavapatna@Sun.COM 		(void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
398012011SSriharsha.Basavapatna@Sun.COM 	}
398112011SSriharsha.Basavapatna@Sun.COM 
398212011SSriharsha.Basavapatna@Sun.COM 	/* Cancel handshake watchdog timeout */
398312011SSriharsha.Basavapatna@Sun.COM 	if (htid) {
398412011SSriharsha.Basavapatna@Sun.COM 		(void) untimeout(htid);
398512011SSriharsha.Basavapatna@Sun.COM 	}
398612011SSriharsha.Basavapatna@Sun.COM 
398712011SSriharsha.Basavapatna@Sun.COM 	/* Cancel transmit watchdog timeout */
398812011SSriharsha.Basavapatna@Sun.COM 	if (wd_tid) {
398912011SSriharsha.Basavapatna@Sun.COM 		(void) untimeout(wd_tid);
399012011SSriharsha.Basavapatna@Sun.COM 	}
399112011SSriharsha.Basavapatna@Sun.COM 
399212011SSriharsha.Basavapatna@Sun.COM 	/* Stop the msg worker thread */
399312011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_TX_DRING && curthread != ldcp->msg_thread) {
399412011SSriharsha.Basavapatna@Sun.COM 		vgen_stop_msg_thread(ldcp);
399512011SSriharsha.Basavapatna@Sun.COM 	}
399612011SSriharsha.Basavapatna@Sun.COM 
399712011SSriharsha.Basavapatna@Sun.COM 	/* Grab all locks while we tear down tx/rx resources */
399812011SSriharsha.Basavapatna@Sun.COM 	LDC_LOCK(ldcp);
399912011SSriharsha.Basavapatna@Sun.COM 
400012011SSriharsha.Basavapatna@Sun.COM 	/* Destroy the local dring which is exported to the peer */
400112011SSriharsha.Basavapatna@Sun.COM 	vgen_destroy_dring(ldcp);
400212011SSriharsha.Basavapatna@Sun.COM 
400312011SSriharsha.Basavapatna@Sun.COM 	/* Unmap the remote dring which is imported from the peer */
400412011SSriharsha.Basavapatna@Sun.COM 	vgen_unmap_dring(ldcp);
400512011SSriharsha.Basavapatna@Sun.COM 
400612011SSriharsha.Basavapatna@Sun.COM 	/*
400712011SSriharsha.Basavapatna@Sun.COM 	 * Bring up the channel and restart handshake
400812011SSriharsha.Basavapatna@Sun.COM 	 * only if the channel is not being torn down.
400912011SSriharsha.Basavapatna@Sun.COM 	 */
401012011SSriharsha.Basavapatna@Sun.COM 	if (flags != VGEN_FLAG_UNINIT) {
401112011SSriharsha.Basavapatna@Sun.COM 
401212011SSriharsha.Basavapatna@Sun.COM 		/* Setup handshake parameters to restart a new handshake */
401312011SSriharsha.Basavapatna@Sun.COM 		vgen_setup_handshake_params(ldcp);
401412011SSriharsha.Basavapatna@Sun.COM 
401512011SSriharsha.Basavapatna@Sun.COM 		/* Bring the channel up */
401612011SSriharsha.Basavapatna@Sun.COM 		vgen_ldc_up(ldcp);
401712011SSriharsha.Basavapatna@Sun.COM 
401812011SSriharsha.Basavapatna@Sun.COM 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
401912011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "ldc_status err\n");
402012011SSriharsha.Basavapatna@Sun.COM 		} else {
402112011SSriharsha.Basavapatna@Sun.COM 			ldcp->ldc_status = istatus;
402212011SSriharsha.Basavapatna@Sun.COM 		}
402312011SSriharsha.Basavapatna@Sun.COM 
402412011SSriharsha.Basavapatna@Sun.COM 		/* If the channel is UP, start handshake */
402512011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->ldc_status == LDC_UP) {
402612011SSriharsha.Basavapatna@Sun.COM 
402712011SSriharsha.Basavapatna@Sun.COM 			if (is_vsw_port == B_FALSE) {
402812011SSriharsha.Basavapatna@Sun.COM 				/*
402912011SSriharsha.Basavapatna@Sun.COM 				 * Channel is up; use this port from now on.
403012011SSriharsha.Basavapatna@Sun.COM 				 */
403112011SSriharsha.Basavapatna@Sun.COM 				(void) atomic_swap_32(&portp->use_vsw_port,
403212011SSriharsha.Basavapatna@Sun.COM 				    B_FALSE);
403312011SSriharsha.Basavapatna@Sun.COM 			}
403412011SSriharsha.Basavapatna@Sun.COM 
403512011SSriharsha.Basavapatna@Sun.COM 			/* Initialize local session id */
403612011SSriharsha.Basavapatna@Sun.COM 			ldcp->local_sid = ddi_get_lbolt();
403712011SSriharsha.Basavapatna@Sun.COM 
403812011SSriharsha.Basavapatna@Sun.COM 			/* clear peer session id */
403912011SSriharsha.Basavapatna@Sun.COM 			ldcp->peer_sid = 0;
404012011SSriharsha.Basavapatna@Sun.COM 
404112011SSriharsha.Basavapatna@Sun.COM 			/*
404212011SSriharsha.Basavapatna@Sun.COM 			 * Initiate Handshake process with peer ldc endpoint by
404312011SSriharsha.Basavapatna@Sun.COM 			 * sending version info vio message. If that fails we
404412011SSriharsha.Basavapatna@Sun.COM 			 * go back to the top of this function to process the
404512011SSriharsha.Basavapatna@Sun.COM 			 * error again. Note that we can be in this loop for
404612011SSriharsha.Basavapatna@Sun.COM 			 * 'vgen_ldc_max_resets' times, after which the channel
404712011SSriharsha.Basavapatna@Sun.COM 			 * is not brought up.
404812011SSriharsha.Basavapatna@Sun.COM 			 */
404912011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->tclock);
405012011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->txlock);
405112011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->wrlock);
405212011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->rxlock);
405312011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
40549336SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->cblock);
405512011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
405612011SSriharsha.Basavapatna@Sun.COM 				if (rv == ECONNRESET) {
405712011SSriharsha.Basavapatna@Sun.COM 					flags = VGEN_FLAG_EVT_RESET;
405812011SSriharsha.Basavapatna@Sun.COM 				} else {
405912011SSriharsha.Basavapatna@Sun.COM 					flags = VGEN_FLAG_NEED_LDCRESET;
406012011SSriharsha.Basavapatna@Sun.COM 				}
406112011SSriharsha.Basavapatna@Sun.COM 
406212011SSriharsha.Basavapatna@Sun.COM 				/*
406312011SSriharsha.Basavapatna@Sun.COM 				 * We still hold 'reset_in_progress'; so we can
406412011SSriharsha.Basavapatna@Sun.COM 				 * just loop back to the top to restart error
406512011SSriharsha.Basavapatna@Sun.COM 				 * processing.
406612011SSriharsha.Basavapatna@Sun.COM 				 */
406712011SSriharsha.Basavapatna@Sun.COM 				goto again;
406812011SSriharsha.Basavapatna@Sun.COM 			}
406912011SSriharsha.Basavapatna@Sun.COM 		} else {
407012011SSriharsha.Basavapatna@Sun.COM 			LDC_UNLOCK(ldcp);
40719336SSriharsha.Basavapatna@Sun.COM 		}
407212011SSriharsha.Basavapatna@Sun.COM 
407312011SSriharsha.Basavapatna@Sun.COM 	} else {	/* flags == VGEN_FLAG_UNINIT */
407412011SSriharsha.Basavapatna@Sun.COM 
407512011SSriharsha.Basavapatna@Sun.COM 		/* Close the channel - retry on EAGAIN */
407612011SSriharsha.Basavapatna@Sun.COM 		while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) {
407712011SSriharsha.Basavapatna@Sun.COM 			if (++retries > vgen_ldccl_retries) {
407812011SSriharsha.Basavapatna@Sun.COM 				break;
407912011SSriharsha.Basavapatna@Sun.COM 			}
408012011SSriharsha.Basavapatna@Sun.COM 			drv_usecwait(VGEN_LDC_CLOSE_DELAY);
408112011SSriharsha.Basavapatna@Sun.COM 		}
408212011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
408312011SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_NOTE,
408412011SSriharsha.Basavapatna@Sun.COM 			    "!vnet%d: Error(%d) closing the channel(0x%lx)\n",
408512011SSriharsha.Basavapatna@Sun.COM 			    vgenp->instance, rv, ldcp->ldc_id);
408612011SSriharsha.Basavapatna@Sun.COM 		}
408712011SSriharsha.Basavapatna@Sun.COM 
408812011SSriharsha.Basavapatna@Sun.COM 		ldcp->ldc_reset_count = 0;
408912011SSriharsha.Basavapatna@Sun.COM 		ldcp->ldc_status = LDC_INIT;
409012011SSriharsha.Basavapatna@Sun.COM 		ldcp->flags &= ~(CHANNEL_STARTED);
409112011SSriharsha.Basavapatna@Sun.COM 
409212011SSriharsha.Basavapatna@Sun.COM 		LDC_UNLOCK(ldcp);
409312011SSriharsha.Basavapatna@Sun.COM 	}
409412011SSriharsha.Basavapatna@Sun.COM 
409512011SSriharsha.Basavapatna@Sun.COM 	/* Done processing channel reset; clear the atomic flag */
409612011SSriharsha.Basavapatna@Sun.COM 	ldcp->reset_in_progress = 0;
409712011SSriharsha.Basavapatna@Sun.COM 	return (0);
40981991Sheppo }
40991991Sheppo 
41001991Sheppo /*
41011991Sheppo  * Initiate handshake with the peer by sending various messages
41021991Sheppo  * based on the handshake-phase that the channel is currently in.
41031991Sheppo  */
410412011SSriharsha.Basavapatna@Sun.COM static int
vgen_handshake(vgen_ldc_t * ldcp)41051991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
41061991Sheppo {
41079336SSriharsha.Basavapatna@Sun.COM 	uint32_t	hphase = ldcp->hphase;
41089336SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
41099336SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
411012011SSriharsha.Basavapatna@Sun.COM 	timeout_id_t	htid;
41111991Sheppo 
41121991Sheppo 	switch (hphase) {
41131991Sheppo 
41141991Sheppo 	case VH_PHASE1:
41151991Sheppo 
41161991Sheppo 		/*
41171991Sheppo 		 * start timer, for entire handshake process, turn this timer
41181991Sheppo 		 * off if all phases of handshake complete successfully and
411912011SSriharsha.Basavapatna@Sun.COM 		 * hphase goes to VH_DONE(below) or channel is reset due to
412012011SSriharsha.Basavapatna@Sun.COM 		 * errors or vgen_ldc_uninit() is invoked(vgen_stop).
41211991Sheppo 		 */
41227572SWentao.Yang@Sun.COM 		ASSERT(ldcp->htid == 0);
41231991Sheppo 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
41245171Ssb155480 		    drv_usectohz(vgen_hwd_interval * MICROSEC));
41251991Sheppo 
41261991Sheppo 		/* Phase 1 involves negotiating the version */
41272793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
41281991Sheppo 		break;
41291991Sheppo 
41301991Sheppo 	case VH_PHASE2:
41312793Slm66018 		rv = vgen_handshake_phase2(ldcp);
41321991Sheppo 		break;
41331991Sheppo 
41341991Sheppo 	case VH_PHASE3:
413512011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handshake_phase3(ldcp);
413612011SSriharsha.Basavapatna@Sun.COM 		break;
413712011SSriharsha.Basavapatna@Sun.COM 
413812011SSriharsha.Basavapatna@Sun.COM 	case VH_PHASE4:
41392793Slm66018 		rv = vgen_send_rdx_info(ldcp);
41401991Sheppo 		break;
41411991Sheppo 
41421991Sheppo 	case VH_DONE:
414312011SSriharsha.Basavapatna@Sun.COM 
414412011SSriharsha.Basavapatna@Sun.COM 		ldcp->ldc_reset_count = 0;
414512011SSriharsha.Basavapatna@Sun.COM 
41464647Sraghuram 		DBG1(vgenp, ldcp, "Handshake Done\n");
41471991Sheppo 
41489336SSriharsha.Basavapatna@Sun.COM 		/*
41499336SSriharsha.Basavapatna@Sun.COM 		 * The channel is up and handshake is done successfully. Now we
41509336SSriharsha.Basavapatna@Sun.COM 		 * can mark the channel link_state as 'up'. We also notify the
41519336SSriharsha.Basavapatna@Sun.COM 		 * stack if the channel is connected to vswitch.
41529336SSriharsha.Basavapatna@Sun.COM 		 */
41539336SSriharsha.Basavapatna@Sun.COM 		ldcp->link_state = LINK_STATE_UP;
41549336SSriharsha.Basavapatna@Sun.COM 
41555171Ssb155480 		if (ldcp->portp == vgenp->vsw_portp) {
41565171Ssb155480 			/*
41575171Ssb155480 			 * If this channel(port) is connected to vsw,
41585171Ssb155480 			 * need to sync multicast table with vsw.
41595171Ssb155480 			 */
41602793Slm66018 			rv = vgen_send_mcast_info(ldcp);
416112011SSriharsha.Basavapatna@Sun.COM 			if (rv != VGEN_SUCCESS)
416211543SWentao.Yang@Sun.COM 				break;
41631991Sheppo 
41649336SSriharsha.Basavapatna@Sun.COM 			if (vgenp->pls_negotiated == B_FALSE) {
41659336SSriharsha.Basavapatna@Sun.COM 				/*
41669336SSriharsha.Basavapatna@Sun.COM 				 * We haven't negotiated with vswitch to get
41679336SSriharsha.Basavapatna@Sun.COM 				 * physical link state updates. We can update
41689336SSriharsha.Basavapatna@Sun.COM 				 * update the stack at this point as the
41699336SSriharsha.Basavapatna@Sun.COM 				 * channel to vswitch is up and the handshake
41709336SSriharsha.Basavapatna@Sun.COM 				 * is done successfully.
41719336SSriharsha.Basavapatna@Sun.COM 				 *
41729336SSriharsha.Basavapatna@Sun.COM 				 * If we have negotiated to get physical link
41739336SSriharsha.Basavapatna@Sun.COM 				 * state updates, then we won't notify the
41749336SSriharsha.Basavapatna@Sun.COM 				 * the stack here; we do that as soon as
41759336SSriharsha.Basavapatna@Sun.COM 				 * vswitch sends us the initial phys link state
41769336SSriharsha.Basavapatna@Sun.COM 				 * (see vgen_handle_physlink_info()).
41779336SSriharsha.Basavapatna@Sun.COM 				 */
417811543SWentao.Yang@Sun.COM 				mutex_exit(&ldcp->cblock);
41799336SSriharsha.Basavapatna@Sun.COM 				vgen_link_update(vgenp, ldcp->link_state);
418011543SWentao.Yang@Sun.COM 				mutex_enter(&ldcp->cblock);
41819336SSriharsha.Basavapatna@Sun.COM 			}
418212011SSriharsha.Basavapatna@Sun.COM 		}
418312011SSriharsha.Basavapatna@Sun.COM 
418412011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->htid != 0) {
418512011SSriharsha.Basavapatna@Sun.COM 			htid = ldcp->htid;
418612011SSriharsha.Basavapatna@Sun.COM 			ldcp->htid = 0;
418712011SSriharsha.Basavapatna@Sun.COM 
418812011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->cblock);
418912011SSriharsha.Basavapatna@Sun.COM 			(void) untimeout(htid);
419012011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->cblock);
41911991Sheppo 		}
41922793Slm66018 
41932793Slm66018 		/*
41942793Slm66018 		 * Check if mac layer should be notified to restart
41952793Slm66018 		 * transmissions. This can happen if the channel got
419612011SSriharsha.Basavapatna@Sun.COM 		 * reset and while tx_blocked is set.
41972793Slm66018 		 */
41982793Slm66018 		mutex_enter(&ldcp->tclock);
419912011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->tx_blocked) {
42006495Sspeer 			vio_net_tx_update_t vtx_update =
42016495Sspeer 			    ldcp->portp->vcb.vio_net_tx_update;
42026495Sspeer 
420312011SSriharsha.Basavapatna@Sun.COM 			ldcp->tx_blocked = B_FALSE;
42046495Sspeer 			vtx_update(ldcp->portp->vhp);
42052793Slm66018 		}
42062793Slm66018 		mutex_exit(&ldcp->tclock);
42072793Slm66018 
420812011SSriharsha.Basavapatna@Sun.COM 		/* start transmit watchdog timer */
420912011SSriharsha.Basavapatna@Sun.COM 		ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
421012011SSriharsha.Basavapatna@Sun.COM 		    drv_usectohz(vgen_txwd_interval * 1000));
421112011SSriharsha.Basavapatna@Sun.COM 
42121991Sheppo 		break;
42131991Sheppo 
42141991Sheppo 	default:
42151991Sheppo 		break;
42161991Sheppo 	}
42172793Slm66018 
421812011SSriharsha.Basavapatna@Sun.COM 	return (rv);
42191991Sheppo }
42201991Sheppo 
42211991Sheppo /*
42221991Sheppo  * Check if the current handshake phase has completed successfully and
42231991Sheppo  * return the status.
42241991Sheppo  */
42251991Sheppo static int
vgen_handshake_done(vgen_ldc_t * ldcp)42261991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
42271991Sheppo {
42284647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
42291991Sheppo 	uint32_t	hphase = ldcp->hphase;
42301991Sheppo 	int 		status = 0;
42311991Sheppo 
42321991Sheppo 	switch (hphase) {
42331991Sheppo 
42341991Sheppo 	case VH_PHASE1:
42351991Sheppo 		/*
42361991Sheppo 		 * Phase1 is done, if version negotiation
42371991Sheppo 		 * completed successfully.
42381991Sheppo 		 */
42391991Sheppo 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
42404650Sraghuram 		    VER_NEGOTIATED);
42411991Sheppo 		break;
42421991Sheppo 
42431991Sheppo 	case VH_PHASE2:
42441991Sheppo 		/*
424512011SSriharsha.Basavapatna@Sun.COM 		 * Phase 2 is done, if attr info
424612011SSriharsha.Basavapatna@Sun.COM 		 * has been exchanged successfully.
42471991Sheppo 		 */
424812011SSriharsha.Basavapatna@Sun.COM 		status = ((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
424912011SSriharsha.Basavapatna@Sun.COM 		    ATTR_INFO_EXCHANGED);
42501991Sheppo 		break;
42511991Sheppo 
42521991Sheppo 	case VH_PHASE3:
425312011SSriharsha.Basavapatna@Sun.COM 		/*
425412011SSriharsha.Basavapatna@Sun.COM 		 * Phase 3 is done, if dring registration
425512011SSriharsha.Basavapatna@Sun.COM 		 * has been exchanged successfully.
425612011SSriharsha.Basavapatna@Sun.COM 		 */
425712011SSriharsha.Basavapatna@Sun.COM 		status = ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
425812011SSriharsha.Basavapatna@Sun.COM 		    DRING_INFO_EXCHANGED);
425912011SSriharsha.Basavapatna@Sun.COM 		break;
426012011SSriharsha.Basavapatna@Sun.COM 
426112011SSriharsha.Basavapatna@Sun.COM 	case VH_PHASE4:
426212011SSriharsha.Basavapatna@Sun.COM 		/* Phase 4 is done, if rdx msg has been exchanged */
42631991Sheppo 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
42644650Sraghuram 		    RDX_EXCHANGED);
42651991Sheppo 		break;
42661991Sheppo 
42671991Sheppo 	default:
42681991Sheppo 		break;
42691991Sheppo 	}
42701991Sheppo 
42711991Sheppo 	if (status == 0) {
42721991Sheppo 		return (VGEN_FAILURE);
42731991Sheppo 	}
42744647Sraghuram 	DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase);
42751991Sheppo 	return (VGEN_SUCCESS);
42761991Sheppo }
42771991Sheppo 
42789336SSriharsha.Basavapatna@Sun.COM /*
42799336SSriharsha.Basavapatna@Sun.COM  * Link State Update Notes:
42809336SSriharsha.Basavapatna@Sun.COM  * The link state of the channel connected to vswitch is reported as the link
42819336SSriharsha.Basavapatna@Sun.COM  * state of the vnet device, by default. If the channel is down or reset, then
42829336SSriharsha.Basavapatna@Sun.COM  * the link state is marked 'down'. If the channel is 'up' *and* handshake
42839336SSriharsha.Basavapatna@Sun.COM  * between the vnet and vswitch is successful, then the link state is marked
42849336SSriharsha.Basavapatna@Sun.COM  * 'up'. If physical network link state is desired, then the vnet device must
42859336SSriharsha.Basavapatna@Sun.COM  * be configured to get physical link updates and the 'linkprop' property
42869336SSriharsha.Basavapatna@Sun.COM  * in the virtual-device MD node indicates this. As part of attribute exchange
42879336SSriharsha.Basavapatna@Sun.COM  * the vnet device negotiates with the vswitch to obtain physical link state
42889336SSriharsha.Basavapatna@Sun.COM  * updates. If it successfully negotiates, vswitch sends an initial physlink
42899336SSriharsha.Basavapatna@Sun.COM  * msg once the handshake is done and further whenever the physical link state
42909336SSriharsha.Basavapatna@Sun.COM  * changes. Currently we don't have mac layer interfaces to report two distinct
42919336SSriharsha.Basavapatna@Sun.COM  * link states - virtual and physical. Thus, if the vnet has been configured to
42929336SSriharsha.Basavapatna@Sun.COM  * get physical link updates, then the link status will be reported as 'up'
42939336SSriharsha.Basavapatna@Sun.COM  * only when both the virtual and physical links are up.
42949336SSriharsha.Basavapatna@Sun.COM  */
42959336SSriharsha.Basavapatna@Sun.COM static void
vgen_link_update(vgen_t * vgenp,link_state_t link_state)42969336SSriharsha.Basavapatna@Sun.COM vgen_link_update(vgen_t *vgenp, link_state_t link_state)
42979336SSriharsha.Basavapatna@Sun.COM {
42989336SSriharsha.Basavapatna@Sun.COM 	vnet_link_update(vgenp->vnetp, link_state);
42999336SSriharsha.Basavapatna@Sun.COM }
43009336SSriharsha.Basavapatna@Sun.COM 
43011991Sheppo /*
43021991Sheppo  * Handle a version info msg from the peer or an ACK/NACK from the peer
43031991Sheppo  * to a version info msg that we sent.
43041991Sheppo  */
43052793Slm66018 static int
vgen_handle_version_negotiate(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)43061991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
43071991Sheppo {
43084647Sraghuram 	vgen_t		*vgenp;
43091991Sheppo 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
43101991Sheppo 	int		ack = 0;
43111991Sheppo 	int		failed = 0;
43121991Sheppo 	int		idx;
43131991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
43142793Slm66018 	int		rv = 0;
43151991Sheppo 
43164647Sraghuram 	vgenp = LDC_TO_VGEN(ldcp);
43174647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
43181991Sheppo 	switch (tagp->vio_subtype) {
43191991Sheppo 	case VIO_SUBTYPE_INFO:
43201991Sheppo 
43211991Sheppo 		/*  Cache sid of peer if this is the first time */
43221991Sheppo 		if (ldcp->peer_sid == 0) {
43234647Sraghuram 			DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n",
43244647Sraghuram 			    tagp->vio_sid);
43251991Sheppo 			ldcp->peer_sid = tagp->vio_sid;
43261991Sheppo 		}
43271991Sheppo 
43281991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
43291991Sheppo 			/*
43301991Sheppo 			 * If we are not already in VH_PHASE1, reset to
43311991Sheppo 			 * pre-handshake state, and initiate handshake
43321991Sheppo 			 * to the peer too.
43331991Sheppo 			 */
433412011SSriharsha.Basavapatna@Sun.COM 			return (EINVAL);
43351991Sheppo 		}
433612011SSriharsha.Basavapatna@Sun.COM 
43371991Sheppo 		ldcp->hstate |= VER_INFO_RCVD;
43381991Sheppo 
43391991Sheppo 		/* save peer's requested values */
43401991Sheppo 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
43411991Sheppo 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
43421991Sheppo 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
43431991Sheppo 
43441991Sheppo 		if ((vermsg->dev_class != VDEV_NETWORK) &&
43451991Sheppo 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
43461991Sheppo 			/* unsupported dev_class, send NACK */
43471991Sheppo 
43484647Sraghuram 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
43492793Slm66018 
43501991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
43511991Sheppo 			tagp->vio_sid = ldcp->local_sid;
43521991Sheppo 			/* send reply msg back to peer */
43532793Slm66018 			rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
43541991Sheppo 			    sizeof (*vermsg), B_FALSE);
43552793Slm66018 			if (rv != VGEN_SUCCESS) {
43562793Slm66018 				return (rv);
43572793Slm66018 			}
43582793Slm66018 			return (VGEN_FAILURE);
43591991Sheppo 		}
43601991Sheppo 
43614647Sraghuram 		DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n",
43624647Sraghuram 		    vermsg->ver_major,  vermsg->ver_minor);
43631991Sheppo 
43641991Sheppo 		idx = 0;
43651991Sheppo 
43661991Sheppo 		for (;;) {
43671991Sheppo 
43681991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
43691991Sheppo 
43701991Sheppo 				/* nack with next lower version */
43711991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
43721991Sheppo 				vermsg->ver_major = versions[idx].ver_major;
43731991Sheppo 				vermsg->ver_minor = versions[idx].ver_minor;
43741991Sheppo 				break;
43751991Sheppo 			}
43761991Sheppo 
43771991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
43781991Sheppo 
43791991Sheppo 				/* major version match - ACK version */
43801991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
43811991Sheppo 				ack = 1;
43821991Sheppo 
43831991Sheppo 				/*
43841991Sheppo 				 * lower minor version to the one this endpt
43851991Sheppo 				 * supports, if necessary
43861991Sheppo 				 */
43871991Sheppo 				if (vermsg->ver_minor >
43881991Sheppo 				    versions[idx].ver_minor) {
43891991Sheppo 					vermsg->ver_minor =
43904650Sraghuram 					    versions[idx].ver_minor;
43911991Sheppo 					ldcp->peer_hparams.ver_minor =
43924650Sraghuram 					    versions[idx].ver_minor;
43931991Sheppo 				}
43941991Sheppo 				break;
43951991Sheppo 			}
43961991Sheppo 
43971991Sheppo 			idx++;
43981991Sheppo 
43991991Sheppo 			if (idx == VGEN_NUM_VER) {
44001991Sheppo 
44011991Sheppo 				/* no version match - send NACK */
44021991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
44031991Sheppo 				vermsg->ver_major = 0;
44041991Sheppo 				vermsg->ver_minor = 0;
44051991Sheppo 				failed = 1;
44061991Sheppo 				break;
44071991Sheppo 			}
44081991Sheppo 
44091991Sheppo 		}
44101991Sheppo 
44111991Sheppo 		tagp->vio_sid = ldcp->local_sid;
44121991Sheppo 
44131991Sheppo 		/* send reply msg back to peer */
44142793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
44152793Slm66018 		    B_FALSE);
44162793Slm66018 		if (rv != VGEN_SUCCESS) {
44172793Slm66018 			return (rv);
44181991Sheppo 		}
44191991Sheppo 
44201991Sheppo 		if (ack) {
44211991Sheppo 			ldcp->hstate |= VER_ACK_SENT;
44224647Sraghuram 			DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n",
44234647Sraghuram 			    vermsg->ver_major, vermsg->ver_minor);
44241991Sheppo 		}
44251991Sheppo 		if (failed) {
44264647Sraghuram 			DWARN(vgenp, ldcp, "Negotiation Failed\n");
44272793Slm66018 			return (VGEN_FAILURE);
44281991Sheppo 		}
44291991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44301991Sheppo 
44311991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
44321991Sheppo 
44331991Sheppo 			/* local and peer versions match? */
44341991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
44354650Sraghuram 			    ldcp->peer_hparams.ver_major) &&
44364650Sraghuram 			    (ldcp->local_hparams.ver_minor ==
44374650Sraghuram 			    ldcp->peer_hparams.ver_minor));
44381991Sheppo 
44395935Ssb155480 			vgen_set_vnet_proto_ops(ldcp);
44405935Ssb155480 
44411991Sheppo 			/* move to the next phase */
444212011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
444312011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
444412011SSriharsha.Basavapatna@Sun.COM 				return (rv);
444512011SSriharsha.Basavapatna@Sun.COM 			}
44461991Sheppo 		}
44471991Sheppo 
44481991Sheppo 		break;
44491991Sheppo 
44501991Sheppo 	case VIO_SUBTYPE_ACK:
44511991Sheppo 
44521991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
44531991Sheppo 			/*  This should not happen. */
44544647Sraghuram 			DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
44552793Slm66018 			return (VGEN_FAILURE);
44561991Sheppo 		}
44571991Sheppo 
44581991Sheppo 		/* SUCCESS - we have agreed on a version */
44591991Sheppo 		ldcp->local_hparams.ver_major = vermsg->ver_major;
44601991Sheppo 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
44611991Sheppo 		ldcp->hstate |= VER_ACK_RCVD;
44621991Sheppo 
44634647Sraghuram 		DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n",
44644647Sraghuram 		    vermsg->ver_major,  vermsg->ver_minor);
44651991Sheppo 
44661991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44671991Sheppo 
44681991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
44691991Sheppo 
44701991Sheppo 			/* local and peer versions match? */
44711991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
44724650Sraghuram 			    ldcp->peer_hparams.ver_major) &&
44734650Sraghuram 			    (ldcp->local_hparams.ver_minor ==
44744650Sraghuram 			    ldcp->peer_hparams.ver_minor));
44751991Sheppo 
44765935Ssb155480 			vgen_set_vnet_proto_ops(ldcp);
44775935Ssb155480 
44781991Sheppo 			/* move to the next phase */
447912011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
448012011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
448112011SSriharsha.Basavapatna@Sun.COM 				return (rv);
448212011SSriharsha.Basavapatna@Sun.COM 			}
44831991Sheppo 		}
44841991Sheppo 		break;
44851991Sheppo 
44861991Sheppo 	case VIO_SUBTYPE_NACK:
44871991Sheppo 
44881991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
44891991Sheppo 			/*  This should not happen.  */
44904647Sraghuram 			DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid "
44914647Sraghuram 			"Phase(%u)\n", ldcp->hphase);
44922793Slm66018 			return (VGEN_FAILURE);
44931991Sheppo 		}
44941991Sheppo 
44954647Sraghuram 		DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n",
44964647Sraghuram 		    vermsg->ver_major, vermsg->ver_minor);
44971991Sheppo 
44981991Sheppo 		/* check if version in NACK is zero */
44991991Sheppo 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
45001991Sheppo 			/*
45011991Sheppo 			 * Version Negotiation has failed.
45021991Sheppo 			 */
45034647Sraghuram 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
45042793Slm66018 			return (VGEN_FAILURE);
45051991Sheppo 		}
45061991Sheppo 
45071991Sheppo 		idx = 0;
45081991Sheppo 
45091991Sheppo 		for (;;) {
45101991Sheppo 
45111991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
45121991Sheppo 				/* select next lower version */
45131991Sheppo 
45141991Sheppo 				ldcp->local_hparams.ver_major =
45154650Sraghuram 				    versions[idx].ver_major;
45161991Sheppo 				ldcp->local_hparams.ver_minor =
45174650Sraghuram 				    versions[idx].ver_minor;
45181991Sheppo 				break;
45191991Sheppo 			}
45201991Sheppo 
45211991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
45221991Sheppo 				/* major version match */
45231991Sheppo 
45241991Sheppo 				ldcp->local_hparams.ver_major =
45254650Sraghuram 				    versions[idx].ver_major;
45261991Sheppo 
45271991Sheppo 				ldcp->local_hparams.ver_minor =
45284650Sraghuram 				    versions[idx].ver_minor;
45291991Sheppo 				break;
45301991Sheppo 			}
45311991Sheppo 
45321991Sheppo 			idx++;
45331991Sheppo 
45341991Sheppo 			if (idx == VGEN_NUM_VER) {
45351991Sheppo 				/*
45361991Sheppo 				 * no version match.
45371991Sheppo 				 * Version Negotiation has failed.
45381991Sheppo 				 */
45394647Sraghuram 				DWARN(vgenp, ldcp,
45404647Sraghuram 				    "Version Negotiation Failed\n");
45412793Slm66018 				return (VGEN_FAILURE);
45421991Sheppo 			}
45431991Sheppo 
45441991Sheppo 		}
45451991Sheppo 
45462793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
45472793Slm66018 		if (rv != VGEN_SUCCESS) {
45482793Slm66018 			return (rv);
45491991Sheppo 		}
45501991Sheppo 
45511991Sheppo 		break;
45521991Sheppo 	}
45532793Slm66018 
45544647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
45552793Slm66018 	return (VGEN_SUCCESS);
45561991Sheppo }
45571991Sheppo 
45581991Sheppo static int
vgen_handle_attr_info(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)455912011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
45601991Sheppo {
456112011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
45625935Ssb155480 	vgen_hparams_t	*lp = &ldcp->local_hparams;
456312011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*rp = &ldcp->peer_hparams;
456412011SSriharsha.Basavapatna@Sun.COM 	uint32_t	mtu;
456512011SSriharsha.Basavapatna@Sun.COM 	uint8_t		dring_mode;
456612011SSriharsha.Basavapatna@Sun.COM 
456712011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate |= ATTR_INFO_RCVD;
456812011SSriharsha.Basavapatna@Sun.COM 
456912011SSriharsha.Basavapatna@Sun.COM 	/* save peer's values */
457012011SSriharsha.Basavapatna@Sun.COM 	rp->mtu = msg->mtu;
457112011SSriharsha.Basavapatna@Sun.COM 	rp->addr = msg->addr;
457212011SSriharsha.Basavapatna@Sun.COM 	rp->addr_type = msg->addr_type;
457312011SSriharsha.Basavapatna@Sun.COM 	rp->xfer_mode = msg->xfer_mode;
457412011SSriharsha.Basavapatna@Sun.COM 	rp->ack_freq = msg->ack_freq;
457512011SSriharsha.Basavapatna@Sun.COM 	rp->dring_mode = msg->options;
457612011SSriharsha.Basavapatna@Sun.COM 
457712011SSriharsha.Basavapatna@Sun.COM 	/*
457812011SSriharsha.Basavapatna@Sun.COM 	 * Process address type, ack frequency and transfer mode attributes.
457912011SSriharsha.Basavapatna@Sun.COM 	 */
45807529SSriharsha.Basavapatna@Sun.COM 	if ((msg->addr_type != ADDR_TYPE_MAC) ||
45815935Ssb155480 	    (msg->ack_freq > 64) ||
45825935Ssb155480 	    (msg->xfer_mode != lp->xfer_mode)) {
45831991Sheppo 		return (VGEN_FAILURE);
45841991Sheppo 	}
45851991Sheppo 
458612011SSriharsha.Basavapatna@Sun.COM 	/*
458712011SSriharsha.Basavapatna@Sun.COM 	 * Process dring mode attribute.
458812011SSriharsha.Basavapatna@Sun.COM 	 */
458912011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
459012011SSriharsha.Basavapatna@Sun.COM 		/*
459112011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.6:
459212011SSriharsha.Basavapatna@Sun.COM 		 * Though we are operating in v1.6 mode, it is possible that
459312011SSriharsha.Basavapatna@Sun.COM 		 * RxDringData mode has been disabled either on this guest or
459412011SSriharsha.Basavapatna@Sun.COM 		 * on the peer guest. If so, we revert to pre v1.6 behavior of
459512011SSriharsha.Basavapatna@Sun.COM 		 * TxDring mode. But this must be agreed upon in both
459612011SSriharsha.Basavapatna@Sun.COM 		 * directions of attr exchange. We first determine the mode
459712011SSriharsha.Basavapatna@Sun.COM 		 * that can be negotiated.
459812011SSriharsha.Basavapatna@Sun.COM 		 */
459912011SSriharsha.Basavapatna@Sun.COM 		if ((msg->options & VIO_RX_DRING_DATA) != 0 &&
4600*13098SWentao.Yang@Sun.COM 		    vgen_mapin_avail(ldcp) == B_TRUE) {
460112011SSriharsha.Basavapatna@Sun.COM 			/*
460212011SSriharsha.Basavapatna@Sun.COM 			 * We are capable of handling RxDringData AND the peer
460312011SSriharsha.Basavapatna@Sun.COM 			 * is also capable of it; we enable RxDringData mode on
460412011SSriharsha.Basavapatna@Sun.COM 			 * this channel.
460512011SSriharsha.Basavapatna@Sun.COM 			 */
460612011SSriharsha.Basavapatna@Sun.COM 			dring_mode = VIO_RX_DRING_DATA;
460712011SSriharsha.Basavapatna@Sun.COM 		} else if ((msg->options & VIO_TX_DRING) != 0) {
460812011SSriharsha.Basavapatna@Sun.COM 			/*
460912011SSriharsha.Basavapatna@Sun.COM 			 * If the peer is capable of TxDring mode, we
461012011SSriharsha.Basavapatna@Sun.COM 			 * negotiate TxDring mode on this channel.
461112011SSriharsha.Basavapatna@Sun.COM 			 */
461212011SSriharsha.Basavapatna@Sun.COM 			dring_mode = VIO_TX_DRING;
461312011SSriharsha.Basavapatna@Sun.COM 		} else {
461412011SSriharsha.Basavapatna@Sun.COM 			/*
461512011SSriharsha.Basavapatna@Sun.COM 			 * We support only VIO_TX_DRING and VIO_RX_DRING_DATA
461612011SSriharsha.Basavapatna@Sun.COM 			 * modes. We don't support VIO_RX_DRING mode.
461712011SSriharsha.Basavapatna@Sun.COM 			 */
461812011SSriharsha.Basavapatna@Sun.COM 			return (VGEN_FAILURE);
461912011SSriharsha.Basavapatna@Sun.COM 		}
462012011SSriharsha.Basavapatna@Sun.COM 
462112011SSriharsha.Basavapatna@Sun.COM 		/*
462212011SSriharsha.Basavapatna@Sun.COM 		 * If we have received an ack for the attr info that we sent,
462312011SSriharsha.Basavapatna@Sun.COM 		 * then check if the dring mode matches what the peer had ack'd
462412011SSriharsha.Basavapatna@Sun.COM 		 * (saved in local hparams). If they don't match, we fail the
462512011SSriharsha.Basavapatna@Sun.COM 		 * handshake.
462612011SSriharsha.Basavapatna@Sun.COM 		 */
462712011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->hstate & ATTR_ACK_RCVD) {
462812011SSriharsha.Basavapatna@Sun.COM 			if (msg->options != lp->dring_mode) {
462912011SSriharsha.Basavapatna@Sun.COM 				/* send NACK */
463012011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
463112011SSriharsha.Basavapatna@Sun.COM 			}
463212011SSriharsha.Basavapatna@Sun.COM 		} else {
463312011SSriharsha.Basavapatna@Sun.COM 			/*
463412011SSriharsha.Basavapatna@Sun.COM 			 * Save the negotiated dring mode in our attr
463512011SSriharsha.Basavapatna@Sun.COM 			 * parameters, so it gets sent in the attr info from us
463612011SSriharsha.Basavapatna@Sun.COM 			 * to the peer.
463712011SSriharsha.Basavapatna@Sun.COM 			 */
463812011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = dring_mode;
463912011SSriharsha.Basavapatna@Sun.COM 		}
464012011SSriharsha.Basavapatna@Sun.COM 
464112011SSriharsha.Basavapatna@Sun.COM 		/* save the negotiated dring mode in the msg to be replied */
464212011SSriharsha.Basavapatna@Sun.COM 		msg->options = dring_mode;
464312011SSriharsha.Basavapatna@Sun.COM 	}
464412011SSriharsha.Basavapatna@Sun.COM 
464512011SSriharsha.Basavapatna@Sun.COM 	/*
464612011SSriharsha.Basavapatna@Sun.COM 	 * Process MTU attribute.
464712011SSriharsha.Basavapatna@Sun.COM 	 */
464812011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
464912011SSriharsha.Basavapatna@Sun.COM 		/*
465012011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.4:
465112011SSriharsha.Basavapatna@Sun.COM 		 * Validate mtu of the peer is at least ETHERMAX. Then, the mtu
465212011SSriharsha.Basavapatna@Sun.COM 		 * is negotiated down to the minimum of our mtu and peer's mtu.
465312011SSriharsha.Basavapatna@Sun.COM 		 */
465412011SSriharsha.Basavapatna@Sun.COM 		if (msg->mtu < ETHERMAX) {
465512011SSriharsha.Basavapatna@Sun.COM 			return (VGEN_FAILURE);
465612011SSriharsha.Basavapatna@Sun.COM 		}
465712011SSriharsha.Basavapatna@Sun.COM 
465812011SSriharsha.Basavapatna@Sun.COM 		mtu = MIN(msg->mtu, vgenp->max_frame_size);
465912011SSriharsha.Basavapatna@Sun.COM 
466012011SSriharsha.Basavapatna@Sun.COM 		/*
466112011SSriharsha.Basavapatna@Sun.COM 		 * If we have received an ack for the attr info
466212011SSriharsha.Basavapatna@Sun.COM 		 * that we sent, then check if the mtu computed
466312011SSriharsha.Basavapatna@Sun.COM 		 * above matches the mtu that the peer had ack'd
466412011SSriharsha.Basavapatna@Sun.COM 		 * (saved in local hparams). If they don't
466512011SSriharsha.Basavapatna@Sun.COM 		 * match, we fail the handshake.
466612011SSriharsha.Basavapatna@Sun.COM 		 */
466712011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->hstate & ATTR_ACK_RCVD) {
466812011SSriharsha.Basavapatna@Sun.COM 			if (mtu != lp->mtu) {
466912011SSriharsha.Basavapatna@Sun.COM 				/* send NACK */
467012011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
467112011SSriharsha.Basavapatna@Sun.COM 			}
467212011SSriharsha.Basavapatna@Sun.COM 		} else {
467312011SSriharsha.Basavapatna@Sun.COM 			/*
467412011SSriharsha.Basavapatna@Sun.COM 			 * Save the mtu computed above in our
467512011SSriharsha.Basavapatna@Sun.COM 			 * attr parameters, so it gets sent in
467612011SSriharsha.Basavapatna@Sun.COM 			 * the attr info from us to the peer.
467712011SSriharsha.Basavapatna@Sun.COM 			 */
467812011SSriharsha.Basavapatna@Sun.COM 			lp->mtu = mtu;
467912011SSriharsha.Basavapatna@Sun.COM 		}
468012011SSriharsha.Basavapatna@Sun.COM 
468112011SSriharsha.Basavapatna@Sun.COM 		/* save the MIN mtu in the msg to be replied */
468212011SSriharsha.Basavapatna@Sun.COM 		msg->mtu = mtu;
468312011SSriharsha.Basavapatna@Sun.COM 
468412011SSriharsha.Basavapatna@Sun.COM 	} else {
46857529SSriharsha.Basavapatna@Sun.COM 		/* versions < 1.4, mtu must match */
46867529SSriharsha.Basavapatna@Sun.COM 		if (msg->mtu != lp->mtu) {
46877529SSriharsha.Basavapatna@Sun.COM 			return (VGEN_FAILURE);
46887529SSriharsha.Basavapatna@Sun.COM 		}
46897529SSriharsha.Basavapatna@Sun.COM 	}
46907529SSriharsha.Basavapatna@Sun.COM 
46911991Sheppo 	return (VGEN_SUCCESS);
46921991Sheppo }
46931991Sheppo 
469412011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_attr_ack(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)469512011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
469612011SSriharsha.Basavapatna@Sun.COM {
469712011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
469812011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
469912011SSriharsha.Basavapatna@Sun.COM 
470012011SSriharsha.Basavapatna@Sun.COM 	/*
470112011SSriharsha.Basavapatna@Sun.COM 	 * Process dring mode attribute.
470212011SSriharsha.Basavapatna@Sun.COM 	 */
470312011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
470412011SSriharsha.Basavapatna@Sun.COM 		/*
470512011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.6:
470612011SSriharsha.Basavapatna@Sun.COM 		 * The ack msg sent by the peer contains the negotiated dring
470712011SSriharsha.Basavapatna@Sun.COM 		 * mode between our capability (that we had sent in our attr
470812011SSriharsha.Basavapatna@Sun.COM 		 * info) and the peer's capability.
470912011SSriharsha.Basavapatna@Sun.COM 		 */
471012011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->hstate & ATTR_ACK_SENT) {
471112011SSriharsha.Basavapatna@Sun.COM 			/*
471212011SSriharsha.Basavapatna@Sun.COM 			 * If we have sent an ack for the attr info msg from
471312011SSriharsha.Basavapatna@Sun.COM 			 * the peer, check if the dring mode that was
471412011SSriharsha.Basavapatna@Sun.COM 			 * negotiated then (saved in local hparams) matches the
471512011SSriharsha.Basavapatna@Sun.COM 			 * mode that the peer has ack'd. If they don't match,
471612011SSriharsha.Basavapatna@Sun.COM 			 * we fail the handshake.
471712011SSriharsha.Basavapatna@Sun.COM 			 */
471812011SSriharsha.Basavapatna@Sun.COM 			if (lp->dring_mode != msg->options) {
471912011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
472012011SSriharsha.Basavapatna@Sun.COM 			}
472112011SSriharsha.Basavapatna@Sun.COM 		} else {
472212011SSriharsha.Basavapatna@Sun.COM 			if ((msg->options & lp->dring_mode) == 0) {
472312011SSriharsha.Basavapatna@Sun.COM 				/*
472412011SSriharsha.Basavapatna@Sun.COM 				 * Peer ack'd with a mode that we don't
472512011SSriharsha.Basavapatna@Sun.COM 				 * support; we fail the handshake.
472612011SSriharsha.Basavapatna@Sun.COM 				 */
472712011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
472812011SSriharsha.Basavapatna@Sun.COM 			}
472912011SSriharsha.Basavapatna@Sun.COM 			if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA))
473012011SSriharsha.Basavapatna@Sun.COM 			    == (VIO_TX_DRING|VIO_RX_DRING_DATA)) {
473112011SSriharsha.Basavapatna@Sun.COM 				/*
473212011SSriharsha.Basavapatna@Sun.COM 				 * Peer must ack with only one negotiated mode.
473312011SSriharsha.Basavapatna@Sun.COM 				 * Otherwise fail handshake.
473412011SSriharsha.Basavapatna@Sun.COM 				 */
473512011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
473612011SSriharsha.Basavapatna@Sun.COM 			}
473712011SSriharsha.Basavapatna@Sun.COM 
473812011SSriharsha.Basavapatna@Sun.COM 			/*
473912011SSriharsha.Basavapatna@Sun.COM 			 * Save the negotiated mode, so we can validate it when
474012011SSriharsha.Basavapatna@Sun.COM 			 * we receive attr info from the peer.
474112011SSriharsha.Basavapatna@Sun.COM 			 */
474212011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = msg->options;
474312011SSriharsha.Basavapatna@Sun.COM 		}
474412011SSriharsha.Basavapatna@Sun.COM 	}
474512011SSriharsha.Basavapatna@Sun.COM 
474612011SSriharsha.Basavapatna@Sun.COM 	/*
474712011SSriharsha.Basavapatna@Sun.COM 	 * Process Physical Link Update attribute.
474812011SSriharsha.Basavapatna@Sun.COM 	 */
474912011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 5) &&
475012011SSriharsha.Basavapatna@Sun.COM 	    ldcp->portp == vgenp->vsw_portp) {
475112011SSriharsha.Basavapatna@Sun.COM 		/*
475212011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.5:
475312011SSriharsha.Basavapatna@Sun.COM 		 * If the vnet device has been configured to get
475412011SSriharsha.Basavapatna@Sun.COM 		 * physical link state updates, check the corresponding
475512011SSriharsha.Basavapatna@Sun.COM 		 * bits in the ack msg, if the peer is vswitch.
475612011SSriharsha.Basavapatna@Sun.COM 		 */
475712011SSriharsha.Basavapatna@Sun.COM 		if (((lp->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
475812011SSriharsha.Basavapatna@Sun.COM 		    PHYSLINK_UPDATE_STATE) &&
475912011SSriharsha.Basavapatna@Sun.COM 		    ((msg->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
476012011SSriharsha.Basavapatna@Sun.COM 		    PHYSLINK_UPDATE_STATE_ACK)) {
476112011SSriharsha.Basavapatna@Sun.COM 			vgenp->pls_negotiated = B_TRUE;
476212011SSriharsha.Basavapatna@Sun.COM 		} else {
476312011SSriharsha.Basavapatna@Sun.COM 			vgenp->pls_negotiated = B_FALSE;
476412011SSriharsha.Basavapatna@Sun.COM 		}
476512011SSriharsha.Basavapatna@Sun.COM 	}
476612011SSriharsha.Basavapatna@Sun.COM 
476712011SSriharsha.Basavapatna@Sun.COM 	/*
476812011SSriharsha.Basavapatna@Sun.COM 	 * Process MTU attribute.
476912011SSriharsha.Basavapatna@Sun.COM 	 */
477012011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
477112011SSriharsha.Basavapatna@Sun.COM 		/*
477212011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.4:
477312011SSriharsha.Basavapatna@Sun.COM 		 * The ack msg sent by the peer contains the minimum of
477412011SSriharsha.Basavapatna@Sun.COM 		 * our mtu (that we had sent in our attr info) and the
477512011SSriharsha.Basavapatna@Sun.COM 		 * peer's mtu.
477612011SSriharsha.Basavapatna@Sun.COM 		 *
477712011SSriharsha.Basavapatna@Sun.COM 		 * If we have sent an ack for the attr info msg from
477812011SSriharsha.Basavapatna@Sun.COM 		 * the peer, check if the mtu that was computed then
477912011SSriharsha.Basavapatna@Sun.COM 		 * (saved in local hparams) matches the mtu that the
478012011SSriharsha.Basavapatna@Sun.COM 		 * peer has ack'd. If they don't match, we fail the
478112011SSriharsha.Basavapatna@Sun.COM 		 * handshake.
478212011SSriharsha.Basavapatna@Sun.COM 		 */
478312011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->hstate & ATTR_ACK_SENT) {
478412011SSriharsha.Basavapatna@Sun.COM 			if (lp->mtu != msg->mtu) {
478512011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
478612011SSriharsha.Basavapatna@Sun.COM 			}
478712011SSriharsha.Basavapatna@Sun.COM 		} else {
478812011SSriharsha.Basavapatna@Sun.COM 			/*
478912011SSriharsha.Basavapatna@Sun.COM 			 * If the mtu ack'd by the peer is > our mtu
479012011SSriharsha.Basavapatna@Sun.COM 			 * fail handshake. Otherwise, save the mtu, so
479112011SSriharsha.Basavapatna@Sun.COM 			 * we can validate it when we receive attr info
479212011SSriharsha.Basavapatna@Sun.COM 			 * from our peer.
479312011SSriharsha.Basavapatna@Sun.COM 			 */
479412011SSriharsha.Basavapatna@Sun.COM 			if (msg->mtu > lp->mtu) {
479512011SSriharsha.Basavapatna@Sun.COM 				return (VGEN_FAILURE);
479612011SSriharsha.Basavapatna@Sun.COM 			}
479712011SSriharsha.Basavapatna@Sun.COM 			if (msg->mtu <= lp->mtu) {
479812011SSriharsha.Basavapatna@Sun.COM 				lp->mtu = msg->mtu;
479912011SSriharsha.Basavapatna@Sun.COM 			}
480012011SSriharsha.Basavapatna@Sun.COM 		}
480112011SSriharsha.Basavapatna@Sun.COM 	}
480212011SSriharsha.Basavapatna@Sun.COM 
480312011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
480412011SSriharsha.Basavapatna@Sun.COM }
480512011SSriharsha.Basavapatna@Sun.COM 
480612011SSriharsha.Basavapatna@Sun.COM 
48071991Sheppo /*
48081991Sheppo  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
48091991Sheppo  * to an attr info msg that we sent.
48101991Sheppo  */
48112793Slm66018 static int
vgen_handle_attr_msg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)481212011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48131991Sheppo {
48147529SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
48157529SSriharsha.Basavapatna@Sun.COM 	vnet_attr_msg_t	*msg = (vnet_attr_msg_t *)tagp;
48162793Slm66018 	int		rv = 0;
48171991Sheppo 
48184647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
48191991Sheppo 	if (ldcp->hphase != VH_PHASE2) {
48204647Sraghuram 		DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d),"
48214647Sraghuram 		" Invalid Phase(%u)\n",
48224647Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
48232793Slm66018 		return (VGEN_FAILURE);
48241991Sheppo 	}
48251991Sheppo 	switch (tagp->vio_subtype) {
48261991Sheppo 	case VIO_SUBTYPE_INFO:
48271991Sheppo 
482812011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_attr_info(ldcp, msg);
482912011SSriharsha.Basavapatna@Sun.COM 		if (rv == VGEN_SUCCESS) {
48301991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
48317529SSriharsha.Basavapatna@Sun.COM 		} else {
48327529SSriharsha.Basavapatna@Sun.COM 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
48331991Sheppo 		}
48341991Sheppo 		tagp->vio_sid = ldcp->local_sid;
48351991Sheppo 
48361991Sheppo 		/* send reply msg back to peer */
48377529SSriharsha.Basavapatna@Sun.COM 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
48382793Slm66018 		    B_FALSE);
48392793Slm66018 		if (rv != VGEN_SUCCESS) {
48402793Slm66018 			return (rv);
48411991Sheppo 		}
48421991Sheppo 
484312011SSriharsha.Basavapatna@Sun.COM 		if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
484412011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "ATTR_NACK_SENT");
484512011SSriharsha.Basavapatna@Sun.COM 			break;
48461991Sheppo 		}
48471991Sheppo 
484812011SSriharsha.Basavapatna@Sun.COM 		ldcp->hstate |= ATTR_ACK_SENT;
484912011SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n");
48501991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
485112011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
485212011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
485312011SSriharsha.Basavapatna@Sun.COM 				return (rv);
485412011SSriharsha.Basavapatna@Sun.COM 			}
48551991Sheppo 		}
48561991Sheppo 
48571991Sheppo 		break;
48581991Sheppo 
48591991Sheppo 	case VIO_SUBTYPE_ACK:
48601991Sheppo 
486112011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_attr_ack(ldcp, msg);
486212011SSriharsha.Basavapatna@Sun.COM 		if (rv == VGEN_FAILURE) {
486312011SSriharsha.Basavapatna@Sun.COM 			break;
48647529SSriharsha.Basavapatna@Sun.COM 		}
48657529SSriharsha.Basavapatna@Sun.COM 
48661991Sheppo 		ldcp->hstate |= ATTR_ACK_RCVD;
48674647Sraghuram 		DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n");
48681991Sheppo 
48691991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
487012011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
487112011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
487212011SSriharsha.Basavapatna@Sun.COM 				return (rv);
487312011SSriharsha.Basavapatna@Sun.COM 			}
48741991Sheppo 		}
48751991Sheppo 		break;
48761991Sheppo 
48771991Sheppo 	case VIO_SUBTYPE_NACK:
48781991Sheppo 
48794647Sraghuram 		DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n");
48802793Slm66018 		return (VGEN_FAILURE);
48811991Sheppo 	}
48824647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
48832793Slm66018 	return (VGEN_SUCCESS);
48841991Sheppo }
48851991Sheppo 
48861991Sheppo static int
vgen_handle_dring_reg_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)488712011SSriharsha.Basavapatna@Sun.COM vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48881991Sheppo {
488912011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
489012011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
489112011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
489212011SSriharsha.Basavapatna@Sun.COM 
489312011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, ldcp, "DRING_INFO_RCVD");
489412011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate |= DRING_INFO_RCVD;
489512011SSriharsha.Basavapatna@Sun.COM 
489612011SSriharsha.Basavapatna@Sun.COM 	if (VGEN_VER_GTEQ(ldcp, 1, 6) &&
489712011SSriharsha.Basavapatna@Sun.COM 	    (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
489812011SSriharsha.Basavapatna@Sun.COM 		/*
489912011SSriharsha.Basavapatna@Sun.COM 		 * The earlier version of Solaris vnet driver doesn't set the
490012011SSriharsha.Basavapatna@Sun.COM 		 * option (VIO_TX_DRING in its case) correctly in its dring reg
490112011SSriharsha.Basavapatna@Sun.COM 		 * message. We workaround that here by doing the check only
490212011SSriharsha.Basavapatna@Sun.COM 		 * for versions >= v1.6.
490312011SSriharsha.Basavapatna@Sun.COM 		 */
490412011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp,
490512011SSriharsha.Basavapatna@Sun.COM 		    "Rcvd dring reg option (%d), negotiated mode (%d)\n",
490612011SSriharsha.Basavapatna@Sun.COM 		    ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode);
49071991Sheppo 		return (VGEN_FAILURE);
49081991Sheppo 	}
490912011SSriharsha.Basavapatna@Sun.COM 
491012011SSriharsha.Basavapatna@Sun.COM 	/*
491112011SSriharsha.Basavapatna@Sun.COM 	 * Map dring exported by the peer.
491212011SSriharsha.Basavapatna@Sun.COM 	 */
491312011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_map_dring(ldcp, (void *)tagp);
491412011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
491512011SSriharsha.Basavapatna@Sun.COM 		return (rv);
491612011SSriharsha.Basavapatna@Sun.COM 	}
491712011SSriharsha.Basavapatna@Sun.COM 
491812011SSriharsha.Basavapatna@Sun.COM 	/*
491912011SSriharsha.Basavapatna@Sun.COM 	 * Map data buffers exported by the peer if we are in RxDringData mode.
492012011SSriharsha.Basavapatna@Sun.COM 	 */
492112011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
492212011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_map_data(ldcp, (void *)tagp);
492312011SSriharsha.Basavapatna@Sun.COM 		if (rv != VGEN_SUCCESS) {
492412011SSriharsha.Basavapatna@Sun.COM 			vgen_unmap_dring(ldcp);
492512011SSriharsha.Basavapatna@Sun.COM 			return (rv);
492612011SSriharsha.Basavapatna@Sun.COM 		}
492712011SSriharsha.Basavapatna@Sun.COM 	}
492812011SSriharsha.Basavapatna@Sun.COM 
492912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->peer_hparams.dring_ready == B_FALSE) {
493012011SSriharsha.Basavapatna@Sun.COM 		ldcp->peer_hparams.dring_ready = B_TRUE;
493112011SSriharsha.Basavapatna@Sun.COM 	}
493212011SSriharsha.Basavapatna@Sun.COM 
493312011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
493412011SSriharsha.Basavapatna@Sun.COM }
493512011SSriharsha.Basavapatna@Sun.COM 
493612011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_dring_reg_ack(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)493712011SSriharsha.Basavapatna@Sun.COM vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
493812011SSriharsha.Basavapatna@Sun.COM {
493912011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
494012011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
494112011SSriharsha.Basavapatna@Sun.COM 
494212011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, ldcp, "DRING_ACK_RCVD");
494312011SSriharsha.Basavapatna@Sun.COM 	ldcp->hstate |= DRING_ACK_RCVD;
494412011SSriharsha.Basavapatna@Sun.COM 
494512011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_ready) {
494612011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_SUCCESS);
494712011SSriharsha.Basavapatna@Sun.COM 	}
494812011SSriharsha.Basavapatna@Sun.COM 
494912011SSriharsha.Basavapatna@Sun.COM 	/* save dring_ident acked by peer */
495012011SSriharsha.Basavapatna@Sun.COM 	lp->dring_ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
495112011SSriharsha.Basavapatna@Sun.COM 
495212011SSriharsha.Basavapatna@Sun.COM 	/* local dring is now ready */
495312011SSriharsha.Basavapatna@Sun.COM 	lp->dring_ready = B_TRUE;
495412011SSriharsha.Basavapatna@Sun.COM 
49551991Sheppo 	return (VGEN_SUCCESS);
49561991Sheppo }
49571991Sheppo 
49581991Sheppo /*
49591991Sheppo  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
49601991Sheppo  * the peer to a dring register msg that we sent.
49611991Sheppo  */
49622793Slm66018 static int
vgen_handle_dring_reg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)49631991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
49641991Sheppo {
496512011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
496612011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
496712011SSriharsha.Basavapatna@Sun.COM 	int		msgsize;
496812011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
49691991Sheppo 
49704647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
49711991Sheppo 	if (ldcp->hphase < VH_PHASE2) {
49721991Sheppo 		/* dring_info can be rcvd in any of the phases after Phase1 */
49734647Sraghuram 		DWARN(vgenp, ldcp,
49744647Sraghuram 		    "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n",
49754650Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
49762793Slm66018 		return (VGEN_FAILURE);
49771991Sheppo 	}
497812011SSriharsha.Basavapatna@Sun.COM 
49791991Sheppo 	switch (tagp->vio_subtype) {
49801991Sheppo 	case VIO_SUBTYPE_INFO:
49811991Sheppo 
498212011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_dring_reg_info(ldcp, tagp);
498312011SSriharsha.Basavapatna@Sun.COM 		if (rv == VGEN_SUCCESS) {
498412011SSriharsha.Basavapatna@Sun.COM 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
49851991Sheppo 		} else {
498612011SSriharsha.Basavapatna@Sun.COM 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
49871991Sheppo 		}
498812011SSriharsha.Basavapatna@Sun.COM 
49891991Sheppo 		tagp->vio_sid = ldcp->local_sid;
499012011SSriharsha.Basavapatna@Sun.COM 
499112011SSriharsha.Basavapatna@Sun.COM 		if (lp->dring_mode == VIO_RX_DRING_DATA) {
499212011SSriharsha.Basavapatna@Sun.COM 			msgsize =
499312011SSriharsha.Basavapatna@Sun.COM 			    VNET_DRING_REG_EXT_MSG_SIZE(ldcp->tx_data_ncookies);
499412011SSriharsha.Basavapatna@Sun.COM 		} else {
499512011SSriharsha.Basavapatna@Sun.COM 			msgsize = sizeof (vio_dring_reg_msg_t);
499612011SSriharsha.Basavapatna@Sun.COM 		}
499712011SSriharsha.Basavapatna@Sun.COM 
49981991Sheppo 		/* send reply msg back to peer */
499912011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, msgsize,
50002793Slm66018 		    B_FALSE);
50012793Slm66018 		if (rv != VGEN_SUCCESS) {
50022793Slm66018 			return (rv);
50031991Sheppo 		}
50041991Sheppo 
500512011SSriharsha.Basavapatna@Sun.COM 		if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
50064647Sraghuram 			DWARN(vgenp, ldcp, "DRING_NACK_SENT");
50072793Slm66018 			return (VGEN_FAILURE);
50081991Sheppo 		}
50091991Sheppo 
501012011SSriharsha.Basavapatna@Sun.COM 		ldcp->hstate |= DRING_ACK_SENT;
501112011SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, ldcp, "DRING_ACK_SENT");
501212011SSriharsha.Basavapatna@Sun.COM 
50131991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
501412011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
501512011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
501612011SSriharsha.Basavapatna@Sun.COM 				return (rv);
501712011SSriharsha.Basavapatna@Sun.COM 			}
50181991Sheppo 		}
50191991Sheppo 		break;
50201991Sheppo 
50211991Sheppo 	case VIO_SUBTYPE_ACK:
50221991Sheppo 
502312011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_dring_reg_ack(ldcp, tagp);
502412011SSriharsha.Basavapatna@Sun.COM 		if (rv == VGEN_FAILURE) {
502512011SSriharsha.Basavapatna@Sun.COM 			return (rv);
50261991Sheppo 		}
50271991Sheppo 
50281991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
502912011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
503012011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
503112011SSriharsha.Basavapatna@Sun.COM 				return (rv);
503212011SSriharsha.Basavapatna@Sun.COM 			}
50331991Sheppo 		}
50341991Sheppo 
50351991Sheppo 		break;
50361991Sheppo 
50371991Sheppo 	case VIO_SUBTYPE_NACK:
50381991Sheppo 
503912011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "DRING_NACK_RCVD");
50402793Slm66018 		return (VGEN_FAILURE);
50411991Sheppo 	}
50424647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
50432793Slm66018 	return (VGEN_SUCCESS);
50441991Sheppo }
50451991Sheppo 
50461991Sheppo /*
50471991Sheppo  * Handle a rdx info msg from the peer or an ACK/NACK
50481991Sheppo  * from the peer to a rdx info msg that we sent.
50491991Sheppo  */
50502793Slm66018 static int
vgen_handle_rdx_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)50511991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
50521991Sheppo {
505312011SSriharsha.Basavapatna@Sun.COM 	int	rv = 0;
50544647Sraghuram 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
50554647Sraghuram 
50564647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
505712011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase != VH_PHASE4) {
50584647Sraghuram 		DWARN(vgenp, ldcp,
50594647Sraghuram 		    "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n",
50604650Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
50612793Slm66018 		return (VGEN_FAILURE);
50621991Sheppo 	}
50631991Sheppo 	switch (tagp->vio_subtype) {
50641991Sheppo 	case VIO_SUBTYPE_INFO:
50651991Sheppo 
50664647Sraghuram 		DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n");
50671991Sheppo 		ldcp->hstate |= RDX_INFO_RCVD;
50681991Sheppo 
50691991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
50701991Sheppo 		tagp->vio_sid = ldcp->local_sid;
50711991Sheppo 		/* send reply msg back to peer */
50722793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
50732793Slm66018 		    B_FALSE);
50742793Slm66018 		if (rv != VGEN_SUCCESS) {
50752793Slm66018 			return (rv);
50761991Sheppo 		}
50771991Sheppo 
50781991Sheppo 		ldcp->hstate |= RDX_ACK_SENT;
50794647Sraghuram 		DBG2(vgenp, ldcp, "RDX_ACK_SENT \n");
50801991Sheppo 
50811991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
508212011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
508312011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
508412011SSriharsha.Basavapatna@Sun.COM 				return (rv);
508512011SSriharsha.Basavapatna@Sun.COM 			}
50861991Sheppo 		}
50871991Sheppo 
50881991Sheppo 		break;
50891991Sheppo 
50901991Sheppo 	case VIO_SUBTYPE_ACK:
50911991Sheppo 
50921991Sheppo 		ldcp->hstate |= RDX_ACK_RCVD;
50931991Sheppo 
50944647Sraghuram 		DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n");
50951991Sheppo 
50961991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
509712011SSriharsha.Basavapatna@Sun.COM 			rv = vgen_handshake(vh_nextphase(ldcp));
509812011SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
509912011SSriharsha.Basavapatna@Sun.COM 				return (rv);
510012011SSriharsha.Basavapatna@Sun.COM 			}
51011991Sheppo 		}
51021991Sheppo 		break;
51031991Sheppo 
51041991Sheppo 	case VIO_SUBTYPE_NACK:
51051991Sheppo 
51064647Sraghuram 		DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n");
51072793Slm66018 		return (VGEN_FAILURE);
51081991Sheppo 	}
51094647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
51102793Slm66018 	return (VGEN_SUCCESS);
51111991Sheppo }
51121991Sheppo 
51131991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
51142793Slm66018 static int
vgen_handle_mcast_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51151991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51161991Sheppo {
511712011SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
511812011SSriharsha.Basavapatna@Sun.COM 	vnet_mcast_msg_t	*msgp = (vnet_mcast_msg_t *)tagp;
511912011SSriharsha.Basavapatna@Sun.COM 	struct ether_addr	*addrp;
512012011SSriharsha.Basavapatna@Sun.COM 	int			count;
512112011SSriharsha.Basavapatna@Sun.COM 	int			i;
51221991Sheppo 
51234647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
51241991Sheppo 	switch (tagp->vio_subtype) {
51251991Sheppo 
51261991Sheppo 	case VIO_SUBTYPE_INFO:
51271991Sheppo 
51281991Sheppo 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
51294647Sraghuram 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n");
51301991Sheppo 		break;
51311991Sheppo 
51321991Sheppo 	case VIO_SUBTYPE_ACK:
51331991Sheppo 
51341991Sheppo 		/* success adding/removing multicast addr */
51354647Sraghuram 		DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n");
51361991Sheppo 		break;
51371991Sheppo 
51381991Sheppo 	case VIO_SUBTYPE_NACK:
51391991Sheppo 
51404647Sraghuram 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n");
51411991Sheppo 		if (!(msgp->set)) {
51421991Sheppo 			/* multicast remove request failed */
51431991Sheppo 			break;
51441991Sheppo 		}
51451991Sheppo 
51461991Sheppo 		/* multicast add request failed */
51471991Sheppo 		for (count = 0; count < msgp->count; count++) {
51481991Sheppo 			addrp = &(msgp->mca[count]);
51491991Sheppo 
51501991Sheppo 			/* delete address from the table */
51511991Sheppo 			for (i = 0; i < vgenp->mccount; i++) {
51521991Sheppo 				if (ether_cmp(addrp,
51531991Sheppo 				    &(vgenp->mctab[i])) == 0) {
51541991Sheppo 					if (vgenp->mccount > 1) {
51554647Sraghuram 						int t = vgenp->mccount - 1;
51561991Sheppo 						vgenp->mctab[i] =
51574650Sraghuram 						    vgenp->mctab[t];
51581991Sheppo 					}
51591991Sheppo 					vgenp->mccount--;
51601991Sheppo 					break;
51611991Sheppo 				}
51621991Sheppo 			}
51631991Sheppo 		}
51641991Sheppo 		break;
51651991Sheppo 
51661991Sheppo 	}
51674647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
51682793Slm66018 
51692793Slm66018 	return (VGEN_SUCCESS);
51701991Sheppo }
51711991Sheppo 
51729336SSriharsha.Basavapatna@Sun.COM /*
51739336SSriharsha.Basavapatna@Sun.COM  * Physical link information message from the peer. Only vswitch should send
51749336SSriharsha.Basavapatna@Sun.COM  * us this message; if the vnet device has been configured to get physical link
51759336SSriharsha.Basavapatna@Sun.COM  * state updates. Note that we must have already negotiated this with the
51769336SSriharsha.Basavapatna@Sun.COM  * vswitch during attribute exchange phase of handshake.
51779336SSriharsha.Basavapatna@Sun.COM  */
51789336SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_physlink_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51799336SSriharsha.Basavapatna@Sun.COM vgen_handle_physlink_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51809336SSriharsha.Basavapatna@Sun.COM {
51819336SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
51829336SSriharsha.Basavapatna@Sun.COM 	vnet_physlink_msg_t	*msgp = (vnet_physlink_msg_t *)tagp;
51839336SSriharsha.Basavapatna@Sun.COM 	link_state_t		link_state;
51849336SSriharsha.Basavapatna@Sun.COM 	int			rv;
51859336SSriharsha.Basavapatna@Sun.COM 
51869336SSriharsha.Basavapatna@Sun.COM 	if (ldcp->portp != vgenp->vsw_portp) {
51879336SSriharsha.Basavapatna@Sun.COM 		/*
51889336SSriharsha.Basavapatna@Sun.COM 		 * drop the message and don't process; as we should
51899336SSriharsha.Basavapatna@Sun.COM 		 * receive physlink_info message from only vswitch.
51909336SSriharsha.Basavapatna@Sun.COM 		 */
51919336SSriharsha.Basavapatna@Sun.COM 		return (VGEN_SUCCESS);
51929336SSriharsha.Basavapatna@Sun.COM 	}
51939336SSriharsha.Basavapatna@Sun.COM 
51949336SSriharsha.Basavapatna@Sun.COM 	if (vgenp->pls_negotiated == B_FALSE) {
51959336SSriharsha.Basavapatna@Sun.COM 		/*
51969336SSriharsha.Basavapatna@Sun.COM 		 * drop the message and don't process; as we should receive
51979336SSriharsha.Basavapatna@Sun.COM 		 * physlink_info message only if physlink update is enabled for
51989336SSriharsha.Basavapatna@Sun.COM 		 * the device and negotiated with vswitch.
51999336SSriharsha.Basavapatna@Sun.COM 		 */
52009336SSriharsha.Basavapatna@Sun.COM 		return (VGEN_SUCCESS);
52019336SSriharsha.Basavapatna@Sun.COM 	}
52029336SSriharsha.Basavapatna@Sun.COM 
52039336SSriharsha.Basavapatna@Sun.COM 	switch (tagp->vio_subtype) {
52049336SSriharsha.Basavapatna@Sun.COM 
52059336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_INFO:
52069336SSriharsha.Basavapatna@Sun.COM 
52079336SSriharsha.Basavapatna@Sun.COM 		if ((msgp->physlink_info & VNET_PHYSLINK_STATE_MASK) ==
52089336SSriharsha.Basavapatna@Sun.COM 		    VNET_PHYSLINK_STATE_UP) {
52099336SSriharsha.Basavapatna@Sun.COM 			link_state = LINK_STATE_UP;
52109336SSriharsha.Basavapatna@Sun.COM 		} else {
52119336SSriharsha.Basavapatna@Sun.COM 			link_state = LINK_STATE_DOWN;
52129336SSriharsha.Basavapatna@Sun.COM 		}
52139336SSriharsha.Basavapatna@Sun.COM 
52149336SSriharsha.Basavapatna@Sun.COM 		if (vgenp->phys_link_state != link_state) {
52159336SSriharsha.Basavapatna@Sun.COM 			vgenp->phys_link_state = link_state;
52169336SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->cblock);
52179336SSriharsha.Basavapatna@Sun.COM 
52189336SSriharsha.Basavapatna@Sun.COM 			/* Now update the stack */
52199336SSriharsha.Basavapatna@Sun.COM 			vgen_link_update(vgenp, link_state);
52209336SSriharsha.Basavapatna@Sun.COM 
52219336SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->cblock);
52229336SSriharsha.Basavapatna@Sun.COM 		}
52239336SSriharsha.Basavapatna@Sun.COM 
52249336SSriharsha.Basavapatna@Sun.COM 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
52259336SSriharsha.Basavapatna@Sun.COM 		tagp->vio_sid = ldcp->local_sid;
52269336SSriharsha.Basavapatna@Sun.COM 
52279336SSriharsha.Basavapatna@Sun.COM 		/* send reply msg back to peer */
52289336SSriharsha.Basavapatna@Sun.COM 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
52299336SSriharsha.Basavapatna@Sun.COM 		    sizeof (vnet_physlink_msg_t), B_FALSE);
52309336SSriharsha.Basavapatna@Sun.COM 		if (rv != VGEN_SUCCESS) {
52319336SSriharsha.Basavapatna@Sun.COM 			return (rv);
52329336SSriharsha.Basavapatna@Sun.COM 		}
52339336SSriharsha.Basavapatna@Sun.COM 		break;
52349336SSriharsha.Basavapatna@Sun.COM 
52359336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_ACK:
52369336SSriharsha.Basavapatna@Sun.COM 
52379336SSriharsha.Basavapatna@Sun.COM 		/* vnet shouldn't recv physlink acks */
52389336SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "rcvd PHYSLINK_ACK \n");
52399336SSriharsha.Basavapatna@Sun.COM 		break;
52409336SSriharsha.Basavapatna@Sun.COM 
52419336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_NACK:
52429336SSriharsha.Basavapatna@Sun.COM 
52439336SSriharsha.Basavapatna@Sun.COM 		/* vnet shouldn't recv physlink nacks */
52449336SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "rcvd PHYSLINK_NACK \n");
52459336SSriharsha.Basavapatna@Sun.COM 		break;
52469336SSriharsha.Basavapatna@Sun.COM 
52479336SSriharsha.Basavapatna@Sun.COM 	}
52489336SSriharsha.Basavapatna@Sun.COM 	DBG1(vgenp, ldcp, "exit\n");
52499336SSriharsha.Basavapatna@Sun.COM 
52509336SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
52519336SSriharsha.Basavapatna@Sun.COM }
52529336SSriharsha.Basavapatna@Sun.COM 
52531991Sheppo /* handler for control messages received from the peer ldc end-point */
52542793Slm66018 static int
vgen_handle_ctrlmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)52551991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
52561991Sheppo {
525712011SSriharsha.Basavapatna@Sun.COM 	int	rv = 0;
525812011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
52594647Sraghuram 
52604647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
52611991Sheppo 	switch (tagp->vio_subtype_env) {
52621991Sheppo 
52631991Sheppo 	case VIO_VER_INFO:
52642793Slm66018 		rv = vgen_handle_version_negotiate(ldcp, tagp);
52651991Sheppo 		break;
52661991Sheppo 
52671991Sheppo 	case VIO_ATTR_INFO:
526812011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_attr_msg(ldcp, tagp);
52691991Sheppo 		break;
52701991Sheppo 
52711991Sheppo 	case VIO_DRING_REG:
52722793Slm66018 		rv = vgen_handle_dring_reg(ldcp, tagp);
52731991Sheppo 		break;
52741991Sheppo 
52751991Sheppo 	case VIO_RDX:
52762793Slm66018 		rv = vgen_handle_rdx_info(ldcp, tagp);
52771991Sheppo 		break;
52781991Sheppo 
52791991Sheppo 	case VNET_MCAST_INFO:
52802793Slm66018 		rv = vgen_handle_mcast_info(ldcp, tagp);
52811991Sheppo 		break;
52821991Sheppo 
52836495Sspeer 	case VIO_DDS_INFO:
52849647SWentao.Yang@Sun.COM 		/*
52859647SWentao.Yang@Sun.COM 		 * If we are in the process of resetting the vswitch channel,
52869647SWentao.Yang@Sun.COM 		 * drop the dds message. A new handshake will be initiated
52879647SWentao.Yang@Sun.COM 		 * when the channel comes back up after the reset and dds
52889647SWentao.Yang@Sun.COM 		 * negotiation can then continue.
52899647SWentao.Yang@Sun.COM 		 */
529012011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->reset_in_progress == 1) {
52919647SWentao.Yang@Sun.COM 			break;
52929647SWentao.Yang@Sun.COM 		}
52936495Sspeer 		rv = vgen_dds_rx(ldcp, tagp);
52946495Sspeer 		break;
52959336SSriharsha.Basavapatna@Sun.COM 
52969336SSriharsha.Basavapatna@Sun.COM 	case VNET_PHYSLINK_INFO:
52979336SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_physlink_info(ldcp, tagp);
52989336SSriharsha.Basavapatna@Sun.COM 		break;
52991991Sheppo 	}
53002793Slm66018 
53014647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
53022793Slm66018 	return (rv);
53031991Sheppo }
53041991Sheppo 
530512011SSriharsha.Basavapatna@Sun.COM /* handler for error messages received from the peer ldc end-point */
530612011SSriharsha.Basavapatna@Sun.COM static void
vgen_handle_errmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)530712011SSriharsha.Basavapatna@Sun.COM vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
530812011SSriharsha.Basavapatna@Sun.COM {
530912011SSriharsha.Basavapatna@Sun.COM 	_NOTE(ARGUNUSED(ldcp, tagp))
531012011SSriharsha.Basavapatna@Sun.COM }
531112011SSriharsha.Basavapatna@Sun.COM 
531212011SSriharsha.Basavapatna@Sun.COM /*
531312011SSriharsha.Basavapatna@Sun.COM  * This function handles raw pkt data messages received over the channel.
531412011SSriharsha.Basavapatna@Sun.COM  * Currently, only priority-eth-type frames are received through this mechanism.
531512011SSriharsha.Basavapatna@Sun.COM  * In this case, the frame(data) is present within the message itself which
531612011SSriharsha.Basavapatna@Sun.COM  * is copied into an mblk before sending it up the stack.
531712011SSriharsha.Basavapatna@Sun.COM  */
531812011SSriharsha.Basavapatna@Sun.COM void
vgen_handle_pkt_data(void * arg1,void * arg2,uint32_t msglen)531912011SSriharsha.Basavapatna@Sun.COM vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen)
532012011SSriharsha.Basavapatna@Sun.COM {
532112011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg1;
532212011SSriharsha.Basavapatna@Sun.COM 	vio_raw_data_msg_t	*pkt	= (vio_raw_data_msg_t *)arg2;
532312011SSriharsha.Basavapatna@Sun.COM 	uint32_t		size;
532412011SSriharsha.Basavapatna@Sun.COM 	mblk_t			*mp;
532512011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t		*vmp;
532612011SSriharsha.Basavapatna@Sun.COM 	vio_net_rx_cb_t		vrx_cb = NULL;
532712011SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
532812011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t		*statsp = &ldcp->stats;
532912011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t		*lp = &ldcp->local_hparams;
533012011SSriharsha.Basavapatna@Sun.COM 	uint_t			dring_mode = lp->dring_mode;
533112011SSriharsha.Basavapatna@Sun.COM 
533212011SSriharsha.Basavapatna@Sun.COM 	ASSERT(MUTEX_HELD(&ldcp->cblock));
533312011SSriharsha.Basavapatna@Sun.COM 
533412011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->cblock);
533512011SSriharsha.Basavapatna@Sun.COM 
533612011SSriharsha.Basavapatna@Sun.COM 	size = msglen - VIO_PKT_DATA_HDRSIZE;
533712011SSriharsha.Basavapatna@Sun.COM 	if (size < ETHERMIN || size > lp->mtu) {
533812011SSriharsha.Basavapatna@Sun.COM 		(void) atomic_inc_32(&statsp->rx_pri_fail);
533912011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->cblock);
534012011SSriharsha.Basavapatna@Sun.COM 		return;
534112011SSriharsha.Basavapatna@Sun.COM 	}
534212011SSriharsha.Basavapatna@Sun.COM 
534312011SSriharsha.Basavapatna@Sun.COM 	vmp = vio_multipool_allocb(&ldcp->vmp, size);
534412011SSriharsha.Basavapatna@Sun.COM 	if (vmp == NULL) {
534512011SSriharsha.Basavapatna@Sun.COM 		mp = allocb(size, BPRI_MED);
534612011SSriharsha.Basavapatna@Sun.COM 		if (mp == NULL) {
534712011SSriharsha.Basavapatna@Sun.COM 			(void) atomic_inc_32(&statsp->rx_pri_fail);
534812011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "allocb failure, "
534912011SSriharsha.Basavapatna@Sun.COM 			    "unable to process priority frame\n");
535012011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->cblock);
535112011SSriharsha.Basavapatna@Sun.COM 			return;
535212011SSriharsha.Basavapatna@Sun.COM 		}
535312011SSriharsha.Basavapatna@Sun.COM 	} else {
535412011SSriharsha.Basavapatna@Sun.COM 		mp = vmp->mp;
535512011SSriharsha.Basavapatna@Sun.COM 	}
535612011SSriharsha.Basavapatna@Sun.COM 
535712011SSriharsha.Basavapatna@Sun.COM 	/* copy the frame from the payload of raw data msg into the mblk */
535812011SSriharsha.Basavapatna@Sun.COM 	bcopy(pkt->data, mp->b_rptr, size);
535912011SSriharsha.Basavapatna@Sun.COM 	mp->b_wptr = mp->b_rptr + size;
536012011SSriharsha.Basavapatna@Sun.COM 
536112011SSriharsha.Basavapatna@Sun.COM 	if (vmp != NULL) {
536212011SSriharsha.Basavapatna@Sun.COM 		vmp->state = VIO_MBLK_HAS_DATA;
536312011SSriharsha.Basavapatna@Sun.COM 	}
536412011SSriharsha.Basavapatna@Sun.COM 
536512011SSriharsha.Basavapatna@Sun.COM 	/* update stats */
536612011SSriharsha.Basavapatna@Sun.COM 	(void) atomic_inc_64(&statsp->rx_pri_packets);
536712011SSriharsha.Basavapatna@Sun.COM 	(void) atomic_add_64(&statsp->rx_pri_bytes, size);
536812011SSriharsha.Basavapatna@Sun.COM 
536912011SSriharsha.Basavapatna@Sun.COM 	/*
537012011SSriharsha.Basavapatna@Sun.COM 	 * If polling is currently enabled, add the packet to the priority
537112011SSriharsha.Basavapatna@Sun.COM 	 * packets list and return. It will be picked up by the polling thread.
537212011SSriharsha.Basavapatna@Sun.COM 	 */
537312011SSriharsha.Basavapatna@Sun.COM 	if (dring_mode == VIO_RX_DRING_DATA) {
537412011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rxlock);
537512011SSriharsha.Basavapatna@Sun.COM 	} else {
537612011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->pollq_lock);
537712011SSriharsha.Basavapatna@Sun.COM 	}
537812011SSriharsha.Basavapatna@Sun.COM 
537912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->polling_on == B_TRUE) {
538012011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->rx_pri_tail != NULL) {
538112011SSriharsha.Basavapatna@Sun.COM 			ldcp->rx_pri_tail->b_next = mp;
538212011SSriharsha.Basavapatna@Sun.COM 		} else {
538312011SSriharsha.Basavapatna@Sun.COM 			ldcp->rx_pri_head = ldcp->rx_pri_tail = mp;
538412011SSriharsha.Basavapatna@Sun.COM 		}
538512011SSriharsha.Basavapatna@Sun.COM 	} else {
538612011SSriharsha.Basavapatna@Sun.COM 		vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
538712011SSriharsha.Basavapatna@Sun.COM 	}
538812011SSriharsha.Basavapatna@Sun.COM 
538912011SSriharsha.Basavapatna@Sun.COM 	if (dring_mode == VIO_RX_DRING_DATA) {
539012011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
539112011SSriharsha.Basavapatna@Sun.COM 	} else {
539212011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->pollq_lock);
539312011SSriharsha.Basavapatna@Sun.COM 	}
539412011SSriharsha.Basavapatna@Sun.COM 
539512011SSriharsha.Basavapatna@Sun.COM 	if (vrx_cb != NULL) {
539612011SSriharsha.Basavapatna@Sun.COM 		vrx_cb(ldcp->portp->vhp, mp);
539712011SSriharsha.Basavapatna@Sun.COM 	}
539812011SSriharsha.Basavapatna@Sun.COM 
539912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->cblock);
540012011SSriharsha.Basavapatna@Sun.COM }
540112011SSriharsha.Basavapatna@Sun.COM 
540212011SSriharsha.Basavapatna@Sun.COM /*
540312011SSriharsha.Basavapatna@Sun.COM  * dummy pkt data handler function for vnet protocol version 1.0
540412011SSriharsha.Basavapatna@Sun.COM  */
540512011SSriharsha.Basavapatna@Sun.COM static void
vgen_handle_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)540612011SSriharsha.Basavapatna@Sun.COM vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
540712011SSriharsha.Basavapatna@Sun.COM {
540812011SSriharsha.Basavapatna@Sun.COM 	_NOTE(ARGUNUSED(arg1, arg2, msglen))
540912011SSriharsha.Basavapatna@Sun.COM }
541012011SSriharsha.Basavapatna@Sun.COM 
54111991Sheppo /* handler for data messages received from the peer ldc end-point */
54122793Slm66018 static int
vgen_handle_datamsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp,uint32_t msglen)54135935Ssb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen)
54141991Sheppo {
541512011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
541612011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
541712011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t	*lp = &ldcp->local_hparams;
54184647Sraghuram 
54194647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
54201991Sheppo 
542112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase != VH_DONE) {
542212011SSriharsha.Basavapatna@Sun.COM 		return (0);
542312011SSriharsha.Basavapatna@Sun.COM 	}
542412011SSriharsha.Basavapatna@Sun.COM 
542512011SSriharsha.Basavapatna@Sun.COM 	/*
542612011SSriharsha.Basavapatna@Sun.COM 	 * We check the data msg seqnum. This is needed only in TxDring mode.
542712011SSriharsha.Basavapatna@Sun.COM 	 */
542812011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_TX_DRING &&
542912011SSriharsha.Basavapatna@Sun.COM 	    tagp->vio_subtype == VIO_SUBTYPE_INFO) {
54305935Ssb155480 		rv = vgen_check_datamsg_seq(ldcp, tagp);
54315935Ssb155480 		if (rv != 0) {
54325935Ssb155480 			return (rv);
54335935Ssb155480 		}
54345935Ssb155480 	}
54355935Ssb155480 
54361991Sheppo 	switch (tagp->vio_subtype_env) {
54371991Sheppo 	case VIO_DRING_DATA:
543812011SSriharsha.Basavapatna@Sun.COM 		rv = ldcp->rx_dringdata((void *)ldcp, (void *)tagp);
54391991Sheppo 		break;
54405935Ssb155480 
54415935Ssb155480 	case VIO_PKT_DATA:
54425935Ssb155480 		ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen);
54435935Ssb155480 		break;
54441991Sheppo 	default:
54451991Sheppo 		break;
54461991Sheppo 	}
54471991Sheppo 
54484647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
54492793Slm66018 	return (rv);
54501991Sheppo }
54511991Sheppo 
54524647Sraghuram 
54534647Sraghuram static int
vgen_ldc_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)545412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
54554647Sraghuram {
545612011SSriharsha.Basavapatna@Sun.COM 	int	rv;
545712011SSriharsha.Basavapatna@Sun.COM 
545812011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
545912011SSriharsha.Basavapatna@Sun.COM 		ASSERT(MUTEX_HELD(&ldcp->cblock));
546012011SSriharsha.Basavapatna@Sun.COM 	}
546112011SSriharsha.Basavapatna@Sun.COM 
546212011SSriharsha.Basavapatna@Sun.COM 	/* Set the flag to indicate reset is in progress */
546312011SSriharsha.Basavapatna@Sun.COM 	if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
546412011SSriharsha.Basavapatna@Sun.COM 		/* another thread is already in the process of resetting */
546512011SSriharsha.Basavapatna@Sun.COM 		return (EBUSY);
546612011SSriharsha.Basavapatna@Sun.COM 	}
546712011SSriharsha.Basavapatna@Sun.COM 
546812011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
546912011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
547012011SSriharsha.Basavapatna@Sun.COM 	}
547112011SSriharsha.Basavapatna@Sun.COM 
547212011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_process_reset(ldcp, VGEN_FLAG_NEED_LDCRESET);
547312011SSriharsha.Basavapatna@Sun.COM 
547412011SSriharsha.Basavapatna@Sun.COM 	if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
547512011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->cblock);
547612011SSriharsha.Basavapatna@Sun.COM 	}
547712011SSriharsha.Basavapatna@Sun.COM 
54782793Slm66018 	return (rv);
54791991Sheppo }
54801991Sheppo 
54811991Sheppo static void
vgen_ldc_up(vgen_ldc_t * ldcp)548212011SSriharsha.Basavapatna@Sun.COM vgen_ldc_up(vgen_ldc_t *ldcp)
54831991Sheppo {
548412011SSriharsha.Basavapatna@Sun.COM 	int		rv;
548512011SSriharsha.Basavapatna@Sun.COM 	uint32_t	retries = 0;
548612011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
548712011SSriharsha.Basavapatna@Sun.COM 
548812011SSriharsha.Basavapatna@Sun.COM 	ASSERT(MUTEX_HELD(&ldcp->cblock));
54891991Sheppo 
54901991Sheppo 	/*
549112011SSriharsha.Basavapatna@Sun.COM 	 * If the channel has been reset max # of times, without successfully
549212011SSriharsha.Basavapatna@Sun.COM 	 * completing handshake, stop and do not bring the channel up.
54931991Sheppo 	 */
549412011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->ldc_reset_count == vgen_ldc_max_resets) {
549512011SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN, "!vnet%d: exceeded number of permitted"
549612011SSriharsha.Basavapatna@Sun.COM 		    " handshake attempts (%d) on channel %ld",
549712011SSriharsha.Basavapatna@Sun.COM 		    vgenp->instance, vgen_ldc_max_resets, ldcp->ldc_id);
549812011SSriharsha.Basavapatna@Sun.COM 		return;
549912011SSriharsha.Basavapatna@Sun.COM 	}
550012011SSriharsha.Basavapatna@Sun.COM 	ldcp->ldc_reset_count++;
550112011SSriharsha.Basavapatna@Sun.COM 
550212011SSriharsha.Basavapatna@Sun.COM 	do {
550312011SSriharsha.Basavapatna@Sun.COM 		rv = ldc_up(ldcp->ldc_handle);
550412011SSriharsha.Basavapatna@Sun.COM 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
550512011SSriharsha.Basavapatna@Sun.COM 			drv_usecwait(VGEN_LDC_UP_DELAY);
550612011SSriharsha.Basavapatna@Sun.COM 		}
550712011SSriharsha.Basavapatna@Sun.COM 		if (retries++ >= vgen_ldcup_retries)
550812011SSriharsha.Basavapatna@Sun.COM 			break;
550912011SSriharsha.Basavapatna@Sun.COM 	} while (rv == EWOULDBLOCK);
551012011SSriharsha.Basavapatna@Sun.COM 
551112011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
551212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
55131991Sheppo 	}
55141991Sheppo }
55151991Sheppo 
551612011SSriharsha.Basavapatna@Sun.COM int
vgen_enable_intr(void * arg)551712011SSriharsha.Basavapatna@Sun.COM vgen_enable_intr(void *arg)
55181991Sheppo {
551912011SSriharsha.Basavapatna@Sun.COM 	uint32_t		end_ix;
552012011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t		msg;
552112011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t		*portp = (vgen_port_t *)arg;
552212011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t		*ldcp = portp->ldcp;
552312011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t		*lp = &ldcp->local_hparams;
552412011SSriharsha.Basavapatna@Sun.COM 
552512011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
552612011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rxlock);
552712011SSriharsha.Basavapatna@Sun.COM 
552812011SSriharsha.Basavapatna@Sun.COM 		ldcp->polling_on = B_FALSE;
552912011SSriharsha.Basavapatna@Sun.COM 		/*
553012011SSriharsha.Basavapatna@Sun.COM 		 * We send a stopped message to peer (sender) as we are turning
553112011SSriharsha.Basavapatna@Sun.COM 		 * off polled mode. This effectively restarts data interrupts
553212011SSriharsha.Basavapatna@Sun.COM 		 * by allowing the peer to send further dring data msgs to us.
553312011SSriharsha.Basavapatna@Sun.COM 		 */
553412011SSriharsha.Basavapatna@Sun.COM 		end_ix = ldcp->next_rxi;
553512011SSriharsha.Basavapatna@Sun.COM 		DECR_RXI(end_ix, ldcp);
553612011SSriharsha.Basavapatna@Sun.COM 		msg.dring_ident = ldcp->peer_hparams.dring_ident;
553712011SSriharsha.Basavapatna@Sun.COM 		(void) vgen_send_dringack_shm(ldcp, (vio_msg_tag_t *)&msg,
553812011SSriharsha.Basavapatna@Sun.COM 		    VNET_START_IDX_UNSPEC, end_ix, VIO_DP_STOPPED);
553912011SSriharsha.Basavapatna@Sun.COM 
554012011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
554112011SSriharsha.Basavapatna@Sun.COM 	} else {
554212011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->pollq_lock);
554312011SSriharsha.Basavapatna@Sun.COM 		ldcp->polling_on = B_FALSE;
554412011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->pollq_lock);
554512011SSriharsha.Basavapatna@Sun.COM 	}
554612011SSriharsha.Basavapatna@Sun.COM 
554712011SSriharsha.Basavapatna@Sun.COM 	return (0);
55481991Sheppo }
55491991Sheppo 
555012011SSriharsha.Basavapatna@Sun.COM int
vgen_disable_intr(void * arg)555112011SSriharsha.Basavapatna@Sun.COM vgen_disable_intr(void *arg)
55521991Sheppo {
555312011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t		*portp = (vgen_port_t *)arg;
555412011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t		*ldcp = portp->ldcp;
555512011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t		*lp = &ldcp->local_hparams;
555612011SSriharsha.Basavapatna@Sun.COM 
555712011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
555812011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rxlock);
555912011SSriharsha.Basavapatna@Sun.COM 		ldcp->polling_on = B_TRUE;
556012011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
55611991Sheppo 	} else {
556212011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->pollq_lock);
556312011SSriharsha.Basavapatna@Sun.COM 		ldcp->polling_on = B_TRUE;
556412011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->pollq_lock);
556512011SSriharsha.Basavapatna@Sun.COM 	}
556612011SSriharsha.Basavapatna@Sun.COM 
556712011SSriharsha.Basavapatna@Sun.COM 	return (0);
556812011SSriharsha.Basavapatna@Sun.COM }
556912011SSriharsha.Basavapatna@Sun.COM 
557012011SSriharsha.Basavapatna@Sun.COM mblk_t *
vgen_rx_poll(void * arg,int bytes_to_pickup)557112011SSriharsha.Basavapatna@Sun.COM vgen_rx_poll(void *arg, int bytes_to_pickup)
557212011SSriharsha.Basavapatna@Sun.COM {
557312011SSriharsha.Basavapatna@Sun.COM 	vgen_port_t		*portp = (vgen_port_t *)arg;
557412011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t		*ldcp = portp->ldcp;
557512011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t		*lp = &ldcp->local_hparams;
557612011SSriharsha.Basavapatna@Sun.COM 	mblk_t			*mp = NULL;
557712011SSriharsha.Basavapatna@Sun.COM 
557812011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
557912011SSriharsha.Basavapatna@Sun.COM 		mp = vgen_poll_rcv_shm(ldcp, bytes_to_pickup);
558012011SSriharsha.Basavapatna@Sun.COM 	} else {
558112011SSriharsha.Basavapatna@Sun.COM 		mp = vgen_poll_rcv(ldcp, bytes_to_pickup);
558212011SSriharsha.Basavapatna@Sun.COM 	}
558312011SSriharsha.Basavapatna@Sun.COM 
558412011SSriharsha.Basavapatna@Sun.COM 	return (mp);
55851991Sheppo }
55861991Sheppo 
55871991Sheppo /* transmit watchdog timeout handler */
55881991Sheppo static void
vgen_tx_watchdog(void * arg)558912011SSriharsha.Basavapatna@Sun.COM vgen_tx_watchdog(void *arg)
55901991Sheppo {
559112011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp;
559212011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp;
559312011SSriharsha.Basavapatna@Sun.COM 	int		rv;
559412011SSriharsha.Basavapatna@Sun.COM 	boolean_t	tx_blocked;
559512011SSriharsha.Basavapatna@Sun.COM 	clock_t		tx_blocked_lbolt;
55961991Sheppo 
55971991Sheppo 	ldcp = (vgen_ldc_t *)arg;
55982336Snarayan 	vgenp = LDC_TO_VGEN(ldcp);
55991991Sheppo 
560012011SSriharsha.Basavapatna@Sun.COM 	tx_blocked = ldcp->tx_blocked;
560112011SSriharsha.Basavapatna@Sun.COM 	tx_blocked_lbolt = ldcp->tx_blocked_lbolt;
560212011SSriharsha.Basavapatna@Sun.COM 
560312011SSriharsha.Basavapatna@Sun.COM 	if (vgen_txwd_timeout &&
560412011SSriharsha.Basavapatna@Sun.COM 	    (tx_blocked == B_TRUE) &&
560512011SSriharsha.Basavapatna@Sun.COM 	    ((ddi_get_lbolt() - tx_blocked_lbolt) >
560612011SSriharsha.Basavapatna@Sun.COM 	    drv_usectohz(vgen_txwd_timeout * 1000))) {
560712011SSriharsha.Basavapatna@Sun.COM 		/*
560812011SSriharsha.Basavapatna@Sun.COM 		 * Something is wrong; the peer is not picking up the packets
560912011SSriharsha.Basavapatna@Sun.COM 		 * in the transmit dring. We now go ahead and reset the channel
561012011SSriharsha.Basavapatna@Sun.COM 		 * to break out of this condition.
561112011SSriharsha.Basavapatna@Sun.COM 		 */
561212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "transmit timeout lbolt(%lx), "
561312011SSriharsha.Basavapatna@Sun.COM 		    "tx_blocked_lbolt(%lx)\n",
561412011SSriharsha.Basavapatna@Sun.COM 		    ddi_get_lbolt(), tx_blocked_lbolt);
561512011SSriharsha.Basavapatna@Sun.COM 
56161991Sheppo #ifdef DEBUG
561712011SSriharsha.Basavapatna@Sun.COM 		if (vgen_inject_error(ldcp, VGEN_ERR_TXTIMEOUT)) {
56181991Sheppo 			/* tx timeout triggered for debugging */
561912011SSriharsha.Basavapatna@Sun.COM 			vgen_inject_err_flag &= ~(VGEN_ERR_TXTIMEOUT);
56201991Sheppo 		}
56211991Sheppo #endif
562212011SSriharsha.Basavapatna@Sun.COM 
562312011SSriharsha.Basavapatna@Sun.COM 		/*
562412011SSriharsha.Basavapatna@Sun.COM 		 * Clear tid before invoking vgen_ldc_reset(). Otherwise,
562512011SSriharsha.Basavapatna@Sun.COM 		 * it will result in a deadlock when vgen_process_reset() tries
562612011SSriharsha.Basavapatna@Sun.COM 		 * to untimeout() on seeing a non-zero tid, but it is being
562712011SSriharsha.Basavapatna@Sun.COM 		 * invoked by the timer itself in this case.
562812011SSriharsha.Basavapatna@Sun.COM 		 */
56291991Sheppo 		mutex_enter(&ldcp->cblock);
563012011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->wd_tid == 0) {
563112011SSriharsha.Basavapatna@Sun.COM 			/* Cancelled by vgen_process_reset() */
563212011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->cblock);
563312011SSriharsha.Basavapatna@Sun.COM 			return;
56341991Sheppo 		}
563512011SSriharsha.Basavapatna@Sun.COM 		ldcp->wd_tid = 0;
563612011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
563712011SSriharsha.Basavapatna@Sun.COM 
563812011SSriharsha.Basavapatna@Sun.COM 		/*
563912011SSriharsha.Basavapatna@Sun.COM 		 * Now reset the channel.
564012011SSriharsha.Basavapatna@Sun.COM 		 */
564112011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_ldc_reset(ldcp, VGEN_OTHER);
564212011SSriharsha.Basavapatna@Sun.COM 		if (rv == 0) {
564312011SSriharsha.Basavapatna@Sun.COM 			/*
564412011SSriharsha.Basavapatna@Sun.COM 			 * We have successfully reset the channel. If we are
564512011SSriharsha.Basavapatna@Sun.COM 			 * in tx flow controlled state, clear it now and enable
564612011SSriharsha.Basavapatna@Sun.COM 			 * transmit in the upper layer.
564712011SSriharsha.Basavapatna@Sun.COM 			 */
564812011SSriharsha.Basavapatna@Sun.COM 			if (ldcp->tx_blocked) {
564912011SSriharsha.Basavapatna@Sun.COM 				vio_net_tx_update_t vtx_update =
565012011SSriharsha.Basavapatna@Sun.COM 				    ldcp->portp->vcb.vio_net_tx_update;
565112011SSriharsha.Basavapatna@Sun.COM 
565212011SSriharsha.Basavapatna@Sun.COM 				ldcp->tx_blocked = B_FALSE;
565312011SSriharsha.Basavapatna@Sun.COM 				vtx_update(ldcp->portp->vhp);
565412011SSriharsha.Basavapatna@Sun.COM 			}
565512011SSriharsha.Basavapatna@Sun.COM 		}
565612011SSriharsha.Basavapatna@Sun.COM 
565712011SSriharsha.Basavapatna@Sun.COM 		/*
565812011SSriharsha.Basavapatna@Sun.COM 		 * Channel has been reset by us or some other thread is already
565912011SSriharsha.Basavapatna@Sun.COM 		 * in the process of resetting. In either case, we return
566012011SSriharsha.Basavapatna@Sun.COM 		 * without restarting the timer. When handshake completes and
566112011SSriharsha.Basavapatna@Sun.COM 		 * the channel is ready for data transmit/receive we start a
566212011SSriharsha.Basavapatna@Sun.COM 		 * new watchdog timer.
566312011SSriharsha.Basavapatna@Sun.COM 		 */
566412011SSriharsha.Basavapatna@Sun.COM 		return;
566512011SSriharsha.Basavapatna@Sun.COM 	}
566612011SSriharsha.Basavapatna@Sun.COM 
566712011SSriharsha.Basavapatna@Sun.COM restart_timer:
566812011SSriharsha.Basavapatna@Sun.COM 	/* Restart the timer */
566912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->cblock);
567012011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->wd_tid == 0) {
567112011SSriharsha.Basavapatna@Sun.COM 		/* Cancelled by vgen_process_reset() */
567212011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
567312011SSriharsha.Basavapatna@Sun.COM 		return;
567412011SSriharsha.Basavapatna@Sun.COM 	}
567512011SSriharsha.Basavapatna@Sun.COM 	ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
567612011SSriharsha.Basavapatna@Sun.COM 	    drv_usectohz(vgen_txwd_interval * 1000));
567712011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->cblock);
56781991Sheppo }
56791991Sheppo 
568012011SSriharsha.Basavapatna@Sun.COM /* Handshake watchdog timeout handler */
56811991Sheppo static void
vgen_hwatchdog(void * arg)568212011SSriharsha.Basavapatna@Sun.COM vgen_hwatchdog(void *arg)
56835935Ssb155480 {
568412011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp = (vgen_ldc_t *)arg;
568512011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
568612011SSriharsha.Basavapatna@Sun.COM 
568712011SSriharsha.Basavapatna@Sun.COM 	DWARN(vgenp, ldcp, "handshake timeout phase(%x) state(%x)\n",
568812011SSriharsha.Basavapatna@Sun.COM 	    ldcp->hphase, ldcp->hstate);
568912011SSriharsha.Basavapatna@Sun.COM 
569012011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->cblock);
569112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->htid == 0) {
569212011SSriharsha.Basavapatna@Sun.COM 		/* Cancelled by vgen_process_reset() */
569312011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
569412011SSriharsha.Basavapatna@Sun.COM 		return;
569512011SSriharsha.Basavapatna@Sun.COM 	}
569612011SSriharsha.Basavapatna@Sun.COM 	ldcp->htid = 0;
569712011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->cblock);
569812011SSriharsha.Basavapatna@Sun.COM 
569912011SSriharsha.Basavapatna@Sun.COM 	/*
570012011SSriharsha.Basavapatna@Sun.COM 	 * Something is wrong; handshake with the peer seems to be hung. We now
570112011SSriharsha.Basavapatna@Sun.COM 	 * go ahead and reset the channel to break out of this condition.
570212011SSriharsha.Basavapatna@Sun.COM 	 */
570312011SSriharsha.Basavapatna@Sun.COM 	(void) vgen_ldc_reset(ldcp, VGEN_OTHER);
57045935Ssb155480 }
57055935Ssb155480 
57061991Sheppo /* Check if the session id in the received message is valid */
57071991Sheppo static int
vgen_check_sid(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)57081991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
57091991Sheppo {
571012011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
57114647Sraghuram 
57121991Sheppo 	if (tagp->vio_sid != ldcp->peer_sid) {
57134647Sraghuram 		DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
57144647Sraghuram 		    ldcp->peer_sid, tagp->vio_sid);
57151991Sheppo 		return (VGEN_FAILURE);
57161991Sheppo 	}
57171991Sheppo 	else
57181991Sheppo 		return (VGEN_SUCCESS);
57191991Sheppo }
57201991Sheppo 
57214647Sraghuram /*
572212011SSriharsha.Basavapatna@Sun.COM  * Initialize the common part of dring registration
572312011SSriharsha.Basavapatna@Sun.COM  * message; used in both TxDring and RxDringData modes.
57244647Sraghuram  */
57254647Sraghuram static void
vgen_init_dring_reg_msg(vgen_ldc_t * ldcp,vio_dring_reg_msg_t * msg,uint8_t option)572612011SSriharsha.Basavapatna@Sun.COM vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
572712011SSriharsha.Basavapatna@Sun.COM 	uint8_t option)
57284647Sraghuram {
572912011SSriharsha.Basavapatna@Sun.COM 	vio_msg_tag_t		*tagp;
573012011SSriharsha.Basavapatna@Sun.COM 
573112011SSriharsha.Basavapatna@Sun.COM 	tagp = &msg->tag;
573212011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_msgtype = VIO_TYPE_CTRL;
573312011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
573412011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype_env = VIO_DRING_REG;
573512011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_sid = ldcp->local_sid;
573612011SSriharsha.Basavapatna@Sun.COM 
573712011SSriharsha.Basavapatna@Sun.COM 	/* get dring info msg payload from ldcp->local */
573812011SSriharsha.Basavapatna@Sun.COM 	bcopy(&(ldcp->local_hparams.dring_cookie), &(msg->cookie[0]),
573912011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t));
574012011SSriharsha.Basavapatna@Sun.COM 	msg->ncookies = ldcp->local_hparams.dring_ncookies;
574112011SSriharsha.Basavapatna@Sun.COM 	msg->num_descriptors = ldcp->local_hparams.num_desc;
574212011SSriharsha.Basavapatna@Sun.COM 	msg->descriptor_size = ldcp->local_hparams.desc_size;
574312011SSriharsha.Basavapatna@Sun.COM 
574412011SSriharsha.Basavapatna@Sun.COM 	msg->options = option;
57458623SSriharsha.Basavapatna@Sun.COM 
57468623SSriharsha.Basavapatna@Sun.COM 	/*
574712011SSriharsha.Basavapatna@Sun.COM 	 * dring_ident is set to 0. After mapping the dring, peer sets this
574812011SSriharsha.Basavapatna@Sun.COM 	 * value and sends it in the ack, which is saved in
574912011SSriharsha.Basavapatna@Sun.COM 	 * vgen_handle_dring_reg().
57508623SSriharsha.Basavapatna@Sun.COM 	 */
575112011SSriharsha.Basavapatna@Sun.COM 	msg->dring_ident = 0;
575210309SSriharsha.Basavapatna@Sun.COM }
575310309SSriharsha.Basavapatna@Sun.COM 
5754*13098SWentao.Yang@Sun.COM static int
vgen_mapin_avail(vgen_ldc_t * ldcp)5755*13098SWentao.Yang@Sun.COM vgen_mapin_avail(vgen_ldc_t *ldcp)
5756*13098SWentao.Yang@Sun.COM {
5757*13098SWentao.Yang@Sun.COM 	int		rv;
5758*13098SWentao.Yang@Sun.COM 	ldc_info_t	info;
5759*13098SWentao.Yang@Sun.COM 	uint64_t	mapin_sz_req;
5760*13098SWentao.Yang@Sun.COM 	uint64_t	dblk_sz;
5761*13098SWentao.Yang@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
5762*13098SWentao.Yang@Sun.COM 
5763*13098SWentao.Yang@Sun.COM 	rv = ldc_info(ldcp->ldc_handle, &info);
5764*13098SWentao.Yang@Sun.COM 	if (rv != 0) {
5765*13098SWentao.Yang@Sun.COM 		return (B_FALSE);
5766*13098SWentao.Yang@Sun.COM 	}
5767*13098SWentao.Yang@Sun.COM 
5768*13098SWentao.Yang@Sun.COM 	dblk_sz = RXDRING_DBLK_SZ(vgenp->max_frame_size);
5769*13098SWentao.Yang@Sun.COM 	mapin_sz_req = (VGEN_RXDRING_NRBUFS * dblk_sz);
5770*13098SWentao.Yang@Sun.COM 
5771*13098SWentao.Yang@Sun.COM 	if (info.direct_map_size_max >= mapin_sz_req) {
5772*13098SWentao.Yang@Sun.COM 		return (B_TRUE);
5773*13098SWentao.Yang@Sun.COM 	}
5774*13098SWentao.Yang@Sun.COM 
5775*13098SWentao.Yang@Sun.COM 	return (B_FALSE);
5776*13098SWentao.Yang@Sun.COM }
5777*13098SWentao.Yang@Sun.COM 
57784647Sraghuram #if DEBUG
57794647Sraghuram 
57804647Sraghuram /*
57814647Sraghuram  * Print debug messages - set to 0xf to enable all msgs
57824647Sraghuram  */
578312011SSriharsha.Basavapatna@Sun.COM void
vgen_debug_printf(const char * fname,vgen_t * vgenp,vgen_ldc_t * ldcp,const char * fmt,...)578412011SSriharsha.Basavapatna@Sun.COM vgen_debug_printf(const char *fname, vgen_t *vgenp,
57854647Sraghuram     vgen_ldc_t *ldcp, const char *fmt, ...)
57864647Sraghuram {
578712011SSriharsha.Basavapatna@Sun.COM 	char	buf[256];
578812011SSriharsha.Basavapatna@Sun.COM 	char	*bufp = buf;
578912011SSriharsha.Basavapatna@Sun.COM 	va_list	ap;
57904647Sraghuram 
57914647Sraghuram 	if ((vgenp != NULL) && (vgenp->vnetp != NULL)) {
57924647Sraghuram 		(void) sprintf(bufp, "vnet%d:",
57934650Sraghuram 		    ((vnet_t *)(vgenp->vnetp))->instance);
57944647Sraghuram 		bufp += strlen(bufp);
57954647Sraghuram 	}
57964647Sraghuram 	if (ldcp != NULL) {
57974647Sraghuram 		(void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id);
57984647Sraghuram 		bufp += strlen(bufp);
57994647Sraghuram 	}
58004647Sraghuram 	(void) sprintf(bufp, "%s: ", fname);
58014647Sraghuram 	bufp += strlen(bufp);
58024647Sraghuram 
58034647Sraghuram 	va_start(ap, fmt);
58044647Sraghuram 	(void) vsprintf(bufp, fmt, ap);
58054647Sraghuram 	va_end(ap);
58064647Sraghuram 
58074647Sraghuram 	if ((ldcp == NULL) ||(vgendbg_ldcid == -1) ||
58084647Sraghuram 	    (vgendbg_ldcid == ldcp->ldc_id)) {
58094647Sraghuram 		cmn_err(CE_CONT, "%s\n", buf);
58104647Sraghuram 	}
58114647Sraghuram }
58124647Sraghuram #endif
58139336SSriharsha.Basavapatna@Sun.COM 
58149336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
58159336SSriharsha.Basavapatna@Sun.COM 
58169336SSriharsha.Basavapatna@Sun.COM static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)58179336SSriharsha.Basavapatna@Sun.COM vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
58189336SSriharsha.Basavapatna@Sun.COM {
58199336SSriharsha.Basavapatna@Sun.COM 	struct iocblk	*iocp;
58209336SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*portp;
58219336SSriharsha.Basavapatna@Sun.COM 	enum		ioc_reply {
58229336SSriharsha.Basavapatna@Sun.COM 			IOC_INVAL = -1,		/* bad, NAK with EINVAL */
58239336SSriharsha.Basavapatna@Sun.COM 			IOC_ACK			/* OK, just send ACK    */
58249336SSriharsha.Basavapatna@Sun.COM 	}		status;
58259336SSriharsha.Basavapatna@Sun.COM 	int		rv;
58269336SSriharsha.Basavapatna@Sun.COM 
58279336SSriharsha.Basavapatna@Sun.COM 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
58289336SSriharsha.Basavapatna@Sun.COM 	iocp->ioc_error = 0;
58299336SSriharsha.Basavapatna@Sun.COM 	portp = (vgen_port_t *)arg;
58309336SSriharsha.Basavapatna@Sun.COM 
58319336SSriharsha.Basavapatna@Sun.COM 	if (portp == NULL) {
58329336SSriharsha.Basavapatna@Sun.COM 		status = IOC_INVAL;
58339336SSriharsha.Basavapatna@Sun.COM 		goto vgen_ioc_exit;
58349336SSriharsha.Basavapatna@Sun.COM 	}
58359336SSriharsha.Basavapatna@Sun.COM 
58369336SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&portp->lock);
58379336SSriharsha.Basavapatna@Sun.COM 
58389336SSriharsha.Basavapatna@Sun.COM 	switch (iocp->ioc_cmd) {
58399336SSriharsha.Basavapatna@Sun.COM 
58409336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_DOWN:
58419336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_UP:
58429336SSriharsha.Basavapatna@Sun.COM 		rv = vgen_force_link_state(portp, iocp->ioc_cmd);
58439336SSriharsha.Basavapatna@Sun.COM 		(rv == 0) ? (status = IOC_ACK) : (status = IOC_INVAL);
58449336SSriharsha.Basavapatna@Sun.COM 		break;
58459336SSriharsha.Basavapatna@Sun.COM 
58469336SSriharsha.Basavapatna@Sun.COM 	default:
58479336SSriharsha.Basavapatna@Sun.COM 		status = IOC_INVAL;
58489336SSriharsha.Basavapatna@Sun.COM 		break;
58499336SSriharsha.Basavapatna@Sun.COM 
58509336SSriharsha.Basavapatna@Sun.COM 	}
58519336SSriharsha.Basavapatna@Sun.COM 
58529336SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&portp->lock);
58539336SSriharsha.Basavapatna@Sun.COM 
58549336SSriharsha.Basavapatna@Sun.COM vgen_ioc_exit:
58559336SSriharsha.Basavapatna@Sun.COM 
58569336SSriharsha.Basavapatna@Sun.COM 	switch (status) {
58579336SSriharsha.Basavapatna@Sun.COM 	default:
58589336SSriharsha.Basavapatna@Sun.COM 	case IOC_INVAL:
58599336SSriharsha.Basavapatna@Sun.COM 		/* Error, reply with a NAK and EINVAL error */
58609336SSriharsha.Basavapatna@Sun.COM 		miocnak(q, mp, 0, EINVAL);
58619336SSriharsha.Basavapatna@Sun.COM 		break;
58629336SSriharsha.Basavapatna@Sun.COM 	case IOC_ACK:
58639336SSriharsha.Basavapatna@Sun.COM 		/* OK, reply with an ACK */
58649336SSriharsha.Basavapatna@Sun.COM 		miocack(q, mp, 0, 0);
58659336SSriharsha.Basavapatna@Sun.COM 		break;
58669336SSriharsha.Basavapatna@Sun.COM 	}
58679336SSriharsha.Basavapatna@Sun.COM }
58689336SSriharsha.Basavapatna@Sun.COM 
58699336SSriharsha.Basavapatna@Sun.COM static int
vgen_force_link_state(vgen_port_t * portp,int cmd)58709336SSriharsha.Basavapatna@Sun.COM vgen_force_link_state(vgen_port_t *portp, int cmd)
58719336SSriharsha.Basavapatna@Sun.COM {
58729336SSriharsha.Basavapatna@Sun.COM 	ldc_status_t	istatus;
587312011SSriharsha.Basavapatna@Sun.COM 	int		rv;
587412011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp = portp->ldcp;
58759336SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = portp->vgenp;
587612011SSriharsha.Basavapatna@Sun.COM 
58779336SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->cblock);
58789336SSriharsha.Basavapatna@Sun.COM 
58799336SSriharsha.Basavapatna@Sun.COM 	switch (cmd) {
58809336SSriharsha.Basavapatna@Sun.COM 
58819336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_DOWN:
58829336SSriharsha.Basavapatna@Sun.COM 		(void) ldc_down(ldcp->ldc_handle);
58839336SSriharsha.Basavapatna@Sun.COM 		ldcp->link_down_forced = B_TRUE;
58849336SSriharsha.Basavapatna@Sun.COM 		break;
58859336SSriharsha.Basavapatna@Sun.COM 
58869336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_UP:
588712011SSriharsha.Basavapatna@Sun.COM 		vgen_ldc_up(ldcp);
58889336SSriharsha.Basavapatna@Sun.COM 		ldcp->link_down_forced = B_FALSE;
58899336SSriharsha.Basavapatna@Sun.COM 
58909336SSriharsha.Basavapatna@Sun.COM 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
58919336SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "ldc_status err\n");
58929336SSriharsha.Basavapatna@Sun.COM 		} else {
58939336SSriharsha.Basavapatna@Sun.COM 			ldcp->ldc_status = istatus;
58949336SSriharsha.Basavapatna@Sun.COM 		}
58959336SSriharsha.Basavapatna@Sun.COM 
58969336SSriharsha.Basavapatna@Sun.COM 		/* if channel is already UP - restart handshake */
58979336SSriharsha.Basavapatna@Sun.COM 		if (ldcp->ldc_status == LDC_UP) {
58989336SSriharsha.Basavapatna@Sun.COM 			vgen_handle_evt_up(ldcp);
58999336SSriharsha.Basavapatna@Sun.COM 		}
59009336SSriharsha.Basavapatna@Sun.COM 		break;
59019336SSriharsha.Basavapatna@Sun.COM 
59029336SSriharsha.Basavapatna@Sun.COM 	}
59039336SSriharsha.Basavapatna@Sun.COM 
59049336SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->cblock);
59059336SSriharsha.Basavapatna@Sun.COM 
59069336SSriharsha.Basavapatna@Sun.COM 	return (0);
59079336SSriharsha.Basavapatna@Sun.COM }
59089336SSriharsha.Basavapatna@Sun.COM 
59099336SSriharsha.Basavapatna@Sun.COM #else
59109336SSriharsha.Basavapatna@Sun.COM 
59119336SSriharsha.Basavapatna@Sun.COM static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)59129336SSriharsha.Basavapatna@Sun.COM vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
59139336SSriharsha.Basavapatna@Sun.COM {
59149336SSriharsha.Basavapatna@Sun.COM 	vgen_port_t	*portp;
59159336SSriharsha.Basavapatna@Sun.COM 
59169336SSriharsha.Basavapatna@Sun.COM 	portp = (vgen_port_t *)arg;
59179336SSriharsha.Basavapatna@Sun.COM 
59189336SSriharsha.Basavapatna@Sun.COM 	if (portp == NULL) {
59199336SSriharsha.Basavapatna@Sun.COM 		miocnak(q, mp, 0, EINVAL);
59209336SSriharsha.Basavapatna@Sun.COM 		return;
59219336SSriharsha.Basavapatna@Sun.COM 	}
59229336SSriharsha.Basavapatna@Sun.COM 
59239336SSriharsha.Basavapatna@Sun.COM 	miocnak(q, mp, 0, ENOTSUP);
59249336SSriharsha.Basavapatna@Sun.COM }
59259336SSriharsha.Basavapatna@Sun.COM 
59269336SSriharsha.Basavapatna@Sun.COM #endif
5927