xref: /onnv-gate/usr/src/uts/sun4v/io/vsw_ldc.c (revision 13098:496fd9979cfc)
15373Sraghuram /*
25373Sraghuram  * CDDL HEADER START
35373Sraghuram  *
45373Sraghuram  * The contents of this file are subject to the terms of the
55373Sraghuram  * Common Development and Distribution License (the "License").
65373Sraghuram  * You may not use this file except in compliance with the License.
75373Sraghuram  *
85373Sraghuram  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95373Sraghuram  * or http://www.opensolaris.org/os/licensing.
105373Sraghuram  * See the License for the specific language governing permissions
115373Sraghuram  * and limitations under the License.
125373Sraghuram  *
135373Sraghuram  * When distributing Covered Code, include this CDDL HEADER in each
145373Sraghuram  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155373Sraghuram  * If applicable, add the following below this CDDL HEADER, with the
165373Sraghuram  * fields enclosed by brackets "[]" replaced with your own identifying
175373Sraghuram  * information: Portions Copyright [yyyy] [name of copyright owner]
185373Sraghuram  *
195373Sraghuram  * CDDL HEADER END
205373Sraghuram  */
215373Sraghuram 
225373Sraghuram /*
2312300SSriharsha.Basavapatna@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245373Sraghuram  */
255373Sraghuram 
265373Sraghuram #include <sys/types.h>
275373Sraghuram #include <sys/errno.h>
285373Sraghuram #include <sys/debug.h>
295373Sraghuram #include <sys/time.h>
305373Sraghuram #include <sys/sysmacros.h>
315373Sraghuram #include <sys/systm.h>
325373Sraghuram #include <sys/user.h>
335373Sraghuram #include <sys/stropts.h>
345373Sraghuram #include <sys/stream.h>
355373Sraghuram #include <sys/strlog.h>
365373Sraghuram #include <sys/strsubr.h>
375373Sraghuram #include <sys/cmn_err.h>
385373Sraghuram #include <sys/cpu.h>
395373Sraghuram #include <sys/kmem.h>
405373Sraghuram #include <sys/conf.h>
415373Sraghuram #include <sys/ddi.h>
425373Sraghuram #include <sys/sunddi.h>
435373Sraghuram #include <sys/ksynch.h>
445373Sraghuram #include <sys/stat.h>
455373Sraghuram #include <sys/kstat.h>
465373Sraghuram #include <sys/vtrace.h>
475373Sraghuram #include <sys/strsun.h>
485373Sraghuram #include <sys/dlpi.h>
495373Sraghuram #include <sys/ethernet.h>
505373Sraghuram #include <net/if.h>
515373Sraghuram #include <sys/varargs.h>
525373Sraghuram #include <sys/machsystm.h>
535373Sraghuram #include <sys/modctl.h>
545373Sraghuram #include <sys/modhash.h>
555373Sraghuram #include <sys/mac.h>
565373Sraghuram #include <sys/mac_ether.h>
575373Sraghuram #include <sys/taskq.h>
585373Sraghuram #include <sys/note.h>
595373Sraghuram #include <sys/mach_descrip.h>
605373Sraghuram #include <sys/mdeg.h>
615373Sraghuram #include <sys/ldc.h>
625373Sraghuram #include <sys/vsw_fdb.h>
635373Sraghuram #include <sys/vsw.h>
645373Sraghuram #include <sys/vio_mailbox.h>
655373Sraghuram #include <sys/vnet_mailbox.h>
665373Sraghuram #include <sys/vnet_common.h>
675373Sraghuram #include <sys/vio_util.h>
685373Sraghuram #include <sys/sdt.h>
695373Sraghuram #include <sys/atomic.h>
705373Sraghuram #include <sys/callb.h>
716419Ssb155480 #include <sys/vlan.h>
725373Sraghuram 
735373Sraghuram /* Port add/deletion/etc routines */
749217SWentao.Yang@Sun.COM static	void vsw_port_delete(vsw_port_t *port);
755373Sraghuram static	int vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id);
7612011SSriharsha.Basavapatna@Sun.COM static	void vsw_ldc_detach(vsw_ldc_t *ldcp);
775373Sraghuram static	int vsw_ldc_init(vsw_ldc_t *ldcp);
789217SWentao.Yang@Sun.COM static	void vsw_ldc_uninit(vsw_ldc_t *ldcp);
7912011SSriharsha.Basavapatna@Sun.COM static	void vsw_ldc_drain(vsw_ldc_t *ldcp);
809217SWentao.Yang@Sun.COM static	void vsw_drain_port_taskq(vsw_port_t *port);
815373Sraghuram static	void vsw_marker_task(void *);
825373Sraghuram static	int vsw_plist_del_node(vsw_t *, vsw_port_t *port);
839217SWentao.Yang@Sun.COM void vsw_detach_ports(vsw_t *vswp);
845373Sraghuram int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node);
855373Sraghuram mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr);
865373Sraghuram int vsw_port_detach(vsw_t *vswp, int p_instance);
878275SEric Cheng int vsw_portsend(vsw_port_t *port, mblk_t *mp);
886419Ssb155480 int vsw_port_attach(vsw_port_t *portp);
895373Sraghuram vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance);
906419Ssb155480 void vsw_vlan_unaware_port_reset(vsw_port_t *portp);
916724Sraghuram void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate);
927529SSriharsha.Basavapatna@Sun.COM void vsw_reset_ports(vsw_t *vswp);
937529SSriharsha.Basavapatna@Sun.COM void vsw_port_reset(vsw_port_t *portp);
949336SSriharsha.Basavapatna@Sun.COM void vsw_physlink_update_ports(vsw_t *vswp);
959336SSriharsha.Basavapatna@Sun.COM static	void vsw_port_physlink_update(vsw_port_t *portp);
965373Sraghuram 
975373Sraghuram /* Interrupt routines */
985373Sraghuram static	uint_t vsw_ldc_cb(uint64_t cb, caddr_t arg);
995373Sraghuram 
1005373Sraghuram /* Handshake routines */
1015373Sraghuram static	void vsw_ldc_reinit(vsw_ldc_t *);
1025373Sraghuram static	void vsw_conn_task(void *);
1035373Sraghuram static	int vsw_check_flag(vsw_ldc_t *, int, uint64_t);
1045373Sraghuram static	void vsw_next_milestone(vsw_ldc_t *);
1055373Sraghuram static	int vsw_supported_version(vio_ver_msg_t *);
1065935Ssb155480 static	void vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp);
1075935Ssb155480 static	void vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp);
10812011SSriharsha.Basavapatna@Sun.COM void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
1095373Sraghuram 
1105373Sraghuram /* Data processing routines */
11112011SSriharsha.Basavapatna@Sun.COM void vsw_process_pkt(void *);
11212011SSriharsha.Basavapatna@Sun.COM static void vsw_dispatch_ctrl_task(vsw_ldc_t *, void *, vio_msg_tag_t *, int);
1135373Sraghuram static void vsw_process_ctrl_pkt(void *);
1145373Sraghuram static void vsw_process_ctrl_ver_pkt(vsw_ldc_t *, void *);
1155373Sraghuram static void vsw_process_ctrl_attr_pkt(vsw_ldc_t *, void *);
1165373Sraghuram static void vsw_process_ctrl_mcst_pkt(vsw_ldc_t *, void *);
1175373Sraghuram static void vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *, void *);
1185373Sraghuram static void vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *, void *);
1195373Sraghuram static void vsw_process_ctrl_rdx_pkt(vsw_ldc_t *, void *);
1209336SSriharsha.Basavapatna@Sun.COM static void vsw_process_physlink_msg(vsw_ldc_t *, void *);
1215935Ssb155480 static void vsw_process_data_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *,
1225935Ssb155480 	uint32_t);
1235935Ssb155480 static void vsw_process_pkt_data_nop(void *, void *, uint32_t);
1245935Ssb155480 static void vsw_process_pkt_data(void *, void *, uint32_t);
1255373Sraghuram static void vsw_process_data_ibnd_pkt(vsw_ldc_t *, void *);
1265935Ssb155480 static void vsw_process_err_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *);
12712011SSriharsha.Basavapatna@Sun.COM static void vsw_process_evt_read(vsw_ldc_t *ldcp);
12812011SSriharsha.Basavapatna@Sun.COM static void vsw_ldc_rcv(vsw_ldc_t *ldcp);
1295373Sraghuram 
1305373Sraghuram /* Switching/data transmit routines */
1315373Sraghuram static	int vsw_descrsend(vsw_ldc_t *, mblk_t *);
1325935Ssb155480 static void vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp);
1335935Ssb155480 static int vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries);
1345935Ssb155480 static int vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count);
1355935Ssb155480 static int vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count);
1365373Sraghuram 
1375373Sraghuram /* Packet creation routines */
1385373Sraghuram static void vsw_send_ver(void *);
1395373Sraghuram static void vsw_send_attr(vsw_ldc_t *);
1405373Sraghuram static void vsw_send_dring_info(vsw_ldc_t *);
1415373Sraghuram static void vsw_send_rdx(vsw_ldc_t *);
1429336SSriharsha.Basavapatna@Sun.COM static void vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state);
1435373Sraghuram 
1445373Sraghuram /* Dring routines */
1455373Sraghuram static void vsw_create_privring(vsw_ldc_t *);
14612011SSriharsha.Basavapatna@Sun.COM static dring_info_t *vsw_map_dring(vsw_ldc_t *ldcp, void *pkt);
14712011SSriharsha.Basavapatna@Sun.COM static void vsw_unmap_dring(vsw_ldc_t *ldcp);
14812011SSriharsha.Basavapatna@Sun.COM static void vsw_destroy_dring(vsw_ldc_t *ldcp);
14912011SSriharsha.Basavapatna@Sun.COM static void vsw_free_lane_resources(vsw_ldc_t *, uint64_t);
15012011SSriharsha.Basavapatna@Sun.COM static int vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt);
1515373Sraghuram static void vsw_set_lane_attr(vsw_t *, lane_t *);
15212011SSriharsha.Basavapatna@Sun.COM dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp,
15312011SSriharsha.Basavapatna@Sun.COM     vio_dring_reg_msg_t *dring_pkt);
154*13098SWentao.Yang@Sun.COM static int vsw_mapin_avail(vsw_ldc_t *ldcp);
15512011SSriharsha.Basavapatna@Sun.COM 
15612011SSriharsha.Basavapatna@Sun.COM /* tx/msg/rcv thread routines */
1575373Sraghuram static void vsw_stop_tx_thread(vsw_ldc_t *ldcp);
1585373Sraghuram static void vsw_ldc_tx_worker(void *arg);
1595373Sraghuram 
1605373Sraghuram /* Misc support routines */
1615373Sraghuram static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr);
1625373Sraghuram static int vsw_get_same_dest_list(struct ether_header *ehp,
1635373Sraghuram     mblk_t **rhead, mblk_t **rtail, mblk_t **mpp);
1645373Sraghuram static mblk_t *vsw_dupmsgchain(mblk_t *mp);
1655373Sraghuram 
1665373Sraghuram /* Debugging routines */
1675373Sraghuram static void dump_flags(uint64_t);
1685373Sraghuram static void display_state(void);
1695373Sraghuram static void display_lane(lane_t *);
1705373Sraghuram static void display_ring(dring_info_t *);
1715373Sraghuram 
1725373Sraghuram /*
1735373Sraghuram  * Functions imported from other files.
1745373Sraghuram  */
1755373Sraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int);
1768275SEric Cheng extern void vsw_unset_hw(vsw_t *, vsw_port_t *, int);
1775373Sraghuram extern int vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port);
1785373Sraghuram extern void vsw_del_mcst_port(vsw_port_t *port);
1795373Sraghuram extern int vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg);
1805373Sraghuram extern int vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg);
1816419Ssb155480 extern void vsw_fdbe_add(vsw_t *vswp, void *port);
1826419Ssb155480 extern void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr);
1836419Ssb155480 extern void vsw_create_vlans(void *arg, int type);
1846419Ssb155480 extern void vsw_destroy_vlans(void *arg, int type);
1856419Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type);
1866419Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type);
1876419Ssb155480 extern boolean_t vsw_frame_lookup_vid(void *arg, int caller,
1886419Ssb155480 	struct ether_header *ehp, uint16_t *vidp);
1896419Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
1906419Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np,
1916419Ssb155480 	mblk_t **npt);
1926419Ssb155480 extern boolean_t vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
1936495Sspeer extern void vsw_hio_start(vsw_t *vswp, vsw_ldc_t *ldcp);
1946495Sspeer extern void vsw_hio_stop(vsw_t *vswp, vsw_ldc_t *ldcp);
1956495Sspeer extern void vsw_process_dds_msg(vsw_t *vswp, vsw_ldc_t *ldcp, void *msg);
1966495Sspeer extern void vsw_hio_stop_port(vsw_port_t *portp);
1978275SEric Cheng extern void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp);
1988275SEric Cheng extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type);
1998275SEric Cheng extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type);
20010041SWentao.Yang@Sun.COM extern void vsw_destroy_rxpools(void *arg);
20112011SSriharsha.Basavapatna@Sun.COM extern void vsw_stop_msg_thread(vsw_ldc_t *ldcp);
20212011SSriharsha.Basavapatna@Sun.COM extern int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t);
20312011SSriharsha.Basavapatna@Sun.COM extern int vsw_dringsend(vsw_ldc_t *, mblk_t *);
20412011SSriharsha.Basavapatna@Sun.COM extern int vsw_reclaim_dring(dring_info_t *dp, int start);
20512011SSriharsha.Basavapatna@Sun.COM extern int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **,
20612011SSriharsha.Basavapatna@Sun.COM     int *);
20712011SSriharsha.Basavapatna@Sun.COM extern vio_dring_reg_msg_t *vsw_create_tx_dring_info(vsw_ldc_t *);
20812011SSriharsha.Basavapatna@Sun.COM extern int vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp);
20912011SSriharsha.Basavapatna@Sun.COM extern void vsw_destroy_tx_dring(vsw_ldc_t *ldcp);
21012011SSriharsha.Basavapatna@Sun.COM extern dring_info_t *vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt);
21112011SSriharsha.Basavapatna@Sun.COM extern void vsw_unmap_rx_dring(vsw_ldc_t *ldcp);
21212011SSriharsha.Basavapatna@Sun.COM extern void vsw_ldc_msg_worker(void *arg);
21312011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_dringdata(void *, void *);
21412011SSriharsha.Basavapatna@Sun.COM extern vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *);
21512011SSriharsha.Basavapatna@Sun.COM extern void vsw_destroy_rx_dring(vsw_ldc_t *ldcp);
21612011SSriharsha.Basavapatna@Sun.COM extern dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt);
21712011SSriharsha.Basavapatna@Sun.COM extern void vsw_unmap_tx_dring(vsw_ldc_t *ldcp);
21812011SSriharsha.Basavapatna@Sun.COM extern void vsw_ldc_rcv_worker(void *arg);
21912011SSriharsha.Basavapatna@Sun.COM extern void vsw_stop_rcv_thread(vsw_ldc_t *ldcp);
22012011SSriharsha.Basavapatna@Sun.COM extern int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *);
22112011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_dringdata_shm(void *, void *);
2225373Sraghuram 
2235373Sraghuram /*
2245373Sraghuram  * Tunables used in this file.
2255373Sraghuram  */
2265373Sraghuram extern int vsw_num_handshakes;
2275373Sraghuram extern int vsw_ldc_tx_delay;
2285373Sraghuram extern int vsw_ldc_tx_retries;
2299217SWentao.Yang@Sun.COM extern int vsw_ldc_retries;
2309217SWentao.Yang@Sun.COM extern int vsw_ldc_delay;
2315373Sraghuram extern boolean_t vsw_ldc_rxthr_enabled;
2325373Sraghuram extern boolean_t vsw_ldc_txthr_enabled;
23312011SSriharsha.Basavapatna@Sun.COM extern uint32_t vsw_num_descriptors;
23412011SSriharsha.Basavapatna@Sun.COM extern uint8_t  vsw_dring_mode;
2355935Ssb155480 extern uint32_t vsw_max_tx_qcount;
2365935Ssb155480 extern boolean_t vsw_obp_ver_proto_workaround;
2377027Ssb155480 extern uint32_t vsw_publish_macaddr_count;
238*13098SWentao.Yang@Sun.COM extern uint32_t vsw_nrbufs_factor;
2395373Sraghuram 
2405373Sraghuram #define	LDC_ENTER_LOCK(ldcp)	\
2415373Sraghuram 				mutex_enter(&((ldcp)->ldc_cblock));\
2425373Sraghuram 				mutex_enter(&((ldcp)->ldc_rxlock));\
2435373Sraghuram 				mutex_enter(&((ldcp)->ldc_txlock));
2445373Sraghuram #define	LDC_EXIT_LOCK(ldcp)	\
2455373Sraghuram 				mutex_exit(&((ldcp)->ldc_txlock));\
2465373Sraghuram 				mutex_exit(&((ldcp)->ldc_rxlock));\
2475373Sraghuram 				mutex_exit(&((ldcp)->ldc_cblock));
2485373Sraghuram 
2495935Ssb155480 #define	VSW_VER_EQ(ldcp, major, minor)	\
2505935Ssb155480 	((ldcp)->lane_out.ver_major == (major) &&	\
2515935Ssb155480 	    (ldcp)->lane_out.ver_minor == (minor))
2525935Ssb155480 
2535935Ssb155480 #define	VSW_VER_LT(ldcp, major, minor)	\
2545935Ssb155480 	(((ldcp)->lane_out.ver_major < (major)) ||	\
2555935Ssb155480 	    ((ldcp)->lane_out.ver_major == (major) &&	\
2565935Ssb155480 	    (ldcp)->lane_out.ver_minor < (minor)))
2575373Sraghuram 
2586419Ssb155480 #define	VSW_VER_GTEQ(ldcp, major, minor)	\
2596419Ssb155480 	(((ldcp)->lane_out.ver_major > (major)) ||	\
2606419Ssb155480 	    ((ldcp)->lane_out.ver_major == (major) &&	\
2616419Ssb155480 	    (ldcp)->lane_out.ver_minor >= (minor)))
2626419Ssb155480 
26312011SSriharsha.Basavapatna@Sun.COM #define	VSW_VER_LTEQ(ldcp, major, minor)	\
26412011SSriharsha.Basavapatna@Sun.COM 	(((ldcp)->lane_out.ver_major < (major)) ||	\
26512011SSriharsha.Basavapatna@Sun.COM 	    ((ldcp)->lane_out.ver_major == (major) &&	\
26612011SSriharsha.Basavapatna@Sun.COM 	    (ldcp)->lane_out.ver_minor <= (minor)))
26712011SSriharsha.Basavapatna@Sun.COM 
2689336SSriharsha.Basavapatna@Sun.COM /*
2699336SSriharsha.Basavapatna@Sun.COM  * VIO Protocol Version Info:
2709336SSriharsha.Basavapatna@Sun.COM  *
2719336SSriharsha.Basavapatna@Sun.COM  * The version specified below represents the version of protocol currently
2729336SSriharsha.Basavapatna@Sun.COM  * supported in the driver. It means the driver can negotiate with peers with
2739336SSriharsha.Basavapatna@Sun.COM  * versions <= this version. Here is a summary of the feature(s) that are
2749336SSriharsha.Basavapatna@Sun.COM  * supported at each version of the protocol:
2759336SSriharsha.Basavapatna@Sun.COM  *
2769336SSriharsha.Basavapatna@Sun.COM  * 1.0			Basic VIO protocol.
2779336SSriharsha.Basavapatna@Sun.COM  * 1.1			vDisk protocol update (no virtual network update).
2789336SSriharsha.Basavapatna@Sun.COM  * 1.2			Support for priority frames (priority-ether-types).
2799336SSriharsha.Basavapatna@Sun.COM  * 1.3			VLAN and HybridIO support.
2809336SSriharsha.Basavapatna@Sun.COM  * 1.4			Jumbo Frame support.
2819336SSriharsha.Basavapatna@Sun.COM  * 1.5			Link State Notification support with optional support
2829336SSriharsha.Basavapatna@Sun.COM  * 			for Physical Link information.
28312011SSriharsha.Basavapatna@Sun.COM  * 1.6			Support for RxDringData mode.
2849336SSriharsha.Basavapatna@Sun.COM  */
28512011SSriharsha.Basavapatna@Sun.COM static	ver_sup_t	vsw_versions[] = { {1, 6} };
2865373Sraghuram 
2875373Sraghuram /*
2885373Sraghuram  * For the moment the state dump routines have their own
2895373Sraghuram  * private flag.
2905373Sraghuram  */
2915373Sraghuram #define	DUMP_STATE	0
2925373Sraghuram 
2935373Sraghuram #if DUMP_STATE
2945373Sraghuram 
2955373Sraghuram #define	DUMP_TAG(tag) \
2965373Sraghuram {			\
2975373Sraghuram 	D1(NULL, "DUMP_TAG: type 0x%llx", (tag).vio_msgtype); \
2985373Sraghuram 	D1(NULL, "DUMP_TAG: stype 0x%llx", (tag).vio_subtype);	\
2995373Sraghuram 	D1(NULL, "DUMP_TAG: senv 0x%llx", (tag).vio_subtype_env);	\
3005373Sraghuram }
3015373Sraghuram 
3025373Sraghuram #define	DUMP_TAG_PTR(tag) \
3035373Sraghuram {			\
3045373Sraghuram 	D1(NULL, "DUMP_TAG: type 0x%llx", (tag)->vio_msgtype); \
3055373Sraghuram 	D1(NULL, "DUMP_TAG: stype 0x%llx", (tag)->vio_subtype);	\
3065373Sraghuram 	D1(NULL, "DUMP_TAG: senv 0x%llx", (tag)->vio_subtype_env);	\
3075373Sraghuram }
3085373Sraghuram 
3095373Sraghuram #define	DUMP_FLAGS(flags) dump_flags(flags);
3105373Sraghuram #define	DISPLAY_STATE()	display_state()
3115373Sraghuram 
3125373Sraghuram #else
3135373Sraghuram 
3145373Sraghuram #define	DUMP_TAG(tag)
3155373Sraghuram #define	DUMP_TAG_PTR(tag)
3165373Sraghuram #define	DUMP_FLAGS(state)
3175373Sraghuram #define	DISPLAY_STATE()
3185373Sraghuram 
3195373Sraghuram #endif	/* DUMP_STATE */
3205373Sraghuram 
3215373Sraghuram /*
3225373Sraghuram  * Attach the specified port.
3235373Sraghuram  *
3245373Sraghuram  * Returns 0 on success, 1 on failure.
3255373Sraghuram  */
3265373Sraghuram int
vsw_port_attach(vsw_port_t * port)3276419Ssb155480 vsw_port_attach(vsw_port_t *port)
3285373Sraghuram {
3296419Ssb155480 	vsw_t			*vswp = port->p_vswp;
3305373Sraghuram 	vsw_port_list_t		*plist = &vswp->plist;
3316419Ssb155480 	vsw_port_t		*p, **pp;
3326419Ssb155480 	int			nids = port->num_ldcs;
3336419Ssb155480 	uint64_t		*ldcids;
3348275SEric Cheng 	int			rv;
3356419Ssb155480 
3366419Ssb155480 	D1(vswp, "%s: enter : port %d", __func__, port->p_instance);
3375373Sraghuram 
3385373Sraghuram 	/* port already exists? */
3395373Sraghuram 	READ_ENTER(&plist->lockrw);
3406419Ssb155480 	for (p = plist->head; p != NULL; p = p->p_next) {
3416419Ssb155480 		if (p->p_instance == port->p_instance) {
3425373Sraghuram 			DWARN(vswp, "%s: port instance %d already attached",
3436419Ssb155480 			    __func__, p->p_instance);
3445373Sraghuram 			RW_EXIT(&plist->lockrw);
3455373Sraghuram 			return (1);
3465373Sraghuram 		}
3475373Sraghuram 	}
3485373Sraghuram 	RW_EXIT(&plist->lockrw);
3495373Sraghuram 
3505373Sraghuram 	mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL);
3515373Sraghuram 	mutex_init(&port->mca_lock, NULL, MUTEX_DRIVER, NULL);
3528275SEric Cheng 	rw_init(&port->maccl_rwlock, NULL, RW_DRIVER, NULL);
3535373Sraghuram 
3545373Sraghuram 	mutex_init(&port->state_lock, NULL, MUTEX_DRIVER, NULL);
3555373Sraghuram 	cv_init(&port->state_cv, NULL, CV_DRIVER, NULL);
3565373Sraghuram 	port->state = VSW_PORT_INIT;
3575373Sraghuram 
3585373Sraghuram 	D2(vswp, "%s: %d nids", __func__, nids);
3596419Ssb155480 	ldcids = port->ldc_ids;
36012011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: ldcid (%llx)", __func__, (uint64_t)ldcids[0]);
36112011SSriharsha.Basavapatna@Sun.COM 	if (vsw_ldc_attach(port, (uint64_t)ldcids[0]) != 0) {
36212011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s: ldc_attach failed", __func__);
36312011SSriharsha.Basavapatna@Sun.COM 		goto exit_error;
3645373Sraghuram 	}
3655373Sraghuram 
3665373Sraghuram 	if (vswp->switching_setup_done == B_TRUE) {
3675373Sraghuram 		/*
3688275SEric Cheng 		 * If the underlying network device has been setup,
3698275SEric Cheng 		 * then open a mac client and porgram the mac address
3708275SEric Cheng 		 * for this port.
3715373Sraghuram 		 */
3728275SEric Cheng 		rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT);
3738275SEric Cheng 		if (rv != 0) {
3748275SEric Cheng 			goto exit_error;
3758275SEric Cheng 		}
3765373Sraghuram 	}
3775373Sraghuram 
3786419Ssb155480 	/* create the fdb entry for this port/mac address */
3796419Ssb155480 	vsw_fdbe_add(vswp, port);
3806419Ssb155480 
3816419Ssb155480 	vsw_create_vlans(port, VSW_VNETPORT);
3826419Ssb155480 
3835373Sraghuram 	WRITE_ENTER(&plist->lockrw);
3845373Sraghuram 
3855373Sraghuram 	/* link it into the list of ports for this vsw instance */
3866419Ssb155480 	pp = (vsw_port_t **)(&plist->head);
3876419Ssb155480 	port->p_next = *pp;
3886419Ssb155480 	*pp = port;
3895373Sraghuram 	plist->num_ports++;
3905373Sraghuram 
3915373Sraghuram 	RW_EXIT(&plist->lockrw);
3925373Sraghuram 
3935373Sraghuram 	/*
3945373Sraghuram 	 * Initialise the port and any ldc's under it.
3955373Sraghuram 	 */
39612011SSriharsha.Basavapatna@Sun.COM 	(void) vsw_ldc_init(port->ldcp);
3975373Sraghuram 
3987027Ssb155480 	/* announce macaddr of vnet to the physical switch */
3997027Ssb155480 	if (vsw_publish_macaddr_count != 0) {	/* enabled */
4008275SEric Cheng 		vsw_publish_macaddr(vswp, port);
4017027Ssb155480 	}
4027027Ssb155480 
4035373Sraghuram 	D1(vswp, "%s: exit", __func__);
4045373Sraghuram 	return (0);
4058275SEric Cheng 
4068275SEric Cheng exit_error:
4078275SEric Cheng 
4088275SEric Cheng 	cv_destroy(&port->state_cv);
4098275SEric Cheng 	mutex_destroy(&port->state_lock);
4108275SEric Cheng 
4118275SEric Cheng 	rw_destroy(&port->maccl_rwlock);
4128275SEric Cheng 	mutex_destroy(&port->tx_lock);
4138275SEric Cheng 	mutex_destroy(&port->mca_lock);
4148275SEric Cheng 	kmem_free(port, sizeof (vsw_port_t));
4158275SEric Cheng 	return (1);
4165373Sraghuram }
4175373Sraghuram 
4185373Sraghuram /*
4195373Sraghuram  * Detach the specified port.
4205373Sraghuram  *
4215373Sraghuram  * Returns 0 on success, 1 on failure.
4225373Sraghuram  */
4235373Sraghuram int
vsw_port_detach(vsw_t * vswp,int p_instance)4245373Sraghuram vsw_port_detach(vsw_t *vswp, int p_instance)
4255373Sraghuram {
4265373Sraghuram 	vsw_port_t	*port = NULL;
4275373Sraghuram 	vsw_port_list_t	*plist = &vswp->plist;
4285373Sraghuram 
4295373Sraghuram 	D1(vswp, "%s: enter: port id %d", __func__, p_instance);
4305373Sraghuram 
4315373Sraghuram 	WRITE_ENTER(&plist->lockrw);
4325373Sraghuram 
4335373Sraghuram 	if ((port = vsw_lookup_port(vswp, p_instance)) == NULL) {
4345373Sraghuram 		RW_EXIT(&plist->lockrw);
4355373Sraghuram 		return (1);
4365373Sraghuram 	}
4375373Sraghuram 
4385373Sraghuram 	if (vsw_plist_del_node(vswp, port)) {
4395373Sraghuram 		RW_EXIT(&plist->lockrw);
4405373Sraghuram 		return (1);
4415373Sraghuram 	}
4425373Sraghuram 
4436495Sspeer 	/* cleanup any HybridIO for this port */
4446495Sspeer 	vsw_hio_stop_port(port);
4456495Sspeer 
4465373Sraghuram 	/*
4475373Sraghuram 	 * No longer need to hold writer lock on port list now
4485373Sraghuram 	 * that we have unlinked the target port from the list.
4495373Sraghuram 	 */
4505373Sraghuram 	RW_EXIT(&plist->lockrw);
4515373Sraghuram 
4528275SEric Cheng 	/* Cleanup and close the mac client */
4538275SEric Cheng 	vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
4548275SEric Cheng 
4556419Ssb155480 	/* Remove the fdb entry for this port/mac address */
4566419Ssb155480 	vsw_fdbe_del(vswp, &(port->p_macaddr));
4576419Ssb155480 	vsw_destroy_vlans(port, VSW_VNETPORT);
4586419Ssb155480 
4596419Ssb155480 	/* Remove any multicast addresses.. */
4606419Ssb155480 	vsw_del_mcst_port(port);
4616419Ssb155480 
4629217SWentao.Yang@Sun.COM 	vsw_port_delete(port);
4635373Sraghuram 
4645373Sraghuram 	D1(vswp, "%s: exit: p_instance(%d)", __func__, p_instance);
4655373Sraghuram 	return (0);
4665373Sraghuram }
4675373Sraghuram 
4685373Sraghuram /*
4695373Sraghuram  * Detach all active ports.
4705373Sraghuram  */
4719217SWentao.Yang@Sun.COM void
vsw_detach_ports(vsw_t * vswp)4725373Sraghuram vsw_detach_ports(vsw_t *vswp)
4735373Sraghuram {
4745373Sraghuram 	vsw_port_list_t 	*plist = &vswp->plist;
4755373Sraghuram 	vsw_port_t		*port = NULL;
4765373Sraghuram 
4775373Sraghuram 	D1(vswp, "%s: enter", __func__);
4785373Sraghuram 
4795373Sraghuram 	WRITE_ENTER(&plist->lockrw);
4805373Sraghuram 
4815373Sraghuram 	while ((port = plist->head) != NULL) {
4829217SWentao.Yang@Sun.COM 		(void) vsw_plist_del_node(vswp, port);
4839217SWentao.Yang@Sun.COM 
4849217SWentao.Yang@Sun.COM 		/* cleanup any HybridIO for this port */
4859217SWentao.Yang@Sun.COM 		vsw_hio_stop_port(port);
4865373Sraghuram 
4878275SEric Cheng 		/* Cleanup and close the mac client */
4888275SEric Cheng 		vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
4895373Sraghuram 
4905373Sraghuram 		/* Remove the fdb entry for this port/mac address */
4916419Ssb155480 		vsw_fdbe_del(vswp, &(port->p_macaddr));
4926419Ssb155480 		vsw_destroy_vlans(port, VSW_VNETPORT);
4935373Sraghuram 
4945373Sraghuram 		/* Remove any multicast addresses.. */
4955373Sraghuram 		vsw_del_mcst_port(port);
4965373Sraghuram 
4975373Sraghuram 		/*
4985373Sraghuram 		 * No longer need to hold the lock on the port list
4995373Sraghuram 		 * now that we have unlinked the target port from the
5005373Sraghuram 		 * list.
5015373Sraghuram 		 */
5025373Sraghuram 		RW_EXIT(&plist->lockrw);
5039217SWentao.Yang@Sun.COM 		vsw_port_delete(port);
5045373Sraghuram 		WRITE_ENTER(&plist->lockrw);
5055373Sraghuram 	}
5065373Sraghuram 	RW_EXIT(&plist->lockrw);
5075373Sraghuram 
5085373Sraghuram 	D1(vswp, "%s: exit", __func__);
5095373Sraghuram }
5105373Sraghuram 
5115373Sraghuram /*
5125373Sraghuram  * Delete the specified port.
5135373Sraghuram  */
5149217SWentao.Yang@Sun.COM static void
vsw_port_delete(vsw_port_t * port)5155373Sraghuram vsw_port_delete(vsw_port_t *port)
5165373Sraghuram {
5175373Sraghuram 	vsw_t			*vswp = port->p_vswp;
5185373Sraghuram 
5195373Sraghuram 	D1(vswp, "%s: enter : port id %d", __func__, port->p_instance);
5205373Sraghuram 
52112011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_uninit(port->ldcp);
5225373Sraghuram 
5235373Sraghuram 	/*
5245373Sraghuram 	 * Wait for any pending ctrl msg tasks which reference this
5255373Sraghuram 	 * port to finish.
5265373Sraghuram 	 */
5279217SWentao.Yang@Sun.COM 	vsw_drain_port_taskq(port);
5285373Sraghuram 
5295373Sraghuram 	/*
5305373Sraghuram 	 * Wait for any active callbacks to finish
5315373Sraghuram 	 */
53212011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_drain(port->ldcp);
53312011SSriharsha.Basavapatna@Sun.COM 
53412011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_detach(port->ldcp);
5355373Sraghuram 
5368275SEric Cheng 	rw_destroy(&port->maccl_rwlock);
5375373Sraghuram 	mutex_destroy(&port->mca_lock);
5385373Sraghuram 	mutex_destroy(&port->tx_lock);
5396419Ssb155480 
5405373Sraghuram 	cv_destroy(&port->state_cv);
5415373Sraghuram 	mutex_destroy(&port->state_lock);
5425373Sraghuram 
5436419Ssb155480 	if (port->num_ldcs != 0) {
5446419Ssb155480 		kmem_free(port->ldc_ids, port->num_ldcs * sizeof (uint64_t));
5456419Ssb155480 		port->num_ldcs = 0;
5466419Ssb155480 	}
5478275SEric Cheng 
5488275SEric Cheng 	if (port->nvids != 0) {
5498275SEric Cheng 		kmem_free(port->vids, sizeof (vsw_vlanid_t) * port->nvids);
5508275SEric Cheng 	}
5518275SEric Cheng 
5525373Sraghuram 	kmem_free(port, sizeof (vsw_port_t));
5535373Sraghuram 
5545373Sraghuram 	D1(vswp, "%s: exit", __func__);
5555373Sraghuram }
5565373Sraghuram 
5575373Sraghuram /*
5585373Sraghuram  * Attach a logical domain channel (ldc) under a specified port.
5595373Sraghuram  *
5605373Sraghuram  * Returns 0 on success, 1 on failure.
5615373Sraghuram  */
5625373Sraghuram static int
vsw_ldc_attach(vsw_port_t * port,uint64_t ldc_id)5635373Sraghuram vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id)
5645373Sraghuram {
5655373Sraghuram 	vsw_t 		*vswp = port->p_vswp;
5665373Sraghuram 	vsw_ldc_t 	*ldcp = NULL;
5675373Sraghuram 	ldc_attr_t 	attr;
5685373Sraghuram 	ldc_status_t	istatus;
5695373Sraghuram 	int 		status = DDI_FAILURE;
5705373Sraghuram 	char		kname[MAXNAMELEN];
5717529SSriharsha.Basavapatna@Sun.COM 	enum		{ PROG_init = 0x0,
57212011SSriharsha.Basavapatna@Sun.COM 			    PROG_callback = 0x1,
57312011SSriharsha.Basavapatna@Sun.COM 			    PROG_tx_thread = 0x2}
5745373Sraghuram 			progress;
5755373Sraghuram 
5765373Sraghuram 	progress = PROG_init;
5775373Sraghuram 
5785373Sraghuram 	D1(vswp, "%s: enter", __func__);
5795373Sraghuram 
5805373Sraghuram 	ldcp = kmem_zalloc(sizeof (vsw_ldc_t), KM_NOSLEEP);
5815373Sraghuram 	if (ldcp == NULL) {
5825373Sraghuram 		DERR(vswp, "%s: kmem_zalloc failed", __func__);
5835373Sraghuram 		return (1);
5845373Sraghuram 	}
5855373Sraghuram 	ldcp->ldc_id = ldc_id;
5865373Sraghuram 
5875373Sraghuram 	mutex_init(&ldcp->ldc_txlock, NULL, MUTEX_DRIVER, NULL);
5885373Sraghuram 	mutex_init(&ldcp->ldc_rxlock, NULL, MUTEX_DRIVER, NULL);
5895373Sraghuram 	mutex_init(&ldcp->ldc_cblock, NULL, MUTEX_DRIVER, NULL);
59012011SSriharsha.Basavapatna@Sun.COM 	ldcp->msg_thr_flags = 0;
59112011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL);
59212011SSriharsha.Basavapatna@Sun.COM 	cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL);
59312011SSriharsha.Basavapatna@Sun.COM 	ldcp->rcv_thr_flags = 0;
59412011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL);
59512011SSriharsha.Basavapatna@Sun.COM 	cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL);
5965373Sraghuram 	mutex_init(&ldcp->drain_cv_lock, NULL, MUTEX_DRIVER, NULL);
5975373Sraghuram 	cv_init(&ldcp->drain_cv, NULL, CV_DRIVER, NULL);
5985373Sraghuram 
5995373Sraghuram 	/* required for handshake with peer */
6005373Sraghuram 	ldcp->local_session = (uint64_t)ddi_get_lbolt();
6015373Sraghuram 	ldcp->peer_session = 0;
6025373Sraghuram 	ldcp->session_status = 0;
6035373Sraghuram 	ldcp->hss_id = 1;	/* Initial handshake session id */
60412011SSriharsha.Basavapatna@Sun.COM 	ldcp->hphase = VSW_MILESTONE0;
6055373Sraghuram 
6066495Sspeer 	(void) atomic_swap_32(&port->p_hio_capable, B_FALSE);
6076495Sspeer 
6085373Sraghuram 	/* only set for outbound lane, inbound set by peer */
6095373Sraghuram 	vsw_set_lane_attr(vswp, &ldcp->lane_out);
6105373Sraghuram 
6115373Sraghuram 	attr.devclass = LDC_DEV_NT_SVC;
6125373Sraghuram 	attr.instance = ddi_get_instance(vswp->dip);
6135373Sraghuram 	attr.mode = LDC_MODE_UNRELIABLE;
6145373Sraghuram 	attr.mtu = VSW_LDC_MTU;
6155373Sraghuram 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
6165373Sraghuram 	if (status != 0) {
6175373Sraghuram 		DERR(vswp, "%s(%lld): ldc_init failed, rv (%d)",
6185373Sraghuram 		    __func__, ldc_id, status);
6195373Sraghuram 		goto ldc_attach_fail;
6205373Sraghuram 	}
6215373Sraghuram 
6225373Sraghuram 	if (vsw_ldc_txthr_enabled) {
6235373Sraghuram 		ldcp->tx_thr_flags = 0;
6245373Sraghuram 		ldcp->tx_mhead = ldcp->tx_mtail = NULL;
6255373Sraghuram 
6265373Sraghuram 		mutex_init(&ldcp->tx_thr_lock, NULL, MUTEX_DRIVER, NULL);
6275373Sraghuram 		cv_init(&ldcp->tx_thr_cv, NULL, CV_DRIVER, NULL);
6285373Sraghuram 		ldcp->tx_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
6295373Sraghuram 		    vsw_ldc_tx_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
6305373Sraghuram 
6315373Sraghuram 		progress |= PROG_tx_thread;
6325373Sraghuram 		if (ldcp->tx_thread == NULL) {
6335373Sraghuram 			DWARN(vswp, "%s(%lld): Failed to create worker thread",
6345373Sraghuram 			    __func__, ldc_id);
6355373Sraghuram 			goto ldc_attach_fail;
6365373Sraghuram 		}
6375373Sraghuram 	}
6385373Sraghuram 
6395373Sraghuram 	status = ldc_reg_callback(ldcp->ldc_handle, vsw_ldc_cb, (caddr_t)ldcp);
6405373Sraghuram 	if (status != 0) {
6415373Sraghuram 		DERR(vswp, "%s(%lld): ldc_reg_callback failed, rv (%d)",
6425373Sraghuram 		    __func__, ldc_id, status);
6435373Sraghuram 		(void) ldc_fini(ldcp->ldc_handle);
6445373Sraghuram 		goto ldc_attach_fail;
6455373Sraghuram 	}
6465935Ssb155480 	/*
6475935Ssb155480 	 * allocate a message for ldc_read()s, big enough to hold ctrl and
6485935Ssb155480 	 * data msgs, including raw data msgs used to recv priority frames.
6495935Ssb155480 	 */
6506419Ssb155480 	ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vswp->max_frame_size;
6515935Ssb155480 	ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
6525373Sraghuram 
6535373Sraghuram 	progress |= PROG_callback;
6545373Sraghuram 
6555373Sraghuram 	mutex_init(&ldcp->status_lock, NULL, MUTEX_DRIVER, NULL);
6565373Sraghuram 
6575373Sraghuram 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
6585373Sraghuram 		DERR(vswp, "%s: ldc_status failed", __func__);
6595373Sraghuram 		mutex_destroy(&ldcp->status_lock);
6605373Sraghuram 		goto ldc_attach_fail;
6615373Sraghuram 	}
6625373Sraghuram 
6635373Sraghuram 	ldcp->ldc_status = istatus;
6645373Sraghuram 	ldcp->ldc_port = port;
6655373Sraghuram 	ldcp->ldc_vswp = vswp;
6665373Sraghuram 
6675935Ssb155480 	vsw_reset_vnet_proto_ops(ldcp);
6685935Ssb155480 
6695373Sraghuram 	(void) sprintf(kname, "%sldc0x%lx", DRV_NAME, ldcp->ldc_id);
6705373Sraghuram 	ldcp->ksp = vgen_setup_kstats(DRV_NAME, vswp->instance,
6715373Sraghuram 	    kname, &ldcp->ldc_stats);
6725373Sraghuram 	if (ldcp->ksp == NULL) {
6735373Sraghuram 		DERR(vswp, "%s: kstats setup failed", __func__);
6745373Sraghuram 		goto ldc_attach_fail;
6755373Sraghuram 	}
6765373Sraghuram 
67712011SSriharsha.Basavapatna@Sun.COM 	/* link it into this port */
67812011SSriharsha.Basavapatna@Sun.COM 	port->ldcp = ldcp;
6795373Sraghuram 
6805373Sraghuram 	D1(vswp, "%s: exit", __func__);
6815373Sraghuram 	return (0);
6825373Sraghuram 
6835373Sraghuram ldc_attach_fail:
6845373Sraghuram 
6855373Sraghuram 	if (progress & PROG_callback) {
6865373Sraghuram 		(void) ldc_unreg_callback(ldcp->ldc_handle);
6875935Ssb155480 		kmem_free(ldcp->ldcmsg, ldcp->msglen);
6885373Sraghuram 	}
6895373Sraghuram 
6905373Sraghuram 	if (progress & PROG_tx_thread) {
6915373Sraghuram 		if (ldcp->tx_thread != NULL) {
6925373Sraghuram 			vsw_stop_tx_thread(ldcp);
6935373Sraghuram 		}
6945373Sraghuram 		mutex_destroy(&ldcp->tx_thr_lock);
6955373Sraghuram 		cv_destroy(&ldcp->tx_thr_cv);
6965373Sraghuram 	}
6975373Sraghuram 	if (ldcp->ksp != NULL) {
6985373Sraghuram 		vgen_destroy_kstats(ldcp->ksp);
6995373Sraghuram 	}
70012011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&ldcp->msg_thr_lock);
70112011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&ldcp->rcv_thr_lock);
7025373Sraghuram 	mutex_destroy(&ldcp->ldc_txlock);
7035373Sraghuram 	mutex_destroy(&ldcp->ldc_rxlock);
7045373Sraghuram 	mutex_destroy(&ldcp->ldc_cblock);
7055373Sraghuram 	mutex_destroy(&ldcp->drain_cv_lock);
70612011SSriharsha.Basavapatna@Sun.COM 	cv_destroy(&ldcp->msg_thr_cv);
70712011SSriharsha.Basavapatna@Sun.COM 	cv_destroy(&ldcp->rcv_thr_cv);
7085373Sraghuram 	cv_destroy(&ldcp->drain_cv);
7095373Sraghuram 
7105373Sraghuram 	kmem_free(ldcp, sizeof (vsw_ldc_t));
7115373Sraghuram 
7125373Sraghuram 	return (1);
7135373Sraghuram }
7145373Sraghuram 
7155373Sraghuram /*
7165373Sraghuram  * Detach a logical domain channel (ldc) belonging to a
7175373Sraghuram  * particular port.
7185373Sraghuram  */
7199217SWentao.Yang@Sun.COM static void
vsw_ldc_detach(vsw_ldc_t * ldcp)72012011SSriharsha.Basavapatna@Sun.COM vsw_ldc_detach(vsw_ldc_t *ldcp)
7215373Sraghuram {
7225373Sraghuram 	int 		rv;
72312011SSriharsha.Basavapatna@Sun.COM 	vsw_t 		*vswp = ldcp->ldc_port->p_vswp;
7249217SWentao.Yang@Sun.COM 	int		retries = 0;
7255373Sraghuram 
7265373Sraghuram 	D2(vswp, "%s: detaching channel %lld", __func__, ldcp->ldc_id);
7275373Sraghuram 
72812011SSriharsha.Basavapatna@Sun.COM 	/* Stop msg/rcv thread */
72912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rcv_thread != NULL) {
73012011SSriharsha.Basavapatna@Sun.COM 		vsw_stop_rcv_thread(ldcp);
73112011SSriharsha.Basavapatna@Sun.COM 	} else if (ldcp->msg_thread != NULL) {
73212011SSriharsha.Basavapatna@Sun.COM 		vsw_stop_msg_thread(ldcp);
7335373Sraghuram 	}
7345935Ssb155480 	kmem_free(ldcp->ldcmsg, ldcp->msglen);
7355373Sraghuram 
7365373Sraghuram 	/* Stop the tx thread */
7375373Sraghuram 	if (ldcp->tx_thread != NULL) {
7385373Sraghuram 		vsw_stop_tx_thread(ldcp);
7395373Sraghuram 		mutex_destroy(&ldcp->tx_thr_lock);
7405373Sraghuram 		cv_destroy(&ldcp->tx_thr_cv);
7415373Sraghuram 		if (ldcp->tx_mhead != NULL) {
7425373Sraghuram 			freemsgchain(ldcp->tx_mhead);
7435373Sraghuram 			ldcp->tx_mhead = ldcp->tx_mtail = NULL;
7445935Ssb155480 			ldcp->tx_cnt = 0;
7455373Sraghuram 		}
7465373Sraghuram 	}
7475373Sraghuram 
7485373Sraghuram 	/* Destory kstats */
7495373Sraghuram 	vgen_destroy_kstats(ldcp->ksp);
7505373Sraghuram 
7515373Sraghuram 	/*
7525373Sraghuram 	 * Before we can close the channel we must release any mapped
7535373Sraghuram 	 * resources (e.g. drings).
7545373Sraghuram 	 */
7555373Sraghuram 	vsw_free_lane_resources(ldcp, INBOUND);
7565373Sraghuram 	vsw_free_lane_resources(ldcp, OUTBOUND);
7575373Sraghuram 
7585373Sraghuram 	/*
7599217SWentao.Yang@Sun.COM 	 * Close the channel, retry on EAAGIN.
7605373Sraghuram 	 */
7619217SWentao.Yang@Sun.COM 	while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) {
7629217SWentao.Yang@Sun.COM 		if (++retries > vsw_ldc_retries) {
7639217SWentao.Yang@Sun.COM 			break;
7649217SWentao.Yang@Sun.COM 		}
7659217SWentao.Yang@Sun.COM 		drv_usecwait(vsw_ldc_delay);
7669217SWentao.Yang@Sun.COM 	}
7679217SWentao.Yang@Sun.COM 	if (rv != 0) {
7689217SWentao.Yang@Sun.COM 		cmn_err(CE_NOTE,
7699217SWentao.Yang@Sun.COM 		    "!vsw%d: Error(%d) closing the channel(0x%lx)\n",
7709217SWentao.Yang@Sun.COM 		    vswp->instance, rv, ldcp->ldc_id);
7715373Sraghuram 	}
7725373Sraghuram 
7735373Sraghuram 	(void) ldc_fini(ldcp->ldc_handle);
7745373Sraghuram 
7755373Sraghuram 	ldcp->ldc_status = LDC_INIT;
7765373Sraghuram 	ldcp->ldc_handle = NULL;
7775373Sraghuram 	ldcp->ldc_vswp = NULL;
7785373Sraghuram 
77912011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&ldcp->msg_thr_lock);
78012011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&ldcp->rcv_thr_lock);
7815373Sraghuram 	mutex_destroy(&ldcp->ldc_txlock);
7825373Sraghuram 	mutex_destroy(&ldcp->ldc_rxlock);
7835373Sraghuram 	mutex_destroy(&ldcp->ldc_cblock);
7845373Sraghuram 	mutex_destroy(&ldcp->drain_cv_lock);
7855373Sraghuram 	mutex_destroy(&ldcp->status_lock);
78612011SSriharsha.Basavapatna@Sun.COM 	cv_destroy(&ldcp->msg_thr_cv);
78712011SSriharsha.Basavapatna@Sun.COM 	cv_destroy(&ldcp->rcv_thr_cv);
78812011SSriharsha.Basavapatna@Sun.COM 	cv_destroy(&ldcp->drain_cv);
7895373Sraghuram 
7905373Sraghuram 	kmem_free(ldcp, sizeof (vsw_ldc_t));
7915373Sraghuram }
7925373Sraghuram 
7935373Sraghuram /*
7945373Sraghuram  * Open and attempt to bring up the channel. Note that channel
7955373Sraghuram  * can only be brought up if peer has also opened channel.
7965373Sraghuram  *
7975373Sraghuram  * Returns 0 if can open and bring up channel, otherwise
7985373Sraghuram  * returns 1.
7995373Sraghuram  */
8005373Sraghuram static int
vsw_ldc_init(vsw_ldc_t * ldcp)8015373Sraghuram vsw_ldc_init(vsw_ldc_t *ldcp)
8025373Sraghuram {
8035373Sraghuram 	vsw_t 		*vswp = ldcp->ldc_vswp;
8045373Sraghuram 	ldc_status_t	istatus = 0;
8055373Sraghuram 	int		rv;
8065373Sraghuram 
8075373Sraghuram 	D1(vswp, "%s: enter", __func__);
8085373Sraghuram 
8095373Sraghuram 	LDC_ENTER_LOCK(ldcp);
8105373Sraghuram 
8115373Sraghuram 	/* don't start at 0 in case clients don't like that */
8125373Sraghuram 	ldcp->next_ident = 1;
8135373Sraghuram 
8145373Sraghuram 	rv = ldc_open(ldcp->ldc_handle);
8155373Sraghuram 	if (rv != 0) {
8165373Sraghuram 		DERR(vswp, "%s: ldc_open failed: id(%lld) rv(%d)",
8175373Sraghuram 		    __func__, ldcp->ldc_id, rv);
8185373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8195373Sraghuram 		return (1);
8205373Sraghuram 	}
8215373Sraghuram 
8225373Sraghuram 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
8235373Sraghuram 		DERR(vswp, "%s: unable to get status", __func__);
8245373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8255373Sraghuram 		return (1);
8265373Sraghuram 
8275373Sraghuram 	} else if (istatus != LDC_OPEN && istatus != LDC_READY) {
8285373Sraghuram 		DERR(vswp, "%s: id (%lld) status(%d) is not OPEN/READY",
8295373Sraghuram 		    __func__, ldcp->ldc_id, istatus);
8305373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8315373Sraghuram 		return (1);
8325373Sraghuram 	}
8335373Sraghuram 
8345373Sraghuram 	mutex_enter(&ldcp->status_lock);
8355373Sraghuram 	ldcp->ldc_status = istatus;
8365373Sraghuram 	mutex_exit(&ldcp->status_lock);
8375373Sraghuram 
8385373Sraghuram 	rv = ldc_up(ldcp->ldc_handle);
8395373Sraghuram 	if (rv != 0) {
8405373Sraghuram 		/*
8415373Sraghuram 		 * Not a fatal error for ldc_up() to fail, as peer
8425373Sraghuram 		 * end point may simply not be ready yet.
8435373Sraghuram 		 */
8445373Sraghuram 		D2(vswp, "%s: ldc_up err id(%lld) rv(%d)", __func__,
8455373Sraghuram 		    ldcp->ldc_id, rv);
8465373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8475373Sraghuram 		return (1);
8485373Sraghuram 	}
8495373Sraghuram 
8505373Sraghuram 	/*
8515373Sraghuram 	 * ldc_up() call is non-blocking so need to explicitly
8525373Sraghuram 	 * check channel status to see if in fact the channel
8535373Sraghuram 	 * is UP.
8545373Sraghuram 	 */
8555373Sraghuram 	mutex_enter(&ldcp->status_lock);
8565373Sraghuram 	if (ldc_status(ldcp->ldc_handle, &ldcp->ldc_status) != 0) {
8575373Sraghuram 		DERR(vswp, "%s: unable to get status", __func__);
8585373Sraghuram 		mutex_exit(&ldcp->status_lock);
8595373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8605373Sraghuram 		return (1);
8615373Sraghuram 
8625373Sraghuram 	}
8635373Sraghuram 
8645373Sraghuram 	if (ldcp->ldc_status == LDC_UP) {
8655373Sraghuram 		D2(vswp, "%s: channel %ld now UP (%ld)", __func__,
8665373Sraghuram 		    ldcp->ldc_id, istatus);
8675373Sraghuram 		mutex_exit(&ldcp->status_lock);
8685373Sraghuram 		LDC_EXIT_LOCK(ldcp);
8695373Sraghuram 
8705373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_UP);
8715373Sraghuram 		return (0);
8725373Sraghuram 	}
8735373Sraghuram 
8745373Sraghuram 	mutex_exit(&ldcp->status_lock);
8755373Sraghuram 	LDC_EXIT_LOCK(ldcp);
8765373Sraghuram 
8775373Sraghuram 	D1(vswp, "%s: exit", __func__);
8785373Sraghuram 	return (0);
8795373Sraghuram }
8805373Sraghuram 
8815373Sraghuram /* disable callbacks on the channel */
8829217SWentao.Yang@Sun.COM static void
vsw_ldc_uninit(vsw_ldc_t * ldcp)8835373Sraghuram vsw_ldc_uninit(vsw_ldc_t *ldcp)
8845373Sraghuram {
8855373Sraghuram 	vsw_t	*vswp = ldcp->ldc_vswp;
8865373Sraghuram 	int	rv;
8875373Sraghuram 
8885373Sraghuram 	D1(vswp, "vsw_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id);
8895373Sraghuram 
8905373Sraghuram 	LDC_ENTER_LOCK(ldcp);
8915373Sraghuram 
8925373Sraghuram 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
8935373Sraghuram 	if (rv != 0) {
8949217SWentao.Yang@Sun.COM 		cmn_err(CE_NOTE, "!vsw_ldc_uninit(%ld): error disabling "
8955373Sraghuram 		    "interrupts (rv = %d)\n", ldcp->ldc_id, rv);
8965373Sraghuram 	}
8975373Sraghuram 
8985373Sraghuram 	mutex_enter(&ldcp->status_lock);
8995373Sraghuram 	ldcp->ldc_status = LDC_INIT;
9005373Sraghuram 	mutex_exit(&ldcp->status_lock);
9015373Sraghuram 
9025373Sraghuram 	LDC_EXIT_LOCK(ldcp);
9035373Sraghuram 
9045373Sraghuram 	D1(vswp, "vsw_ldc_uninit: exit: id(%lx)", ldcp->ldc_id);
9055373Sraghuram }
9065373Sraghuram 
9075373Sraghuram /*
9085373Sraghuram  * Wait until the callback(s) associated with the ldcs under the specified
9095373Sraghuram  * port have completed.
9105373Sraghuram  *
9115373Sraghuram  * Prior to this function being invoked each channel under this port
9125373Sraghuram  * should have been quiesced via ldc_set_cb_mode(DISABLE).
9135373Sraghuram  *
9145373Sraghuram  * A short explaination of what we are doing below..
9155373Sraghuram  *
9165373Sraghuram  * The simplest approach would be to have a reference counter in
9175373Sraghuram  * the ldc structure which is increment/decremented by the callbacks as
9185373Sraghuram  * they use the channel. The drain function could then simply disable any
9195373Sraghuram  * further callbacks and do a cv_wait for the ref to hit zero. Unfortunately
9205373Sraghuram  * there is a tiny window here - before the callback is able to get the lock
9215373Sraghuram  * on the channel it is interrupted and this function gets to execute. It
9225373Sraghuram  * sees that the ref count is zero and believes its free to delete the
9235373Sraghuram  * associated data structures.
9245373Sraghuram  *
9255373Sraghuram  * We get around this by taking advantage of the fact that before the ldc
9265373Sraghuram  * framework invokes a callback it sets a flag to indicate that there is a
9275373Sraghuram  * callback active (or about to become active). If when we attempt to
9285373Sraghuram  * unregister a callback when this active flag is set then the unregister
9295373Sraghuram  * will fail with EWOULDBLOCK.
9305373Sraghuram  *
9315373Sraghuram  * If the unregister fails we do a cv_timedwait. We will either be signaled
9325373Sraghuram  * by the callback as it is exiting (note we have to wait a short period to
9335373Sraghuram  * allow the callback to return fully to the ldc framework and it to clear
9345373Sraghuram  * the active flag), or by the timer expiring. In either case we again attempt
9355373Sraghuram  * the unregister. We repeat this until we can succesfully unregister the
9365373Sraghuram  * callback.
9375373Sraghuram  *
9385373Sraghuram  * The reason we use a cv_timedwait rather than a simple cv_wait is to catch
9395373Sraghuram  * the case where the callback has finished but the ldc framework has not yet
9405373Sraghuram  * cleared the active flag. In this case we would never get a cv_signal.
9415373Sraghuram  */
9429217SWentao.Yang@Sun.COM static void
vsw_ldc_drain(vsw_ldc_t * ldcp)94312011SSriharsha.Basavapatna@Sun.COM vsw_ldc_drain(vsw_ldc_t *ldcp)
9445373Sraghuram {
94512011SSriharsha.Basavapatna@Sun.COM 	vsw_t	*vswp = ldcp->ldc_port->p_vswp;
9465373Sraghuram 
9475373Sraghuram 	D1(vswp, "%s: enter", __func__);
9485373Sraghuram 
94912011SSriharsha.Basavapatna@Sun.COM 	/*
95012011SSriharsha.Basavapatna@Sun.COM 	 * If we can unregister the channel callback then we
95112011SSriharsha.Basavapatna@Sun.COM 	 * know that there is no callback either running or
95212011SSriharsha.Basavapatna@Sun.COM 	 * scheduled to run for this channel so move on to next
95312011SSriharsha.Basavapatna@Sun.COM 	 * channel in the list.
95412011SSriharsha.Basavapatna@Sun.COM 	 */
95512011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->drain_cv_lock);
95612011SSriharsha.Basavapatna@Sun.COM 
95712011SSriharsha.Basavapatna@Sun.COM 	/* prompt active callbacks to quit */
95812011SSriharsha.Basavapatna@Sun.COM 	ldcp->drain_state = VSW_LDC_DRAINING;
95912011SSriharsha.Basavapatna@Sun.COM 
96012011SSriharsha.Basavapatna@Sun.COM 	if ((ldc_unreg_callback(ldcp->ldc_handle)) == 0) {
96112011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: unreg callback for chan %ld", __func__,
96212011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_id);
96312011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->drain_cv_lock);
96412011SSriharsha.Basavapatna@Sun.COM 	} else {
9655373Sraghuram 		/*
96612011SSriharsha.Basavapatna@Sun.COM 		 * If we end up here we know that either 1) a callback
96712011SSriharsha.Basavapatna@Sun.COM 		 * is currently executing, 2) is about to start (i.e.
96812011SSriharsha.Basavapatna@Sun.COM 		 * the ldc framework has set the active flag but
96912011SSriharsha.Basavapatna@Sun.COM 		 * has not actually invoked the callback yet, or 3)
97012011SSriharsha.Basavapatna@Sun.COM 		 * has finished and has returned to the ldc framework
97112011SSriharsha.Basavapatna@Sun.COM 		 * but the ldc framework has not yet cleared the
97212011SSriharsha.Basavapatna@Sun.COM 		 * active bit.
97312011SSriharsha.Basavapatna@Sun.COM 		 *
97412011SSriharsha.Basavapatna@Sun.COM 		 * Wait for it to finish.
9755373Sraghuram 		 */
97612011SSriharsha.Basavapatna@Sun.COM 		while (ldc_unreg_callback(ldcp->ldc_handle) == EWOULDBLOCK) {
97712011SSriharsha.Basavapatna@Sun.COM 			(void) cv_timedwait(&ldcp->drain_cv,
97812011SSriharsha.Basavapatna@Sun.COM 			    &ldcp->drain_cv_lock, ddi_get_lbolt() + hz);
9795373Sraghuram 		}
98012011SSriharsha.Basavapatna@Sun.COM 
98112011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->drain_cv_lock);
98212011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: unreg callback for chan %ld after "
98312011SSriharsha.Basavapatna@Sun.COM 		    "timeout", __func__, ldcp->ldc_id);
9845373Sraghuram 	}
9855373Sraghuram 
9865373Sraghuram 	D1(vswp, "%s: exit", __func__);
9875373Sraghuram }
9885373Sraghuram 
9895373Sraghuram /*
9905373Sraghuram  * Wait until all tasks which reference this port have completed.
9915373Sraghuram  *
9925373Sraghuram  * Prior to this function being invoked each channel under this port
9935373Sraghuram  * should have been quiesced via ldc_set_cb_mode(DISABLE).
9945373Sraghuram  */
9959217SWentao.Yang@Sun.COM static void
vsw_drain_port_taskq(vsw_port_t * port)9965373Sraghuram vsw_drain_port_taskq(vsw_port_t *port)
9975373Sraghuram {
9985373Sraghuram 	vsw_t		*vswp = port->p_vswp;
9995373Sraghuram 
10005373Sraghuram 	D1(vswp, "%s: enter", __func__);
10015373Sraghuram 
10025373Sraghuram 	/*
10035373Sraghuram 	 * Mark the port as in the process of being detached, and
10045373Sraghuram 	 * dispatch a marker task to the queue so we know when all
10055373Sraghuram 	 * relevant tasks have completed.
10065373Sraghuram 	 */
10075373Sraghuram 	mutex_enter(&port->state_lock);
10085373Sraghuram 	port->state = VSW_PORT_DETACHING;
10095373Sraghuram 
10105373Sraghuram 	if ((vswp->taskq_p == NULL) ||
10115373Sraghuram 	    (ddi_taskq_dispatch(vswp->taskq_p, vsw_marker_task,
10125373Sraghuram 	    port, DDI_NOSLEEP) != DDI_SUCCESS)) {
10139217SWentao.Yang@Sun.COM 		cmn_err(CE_NOTE, "!vsw%d: unable to dispatch marker task",
10149217SWentao.Yang@Sun.COM 		    vswp->instance);
10155373Sraghuram 		mutex_exit(&port->state_lock);
10169217SWentao.Yang@Sun.COM 		return;
10175373Sraghuram 	}
10185373Sraghuram 
10195373Sraghuram 	/*
10205373Sraghuram 	 * Wait for the marker task to finish.
10215373Sraghuram 	 */
10225373Sraghuram 	while (port->state != VSW_PORT_DETACHABLE)
10235373Sraghuram 		cv_wait(&port->state_cv, &port->state_lock);
10245373Sraghuram 
10255373Sraghuram 	mutex_exit(&port->state_lock);
10265373Sraghuram 
10275373Sraghuram 	D1(vswp, "%s: exit", __func__);
10285373Sraghuram }
10295373Sraghuram 
10305373Sraghuram static void
vsw_marker_task(void * arg)10315373Sraghuram vsw_marker_task(void *arg)
10325373Sraghuram {
10335373Sraghuram 	vsw_port_t	*port = arg;
10345373Sraghuram 	vsw_t		*vswp = port->p_vswp;
10355373Sraghuram 
10365373Sraghuram 	D1(vswp, "%s: enter", __func__);
10375373Sraghuram 
10385373Sraghuram 	mutex_enter(&port->state_lock);
10395373Sraghuram 
10405373Sraghuram 	/*
10415373Sraghuram 	 * No further tasks should be dispatched which reference
10425373Sraghuram 	 * this port so ok to mark it as safe to detach.
10435373Sraghuram 	 */
10445373Sraghuram 	port->state = VSW_PORT_DETACHABLE;
10455373Sraghuram 
10465373Sraghuram 	cv_signal(&port->state_cv);
10475373Sraghuram 
10485373Sraghuram 	mutex_exit(&port->state_lock);
10495373Sraghuram 
10505373Sraghuram 	D1(vswp, "%s: exit", __func__);
10515373Sraghuram }
10525373Sraghuram 
10535373Sraghuram vsw_port_t *
vsw_lookup_port(vsw_t * vswp,int p_instance)10545373Sraghuram vsw_lookup_port(vsw_t *vswp, int p_instance)
10555373Sraghuram {
10565373Sraghuram 	vsw_port_list_t *plist = &vswp->plist;
10575373Sraghuram 	vsw_port_t	*port;
10585373Sraghuram 
10595373Sraghuram 	for (port = plist->head; port != NULL; port = port->p_next) {
10605373Sraghuram 		if (port->p_instance == p_instance) {
10615373Sraghuram 			D2(vswp, "vsw_lookup_port: found p_instance\n");
10625373Sraghuram 			return (port);
10635373Sraghuram 		}
10645373Sraghuram 	}
10655373Sraghuram 
10665373Sraghuram 	return (NULL);
10675373Sraghuram }
10685373Sraghuram 
10696419Ssb155480 void
vsw_vlan_unaware_port_reset(vsw_port_t * portp)10706419Ssb155480 vsw_vlan_unaware_port_reset(vsw_port_t *portp)
10716419Ssb155480 {
107212011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t	*ldcp = portp->ldcp;
10736419Ssb155480 
10746419Ssb155480 	mutex_enter(&ldcp->ldc_cblock);
10756419Ssb155480 
10766419Ssb155480 	/*
10776419Ssb155480 	 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
10786419Ssb155480 	 * the connection. See comments in vsw_set_vnet_proto_ops().
10796419Ssb155480 	 */
10806419Ssb155480 	if (ldcp->hphase == VSW_MILESTONE4 && VSW_VER_LT(ldcp, 1, 3) &&
10816419Ssb155480 	    portp->nvids != 0) {
10826419Ssb155480 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
10836419Ssb155480 	}
10846419Ssb155480 
10856419Ssb155480 	mutex_exit(&ldcp->ldc_cblock);
10866419Ssb155480 }
10876419Ssb155480 
10886495Sspeer void
vsw_hio_port_reset(vsw_port_t * portp,boolean_t immediate)10896724Sraghuram vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate)
10906495Sspeer {
109112011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t	*ldcp = portp->ldcp;
10926495Sspeer 
10936495Sspeer 	mutex_enter(&ldcp->ldc_cblock);
10946495Sspeer 
10956495Sspeer 	/*
10966495Sspeer 	 * If the peer is HybridIO capable (ver >= 1.3), reset channel
10976495Sspeer 	 * to trigger re-negotiation, which inturn trigger HybridIO
10986495Sspeer 	 * setup/cleanup.
10996495Sspeer 	 */
11006495Sspeer 	if ((ldcp->hphase == VSW_MILESTONE4) &&
11016495Sspeer 	    (portp->p_hio_capable == B_TRUE)) {
11026724Sraghuram 		if (immediate == B_TRUE) {
11036724Sraghuram 			(void) ldc_down(ldcp->ldc_handle);
11046724Sraghuram 		} else {
11056724Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
11066724Sraghuram 		}
11076495Sspeer 	}
11086495Sspeer 
11096495Sspeer 	mutex_exit(&ldcp->ldc_cblock);
11106495Sspeer }
11116495Sspeer 
11127529SSriharsha.Basavapatna@Sun.COM void
vsw_port_reset(vsw_port_t * portp)11137529SSriharsha.Basavapatna@Sun.COM vsw_port_reset(vsw_port_t *portp)
11147529SSriharsha.Basavapatna@Sun.COM {
111512011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t	*ldcp = portp->ldcp;
11167529SSriharsha.Basavapatna@Sun.COM 
11177529SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->ldc_cblock);
11187529SSriharsha.Basavapatna@Sun.COM 
11197529SSriharsha.Basavapatna@Sun.COM 	/*
11207529SSriharsha.Basavapatna@Sun.COM 	 * reset channel and terminate the connection.
11217529SSriharsha.Basavapatna@Sun.COM 	 */
11227529SSriharsha.Basavapatna@Sun.COM 	vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
11237529SSriharsha.Basavapatna@Sun.COM 
11247529SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->ldc_cblock);
11257529SSriharsha.Basavapatna@Sun.COM }
11267529SSriharsha.Basavapatna@Sun.COM 
11277529SSriharsha.Basavapatna@Sun.COM void
vsw_reset_ports(vsw_t * vswp)11287529SSriharsha.Basavapatna@Sun.COM vsw_reset_ports(vsw_t *vswp)
11297529SSriharsha.Basavapatna@Sun.COM {
11307529SSriharsha.Basavapatna@Sun.COM 	vsw_port_list_t	*plist = &vswp->plist;
11317529SSriharsha.Basavapatna@Sun.COM 	vsw_port_t	*portp;
11327529SSriharsha.Basavapatna@Sun.COM 
11337529SSriharsha.Basavapatna@Sun.COM 	READ_ENTER(&plist->lockrw);
11347529SSriharsha.Basavapatna@Sun.COM 	for (portp = plist->head; portp != NULL; portp = portp->p_next) {
11357529SSriharsha.Basavapatna@Sun.COM 		if ((portp->p_hio_capable) && (portp->p_hio_enabled)) {
11367529SSriharsha.Basavapatna@Sun.COM 			vsw_hio_stop_port(portp);
11377529SSriharsha.Basavapatna@Sun.COM 		}
11387529SSriharsha.Basavapatna@Sun.COM 		vsw_port_reset(portp);
11397529SSriharsha.Basavapatna@Sun.COM 	}
11407529SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&plist->lockrw);
11417529SSriharsha.Basavapatna@Sun.COM }
11427529SSriharsha.Basavapatna@Sun.COM 
11439336SSriharsha.Basavapatna@Sun.COM static void
vsw_send_physlink_msg(vsw_ldc_t * ldcp,link_state_t plink_state)11449336SSriharsha.Basavapatna@Sun.COM vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state)
11459336SSriharsha.Basavapatna@Sun.COM {
11469336SSriharsha.Basavapatna@Sun.COM 	vnet_physlink_msg_t	msg;
11479336SSriharsha.Basavapatna@Sun.COM 	vnet_physlink_msg_t	*msgp = &msg;
11489336SSriharsha.Basavapatna@Sun.COM 	uint32_t		physlink_info = 0;
11499336SSriharsha.Basavapatna@Sun.COM 
11509336SSriharsha.Basavapatna@Sun.COM 	if (plink_state == LINK_STATE_UP) {
11519336SSriharsha.Basavapatna@Sun.COM 		physlink_info |= VNET_PHYSLINK_STATE_UP;
11529336SSriharsha.Basavapatna@Sun.COM 	} else {
11539336SSriharsha.Basavapatna@Sun.COM 		physlink_info |= VNET_PHYSLINK_STATE_DOWN;
11549336SSriharsha.Basavapatna@Sun.COM 	}
11559336SSriharsha.Basavapatna@Sun.COM 
11569336SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_msgtype = VIO_TYPE_CTRL;
11579336SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_subtype = VIO_SUBTYPE_INFO;
11589336SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_subtype_env = VNET_PHYSLINK_INFO;
11599336SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_sid = ldcp->local_session;
11609336SSriharsha.Basavapatna@Sun.COM 	msgp->physlink_info = physlink_info;
11619336SSriharsha.Basavapatna@Sun.COM 
11629336SSriharsha.Basavapatna@Sun.COM 	(void) vsw_send_msg(ldcp, msgp, sizeof (msg), B_TRUE);
11639336SSriharsha.Basavapatna@Sun.COM }
11649336SSriharsha.Basavapatna@Sun.COM 
11659336SSriharsha.Basavapatna@Sun.COM static void
vsw_port_physlink_update(vsw_port_t * portp)11669336SSriharsha.Basavapatna@Sun.COM vsw_port_physlink_update(vsw_port_t *portp)
11679336SSriharsha.Basavapatna@Sun.COM {
11689336SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t	*ldcp;
11699336SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp;
11709336SSriharsha.Basavapatna@Sun.COM 
11719336SSriharsha.Basavapatna@Sun.COM 	vswp = portp->p_vswp;
117212011SSriharsha.Basavapatna@Sun.COM 	ldcp = portp->ldcp;
11739336SSriharsha.Basavapatna@Sun.COM 
11749336SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->ldc_cblock);
11759336SSriharsha.Basavapatna@Sun.COM 
11769336SSriharsha.Basavapatna@Sun.COM 	/*
11779336SSriharsha.Basavapatna@Sun.COM 	 * If handshake has completed successfully and if the vnet device
11789336SSriharsha.Basavapatna@Sun.COM 	 * has negotiated to get physical link state updates, send a message
11799336SSriharsha.Basavapatna@Sun.COM 	 * with the current state.
11809336SSriharsha.Basavapatna@Sun.COM 	 */
11819336SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase == VSW_MILESTONE4 && ldcp->pls_negotiated == B_TRUE) {
11829336SSriharsha.Basavapatna@Sun.COM 		vsw_send_physlink_msg(ldcp, vswp->phys_link_state);
11839336SSriharsha.Basavapatna@Sun.COM 	}
11849336SSriharsha.Basavapatna@Sun.COM 
11859336SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->ldc_cblock);
11869336SSriharsha.Basavapatna@Sun.COM }
11879336SSriharsha.Basavapatna@Sun.COM 
11889336SSriharsha.Basavapatna@Sun.COM void
vsw_physlink_update_ports(vsw_t * vswp)11899336SSriharsha.Basavapatna@Sun.COM vsw_physlink_update_ports(vsw_t *vswp)
11909336SSriharsha.Basavapatna@Sun.COM {
11919336SSriharsha.Basavapatna@Sun.COM 	vsw_port_list_t	*plist = &vswp->plist;
11929336SSriharsha.Basavapatna@Sun.COM 	vsw_port_t	*portp;
11939336SSriharsha.Basavapatna@Sun.COM 
11949336SSriharsha.Basavapatna@Sun.COM 	READ_ENTER(&plist->lockrw);
11959336SSriharsha.Basavapatna@Sun.COM 	for (portp = plist->head; portp != NULL; portp = portp->p_next) {
11969336SSriharsha.Basavapatna@Sun.COM 		vsw_port_physlink_update(portp);
11979336SSriharsha.Basavapatna@Sun.COM 	}
11989336SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&plist->lockrw);
11999336SSriharsha.Basavapatna@Sun.COM }
12007529SSriharsha.Basavapatna@Sun.COM 
12015373Sraghuram /*
12025373Sraghuram  * Search for and remove the specified port from the port
12035373Sraghuram  * list. Returns 0 if able to locate and remove port, otherwise
12045373Sraghuram  * returns 1.
12055373Sraghuram  */
12065373Sraghuram static int
vsw_plist_del_node(vsw_t * vswp,vsw_port_t * port)12075373Sraghuram vsw_plist_del_node(vsw_t *vswp, vsw_port_t *port)
12085373Sraghuram {
12095373Sraghuram 	vsw_port_list_t *plist = &vswp->plist;
12105373Sraghuram 	vsw_port_t	*curr_p, *prev_p;
12115373Sraghuram 
12125373Sraghuram 	if (plist->head == NULL)
12135373Sraghuram 		return (1);
12145373Sraghuram 
12155373Sraghuram 	curr_p = prev_p = plist->head;
12165373Sraghuram 
12175373Sraghuram 	while (curr_p != NULL) {
12185373Sraghuram 		if (curr_p == port) {
12195373Sraghuram 			if (prev_p == curr_p) {
12205373Sraghuram 				plist->head = curr_p->p_next;
12215373Sraghuram 			} else {
12225373Sraghuram 				prev_p->p_next = curr_p->p_next;
12235373Sraghuram 			}
12245373Sraghuram 			plist->num_ports--;
12255373Sraghuram 			break;
12265373Sraghuram 		} else {
12275373Sraghuram 			prev_p = curr_p;
12285373Sraghuram 			curr_p = curr_p->p_next;
12295373Sraghuram 		}
12305373Sraghuram 	}
12315373Sraghuram 	return (0);
12325373Sraghuram }
12335373Sraghuram 
12345373Sraghuram /*
12355373Sraghuram  * Interrupt handler for ldc messages.
12365373Sraghuram  */
12375373Sraghuram static uint_t
vsw_ldc_cb(uint64_t event,caddr_t arg)12385373Sraghuram vsw_ldc_cb(uint64_t event, caddr_t arg)
12395373Sraghuram {
12405373Sraghuram 	vsw_ldc_t	*ldcp = (vsw_ldc_t  *)arg;
12415373Sraghuram 	vsw_t 		*vswp = ldcp->ldc_vswp;
12425373Sraghuram 
12435373Sraghuram 	D1(vswp, "%s: enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
12445373Sraghuram 
12455373Sraghuram 	mutex_enter(&ldcp->ldc_cblock);
12465373Sraghuram 	ldcp->ldc_stats.callbacks++;
12475373Sraghuram 
12485373Sraghuram 	mutex_enter(&ldcp->status_lock);
12495373Sraghuram 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
12505373Sraghuram 		mutex_exit(&ldcp->status_lock);
12515373Sraghuram 		mutex_exit(&ldcp->ldc_cblock);
12525373Sraghuram 		return (LDC_SUCCESS);
12535373Sraghuram 	}
12545373Sraghuram 	mutex_exit(&ldcp->status_lock);
12555373Sraghuram 
12565373Sraghuram 	if (event & LDC_EVT_UP) {
12575373Sraghuram 		/*
12585373Sraghuram 		 * Channel has come up.
12595373Sraghuram 		 */
12605373Sraghuram 		D2(vswp, "%s: id(%ld) event(%llx) UP: status(%ld)",
12615373Sraghuram 		    __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12625373Sraghuram 
12635373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_UP);
12645373Sraghuram 
12655373Sraghuram 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
12665373Sraghuram 	}
12675373Sraghuram 
12685373Sraghuram 	if (event & LDC_EVT_READ) {
12695373Sraghuram 		/*
12705373Sraghuram 		 * Data available for reading.
12715373Sraghuram 		 */
12725373Sraghuram 		D2(vswp, "%s: id(ld) event(%llx) data READ",
12735373Sraghuram 		    __func__, ldcp->ldc_id, event);
12745373Sraghuram 
127512011SSriharsha.Basavapatna@Sun.COM 		vsw_process_evt_read(ldcp);
12765373Sraghuram 
12775373Sraghuram 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
12785373Sraghuram 
12795373Sraghuram 		goto vsw_cb_exit;
12805373Sraghuram 	}
12815373Sraghuram 
12825373Sraghuram 	if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) {
12835373Sraghuram 		D2(vswp, "%s: id(%ld) event (%lx) DOWN/RESET: status(%ld)",
12845373Sraghuram 		    __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12855373Sraghuram 
12865373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
12875373Sraghuram 	}
12885373Sraghuram 
12895373Sraghuram 	/*
12905373Sraghuram 	 * Catch either LDC_EVT_WRITE which we don't support or any
12915373Sraghuram 	 * unknown event.
12925373Sraghuram 	 */
12935373Sraghuram 	if (event &
12945373Sraghuram 	    ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) {
12955373Sraghuram 		DERR(vswp, "%s: id(%ld) Unexpected event=(%llx) status(%ld)",
12965373Sraghuram 		    __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12975373Sraghuram 	}
12985373Sraghuram 
12995373Sraghuram vsw_cb_exit:
13005373Sraghuram 	mutex_exit(&ldcp->ldc_cblock);
13015373Sraghuram 
13025373Sraghuram 	/*
13035373Sraghuram 	 * Let the drain function know we are finishing if it
13045373Sraghuram 	 * is waiting.
13055373Sraghuram 	 */
13065373Sraghuram 	mutex_enter(&ldcp->drain_cv_lock);
13075373Sraghuram 	if (ldcp->drain_state == VSW_LDC_DRAINING)
13085373Sraghuram 		cv_signal(&ldcp->drain_cv);
13095373Sraghuram 	mutex_exit(&ldcp->drain_cv_lock);
13105373Sraghuram 
13115373Sraghuram 	return (LDC_SUCCESS);
13125373Sraghuram }
13135373Sraghuram 
13145373Sraghuram /*
13155373Sraghuram  * Reinitialise data structures associated with the channel.
13165373Sraghuram  */
13175373Sraghuram static void
vsw_ldc_reinit(vsw_ldc_t * ldcp)13185373Sraghuram vsw_ldc_reinit(vsw_ldc_t *ldcp)
13195373Sraghuram {
13205373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
13215373Sraghuram 	vsw_port_t	*port;
13225373Sraghuram 
13235373Sraghuram 	D1(vswp, "%s: enter", __func__);
13245373Sraghuram 
13255373Sraghuram 	port = ldcp->ldc_port;
13265373Sraghuram 
13275373Sraghuram 	D2(vswp, "%s: in 0x%llx : out 0x%llx", __func__,
13285373Sraghuram 	    ldcp->lane_in.lstate, ldcp->lane_out.lstate);
13295373Sraghuram 
13305373Sraghuram 	vsw_free_lane_resources(ldcp, INBOUND);
13315373Sraghuram 	vsw_free_lane_resources(ldcp, OUTBOUND);
13325373Sraghuram 
13335373Sraghuram 	ldcp->lane_in.lstate = 0;
13345373Sraghuram 	ldcp->lane_out.lstate = 0;
13355373Sraghuram 
13365373Sraghuram 	/*
13375373Sraghuram 	 * Remove parent port from any multicast groups
13385373Sraghuram 	 * it may have registered with. Client must resend
13395373Sraghuram 	 * multicast add command after handshake completes.
13405373Sraghuram 	 */
13415373Sraghuram 	vsw_del_mcst_port(port);
13425373Sraghuram 
13435373Sraghuram 	ldcp->peer_session = 0;
13445373Sraghuram 	ldcp->session_status = 0;
13455373Sraghuram 	ldcp->hcnt = 0;
13465373Sraghuram 	ldcp->hphase = VSW_MILESTONE0;
13475935Ssb155480 
13485935Ssb155480 	vsw_reset_vnet_proto_ops(ldcp);
13495373Sraghuram 
13505373Sraghuram 	D1(vswp, "%s: exit", __func__);
13515373Sraghuram }
13525373Sraghuram 
13535373Sraghuram /*
13545373Sraghuram  * Process a connection event.
13555373Sraghuram  */
135612011SSriharsha.Basavapatna@Sun.COM void
vsw_process_conn_evt(vsw_ldc_t * ldcp,uint16_t evt)13575373Sraghuram vsw_process_conn_evt(vsw_ldc_t *ldcp, uint16_t evt)
13585373Sraghuram {
13595373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
13605373Sraghuram 	vsw_conn_evt_t	*conn = NULL;
13615373Sraghuram 
13625373Sraghuram 	D1(vswp, "%s: enter", __func__);
13635373Sraghuram 
13645373Sraghuram 	/*
13655373Sraghuram 	 * Check if either a reset or restart event is pending
13665373Sraghuram 	 * or in progress. If so just return.
13675373Sraghuram 	 *
13685373Sraghuram 	 * A VSW_CONN_RESET event originates either with a LDC_RESET_EVT
13695373Sraghuram 	 * being received by the callback handler, or a ECONNRESET error
13705373Sraghuram 	 * code being returned from a ldc_read() or ldc_write() call.
13715373Sraghuram 	 *
13725373Sraghuram 	 * A VSW_CONN_RESTART event occurs when some error checking code
13735373Sraghuram 	 * decides that there is a problem with data from the channel,
13745373Sraghuram 	 * and that the handshake should be restarted.
13755373Sraghuram 	 */
13765373Sraghuram 	if (((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) &&
13775373Sraghuram 	    (ldstub((uint8_t *)&ldcp->reset_active)))
13785373Sraghuram 		return;
13795373Sraghuram 
13805373Sraghuram 	/*
13815373Sraghuram 	 * If it is an LDC_UP event we first check the recorded
13825373Sraghuram 	 * state of the channel. If this is UP then we know that
13835373Sraghuram 	 * the channel moving to the UP state has already been dealt
13845373Sraghuram 	 * with and don't need to dispatch a  new task.
13855373Sraghuram 	 *
13865373Sraghuram 	 * The reason for this check is that when we do a ldc_up(),
13875373Sraghuram 	 * depending on the state of the peer, we may or may not get
13885373Sraghuram 	 * a LDC_UP event. As we can't depend on getting a LDC_UP evt
13895373Sraghuram 	 * every time we do ldc_up() we explicitly check the channel
13905373Sraghuram 	 * status to see has it come up (ldc_up() is asynch and will
13915373Sraghuram 	 * complete at some undefined time), and take the appropriate
13925373Sraghuram 	 * action.
13935373Sraghuram 	 *
13945373Sraghuram 	 * The flip side of this is that we may get a LDC_UP event
13955373Sraghuram 	 * when we have already seen that the channel is up and have
13965373Sraghuram 	 * dealt with that.
13975373Sraghuram 	 */
13985373Sraghuram 	mutex_enter(&ldcp->status_lock);
13995373Sraghuram 	if (evt == VSW_CONN_UP) {
14005373Sraghuram 		if ((ldcp->ldc_status == LDC_UP) || (ldcp->reset_active != 0)) {
14015373Sraghuram 			mutex_exit(&ldcp->status_lock);
14025373Sraghuram 			return;
14035373Sraghuram 		}
14045373Sraghuram 	}
14055373Sraghuram 	mutex_exit(&ldcp->status_lock);
14065373Sraghuram 
14075373Sraghuram 	/*
14085373Sraghuram 	 * The transaction group id allows us to identify and discard
14095373Sraghuram 	 * any tasks which are still pending on the taskq and refer
14105373Sraghuram 	 * to the handshake session we are about to restart or reset.
14115373Sraghuram 	 * These stale messages no longer have any real meaning.
14125373Sraghuram 	 */
14135373Sraghuram 	(void) atomic_inc_32(&ldcp->hss_id);
14145373Sraghuram 
14155373Sraghuram 	ASSERT(vswp->taskq_p != NULL);
14165373Sraghuram 
14175373Sraghuram 	if ((conn = kmem_zalloc(sizeof (vsw_conn_evt_t), KM_NOSLEEP)) == NULL) {
14185373Sraghuram 		cmn_err(CE_WARN, "!vsw%d: unable to allocate memory for"
14195373Sraghuram 		    " connection event", vswp->instance);
14205373Sraghuram 		goto err_exit;
14215373Sraghuram 	}
14225373Sraghuram 
14235373Sraghuram 	conn->evt = evt;
14245373Sraghuram 	conn->ldcp = ldcp;
14255373Sraghuram 
14265373Sraghuram 	if (ddi_taskq_dispatch(vswp->taskq_p, vsw_conn_task, conn,
14275373Sraghuram 	    DDI_NOSLEEP) != DDI_SUCCESS) {
14285373Sraghuram 		cmn_err(CE_WARN, "!vsw%d: Can't dispatch connection task",
14295373Sraghuram 		    vswp->instance);
14305373Sraghuram 
14315373Sraghuram 		kmem_free(conn, sizeof (vsw_conn_evt_t));
14325373Sraghuram 		goto err_exit;
14335373Sraghuram 	}
14345373Sraghuram 
14355373Sraghuram 	D1(vswp, "%s: exit", __func__);
14365373Sraghuram 	return;
14375373Sraghuram 
14385373Sraghuram err_exit:
14395373Sraghuram 	/*
14405373Sraghuram 	 * Have mostly likely failed due to memory shortage. Clear the flag so
14415373Sraghuram 	 * that future requests will at least be attempted and will hopefully
14425373Sraghuram 	 * succeed.
14435373Sraghuram 	 */
14445373Sraghuram 	if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
14455373Sraghuram 		ldcp->reset_active = 0;
14465373Sraghuram }
14475373Sraghuram 
14485373Sraghuram /*
14495373Sraghuram  * Deal with events relating to a connection. Invoked from a taskq.
14505373Sraghuram  */
14515373Sraghuram static void
vsw_conn_task(void * arg)14525373Sraghuram vsw_conn_task(void *arg)
14535373Sraghuram {
14545373Sraghuram 	vsw_conn_evt_t	*conn = (vsw_conn_evt_t *)arg;
14555373Sraghuram 	vsw_ldc_t	*ldcp = NULL;
14566495Sspeer 	vsw_port_t	*portp;
14575373Sraghuram 	vsw_t		*vswp = NULL;
14585373Sraghuram 	uint16_t	evt;
14595373Sraghuram 	ldc_status_t	curr_status;
14605373Sraghuram 
14615373Sraghuram 	ldcp = conn->ldcp;
14625373Sraghuram 	evt = conn->evt;
14635373Sraghuram 	vswp = ldcp->ldc_vswp;
14646495Sspeer 	portp = ldcp->ldc_port;
14655373Sraghuram 
14665373Sraghuram 	D1(vswp, "%s: enter", __func__);
14675373Sraghuram 
14685373Sraghuram 	/* can safely free now have copied out data */
14695373Sraghuram 	kmem_free(conn, sizeof (vsw_conn_evt_t));
14705373Sraghuram 
147112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rcv_thread != NULL) {
147212011SSriharsha.Basavapatna@Sun.COM 		vsw_stop_rcv_thread(ldcp);
147312011SSriharsha.Basavapatna@Sun.COM 	} else if (ldcp->msg_thread != NULL) {
147412011SSriharsha.Basavapatna@Sun.COM 		vsw_stop_msg_thread(ldcp);
147512011SSriharsha.Basavapatna@Sun.COM 	}
147612011SSriharsha.Basavapatna@Sun.COM 
14775373Sraghuram 	mutex_enter(&ldcp->status_lock);
14785373Sraghuram 	if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
14795373Sraghuram 		cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
14805373Sraghuram 		    "channel %ld", vswp->instance, ldcp->ldc_id);
14815373Sraghuram 		mutex_exit(&ldcp->status_lock);
14825373Sraghuram 		return;
14835373Sraghuram 	}
14845373Sraghuram 
14855373Sraghuram 	/*
14865373Sraghuram 	 * If we wish to restart the handshake on this channel, then if
14875373Sraghuram 	 * the channel is UP we bring it DOWN to flush the underlying
14885373Sraghuram 	 * ldc queue.
14895373Sraghuram 	 */
14905373Sraghuram 	if ((evt == VSW_CONN_RESTART) && (curr_status == LDC_UP))
14915373Sraghuram 		(void) ldc_down(ldcp->ldc_handle);
14925373Sraghuram 
14936724Sraghuram 	if ((portp->p_hio_capable) && (portp->p_hio_enabled)) {
14946495Sspeer 		vsw_hio_stop(vswp, ldcp);
14956495Sspeer 	}
14966495Sspeer 
14975373Sraghuram 	/*
14985373Sraghuram 	 * re-init all the associated data structures.
14995373Sraghuram 	 */
15005373Sraghuram 	vsw_ldc_reinit(ldcp);
15015373Sraghuram 
15025373Sraghuram 	/*
15035373Sraghuram 	 * Bring the channel back up (note it does no harm to
15045373Sraghuram 	 * do this even if the channel is already UP, Just
15055373Sraghuram 	 * becomes effectively a no-op).
15065373Sraghuram 	 */
15075373Sraghuram 	(void) ldc_up(ldcp->ldc_handle);
15085373Sraghuram 
15095373Sraghuram 	/*
15105373Sraghuram 	 * Check if channel is now UP. This will only happen if
15115373Sraghuram 	 * peer has also done a ldc_up().
15125373Sraghuram 	 */
15135373Sraghuram 	if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
15145373Sraghuram 		cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
15155373Sraghuram 		    "channel %ld", vswp->instance, ldcp->ldc_id);
15165373Sraghuram 		mutex_exit(&ldcp->status_lock);
15175373Sraghuram 		return;
15185373Sraghuram 	}
15195373Sraghuram 
15205373Sraghuram 	ldcp->ldc_status = curr_status;
15215373Sraghuram 
15225373Sraghuram 	/* channel UP so restart handshake by sending version info */
15235373Sraghuram 	if (curr_status == LDC_UP) {
15245373Sraghuram 		if (ldcp->hcnt++ > vsw_num_handshakes) {
15255373Sraghuram 			cmn_err(CE_WARN, "!vsw%d: exceeded number of permitted"
15265373Sraghuram 			    " handshake attempts (%d) on channel %ld",
15275373Sraghuram 			    vswp->instance, ldcp->hcnt, ldcp->ldc_id);
15285373Sraghuram 			mutex_exit(&ldcp->status_lock);
15295373Sraghuram 			return;
15305373Sraghuram 		}
15315373Sraghuram 
15325935Ssb155480 		if (vsw_obp_ver_proto_workaround == B_FALSE &&
15335935Ssb155480 		    (ddi_taskq_dispatch(vswp->taskq_p, vsw_send_ver, ldcp,
15345935Ssb155480 		    DDI_NOSLEEP) != DDI_SUCCESS)) {
15355373Sraghuram 			cmn_err(CE_WARN, "!vsw%d: Can't dispatch version task",
15365373Sraghuram 			    vswp->instance);
15375373Sraghuram 
15385373Sraghuram 			/*
15395373Sraghuram 			 * Don't count as valid restart attempt if couldn't
15405373Sraghuram 			 * send version msg.
15415373Sraghuram 			 */
15425373Sraghuram 			if (ldcp->hcnt > 0)
15435373Sraghuram 				ldcp->hcnt--;
15445373Sraghuram 		}
15455373Sraghuram 	}
15465373Sraghuram 
15475373Sraghuram 	/*
15485373Sraghuram 	 * Mark that the process is complete by clearing the flag.
15495373Sraghuram 	 *
15505373Sraghuram 	 * Note is it possible that the taskq dispatch above may have failed,
15515373Sraghuram 	 * most likely due to memory shortage. We still clear the flag so
15525373Sraghuram 	 * future attempts will at least be attempted and will hopefully
15535373Sraghuram 	 * succeed.
15545373Sraghuram 	 */
15555373Sraghuram 	if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
15565373Sraghuram 		ldcp->reset_active = 0;
15575373Sraghuram 
15585373Sraghuram 	mutex_exit(&ldcp->status_lock);
15595373Sraghuram 
15605373Sraghuram 	D1(vswp, "%s: exit", __func__);
15615373Sraghuram }
15625373Sraghuram 
15635373Sraghuram /*
15645373Sraghuram  * returns 0 if legal for event signified by flag to have
15655373Sraghuram  * occured at the time it did. Otherwise returns 1.
15665373Sraghuram  */
15675373Sraghuram int
vsw_check_flag(vsw_ldc_t * ldcp,int dir,uint64_t flag)15685373Sraghuram vsw_check_flag(vsw_ldc_t *ldcp, int dir, uint64_t flag)
15695373Sraghuram {
15705373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
15715373Sraghuram 	uint64_t	state;
15725373Sraghuram 	uint64_t	phase;
15735373Sraghuram 
15745373Sraghuram 	if (dir == INBOUND)
15755373Sraghuram 		state = ldcp->lane_in.lstate;
15765373Sraghuram 	else
15775373Sraghuram 		state = ldcp->lane_out.lstate;
15785373Sraghuram 
15795373Sraghuram 	phase = ldcp->hphase;
15805373Sraghuram 
15815373Sraghuram 	switch (flag) {
15825373Sraghuram 	case VSW_VER_INFO_RECV:
15835373Sraghuram 		if (phase > VSW_MILESTONE0) {
15845373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): VER_INFO_RECV"
15855373Sraghuram 			    " when in state %d\n", ldcp->ldc_id, phase);
15865373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
15875373Sraghuram 			return (1);
15885373Sraghuram 		}
15895373Sraghuram 		break;
15905373Sraghuram 
15915373Sraghuram 	case VSW_VER_ACK_RECV:
15925373Sraghuram 	case VSW_VER_NACK_RECV:
15935373Sraghuram 		if (!(state & VSW_VER_INFO_SENT)) {
15945373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): spurious VER_ACK or "
15955373Sraghuram 			    "VER_NACK when in state %d\n", ldcp->ldc_id, phase);
15965373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
15975373Sraghuram 			return (1);
15985373Sraghuram 		} else
15995373Sraghuram 			state &= ~VSW_VER_INFO_SENT;
16005373Sraghuram 		break;
16015373Sraghuram 
16025373Sraghuram 	case VSW_ATTR_INFO_RECV:
16035373Sraghuram 		if ((phase < VSW_MILESTONE1) || (phase >= VSW_MILESTONE2)) {
16045373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): ATTR_INFO_RECV"
16055373Sraghuram 			    " when in state %d\n", ldcp->ldc_id, phase);
16065373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16075373Sraghuram 			return (1);
16085373Sraghuram 		}
16095373Sraghuram 		break;
16105373Sraghuram 
16115373Sraghuram 	case VSW_ATTR_ACK_RECV:
16125373Sraghuram 	case VSW_ATTR_NACK_RECV:
16135373Sraghuram 		if (!(state & VSW_ATTR_INFO_SENT)) {
16145373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): spurious ATTR_ACK"
16155373Sraghuram 			    " or ATTR_NACK when in state %d\n",
16165373Sraghuram 			    ldcp->ldc_id, phase);
16175373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16185373Sraghuram 			return (1);
16195373Sraghuram 		} else
16205373Sraghuram 			state &= ~VSW_ATTR_INFO_SENT;
16215373Sraghuram 		break;
16225373Sraghuram 
16235373Sraghuram 	case VSW_DRING_INFO_RECV:
16245373Sraghuram 		if (phase < VSW_MILESTONE1) {
16255373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): DRING_INFO_RECV"
16265373Sraghuram 			    " when in state %d\n", ldcp->ldc_id, phase);
16275373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16285373Sraghuram 			return (1);
16295373Sraghuram 		}
16305373Sraghuram 		break;
16315373Sraghuram 
16325373Sraghuram 	case VSW_DRING_ACK_RECV:
16335373Sraghuram 	case VSW_DRING_NACK_RECV:
16345373Sraghuram 		if (!(state & VSW_DRING_INFO_SENT)) {
16355373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): spurious DRING_ACK "
16365373Sraghuram 			    " or DRING_NACK when in state %d\n",
16375373Sraghuram 			    ldcp->ldc_id, phase);
16385373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16395373Sraghuram 			return (1);
16405373Sraghuram 		} else
16415373Sraghuram 			state &= ~VSW_DRING_INFO_SENT;
16425373Sraghuram 		break;
16435373Sraghuram 
16445373Sraghuram 	case VSW_RDX_INFO_RECV:
16455373Sraghuram 		if (phase < VSW_MILESTONE3) {
16465373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): RDX_INFO_RECV"
16475373Sraghuram 			    " when in state %d\n", ldcp->ldc_id, phase);
16485373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16495373Sraghuram 			return (1);
16505373Sraghuram 		}
16515373Sraghuram 		break;
16525373Sraghuram 
16535373Sraghuram 	case VSW_RDX_ACK_RECV:
16545373Sraghuram 	case VSW_RDX_NACK_RECV:
16555373Sraghuram 		if (!(state & VSW_RDX_INFO_SENT)) {
16565373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): spurious RDX_ACK or "
16575373Sraghuram 			    "RDX_NACK when in state %d\n", ldcp->ldc_id, phase);
16585373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16595373Sraghuram 			return (1);
16605373Sraghuram 		} else
16615373Sraghuram 			state &= ~VSW_RDX_INFO_SENT;
16625373Sraghuram 		break;
16635373Sraghuram 
16645373Sraghuram 	case VSW_MCST_INFO_RECV:
16655373Sraghuram 		if (phase < VSW_MILESTONE3) {
16665373Sraghuram 			DERR(vswp, "vsw_check_flag (%d): VSW_MCST_INFO_RECV"
16675373Sraghuram 			    " when in state %d\n", ldcp->ldc_id, phase);
16685373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16695373Sraghuram 			return (1);
16705373Sraghuram 		}
16715373Sraghuram 		break;
16725373Sraghuram 
16735373Sraghuram 	default:
16745373Sraghuram 		DERR(vswp, "vsw_check_flag (%lld): unknown flag (%llx)",
16755373Sraghuram 		    ldcp->ldc_id, flag);
16765373Sraghuram 		return (1);
16775373Sraghuram 	}
16785373Sraghuram 
16795373Sraghuram 	if (dir == INBOUND)
16805373Sraghuram 		ldcp->lane_in.lstate = state;
16815373Sraghuram 	else
16825373Sraghuram 		ldcp->lane_out.lstate = state;
16835373Sraghuram 
16845373Sraghuram 	D1(vswp, "vsw_check_flag (chan %lld): exit", ldcp->ldc_id);
16855373Sraghuram 
16865373Sraghuram 	return (0);
16875373Sraghuram }
16885373Sraghuram 
16895373Sraghuram void
vsw_next_milestone(vsw_ldc_t * ldcp)16905373Sraghuram vsw_next_milestone(vsw_ldc_t *ldcp)
16915373Sraghuram {
16925373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
16936495Sspeer 	vsw_port_t	*portp = ldcp->ldc_port;
169412011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_out = &ldcp->lane_out;
169512011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_in = &ldcp->lane_in;
16965373Sraghuram 
16975373Sraghuram 	D1(vswp, "%s (chan %lld): enter (phase %ld)", __func__,
16985373Sraghuram 	    ldcp->ldc_id, ldcp->hphase);
16995373Sraghuram 
170012011SSriharsha.Basavapatna@Sun.COM 	DUMP_FLAGS(lane_in->lstate);
170112011SSriharsha.Basavapatna@Sun.COM 	DUMP_FLAGS(lane_out->lstate);
17025373Sraghuram 
17035373Sraghuram 	switch (ldcp->hphase) {
17045373Sraghuram 
17055373Sraghuram 	case VSW_MILESTONE0:
17065373Sraghuram 		/*
17075373Sraghuram 		 * If we haven't started to handshake with our peer,
17085373Sraghuram 		 * start to do so now.
17095373Sraghuram 		 */
171012011SSriharsha.Basavapatna@Sun.COM 		if (lane_out->lstate == 0) {
17115373Sraghuram 			D2(vswp, "%s: (chan %lld) starting handshake "
17125373Sraghuram 			    "with peer", __func__, ldcp->ldc_id);
17135373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_UP);
17145373Sraghuram 		}
17155373Sraghuram 
17165373Sraghuram 		/*
17175373Sraghuram 		 * Only way to pass this milestone is to have successfully
17185373Sraghuram 		 * negotiated version info.
17195373Sraghuram 		 */
172012011SSriharsha.Basavapatna@Sun.COM 		if ((lane_in->lstate & VSW_VER_ACK_SENT) &&
172112011SSriharsha.Basavapatna@Sun.COM 		    (lane_out->lstate & VSW_VER_ACK_RECV)) {
17225373Sraghuram 
17235373Sraghuram 			D2(vswp, "%s: (chan %lld) leaving milestone 0",
17245373Sraghuram 			    __func__, ldcp->ldc_id);
17255373Sraghuram 
17265935Ssb155480 			vsw_set_vnet_proto_ops(ldcp);
17275935Ssb155480 
17285373Sraghuram 			/*
17295373Sraghuram 			 * Next milestone is passed when attribute
17305373Sraghuram 			 * information has been successfully exchanged.
17315373Sraghuram 			 */
17325373Sraghuram 			ldcp->hphase = VSW_MILESTONE1;
17335373Sraghuram 			vsw_send_attr(ldcp);
17345373Sraghuram 
17355373Sraghuram 		}
17365373Sraghuram 		break;
17375373Sraghuram 
17385373Sraghuram 	case VSW_MILESTONE1:
17395373Sraghuram 		/*
17405373Sraghuram 		 * Only way to pass this milestone is to have successfully
174112011SSriharsha.Basavapatna@Sun.COM 		 * negotiated attribute information, in both directions.
174212011SSriharsha.Basavapatna@Sun.COM 		 */
174312011SSriharsha.Basavapatna@Sun.COM 		if (!((lane_in->lstate & VSW_ATTR_ACK_SENT) &&
174412011SSriharsha.Basavapatna@Sun.COM 		    (lane_out->lstate & VSW_ATTR_ACK_RECV))) {
174512011SSriharsha.Basavapatna@Sun.COM 			break;
174612011SSriharsha.Basavapatna@Sun.COM 		}
174712011SSriharsha.Basavapatna@Sun.COM 
174812011SSriharsha.Basavapatna@Sun.COM 		ldcp->hphase = VSW_MILESTONE2;
174912011SSriharsha.Basavapatna@Sun.COM 
175012011SSriharsha.Basavapatna@Sun.COM 		/*
175112011SSriharsha.Basavapatna@Sun.COM 		 * If the peer device has said it wishes to
175212011SSriharsha.Basavapatna@Sun.COM 		 * use descriptor rings then we send it our ring
175312011SSriharsha.Basavapatna@Sun.COM 		 * info, otherwise we just set up a private ring
175412011SSriharsha.Basavapatna@Sun.COM 		 * which we use an internal buffer
17555373Sraghuram 		 */
175612011SSriharsha.Basavapatna@Sun.COM 		if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
175712011SSriharsha.Basavapatna@Sun.COM 		    (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
175812011SSriharsha.Basavapatna@Sun.COM 		    (VSW_VER_LT(ldcp, 1, 2) &&
175912011SSriharsha.Basavapatna@Sun.COM 		    (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
176012011SSriharsha.Basavapatna@Sun.COM 			vsw_send_dring_info(ldcp);
176112011SSriharsha.Basavapatna@Sun.COM 			break;
17625373Sraghuram 		}
176312011SSriharsha.Basavapatna@Sun.COM 
176412011SSriharsha.Basavapatna@Sun.COM 		/*
176512011SSriharsha.Basavapatna@Sun.COM 		 * The peer doesn't operate in dring mode; we
176612011SSriharsha.Basavapatna@Sun.COM 		 * can simply fallthru to the RDX phase from
176712011SSriharsha.Basavapatna@Sun.COM 		 * here.
176812011SSriharsha.Basavapatna@Sun.COM 		 */
176912011SSriharsha.Basavapatna@Sun.COM 		/*FALLTHRU*/
17705373Sraghuram 
17715373Sraghuram 	case VSW_MILESTONE2:
17725373Sraghuram 		/*
17735373Sraghuram 		 * If peer has indicated in its attribute message that
17745373Sraghuram 		 * it wishes to use descriptor rings then the only way
17755373Sraghuram 		 * to pass this milestone is for us to have received
17765373Sraghuram 		 * valid dring info.
17775373Sraghuram 		 *
17785373Sraghuram 		 * If peer is not using descriptor rings then just fall
17795373Sraghuram 		 * through.
17805373Sraghuram 		 */
17816419Ssb155480 		if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
178212011SSriharsha.Basavapatna@Sun.COM 		    (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
17835935Ssb155480 		    (VSW_VER_LT(ldcp, 1, 2) &&
178412011SSriharsha.Basavapatna@Sun.COM 		    (lane_in->xfer_mode ==
17855935Ssb155480 		    VIO_DRING_MODE_V1_0))) {
178612011SSriharsha.Basavapatna@Sun.COM 			if (!(lane_in->lstate & VSW_DRING_ACK_SENT))
17875935Ssb155480 				break;
17885935Ssb155480 		}
17895373Sraghuram 
17905373Sraghuram 		D2(vswp, "%s: (chan %lld) leaving milestone 2",
17915373Sraghuram 		    __func__, ldcp->ldc_id);
17925373Sraghuram 
17935373Sraghuram 		ldcp->hphase = VSW_MILESTONE3;
17945373Sraghuram 		vsw_send_rdx(ldcp);
17955373Sraghuram 		break;
17965373Sraghuram 
17975373Sraghuram 	case VSW_MILESTONE3:
17985373Sraghuram 		/*
17995373Sraghuram 		 * Pass this milestone when all paramaters have been
18005373Sraghuram 		 * successfully exchanged and RDX sent in both directions.
18015373Sraghuram 		 *
180212011SSriharsha.Basavapatna@Sun.COM 		 * Mark the relevant lane as available to transmit data. In
180312011SSriharsha.Basavapatna@Sun.COM 		 * RxDringData mode, lane_in is associated with transmit and
180412011SSriharsha.Basavapatna@Sun.COM 		 * lane_out is associated with receive. It is the reverse in
180512011SSriharsha.Basavapatna@Sun.COM 		 * TxDring mode.
18065373Sraghuram 		 */
180712011SSriharsha.Basavapatna@Sun.COM 		if ((lane_out->lstate & VSW_RDX_ACK_SENT) &&
180812011SSriharsha.Basavapatna@Sun.COM 		    (lane_in->lstate & VSW_RDX_ACK_RECV)) {
18095373Sraghuram 
18105373Sraghuram 			D2(vswp, "%s: (chan %lld) leaving milestone 3",
18115373Sraghuram 			    __func__, ldcp->ldc_id);
18125373Sraghuram 			D2(vswp, "%s: ** handshake complete (0x%llx : "
181312011SSriharsha.Basavapatna@Sun.COM 			    "0x%llx) **", __func__, lane_in->lstate,
181412011SSriharsha.Basavapatna@Sun.COM 			    lane_out->lstate);
181512011SSriharsha.Basavapatna@Sun.COM 			if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
181612011SSriharsha.Basavapatna@Sun.COM 				lane_in->lstate |= VSW_LANE_ACTIVE;
181712011SSriharsha.Basavapatna@Sun.COM 			} else {
181812011SSriharsha.Basavapatna@Sun.COM 				lane_out->lstate |= VSW_LANE_ACTIVE;
181912011SSriharsha.Basavapatna@Sun.COM 			}
18205373Sraghuram 			ldcp->hphase = VSW_MILESTONE4;
18215373Sraghuram 			ldcp->hcnt = 0;
18225373Sraghuram 			DISPLAY_STATE();
18236495Sspeer 			/* Start HIO if enabled and capable */
18246495Sspeer 			if ((portp->p_hio_enabled) && (portp->p_hio_capable)) {
18256495Sspeer 				D2(vswp, "%s: start HybridIO setup", __func__);
18266495Sspeer 				vsw_hio_start(vswp, ldcp);
18276495Sspeer 			}
18289336SSriharsha.Basavapatna@Sun.COM 
18299336SSriharsha.Basavapatna@Sun.COM 			if (ldcp->pls_negotiated == B_TRUE) {
18309336SSriharsha.Basavapatna@Sun.COM 				/*
18319336SSriharsha.Basavapatna@Sun.COM 				 * The vnet device has negotiated to get phys
18329336SSriharsha.Basavapatna@Sun.COM 				 * link updates. Now that the handshake with
18339336SSriharsha.Basavapatna@Sun.COM 				 * the vnet device is complete, send an initial
18349336SSriharsha.Basavapatna@Sun.COM 				 * update with the current physical link state.
18359336SSriharsha.Basavapatna@Sun.COM 				 */
18369336SSriharsha.Basavapatna@Sun.COM 				vsw_send_physlink_msg(ldcp,
18379336SSriharsha.Basavapatna@Sun.COM 				    vswp->phys_link_state);
18389336SSriharsha.Basavapatna@Sun.COM 			}
18399336SSriharsha.Basavapatna@Sun.COM 
18405373Sraghuram 		} else {
18415373Sraghuram 			D2(vswp, "%s: still in milestone 3 (0x%llx : 0x%llx)",
184212011SSriharsha.Basavapatna@Sun.COM 			    __func__, lane_in->lstate,
184312011SSriharsha.Basavapatna@Sun.COM 			    lane_out->lstate);
18445373Sraghuram 		}
18455373Sraghuram 		break;
18465373Sraghuram 
18475373Sraghuram 	case VSW_MILESTONE4:
18485373Sraghuram 		D2(vswp, "%s: (chan %lld) in milestone 4", __func__,
18495373Sraghuram 		    ldcp->ldc_id);
18505373Sraghuram 		break;
18515373Sraghuram 
18525373Sraghuram 	default:
18535373Sraghuram 		DERR(vswp, "%s: (chan %lld) Unknown Phase %x", __func__,
18545373Sraghuram 		    ldcp->ldc_id, ldcp->hphase);
18555373Sraghuram 	}
18565373Sraghuram 
18575373Sraghuram 	D1(vswp, "%s (chan %lld): exit (phase %ld)", __func__, ldcp->ldc_id,
18585373Sraghuram 	    ldcp->hphase);
18595373Sraghuram }
18605373Sraghuram 
18615373Sraghuram /*
18625373Sraghuram  * Check if major version is supported.
18635373Sraghuram  *
18645373Sraghuram  * Returns 0 if finds supported major number, and if necessary
18655373Sraghuram  * adjusts the minor field.
18665373Sraghuram  *
18675373Sraghuram  * Returns 1 if can't match major number exactly. Sets mjor/minor
18685373Sraghuram  * to next lowest support values, or to zero if no other values possible.
18695373Sraghuram  */
18705373Sraghuram static int
vsw_supported_version(vio_ver_msg_t * vp)18715373Sraghuram vsw_supported_version(vio_ver_msg_t *vp)
18725373Sraghuram {
18735373Sraghuram 	int	i;
18745373Sraghuram 
18755373Sraghuram 	D1(NULL, "vsw_supported_version: enter");
18765373Sraghuram 
18775373Sraghuram 	for (i = 0; i < VSW_NUM_VER; i++) {
18785373Sraghuram 		if (vsw_versions[i].ver_major == vp->ver_major) {
18795373Sraghuram 			/*
18805373Sraghuram 			 * Matching or lower major version found. Update
18815373Sraghuram 			 * minor number if necessary.
18825373Sraghuram 			 */
18835373Sraghuram 			if (vp->ver_minor > vsw_versions[i].ver_minor) {
18845373Sraghuram 				D2(NULL, "%s: adjusting minor value from %d "
18855373Sraghuram 				    "to %d", __func__, vp->ver_minor,
18865373Sraghuram 				    vsw_versions[i].ver_minor);
18875373Sraghuram 				vp->ver_minor = vsw_versions[i].ver_minor;
18885373Sraghuram 			}
18895373Sraghuram 
18905373Sraghuram 			return (0);
18915373Sraghuram 		}
18925373Sraghuram 
18935935Ssb155480 		/*
18945935Ssb155480 		 * If the message contains a higher major version number, set
18955935Ssb155480 		 * the message's major/minor versions to the current values
18965935Ssb155480 		 * and return false, so this message will get resent with
18975935Ssb155480 		 * these values.
18985935Ssb155480 		 */
18995373Sraghuram 		if (vsw_versions[i].ver_major < vp->ver_major) {
19005935Ssb155480 			D2(NULL, "%s: adjusting major and minor "
19015935Ssb155480 			    "values to %d, %d\n",
19025935Ssb155480 			    __func__, vsw_versions[i].ver_major,
19035935Ssb155480 			    vsw_versions[i].ver_minor);
19045935Ssb155480 			vp->ver_major = vsw_versions[i].ver_major;
19055935Ssb155480 			vp->ver_minor = vsw_versions[i].ver_minor;
19065373Sraghuram 			return (1);
19075373Sraghuram 		}
19085373Sraghuram 	}
19095373Sraghuram 
19105373Sraghuram 	/* No match was possible, zero out fields */
19115373Sraghuram 	vp->ver_major = 0;
19125373Sraghuram 	vp->ver_minor = 0;
19135373Sraghuram 
19145373Sraghuram 	D1(NULL, "vsw_supported_version: exit");
19155373Sraghuram 
19165373Sraghuram 	return (1);
19175373Sraghuram }
19185373Sraghuram 
19195373Sraghuram /*
19205935Ssb155480  * Set vnet-protocol-version dependent functions based on version.
19215935Ssb155480  */
19225935Ssb155480 static void
vsw_set_vnet_proto_ops(vsw_ldc_t * ldcp)19235935Ssb155480 vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp)
19245935Ssb155480 {
19255935Ssb155480 	vsw_t	*vswp = ldcp->ldc_vswp;
19265935Ssb155480 	lane_t	*lp = &ldcp->lane_out;
19275935Ssb155480 
192812011SSriharsha.Basavapatna@Sun.COM 	/*
192912011SSriharsha.Basavapatna@Sun.COM 	 * Setup the appropriate dring data processing routine and any
193012011SSriharsha.Basavapatna@Sun.COM 	 * associated thread based on the version.
193112011SSriharsha.Basavapatna@Sun.COM 	 *
193212011SSriharsha.Basavapatna@Sun.COM 	 * In versions < 1.6, we support only TxDring mode. In this mode, the
193312011SSriharsha.Basavapatna@Sun.COM 	 * msg worker thread processes all types of VIO msgs (ctrl and data).
193412011SSriharsha.Basavapatna@Sun.COM 	 *
193512011SSriharsha.Basavapatna@Sun.COM 	 * In versions >= 1.6, we also support RxDringData mode. In this mode,
193612011SSriharsha.Basavapatna@Sun.COM 	 * the rcv worker thread processes dring data messages (msgtype:
193712011SSriharsha.Basavapatna@Sun.COM 	 * VIO_TYPE_DATA, subtype: VIO_SUBTYPE_INFO, env: VIO_DRING_DATA). The
193812011SSriharsha.Basavapatna@Sun.COM 	 * rest of the data messages (including acks) and ctrl messages are
193912011SSriharsha.Basavapatna@Sun.COM 	 * handled directly by the callback (intr) thread.
194012011SSriharsha.Basavapatna@Sun.COM 	 *
194112011SSriharsha.Basavapatna@Sun.COM 	 * However, for versions >= 1.6, we could still fallback to TxDring
194212011SSriharsha.Basavapatna@Sun.COM 	 * mode. This could happen if RxDringData mode has been disabled (see
1943*13098SWentao.Yang@Sun.COM 	 * below) on this guest or on the peer guest. This info is determined
1944*13098SWentao.Yang@Sun.COM 	 * as part of attr exchange phase of handshake. Hence, we setup these
1945*13098SWentao.Yang@Sun.COM 	 * pointers for v1.6 after attr msg phase completes during handshake.
194612011SSriharsha.Basavapatna@Sun.COM 	 */
194712011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 6)) {
194812011SSriharsha.Basavapatna@Sun.COM 		/*
194912011SSriharsha.Basavapatna@Sun.COM 		 * Set data dring mode for vsw_send_attr(). We setup msg worker
195012011SSriharsha.Basavapatna@Sun.COM 		 * thread in TxDring mode or rcv worker thread in RxDringData
195112011SSriharsha.Basavapatna@Sun.COM 		 * mode when attr phase of handshake completes.
195212011SSriharsha.Basavapatna@Sun.COM 		 */
1953*13098SWentao.Yang@Sun.COM 		if (vsw_mapin_avail(ldcp) == B_TRUE) {
195412011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING);
195512011SSriharsha.Basavapatna@Sun.COM 		} else {
195612011SSriharsha.Basavapatna@Sun.COM 			lp->dring_mode = VIO_TX_DRING;
195712011SSriharsha.Basavapatna@Sun.COM 		}
195812011SSriharsha.Basavapatna@Sun.COM 	} else {
195912011SSriharsha.Basavapatna@Sun.COM 		lp->dring_mode = VIO_TX_DRING;
196012011SSriharsha.Basavapatna@Sun.COM 	}
196112011SSriharsha.Basavapatna@Sun.COM 
196212011SSriharsha.Basavapatna@Sun.COM 	/*
196312011SSriharsha.Basavapatna@Sun.COM 	 * Setup the MTU for attribute negotiation based on the version.
196412011SSriharsha.Basavapatna@Sun.COM 	 */
19657529SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 4)) {
19666419Ssb155480 		/*
19677529SSriharsha.Basavapatna@Sun.COM 		 * If the version negotiated with peer is >= 1.4(Jumbo Frame
19687529SSriharsha.Basavapatna@Sun.COM 		 * Support), set the mtu in our attributes to max_frame_size.
19696419Ssb155480 		 */
19706419Ssb155480 		lp->mtu = vswp->max_frame_size;
19717529SSriharsha.Basavapatna@Sun.COM 	} else if (VSW_VER_EQ(ldcp, 1, 3)) {
19727529SSriharsha.Basavapatna@Sun.COM 		/*
19737529SSriharsha.Basavapatna@Sun.COM 		 * If the version negotiated with peer is == 1.3 (Vlan Tag
19747529SSriharsha.Basavapatna@Sun.COM 		 * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ.
19757529SSriharsha.Basavapatna@Sun.COM 		 */
19767529SSriharsha.Basavapatna@Sun.COM 		lp->mtu = ETHERMAX + VLAN_TAGSZ;
19776419Ssb155480 	} else {
19786419Ssb155480 		vsw_port_t	*portp = ldcp->ldc_port;
19796419Ssb155480 		/*
19806419Ssb155480 		 * Pre-1.3 peers expect max frame size of ETHERMAX.
19817529SSriharsha.Basavapatna@Sun.COM 		 * We can negotiate that size with those peers provided only
19827529SSriharsha.Basavapatna@Sun.COM 		 * pvid is defined for our peer and there are no vids. Then we
19837529SSriharsha.Basavapatna@Sun.COM 		 * can send/recv only untagged frames of max size ETHERMAX.
19847529SSriharsha.Basavapatna@Sun.COM 		 * Note that pvid of the peer can be different, as vsw has to
19857529SSriharsha.Basavapatna@Sun.COM 		 * serve the vnet in that vlan even if itself is not assigned
19867529SSriharsha.Basavapatna@Sun.COM 		 * to that vlan.
19876419Ssb155480 		 */
19887529SSriharsha.Basavapatna@Sun.COM 		if (portp->nvids == 0) {
19896419Ssb155480 			lp->mtu = ETHERMAX;
19906419Ssb155480 		}
19916419Ssb155480 	}
19926419Ssb155480 
199312011SSriharsha.Basavapatna@Sun.COM 	/*
199412011SSriharsha.Basavapatna@Sun.COM 	 * Setup version dependent data processing functions.
199512011SSriharsha.Basavapatna@Sun.COM 	 */
19966419Ssb155480 	if (VSW_VER_GTEQ(ldcp, 1, 2)) {
19976419Ssb155480 		/* Versions >= 1.2 */
19985935Ssb155480 
19995935Ssb155480 		if (VSW_PRI_ETH_DEFINED(vswp)) {
20005935Ssb155480 			/*
20015935Ssb155480 			 * enable priority routines and pkt mode only if
20025935Ssb155480 			 * at least one pri-eth-type is specified in MD.
20035935Ssb155480 			 */
20045935Ssb155480 			ldcp->tx = vsw_ldctx_pri;
20055935Ssb155480 			ldcp->rx_pktdata = vsw_process_pkt_data;
20065935Ssb155480 
20075935Ssb155480 			/* set xfer mode for vsw_send_attr() */
20085935Ssb155480 			lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
20095935Ssb155480 		} else {
20105935Ssb155480 			/* no priority eth types defined in MD */
20115935Ssb155480 
20125935Ssb155480 			ldcp->tx = vsw_ldctx;
20135935Ssb155480 			ldcp->rx_pktdata = vsw_process_pkt_data_nop;
20145935Ssb155480 
20155935Ssb155480 			/* set xfer mode for vsw_send_attr() */
20165935Ssb155480 			lp->xfer_mode = VIO_DRING_MODE_V1_2;
20175935Ssb155480 		}
20186419Ssb155480 
20195935Ssb155480 	} else {
20205935Ssb155480 		/* Versions prior to 1.2  */
20215935Ssb155480 
20225935Ssb155480 		vsw_reset_vnet_proto_ops(ldcp);
20235935Ssb155480 	}
20245935Ssb155480 }
20255935Ssb155480 
20265935Ssb155480 /*
20275935Ssb155480  * Reset vnet-protocol-version dependent functions to v1.0.
20285935Ssb155480  */
20295935Ssb155480 static void
vsw_reset_vnet_proto_ops(vsw_ldc_t * ldcp)20305935Ssb155480 vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp)
20315935Ssb155480 {
20325935Ssb155480 	lane_t	*lp = &ldcp->lane_out;
20335935Ssb155480 
20345935Ssb155480 	ldcp->tx = vsw_ldctx;
20355935Ssb155480 	ldcp->rx_pktdata = vsw_process_pkt_data_nop;
20365935Ssb155480 
20375935Ssb155480 	/* set xfer mode for vsw_send_attr() */
20385935Ssb155480 	lp->xfer_mode = VIO_DRING_MODE_V1_0;
20395935Ssb155480 }
20405935Ssb155480 
204112011SSriharsha.Basavapatna@Sun.COM static void
vsw_process_evt_read(vsw_ldc_t * ldcp)204212011SSriharsha.Basavapatna@Sun.COM vsw_process_evt_read(vsw_ldc_t *ldcp)
204312011SSriharsha.Basavapatna@Sun.COM {
204412011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->msg_thread != NULL) {
204512011SSriharsha.Basavapatna@Sun.COM 		/*
204612011SSriharsha.Basavapatna@Sun.COM 		 * TxDring mode; wakeup message worker
204712011SSriharsha.Basavapatna@Sun.COM 		 * thread to process the VIO messages.
204812011SSriharsha.Basavapatna@Sun.COM 		 */
204912011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->ldc_cblock);
205012011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->msg_thr_lock);
205112011SSriharsha.Basavapatna@Sun.COM 		if (!(ldcp->msg_thr_flags & VSW_WTHR_DATARCVD)) {
205212011SSriharsha.Basavapatna@Sun.COM 			ldcp->msg_thr_flags |= VSW_WTHR_DATARCVD;
205312011SSriharsha.Basavapatna@Sun.COM 			cv_signal(&ldcp->msg_thr_cv);
205412011SSriharsha.Basavapatna@Sun.COM 		}
205512011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->msg_thr_lock);
205612011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->ldc_cblock);
205712011SSriharsha.Basavapatna@Sun.COM 	} else {
205812011SSriharsha.Basavapatna@Sun.COM 		/*
205912011SSriharsha.Basavapatna@Sun.COM 		 * We invoke vsw_process_pkt() in the context of the LDC
206012011SSriharsha.Basavapatna@Sun.COM 		 * callback (vsw_ldc_cb()) during handshake, until the dring
206112011SSriharsha.Basavapatna@Sun.COM 		 * mode is negotiated. After the dring mode is negotiated, the
206212011SSriharsha.Basavapatna@Sun.COM 		 * msgs are processed by the msg worker thread (above case) if
206312011SSriharsha.Basavapatna@Sun.COM 		 * the dring mode is TxDring. Otherwise (in RxDringData mode)
206412011SSriharsha.Basavapatna@Sun.COM 		 * we continue to process the msgs directly in the callback
206512011SSriharsha.Basavapatna@Sun.COM 		 * context.
206612011SSriharsha.Basavapatna@Sun.COM 		 */
206712011SSriharsha.Basavapatna@Sun.COM 		vsw_process_pkt(ldcp);
206812011SSriharsha.Basavapatna@Sun.COM 	}
206912011SSriharsha.Basavapatna@Sun.COM }
207012011SSriharsha.Basavapatna@Sun.COM 
20715935Ssb155480 /*
20725373Sraghuram  * Main routine for processing messages received over LDC.
20735373Sraghuram  */
207412011SSriharsha.Basavapatna@Sun.COM void
vsw_process_pkt(void * arg)20755373Sraghuram vsw_process_pkt(void *arg)
20765373Sraghuram {
20775373Sraghuram 	vsw_ldc_t	*ldcp = (vsw_ldc_t  *)arg;
20785373Sraghuram 	vsw_t 		*vswp = ldcp->ldc_vswp;
20795373Sraghuram 	size_t		msglen;
20805935Ssb155480 	vio_msg_tag_t	*tagp;
20815935Ssb155480 	uint64_t	*ldcmsg;
20825373Sraghuram 	int 		rv = 0;
20835373Sraghuram 
20845373Sraghuram 
20855373Sraghuram 	D1(vswp, "%s enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
20865373Sraghuram 
20875373Sraghuram 	ASSERT(MUTEX_HELD(&ldcp->ldc_cblock));
20885373Sraghuram 
20895935Ssb155480 	ldcmsg = ldcp->ldcmsg;
20905373Sraghuram 	/*
20915373Sraghuram 	 * If channel is up read messages until channel is empty.
20925373Sraghuram 	 */
20935373Sraghuram 	do {
20945935Ssb155480 		msglen = ldcp->msglen;
20955935Ssb155480 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
20965373Sraghuram 
20975373Sraghuram 		if (rv != 0) {
20985373Sraghuram 			DERR(vswp, "%s :ldc_read err id(%lld) rv(%d) len(%d)\n",
20995373Sraghuram 			    __func__, ldcp->ldc_id, rv, msglen);
21005373Sraghuram 		}
21015373Sraghuram 
21025373Sraghuram 		/* channel has been reset */
21035373Sraghuram 		if (rv == ECONNRESET) {
21045373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
21055373Sraghuram 			break;
21065373Sraghuram 		}
21075373Sraghuram 
21085373Sraghuram 		if (msglen == 0) {
21095373Sraghuram 			D2(vswp, "%s: ldc_read id(%lld) NODATA", __func__,
21105373Sraghuram 			    ldcp->ldc_id);
21115373Sraghuram 			break;
21125373Sraghuram 		}
21135373Sraghuram 
21145373Sraghuram 		D2(vswp, "%s: ldc_read id(%lld): msglen(%d)", __func__,
21155373Sraghuram 		    ldcp->ldc_id, msglen);
21165373Sraghuram 
21175373Sraghuram 		/*
21185373Sraghuram 		 * Figure out what sort of packet we have gotten by
21195373Sraghuram 		 * examining the msg tag, and then switch it appropriately.
21205373Sraghuram 		 */
21215935Ssb155480 		tagp = (vio_msg_tag_t *)ldcmsg;
21225935Ssb155480 
21235935Ssb155480 		switch (tagp->vio_msgtype) {
21245373Sraghuram 		case VIO_TYPE_CTRL:
212512011SSriharsha.Basavapatna@Sun.COM 			vsw_dispatch_ctrl_task(ldcp, ldcmsg, tagp, msglen);
21265373Sraghuram 			break;
21275373Sraghuram 		case VIO_TYPE_DATA:
21285935Ssb155480 			vsw_process_data_pkt(ldcp, ldcmsg, tagp, msglen);
21295373Sraghuram 			break;
21305373Sraghuram 		case VIO_TYPE_ERR:
21315935Ssb155480 			vsw_process_err_pkt(ldcp, ldcmsg, tagp);
21325373Sraghuram 			break;
21335373Sraghuram 		default:
21345373Sraghuram 			DERR(vswp, "%s: Unknown tag(%lx) ", __func__,
21355935Ssb155480 			    "id(%lx)\n", tagp->vio_msgtype, ldcp->ldc_id);
21365373Sraghuram 			break;
21375373Sraghuram 		}
21385373Sraghuram 	} while (msglen);
21395373Sraghuram 
21405373Sraghuram 	D1(vswp, "%s exit: ldcid (%lld)\n", __func__, ldcp->ldc_id);
21415373Sraghuram }
21425373Sraghuram 
21435373Sraghuram /*
21445373Sraghuram  * Dispatch a task to process a VIO control message.
21455373Sraghuram  */
21465373Sraghuram static void
vsw_dispatch_ctrl_task(vsw_ldc_t * ldcp,void * cpkt,vio_msg_tag_t * tagp,int msglen)214712011SSriharsha.Basavapatna@Sun.COM vsw_dispatch_ctrl_task(vsw_ldc_t *ldcp, void *cpkt, vio_msg_tag_t *tagp,
214812011SSriharsha.Basavapatna@Sun.COM 	int msglen)
21495373Sraghuram {
21505373Sraghuram 	vsw_ctrl_task_t		*ctaskp = NULL;
21515373Sraghuram 	vsw_port_t		*port = ldcp->ldc_port;
21525373Sraghuram 	vsw_t			*vswp = port->p_vswp;
21535373Sraghuram 
21545373Sraghuram 	D1(vswp, "%s: enter", __func__);
21555373Sraghuram 
21565373Sraghuram 	/*
21575373Sraghuram 	 * We need to handle RDX ACK messages in-band as once they
21585373Sraghuram 	 * are exchanged it is possible that we will get an
21595373Sraghuram 	 * immediate (legitimate) data packet.
21605373Sraghuram 	 */
21615935Ssb155480 	if ((tagp->vio_subtype_env == VIO_RDX) &&
21625935Ssb155480 	    (tagp->vio_subtype == VIO_SUBTYPE_ACK)) {
21635373Sraghuram 
21645373Sraghuram 		if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_ACK_RECV))
21655373Sraghuram 			return;
21665373Sraghuram 
21675373Sraghuram 		ldcp->lane_in.lstate |= VSW_RDX_ACK_RECV;
21685373Sraghuram 		D2(vswp, "%s (%ld) handling RDX_ACK in place "
21695373Sraghuram 		    "(ostate 0x%llx : hphase %d)", __func__,
21705373Sraghuram 		    ldcp->ldc_id, ldcp->lane_in.lstate, ldcp->hphase);
21715373Sraghuram 		vsw_next_milestone(ldcp);
21725373Sraghuram 		return;
21735373Sraghuram 	}
21745373Sraghuram 
21755373Sraghuram 	ctaskp = kmem_alloc(sizeof (vsw_ctrl_task_t), KM_NOSLEEP);
21765373Sraghuram 
21775373Sraghuram 	if (ctaskp == NULL) {
21785373Sraghuram 		DERR(vswp, "%s: unable to alloc space for ctrl msg", __func__);
21795373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
21805373Sraghuram 		return;
21815373Sraghuram 	}
21825373Sraghuram 
21835373Sraghuram 	ctaskp->ldcp = ldcp;
218412011SSriharsha.Basavapatna@Sun.COM 	bcopy((def_msg_t *)cpkt, &ctaskp->pktp, msglen);
21855373Sraghuram 	ctaskp->hss_id = ldcp->hss_id;
21865373Sraghuram 
21875373Sraghuram 	/*
21885373Sraghuram 	 * Dispatch task to processing taskq if port is not in
21895373Sraghuram 	 * the process of being detached.
21905373Sraghuram 	 */
21915373Sraghuram 	mutex_enter(&port->state_lock);
21925373Sraghuram 	if (port->state == VSW_PORT_INIT) {
21935373Sraghuram 		if ((vswp->taskq_p == NULL) ||
21945373Sraghuram 		    (ddi_taskq_dispatch(vswp->taskq_p, vsw_process_ctrl_pkt,
21955373Sraghuram 		    ctaskp, DDI_NOSLEEP) != DDI_SUCCESS)) {
21967481SWentao.Yang@Sun.COM 			mutex_exit(&port->state_lock);
21975373Sraghuram 			DERR(vswp, "%s: unable to dispatch task to taskq",
21985373Sraghuram 			    __func__);
21997481SWentao.Yang@Sun.COM 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
22005373Sraghuram 			kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22015373Sraghuram 			return;
22025373Sraghuram 		}
22035373Sraghuram 	} else {
22047481SWentao.Yang@Sun.COM 		kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22055373Sraghuram 		DWARN(vswp, "%s: port %d detaching, not dispatching "
22065373Sraghuram 		    "task", __func__, port->p_instance);
22075373Sraghuram 	}
22085373Sraghuram 
22095373Sraghuram 	mutex_exit(&port->state_lock);
22105373Sraghuram 
22115373Sraghuram 	D2(vswp, "%s: dispatched task to taskq for chan %d", __func__,
22125373Sraghuram 	    ldcp->ldc_id);
22135373Sraghuram 	D1(vswp, "%s: exit", __func__);
22145373Sraghuram }
22155373Sraghuram 
22165373Sraghuram /*
22175373Sraghuram  * Process a VIO ctrl message. Invoked from taskq.
22185373Sraghuram  */
22195373Sraghuram static void
vsw_process_ctrl_pkt(void * arg)22205373Sraghuram vsw_process_ctrl_pkt(void *arg)
22215373Sraghuram {
22225373Sraghuram 	vsw_ctrl_task_t	*ctaskp = (vsw_ctrl_task_t *)arg;
22235373Sraghuram 	vsw_ldc_t	*ldcp = ctaskp->ldcp;
22245373Sraghuram 	vsw_t 		*vswp = ldcp->ldc_vswp;
22255373Sraghuram 	vio_msg_tag_t	tag;
22265373Sraghuram 	uint16_t	env;
22275373Sraghuram 
22285373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
22295373Sraghuram 
22305373Sraghuram 	bcopy(&ctaskp->pktp, &tag, sizeof (vio_msg_tag_t));
22315373Sraghuram 	env = tag.vio_subtype_env;
22325373Sraghuram 
22335373Sraghuram 	/* stale pkt check */
22345373Sraghuram 	if (ctaskp->hss_id < ldcp->hss_id) {
22355373Sraghuram 		DWARN(vswp, "%s: discarding stale packet belonging to earlier"
22365373Sraghuram 		    " (%ld) handshake session", __func__, ctaskp->hss_id);
22377481SWentao.Yang@Sun.COM 		kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22385373Sraghuram 		return;
22395373Sraghuram 	}
22405373Sraghuram 
22415373Sraghuram 	/* session id check */
22425373Sraghuram 	if (ldcp->session_status & VSW_PEER_SESSION) {
22435373Sraghuram 		if (ldcp->peer_session != tag.vio_sid) {
22445373Sraghuram 			DERR(vswp, "%s (chan %d): invalid session id (%llx)",
22455373Sraghuram 			    __func__, ldcp->ldc_id, tag.vio_sid);
22465373Sraghuram 			kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22475373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
22485373Sraghuram 			return;
22495373Sraghuram 		}
22505373Sraghuram 	}
22515373Sraghuram 
22525373Sraghuram 	/*
22535373Sraghuram 	 * Switch on vio_subtype envelope, then let lower routines
22545373Sraghuram 	 * decide if its an INFO, ACK or NACK packet.
22555373Sraghuram 	 */
22565373Sraghuram 	switch (env) {
22575373Sraghuram 	case VIO_VER_INFO:
22585373Sraghuram 		vsw_process_ctrl_ver_pkt(ldcp, &ctaskp->pktp);
22595373Sraghuram 		break;
22605373Sraghuram 	case VIO_DRING_REG:
22615373Sraghuram 		vsw_process_ctrl_dring_reg_pkt(ldcp, &ctaskp->pktp);
22625373Sraghuram 		break;
22635373Sraghuram 	case VIO_DRING_UNREG:
22645373Sraghuram 		vsw_process_ctrl_dring_unreg_pkt(ldcp, &ctaskp->pktp);
22655373Sraghuram 		break;
22665373Sraghuram 	case VIO_ATTR_INFO:
22675373Sraghuram 		vsw_process_ctrl_attr_pkt(ldcp, &ctaskp->pktp);
22685373Sraghuram 		break;
22695373Sraghuram 	case VNET_MCAST_INFO:
22705373Sraghuram 		vsw_process_ctrl_mcst_pkt(ldcp, &ctaskp->pktp);
22715373Sraghuram 		break;
22725373Sraghuram 	case VIO_RDX:
22735373Sraghuram 		vsw_process_ctrl_rdx_pkt(ldcp, &ctaskp->pktp);
22745373Sraghuram 		break;
22756495Sspeer 	case VIO_DDS_INFO:
22766495Sspeer 		vsw_process_dds_msg(vswp, ldcp, &ctaskp->pktp);
22776495Sspeer 		break;
22789336SSriharsha.Basavapatna@Sun.COM 
22799336SSriharsha.Basavapatna@Sun.COM 	case VNET_PHYSLINK_INFO:
22809336SSriharsha.Basavapatna@Sun.COM 		vsw_process_physlink_msg(ldcp, &ctaskp->pktp);
22819336SSriharsha.Basavapatna@Sun.COM 		break;
22825373Sraghuram 	default:
22835373Sraghuram 		DERR(vswp, "%s: unknown vio_subtype_env (%x)\n", __func__, env);
22845373Sraghuram 	}
22855373Sraghuram 
22865373Sraghuram 	kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22875373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
22885373Sraghuram }
22895373Sraghuram 
22905373Sraghuram /*
22915373Sraghuram  * Version negotiation. We can end up here either because our peer
22925373Sraghuram  * has responded to a handshake message we have sent it, or our peer
22935373Sraghuram  * has initiated a handshake with us. If its the former then can only
22945373Sraghuram  * be ACK or NACK, if its the later can only be INFO.
22955373Sraghuram  *
22965373Sraghuram  * If its an ACK we move to the next stage of the handshake, namely
22975373Sraghuram  * attribute exchange. If its a NACK we see if we can specify another
22985373Sraghuram  * version, if we can't we stop.
22995373Sraghuram  *
23005373Sraghuram  * If it is an INFO we reset all params associated with communication
23015373Sraghuram  * in that direction over this channel (remember connection is
23025373Sraghuram  * essentially 2 independent simplex channels).
23035373Sraghuram  */
23045373Sraghuram void
vsw_process_ctrl_ver_pkt(vsw_ldc_t * ldcp,void * pkt)23055373Sraghuram vsw_process_ctrl_ver_pkt(vsw_ldc_t *ldcp, void *pkt)
23065373Sraghuram {
23075373Sraghuram 	vio_ver_msg_t	*ver_pkt;
23085373Sraghuram 	vsw_t 		*vswp = ldcp->ldc_vswp;
23095373Sraghuram 
23105373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
23115373Sraghuram 
23125373Sraghuram 	/*
23135373Sraghuram 	 * We know this is a ctrl/version packet so
23145373Sraghuram 	 * cast it into the correct structure.
23155373Sraghuram 	 */
23165373Sraghuram 	ver_pkt = (vio_ver_msg_t *)pkt;
23175373Sraghuram 
23185373Sraghuram 	switch (ver_pkt->tag.vio_subtype) {
23195373Sraghuram 	case VIO_SUBTYPE_INFO:
23205373Sraghuram 		D2(vswp, "vsw_process_ctrl_ver_pkt: VIO_SUBTYPE_INFO\n");
23215373Sraghuram 
23225373Sraghuram 		/*
23235373Sraghuram 		 * Record the session id, which we will use from now
23245373Sraghuram 		 * until we see another VER_INFO msg. Even then the
23255373Sraghuram 		 * session id in most cases will be unchanged, execpt
23265373Sraghuram 		 * if channel was reset.
23275373Sraghuram 		 */
23285373Sraghuram 		if ((ldcp->session_status & VSW_PEER_SESSION) &&
23295373Sraghuram 		    (ldcp->peer_session != ver_pkt->tag.vio_sid)) {
23305373Sraghuram 			DERR(vswp, "%s: updating session id for chan %lld "
23315373Sraghuram 			    "from %llx to %llx", __func__, ldcp->ldc_id,
23325373Sraghuram 			    ldcp->peer_session, ver_pkt->tag.vio_sid);
23335373Sraghuram 		}
23345373Sraghuram 
23355373Sraghuram 		ldcp->peer_session = ver_pkt->tag.vio_sid;
23365373Sraghuram 		ldcp->session_status |= VSW_PEER_SESSION;
23375373Sraghuram 
23385373Sraghuram 		/* Legal message at this time ? */
23395373Sraghuram 		if (vsw_check_flag(ldcp, INBOUND, VSW_VER_INFO_RECV))
23405373Sraghuram 			return;
23415373Sraghuram 
23425373Sraghuram 		/*
23435373Sraghuram 		 * First check the device class. Currently only expect
23445373Sraghuram 		 * to be talking to a network device. In the future may
23455373Sraghuram 		 * also talk to another switch.
23465373Sraghuram 		 */
23475373Sraghuram 		if (ver_pkt->dev_class != VDEV_NETWORK) {
23485373Sraghuram 			DERR(vswp, "%s: illegal device class %d", __func__,
23495373Sraghuram 			    ver_pkt->dev_class);
23505373Sraghuram 
23515373Sraghuram 			ver_pkt->tag.vio_sid = ldcp->local_session;
23525373Sraghuram 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
23535373Sraghuram 
23545373Sraghuram 			DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
23555373Sraghuram 
23565373Sraghuram 			(void) vsw_send_msg(ldcp, (void *)ver_pkt,
23575373Sraghuram 			    sizeof (vio_ver_msg_t), B_TRUE);
23585373Sraghuram 
23595373Sraghuram 			ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
23605373Sraghuram 			vsw_next_milestone(ldcp);
23615373Sraghuram 			return;
23625373Sraghuram 		} else {
23635373Sraghuram 			ldcp->dev_class = ver_pkt->dev_class;
23645373Sraghuram 		}
23655373Sraghuram 
23665373Sraghuram 		/*
23675373Sraghuram 		 * Now check the version.
23685373Sraghuram 		 */
23695373Sraghuram 		if (vsw_supported_version(ver_pkt) == 0) {
23705373Sraghuram 			/*
23715373Sraghuram 			 * Support this major version and possibly
23725373Sraghuram 			 * adjusted minor version.
23735373Sraghuram 			 */
23745373Sraghuram 
23755373Sraghuram 			D2(vswp, "%s: accepted ver %d:%d", __func__,
23765373Sraghuram 			    ver_pkt->ver_major, ver_pkt->ver_minor);
23775373Sraghuram 
23785373Sraghuram 			/* Store accepted values */
23795373Sraghuram 			ldcp->lane_in.ver_major = ver_pkt->ver_major;
23805373Sraghuram 			ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
23815373Sraghuram 
23825373Sraghuram 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
23835373Sraghuram 
23845373Sraghuram 			ldcp->lane_in.lstate |= VSW_VER_ACK_SENT;
23855935Ssb155480 
23865935Ssb155480 			if (vsw_obp_ver_proto_workaround == B_TRUE) {
23875935Ssb155480 				/*
23885935Ssb155480 				 * Send a version info message
23895935Ssb155480 				 * using the accepted version that
23905935Ssb155480 				 * we are about to ack. Also note that
23915935Ssb155480 				 * we send our ver info before we ack.
23925935Ssb155480 				 * Otherwise, as soon as receiving the
23935935Ssb155480 				 * ack, obp sends attr info msg, which
23945935Ssb155480 				 * breaks vsw_check_flag() invoked
23955935Ssb155480 				 * from vsw_process_ctrl_attr_pkt();
23965935Ssb155480 				 * as we also need VSW_VER_ACK_RECV to
23975935Ssb155480 				 * be set in lane_out.lstate, before
23985935Ssb155480 				 * we can receive attr info.
23995935Ssb155480 				 */
24005935Ssb155480 				vsw_send_ver(ldcp);
24015935Ssb155480 			}
24025373Sraghuram 		} else {
24035373Sraghuram 			/*
24045373Sraghuram 			 * NACK back with the next lower major/minor
24055373Sraghuram 			 * pairing we support (if don't suuport any more
24065373Sraghuram 			 * versions then they will be set to zero.
24075373Sraghuram 			 */
24085373Sraghuram 
24095373Sraghuram 			D2(vswp, "%s: replying with ver %d:%d", __func__,
24105373Sraghuram 			    ver_pkt->ver_major, ver_pkt->ver_minor);
24115373Sraghuram 
24125373Sraghuram 			/* Store updated values */
24135373Sraghuram 			ldcp->lane_in.ver_major = ver_pkt->ver_major;
24145373Sraghuram 			ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
24155373Sraghuram 
24165373Sraghuram 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
24175373Sraghuram 
24185373Sraghuram 			ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
24195373Sraghuram 		}
24205373Sraghuram 
24215373Sraghuram 		DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
24225373Sraghuram 		ver_pkt->tag.vio_sid = ldcp->local_session;
24235373Sraghuram 		(void) vsw_send_msg(ldcp, (void *)ver_pkt,
24245373Sraghuram 		    sizeof (vio_ver_msg_t), B_TRUE);
24255373Sraghuram 
24265373Sraghuram 		vsw_next_milestone(ldcp);
24275373Sraghuram 		break;
24285373Sraghuram 
24295373Sraghuram 	case VIO_SUBTYPE_ACK:
24305373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_ACK\n", __func__);
24315373Sraghuram 
24325373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_ACK_RECV))
24335373Sraghuram 			return;
24345373Sraghuram 
24355373Sraghuram 		/* Store updated values */
24365935Ssb155480 		ldcp->lane_out.ver_major = ver_pkt->ver_major;
24375935Ssb155480 		ldcp->lane_out.ver_minor = ver_pkt->ver_minor;
24385373Sraghuram 
24395373Sraghuram 		ldcp->lane_out.lstate |= VSW_VER_ACK_RECV;
24405373Sraghuram 		vsw_next_milestone(ldcp);
24415373Sraghuram 
24425373Sraghuram 		break;
24435373Sraghuram 
24445373Sraghuram 	case VIO_SUBTYPE_NACK:
24455373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_NACK\n", __func__);
24465373Sraghuram 
24475373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_NACK_RECV))
24485373Sraghuram 			return;
24495373Sraghuram 
24505373Sraghuram 		/*
24515373Sraghuram 		 * If our peer sent us a NACK with the ver fields set to
24525373Sraghuram 		 * zero then there is nothing more we can do. Otherwise see
24535373Sraghuram 		 * if we support either the version suggested, or a lesser
24545373Sraghuram 		 * one.
24555373Sraghuram 		 */
24565373Sraghuram 		if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
24575373Sraghuram 			DERR(vswp, "%s: peer unable to negotiate any "
24585373Sraghuram 			    "further.", __func__);
24595373Sraghuram 			ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
24605373Sraghuram 			vsw_next_milestone(ldcp);
24615373Sraghuram 			return;
24625373Sraghuram 		}
24635373Sraghuram 
24645373Sraghuram 		/*
24655373Sraghuram 		 * Check to see if we support this major version or
24665373Sraghuram 		 * a lower one. If we don't then maj/min will be set
24675373Sraghuram 		 * to zero.
24685373Sraghuram 		 */
24695373Sraghuram 		(void) vsw_supported_version(ver_pkt);
24705373Sraghuram 		if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
24715373Sraghuram 			/* Nothing more we can do */
24725373Sraghuram 			DERR(vswp, "%s: version negotiation failed.\n",
24735373Sraghuram 			    __func__);
24745373Sraghuram 			ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
24755373Sraghuram 			vsw_next_milestone(ldcp);
24765373Sraghuram 		} else {
24775373Sraghuram 			/* found a supported major version */
24785373Sraghuram 			ldcp->lane_out.ver_major = ver_pkt->ver_major;
24795373Sraghuram 			ldcp->lane_out.ver_minor = ver_pkt->ver_minor;
24805373Sraghuram 
24815373Sraghuram 			D2(vswp, "%s: resending with updated values (%x, %x)",
24825373Sraghuram 			    __func__, ver_pkt->ver_major, ver_pkt->ver_minor);
24835373Sraghuram 
24845373Sraghuram 			ldcp->lane_out.lstate |= VSW_VER_INFO_SENT;
24855373Sraghuram 			ver_pkt->tag.vio_sid = ldcp->local_session;
24865373Sraghuram 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
24875373Sraghuram 
24885373Sraghuram 			DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
24895373Sraghuram 
24905373Sraghuram 			(void) vsw_send_msg(ldcp, (void *)ver_pkt,
24915373Sraghuram 			    sizeof (vio_ver_msg_t), B_TRUE);
24925373Sraghuram 
24935373Sraghuram 			vsw_next_milestone(ldcp);
24945373Sraghuram 
24955373Sraghuram 		}
24965373Sraghuram 		break;
24975373Sraghuram 
24985373Sraghuram 	default:
24995373Sraghuram 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
25005373Sraghuram 		    ver_pkt->tag.vio_subtype);
25015373Sraghuram 	}
25025373Sraghuram 
25035373Sraghuram 	D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id);
25045373Sraghuram }
25055373Sraghuram 
250612011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_attr_info(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)250712011SSriharsha.Basavapatna@Sun.COM vsw_process_attr_info(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg)
250812011SSriharsha.Basavapatna@Sun.COM {
250912011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
251012011SSriharsha.Basavapatna@Sun.COM 	vsw_port_t		*port = ldcp->ldc_port;
251112011SSriharsha.Basavapatna@Sun.COM 	struct ether_addr	ea;
251212011SSriharsha.Basavapatna@Sun.COM 	uint64_t		macaddr = 0;
251312011SSriharsha.Basavapatna@Sun.COM 	lane_t			*lane_out = &ldcp->lane_out;
251412011SSriharsha.Basavapatna@Sun.COM 	lane_t			*lane_in = &ldcp->lane_in;
251512011SSriharsha.Basavapatna@Sun.COM 	uint32_t		mtu;
251612011SSriharsha.Basavapatna@Sun.COM 	int			i;
251712011SSriharsha.Basavapatna@Sun.COM 	uint8_t			dring_mode;
251812011SSriharsha.Basavapatna@Sun.COM 
251912011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
252012011SSriharsha.Basavapatna@Sun.COM 
252112011SSriharsha.Basavapatna@Sun.COM 	if (vsw_check_flag(ldcp, INBOUND, VSW_ATTR_INFO_RECV)) {
252212011SSriharsha.Basavapatna@Sun.COM 		return (1);
252312011SSriharsha.Basavapatna@Sun.COM 	}
252412011SSriharsha.Basavapatna@Sun.COM 
252512011SSriharsha.Basavapatna@Sun.COM 	if ((msg->xfer_mode != VIO_DESC_MODE) &&
252612011SSriharsha.Basavapatna@Sun.COM 	    (msg->xfer_mode != lane_out->xfer_mode)) {
252712011SSriharsha.Basavapatna@Sun.COM 		D2(NULL, "%s: unknown mode %x\n", __func__, msg->xfer_mode);
252812011SSriharsha.Basavapatna@Sun.COM 		return (1);
252912011SSriharsha.Basavapatna@Sun.COM 	}
253012011SSriharsha.Basavapatna@Sun.COM 
253112011SSriharsha.Basavapatna@Sun.COM 	/* Only support MAC addresses at moment. */
253212011SSriharsha.Basavapatna@Sun.COM 	if ((msg->addr_type != ADDR_TYPE_MAC) || (msg->addr == 0)) {
253312011SSriharsha.Basavapatna@Sun.COM 		D2(NULL, "%s: invalid addr_type %x, or address 0x%llx\n",
253412011SSriharsha.Basavapatna@Sun.COM 		    __func__, msg->addr_type, msg->addr);
253512011SSriharsha.Basavapatna@Sun.COM 		return (1);
253612011SSriharsha.Basavapatna@Sun.COM 	}
253712011SSriharsha.Basavapatna@Sun.COM 
253812011SSriharsha.Basavapatna@Sun.COM 	/*
253912011SSriharsha.Basavapatna@Sun.COM 	 * MAC address supplied by device should match that stored
254012011SSriharsha.Basavapatna@Sun.COM 	 * in the vsw-port OBP node. Need to decide what to do if they
254112011SSriharsha.Basavapatna@Sun.COM 	 * don't match, for the moment just warn but don't fail.
254212011SSriharsha.Basavapatna@Sun.COM 	 */
254312011SSriharsha.Basavapatna@Sun.COM 	vnet_macaddr_ultostr(msg->addr, ea.ether_addr_octet);
254412011SSriharsha.Basavapatna@Sun.COM 	if (ether_cmp(&ea, &port->p_macaddr) != 0) {
254512011SSriharsha.Basavapatna@Sun.COM 		DERR(NULL, "%s: device supplied address "
254612011SSriharsha.Basavapatna@Sun.COM 		    "0x%llx doesn't match node address 0x%llx\n",
254712011SSriharsha.Basavapatna@Sun.COM 		    __func__, msg->addr, port->p_macaddr);
254812011SSriharsha.Basavapatna@Sun.COM 	}
254912011SSriharsha.Basavapatna@Sun.COM 
255012011SSriharsha.Basavapatna@Sun.COM 	/*
255112011SSriharsha.Basavapatna@Sun.COM 	 * Ack freq only makes sense in pkt mode, in shared
255212011SSriharsha.Basavapatna@Sun.COM 	 * mode the ring descriptors say whether or not to
255312011SSriharsha.Basavapatna@Sun.COM 	 * send back an ACK.
255412011SSriharsha.Basavapatna@Sun.COM 	 */
255512011SSriharsha.Basavapatna@Sun.COM 	if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
255612011SSriharsha.Basavapatna@Sun.COM 	    (msg->xfer_mode & VIO_DRING_MODE_V1_2)) ||
255712011SSriharsha.Basavapatna@Sun.COM 	    (VSW_VER_LT(ldcp, 1, 2) &&
255812011SSriharsha.Basavapatna@Sun.COM 	    (msg->xfer_mode == VIO_DRING_MODE_V1_0))) {
255912011SSriharsha.Basavapatna@Sun.COM 		if (msg->ack_freq > 0) {
256012011SSriharsha.Basavapatna@Sun.COM 			D2(NULL, "%s: non zero ack freq in SHM mode\n",
256112011SSriharsha.Basavapatna@Sun.COM 			    __func__);
256212011SSriharsha.Basavapatna@Sun.COM 			return (1);
256312011SSriharsha.Basavapatna@Sun.COM 		}
256412011SSriharsha.Basavapatna@Sun.COM 	}
256512011SSriharsha.Basavapatna@Sun.COM 
256612011SSriharsha.Basavapatna@Sun.COM 	/*
256712011SSriharsha.Basavapatna@Sun.COM 	 * Process dring mode attribute.
256812011SSriharsha.Basavapatna@Sun.COM 	 */
256912011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 6)) {
257012011SSriharsha.Basavapatna@Sun.COM 		/*
257112011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.6:
257212011SSriharsha.Basavapatna@Sun.COM 		 * Though we are operating in v1.6 mode, it is possible that
257312011SSriharsha.Basavapatna@Sun.COM 		 * RxDringData mode has been disabled either on this guest or
257412011SSriharsha.Basavapatna@Sun.COM 		 * on the peer guest. If so, we revert to pre v1.6 behavior of
257512011SSriharsha.Basavapatna@Sun.COM 		 * TxDring mode. But this must be agreed upon in both
257612011SSriharsha.Basavapatna@Sun.COM 		 * directions of attr exchange. We first determine the mode
257712011SSriharsha.Basavapatna@Sun.COM 		 * that can be negotiated.
257812011SSriharsha.Basavapatna@Sun.COM 		 */
257912011SSriharsha.Basavapatna@Sun.COM 		if ((msg->options & VIO_RX_DRING_DATA) != 0 &&
2580*13098SWentao.Yang@Sun.COM 		    vsw_mapin_avail(ldcp) == B_TRUE) {
258112011SSriharsha.Basavapatna@Sun.COM 			/*
258212011SSriharsha.Basavapatna@Sun.COM 			 * The peer is capable of handling RxDringData AND we
258312011SSriharsha.Basavapatna@Sun.COM 			 * are also capable of it; we enable RxDringData mode
258412011SSriharsha.Basavapatna@Sun.COM 			 * on this channel.
258512011SSriharsha.Basavapatna@Sun.COM 			 */
258612011SSriharsha.Basavapatna@Sun.COM 			dring_mode = VIO_RX_DRING_DATA;
258712011SSriharsha.Basavapatna@Sun.COM 		} else if ((msg->options & VIO_TX_DRING) != 0) {
258812011SSriharsha.Basavapatna@Sun.COM 			/*
258912011SSriharsha.Basavapatna@Sun.COM 			 * If the peer is capable of TxDring mode, we
259012011SSriharsha.Basavapatna@Sun.COM 			 * negotiate TxDring mode on this channel.
259112011SSriharsha.Basavapatna@Sun.COM 			 */
259212011SSriharsha.Basavapatna@Sun.COM 			dring_mode = VIO_TX_DRING;
259312011SSriharsha.Basavapatna@Sun.COM 		} else {
259412011SSriharsha.Basavapatna@Sun.COM 			/*
259512011SSriharsha.Basavapatna@Sun.COM 			 * We support only VIO_TX_DRING and VIO_RX_DRING_DATA
259612011SSriharsha.Basavapatna@Sun.COM 			 * modes. We don't support VIO_RX_DRING mode.
259712011SSriharsha.Basavapatna@Sun.COM 			 */
259812011SSriharsha.Basavapatna@Sun.COM 			return (1);
259912011SSriharsha.Basavapatna@Sun.COM 		}
260012011SSriharsha.Basavapatna@Sun.COM 
260112011SSriharsha.Basavapatna@Sun.COM 		/*
260212011SSriharsha.Basavapatna@Sun.COM 		 * If we have received an ack for the attr info that we sent,
260312011SSriharsha.Basavapatna@Sun.COM 		 * then check if the dring mode matches what the peer had ack'd
260412011SSriharsha.Basavapatna@Sun.COM 		 * (saved in lane_out). If they don't match, we fail the
260512011SSriharsha.Basavapatna@Sun.COM 		 * handshake.
260612011SSriharsha.Basavapatna@Sun.COM 		 */
260712011SSriharsha.Basavapatna@Sun.COM 		if (lane_out->lstate & VSW_ATTR_ACK_RECV) {
260812011SSriharsha.Basavapatna@Sun.COM 			if (msg->options != lane_out->dring_mode) {
260912011SSriharsha.Basavapatna@Sun.COM 				/* send NACK */
261012011SSriharsha.Basavapatna@Sun.COM 				return (1);
261112011SSriharsha.Basavapatna@Sun.COM 			}
261212011SSriharsha.Basavapatna@Sun.COM 		} else {
261312011SSriharsha.Basavapatna@Sun.COM 			/*
261412011SSriharsha.Basavapatna@Sun.COM 			 * Save the negotiated dring mode in our attr
261512011SSriharsha.Basavapatna@Sun.COM 			 * parameters, so it gets sent in the attr info from us
261612011SSriharsha.Basavapatna@Sun.COM 			 * to the peer.
261712011SSriharsha.Basavapatna@Sun.COM 			 */
261812011SSriharsha.Basavapatna@Sun.COM 			lane_out->dring_mode = dring_mode;
261912011SSriharsha.Basavapatna@Sun.COM 		}
262012011SSriharsha.Basavapatna@Sun.COM 
262112011SSriharsha.Basavapatna@Sun.COM 		/* save the negotiated dring mode in the msg to be replied */
262212011SSriharsha.Basavapatna@Sun.COM 		msg->options = dring_mode;
262312011SSriharsha.Basavapatna@Sun.COM 	}
262412011SSriharsha.Basavapatna@Sun.COM 
262512011SSriharsha.Basavapatna@Sun.COM 	/*
262612011SSriharsha.Basavapatna@Sun.COM 	 * Process MTU attribute.
262712011SSriharsha.Basavapatna@Sun.COM 	 */
262812011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 4)) {
262912011SSriharsha.Basavapatna@Sun.COM 		/*
263012011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.4:
263112011SSriharsha.Basavapatna@Sun.COM 		 * Validate mtu of the peer is at least ETHERMAX. Then, the mtu
263212011SSriharsha.Basavapatna@Sun.COM 		 * is negotiated down to the minimum of our mtu and peer's mtu.
263312011SSriharsha.Basavapatna@Sun.COM 		 */
263412011SSriharsha.Basavapatna@Sun.COM 		if (msg->mtu < ETHERMAX) {
263512011SSriharsha.Basavapatna@Sun.COM 			return (1);
263612011SSriharsha.Basavapatna@Sun.COM 		}
263712011SSriharsha.Basavapatna@Sun.COM 
263812011SSriharsha.Basavapatna@Sun.COM 		mtu = MIN(msg->mtu, vswp->max_frame_size);
263912011SSriharsha.Basavapatna@Sun.COM 
264012011SSriharsha.Basavapatna@Sun.COM 		/*
264112011SSriharsha.Basavapatna@Sun.COM 		 * If we have received an ack for the attr info
264212011SSriharsha.Basavapatna@Sun.COM 		 * that we sent, then check if the mtu computed
264312011SSriharsha.Basavapatna@Sun.COM 		 * above matches the mtu that the peer had ack'd
264412011SSriharsha.Basavapatna@Sun.COM 		 * (saved in local hparams). If they don't
264512011SSriharsha.Basavapatna@Sun.COM 		 * match, we fail the handshake.
264612011SSriharsha.Basavapatna@Sun.COM 		 */
264712011SSriharsha.Basavapatna@Sun.COM 		if (lane_out->lstate & VSW_ATTR_ACK_RECV) {
264812011SSriharsha.Basavapatna@Sun.COM 			if (mtu != lane_out->mtu) {
264912011SSriharsha.Basavapatna@Sun.COM 				/* send NACK */
265012011SSriharsha.Basavapatna@Sun.COM 				return (1);
265112011SSriharsha.Basavapatna@Sun.COM 			}
265212011SSriharsha.Basavapatna@Sun.COM 		} else {
265312011SSriharsha.Basavapatna@Sun.COM 			/*
265412011SSriharsha.Basavapatna@Sun.COM 			 * Save the mtu computed above in our
265512011SSriharsha.Basavapatna@Sun.COM 			 * attr parameters, so it gets sent in
265612011SSriharsha.Basavapatna@Sun.COM 			 * the attr info from us to the peer.
265712011SSriharsha.Basavapatna@Sun.COM 			 */
265812011SSriharsha.Basavapatna@Sun.COM 			lane_out->mtu = mtu;
265912011SSriharsha.Basavapatna@Sun.COM 		}
266012011SSriharsha.Basavapatna@Sun.COM 
266112011SSriharsha.Basavapatna@Sun.COM 		/* save the MIN mtu in the msg to be replied */
266212011SSriharsha.Basavapatna@Sun.COM 		msg->mtu = mtu;
266312011SSriharsha.Basavapatna@Sun.COM 	} else {
266412011SSriharsha.Basavapatna@Sun.COM 		/* Versions < 1.4, mtu must match */
266512011SSriharsha.Basavapatna@Sun.COM 		if (msg->mtu != lane_out->mtu) {
266612011SSriharsha.Basavapatna@Sun.COM 			D2(NULL, "%s: invalid MTU (0x%llx)\n",
266712011SSriharsha.Basavapatna@Sun.COM 			    __func__, msg->mtu);
266812011SSriharsha.Basavapatna@Sun.COM 			return (1);
266912011SSriharsha.Basavapatna@Sun.COM 		}
267012011SSriharsha.Basavapatna@Sun.COM 	}
267112011SSriharsha.Basavapatna@Sun.COM 
267212011SSriharsha.Basavapatna@Sun.COM 	/*
267312011SSriharsha.Basavapatna@Sun.COM 	 * Otherwise store attributes for this lane and update
267412011SSriharsha.Basavapatna@Sun.COM 	 * lane state.
267512011SSriharsha.Basavapatna@Sun.COM 	 */
267612011SSriharsha.Basavapatna@Sun.COM 	lane_in->mtu = msg->mtu;
267712011SSriharsha.Basavapatna@Sun.COM 	lane_in->addr = msg->addr;
267812011SSriharsha.Basavapatna@Sun.COM 	lane_in->addr_type = msg->addr_type;
267912011SSriharsha.Basavapatna@Sun.COM 	lane_in->xfer_mode = msg->xfer_mode;
268012011SSriharsha.Basavapatna@Sun.COM 	lane_in->ack_freq = msg->ack_freq;
268112011SSriharsha.Basavapatna@Sun.COM 	lane_in->physlink_update = msg->physlink_update;
268212011SSriharsha.Basavapatna@Sun.COM 	lane_in->dring_mode = msg->options;
268312011SSriharsha.Basavapatna@Sun.COM 
268412011SSriharsha.Basavapatna@Sun.COM 	/*
268512011SSriharsha.Basavapatna@Sun.COM 	 * Check if the client has requested physlink state updates.
268612011SSriharsha.Basavapatna@Sun.COM 	 * If there is a physical device bound to this vswitch (L2
268712011SSriharsha.Basavapatna@Sun.COM 	 * mode), set the ack bits to indicate it is supported.
268812011SSriharsha.Basavapatna@Sun.COM 	 * Otherwise, set the nack bits.
268912011SSriharsha.Basavapatna@Sun.COM 	 */
269012011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 5)) {	/* Protocol ver >= 1.5 */
269112011SSriharsha.Basavapatna@Sun.COM 
269212011SSriharsha.Basavapatna@Sun.COM 		/* Does the vnet need phys link state updates ? */
269312011SSriharsha.Basavapatna@Sun.COM 		if ((lane_in->physlink_update &
269412011SSriharsha.Basavapatna@Sun.COM 		    PHYSLINK_UPDATE_STATE_MASK) ==
269512011SSriharsha.Basavapatna@Sun.COM 		    PHYSLINK_UPDATE_STATE) {
269612011SSriharsha.Basavapatna@Sun.COM 
269712011SSriharsha.Basavapatna@Sun.COM 			if (vswp->smode & VSW_LAYER2) {
269812011SSriharsha.Basavapatna@Sun.COM 				/* is a net-dev assigned to us ? */
269912011SSriharsha.Basavapatna@Sun.COM 				msg->physlink_update =
270012011SSriharsha.Basavapatna@Sun.COM 				    PHYSLINK_UPDATE_STATE_ACK;
270112011SSriharsha.Basavapatna@Sun.COM 				ldcp->pls_negotiated = B_TRUE;
270212011SSriharsha.Basavapatna@Sun.COM 			} else {
270312011SSriharsha.Basavapatna@Sun.COM 				/* not in L2 mode */
270412011SSriharsha.Basavapatna@Sun.COM 				msg->physlink_update =
270512011SSriharsha.Basavapatna@Sun.COM 				    PHYSLINK_UPDATE_STATE_NACK;
270612011SSriharsha.Basavapatna@Sun.COM 				ldcp->pls_negotiated = B_FALSE;
270712011SSriharsha.Basavapatna@Sun.COM 			}
270812011SSriharsha.Basavapatna@Sun.COM 
270912011SSriharsha.Basavapatna@Sun.COM 		} else {
271012011SSriharsha.Basavapatna@Sun.COM 			msg->physlink_update =
271112011SSriharsha.Basavapatna@Sun.COM 			    PHYSLINK_UPDATE_NONE;
271212011SSriharsha.Basavapatna@Sun.COM 			ldcp->pls_negotiated = B_FALSE;
271312011SSriharsha.Basavapatna@Sun.COM 		}
271412011SSriharsha.Basavapatna@Sun.COM 
271512011SSriharsha.Basavapatna@Sun.COM 	} else {
271612011SSriharsha.Basavapatna@Sun.COM 		/*
271712011SSriharsha.Basavapatna@Sun.COM 		 * physlink_update bits are ignored
271812011SSriharsha.Basavapatna@Sun.COM 		 * if set by clients < v1.5 protocol.
271912011SSriharsha.Basavapatna@Sun.COM 		 */
272012011SSriharsha.Basavapatna@Sun.COM 		msg->physlink_update = PHYSLINK_UPDATE_NONE;
272112011SSriharsha.Basavapatna@Sun.COM 		ldcp->pls_negotiated = B_FALSE;
272212011SSriharsha.Basavapatna@Sun.COM 	}
272312011SSriharsha.Basavapatna@Sun.COM 
272412011SSriharsha.Basavapatna@Sun.COM 	macaddr = lane_in->addr;
272512011SSriharsha.Basavapatna@Sun.COM 	for (i = ETHERADDRL - 1; i >= 0; i--) {
272612011SSriharsha.Basavapatna@Sun.COM 		port->p_macaddr.ether_addr_octet[i] = macaddr & 0xFF;
272712011SSriharsha.Basavapatna@Sun.COM 		macaddr >>= 8;
272812011SSriharsha.Basavapatna@Sun.COM 	}
272912011SSriharsha.Basavapatna@Sun.COM 
273012011SSriharsha.Basavapatna@Sun.COM 	/*
273112011SSriharsha.Basavapatna@Sun.COM 	 * Setup device specific xmit routines. Note this could be changed
273212011SSriharsha.Basavapatna@Sun.COM 	 * further in vsw_send_dring_info() for versions >= 1.6 if operating in
273312011SSriharsha.Basavapatna@Sun.COM 	 * RxDringData mode.
273412011SSriharsha.Basavapatna@Sun.COM 	 */
273512011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&port->tx_lock);
273612011SSriharsha.Basavapatna@Sun.COM 
273712011SSriharsha.Basavapatna@Sun.COM 	if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
273812011SSriharsha.Basavapatna@Sun.COM 	    (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
273912011SSriharsha.Basavapatna@Sun.COM 	    (VSW_VER_LT(ldcp, 1, 2) &&
274012011SSriharsha.Basavapatna@Sun.COM 	    (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
274112011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: mode = VIO_DRING_MODE", __func__);
274212011SSriharsha.Basavapatna@Sun.COM 		port->transmit = vsw_dringsend;
274312011SSriharsha.Basavapatna@Sun.COM 	} else if (lane_in->xfer_mode == VIO_DESC_MODE) {
274412011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: mode = VIO_DESC_MODE", __func__);
274512011SSriharsha.Basavapatna@Sun.COM 		vsw_create_privring(ldcp);
274612011SSriharsha.Basavapatna@Sun.COM 		port->transmit = vsw_descrsend;
274712011SSriharsha.Basavapatna@Sun.COM 		lane_out->xfer_mode = VIO_DESC_MODE;
274812011SSriharsha.Basavapatna@Sun.COM 	}
274912011SSriharsha.Basavapatna@Sun.COM 
275012011SSriharsha.Basavapatna@Sun.COM 	/*
275112011SSriharsha.Basavapatna@Sun.COM 	 * HybridIO is supported only vnet, not by OBP.
275212011SSriharsha.Basavapatna@Sun.COM 	 * So, set hio_capable to true only when in DRING mode.
275312011SSriharsha.Basavapatna@Sun.COM 	 */
275412011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 3) &&
275512011SSriharsha.Basavapatna@Sun.COM 	    (lane_in->xfer_mode != VIO_DESC_MODE)) {
275612011SSriharsha.Basavapatna@Sun.COM 		(void) atomic_swap_32(&port->p_hio_capable, B_TRUE);
275712011SSriharsha.Basavapatna@Sun.COM 	} else {
275812011SSriharsha.Basavapatna@Sun.COM 		(void) atomic_swap_32(&port->p_hio_capable, B_FALSE);
275912011SSriharsha.Basavapatna@Sun.COM 	}
276012011SSriharsha.Basavapatna@Sun.COM 
276112011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&port->tx_lock);
276212011SSriharsha.Basavapatna@Sun.COM 
276312011SSriharsha.Basavapatna@Sun.COM 	return (0);
276412011SSriharsha.Basavapatna@Sun.COM }
276512011SSriharsha.Basavapatna@Sun.COM 
276612011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_attr_ack(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)276712011SSriharsha.Basavapatna@Sun.COM vsw_process_attr_ack(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg)
276812011SSriharsha.Basavapatna@Sun.COM {
276912011SSriharsha.Basavapatna@Sun.COM 	vsw_t	*vswp = ldcp->ldc_vswp;
277012011SSriharsha.Basavapatna@Sun.COM 	lane_t	*lane_out = &ldcp->lane_out;
277112011SSriharsha.Basavapatna@Sun.COM 	lane_t	*lane_in = &ldcp->lane_in;
277212011SSriharsha.Basavapatna@Sun.COM 
277312011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
277412011SSriharsha.Basavapatna@Sun.COM 
277512011SSriharsha.Basavapatna@Sun.COM 	if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_ACK_RECV)) {
277612011SSriharsha.Basavapatna@Sun.COM 		return (1);
277712011SSriharsha.Basavapatna@Sun.COM 	}
277812011SSriharsha.Basavapatna@Sun.COM 
277912011SSriharsha.Basavapatna@Sun.COM 	/*
278012011SSriharsha.Basavapatna@Sun.COM 	 * Process dring mode attribute.
278112011SSriharsha.Basavapatna@Sun.COM 	 */
278212011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 6)) {
278312011SSriharsha.Basavapatna@Sun.COM 		/*
278412011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.6:
278512011SSriharsha.Basavapatna@Sun.COM 		 * The ack msg sent by the peer contains the negotiated dring
278612011SSriharsha.Basavapatna@Sun.COM 		 * mode between our capability (that we had sent in our attr
278712011SSriharsha.Basavapatna@Sun.COM 		 * info) and the peer's capability.
278812011SSriharsha.Basavapatna@Sun.COM 		 */
278912011SSriharsha.Basavapatna@Sun.COM 		if (lane_in->lstate & VSW_ATTR_ACK_SENT) {
279012011SSriharsha.Basavapatna@Sun.COM 			/*
279112011SSriharsha.Basavapatna@Sun.COM 			 * If we have sent an ack for the attr info msg from
279212011SSriharsha.Basavapatna@Sun.COM 			 * the peer, check if the dring mode that was
279312011SSriharsha.Basavapatna@Sun.COM 			 * negotiated then (saved in lane_out) matches the
279412011SSriharsha.Basavapatna@Sun.COM 			 * mode that the peer has ack'd. If they don't match,
279512011SSriharsha.Basavapatna@Sun.COM 			 * we fail the handshake.
279612011SSriharsha.Basavapatna@Sun.COM 			 */
279712011SSriharsha.Basavapatna@Sun.COM 			if (lane_out->dring_mode != msg->options) {
279812011SSriharsha.Basavapatna@Sun.COM 				return (1);
279912011SSriharsha.Basavapatna@Sun.COM 			}
280012011SSriharsha.Basavapatna@Sun.COM 		} else {
280112011SSriharsha.Basavapatna@Sun.COM 			if ((msg->options & lane_out->dring_mode) == 0) {
280212011SSriharsha.Basavapatna@Sun.COM 				/*
280312011SSriharsha.Basavapatna@Sun.COM 				 * Peer ack'd with a mode that we don't
280412011SSriharsha.Basavapatna@Sun.COM 				 * support; we fail the handshake.
280512011SSriharsha.Basavapatna@Sun.COM 				 */
280612011SSriharsha.Basavapatna@Sun.COM 				return (1);
280712011SSriharsha.Basavapatna@Sun.COM 			}
280812011SSriharsha.Basavapatna@Sun.COM 			if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA))
280912011SSriharsha.Basavapatna@Sun.COM 			    == (VIO_TX_DRING|VIO_RX_DRING_DATA)) {
281012011SSriharsha.Basavapatna@Sun.COM 				/*
281112011SSriharsha.Basavapatna@Sun.COM 				 * Peer must ack with only one negotiated mode.
281212011SSriharsha.Basavapatna@Sun.COM 				 * Otherwise fail handshake.
281312011SSriharsha.Basavapatna@Sun.COM 				 */
281412011SSriharsha.Basavapatna@Sun.COM 				return (1);
281512011SSriharsha.Basavapatna@Sun.COM 			}
281612011SSriharsha.Basavapatna@Sun.COM 
281712011SSriharsha.Basavapatna@Sun.COM 			/*
281812011SSriharsha.Basavapatna@Sun.COM 			 * Save the negotiated mode, so we can validate it when
281912011SSriharsha.Basavapatna@Sun.COM 			 * we receive attr info from the peer.
282012011SSriharsha.Basavapatna@Sun.COM 			 */
282112011SSriharsha.Basavapatna@Sun.COM 			lane_out->dring_mode = msg->options;
282212011SSriharsha.Basavapatna@Sun.COM 		}
282312011SSriharsha.Basavapatna@Sun.COM 	}
282412011SSriharsha.Basavapatna@Sun.COM 
282512011SSriharsha.Basavapatna@Sun.COM 	/*
282612011SSriharsha.Basavapatna@Sun.COM 	 * Process MTU attribute.
282712011SSriharsha.Basavapatna@Sun.COM 	 */
282812011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 4)) {
282912011SSriharsha.Basavapatna@Sun.COM 		/*
283012011SSriharsha.Basavapatna@Sun.COM 		 * Versions >= 1.4:
283112011SSriharsha.Basavapatna@Sun.COM 		 * The ack msg sent by the peer contains the minimum of
283212011SSriharsha.Basavapatna@Sun.COM 		 * our mtu (that we had sent in our attr info) and the
283312011SSriharsha.Basavapatna@Sun.COM 		 * peer's mtu.
283412011SSriharsha.Basavapatna@Sun.COM 		 *
283512011SSriharsha.Basavapatna@Sun.COM 		 * If we have sent an ack for the attr info msg from
283612011SSriharsha.Basavapatna@Sun.COM 		 * the peer, check if the mtu that was computed then
283712011SSriharsha.Basavapatna@Sun.COM 		 * (saved in lane_out params) matches the mtu that the
283812011SSriharsha.Basavapatna@Sun.COM 		 * peer has ack'd. If they don't match, we fail the
283912011SSriharsha.Basavapatna@Sun.COM 		 * handshake.
284012011SSriharsha.Basavapatna@Sun.COM 		 */
284112011SSriharsha.Basavapatna@Sun.COM 		if (lane_in->lstate & VSW_ATTR_ACK_SENT) {
284212011SSriharsha.Basavapatna@Sun.COM 			if (lane_out->mtu != msg->mtu) {
284312011SSriharsha.Basavapatna@Sun.COM 				return (1);
284412011SSriharsha.Basavapatna@Sun.COM 			}
284512011SSriharsha.Basavapatna@Sun.COM 		} else {
284612011SSriharsha.Basavapatna@Sun.COM 			/*
284712011SSriharsha.Basavapatna@Sun.COM 			 * If the mtu ack'd by the peer is > our mtu
284812011SSriharsha.Basavapatna@Sun.COM 			 * fail handshake. Otherwise, save the mtu, so
284912011SSriharsha.Basavapatna@Sun.COM 			 * we can validate it when we receive attr info
285012011SSriharsha.Basavapatna@Sun.COM 			 * from our peer.
285112011SSriharsha.Basavapatna@Sun.COM 			 */
285212011SSriharsha.Basavapatna@Sun.COM 			if (msg->mtu <= lane_out->mtu) {
285312011SSriharsha.Basavapatna@Sun.COM 				lane_out->mtu = msg->mtu;
285412011SSriharsha.Basavapatna@Sun.COM 			} else {
285512011SSriharsha.Basavapatna@Sun.COM 				return (1);
285612011SSriharsha.Basavapatna@Sun.COM 			}
285712011SSriharsha.Basavapatna@Sun.COM 		}
285812011SSriharsha.Basavapatna@Sun.COM 	}
285912011SSriharsha.Basavapatna@Sun.COM 
286012011SSriharsha.Basavapatna@Sun.COM 	return (0);
286112011SSriharsha.Basavapatna@Sun.COM }
286212011SSriharsha.Basavapatna@Sun.COM 
28635373Sraghuram /*
28645373Sraghuram  * Process an attribute packet. We can end up here either because our peer
28655373Sraghuram  * has ACK/NACK'ed back to an earlier ATTR msg we had sent it, or our
28665373Sraghuram  * peer has sent us an attribute INFO message
28675373Sraghuram  *
28685373Sraghuram  * If its an ACK we then move to the next stage of the handshake which
28695373Sraghuram  * is to send our descriptor ring info to our peer. If its a NACK then
28705373Sraghuram  * there is nothing more we can (currently) do.
28715373Sraghuram  *
28725373Sraghuram  * If we get a valid/acceptable INFO packet (and we have already negotiated
28735373Sraghuram  * a version) we ACK back and set channel state to ATTR_RECV, otherwise we
28745373Sraghuram  * NACK back and reset channel state to INACTIV.
28755373Sraghuram  *
28765373Sraghuram  * FUTURE: in time we will probably negotiate over attributes, but for
28775373Sraghuram  * the moment unacceptable attributes are regarded as a fatal error.
28785373Sraghuram  *
28795373Sraghuram  */
28805373Sraghuram void
vsw_process_ctrl_attr_pkt(vsw_ldc_t * ldcp,void * pkt)28815373Sraghuram vsw_process_ctrl_attr_pkt(vsw_ldc_t *ldcp, void *pkt)
28825373Sraghuram {
288312011SSriharsha.Basavapatna@Sun.COM 	vnet_attr_msg_t	*attr_pkt;
288412011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
288512011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_out = &ldcp->lane_out;
288612011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_in = &ldcp->lane_in;
288712011SSriharsha.Basavapatna@Sun.COM 	int		rv;
28885373Sraghuram 
28895373Sraghuram 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
28905373Sraghuram 
28915373Sraghuram 	/*
28925373Sraghuram 	 * We know this is a ctrl/attr packet so
28935373Sraghuram 	 * cast it into the correct structure.
28945373Sraghuram 	 */
28955373Sraghuram 	attr_pkt = (vnet_attr_msg_t *)pkt;
28965373Sraghuram 
28975373Sraghuram 	switch (attr_pkt->tag.vio_subtype) {
28985373Sraghuram 	case VIO_SUBTYPE_INFO:
289912011SSriharsha.Basavapatna@Sun.COM 
290012011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_process_attr_info(ldcp, attr_pkt);
290112011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
290212011SSriharsha.Basavapatna@Sun.COM 			vsw_free_lane_resources(ldcp, INBOUND);
290312011SSriharsha.Basavapatna@Sun.COM 			attr_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
290412011SSriharsha.Basavapatna@Sun.COM 			ldcp->lane_in.lstate |= VSW_ATTR_NACK_SENT;
29057529SSriharsha.Basavapatna@Sun.COM 		} else {
290612011SSriharsha.Basavapatna@Sun.COM 			attr_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
290712011SSriharsha.Basavapatna@Sun.COM 			lane_in->lstate |= VSW_ATTR_ACK_SENT;
29085373Sraghuram 		}
29095373Sraghuram 		attr_pkt->tag.vio_sid = ldcp->local_session;
29105373Sraghuram 		DUMP_TAG_PTR((vio_msg_tag_t *)attr_pkt);
29115373Sraghuram 		(void) vsw_send_msg(ldcp, (void *)attr_pkt,
29125373Sraghuram 		    sizeof (vnet_attr_msg_t), B_TRUE);
29135373Sraghuram 		vsw_next_milestone(ldcp);
29145373Sraghuram 		break;
29155373Sraghuram 
29165373Sraghuram 	case VIO_SUBTYPE_ACK:
291712011SSriharsha.Basavapatna@Sun.COM 
291812011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_process_attr_ack(ldcp, attr_pkt);
291912011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
29205373Sraghuram 			return;
29217529SSriharsha.Basavapatna@Sun.COM 		}
29227529SSriharsha.Basavapatna@Sun.COM 		lane_out->lstate |= VSW_ATTR_ACK_RECV;
29235373Sraghuram 		vsw_next_milestone(ldcp);
29245373Sraghuram 		break;
29255373Sraghuram 
29265373Sraghuram 	case VIO_SUBTYPE_NACK:
29275373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
29285373Sraghuram 
29295373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_NACK_RECV))
29305373Sraghuram 			return;
29315373Sraghuram 
29327529SSriharsha.Basavapatna@Sun.COM 		lane_out->lstate |= VSW_ATTR_NACK_RECV;
29335373Sraghuram 		vsw_next_milestone(ldcp);
29345373Sraghuram 		break;
29355373Sraghuram 
29365373Sraghuram 	default:
29375373Sraghuram 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
29385373Sraghuram 		    attr_pkt->tag.vio_subtype);
29395373Sraghuram 	}
29405373Sraghuram 
29415373Sraghuram 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
29425373Sraghuram }
29435373Sraghuram 
294412011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_dring_reg_info(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)294512011SSriharsha.Basavapatna@Sun.COM vsw_process_dring_reg_info(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp)
294612011SSriharsha.Basavapatna@Sun.COM {
294712011SSriharsha.Basavapatna@Sun.COM 	int		rv;
294812011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
294912011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
295012011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp = NULL;
295112011SSriharsha.Basavapatna@Sun.COM 
295212011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
295312011SSriharsha.Basavapatna@Sun.COM 
295412011SSriharsha.Basavapatna@Sun.COM 	rv = vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV);
295512011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
295612011SSriharsha.Basavapatna@Sun.COM 		return (1);
295712011SSriharsha.Basavapatna@Sun.COM 	}
295812011SSriharsha.Basavapatna@Sun.COM 
295912011SSriharsha.Basavapatna@Sun.COM 	if (VSW_VER_GTEQ(ldcp, 1, 6) &&
296012011SSriharsha.Basavapatna@Sun.COM 	    (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
296112011SSriharsha.Basavapatna@Sun.COM 		/*
296212011SSriharsha.Basavapatna@Sun.COM 		 * The earlier version of Solaris vnet driver doesn't set the
296312011SSriharsha.Basavapatna@Sun.COM 		 * option (VIO_TX_DRING in its case) correctly in its dring reg
296412011SSriharsha.Basavapatna@Sun.COM 		 * message. We workaround that here by doing the check only
296512011SSriharsha.Basavapatna@Sun.COM 		 * for versions >= v1.6.
296612011SSriharsha.Basavapatna@Sun.COM 		 */
296712011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s(%lld): Rcvd dring reg option (%d), "
296812011SSriharsha.Basavapatna@Sun.COM 		    "negotiated mode (%d)\n", __func__, ldcp->ldc_id,
296912011SSriharsha.Basavapatna@Sun.COM 		    ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode);
297012011SSriharsha.Basavapatna@Sun.COM 		return (1);
297112011SSriharsha.Basavapatna@Sun.COM 	}
297212011SSriharsha.Basavapatna@Sun.COM 
297312011SSriharsha.Basavapatna@Sun.COM 	/*
297412011SSriharsha.Basavapatna@Sun.COM 	 * Map dring exported by the peer.
297512011SSriharsha.Basavapatna@Sun.COM 	 */
297612011SSriharsha.Basavapatna@Sun.COM 	dp = vsw_map_dring(ldcp, (void *)tagp);
297712011SSriharsha.Basavapatna@Sun.COM 	if (dp == NULL) {
297812011SSriharsha.Basavapatna@Sun.COM 		return (1);
297912011SSriharsha.Basavapatna@Sun.COM 	}
298012011SSriharsha.Basavapatna@Sun.COM 
298112011SSriharsha.Basavapatna@Sun.COM 	/*
298212011SSriharsha.Basavapatna@Sun.COM 	 * Map data buffers exported by the peer if we are in RxDringData mode.
298312011SSriharsha.Basavapatna@Sun.COM 	 */
298412011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
298512011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_map_data(ldcp, dp, (void *)tagp);
298612011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
298712011SSriharsha.Basavapatna@Sun.COM 			vsw_unmap_dring(ldcp);
298812011SSriharsha.Basavapatna@Sun.COM 			return (1);
298912011SSriharsha.Basavapatna@Sun.COM 		}
299012011SSriharsha.Basavapatna@Sun.COM 	}
299112011SSriharsha.Basavapatna@Sun.COM 
299212011SSriharsha.Basavapatna@Sun.COM 	return (0);
299312011SSriharsha.Basavapatna@Sun.COM }
299412011SSriharsha.Basavapatna@Sun.COM 
299512011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_dring_reg_ack(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)299612011SSriharsha.Basavapatna@Sun.COM vsw_process_dring_reg_ack(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp)
299712011SSriharsha.Basavapatna@Sun.COM {
299812011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
299912011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp;
300012011SSriharsha.Basavapatna@Sun.COM 
300112011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
300212011SSriharsha.Basavapatna@Sun.COM 
300312011SSriharsha.Basavapatna@Sun.COM 	if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_ACK_RECV)) {
300412011SSriharsha.Basavapatna@Sun.COM 		return (1);
300512011SSriharsha.Basavapatna@Sun.COM 	}
300612011SSriharsha.Basavapatna@Sun.COM 
300712011SSriharsha.Basavapatna@Sun.COM 	dp = ldcp->lane_out.dringp;
300812011SSriharsha.Basavapatna@Sun.COM 
300912011SSriharsha.Basavapatna@Sun.COM 	/* save dring_ident acked by peer */
301012011SSriharsha.Basavapatna@Sun.COM 	dp->ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
301112011SSriharsha.Basavapatna@Sun.COM 
301212011SSriharsha.Basavapatna@Sun.COM 	return (0);
301312011SSriharsha.Basavapatna@Sun.COM }
301412011SSriharsha.Basavapatna@Sun.COM 
30155373Sraghuram /*
30165373Sraghuram  * Process a dring info packet. We can end up here either because our peer
30175373Sraghuram  * has ACK/NACK'ed back to an earlier DRING msg we had sent it, or our
30185373Sraghuram  * peer has sent us a dring INFO message.
30195373Sraghuram  *
30205373Sraghuram  * If we get a valid/acceptable INFO packet (and we have already negotiated
30215373Sraghuram  * a version) we ACK back and update the lane state, otherwise we NACK back.
30225373Sraghuram  *
30235373Sraghuram  * FUTURE: nothing to stop client from sending us info on multiple dring's
30245373Sraghuram  * but for the moment we will just use the first one we are given.
30255373Sraghuram  *
30265373Sraghuram  */
30275373Sraghuram void
vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t * ldcp,void * pkt)30285373Sraghuram vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *ldcp, void *pkt)
30295373Sraghuram {
303012011SSriharsha.Basavapatna@Sun.COM 	int		rv;
303112011SSriharsha.Basavapatna@Sun.COM 	int		msgsize;
303212011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp;
303312011SSriharsha.Basavapatna@Sun.COM 	vio_msg_tag_t	*tagp = (vio_msg_tag_t *)pkt;
303412011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
303512011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_out = &ldcp->lane_out;
303612011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lane_in = &ldcp->lane_in;
30375373Sraghuram 
30385373Sraghuram 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
30395373Sraghuram 
304012011SSriharsha.Basavapatna@Sun.COM 	switch (tagp->vio_subtype) {
30415373Sraghuram 	case VIO_SUBTYPE_INFO:
304212011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_process_dring_reg_info(ldcp, tagp);
304312011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
30445373Sraghuram 			vsw_free_lane_resources(ldcp, INBOUND);
304512011SSriharsha.Basavapatna@Sun.COM 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
304612011SSriharsha.Basavapatna@Sun.COM 			lane_in->lstate |= VSW_DRING_NACK_SENT;
30475373Sraghuram 		} else {
304812011SSriharsha.Basavapatna@Sun.COM 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
304912011SSriharsha.Basavapatna@Sun.COM 			lane_in->lstate |= VSW_DRING_ACK_SENT;
30505373Sraghuram 		}
305112011SSriharsha.Basavapatna@Sun.COM 		tagp->vio_sid = ldcp->local_session;
305212011SSriharsha.Basavapatna@Sun.COM 		DUMP_TAG_PTR(tagp);
305312011SSriharsha.Basavapatna@Sun.COM 		if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
305412011SSriharsha.Basavapatna@Sun.COM 			dp = lane_in->dringp;
305512011SSriharsha.Basavapatna@Sun.COM 			msgsize =
305612011SSriharsha.Basavapatna@Sun.COM 			    VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies);
30575373Sraghuram 		} else {
305812011SSriharsha.Basavapatna@Sun.COM 			msgsize = sizeof (vio_dring_reg_msg_t);
30595373Sraghuram 		}
306012011SSriharsha.Basavapatna@Sun.COM 		(void) vsw_send_msg(ldcp, (void *)tagp, msgsize, B_TRUE);
30615373Sraghuram 		vsw_next_milestone(ldcp);
30625373Sraghuram 		break;
30635373Sraghuram 
30645373Sraghuram 	case VIO_SUBTYPE_ACK:
306512011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_process_dring_reg_ack(ldcp, tagp);
306612011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
30675373Sraghuram 			return;
30685373Sraghuram 		}
306912011SSriharsha.Basavapatna@Sun.COM 		lane_out->lstate |= VSW_DRING_ACK_RECV;
30705373Sraghuram 		vsw_next_milestone(ldcp);
30715373Sraghuram 		break;
30725373Sraghuram 
30735373Sraghuram 	case VIO_SUBTYPE_NACK:
30745373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
30755373Sraghuram 
30765373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_NACK_RECV))
30775373Sraghuram 			return;
30785373Sraghuram 
307912011SSriharsha.Basavapatna@Sun.COM 		lane_out->lstate |= VSW_DRING_NACK_RECV;
30805373Sraghuram 		vsw_next_milestone(ldcp);
30815373Sraghuram 		break;
30825373Sraghuram 
30835373Sraghuram 	default:
30845373Sraghuram 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
308512011SSriharsha.Basavapatna@Sun.COM 		    tagp->vio_subtype);
30865373Sraghuram 	}
30875373Sraghuram 
30885373Sraghuram 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
30895373Sraghuram }
30905373Sraghuram 
30915373Sraghuram /*
30925373Sraghuram  * Process a request from peer to unregister a dring.
30935373Sraghuram  *
30945373Sraghuram  * For the moment we just restart the handshake if our
30955373Sraghuram  * peer endpoint attempts to unregister a dring.
30965373Sraghuram  */
30975373Sraghuram void
vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t * ldcp,void * pkt)30985373Sraghuram vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *ldcp, void *pkt)
30995373Sraghuram {
31005373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
31015373Sraghuram 	vio_dring_unreg_msg_t	*dring_pkt;
31025373Sraghuram 
31035373Sraghuram 	/*
31045373Sraghuram 	 * We know this is a ctrl/dring packet so
31055373Sraghuram 	 * cast it into the correct structure.
31065373Sraghuram 	 */
31075373Sraghuram 	dring_pkt = (vio_dring_unreg_msg_t *)pkt;
31085373Sraghuram 
31095373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
31105373Sraghuram 
31115373Sraghuram 	switch (dring_pkt->tag.vio_subtype) {
31125373Sraghuram 	case VIO_SUBTYPE_INFO:
31135373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
31145373Sraghuram 
31155373Sraghuram 		DWARN(vswp, "%s: restarting handshake..", __func__);
31165373Sraghuram 		break;
31175373Sraghuram 
31185373Sraghuram 	case VIO_SUBTYPE_ACK:
31195373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
31205373Sraghuram 
31215373Sraghuram 		DWARN(vswp, "%s: restarting handshake..", __func__);
31225373Sraghuram 		break;
31235373Sraghuram 
31245373Sraghuram 	case VIO_SUBTYPE_NACK:
31255373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
31265373Sraghuram 
31275373Sraghuram 		DWARN(vswp, "%s: restarting handshake..", __func__);
31285373Sraghuram 		break;
31295373Sraghuram 
31305373Sraghuram 	default:
31315373Sraghuram 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
31325373Sraghuram 		    dring_pkt->tag.vio_subtype);
31335373Sraghuram 	}
31345373Sraghuram 
31355373Sraghuram 	vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
31365373Sraghuram 
31375373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
31385373Sraghuram }
31395373Sraghuram 
31405373Sraghuram #define	SND_MCST_NACK(ldcp, pkt) \
31415373Sraghuram 	pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \
31425373Sraghuram 	pkt->tag.vio_sid = ldcp->local_session; \
31435373Sraghuram 	(void) vsw_send_msg(ldcp, (void *)pkt, \
31445373Sraghuram 			sizeof (vnet_mcast_msg_t), B_TRUE);
31455373Sraghuram 
31465373Sraghuram /*
31475373Sraghuram  * Process a multicast request from a vnet.
31485373Sraghuram  *
31495373Sraghuram  * Vnet's specify a multicast address that they are interested in. This
31505373Sraghuram  * address is used as a key into the hash table which forms the multicast
31515373Sraghuram  * forwarding database (mFDB).
31525373Sraghuram  *
31535373Sraghuram  * The table keys are the multicast addresses, while the table entries
31545373Sraghuram  * are pointers to lists of ports which wish to receive packets for the
31555373Sraghuram  * specified multicast address.
31565373Sraghuram  *
31575373Sraghuram  * When a multicast packet is being switched we use the address as a key
31585373Sraghuram  * into the hash table, and then walk the appropriate port list forwarding
31595373Sraghuram  * the pkt to each port in turn.
31605373Sraghuram  *
31615373Sraghuram  * If a vnet is no longer interested in a particular multicast grouping
31625373Sraghuram  * we simply find the correct location in the hash table and then delete
31635373Sraghuram  * the relevant port from the port list.
31645373Sraghuram  *
31655373Sraghuram  * To deal with the case whereby a port is being deleted without first
31665373Sraghuram  * removing itself from the lists in the hash table, we maintain a list
31675373Sraghuram  * of multicast addresses the port has registered an interest in, within
31685373Sraghuram  * the port structure itself. We then simply walk that list of addresses
31695373Sraghuram  * using them as keys into the hash table and remove the port from the
31705373Sraghuram  * appropriate lists.
31715373Sraghuram  */
31725373Sraghuram static void
vsw_process_ctrl_mcst_pkt(vsw_ldc_t * ldcp,void * pkt)31735373Sraghuram vsw_process_ctrl_mcst_pkt(vsw_ldc_t *ldcp, void *pkt)
31745373Sraghuram {
31755373Sraghuram 	vnet_mcast_msg_t	*mcst_pkt;
31765373Sraghuram 	vsw_port_t		*port = ldcp->ldc_port;
31775373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
31785373Sraghuram 	int			i;
31795373Sraghuram 
31805373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
31815373Sraghuram 
31825373Sraghuram 	/*
31835373Sraghuram 	 * We know this is a ctrl/mcast packet so
31845373Sraghuram 	 * cast it into the correct structure.
31855373Sraghuram 	 */
31865373Sraghuram 	mcst_pkt = (vnet_mcast_msg_t *)pkt;
31875373Sraghuram 
31885373Sraghuram 	switch (mcst_pkt->tag.vio_subtype) {
31895373Sraghuram 	case VIO_SUBTYPE_INFO:
31905373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
31915373Sraghuram 
31925373Sraghuram 		/*
31935373Sraghuram 		 * Check if in correct state to receive a multicast
31945373Sraghuram 		 * message (i.e. handshake complete). If not reset
31955373Sraghuram 		 * the handshake.
31965373Sraghuram 		 */
31975373Sraghuram 		if (vsw_check_flag(ldcp, INBOUND, VSW_MCST_INFO_RECV))
31985373Sraghuram 			return;
31995373Sraghuram 
32005373Sraghuram 		/*
32015373Sraghuram 		 * Before attempting to add or remove address check
32025373Sraghuram 		 * that they are valid multicast addresses.
32035373Sraghuram 		 * If not, then NACK back.
32045373Sraghuram 		 */
32055373Sraghuram 		for (i = 0; i < mcst_pkt->count; i++) {
32065373Sraghuram 			if ((mcst_pkt->mca[i].ether_addr_octet[0] & 01) != 1) {
32075373Sraghuram 				DERR(vswp, "%s: invalid multicast address",
32085373Sraghuram 				    __func__);
32095373Sraghuram 				SND_MCST_NACK(ldcp, mcst_pkt);
32105373Sraghuram 				return;
32115373Sraghuram 			}
32125373Sraghuram 		}
32135373Sraghuram 
32145373Sraghuram 		/*
32155373Sraghuram 		 * Now add/remove the addresses. If this fails we
32165373Sraghuram 		 * NACK back.
32175373Sraghuram 		 */
32185373Sraghuram 		if (vsw_add_rem_mcst(mcst_pkt, port) != 0) {
32195373Sraghuram 			SND_MCST_NACK(ldcp, mcst_pkt);
32205373Sraghuram 			return;
32215373Sraghuram 		}
32225373Sraghuram 
32235373Sraghuram 		mcst_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
32245373Sraghuram 		mcst_pkt->tag.vio_sid = ldcp->local_session;
32255373Sraghuram 
32265373Sraghuram 		DUMP_TAG_PTR((vio_msg_tag_t *)mcst_pkt);
32275373Sraghuram 
32285373Sraghuram 		(void) vsw_send_msg(ldcp, (void *)mcst_pkt,
32295373Sraghuram 		    sizeof (vnet_mcast_msg_t), B_TRUE);
32305373Sraghuram 		break;
32315373Sraghuram 
32325373Sraghuram 	case VIO_SUBTYPE_ACK:
32335373Sraghuram 		DWARN(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
32345373Sraghuram 
32355373Sraghuram 		/*
32365373Sraghuram 		 * We shouldn't ever get a multicast ACK message as
32375373Sraghuram 		 * at the moment we never request multicast addresses
32385373Sraghuram 		 * to be set on some other device. This may change in
32395373Sraghuram 		 * the future if we have cascading switches.
32405373Sraghuram 		 */
32415373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_ACK_RECV))
32425373Sraghuram 			return;
32435373Sraghuram 
32445373Sraghuram 				/* Do nothing */
32455373Sraghuram 		break;
32465373Sraghuram 
32475373Sraghuram 	case VIO_SUBTYPE_NACK:
32485373Sraghuram 		DWARN(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
32495373Sraghuram 
32505373Sraghuram 		/*
32515373Sraghuram 		 * We shouldn't get a multicast NACK packet for the
32525373Sraghuram 		 * same reasons as we shouldn't get a ACK packet.
32535373Sraghuram 		 */
32545373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_NACK_RECV))
32555373Sraghuram 			return;
32565373Sraghuram 
32575373Sraghuram 				/* Do nothing */
32585373Sraghuram 		break;
32595373Sraghuram 
32605373Sraghuram 	default:
32615373Sraghuram 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
32625373Sraghuram 		    mcst_pkt->tag.vio_subtype);
32635373Sraghuram 	}
32645373Sraghuram 
32655373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
32665373Sraghuram }
32675373Sraghuram 
32685373Sraghuram static void
vsw_process_ctrl_rdx_pkt(vsw_ldc_t * ldcp,void * pkt)32695373Sraghuram vsw_process_ctrl_rdx_pkt(vsw_ldc_t *ldcp, void *pkt)
32705373Sraghuram {
32715373Sraghuram 	vio_rdx_msg_t	*rdx_pkt;
32725373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
32735373Sraghuram 
32745373Sraghuram 	/*
32755373Sraghuram 	 * We know this is a ctrl/rdx packet so
32765373Sraghuram 	 * cast it into the correct structure.
32775373Sraghuram 	 */
32785373Sraghuram 	rdx_pkt = (vio_rdx_msg_t *)pkt;
32795373Sraghuram 
32805373Sraghuram 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
32815373Sraghuram 
32825373Sraghuram 	switch (rdx_pkt->tag.vio_subtype) {
32835373Sraghuram 	case VIO_SUBTYPE_INFO:
32845373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
32855373Sraghuram 
32865373Sraghuram 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_RDX_INFO_RECV))
32875373Sraghuram 			return;
32885373Sraghuram 
32895373Sraghuram 		rdx_pkt->tag.vio_sid = ldcp->local_session;
32905373Sraghuram 		rdx_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
32915373Sraghuram 
32925373Sraghuram 		DUMP_TAG_PTR((vio_msg_tag_t *)rdx_pkt);
32935373Sraghuram 
32945373Sraghuram 		ldcp->lane_out.lstate |= VSW_RDX_ACK_SENT;
32955373Sraghuram 
32965373Sraghuram 		(void) vsw_send_msg(ldcp, (void *)rdx_pkt,
32975373Sraghuram 		    sizeof (vio_rdx_msg_t), B_TRUE);
32985373Sraghuram 
32995373Sraghuram 		vsw_next_milestone(ldcp);
33005373Sraghuram 		break;
33015373Sraghuram 
33025373Sraghuram 	case VIO_SUBTYPE_ACK:
33035373Sraghuram 		/*
33045373Sraghuram 		 * Should be handled in-band by callback handler.
33055373Sraghuram 		 */
33065373Sraghuram 		DERR(vswp, "%s: Unexpected VIO_SUBTYPE_ACK", __func__);
33075373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33085373Sraghuram 		break;
33095373Sraghuram 
33105373Sraghuram 	case VIO_SUBTYPE_NACK:
33115373Sraghuram 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
33125373Sraghuram 
33135373Sraghuram 		if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_NACK_RECV))
33145373Sraghuram 			return;
33155373Sraghuram 
33165373Sraghuram 		ldcp->lane_in.lstate |= VSW_RDX_NACK_RECV;
33175373Sraghuram 		vsw_next_milestone(ldcp);
33185373Sraghuram 		break;
33195373Sraghuram 
33205373Sraghuram 	default:
33215373Sraghuram 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33225373Sraghuram 		    rdx_pkt->tag.vio_subtype);
33235373Sraghuram 	}
33245373Sraghuram 
33255373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33265373Sraghuram }
33275373Sraghuram 
33285373Sraghuram static void
vsw_process_physlink_msg(vsw_ldc_t * ldcp,void * pkt)33299336SSriharsha.Basavapatna@Sun.COM vsw_process_physlink_msg(vsw_ldc_t *ldcp, void *pkt)
33309336SSriharsha.Basavapatna@Sun.COM {
33319336SSriharsha.Basavapatna@Sun.COM 	vnet_physlink_msg_t	*msgp;
33329336SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
33339336SSriharsha.Basavapatna@Sun.COM 
33349336SSriharsha.Basavapatna@Sun.COM 	msgp = (vnet_physlink_msg_t *)pkt;
33359336SSriharsha.Basavapatna@Sun.COM 
33369336SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
33379336SSriharsha.Basavapatna@Sun.COM 
33389336SSriharsha.Basavapatna@Sun.COM 	switch (msgp->tag.vio_subtype) {
33399336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_INFO:
33409336SSriharsha.Basavapatna@Sun.COM 
33419336SSriharsha.Basavapatna@Sun.COM 		/* vsw shouldn't recv physlink info */
33429336SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s: Unexpected VIO_SUBTYPE_INFO", __func__);
33439336SSriharsha.Basavapatna@Sun.COM 		break;
33449336SSriharsha.Basavapatna@Sun.COM 
33459336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_ACK:
33469336SSriharsha.Basavapatna@Sun.COM 
33479336SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
33489336SSriharsha.Basavapatna@Sun.COM 		break;
33499336SSriharsha.Basavapatna@Sun.COM 
33509336SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_NACK:
33519336SSriharsha.Basavapatna@Sun.COM 
33529336SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
33539336SSriharsha.Basavapatna@Sun.COM 		break;
33549336SSriharsha.Basavapatna@Sun.COM 
33559336SSriharsha.Basavapatna@Sun.COM 	default:
33569336SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33579336SSriharsha.Basavapatna@Sun.COM 		    msgp->tag.vio_subtype);
33589336SSriharsha.Basavapatna@Sun.COM 	}
33599336SSriharsha.Basavapatna@Sun.COM 
33609336SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33619336SSriharsha.Basavapatna@Sun.COM }
33629336SSriharsha.Basavapatna@Sun.COM 
33639336SSriharsha.Basavapatna@Sun.COM static void
vsw_process_data_pkt(vsw_ldc_t * ldcp,void * dpkt,vio_msg_tag_t * tagp,uint32_t msglen)33645935Ssb155480 vsw_process_data_pkt(vsw_ldc_t *ldcp, void *dpkt, vio_msg_tag_t *tagp,
33655935Ssb155480 	uint32_t msglen)
33665373Sraghuram {
33675935Ssb155480 	uint16_t	env = tagp->vio_subtype_env;
33685373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
336912011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
337012011SSriharsha.Basavapatna@Sun.COM 	uint8_t		dring_mode = lp->dring_mode;
33715373Sraghuram 
33725373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
33735373Sraghuram 
33745373Sraghuram 	/* session id check */
33755373Sraghuram 	if (ldcp->session_status & VSW_PEER_SESSION) {
33765935Ssb155480 		if (ldcp->peer_session != tagp->vio_sid) {
33775373Sraghuram 			DERR(vswp, "%s (chan %d): invalid session id (%llx)",
33785935Ssb155480 			    __func__, ldcp->ldc_id, tagp->vio_sid);
33795373Sraghuram 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33805373Sraghuram 			return;
33815373Sraghuram 		}
33825373Sraghuram 	}
33835373Sraghuram 
33845373Sraghuram 	/*
33855373Sraghuram 	 * It is an error for us to be getting data packets
33865373Sraghuram 	 * before the handshake has completed.
33875373Sraghuram 	 */
33885373Sraghuram 	if (ldcp->hphase != VSW_MILESTONE4) {
33895373Sraghuram 		DERR(vswp, "%s: got data packet before handshake complete "
33905373Sraghuram 		    "hphase %d (%x: %x)", __func__, ldcp->hphase,
33915373Sraghuram 		    ldcp->lane_in.lstate, ldcp->lane_out.lstate);
33925373Sraghuram 		DUMP_FLAGS(ldcp->lane_in.lstate);
33935373Sraghuram 		DUMP_FLAGS(ldcp->lane_out.lstate);
33945373Sraghuram 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33955373Sraghuram 		return;
33965373Sraghuram 	}
339712011SSriharsha.Basavapatna@Sun.COM 	if (dring_mode == VIO_TX_DRING) {
339812011SSriharsha.Basavapatna@Sun.COM 		/*
339912011SSriharsha.Basavapatna@Sun.COM 		 * To reduce the locking contention, release the ldc_cblock
340012011SSriharsha.Basavapatna@Sun.COM 		 * here and re-acquire it once we are done receiving packets.
340112011SSriharsha.Basavapatna@Sun.COM 		 * We do this only in TxDring mode to allow further callbaks to
340212011SSriharsha.Basavapatna@Sun.COM 		 * continue while the msg worker thread processes the messages.
340312011SSriharsha.Basavapatna@Sun.COM 		 * In RxDringData mode, we process the messages in the callback
340412011SSriharsha.Basavapatna@Sun.COM 		 * itself and wake up rcv worker thread to process only data
340512011SSriharsha.Basavapatna@Sun.COM 		 * info messages.
340612011SSriharsha.Basavapatna@Sun.COM 		 */
340712011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->ldc_cblock);
340812011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->ldc_rxlock);
340912011SSriharsha.Basavapatna@Sun.COM 	}
34105373Sraghuram 
34115373Sraghuram 	/*
34125373Sraghuram 	 * Switch on vio_subtype envelope, then let lower routines
34135373Sraghuram 	 * decide if its an INFO, ACK or NACK packet.
34145373Sraghuram 	 */
34155373Sraghuram 	if (env == VIO_DRING_DATA) {
341612011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dringdata(ldcp, dpkt);
34175373Sraghuram 	} else if (env == VIO_PKT_DATA) {
34185935Ssb155480 		ldcp->rx_pktdata(ldcp, dpkt, msglen);
34195373Sraghuram 	} else if (env == VIO_DESC_DATA) {
34205373Sraghuram 		vsw_process_data_ibnd_pkt(ldcp, dpkt);
34215373Sraghuram 	} else {
342212011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s: unknown vio_subtype_env (%x)\n",
342312011SSriharsha.Basavapatna@Sun.COM 		    __func__, env);
34245373Sraghuram 	}
34255373Sraghuram 
342612011SSriharsha.Basavapatna@Sun.COM 	if (dring_mode == VIO_TX_DRING) {
342712011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->ldc_rxlock);
342812011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->ldc_cblock);
342912011SSriharsha.Basavapatna@Sun.COM 	}
34305373Sraghuram 
34315373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
34325373Sraghuram }
34335373Sraghuram 
34345373Sraghuram /*
34355935Ssb155480  * dummy pkt data handler function for vnet protocol version 1.0
34365935Ssb155480  */
34375935Ssb155480 static void
vsw_process_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)34385935Ssb155480 vsw_process_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
34395935Ssb155480 {
34405935Ssb155480 	_NOTE(ARGUNUSED(arg1, arg2, msglen))
34415935Ssb155480 }
34425935Ssb155480 
34435935Ssb155480 /*
34445935Ssb155480  * This function handles raw pkt data messages received over the channel.
34455935Ssb155480  * Currently, only priority-eth-type frames are received through this mechanism.
34465935Ssb155480  * In this case, the frame(data) is present within the message itself which
34475935Ssb155480  * is copied into an mblk before switching it.
34485373Sraghuram  */
34495373Sraghuram static void
vsw_process_pkt_data(void * arg1,void * arg2,uint32_t msglen)34505935Ssb155480 vsw_process_pkt_data(void *arg1, void *arg2, uint32_t msglen)
34515373Sraghuram {
34525935Ssb155480 	vsw_ldc_t		*ldcp = (vsw_ldc_t *)arg1;
34535935Ssb155480 	vio_raw_data_msg_t	*dpkt = (vio_raw_data_msg_t *)arg2;
34545935Ssb155480 	uint32_t		size;
34555935Ssb155480 	mblk_t			*mp;
345612011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t		*vmp;
34575935Ssb155480 	vsw_t			*vswp = ldcp->ldc_vswp;
34585935Ssb155480 	vgen_stats_t		*statsp = &ldcp->ldc_stats;
34596419Ssb155480 	lane_t			*lp = &ldcp->lane_out;
34605935Ssb155480 
34615935Ssb155480 	size = msglen - VIO_PKT_DATA_HDRSIZE;
34626419Ssb155480 	if (size < ETHERMIN || size > lp->mtu) {
34635935Ssb155480 		(void) atomic_inc_32(&statsp->rx_pri_fail);
34645935Ssb155480 		DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
34655935Ssb155480 		    ldcp->ldc_id, size);
34665935Ssb155480 		return;
34675935Ssb155480 	}
34685935Ssb155480 
346912011SSriharsha.Basavapatna@Sun.COM 	vmp = vio_multipool_allocb(&ldcp->vmp, size + VLAN_TAGSZ);
347012011SSriharsha.Basavapatna@Sun.COM 	if (vmp == NULL) {
34716419Ssb155480 		mp = allocb(size + VLAN_TAGSZ, BPRI_MED);
34725935Ssb155480 		if (mp == NULL) {
34735935Ssb155480 			(void) atomic_inc_32(&statsp->rx_pri_fail);
34745935Ssb155480 			DWARN(vswp, "%s(%lld) allocb failure, "
34755935Ssb155480 			    "unable to process priority frame\n", __func__,
34765935Ssb155480 			    ldcp->ldc_id);
34775935Ssb155480 			return;
34785935Ssb155480 		}
347912011SSriharsha.Basavapatna@Sun.COM 	} else {
348012011SSriharsha.Basavapatna@Sun.COM 		mp = vmp->mp;
34815935Ssb155480 	}
34825935Ssb155480 
34836419Ssb155480 	/* skip over the extra space for vlan tag */
34846419Ssb155480 	mp->b_rptr += VLAN_TAGSZ;
34856419Ssb155480 
34865935Ssb155480 	/* copy the frame from the payload of raw data msg into the mblk */
34875935Ssb155480 	bcopy(dpkt->data, mp->b_rptr, size);
34885935Ssb155480 	mp->b_wptr = mp->b_rptr + size;
34895935Ssb155480 
349012011SSriharsha.Basavapatna@Sun.COM 	if (vmp != NULL) {
349112011SSriharsha.Basavapatna@Sun.COM 		vmp->state = VIO_MBLK_HAS_DATA;
349212011SSriharsha.Basavapatna@Sun.COM 	}
349312011SSriharsha.Basavapatna@Sun.COM 
34945935Ssb155480 	/* update stats */
34955935Ssb155480 	(void) atomic_inc_64(&statsp->rx_pri_packets);
34965935Ssb155480 	(void) atomic_add_64(&statsp->rx_pri_bytes, size);
34975935Ssb155480 
34986419Ssb155480 	/*
34996419Ssb155480 	 * VLAN_TAGSZ of extra space has been pre-alloc'd if tag is needed.
35006419Ssb155480 	 */
35016419Ssb155480 	(void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
35026419Ssb155480 
35035935Ssb155480 	/* switch the frame to destination */
35045935Ssb155480 	vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT, ldcp->ldc_port, NULL);
35055373Sraghuram }
35065373Sraghuram 
35075373Sraghuram /*
35085373Sraghuram  * Process an in-band descriptor message (most likely from
35095373Sraghuram  * OBP).
35105373Sraghuram  */
35115373Sraghuram static void
vsw_process_data_ibnd_pkt(vsw_ldc_t * ldcp,void * pkt)35125373Sraghuram vsw_process_data_ibnd_pkt(vsw_ldc_t *ldcp, void *pkt)
35135373Sraghuram {
35145373Sraghuram 	vnet_ibnd_desc_t	*ibnd_desc;
35155373Sraghuram 	dring_info_t		*dp = NULL;
35165373Sraghuram 	vsw_private_desc_t	*priv_addr = NULL;
35175373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
35185373Sraghuram 	mblk_t			*mp = NULL;
35195373Sraghuram 	size_t			nbytes = 0;
35205373Sraghuram 	size_t			off = 0;
35215373Sraghuram 	uint64_t		idx = 0;
35225373Sraghuram 	uint32_t		num = 1, len, datalen = 0;
35235373Sraghuram 	uint64_t		ncookies = 0;
35245373Sraghuram 	int			i, rv;
35255373Sraghuram 	int			j = 0;
35265373Sraghuram 
35275373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
35285373Sraghuram 
35295373Sraghuram 	ibnd_desc = (vnet_ibnd_desc_t *)pkt;
35305373Sraghuram 
35315373Sraghuram 	switch (ibnd_desc->hdr.tag.vio_subtype) {
35325373Sraghuram 	case VIO_SUBTYPE_INFO:
35335373Sraghuram 		D1(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
35345373Sraghuram 
35355373Sraghuram 		if (vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV))
35365373Sraghuram 			return;
35375373Sraghuram 
35385373Sraghuram 		/*
35395373Sraghuram 		 * Data is padded to align on a 8 byte boundary,
35405373Sraghuram 		 * nbytes is actual data length, i.e. minus that
35415373Sraghuram 		 * padding.
35425373Sraghuram 		 */
35435373Sraghuram 		datalen = ibnd_desc->nbytes;
35445373Sraghuram 
35455373Sraghuram 		D2(vswp, "%s(%lld): processing inband desc : "
35465373Sraghuram 		    ": datalen 0x%lx", __func__, ldcp->ldc_id, datalen);
35475373Sraghuram 
35485373Sraghuram 		ncookies = ibnd_desc->ncookies;
35495373Sraghuram 
35505373Sraghuram 		/*
35515373Sraghuram 		 * allocb(9F) returns an aligned data block. We
35525373Sraghuram 		 * need to ensure that we ask ldc for an aligned
35535373Sraghuram 		 * number of bytes also.
35545373Sraghuram 		 */
35555373Sraghuram 		nbytes = datalen;
35565373Sraghuram 		if (nbytes & 0x7) {
35575373Sraghuram 			off = 8 - (nbytes & 0x7);
35585373Sraghuram 			nbytes += off;
35595373Sraghuram 		}
35605373Sraghuram 
35616419Ssb155480 		/* alloc extra space for VLAN_TAG */
35626419Ssb155480 		mp = allocb(datalen + 8, BPRI_MED);
35635373Sraghuram 		if (mp == NULL) {
35645373Sraghuram 			DERR(vswp, "%s(%lld): allocb failed",
35655373Sraghuram 			    __func__, ldcp->ldc_id);
35665373Sraghuram 			ldcp->ldc_stats.rx_allocb_fail++;
35675373Sraghuram 			return;
35685373Sraghuram 		}
35695373Sraghuram 
35706419Ssb155480 		/* skip over the extra space for VLAN_TAG */
35716419Ssb155480 		mp->b_rptr += 8;
35726419Ssb155480 
35735373Sraghuram 		rv = ldc_mem_copy(ldcp->ldc_handle, (caddr_t)mp->b_rptr,
35745373Sraghuram 		    0, &nbytes, ibnd_desc->memcookie, (uint64_t)ncookies,
35755373Sraghuram 		    LDC_COPY_IN);
35765373Sraghuram 
35775373Sraghuram 		if (rv != 0) {
35785373Sraghuram 			DERR(vswp, "%s(%d): unable to copy in data from "
35795373Sraghuram 			    "%d cookie(s)", __func__, ldcp->ldc_id, ncookies);
35805373Sraghuram 			freemsg(mp);
35815373Sraghuram 			ldcp->ldc_stats.ierrors++;
35825373Sraghuram 			return;
35835373Sraghuram 		}
35845373Sraghuram 
35855373Sraghuram 		D2(vswp, "%s(%d): copied in %ld bytes using %d cookies",
35865373Sraghuram 		    __func__, ldcp->ldc_id, nbytes, ncookies);
35875373Sraghuram 
35885373Sraghuram 		/* point to the actual end of data */
35895373Sraghuram 		mp->b_wptr = mp->b_rptr + datalen;
35905373Sraghuram 		ldcp->ldc_stats.ipackets++;
35915373Sraghuram 		ldcp->ldc_stats.rbytes += datalen;
35925373Sraghuram 
35935373Sraghuram 		/*
35945373Sraghuram 		 * We ACK back every in-band descriptor message we process
35955373Sraghuram 		 */
35965373Sraghuram 		ibnd_desc->hdr.tag.vio_subtype = VIO_SUBTYPE_ACK;
35975373Sraghuram 		ibnd_desc->hdr.tag.vio_sid = ldcp->local_session;
35985373Sraghuram 		(void) vsw_send_msg(ldcp, (void *)ibnd_desc,
35995373Sraghuram 		    sizeof (vnet_ibnd_desc_t), B_TRUE);
36005373Sraghuram 
36016419Ssb155480 		/*
36026419Ssb155480 		 * there is extra space alloc'd for VLAN_TAG
36036419Ssb155480 		 */
36046419Ssb155480 		(void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
36056419Ssb155480 
36065373Sraghuram 		/* send the packet to be switched */
36075373Sraghuram 		vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT,
36085373Sraghuram 		    ldcp->ldc_port, NULL);
36095373Sraghuram 
36105373Sraghuram 		break;
36115373Sraghuram 
36125373Sraghuram 	case VIO_SUBTYPE_ACK:
36135373Sraghuram 		D1(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
36145373Sraghuram 
36155373Sraghuram 		/* Verify the ACK is valid */
36165373Sraghuram 		idx = ibnd_desc->hdr.desc_handle;
36175373Sraghuram 
361812011SSriharsha.Basavapatna@Sun.COM 		if (idx >= vsw_num_descriptors) {
36195373Sraghuram 			cmn_err(CE_WARN, "!vsw%d: corrupted ACK received "
36205373Sraghuram 			    "(idx %ld)", vswp->instance, idx);
36215373Sraghuram 			return;
36225373Sraghuram 		}
36235373Sraghuram 
36245373Sraghuram 		if ((dp = ldcp->lane_out.dringp) == NULL) {
36255373Sraghuram 			DERR(vswp, "%s: no dring found", __func__);
36265373Sraghuram 			return;
36275373Sraghuram 		}
36285373Sraghuram 
36295373Sraghuram 		len = dp->num_descriptors;
36305373Sraghuram 		/*
36315373Sraghuram 		 * If the descriptor we are being ACK'ed for is not the
36325373Sraghuram 		 * one we expected, then pkts were lost somwhere, either
36335373Sraghuram 		 * when we tried to send a msg, or a previous ACK msg from
36345373Sraghuram 		 * our peer. In either case we now reclaim the descriptors
36355373Sraghuram 		 * in the range from the last ACK we received up to the
36365373Sraghuram 		 * current ACK.
36375373Sraghuram 		 */
36385373Sraghuram 		if (idx != dp->last_ack_recv) {
36395373Sraghuram 			DWARN(vswp, "%s: dropped pkts detected, (%ld, %ld)",
36405373Sraghuram 			    __func__, dp->last_ack_recv, idx);
36415373Sraghuram 			num = idx >= dp->last_ack_recv ?
36425373Sraghuram 			    idx - dp->last_ack_recv + 1:
36435373Sraghuram 			    (len - dp->last_ack_recv + 1) + idx;
36445373Sraghuram 		}
36455373Sraghuram 
36465373Sraghuram 		/*
36475373Sraghuram 		 * When we sent the in-band message to our peer we
36485373Sraghuram 		 * marked the copy in our private ring as READY. We now
36495373Sraghuram 		 * check that the descriptor we are being ACK'ed for is in
36505373Sraghuram 		 * fact READY, i.e. it is one we have shared with our peer.
36515373Sraghuram 		 *
36525373Sraghuram 		 * If its not we flag an error, but still reset the descr
36535373Sraghuram 		 * back to FREE.
36545373Sraghuram 		 */
36555373Sraghuram 		for (i = dp->last_ack_recv; j < num; i = (i + 1) % len, j++) {
36565373Sraghuram 			priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
36575373Sraghuram 			mutex_enter(&priv_addr->dstate_lock);
36585373Sraghuram 			if (priv_addr->dstate != VIO_DESC_READY) {
36595373Sraghuram 				DERR(vswp, "%s: (%ld) desc at index %ld not "
36605373Sraghuram 				    "READY (0x%lx)", __func__,
36615373Sraghuram 				    ldcp->ldc_id, idx, priv_addr->dstate);
36625373Sraghuram 				DERR(vswp, "%s: bound %d: ncookies %ld : "
36635373Sraghuram 				    "datalen %ld", __func__,
36645373Sraghuram 				    priv_addr->bound, priv_addr->ncookies,
36655373Sraghuram 				    priv_addr->datalen);
36665373Sraghuram 			}
36675373Sraghuram 			D2(vswp, "%s: (%lld) freeing descp at %lld", __func__,
36685373Sraghuram 			    ldcp->ldc_id, idx);
36695373Sraghuram 			/* release resources associated with sent msg */
36705373Sraghuram 			priv_addr->datalen = 0;
36715373Sraghuram 			priv_addr->dstate = VIO_DESC_FREE;
36725373Sraghuram 			mutex_exit(&priv_addr->dstate_lock);
36735373Sraghuram 		}
36745373Sraghuram 		/* update to next expected value */
36755373Sraghuram 		dp->last_ack_recv = (idx + 1) % dp->num_descriptors;
36765373Sraghuram 
36775373Sraghuram 		break;
36785373Sraghuram 
36795373Sraghuram 	case VIO_SUBTYPE_NACK:
36805373Sraghuram 		DERR(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
36815373Sraghuram 
36825373Sraghuram 		/*
36835373Sraghuram 		 * We should only get a NACK if our peer doesn't like
36845373Sraghuram 		 * something about a message we have sent it. If this
36855373Sraghuram 		 * happens we just release the resources associated with
36865373Sraghuram 		 * the message. (We are relying on higher layers to decide
36875373Sraghuram 		 * whether or not to resend.
36885373Sraghuram 		 */
36895373Sraghuram 
36905373Sraghuram 		/* limit check */
36915373Sraghuram 		idx = ibnd_desc->hdr.desc_handle;
36925373Sraghuram 
369312011SSriharsha.Basavapatna@Sun.COM 		if (idx >= vsw_num_descriptors) {
36945373Sraghuram 			DERR(vswp, "%s: corrupted NACK received (idx %lld)",
36955373Sraghuram 			    __func__, idx);
36965373Sraghuram 			return;
36975373Sraghuram 		}
36985373Sraghuram 
36995373Sraghuram 		if ((dp = ldcp->lane_out.dringp) == NULL) {
37005373Sraghuram 			DERR(vswp, "%s: no dring found", __func__);
37015373Sraghuram 			return;
37025373Sraghuram 		}
37035373Sraghuram 
37045373Sraghuram 		priv_addr = (vsw_private_desc_t *)dp->priv_addr;
37055373Sraghuram 
37065373Sraghuram 		/* move to correct location in ring */
37075373Sraghuram 		priv_addr += idx;
37085373Sraghuram 
37095373Sraghuram 		/* release resources associated with sent msg */
37105373Sraghuram 		mutex_enter(&priv_addr->dstate_lock);
37115373Sraghuram 		priv_addr->datalen = 0;
37125373Sraghuram 		priv_addr->dstate = VIO_DESC_FREE;
37135373Sraghuram 		mutex_exit(&priv_addr->dstate_lock);
37145373Sraghuram 
37155373Sraghuram 		break;
37165373Sraghuram 
37175373Sraghuram 	default:
37185373Sraghuram 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
37195373Sraghuram 		    ldcp->ldc_id, ibnd_desc->hdr.tag.vio_subtype);
37205373Sraghuram 	}
37215373Sraghuram 
37225373Sraghuram 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
37235373Sraghuram }
37245373Sraghuram 
37255373Sraghuram static void
vsw_process_err_pkt(vsw_ldc_t * ldcp,void * epkt,vio_msg_tag_t * tagp)37265935Ssb155480 vsw_process_err_pkt(vsw_ldc_t *ldcp, void *epkt, vio_msg_tag_t *tagp)
37275373Sraghuram {
37285373Sraghuram 	_NOTE(ARGUNUSED(epkt))
37295373Sraghuram 
37305373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
37315935Ssb155480 	uint16_t	env = tagp->vio_subtype_env;
37325373Sraghuram 
37335373Sraghuram 	D1(vswp, "%s (%lld): enter\n", __func__, ldcp->ldc_id);
37345373Sraghuram 
37355373Sraghuram 	/*
37365373Sraghuram 	 * Error vio_subtypes have yet to be defined. So for
37375373Sraghuram 	 * the moment we can't do anything.
37385373Sraghuram 	 */
37395373Sraghuram 	D2(vswp, "%s: (%x) vio_subtype env", __func__, env);
37405373Sraghuram 
37415373Sraghuram 	D1(vswp, "%s (%lld): exit\n", __func__, ldcp->ldc_id);
37425373Sraghuram }
37435373Sraghuram 
37445373Sraghuram /* transmit the packet over the given port */
37455373Sraghuram int
vsw_portsend(vsw_port_t * port,mblk_t * mp)37468275SEric Cheng vsw_portsend(vsw_port_t *port, mblk_t *mp)
37475373Sraghuram {
37488275SEric Cheng 	mblk_t		*mpt;
37498275SEric Cheng 	int		count;
375012011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t 	*ldcp = port->ldcp;
37515373Sraghuram 	int		status = 0;
37525373Sraghuram 
37538275SEric Cheng 	count = vsw_vlan_frame_untag(port, VSW_VNETPORT, &mp, &mpt);
37548275SEric Cheng 	if (count != 0) {
37558275SEric Cheng 		status = ldcp->tx(ldcp, mp, mpt, count);
37566419Ssb155480 	}
37575935Ssb155480 	return (status);
37585935Ssb155480 }
37595935Ssb155480 
37605935Ssb155480 /*
37615935Ssb155480  * Break up frames into 2 seperate chains: normal and
37625935Ssb155480  * priority, based on the frame type. The number of
37635935Ssb155480  * priority frames is also counted and returned.
37645935Ssb155480  *
37655935Ssb155480  * Params:
37665935Ssb155480  * 	vswp:	pointer to the instance of vsw
37675935Ssb155480  *	np:	head of packet chain to be broken
37685935Ssb155480  *	npt:	tail of packet chain to be broken
37695935Ssb155480  *
37705935Ssb155480  * Returns:
37715935Ssb155480  *	np:	head of normal data packets
37725935Ssb155480  *	npt:	tail of normal data packets
37735935Ssb155480  *	hp:	head of high priority packets
37745935Ssb155480  *	hpt:	tail of high priority packets
37755935Ssb155480  */
37765935Ssb155480 static uint32_t
vsw_get_pri_packets(vsw_t * vswp,mblk_t ** np,mblk_t ** npt,mblk_t ** hp,mblk_t ** hpt)37775935Ssb155480 vsw_get_pri_packets(vsw_t *vswp, mblk_t **np, mblk_t **npt,
37785935Ssb155480 	mblk_t **hp, mblk_t **hpt)
37795935Ssb155480 {
37805935Ssb155480 	mblk_t			*tmp = NULL;
37815935Ssb155480 	mblk_t			*smp = NULL;
37825935Ssb155480 	mblk_t			*hmp = NULL;	/* high prio pkts head */
37835935Ssb155480 	mblk_t			*hmpt = NULL;	/* high prio pkts tail */
37845935Ssb155480 	mblk_t			*nmp = NULL;	/* normal pkts head */
37855935Ssb155480 	mblk_t			*nmpt = NULL;	/* normal pkts tail */
37865935Ssb155480 	uint32_t		count = 0;
37875935Ssb155480 	int			i;
37885935Ssb155480 	struct ether_header	*ehp;
37895935Ssb155480 	uint32_t		num_types;
37905935Ssb155480 	uint16_t		*types;
37915935Ssb155480 
37925935Ssb155480 	tmp = *np;
37935935Ssb155480 	while (tmp != NULL) {
37945935Ssb155480 
37955935Ssb155480 		smp = tmp;
37965935Ssb155480 		tmp = tmp->b_next;
37975935Ssb155480 		smp->b_next = NULL;
37985935Ssb155480 		smp->b_prev = NULL;
37995935Ssb155480 
38005935Ssb155480 		ehp = (struct ether_header *)smp->b_rptr;
38015935Ssb155480 		num_types = vswp->pri_num_types;
38025935Ssb155480 		types = vswp->pri_types;
38035935Ssb155480 		for (i = 0; i < num_types; i++) {
38045935Ssb155480 			if (ehp->ether_type == types[i]) {
38055935Ssb155480 				/* high priority frame */
38065935Ssb155480 
38075935Ssb155480 				if (hmp != NULL) {
38085935Ssb155480 					hmpt->b_next = smp;
38095935Ssb155480 					hmpt = smp;
38105935Ssb155480 				} else {
38115935Ssb155480 					hmp = hmpt = smp;
38125935Ssb155480 				}
38135935Ssb155480 				count++;
38145935Ssb155480 				break;
38155935Ssb155480 			}
38165935Ssb155480 		}
38175935Ssb155480 		if (i == num_types) {
38185935Ssb155480 			/* normal data frame */
38195935Ssb155480 
38205935Ssb155480 			if (nmp != NULL) {
38215935Ssb155480 				nmpt->b_next = smp;
38225935Ssb155480 				nmpt = smp;
38235935Ssb155480 			} else {
38245935Ssb155480 				nmp = nmpt = smp;
38255935Ssb155480 			}
38265935Ssb155480 		}
38275935Ssb155480 	}
38285935Ssb155480 
38295935Ssb155480 	*hp = hmp;
38305935Ssb155480 	*hpt = hmpt;
38315935Ssb155480 	*np = nmp;
38325935Ssb155480 	*npt = nmpt;
38335935Ssb155480 
38345935Ssb155480 	return (count);
38355935Ssb155480 }
38365935Ssb155480 
38375935Ssb155480 /*
38385935Ssb155480  * Wrapper function to transmit normal and/or priority frames over the channel.
38395935Ssb155480  */
38405935Ssb155480 static int
vsw_ldctx_pri(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)38415935Ssb155480 vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
38425935Ssb155480 {
38435935Ssb155480 	vsw_ldc_t 		*ldcp = (vsw_ldc_t *)arg;
38445935Ssb155480 	mblk_t			*tmp;
38455935Ssb155480 	mblk_t			*smp;
38465935Ssb155480 	mblk_t			*hmp;	/* high prio pkts head */
38475935Ssb155480 	mblk_t			*hmpt;	/* high prio pkts tail */
38485935Ssb155480 	mblk_t			*nmp;	/* normal pkts head */
38495935Ssb155480 	mblk_t			*nmpt;	/* normal pkts tail */
38505935Ssb155480 	uint32_t		n = 0;
38515935Ssb155480 	vsw_t			*vswp = ldcp->ldc_vswp;
38525935Ssb155480 
38535935Ssb155480 	ASSERT(VSW_PRI_ETH_DEFINED(vswp));
38545935Ssb155480 	ASSERT(count != 0);
38555935Ssb155480 
38565935Ssb155480 	nmp = mp;
38575935Ssb155480 	nmpt = mpt;
38585935Ssb155480 
38595935Ssb155480 	/* gather any priority frames from the chain of packets */
38605935Ssb155480 	n = vsw_get_pri_packets(vswp, &nmp, &nmpt, &hmp, &hmpt);
38615935Ssb155480 
38625935Ssb155480 	/* transmit priority frames */
38635935Ssb155480 	tmp = hmp;
38645935Ssb155480 	while (tmp != NULL) {
38655935Ssb155480 		smp = tmp;
38665935Ssb155480 		tmp = tmp->b_next;
38675935Ssb155480 		smp->b_next = NULL;
38685935Ssb155480 		vsw_ldcsend_pkt(ldcp, smp);
38695935Ssb155480 	}
38705935Ssb155480 
38715935Ssb155480 	count -= n;
38725935Ssb155480 
38735935Ssb155480 	if (count == 0) {
38745935Ssb155480 		/* no normal data frames to process */
38755935Ssb155480 		return (0);
38765935Ssb155480 	}
38775935Ssb155480 
38785935Ssb155480 	return (vsw_ldctx(ldcp, nmp, nmpt, count));
38795935Ssb155480 }
38805935Ssb155480 
38815935Ssb155480 /*
38825935Ssb155480  * Wrapper function to transmit normal frames over the channel.
38835935Ssb155480  */
38845935Ssb155480 static int
vsw_ldctx(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)38855935Ssb155480 vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
38865935Ssb155480 {
38875935Ssb155480 	vsw_ldc_t 	*ldcp = (vsw_ldc_t *)arg;
38885935Ssb155480 	mblk_t		*tmp = NULL;
38895935Ssb155480 
38905935Ssb155480 	ASSERT(count != 0);
38915373Sraghuram 	/*
38925935Ssb155480 	 * If the TX thread is enabled, then queue the
38935935Ssb155480 	 * ordinary frames and signal the tx thread.
38945373Sraghuram 	 */
38955373Sraghuram 	if (ldcp->tx_thread != NULL) {
38965935Ssb155480 
38975373Sraghuram 		mutex_enter(&ldcp->tx_thr_lock);
38985935Ssb155480 
38995935Ssb155480 		if ((ldcp->tx_cnt + count) >= vsw_max_tx_qcount) {
39005935Ssb155480 			/*
39015935Ssb155480 			 * If we reached queue limit,
39025935Ssb155480 			 * do not queue new packets,
39035935Ssb155480 			 * drop them.
39045935Ssb155480 			 */
39055935Ssb155480 			ldcp->ldc_stats.tx_qfull += count;
39065935Ssb155480 			mutex_exit(&ldcp->tx_thr_lock);
39075935Ssb155480 			freemsgchain(mp);
39085935Ssb155480 			goto exit;
39095935Ssb155480 		}
39105373Sraghuram 		if (ldcp->tx_mhead == NULL) {
39115373Sraghuram 			ldcp->tx_mhead = mp;
39125373Sraghuram 			ldcp->tx_mtail = mpt;
39135373Sraghuram 			cv_signal(&ldcp->tx_thr_cv);
39145373Sraghuram 		} else {
39155373Sraghuram 			ldcp->tx_mtail->b_next = mp;
39165373Sraghuram 			ldcp->tx_mtail = mpt;
39175373Sraghuram 		}
39185935Ssb155480 		ldcp->tx_cnt += count;
39195373Sraghuram 		mutex_exit(&ldcp->tx_thr_lock);
39205373Sraghuram 	} else {
39215373Sraghuram 		while (mp != NULL) {
39225373Sraghuram 			tmp = mp->b_next;
39235373Sraghuram 			mp->b_next = mp->b_prev = NULL;
39245373Sraghuram 			(void) vsw_ldcsend(ldcp, mp, 1);
39255373Sraghuram 			mp = tmp;
39265373Sraghuram 		}
39275373Sraghuram 	}
39285373Sraghuram 
39295935Ssb155480 exit:
39305935Ssb155480 	return (0);
39315935Ssb155480 }
39325935Ssb155480 
39335935Ssb155480 /*
39345935Ssb155480  * This function transmits the frame in the payload of a raw data
39355935Ssb155480  * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
39365935Ssb155480  * send special frames with high priorities, without going through
39375935Ssb155480  * the normal data path which uses descriptor ring mechanism.
39385935Ssb155480  */
39395935Ssb155480 static void
vsw_ldcsend_pkt(vsw_ldc_t * ldcp,mblk_t * mp)39405935Ssb155480 vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp)
39415935Ssb155480 {
39425935Ssb155480 	vio_raw_data_msg_t	*pkt;
39435935Ssb155480 	mblk_t			*bp;
39445935Ssb155480 	mblk_t			*nmp = NULL;
394512011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t		*vmp;
39465935Ssb155480 	caddr_t			dst;
39475935Ssb155480 	uint32_t		mblksz;
39485935Ssb155480 	uint32_t		size;
39495935Ssb155480 	uint32_t		nbytes;
39505935Ssb155480 	int			rv;
39515935Ssb155480 	vsw_t			*vswp = ldcp->ldc_vswp;
39525935Ssb155480 	vgen_stats_t		*statsp = &ldcp->ldc_stats;
39535935Ssb155480 
39545935Ssb155480 	if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
39555935Ssb155480 	    (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
39565935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
39575935Ssb155480 		DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
39585935Ssb155480 		    "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
39595935Ssb155480 		    ldcp->lane_out.lstate);
39605935Ssb155480 		goto send_pkt_exit;
39615935Ssb155480 	}
39625935Ssb155480 
39635935Ssb155480 	size = msgsize(mp);
39645935Ssb155480 
39655935Ssb155480 	/* frame size bigger than available payload len of raw data msg ? */
39665935Ssb155480 	if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
39675935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
39685935Ssb155480 		DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
39695935Ssb155480 		    ldcp->ldc_id, size);
39705935Ssb155480 		goto send_pkt_exit;
39715935Ssb155480 	}
39725935Ssb155480 
39735935Ssb155480 	if (size < ETHERMIN)
39745935Ssb155480 		size = ETHERMIN;
39755935Ssb155480 
39765935Ssb155480 	/* alloc space for a raw data message */
397712011SSriharsha.Basavapatna@Sun.COM 	vmp = vio_allocb(vswp->pri_tx_vmp);
397812011SSriharsha.Basavapatna@Sun.COM 	if (vmp == NULL) {
39795935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
39805935Ssb155480 		DWARN(vswp, "vio_allocb failed\n");
39815935Ssb155480 		goto send_pkt_exit;
398212011SSriharsha.Basavapatna@Sun.COM 	} else {
398312011SSriharsha.Basavapatna@Sun.COM 		nmp = vmp->mp;
39845935Ssb155480 	}
39855935Ssb155480 	pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
39865935Ssb155480 
39875935Ssb155480 	/* copy frame into the payload of raw data message */
39885935Ssb155480 	dst = (caddr_t)pkt->data;
39895935Ssb155480 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
39905935Ssb155480 		mblksz = MBLKL(bp);
39915935Ssb155480 		bcopy(bp->b_rptr, dst, mblksz);
39925935Ssb155480 		dst += mblksz;
39935935Ssb155480 	}
39945935Ssb155480 
399512011SSriharsha.Basavapatna@Sun.COM 	vmp->state = VIO_MBLK_HAS_DATA;
399612011SSriharsha.Basavapatna@Sun.COM 
39975935Ssb155480 	/* setup the raw data msg */
39985935Ssb155480 	pkt->tag.vio_msgtype = VIO_TYPE_DATA;
39995935Ssb155480 	pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
40005935Ssb155480 	pkt->tag.vio_subtype_env = VIO_PKT_DATA;
40015935Ssb155480 	pkt->tag.vio_sid = ldcp->local_session;
40025935Ssb155480 	nbytes = VIO_PKT_DATA_HDRSIZE + size;
40035935Ssb155480 
40045935Ssb155480 	/* send the msg over ldc */
40055935Ssb155480 	rv = vsw_send_msg(ldcp, (void *)pkt, nbytes, B_TRUE);
40065935Ssb155480 	if (rv != 0) {
40075935Ssb155480 		(void) atomic_inc_32(&statsp->tx_pri_fail);
40085935Ssb155480 		DWARN(vswp, "%s(%lld) Error sending priority frame\n", __func__,
40095935Ssb155480 		    ldcp->ldc_id);
40105935Ssb155480 		goto send_pkt_exit;
40115935Ssb155480 	}
40125935Ssb155480 
40135935Ssb155480 	/* update stats */
40145935Ssb155480 	(void) atomic_inc_64(&statsp->tx_pri_packets);
40155935Ssb155480 	(void) atomic_add_64(&statsp->tx_pri_packets, size);
40165935Ssb155480 
40175935Ssb155480 send_pkt_exit:
40185935Ssb155480 	if (nmp != NULL)
40195935Ssb155480 		freemsg(nmp);
40205935Ssb155480 	freemsg(mp);
40215373Sraghuram }
40225373Sraghuram 
40235373Sraghuram /*
40245373Sraghuram  * Transmit the packet over the given LDC channel.
40255373Sraghuram  *
40265373Sraghuram  * The 'retries' argument indicates how many times a packet
40275373Sraghuram  * is retried before it is dropped. Note, the retry is done
40285373Sraghuram  * only for a resource related failure, for all other failures
40295373Sraghuram  * the packet is dropped immediately.
40305373Sraghuram  */
40315373Sraghuram static int
vsw_ldcsend(vsw_ldc_t * ldcp,mblk_t * mp,uint32_t retries)40325935Ssb155480 vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries)
40335373Sraghuram {
403412011SSriharsha.Basavapatna@Sun.COM 	int		i;
403512011SSriharsha.Basavapatna@Sun.COM 	int		rc;
403612011SSriharsha.Basavapatna@Sun.COM 	int		status = 0;
403712011SSriharsha.Basavapatna@Sun.COM 	vsw_port_t	*port = ldcp->ldc_port;
403812011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp = NULL;
403912011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
40405373Sraghuram 
40415373Sraghuram 	for (i = 0; i < retries; ) {
40425373Sraghuram 		/*
40435373Sraghuram 		 * Send the message out using the appropriate
40445373Sraghuram 		 * transmit function which will free mblock when it
40455373Sraghuram 		 * is finished with it.
40465373Sraghuram 		 */
40475373Sraghuram 		mutex_enter(&port->tx_lock);
40485373Sraghuram 		if (port->transmit != NULL) {
40495373Sraghuram 			status = (*port->transmit)(ldcp, mp);
40505373Sraghuram 		}
40515373Sraghuram 		if (status == LDC_TX_SUCCESS) {
40525373Sraghuram 			mutex_exit(&port->tx_lock);
40535373Sraghuram 			break;
40545373Sraghuram 		}
40555373Sraghuram 		i++;	/* increment the counter here */
40565373Sraghuram 
40575373Sraghuram 		/* If its the last retry, then update the oerror */
40585373Sraghuram 		if ((i == retries) && (status == LDC_TX_NORESOURCES)) {
40595373Sraghuram 			ldcp->ldc_stats.oerrors++;
40605373Sraghuram 		}
40615373Sraghuram 		mutex_exit(&port->tx_lock);
40625373Sraghuram 
40635373Sraghuram 		if (status != LDC_TX_NORESOURCES) {
40645373Sraghuram 			/*
40655373Sraghuram 			 * No retrying required for errors un-related
40665373Sraghuram 			 * to resources.
40675373Sraghuram 			 */
40685373Sraghuram 			break;
40695373Sraghuram 		}
40705464Sraghuram 		if (((dp = ldcp->lane_out.dringp) != NULL) &&
40716419Ssb155480 		    ((VSW_VER_GTEQ(ldcp, 1, 2) &&
40725935Ssb155480 		    (ldcp->lane_out.xfer_mode & VIO_DRING_MODE_V1_2)) ||
40735935Ssb155480 		    ((VSW_VER_LT(ldcp, 1, 2) &&
40745935Ssb155480 		    (ldcp->lane_out.xfer_mode == VIO_DRING_MODE_V1_0))))) {
407512011SSriharsha.Basavapatna@Sun.COM 
407612011SSriharsha.Basavapatna@Sun.COM 			/* Need to reclaim in TxDring mode. */
407712011SSriharsha.Basavapatna@Sun.COM 			if (lp->dring_mode == VIO_TX_DRING) {
407812011SSriharsha.Basavapatna@Sun.COM 				rc = vsw_reclaim_dring(dp, dp->end_idx);
407912011SSriharsha.Basavapatna@Sun.COM 			}
408012011SSriharsha.Basavapatna@Sun.COM 
40815464Sraghuram 		} else {
40825464Sraghuram 			/*
40835464Sraghuram 			 * If there is no dring or the xfer_mode is
40845464Sraghuram 			 * set to DESC_MODE(ie., OBP), then simply break here.
40855464Sraghuram 			 */
40865373Sraghuram 			break;
40875373Sraghuram 		}
40885373Sraghuram 
40895373Sraghuram 		/*
40905373Sraghuram 		 * Delay only if none were reclaimed
40915373Sraghuram 		 * and its not the last retry.
40925373Sraghuram 		 */
40935373Sraghuram 		if ((rc == 0) && (i < retries)) {
40945373Sraghuram 			delay(drv_usectohz(vsw_ldc_tx_delay));
40955373Sraghuram 		}
40965373Sraghuram 	}
40975373Sraghuram 	freemsg(mp);
40985373Sraghuram 	return (status);
40995373Sraghuram }
41005373Sraghuram 
41015373Sraghuram /*
41025373Sraghuram  * Send an in-band descriptor message over ldc.
41035373Sraghuram  */
41045373Sraghuram static int
vsw_descrsend(vsw_ldc_t * ldcp,mblk_t * mp)41055373Sraghuram vsw_descrsend(vsw_ldc_t *ldcp, mblk_t *mp)
41065373Sraghuram {
41075373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
41085373Sraghuram 	vnet_ibnd_desc_t	ibnd_msg;
41095373Sraghuram 	vsw_private_desc_t	*priv_desc = NULL;
41105373Sraghuram 	dring_info_t		*dp = NULL;
41115373Sraghuram 	size_t			n, size = 0;
41125373Sraghuram 	caddr_t			bufp;
41135373Sraghuram 	mblk_t			*bp;
41145373Sraghuram 	int			idx, i;
41155373Sraghuram 	int			status = LDC_TX_SUCCESS;
41165373Sraghuram 	static int		warn_msg = 1;
41176419Ssb155480 	lane_t			*lp = &ldcp->lane_out;
41185373Sraghuram 
41195373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
41205373Sraghuram 
41215373Sraghuram 	ASSERT(mp != NULL);
41225373Sraghuram 
41235373Sraghuram 	if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
41245373Sraghuram 	    (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
41255373Sraghuram 		DERR(vswp, "%s(%lld) status(%d) state (0x%llx), dropping pkt",
41265373Sraghuram 		    __func__, ldcp->ldc_id, ldcp->ldc_status,
41275373Sraghuram 		    ldcp->lane_out.lstate);
41285373Sraghuram 		ldcp->ldc_stats.oerrors++;
41295373Sraghuram 		return (LDC_TX_FAILURE);
41305373Sraghuram 	}
41315373Sraghuram 
41325373Sraghuram 	/*
413312011SSriharsha.Basavapatna@Sun.COM 	 * The dring here is as an internal buffer,
413412011SSriharsha.Basavapatna@Sun.COM 	 * rather than a transfer channel.
41355373Sraghuram 	 */
41365373Sraghuram 	if ((dp = ldcp->lane_out.dringp) == NULL) {
41375373Sraghuram 		DERR(vswp, "%s(%lld): no dring for outbound lane",
41385373Sraghuram 		    __func__, ldcp->ldc_id);
41395373Sraghuram 		DERR(vswp, "%s(%lld) status(%d) state (0x%llx)", __func__,
41405373Sraghuram 		    ldcp->ldc_id, ldcp->ldc_status, ldcp->lane_out.lstate);
41415373Sraghuram 		ldcp->ldc_stats.oerrors++;
41425373Sraghuram 		return (LDC_TX_FAILURE);
41435373Sraghuram 	}
41445373Sraghuram 
41455373Sraghuram 	size = msgsize(mp);
41466419Ssb155480 	if (size > (size_t)lp->mtu) {
41475373Sraghuram 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
41485373Sraghuram 		    ldcp->ldc_id, size);
41495373Sraghuram 		ldcp->ldc_stats.oerrors++;
41505373Sraghuram 		return (LDC_TX_FAILURE);
41515373Sraghuram 	}
41525373Sraghuram 
41535373Sraghuram 	/*
41545373Sraghuram 	 * Find a free descriptor in our buffer ring
41555373Sraghuram 	 */
41565373Sraghuram 	if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) {
41575373Sraghuram 		if (warn_msg) {
41585373Sraghuram 			DERR(vswp, "%s(%lld): no descriptor available for ring "
41595373Sraghuram 			    "at 0x%llx", __func__, ldcp->ldc_id, dp);
41605373Sraghuram 			warn_msg = 0;
41615373Sraghuram 		}
41625373Sraghuram 
41635373Sraghuram 		/* nothing more we can do */
41645373Sraghuram 		status = LDC_TX_NORESOURCES;
41655373Sraghuram 		goto vsw_descrsend_free_exit;
41665373Sraghuram 	} else {
41675373Sraghuram 		D2(vswp, "%s(%lld): free private descriptor found at pos "
41685373Sraghuram 		    "%ld addr 0x%x\n", __func__, ldcp->ldc_id, idx, priv_desc);
41695373Sraghuram 		warn_msg = 1;
41705373Sraghuram 	}
41715373Sraghuram 
41725373Sraghuram 	/* copy data into the descriptor */
41735373Sraghuram 	bufp = priv_desc->datap;
41745373Sraghuram 	for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) {
41755373Sraghuram 		n = MBLKL(bp);
41765373Sraghuram 		bcopy(bp->b_rptr, bufp, n);
41775373Sraghuram 		bufp += n;
41785373Sraghuram 	}
41795373Sraghuram 
41805373Sraghuram 	priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size;
41815373Sraghuram 
41825373Sraghuram 	/* create and send the in-band descp msg */
41835373Sraghuram 	ibnd_msg.hdr.tag.vio_msgtype = VIO_TYPE_DATA;
41845373Sraghuram 	ibnd_msg.hdr.tag.vio_subtype = VIO_SUBTYPE_INFO;
41855373Sraghuram 	ibnd_msg.hdr.tag.vio_subtype_env = VIO_DESC_DATA;
41865373Sraghuram 	ibnd_msg.hdr.tag.vio_sid = ldcp->local_session;
41875373Sraghuram 
41885373Sraghuram 	/*
41895373Sraghuram 	 * Copy the mem cookies describing the data from the
41905373Sraghuram 	 * private region of the descriptor ring into the inband
41915373Sraghuram 	 * descriptor.
41925373Sraghuram 	 */
41935373Sraghuram 	for (i = 0; i < priv_desc->ncookies; i++) {
41945373Sraghuram 		bcopy(&priv_desc->memcookie[i], &ibnd_msg.memcookie[i],
41955373Sraghuram 		    sizeof (ldc_mem_cookie_t));
41965373Sraghuram 	}
41975373Sraghuram 
41985373Sraghuram 	ibnd_msg.hdr.desc_handle = idx;
41995373Sraghuram 	ibnd_msg.ncookies = priv_desc->ncookies;
42005373Sraghuram 	ibnd_msg.nbytes = size;
42015373Sraghuram 
42025373Sraghuram 	ldcp->ldc_stats.opackets++;
42035373Sraghuram 	ldcp->ldc_stats.obytes += size;
42045373Sraghuram 
42055373Sraghuram 	(void) vsw_send_msg(ldcp, (void *)&ibnd_msg,
42065373Sraghuram 	    sizeof (vnet_ibnd_desc_t), B_TRUE);
42075373Sraghuram 
42085373Sraghuram vsw_descrsend_free_exit:
42095373Sraghuram 
42105373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
42115373Sraghuram 	return (status);
42125373Sraghuram }
42135373Sraghuram 
42145373Sraghuram static void
vsw_send_ver(void * arg)42155373Sraghuram vsw_send_ver(void *arg)
42165373Sraghuram {
42175373Sraghuram 	vsw_ldc_t	*ldcp = (vsw_ldc_t *)arg;
42185373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
42195373Sraghuram 	lane_t		*lp = &ldcp->lane_out;
42205373Sraghuram 	vio_ver_msg_t	ver_msg;
42215373Sraghuram 
42225373Sraghuram 	D1(vswp, "%s enter", __func__);
42235373Sraghuram 
42245373Sraghuram 	ver_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
42255373Sraghuram 	ver_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
42265373Sraghuram 	ver_msg.tag.vio_subtype_env = VIO_VER_INFO;
42275373Sraghuram 	ver_msg.tag.vio_sid = ldcp->local_session;
42285373Sraghuram 
42295935Ssb155480 	if (vsw_obp_ver_proto_workaround == B_FALSE) {
42305935Ssb155480 		ver_msg.ver_major = vsw_versions[0].ver_major;
42315935Ssb155480 		ver_msg.ver_minor = vsw_versions[0].ver_minor;
42325935Ssb155480 	} else {
42335935Ssb155480 		/* use the major,minor that we've ack'd */
42345935Ssb155480 		lane_t	*lpi = &ldcp->lane_in;
42355935Ssb155480 		ver_msg.ver_major = lpi->ver_major;
42365935Ssb155480 		ver_msg.ver_minor = lpi->ver_minor;
42375935Ssb155480 	}
42385373Sraghuram 	ver_msg.dev_class = VDEV_NETWORK_SWITCH;
42395373Sraghuram 
42405373Sraghuram 	lp->lstate |= VSW_VER_INFO_SENT;
42415373Sraghuram 	lp->ver_major = ver_msg.ver_major;
42425373Sraghuram 	lp->ver_minor = ver_msg.ver_minor;
42435373Sraghuram 
42445373Sraghuram 	DUMP_TAG(ver_msg.tag);
42455373Sraghuram 
42465373Sraghuram 	(void) vsw_send_msg(ldcp, &ver_msg, sizeof (vio_ver_msg_t), B_TRUE);
42475373Sraghuram 
42485373Sraghuram 	D1(vswp, "%s (%d): exit", __func__, ldcp->ldc_id);
42495373Sraghuram }
42505373Sraghuram 
42515373Sraghuram static void
vsw_send_attr(vsw_ldc_t * ldcp)42525373Sraghuram vsw_send_attr(vsw_ldc_t *ldcp)
42535373Sraghuram {
42545373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
42555373Sraghuram 	lane_t			*lp = &ldcp->lane_out;
42565373Sraghuram 	vnet_attr_msg_t		attr_msg;
42575373Sraghuram 
42585373Sraghuram 	D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
42595373Sraghuram 
42605373Sraghuram 	/*
42615373Sraghuram 	 * Subtype is set to INFO by default
42625373Sraghuram 	 */
42635373Sraghuram 	attr_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
42645373Sraghuram 	attr_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
42655373Sraghuram 	attr_msg.tag.vio_subtype_env = VIO_ATTR_INFO;
42665373Sraghuram 	attr_msg.tag.vio_sid = ldcp->local_session;
42675373Sraghuram 
42685373Sraghuram 	/* payload copied from default settings for lane */
42695373Sraghuram 	attr_msg.mtu = lp->mtu;
42705373Sraghuram 	attr_msg.addr_type = lp->addr_type;
42715373Sraghuram 	attr_msg.xfer_mode = lp->xfer_mode;
42725373Sraghuram 	attr_msg.ack_freq = lp->xfer_mode;
427312011SSriharsha.Basavapatna@Sun.COM 	attr_msg.options = lp->dring_mode;
42745373Sraghuram 
42755373Sraghuram 	READ_ENTER(&vswp->if_lockrw);
42765462Swentaoy 	attr_msg.addr = vnet_macaddr_strtoul((vswp->if_addr).ether_addr_octet);
42775373Sraghuram 	RW_EXIT(&vswp->if_lockrw);
42785373Sraghuram 
42795373Sraghuram 	ldcp->lane_out.lstate |= VSW_ATTR_INFO_SENT;
42805373Sraghuram 
42815373Sraghuram 	DUMP_TAG(attr_msg.tag);
42825373Sraghuram 
42835373Sraghuram 	(void) vsw_send_msg(ldcp, &attr_msg, sizeof (vnet_attr_msg_t), B_TRUE);
42845373Sraghuram 
42855373Sraghuram 	D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
42865373Sraghuram }
42875373Sraghuram 
42885373Sraghuram static void
vsw_send_dring_info(vsw_ldc_t * ldcp)42895373Sraghuram vsw_send_dring_info(vsw_ldc_t *ldcp)
42905373Sraghuram {
429112011SSriharsha.Basavapatna@Sun.COM 	int		msgsize;
429212011SSriharsha.Basavapatna@Sun.COM 	void		*msg;
429312011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
429412011SSriharsha.Basavapatna@Sun.COM 	vsw_port_t	*port = ldcp->ldc_port;
429512011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
429612011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->ldc_stats;
42975373Sraghuram 
42985373Sraghuram 	D1(vswp, "%s: (%ld) enter", __func__, ldcp->ldc_id);
42995373Sraghuram 
430012011SSriharsha.Basavapatna@Sun.COM 	/* dring mode has been negotiated in attr phase; save in stats */
430112011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_mode = lp->dring_mode;
430212011SSriharsha.Basavapatna@Sun.COM 
430312011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
430412011SSriharsha.Basavapatna@Sun.COM 		/*
430512011SSriharsha.Basavapatna@Sun.COM 		 * Change the transmit routine for RxDringData mode.
430612011SSriharsha.Basavapatna@Sun.COM 		 */
430712011SSriharsha.Basavapatna@Sun.COM 		port->transmit = vsw_dringsend_shm;
430812011SSriharsha.Basavapatna@Sun.COM 		msg = (void *) vsw_create_rx_dring_info(ldcp);
430912011SSriharsha.Basavapatna@Sun.COM 		if (msg == NULL) {
431012011SSriharsha.Basavapatna@Sun.COM 			return;
431112011SSriharsha.Basavapatna@Sun.COM 		}
431212011SSriharsha.Basavapatna@Sun.COM 		msgsize =
431312011SSriharsha.Basavapatna@Sun.COM 		    VNET_DRING_REG_EXT_MSG_SIZE(lp->dringp->data_ncookies);
431412011SSriharsha.Basavapatna@Sun.COM 		ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
431512011SSriharsha.Basavapatna@Sun.COM 		    vsw_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
431612011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dringdata = vsw_process_dringdata_shm;
431712011SSriharsha.Basavapatna@Sun.COM 	} else {
431812011SSriharsha.Basavapatna@Sun.COM 		msg = (void *) vsw_create_tx_dring_info(ldcp);
431912011SSriharsha.Basavapatna@Sun.COM 		if (msg == NULL) {
432012011SSriharsha.Basavapatna@Sun.COM 			return;
432112011SSriharsha.Basavapatna@Sun.COM 		}
432212011SSriharsha.Basavapatna@Sun.COM 		msgsize = sizeof (vio_dring_reg_msg_t);
432312011SSriharsha.Basavapatna@Sun.COM 		ldcp->msg_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
432412011SSriharsha.Basavapatna@Sun.COM 		    vsw_ldc_msg_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
432512011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dringdata = vsw_process_dringdata;
43265373Sraghuram 	}
43275373Sraghuram 
432812011SSriharsha.Basavapatna@Sun.COM 	lp->lstate |= VSW_DRING_INFO_SENT;
432912011SSriharsha.Basavapatna@Sun.COM 	DUMP_TAG_PTR((vio_msg_tag_t *)msg);
433012011SSriharsha.Basavapatna@Sun.COM 	(void) vsw_send_msg(ldcp, msg, msgsize, B_TRUE);
433112011SSriharsha.Basavapatna@Sun.COM 	kmem_free(msg, msgsize);
43325373Sraghuram 
43335373Sraghuram 	D1(vswp, "%s: (%ld) exit", __func__, ldcp->ldc_id);
43345373Sraghuram }
43355373Sraghuram 
43365373Sraghuram static void
vsw_send_rdx(vsw_ldc_t * ldcp)43375373Sraghuram vsw_send_rdx(vsw_ldc_t *ldcp)
43385373Sraghuram {
43395373Sraghuram 	vsw_t		*vswp = ldcp->ldc_vswp;
43405373Sraghuram 	vio_rdx_msg_t	rdx_msg;
43415373Sraghuram 
43425373Sraghuram 	D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
43435373Sraghuram 
43445373Sraghuram 	rdx_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
43455373Sraghuram 	rdx_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
43465373Sraghuram 	rdx_msg.tag.vio_subtype_env = VIO_RDX;
43475373Sraghuram 	rdx_msg.tag.vio_sid = ldcp->local_session;
43485373Sraghuram 
43495373Sraghuram 	ldcp->lane_in.lstate |= VSW_RDX_INFO_SENT;
43505373Sraghuram 
43515373Sraghuram 	DUMP_TAG(rdx_msg.tag);
43525373Sraghuram 
43535373Sraghuram 	(void) vsw_send_msg(ldcp, &rdx_msg, sizeof (vio_rdx_msg_t), B_TRUE);
43545373Sraghuram 
43555373Sraghuram 	D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
43565373Sraghuram }
43575373Sraghuram 
43585373Sraghuram /*
43595373Sraghuram  * Remove the specified address from the list of address maintained
43605373Sraghuram  * in this port node.
43615373Sraghuram  */
43625373Sraghuram mcst_addr_t *
vsw_del_addr(uint8_t devtype,void * arg,uint64_t addr)43635373Sraghuram vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr)
43645373Sraghuram {
43655373Sraghuram 	vsw_t		*vswp = NULL;
43665373Sraghuram 	vsw_port_t	*port = NULL;
43675373Sraghuram 	mcst_addr_t	*prev_p = NULL;
43685373Sraghuram 	mcst_addr_t	*curr_p = NULL;
43695373Sraghuram 
43705373Sraghuram 	D1(NULL, "%s: enter : devtype %d : addr 0x%llx",
43715373Sraghuram 	    __func__, devtype, addr);
43725373Sraghuram 
43735373Sraghuram 	if (devtype == VSW_VNETPORT) {
43745373Sraghuram 		port = (vsw_port_t *)arg;
43755373Sraghuram 		mutex_enter(&port->mca_lock);
43765373Sraghuram 		prev_p = curr_p = port->mcap;
43775373Sraghuram 	} else {
43785373Sraghuram 		vswp = (vsw_t *)arg;
43795373Sraghuram 		mutex_enter(&vswp->mca_lock);
43805373Sraghuram 		prev_p = curr_p = vswp->mcap;
43815373Sraghuram 	}
43825373Sraghuram 
43835373Sraghuram 	while (curr_p != NULL) {
43845373Sraghuram 		if (curr_p->addr == addr) {
43855373Sraghuram 			D2(NULL, "%s: address found", __func__);
43865373Sraghuram 			/* match found */
43875373Sraghuram 			if (prev_p == curr_p) {
43885373Sraghuram 				/* list head */
43895373Sraghuram 				if (devtype == VSW_VNETPORT)
43905373Sraghuram 					port->mcap = curr_p->nextp;
43915373Sraghuram 				else
43925373Sraghuram 					vswp->mcap = curr_p->nextp;
43935373Sraghuram 			} else {
43945373Sraghuram 				prev_p->nextp = curr_p->nextp;
43955373Sraghuram 			}
43965373Sraghuram 			break;
43975373Sraghuram 		} else {
43985373Sraghuram 			prev_p = curr_p;
43995373Sraghuram 			curr_p = curr_p->nextp;
44005373Sraghuram 		}
44015373Sraghuram 	}
44025373Sraghuram 
44035373Sraghuram 	if (devtype == VSW_VNETPORT)
44045373Sraghuram 		mutex_exit(&port->mca_lock);
44055373Sraghuram 	else
44065373Sraghuram 		mutex_exit(&vswp->mca_lock);
44075373Sraghuram 
44085373Sraghuram 	D1(NULL, "%s: exit", __func__);
44095373Sraghuram 
44105373Sraghuram 	return (curr_p);
44115373Sraghuram }
44125373Sraghuram 
44135373Sraghuram /*
44145373Sraghuram  * Create a ring consisting of just a private portion and link
44155373Sraghuram  * it into the list of rings for the outbound lane.
44165373Sraghuram  *
44175373Sraghuram  * These type of rings are used primarily for temporary data
44185373Sraghuram  * storage (i.e. as data buffers).
44195373Sraghuram  */
44205373Sraghuram void
vsw_create_privring(vsw_ldc_t * ldcp)44215373Sraghuram vsw_create_privring(vsw_ldc_t *ldcp)
44225373Sraghuram {
442312011SSriharsha.Basavapatna@Sun.COM 	dring_info_t		*dp;
44245373Sraghuram 	vsw_t			*vswp = ldcp->ldc_vswp;
44255373Sraghuram 
44265373Sraghuram 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
44275373Sraghuram 
44285373Sraghuram 	dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
44295373Sraghuram 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
443012011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
443112011SSriharsha.Basavapatna@Sun.COM 	ldcp->lane_out.dringp = dp;
44325373Sraghuram 
44335373Sraghuram 	/* no public section */
44345373Sraghuram 	dp->pub_addr = NULL;
44355373Sraghuram 	dp->priv_addr = kmem_zalloc(
443612011SSriharsha.Basavapatna@Sun.COM 	    (sizeof (vsw_private_desc_t) * vsw_num_descriptors), KM_SLEEP);
443712011SSriharsha.Basavapatna@Sun.COM 	dp->num_descriptors = vsw_num_descriptors;
443812011SSriharsha.Basavapatna@Sun.COM 
443912011SSriharsha.Basavapatna@Sun.COM 	if (vsw_setup_tx_dring(ldcp, dp)) {
44405373Sraghuram 		DERR(vswp, "%s: setup of ring failed", __func__);
444112011SSriharsha.Basavapatna@Sun.COM 		vsw_destroy_tx_dring(ldcp);
44425373Sraghuram 		return;
44435373Sraghuram 	}
44445373Sraghuram 
44455373Sraghuram 	/* haven't used any descriptors yet */
44465373Sraghuram 	dp->end_idx = 0;
44475373Sraghuram 	dp->restart_reqd = B_TRUE;
44485373Sraghuram 
44495373Sraghuram 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
44505373Sraghuram }
44515373Sraghuram 
44525373Sraghuram /*
44535373Sraghuram  * Set the default lane attributes. These are copied into
44545373Sraghuram  * the attr msg we send to our peer. If they are not acceptable
44555373Sraghuram  * then (currently) the handshake ends.
44565373Sraghuram  */
44575373Sraghuram static void
vsw_set_lane_attr(vsw_t * vswp,lane_t * lp)44585373Sraghuram vsw_set_lane_attr(vsw_t *vswp, lane_t *lp)
44595373Sraghuram {
44605373Sraghuram 	bzero(lp, sizeof (lane_t));
44615373Sraghuram 
44625373Sraghuram 	READ_ENTER(&vswp->if_lockrw);
44635373Sraghuram 	ether_copy(&(vswp->if_addr), &(lp->addr));
44645373Sraghuram 	RW_EXIT(&vswp->if_lockrw);
44655373Sraghuram 
44666419Ssb155480 	lp->mtu = vswp->max_frame_size;
44675373Sraghuram 	lp->addr_type = ADDR_TYPE_MAC;
44685935Ssb155480 	lp->xfer_mode = VIO_DRING_MODE_V1_0;
44695373Sraghuram 	lp->ack_freq = 0;	/* for shared mode */
44705935Ssb155480 	lp->seq_num = VNET_ISS;
44715373Sraghuram }
44725373Sraghuram 
44735373Sraghuram /*
447412011SSriharsha.Basavapatna@Sun.COM  * Map the descriptor ring exported by the peer.
44755373Sraghuram  */
447612011SSriharsha.Basavapatna@Sun.COM static dring_info_t *
vsw_map_dring(vsw_ldc_t * ldcp,void * pkt)447712011SSriharsha.Basavapatna@Sun.COM vsw_map_dring(vsw_ldc_t *ldcp, void *pkt)
44785373Sraghuram {
447912011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp = NULL;
448012011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
448112011SSriharsha.Basavapatna@Sun.COM 
448212011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
448312011SSriharsha.Basavapatna@Sun.COM 		/*
448412011SSriharsha.Basavapatna@Sun.COM 		 * In RxDringData mode, dring that we map in
448512011SSriharsha.Basavapatna@Sun.COM 		 * becomes our transmit descriptor ring.
448612011SSriharsha.Basavapatna@Sun.COM 		 */
448712011SSriharsha.Basavapatna@Sun.COM 		dp =  vsw_map_tx_dring(ldcp, pkt);
448812011SSriharsha.Basavapatna@Sun.COM 	} else {
448912011SSriharsha.Basavapatna@Sun.COM 		/*
449012011SSriharsha.Basavapatna@Sun.COM 		 * In TxDring mode, dring that we map in
449112011SSriharsha.Basavapatna@Sun.COM 		 * becomes our receive descriptor ring.
449212011SSriharsha.Basavapatna@Sun.COM 		 */
449312011SSriharsha.Basavapatna@Sun.COM 		dp =  vsw_map_rx_dring(ldcp, pkt);
44945373Sraghuram 	}
449512011SSriharsha.Basavapatna@Sun.COM 	return (dp);
44965373Sraghuram }
44975373Sraghuram 
44985373Sraghuram /*
449912011SSriharsha.Basavapatna@Sun.COM  * Common dring mapping function used in both TxDring and RxDringData modes.
45005373Sraghuram  */
450112011SSriharsha.Basavapatna@Sun.COM dring_info_t *
vsw_map_dring_cmn(vsw_ldc_t * ldcp,vio_dring_reg_msg_t * dring_pkt)450212011SSriharsha.Basavapatna@Sun.COM vsw_map_dring_cmn(vsw_ldc_t *ldcp, vio_dring_reg_msg_t *dring_pkt)
45035373Sraghuram {
450412011SSriharsha.Basavapatna@Sun.COM 	int		rv;
450512011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp;
450612011SSriharsha.Basavapatna@Sun.COM 	ldc_mem_info_t	minfo;
450712011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
450812011SSriharsha.Basavapatna@Sun.COM 
450912011SSriharsha.Basavapatna@Sun.COM 	/*
451012011SSriharsha.Basavapatna@Sun.COM 	 * If the dring params are unacceptable then we NACK back.
451112011SSriharsha.Basavapatna@Sun.COM 	 */
451212011SSriharsha.Basavapatna@Sun.COM 	if ((dring_pkt->num_descriptors == 0) ||
451312011SSriharsha.Basavapatna@Sun.COM 	    (dring_pkt->descriptor_size == 0) ||
451412011SSriharsha.Basavapatna@Sun.COM 	    (dring_pkt->ncookies != 1)) {
451512011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s (%lld): invalid dring info",
451612011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id);
451712011SSriharsha.Basavapatna@Sun.COM 		return (NULL);
45185373Sraghuram 	}
45195373Sraghuram 
452012011SSriharsha.Basavapatna@Sun.COM 	dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
452112011SSriharsha.Basavapatna@Sun.COM 
452212011SSriharsha.Basavapatna@Sun.COM 	dp->num_descriptors = dring_pkt->num_descriptors;
452312011SSriharsha.Basavapatna@Sun.COM 	dp->descriptor_size = dring_pkt->descriptor_size;
452412011SSriharsha.Basavapatna@Sun.COM 	dp->options = dring_pkt->options;
452512011SSriharsha.Basavapatna@Sun.COM 	dp->dring_ncookies = dring_pkt->ncookies;
452612011SSriharsha.Basavapatna@Sun.COM 
452712011SSriharsha.Basavapatna@Sun.COM 	/*
452812011SSriharsha.Basavapatna@Sun.COM 	 * Note: should only get one cookie. Enforced in
452912011SSriharsha.Basavapatna@Sun.COM 	 * the ldc layer.
453012011SSriharsha.Basavapatna@Sun.COM 	 */
453112011SSriharsha.Basavapatna@Sun.COM 	bcopy(&dring_pkt->cookie[0], &dp->dring_cookie[0],
453212011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t));
453312011SSriharsha.Basavapatna@Sun.COM 
453412011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_map(ldcp->ldc_handle, &dp->dring_cookie[0],
453512011SSriharsha.Basavapatna@Sun.COM 	    dp->dring_ncookies, dp->num_descriptors, dp->descriptor_size,
453612011SSriharsha.Basavapatna@Sun.COM 	    LDC_DIRECT_MAP, &(dp->dring_handle));
453712011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
453812011SSriharsha.Basavapatna@Sun.COM 		goto fail;
453912011SSriharsha.Basavapatna@Sun.COM 	}
454012011SSriharsha.Basavapatna@Sun.COM 
454112011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_info(dp->dring_handle, &minfo);
454212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
454312011SSriharsha.Basavapatna@Sun.COM 		goto fail;
454412011SSriharsha.Basavapatna@Sun.COM 	}
454512011SSriharsha.Basavapatna@Sun.COM 	/* store the address of the ring */
454612011SSriharsha.Basavapatna@Sun.COM 	dp->pub_addr = minfo.vaddr;
454712011SSriharsha.Basavapatna@Sun.COM 
454812011SSriharsha.Basavapatna@Sun.COM 	/* cache the dring mtype */
454912011SSriharsha.Basavapatna@Sun.COM 	dp->dring_mtype = minfo.mtype;
455012011SSriharsha.Basavapatna@Sun.COM 
455112011SSriharsha.Basavapatna@Sun.COM 	/* no private section as we are importing */
455212011SSriharsha.Basavapatna@Sun.COM 	dp->priv_addr = NULL;
455312011SSriharsha.Basavapatna@Sun.COM 
455412011SSriharsha.Basavapatna@Sun.COM 	/*
455512011SSriharsha.Basavapatna@Sun.COM 	 * Using simple mono increasing int for ident at the moment.
455612011SSriharsha.Basavapatna@Sun.COM 	 */
455712011SSriharsha.Basavapatna@Sun.COM 	dp->ident = ldcp->next_ident;
455812011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_ident++;
455912011SSriharsha.Basavapatna@Sun.COM 
456012011SSriharsha.Basavapatna@Sun.COM 	/*
456112011SSriharsha.Basavapatna@Sun.COM 	 * Acknowledge it; we send back a unique dring identifier that
456212011SSriharsha.Basavapatna@Sun.COM 	 * the sending side will use in future to refer to this
456312011SSriharsha.Basavapatna@Sun.COM 	 * descriptor ring.
456412011SSriharsha.Basavapatna@Sun.COM 	 */
456512011SSriharsha.Basavapatna@Sun.COM 	dring_pkt->dring_ident = dp->ident;
456612011SSriharsha.Basavapatna@Sun.COM 
456712011SSriharsha.Basavapatna@Sun.COM 	return (dp);
456812011SSriharsha.Basavapatna@Sun.COM fail:
456912011SSriharsha.Basavapatna@Sun.COM 	if (dp->dring_handle != NULL) {
457012011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unmap(dp->dring_handle);
457112011SSriharsha.Basavapatna@Sun.COM 	}
457212011SSriharsha.Basavapatna@Sun.COM 	kmem_free(dp, sizeof (*dp));
457312011SSriharsha.Basavapatna@Sun.COM 	return (NULL);
45745373Sraghuram }
45755373Sraghuram 
45765373Sraghuram /*
457712011SSriharsha.Basavapatna@Sun.COM  * Unmap the descriptor ring exported by the peer.
45785373Sraghuram  */
457912011SSriharsha.Basavapatna@Sun.COM static void
vsw_unmap_dring(vsw_ldc_t * ldcp)458012011SSriharsha.Basavapatna@Sun.COM vsw_unmap_dring(vsw_ldc_t *ldcp)
45815373Sraghuram {
458212011SSriharsha.Basavapatna@Sun.COM 	lane_t	*lane_out = &ldcp->lane_out;
458312011SSriharsha.Basavapatna@Sun.COM 
458412011SSriharsha.Basavapatna@Sun.COM 	if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
458512011SSriharsha.Basavapatna@Sun.COM 		vsw_unmap_tx_dring(ldcp);
45865373Sraghuram 	} else {
458712011SSriharsha.Basavapatna@Sun.COM 		vsw_unmap_rx_dring(ldcp);
45885373Sraghuram 	}
45895373Sraghuram }
45905373Sraghuram 
45915373Sraghuram /*
459212011SSriharsha.Basavapatna@Sun.COM  * Map the shared memory data buffer area exported by the peer.
459312011SSriharsha.Basavapatna@Sun.COM  * Used in RxDringData mode only.
45945373Sraghuram  */
45955373Sraghuram static int
vsw_map_data(vsw_ldc_t * ldcp,dring_info_t * dp,void * pkt)459612011SSriharsha.Basavapatna@Sun.COM vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt)
45975373Sraghuram {
459812011SSriharsha.Basavapatna@Sun.COM 	int			rv;
459912011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_ext_msg_t	*emsg;
460012011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t	*msg = pkt;
460112011SSriharsha.Basavapatna@Sun.COM 	uint8_t			*buf = (uint8_t *)msg->cookie;
460212011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
4603*13098SWentao.Yang@Sun.COM 	ldc_mem_info_t		minfo;
460412011SSriharsha.Basavapatna@Sun.COM 
460512011SSriharsha.Basavapatna@Sun.COM 	/* skip over dring cookies */
460612011SSriharsha.Basavapatna@Sun.COM 	ASSERT(msg->ncookies == 1);
460712011SSriharsha.Basavapatna@Sun.COM 	buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
460812011SSriharsha.Basavapatna@Sun.COM 
460912011SSriharsha.Basavapatna@Sun.COM 	emsg = (vio_dring_reg_ext_msg_t *)buf;
461012011SSriharsha.Basavapatna@Sun.COM 	if (emsg->data_ncookies > VNET_DATA_AREA_COOKIES) {
46115373Sraghuram 		return (1);
46125373Sraghuram 	}
46135373Sraghuram 
461412011SSriharsha.Basavapatna@Sun.COM 	/* save # of data area cookies */
461512011SSriharsha.Basavapatna@Sun.COM 	dp->data_ncookies = emsg->data_ncookies;
461612011SSriharsha.Basavapatna@Sun.COM 
461712011SSriharsha.Basavapatna@Sun.COM 	/* save data area size */
461812011SSriharsha.Basavapatna@Sun.COM 	dp->data_sz = emsg->data_area_size;
461912011SSriharsha.Basavapatna@Sun.COM 
462012011SSriharsha.Basavapatna@Sun.COM 	/* allocate ldc mem handle for data area */
462112011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle);
462212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
462312011SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN, "ldc_mem_alloc_handle failed\n");
462412011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s (%lld) ldc_mem_alloc_handle() failed: %d\n",
462512011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id, rv);
462612011SSriharsha.Basavapatna@Sun.COM 		return (1);
462712011SSriharsha.Basavapatna@Sun.COM 	}
462812011SSriharsha.Basavapatna@Sun.COM 
462912011SSriharsha.Basavapatna@Sun.COM 	/* map the data area */
463012011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_map(dp->data_handle, emsg->data_cookie,
463112011SSriharsha.Basavapatna@Sun.COM 	    emsg->data_ncookies, LDC_DIRECT_MAP, LDC_MEM_R,
463212011SSriharsha.Basavapatna@Sun.COM 	    (caddr_t *)&dp->data_addr, NULL);
463312011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
463412011SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN, "ldc_mem_map failed\n");
463512011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s (%lld) ldc_mem_map() failed: %d\n",
463612011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id, rv);
463712011SSriharsha.Basavapatna@Sun.COM 		return (1);
463812011SSriharsha.Basavapatna@Sun.COM 	}
463912011SSriharsha.Basavapatna@Sun.COM 
4640*13098SWentao.Yang@Sun.COM 	/* get the map info */
4641*13098SWentao.Yang@Sun.COM 	rv = ldc_mem_info(dp->data_handle, &minfo);
4642*13098SWentao.Yang@Sun.COM 	if (rv != 0) {
4643*13098SWentao.Yang@Sun.COM 		cmn_err(CE_WARN, "ldc_mem_info failed\n");
4644*13098SWentao.Yang@Sun.COM 		DWARN(vswp, "%s (%lld) ldc_mem_info() failed: %d\n",
4645*13098SWentao.Yang@Sun.COM 		    __func__, ldcp->ldc_id, rv);
4646*13098SWentao.Yang@Sun.COM 		return (1);
4647*13098SWentao.Yang@Sun.COM 	}
4648*13098SWentao.Yang@Sun.COM 
4649*13098SWentao.Yang@Sun.COM 	if (minfo.mtype != LDC_DIRECT_MAP) {
4650*13098SWentao.Yang@Sun.COM 		DWARN(vswp, "%s (%lld) mtype(%d) is not direct map\n",
4651*13098SWentao.Yang@Sun.COM 		    __func__, ldcp->ldc_id, minfo.mtype);
4652*13098SWentao.Yang@Sun.COM 		return (1);
4653*13098SWentao.Yang@Sun.COM 	}
4654*13098SWentao.Yang@Sun.COM 
465512011SSriharsha.Basavapatna@Sun.COM 	/* allocate memory for data area cookies */
465612011SSriharsha.Basavapatna@Sun.COM 	dp->data_cookie = kmem_zalloc(emsg->data_ncookies *
465712011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t), KM_SLEEP);
465812011SSriharsha.Basavapatna@Sun.COM 
465912011SSriharsha.Basavapatna@Sun.COM 	/* save data area cookies */
466012011SSriharsha.Basavapatna@Sun.COM 	bcopy(emsg->data_cookie, dp->data_cookie,
466112011SSriharsha.Basavapatna@Sun.COM 	    emsg->data_ncookies * sizeof (ldc_mem_cookie_t));
466212011SSriharsha.Basavapatna@Sun.COM 
466312011SSriharsha.Basavapatna@Sun.COM 	return (0);
46645373Sraghuram }
46655373Sraghuram 
46665373Sraghuram /*
466712011SSriharsha.Basavapatna@Sun.COM  * Reset and free all the resources associated with the channel.
46685373Sraghuram  */
46695373Sraghuram static void
vsw_free_lane_resources(vsw_ldc_t * ldcp,uint64_t dir)46705373Sraghuram vsw_free_lane_resources(vsw_ldc_t *ldcp, uint64_t dir)
46715373Sraghuram {
467212011SSriharsha.Basavapatna@Sun.COM 	lane_t	*lp;
46735373Sraghuram 
46745373Sraghuram 	D1(ldcp->ldc_vswp, "%s (%lld): enter", __func__, ldcp->ldc_id);
46755373Sraghuram 
46765373Sraghuram 	if (dir == INBOUND) {
46775373Sraghuram 		D2(ldcp->ldc_vswp, "%s: freeing INBOUND lane"
46785373Sraghuram 		    " of channel %lld", __func__, ldcp->ldc_id);
46795373Sraghuram 		lp = &ldcp->lane_in;
46805373Sraghuram 	} else {
46815373Sraghuram 		D2(ldcp->ldc_vswp, "%s: freeing OUTBOUND lane"
46825373Sraghuram 		    " of channel %lld", __func__, ldcp->ldc_id);
46835373Sraghuram 		lp = &ldcp->lane_out;
46845373Sraghuram 	}
46855373Sraghuram 
46865373Sraghuram 	lp->lstate = VSW_LANE_INACTIV;
46875935Ssb155480 	lp->seq_num = VNET_ISS;
46885373Sraghuram 
468912011SSriharsha.Basavapatna@Sun.COM 	if (dir == INBOUND) {
469012011SSriharsha.Basavapatna@Sun.COM 		/* Unmap the remote dring which is imported from the peer */
469112011SSriharsha.Basavapatna@Sun.COM 		vsw_unmap_dring(ldcp);
469212011SSriharsha.Basavapatna@Sun.COM 	} else {
469312011SSriharsha.Basavapatna@Sun.COM 		/* Destroy the local dring which is exported to the peer */
469412011SSriharsha.Basavapatna@Sun.COM 		vsw_destroy_dring(ldcp);
46955373Sraghuram 	}
46965373Sraghuram 
46975373Sraghuram 	D1(ldcp->ldc_vswp, "%s (%lld): exit", __func__, ldcp->ldc_id);
46985373Sraghuram }
46995373Sraghuram 
47005373Sraghuram /*
470112011SSriharsha.Basavapatna@Sun.COM  * Destroy the descriptor ring.
47025373Sraghuram  */
47035373Sraghuram static void
vsw_destroy_dring(vsw_ldc_t * ldcp)470412011SSriharsha.Basavapatna@Sun.COM vsw_destroy_dring(vsw_ldc_t *ldcp)
47055373Sraghuram {
470612011SSriharsha.Basavapatna@Sun.COM 	lane_t	*lp = &ldcp->lane_out;
470712011SSriharsha.Basavapatna@Sun.COM 
470812011SSriharsha.Basavapatna@Sun.COM 	if (lp->dring_mode == VIO_RX_DRING_DATA) {
470912011SSriharsha.Basavapatna@Sun.COM 		vsw_destroy_rx_dring(ldcp);
471012011SSriharsha.Basavapatna@Sun.COM 	} else {
471112011SSriharsha.Basavapatna@Sun.COM 		vsw_destroy_tx_dring(ldcp);
47125373Sraghuram 	}
47135373Sraghuram }
47145373Sraghuram 
47155373Sraghuram /*
47165373Sraghuram  * vsw_ldc_tx_worker -- A per LDC worker thread to transmit data.
47175373Sraghuram  * This thread is woken up by the vsw_portsend to transmit
47185373Sraghuram  * packets.
47195373Sraghuram  */
47205373Sraghuram static void
vsw_ldc_tx_worker(void * arg)47215373Sraghuram vsw_ldc_tx_worker(void *arg)
47225373Sraghuram {
47235373Sraghuram 	callb_cpr_t	cprinfo;
47245373Sraghuram 	vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
47255373Sraghuram 	vsw_t *vswp = ldcp->ldc_vswp;
47265373Sraghuram 	mblk_t *mp;
47275373Sraghuram 	mblk_t *tmp;
47285373Sraghuram 
47295373Sraghuram 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
47305373Sraghuram 	CALLB_CPR_INIT(&cprinfo, &ldcp->tx_thr_lock, callb_generic_cpr,
47315373Sraghuram 	    "vnet_tx_thread");
47325373Sraghuram 	mutex_enter(&ldcp->tx_thr_lock);
47335373Sraghuram 	while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP)) {
47345373Sraghuram 
47355373Sraghuram 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
47365373Sraghuram 		/*
47375373Sraghuram 		 * Wait until the data is received or a stop
47385373Sraghuram 		 * request is received.
47395373Sraghuram 		 */
47405373Sraghuram 		while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP) &&
47415373Sraghuram 		    (ldcp->tx_mhead == NULL)) {
47425373Sraghuram 			cv_wait(&ldcp->tx_thr_cv, &ldcp->tx_thr_lock);
47435373Sraghuram 		}
47445373Sraghuram 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->tx_thr_lock)
47455373Sraghuram 
47465373Sraghuram 		/*
47475373Sraghuram 		 * First process the stop request.
47485373Sraghuram 		 */
47495373Sraghuram 		if (ldcp->tx_thr_flags & VSW_WTHR_STOP) {
47505373Sraghuram 			D2(vswp, "%s(%lld):tx thread stopped\n",
47515373Sraghuram 			    __func__, ldcp->ldc_id);
47525373Sraghuram 			break;
47535373Sraghuram 		}
47545373Sraghuram 		mp = ldcp->tx_mhead;
47555373Sraghuram 		ldcp->tx_mhead = ldcp->tx_mtail = NULL;
47565935Ssb155480 		ldcp->tx_cnt = 0;
47575373Sraghuram 		mutex_exit(&ldcp->tx_thr_lock);
47585373Sraghuram 		D2(vswp, "%s(%lld):calling vsw_ldcsend\n",
47595373Sraghuram 		    __func__, ldcp->ldc_id);
47605373Sraghuram 		while (mp != NULL) {
47615373Sraghuram 			tmp = mp->b_next;
47625373Sraghuram 			mp->b_next = mp->b_prev = NULL;
47635373Sraghuram 			(void) vsw_ldcsend(ldcp, mp, vsw_ldc_tx_retries);
47645373Sraghuram 			mp = tmp;
47655373Sraghuram 		}
47665373Sraghuram 		mutex_enter(&ldcp->tx_thr_lock);
47675373Sraghuram 	}
47685373Sraghuram 
47695373Sraghuram 	/*
47705373Sraghuram 	 * Update the run status and wakeup the thread that
47715373Sraghuram 	 * has sent the stop request.
47725373Sraghuram 	 */
47739217SWentao.Yang@Sun.COM 	ldcp->tx_thr_flags &= ~VSW_WTHR_STOP;
47749217SWentao.Yang@Sun.COM 	ldcp->tx_thread = NULL;
47755373Sraghuram 	CALLB_CPR_EXIT(&cprinfo);
47765373Sraghuram 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
47775373Sraghuram 	thread_exit();
47785373Sraghuram }
47795373Sraghuram 
47805373Sraghuram /* vsw_stop_tx_thread -- Co-ordinate with receive thread to stop it */
47815373Sraghuram static void
vsw_stop_tx_thread(vsw_ldc_t * ldcp)47825373Sraghuram vsw_stop_tx_thread(vsw_ldc_t *ldcp)
47835373Sraghuram {
47849217SWentao.Yang@Sun.COM 	kt_did_t	tid = 0;
47859217SWentao.Yang@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
47865373Sraghuram 
47875373Sraghuram 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
47885373Sraghuram 	/*
47895373Sraghuram 	 * Send a stop request by setting the stop flag and
47905373Sraghuram 	 * wait until the receive thread stops.
47915373Sraghuram 	 */
47925373Sraghuram 	mutex_enter(&ldcp->tx_thr_lock);
47939217SWentao.Yang@Sun.COM 	if (ldcp->tx_thread != NULL) {
47949217SWentao.Yang@Sun.COM 		tid = ldcp->tx_thread->t_did;
47955373Sraghuram 		ldcp->tx_thr_flags |= VSW_WTHR_STOP;
47965373Sraghuram 		cv_signal(&ldcp->tx_thr_cv);
47975373Sraghuram 	}
47985373Sraghuram 	mutex_exit(&ldcp->tx_thr_lock);
47999217SWentao.Yang@Sun.COM 
48009217SWentao.Yang@Sun.COM 	if (tid != 0) {
48019217SWentao.Yang@Sun.COM 		thread_join(tid);
48029217SWentao.Yang@Sun.COM 	}
48039217SWentao.Yang@Sun.COM 
48045373Sraghuram 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
48055373Sraghuram }
48065373Sraghuram 
4807*13098SWentao.Yang@Sun.COM static int
vsw_mapin_avail(vsw_ldc_t * ldcp)4808*13098SWentao.Yang@Sun.COM vsw_mapin_avail(vsw_ldc_t *ldcp)
4809*13098SWentao.Yang@Sun.COM {
4810*13098SWentao.Yang@Sun.COM 	int		rv;
4811*13098SWentao.Yang@Sun.COM 	ldc_info_t	info;
4812*13098SWentao.Yang@Sun.COM 	uint64_t	mapin_sz_req;
4813*13098SWentao.Yang@Sun.COM 	uint64_t	dblk_sz;
4814*13098SWentao.Yang@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
4815*13098SWentao.Yang@Sun.COM 
4816*13098SWentao.Yang@Sun.COM 	rv = ldc_info(ldcp->ldc_handle, &info);
4817*13098SWentao.Yang@Sun.COM 	if (rv != 0) {
4818*13098SWentao.Yang@Sun.COM 		return (B_FALSE);
4819*13098SWentao.Yang@Sun.COM 	}
4820*13098SWentao.Yang@Sun.COM 
4821*13098SWentao.Yang@Sun.COM 	dblk_sz = RXDRING_DBLK_SZ(vswp->max_frame_size);
4822*13098SWentao.Yang@Sun.COM 	mapin_sz_req = (VSW_RXDRING_NRBUFS * dblk_sz);
4823*13098SWentao.Yang@Sun.COM 
4824*13098SWentao.Yang@Sun.COM 	if (info.direct_map_size_max >= mapin_sz_req) {
4825*13098SWentao.Yang@Sun.COM 		return (B_TRUE);
4826*13098SWentao.Yang@Sun.COM 	}
4827*13098SWentao.Yang@Sun.COM 
4828*13098SWentao.Yang@Sun.COM 	return (B_FALSE);
4829*13098SWentao.Yang@Sun.COM }
4830*13098SWentao.Yang@Sun.COM 
48315373Sraghuram /*
48325373Sraghuram  * Debugging routines
48335373Sraghuram  */
48345373Sraghuram static void
display_state(void)48355373Sraghuram display_state(void)
48365373Sraghuram {
48375373Sraghuram 	vsw_t		*vswp;
48385373Sraghuram 	vsw_port_list_t	*plist;
48395373Sraghuram 	vsw_port_t 	*port;
48405373Sraghuram 	vsw_ldc_t 	*ldcp;
48415373Sraghuram 	extern vsw_t 	*vsw_head;
48425373Sraghuram 
48435373Sraghuram 	cmn_err(CE_NOTE, "***** system state *****");
48445373Sraghuram 
48455373Sraghuram 	for (vswp = vsw_head; vswp; vswp = vswp->next) {
48465373Sraghuram 		plist = &vswp->plist;
48475373Sraghuram 		READ_ENTER(&plist->lockrw);
48485373Sraghuram 		cmn_err(CE_CONT, "vsw instance %d has %d ports attached\n",
48495373Sraghuram 		    vswp->instance, plist->num_ports);
48505373Sraghuram 
48515373Sraghuram 		for (port = plist->head; port != NULL; port = port->p_next) {
48525373Sraghuram 			cmn_err(CE_CONT, "port %d : %d ldcs attached\n",
48536419Ssb155480 			    port->p_instance, port->num_ldcs);
485412011SSriharsha.Basavapatna@Sun.COM 			ldcp = port->ldcp;
485512011SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_CONT, "chan %lu : dev %d : "
485612011SSriharsha.Basavapatna@Sun.COM 			    "status %d : phase %u\n",
485712011SSriharsha.Basavapatna@Sun.COM 			    ldcp->ldc_id, ldcp->dev_class,
485812011SSriharsha.Basavapatna@Sun.COM 			    ldcp->ldc_status, ldcp->hphase);
485912011SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_CONT, "chan %lu : lsession %lu : "
486012011SSriharsha.Basavapatna@Sun.COM 			    "psession %lu\n", ldcp->ldc_id,
486112011SSriharsha.Basavapatna@Sun.COM 			    ldcp->local_session, ldcp->peer_session);
486212011SSriharsha.Basavapatna@Sun.COM 
486312011SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_CONT, "Inbound lane:\n");
486412011SSriharsha.Basavapatna@Sun.COM 			display_lane(&ldcp->lane_in);
486512011SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_CONT, "Outbound lane:\n");
486612011SSriharsha.Basavapatna@Sun.COM 			display_lane(&ldcp->lane_out);
48675373Sraghuram 		}
48685373Sraghuram 		RW_EXIT(&plist->lockrw);
48695373Sraghuram 	}
48705373Sraghuram 	cmn_err(CE_NOTE, "***** system state *****");
48715373Sraghuram }
48725373Sraghuram 
48735373Sraghuram static void
display_lane(lane_t * lp)48745373Sraghuram display_lane(lane_t *lp)
48755373Sraghuram {
487612011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*drp = lp->dringp;
48775373Sraghuram 
48785373Sraghuram 	cmn_err(CE_CONT, "ver 0x%x:0x%x : state %lx : mtu 0x%lx\n",
48795373Sraghuram 	    lp->ver_major, lp->ver_minor, lp->lstate, lp->mtu);
48805373Sraghuram 	cmn_err(CE_CONT, "addr_type %d : addr 0x%lx : xmode %d\n",
48815373Sraghuram 	    lp->addr_type, lp->addr, lp->xfer_mode);
48825373Sraghuram 	cmn_err(CE_CONT, "dringp 0x%lx\n", (uint64_t)lp->dringp);
48835373Sraghuram 
48845373Sraghuram 	cmn_err(CE_CONT, "Dring info:\n");
488512011SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "\tnum_desc %u : dsize %u\n",
488612011SSriharsha.Basavapatna@Sun.COM 	    drp->num_descriptors, drp->descriptor_size);
488712011SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "\thandle 0x%lx\n", drp->dring_handle);
488812011SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "\tpub_addr 0x%lx : priv_addr 0x%lx\n",
488912011SSriharsha.Basavapatna@Sun.COM 	    (uint64_t)drp->pub_addr, (uint64_t)drp->priv_addr);
489012011SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "\tident 0x%lx : end_idx %lu\n",
489112011SSriharsha.Basavapatna@Sun.COM 	    drp->ident, drp->end_idx);
489212011SSriharsha.Basavapatna@Sun.COM 	display_ring(drp);
48935373Sraghuram }
48945373Sraghuram 
48955373Sraghuram static void
display_ring(dring_info_t * dringp)48965373Sraghuram display_ring(dring_info_t *dringp)
48975373Sraghuram {
48985373Sraghuram 	uint64_t		i;
48995373Sraghuram 	uint64_t		priv_count = 0;
49005373Sraghuram 	uint64_t		pub_count = 0;
49015373Sraghuram 	vnet_public_desc_t	*pub_addr = NULL;
49025373Sraghuram 	vsw_private_desc_t	*priv_addr = NULL;
49035373Sraghuram 
490412011SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < vsw_num_descriptors; i++) {
49055373Sraghuram 		if (dringp->pub_addr != NULL) {
49065373Sraghuram 			pub_addr = (vnet_public_desc_t *)dringp->pub_addr + i;
49075373Sraghuram 
49085373Sraghuram 			if (pub_addr->hdr.dstate == VIO_DESC_FREE)
49095373Sraghuram 				pub_count++;
49105373Sraghuram 		}
49115373Sraghuram 
49125373Sraghuram 		if (dringp->priv_addr != NULL) {
49135373Sraghuram 			priv_addr = (vsw_private_desc_t *)dringp->priv_addr + i;
49145373Sraghuram 
49155373Sraghuram 			if (priv_addr->dstate == VIO_DESC_FREE)
49165373Sraghuram 				priv_count++;
49175373Sraghuram 		}
49185373Sraghuram 	}
49195373Sraghuram 	cmn_err(CE_CONT, "\t%lu elements: %lu priv free: %lu pub free\n",
49205373Sraghuram 	    i, priv_count, pub_count);
49215373Sraghuram }
49225373Sraghuram 
49235373Sraghuram static void
dump_flags(uint64_t state)49245373Sraghuram dump_flags(uint64_t state)
49255373Sraghuram {
49265373Sraghuram 	int	i;
49275373Sraghuram 
49285373Sraghuram 	typedef struct flag_name {
49295373Sraghuram 		int	flag_val;
49305373Sraghuram 		char	*flag_name;
49315373Sraghuram 	} flag_name_t;
49325373Sraghuram 
49335373Sraghuram 	flag_name_t	flags[] = {
49345373Sraghuram 		VSW_VER_INFO_SENT, "VSW_VER_INFO_SENT",
49355373Sraghuram 		VSW_VER_INFO_RECV, "VSW_VER_INFO_RECV",
49365373Sraghuram 		VSW_VER_ACK_RECV, "VSW_VER_ACK_RECV",
49375373Sraghuram 		VSW_VER_ACK_SENT, "VSW_VER_ACK_SENT",
49385373Sraghuram 		VSW_VER_NACK_RECV, "VSW_VER_NACK_RECV",
49395373Sraghuram 		VSW_VER_NACK_SENT, "VSW_VER_NACK_SENT",
49405373Sraghuram 		VSW_ATTR_INFO_SENT, "VSW_ATTR_INFO_SENT",
49415373Sraghuram 		VSW_ATTR_INFO_RECV, "VSW_ATTR_INFO_RECV",
49425373Sraghuram 		VSW_ATTR_ACK_SENT, "VSW_ATTR_ACK_SENT",
49435373Sraghuram 		VSW_ATTR_ACK_RECV, "VSW_ATTR_ACK_RECV",
49445373Sraghuram 		VSW_ATTR_NACK_SENT, "VSW_ATTR_NACK_SENT",
49455373Sraghuram 		VSW_ATTR_NACK_RECV, "VSW_ATTR_NACK_RECV",
49465373Sraghuram 		VSW_DRING_INFO_SENT, "VSW_DRING_INFO_SENT",
49475373Sraghuram 		VSW_DRING_INFO_RECV, "VSW_DRING_INFO_RECV",
49485373Sraghuram 		VSW_DRING_ACK_SENT, "VSW_DRING_ACK_SENT",
49495373Sraghuram 		VSW_DRING_ACK_RECV, "VSW_DRING_ACK_RECV",
49505373Sraghuram 		VSW_DRING_NACK_SENT, "VSW_DRING_NACK_SENT",
49515373Sraghuram 		VSW_DRING_NACK_RECV, "VSW_DRING_NACK_RECV",
49525373Sraghuram 		VSW_RDX_INFO_SENT, "VSW_RDX_INFO_SENT",
49535373Sraghuram 		VSW_RDX_INFO_RECV, "VSW_RDX_INFO_RECV",
49545373Sraghuram 		VSW_RDX_ACK_SENT, "VSW_RDX_ACK_SENT",
49555373Sraghuram 		VSW_RDX_ACK_RECV, "VSW_RDX_ACK_RECV",
49565373Sraghuram 		VSW_RDX_NACK_SENT, "VSW_RDX_NACK_SENT",
49575373Sraghuram 		VSW_RDX_NACK_RECV, "VSW_RDX_NACK_RECV",
49585373Sraghuram 		VSW_MCST_INFO_SENT, "VSW_MCST_INFO_SENT",
49595373Sraghuram 		VSW_MCST_INFO_RECV, "VSW_MCST_INFO_RECV",
49605373Sraghuram 		VSW_MCST_ACK_SENT, "VSW_MCST_ACK_SENT",
49615373Sraghuram 		VSW_MCST_ACK_RECV, "VSW_MCST_ACK_RECV",
49625373Sraghuram 		VSW_MCST_NACK_SENT, "VSW_MCST_NACK_SENT",
49635373Sraghuram 		VSW_MCST_NACK_RECV, "VSW_MCST_NACK_RECV",
49645373Sraghuram 		VSW_LANE_ACTIVE, "VSW_LANE_ACTIVE"};
49655373Sraghuram 
49665373Sraghuram 	DERR(NULL, "DUMP_FLAGS: %llx\n", state);
49675373Sraghuram 	for (i = 0; i < sizeof (flags)/sizeof (flag_name_t); i++) {
49685373Sraghuram 		if (state & flags[i].flag_val)
49695373Sraghuram 			DERR(NULL, "DUMP_FLAGS %s", flags[i].flag_name);
49705373Sraghuram 	}
49715373Sraghuram }
4972