xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_gen.c (revision 5171:a74ecb2f684c)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
233653Snarayan  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo #include <sys/types.h>
301991Sheppo #include <sys/errno.h>
311991Sheppo #include <sys/param.h>
321991Sheppo #include <sys/stream.h>
334647Sraghuram #include <sys/strsubr.h>
341991Sheppo #include <sys/kmem.h>
351991Sheppo #include <sys/conf.h>
361991Sheppo #include <sys/devops.h>
371991Sheppo #include <sys/ksynch.h>
381991Sheppo #include <sys/stat.h>
391991Sheppo #include <sys/modctl.h>
401991Sheppo #include <sys/debug.h>
411991Sheppo #include <sys/ethernet.h>
421991Sheppo #include <sys/ddi.h>
431991Sheppo #include <sys/sunddi.h>
441991Sheppo #include <sys/strsun.h>
451991Sheppo #include <sys/note.h>
461991Sheppo #include <sys/mac.h>
472311Sseb #include <sys/mac_ether.h>
481991Sheppo #include <sys/ldc.h>
491991Sheppo #include <sys/mach_descrip.h>
501991Sheppo #include <sys/mdeg.h>
514647Sraghuram #include <net/if.h>
524647Sraghuram #include <sys/vnet.h>
531991Sheppo #include <sys/vio_mailbox.h>
541991Sheppo #include <sys/vio_common.h>
551991Sheppo #include <sys/vnet_common.h>
562336Snarayan #include <sys/vnet_mailbox.h>
572336Snarayan #include <sys/vio_util.h>
581991Sheppo #include <sys/vnet_gen.h>
594647Sraghuram #include <sys/callb.h>
604647Sraghuram #include <sys/sdt.h>
614647Sraghuram #include <sys/intr.h>
624647Sraghuram #include <sys/pattr.h>
631991Sheppo 
641991Sheppo /*
651991Sheppo  * Implementation of the mac functionality for vnet using the
661991Sheppo  * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
671991Sheppo  */
681991Sheppo 
691991Sheppo /*
701991Sheppo  * Function prototypes.
711991Sheppo  */
721991Sheppo /* vgen proxy entry points */
732311Sseb int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
742311Sseb 	mac_register_t **vgenmacp);
752336Snarayan int vgen_uninit(void *arg);
761991Sheppo static int vgen_start(void *arg);
771991Sheppo static void vgen_stop(void *arg);
781991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
791991Sheppo static int vgen_multicst(void *arg, boolean_t add,
801991Sheppo 	const uint8_t *mca);
811991Sheppo static int vgen_promisc(void *arg, boolean_t on);
821991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
832311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
841991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp);
851991Sheppo 
861991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */
871991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
881991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
892793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx,
902793Slm66018 	void *txarg, boolean_t upgrade);
911991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
921991Sheppo void vnet_del_def_rte(void *arg);
932311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
942311Sseb void vnet_tx_update(void *arg);
951991Sheppo 
961991Sheppo /* vgen internal functions */
971991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
981991Sheppo static void vgen_port_detach(vgen_port_t *portp);
991991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
1001991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
1011991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1021991Sheppo 	int port_num);
1031991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
1041991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
1051991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1061991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1071991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1081991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1091991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port);
1101991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp);
1111991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1121991Sheppo 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
1132311Sseb static uint64_t	vgen_port_stat(vgen_port_t *portp, uint_t stat);
1141991Sheppo 
1151991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1161991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1171991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp);
1181991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp);
1191991Sheppo static void vgen_init_ports(vgen_t *vgenp);
1201991Sheppo static void vgen_port_init(vgen_port_t *portp);
1211991Sheppo static void vgen_uninit_ports(vgen_t *vgenp);
1221991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1231991Sheppo static void vgen_init_ldcs(vgen_port_t *portp);
1241991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp);
1251991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1261991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
1271991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp);
1281991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp);
1291991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp);
1301991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp);
1312311Sseb static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
1321991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
1331991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1341991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp);
1351991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp);
1361991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp);
1371991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp);
1381991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp);
1391991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp);
1401991Sheppo static void vgen_ldc_watchdog(void *arg);
1411991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp);
1421991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp);
1431991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw);
1441991Sheppo 
1451991Sheppo /* vgen handshake functions */
1461991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
1471991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
1481991Sheppo 	uint16_t ver_minor);
1491991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp);
1501991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
1511991Sheppo 	boolean_t caller_holds_lock);
1521991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1531991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
1541991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp);
1551991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
1562336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1571991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1581991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
1591991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp);
1601991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp);
1611991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp);
1621991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp);
1631991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp);
1642793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1651991Sheppo 	vio_msg_tag_t *tagp);
1662793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1672793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1682793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1692793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1702793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1714647Sraghuram static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1724647Sraghuram static int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1734647Sraghuram static int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1744647Sraghuram static int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1754647Sraghuram static int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1762793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1772336Snarayan 	uint32_t start, int32_t end, uint8_t pstate);
1784647Sraghuram static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1791991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1802793Slm66018 static void vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag);
1812793Slm66018 static void vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag);
1821991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1831991Sheppo static uint64_t	vgen_macaddr_strtoul(const uint8_t *macaddr);
1841991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr);
1851991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
1861991Sheppo static void vgen_hwatchdog(void *arg);
1871991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
1881991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp);
1891991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp);
1904647Sraghuram static uint_t vgen_ldc_rcv_softintr(caddr_t arg1, caddr_t arg2);
1914647Sraghuram static void vgen_stop_rcv_thread(vgen_ldc_t *ldcp);
1924647Sraghuram static void vgen_ldc_rcv_worker(void *arg);
1934647Sraghuram static void vgen_handle_evt_read(vgen_ldc_t *ldcp);
1944647Sraghuram static void vgen_ldc_queue_data(vgen_ldc_t *ldcp,
1954647Sraghuram 	mblk_t *rhead, mblk_t *rtail);
1961991Sheppo 
1971991Sheppo /*
1981991Sheppo  * The handshake process consists of 5 phases defined below, with VH_PHASE0
1991991Sheppo  * being the pre-handshake phase and VH_DONE is the phase to indicate
2001991Sheppo  * successful completion of all phases.
2011991Sheppo  * Each phase may have one to several handshake states which are required
2021991Sheppo  * to complete successfully to move to the next phase.
2031991Sheppo  * Refer to the functions vgen_handshake() and vgen_handshake_done() for
2041991Sheppo  * more details.
2051991Sheppo  */
2061991Sheppo /* handshake phases */
2071991Sheppo enum {	VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
2081991Sheppo 
2091991Sheppo /* handshake states */
2101991Sheppo enum {
2111991Sheppo 
2121991Sheppo 	VER_INFO_SENT	=	0x1,
2131991Sheppo 	VER_ACK_RCVD	=	0x2,
2141991Sheppo 	VER_INFO_RCVD	=	0x4,
2151991Sheppo 	VER_ACK_SENT	=	0x8,
2161991Sheppo 	VER_NEGOTIATED	=	(VER_ACK_RCVD | VER_ACK_SENT),
2171991Sheppo 
2181991Sheppo 	ATTR_INFO_SENT	=	0x10,
2191991Sheppo 	ATTR_ACK_RCVD	=	0x20,
2201991Sheppo 	ATTR_INFO_RCVD	=	0x40,
2211991Sheppo 	ATTR_ACK_SENT	=	0x80,
2221991Sheppo 	ATTR_INFO_EXCHANGED	=	(ATTR_ACK_RCVD | ATTR_ACK_SENT),
2231991Sheppo 
2241991Sheppo 	DRING_INFO_SENT	=	0x100,
2251991Sheppo 	DRING_ACK_RCVD	=	0x200,
2261991Sheppo 	DRING_INFO_RCVD	=	0x400,
2271991Sheppo 	DRING_ACK_SENT	=	0x800,
2281991Sheppo 	DRING_INFO_EXCHANGED	=	(DRING_ACK_RCVD | DRING_ACK_SENT),
2291991Sheppo 
2301991Sheppo 	RDX_INFO_SENT	=	0x1000,
2311991Sheppo 	RDX_ACK_RCVD	=	0x2000,
2321991Sheppo 	RDX_INFO_RCVD	=	0x4000,
2331991Sheppo 	RDX_ACK_SENT	=	0x8000,
2341991Sheppo 	RDX_EXCHANGED	=	(RDX_ACK_RCVD | RDX_ACK_SENT)
2351991Sheppo 
2361991Sheppo };
2371991Sheppo 
2381991Sheppo #define	LDC_LOCK(ldcp)	\
2391991Sheppo 				mutex_enter(&((ldcp)->cblock));\
2404647Sraghuram 				mutex_enter(&((ldcp)->rxlock));\
2414647Sraghuram 				mutex_enter(&((ldcp)->wrlock));\
2421991Sheppo 				mutex_enter(&((ldcp)->txlock));\
2431991Sheppo 				mutex_enter(&((ldcp)->tclock));
2441991Sheppo #define	LDC_UNLOCK(ldcp)	\
2451991Sheppo 				mutex_exit(&((ldcp)->tclock));\
2461991Sheppo 				mutex_exit(&((ldcp)->txlock));\
2474647Sraghuram 				mutex_exit(&((ldcp)->wrlock));\
2484647Sraghuram 				mutex_exit(&((ldcp)->rxlock));\
2491991Sheppo 				mutex_exit(&((ldcp)->cblock));
2501991Sheppo 
2511991Sheppo static struct ether_addr etherbroadcastaddr = {
2521991Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2531991Sheppo };
2541991Sheppo /*
2551991Sheppo  * MIB II broadcast/multicast packets
2561991Sheppo  */
2571991Sheppo #define	IS_BROADCAST(ehp) \
2581991Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
2591991Sheppo #define	IS_MULTICAST(ehp) \
2601991Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
2611991Sheppo 
2621991Sheppo /*
2631991Sheppo  * Property names
2641991Sheppo  */
2651991Sheppo static char macaddr_propname[] = "mac-address";
2661991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2671991Sheppo static char channel_propname[] = "channel-endpoint";
2681991Sheppo static char reg_propname[] = "reg";
2691991Sheppo static char port_propname[] = "port";
2701991Sheppo static char swport_propname[] = "switch-port";
2711991Sheppo static char id_propname[] = "id";
2721991Sheppo 
2731991Sheppo /* versions supported - in decreasing order */
2741991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} };
2751991Sheppo 
2761991Sheppo /* Tunables */
277*5171Ssb155480 uint32_t vgen_hwd_interval = 5;		/* handshake watchdog freq in sec */
2783297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */
2791991Sheppo uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
2802109Slm66018 uint32_t vgen_ldcup_retries = 5;	/* max # of ldc_up() retries */
2812336Snarayan uint32_t vgen_recv_delay = 1;		/* delay when rx descr not ready */
2822336Snarayan uint32_t vgen_recv_retries = 10;	/* retry when rx descr not ready */
2835022Sraghuram uint32_t vgen_tx_retries = 0x4;		/* retry when tx descr not available */
2845022Sraghuram uint32_t vgen_tx_delay = 0x30;		/* delay when tx descr not available */
2851991Sheppo 
2864647Sraghuram int vgen_rcv_thread_enabled = 1;	/* Enable Recieve thread */
2874647Sraghuram 
2884647Sraghuram /*
2894647Sraghuram  * max # of packets accumulated prior to sending them up. It is best
2904647Sraghuram  * to keep this at 60% of the number of recieve buffers.
2914647Sraghuram  */
2924647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6);
2934647Sraghuram 
2944647Sraghuram /*
2954647Sraghuram  * Tunables for each receive buffer size and number of buffers for
2964647Sraghuram  * each buffer size.
2974647Sraghuram  */
2984647Sraghuram uint32_t vgen_rbufsz1 = VGEN_DBLK_SZ_128;
2994647Sraghuram uint32_t vgen_rbufsz2 = VGEN_DBLK_SZ_256;
3004647Sraghuram uint32_t vgen_rbufsz3 = VGEN_DBLK_SZ_2048;
3014647Sraghuram 
3024647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS;
3034647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS;
3044647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS;
3054647Sraghuram 
3061991Sheppo #ifdef DEBUG
3071991Sheppo /* flags to simulate error conditions for debugging */
3081991Sheppo int vgen_trigger_txtimeout = 0;
3091991Sheppo int vgen_trigger_rxlost = 0;
3101991Sheppo #endif
3111991Sheppo 
3121991Sheppo /* MD update matching structure */
3131991Sheppo static md_prop_match_t	vport_prop_match[] = {
3141991Sheppo 	{ MDET_PROP_VAL,	"id" },
3151991Sheppo 	{ MDET_LIST_END,	NULL }
3161991Sheppo };
3171991Sheppo 
3181991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
3191991Sheppo 					vport_prop_match };
3201991Sheppo 
3211991Sheppo /* template for matching a particular vnet instance */
3221991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
3231991Sheppo 	{ MDET_PROP_STR,	"name",		"network" },
3241991Sheppo 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
3251991Sheppo 	{ MDET_LIST_END,	NULL,		NULL }
3261991Sheppo };
3271991Sheppo 
3281991Sheppo #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
3291991Sheppo 
3301991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
3311991Sheppo 
3322311Sseb static mac_callbacks_t vgen_m_callbacks = {
3332311Sseb 	0,
3342311Sseb 	vgen_stat,
3352311Sseb 	vgen_start,
3362311Sseb 	vgen_stop,
3372311Sseb 	vgen_promisc,
3382311Sseb 	vgen_multicst,
3392311Sseb 	vgen_unicst,
3402311Sseb 	vgen_tx,
3412311Sseb 	NULL,
3422311Sseb 	NULL,
3432311Sseb 	NULL
3442311Sseb };
3452311Sseb 
3461991Sheppo /* externs */
3474647Sraghuram extern pri_t	maxclsyspri;
3484647Sraghuram extern proc_t	p0;
3491991Sheppo extern uint32_t vnet_ntxds;
3501991Sheppo extern uint32_t vnet_ldcwd_interval;
3511991Sheppo extern uint32_t vnet_ldcwd_txtimeout;
3522410Slm66018 extern uint32_t vnet_ldc_mtu;
3532336Snarayan extern uint32_t vnet_nrbufs;
3544647Sraghuram 
3551991Sheppo 
3561991Sheppo #ifdef DEBUG
3571991Sheppo 
3584647Sraghuram extern int vnet_dbglevel;
3594647Sraghuram static void debug_printf(const char *fname, vgen_t *vgenp,
3604647Sraghuram 	vgen_ldc_t *ldcp, const char *fmt, ...);
3614647Sraghuram 
3624647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */
3634647Sraghuram int vgendbg_ldcid = -1;
3641991Sheppo 
3651991Sheppo /* simulate handshake error conditions for debug */
3661991Sheppo uint32_t vgen_hdbg;
3671991Sheppo #define	HDBG_VERSION	0x1
3681991Sheppo #define	HDBG_TIMEOUT	0x2
3691991Sheppo #define	HDBG_BAD_SID	0x4
3701991Sheppo #define	HDBG_OUT_STATE	0x8
3711991Sheppo 
3721991Sheppo #endif
3731991Sheppo 
3742336Snarayan 
3751991Sheppo 
3761991Sheppo /*
3771991Sheppo  * vgen_init() is called by an instance of vnet driver to initialize the
3781991Sheppo  * corresponding generic proxy transport layer. The arguments passed by vnet
3791991Sheppo  * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
3802311Sseb  * the mac address of the vnet device, and a pointer to mac_register_t of
3812311Sseb  * the generic transport is returned in the last argument.
3821991Sheppo  */
3831991Sheppo int
3842311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
3852311Sseb     mac_register_t **vgenmacp)
3861991Sheppo {
3871991Sheppo 	vgen_t *vgenp;
3882311Sseb 	mac_register_t *macp;
3891991Sheppo 	int instance;
3901991Sheppo 
3912311Sseb 	if ((vnetp == NULL) || (vnetdip == NULL))
3921991Sheppo 		return (DDI_FAILURE);
3931991Sheppo 
3941991Sheppo 	instance = ddi_get_instance(vnetdip);
3951991Sheppo 
3964647Sraghuram 	DBG1(NULL, NULL, "vnet(%d):%s: enter\n", instance);
3971991Sheppo 
3981991Sheppo 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
3991991Sheppo 
4001991Sheppo 	vgenp->vnetp = vnetp;
4011991Sheppo 	vgenp->vnetdip = vnetdip;
4021991Sheppo 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
4031991Sheppo 
4042311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4052311Sseb 		KMEM_FREE(vgenp);
4062311Sseb 		return (DDI_FAILURE);
4072311Sseb 	}
4082311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4092311Sseb 	macp->m_driver = vgenp;
4102311Sseb 	macp->m_dip = vnetdip;
4112311Sseb 	macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
4122311Sseb 	macp->m_callbacks = &vgen_m_callbacks;
4132311Sseb 	macp->m_min_sdu = 0;
4142311Sseb 	macp->m_max_sdu = ETHERMTU;
4152311Sseb 	vgenp->macp = macp;
4162311Sseb 
4171991Sheppo 	/* allocate multicast table */
4181991Sheppo 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
4191991Sheppo 	    sizeof (struct ether_addr), KM_SLEEP);
4201991Sheppo 	vgenp->mccount = 0;
4211991Sheppo 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
4221991Sheppo 
4231991Sheppo 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
4241991Sheppo 
4251991Sheppo 	/* register with MD event generator */
4261991Sheppo 	if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) {
4271991Sheppo 		mutex_destroy(&vgenp->lock);
4281991Sheppo 		kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
4291991Sheppo 		    sizeof (struct ether_addr));
4302311Sseb 		mac_free(vgenp->macp);
4311991Sheppo 		KMEM_FREE(vgenp);
4321991Sheppo 		return (DDI_FAILURE);
4331991Sheppo 	}
4341991Sheppo 
4352311Sseb 	/* register macp of this vgen_t with vnet */
4362311Sseb 	*vgenmacp = vgenp->macp;
4371991Sheppo 
4384647Sraghuram 	DBG1(NULL, NULL, "vnet(%d):%s: exit\n", instance);
4391991Sheppo 	return (DDI_SUCCESS);
4401991Sheppo }
4411991Sheppo 
4421991Sheppo /*
4431991Sheppo  * Called by vnet to undo the initializations done by vgen_init().
4441991Sheppo  * The handle provided by generic transport during vgen_init() is the argument.
4451991Sheppo  */
4462336Snarayan int
4471991Sheppo vgen_uninit(void *arg)
4481991Sheppo {
4491991Sheppo 	vgen_t	*vgenp = (vgen_t *)arg;
4502336Snarayan 	vio_mblk_pool_t *rp, *nrp;
4512336Snarayan 
4522336Snarayan 	if (vgenp == NULL) {
4532336Snarayan 		return (DDI_FAILURE);
4542336Snarayan 	}
4551991Sheppo 
4564647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
4571991Sheppo 
4581991Sheppo 	/* unregister with MD event generator */
4591991Sheppo 	vgen_mdeg_unreg(vgenp);
4601991Sheppo 
4611991Sheppo 	mutex_enter(&vgenp->lock);
4621991Sheppo 
4631991Sheppo 	/* detach all ports from the device */
4641991Sheppo 	vgen_detach_ports(vgenp);
4651991Sheppo 
4662336Snarayan 	/*
4672336Snarayan 	 * free any pending rx mblk pools,
4682336Snarayan 	 * that couldn't be freed previously during channel detach.
4692336Snarayan 	 */
4702336Snarayan 	rp = vgenp->rmp;
4712336Snarayan 	while (rp != NULL) {
4722336Snarayan 		nrp = vgenp->rmp = rp->nextp;
4732336Snarayan 		if (vio_destroy_mblks(rp)) {
4742336Snarayan 			vgenp->rmp = rp;
4752336Snarayan 			mutex_exit(&vgenp->lock);
4762336Snarayan 			return (DDI_FAILURE);
4772336Snarayan 		}
4782336Snarayan 		rp = nrp;
4792336Snarayan 	}
4802336Snarayan 
4811991Sheppo 	/* free multicast table */
4821991Sheppo 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
4831991Sheppo 
4842311Sseb 	mac_free(vgenp->macp);
4852311Sseb 
4861991Sheppo 	mutex_exit(&vgenp->lock);
4871991Sheppo 
4881991Sheppo 	mutex_destroy(&vgenp->lock);
4891991Sheppo 
4901991Sheppo 	KMEM_FREE(vgenp);
4911991Sheppo 
4924647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
4932336Snarayan 
4942336Snarayan 	return (DDI_SUCCESS);
4951991Sheppo }
4961991Sheppo 
4971991Sheppo /* enable transmit/receive for the device */
4982311Sseb int
4991991Sheppo vgen_start(void *arg)
5001991Sheppo {
5011991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5021991Sheppo 
5034647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
5041991Sheppo 
5051991Sheppo 	mutex_enter(&vgenp->lock);
5061991Sheppo 	vgen_init_ports(vgenp);
5071991Sheppo 	vgenp->flags |= VGEN_STARTED;
5081991Sheppo 	mutex_exit(&vgenp->lock);
5091991Sheppo 
5104647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
5111991Sheppo 	return (DDI_SUCCESS);
5121991Sheppo }
5131991Sheppo 
5141991Sheppo /* stop transmit/receive */
5152311Sseb void
5161991Sheppo vgen_stop(void *arg)
5171991Sheppo {
5181991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5191991Sheppo 
5204647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
5211991Sheppo 
5221991Sheppo 	mutex_enter(&vgenp->lock);
5231991Sheppo 	vgen_uninit_ports(vgenp);
5241991Sheppo 	vgenp->flags &= ~(VGEN_STARTED);
5251991Sheppo 	mutex_exit(&vgenp->lock);
5261991Sheppo 
5274647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
5281991Sheppo }
5291991Sheppo 
5301991Sheppo /* vgen transmit function */
5311991Sheppo static mblk_t *
5321991Sheppo vgen_tx(void *arg, mblk_t *mp)
5331991Sheppo {
5345022Sraghuram 	int i;
5351991Sheppo 	vgen_port_t *portp;
5365022Sraghuram 	int status = VGEN_FAILURE;
5371991Sheppo 
5381991Sheppo 	portp = (vgen_port_t *)arg;
5395022Sraghuram 	/*
5405022Sraghuram 	 * Retry so that we avoid reporting a failure
5415022Sraghuram 	 * to the upper layer. Returning a failure may cause the
5425022Sraghuram 	 * upper layer to go into single threaded mode there by
5435022Sraghuram 	 * causing performance degradation, especially for a large
5445022Sraghuram 	 * number of connections.
5455022Sraghuram 	 */
5465022Sraghuram 	for (i = 0; i < vgen_tx_retries; ) {
5475022Sraghuram 		status = vgen_portsend(portp, mp);
5485022Sraghuram 		if (status == VGEN_SUCCESS) {
5495022Sraghuram 			break;
5505022Sraghuram 		}
5515022Sraghuram 		if (++i < vgen_tx_retries)
5525022Sraghuram 			delay(drv_usectohz(vgen_tx_delay));
5535022Sraghuram 	}
5541991Sheppo 	if (status != VGEN_SUCCESS) {
5551991Sheppo 		/* failure */
5561991Sheppo 		return (mp);
5571991Sheppo 	}
5581991Sheppo 	/* success */
5591991Sheppo 	return (NULL);
5601991Sheppo }
5611991Sheppo 
5621991Sheppo /* transmit packets over the given port */
5631991Sheppo static int
5641991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
5651991Sheppo {
5661991Sheppo 	vgen_ldclist_t	*ldclp;
5671991Sheppo 	vgen_ldc_t *ldcp;
5681991Sheppo 	int status;
5695022Sraghuram 	int rv = VGEN_SUCCESS;
5701991Sheppo 
5711991Sheppo 	ldclp = &portp->ldclist;
5721991Sheppo 	READ_ENTER(&ldclp->rwlock);
5731991Sheppo 	/*
5742336Snarayan 	 * NOTE: for now, we will assume we have a single channel.
5751991Sheppo 	 */
5761991Sheppo 	if (ldclp->headp == NULL) {
5771991Sheppo 		RW_EXIT(&ldclp->rwlock);
5781991Sheppo 		return (VGEN_FAILURE);
5791991Sheppo 	}
5801991Sheppo 	ldcp = ldclp->headp;
5811991Sheppo 
5821991Sheppo 	status  = vgen_ldcsend(ldcp, mp);
5835022Sraghuram 
5841991Sheppo 	RW_EXIT(&ldclp->rwlock);
5851991Sheppo 
5865022Sraghuram 	if (status != VGEN_TX_SUCCESS) {
5875022Sraghuram 		rv = VGEN_FAILURE;
5885022Sraghuram 	}
5895022Sraghuram 	return (rv);
5901991Sheppo }
5911991Sheppo 
5921991Sheppo /* channel transmit function */
5931991Sheppo static int
5941991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp)
5951991Sheppo {
5961991Sheppo 	vgen_private_desc_t	*tbufp;
5974647Sraghuram 	vgen_private_desc_t	*rtbufp;
5984647Sraghuram 	vnet_public_desc_t	*rtxdp;
5991991Sheppo 	vgen_private_desc_t	*ntbufp;
6001991Sheppo 	vnet_public_desc_t	*txdp;
6014647Sraghuram 	vio_dring_entry_hdr_t	*hdrp;
6021991Sheppo 	vgen_stats_t		*statsp;
6031991Sheppo 	struct ether_header	*ehp;
6041991Sheppo 	boolean_t	is_bcast = B_FALSE;
6051991Sheppo 	boolean_t	is_mcast = B_FALSE;
6062336Snarayan 	size_t		mblksz;
6072336Snarayan 	caddr_t		dst;
6082336Snarayan 	mblk_t		*bp;
6094647Sraghuram 	size_t		size;
6104647Sraghuram 	int		rv = 0;
6112793Slm66018 	ldc_status_t	istatus;
6124647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6134647Sraghuram 
6141991Sheppo 	statsp = ldcp->statsp;
6152109Slm66018 	size = msgsize(mp);
6162109Slm66018 
6174647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
6184647Sraghuram 
6192109Slm66018 	if (ldcp->ldc_status != LDC_UP) {
6204647Sraghuram 		DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
6214647Sraghuram 		    ldcp->ldc_status);
6222109Slm66018 		/* retry ldc_up() if needed */
6232109Slm66018 		if (ldcp->flags & CHANNEL_STARTED)
6242109Slm66018 			(void) ldc_up(ldcp->ldc_handle);
6252109Slm66018 		goto vgen_tx_exit;
6261991Sheppo 	}
6271991Sheppo 
6284647Sraghuram 	/* drop the packet if ldc is not up or handshake is not done */
6292109Slm66018 	if (ldcp->hphase != VH_DONE) {
6304647Sraghuram 		DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
6314647Sraghuram 		    ldcp->hphase);
6322109Slm66018 		goto vgen_tx_exit;
6332109Slm66018 	}
6342109Slm66018 
6351991Sheppo 	if (size > (size_t)ETHERMAX) {
6364647Sraghuram 		DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
6371991Sheppo 		goto vgen_tx_exit;
6381991Sheppo 	}
6394647Sraghuram 	if (size < ETHERMIN)
6404647Sraghuram 		size = ETHERMIN;
6414647Sraghuram 
6424647Sraghuram 	ehp = (struct ether_header *)mp->b_rptr;
6434647Sraghuram 	is_bcast = IS_BROADCAST(ehp);
6444647Sraghuram 	is_mcast = IS_MULTICAST(ehp);
6454647Sraghuram 
6464647Sraghuram 	mutex_enter(&ldcp->txlock);
6471991Sheppo 	/*
6481991Sheppo 	 * allocate a descriptor
6491991Sheppo 	 */
6501991Sheppo 	tbufp = ldcp->next_tbufp;
6511991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
6522336Snarayan 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
6531991Sheppo 
6541991Sheppo 		mutex_enter(&ldcp->tclock);
6554647Sraghuram 		/* Try reclaiming now */
6564647Sraghuram 		vgen_reclaim_dring(ldcp);
6574647Sraghuram 		ldcp->reclaim_lbolt = ddi_get_lbolt();
6584647Sraghuram 
6592336Snarayan 		if (ntbufp == ldcp->cur_tbufp) {
6604647Sraghuram 			/* Now we are really out of tbuf/txds */
6611991Sheppo 			ldcp->need_resched = B_TRUE;
6622336Snarayan 			mutex_exit(&ldcp->tclock);
6632336Snarayan 
6642336Snarayan 			statsp->tx_no_desc++;
6652336Snarayan 			mutex_exit(&ldcp->txlock);
6662336Snarayan 
6672336Snarayan 			return (VGEN_TX_NORESOURCES);
6682336Snarayan 		}
6691991Sheppo 		mutex_exit(&ldcp->tclock);
6701991Sheppo 	}
6714647Sraghuram 	/* update next available tbuf in the ring and update tx index */
6724647Sraghuram 	ldcp->next_tbufp = ntbufp;
6734647Sraghuram 	INCR_TXI(ldcp->next_txi, ldcp);
6744647Sraghuram 
6754647Sraghuram 	/* Mark the buffer busy before releasing the lock */
6764647Sraghuram 	tbufp->flags = VGEN_PRIV_DESC_BUSY;
6774647Sraghuram 	mutex_exit(&ldcp->txlock);
6782109Slm66018 
6792109Slm66018 	/* copy data into pre-allocated transmit buffer */
6802336Snarayan 	dst = tbufp->datap + VNET_IPALIGN;
6812336Snarayan 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
6822336Snarayan 		mblksz = MBLKL(bp);
6832336Snarayan 		bcopy(bp->b_rptr, dst, mblksz);
6842336Snarayan 		dst += mblksz;
6851991Sheppo 	}
6861991Sheppo 
6872109Slm66018 	tbufp->datalen = size;
6881991Sheppo 
6891991Sheppo 	/* initialize the corresponding public descriptor (txd) */
6901991Sheppo 	txdp = tbufp->descp;
6911991Sheppo 	hdrp = &txdp->hdr;
6922109Slm66018 	txdp->nbytes = size;
6932109Slm66018 	txdp->ncookies = tbufp->ncookies;
6941991Sheppo 	bcopy((tbufp->memcookie), (txdp->memcookie),
6954650Sraghuram 	    tbufp->ncookies * sizeof (ldc_mem_cookie_t));
6964647Sraghuram 
6974647Sraghuram 	mutex_enter(&ldcp->wrlock);
6984647Sraghuram 	/*
6994647Sraghuram 	 * If the flags not set to BUSY, it implies that the clobber
7004647Sraghuram 	 * was done while we were copying the data. In such case,
7014647Sraghuram 	 * discard the packet and return.
7024647Sraghuram 	 */
7034647Sraghuram 	if (tbufp->flags != VGEN_PRIV_DESC_BUSY) {
7044647Sraghuram 		statsp->oerrors++;
7054647Sraghuram 		mutex_exit(&ldcp->wrlock);
7064647Sraghuram 		goto vgen_tx_exit;
7074647Sraghuram 	}
7082336Snarayan 	hdrp->dstate = VIO_DESC_READY;
7091991Sheppo 
7101991Sheppo 	/* update stats */
7111991Sheppo 	statsp->opackets++;
7122109Slm66018 	statsp->obytes += size;
7131991Sheppo 	if (is_bcast)
7141991Sheppo 		statsp->brdcstxmt++;
7151991Sheppo 	else if (is_mcast)
7161991Sheppo 		statsp->multixmt++;
7171991Sheppo 
7184647Sraghuram 	/* send dring datamsg to the peer */
7194647Sraghuram 	if (ldcp->resched_peer) {
7204647Sraghuram 
7214647Sraghuram 		rtbufp = &ldcp->tbufp[ldcp->resched_peer_txi];
7224647Sraghuram 		rtxdp = rtbufp->descp;
7234647Sraghuram 
7244647Sraghuram 		if (rtxdp->hdr.dstate == VIO_DESC_READY) {
7254647Sraghuram 
7264647Sraghuram 			rv = vgen_send_dring_data(ldcp,
7274647Sraghuram 			    (uint32_t)ldcp->resched_peer_txi, -1);
7284647Sraghuram 			if (rv != 0) {
7294647Sraghuram 				/* error: drop the packet */
7304647Sraghuram 				DWARN(vgenp, ldcp, "vgen_send_dring_data "
7314650Sraghuram 				    "failed: rv(%d) len(%d)\n",
7324650Sraghuram 				    ldcp->ldc_id, rv, size);
7334647Sraghuram 				statsp->oerrors++;
7344647Sraghuram 			} else {
7354647Sraghuram 				ldcp->resched_peer = B_FALSE;
7364647Sraghuram 			}
7374647Sraghuram 
7384647Sraghuram 		}
7394647Sraghuram 
7404647Sraghuram 	}
7414647Sraghuram 
7424647Sraghuram 	mutex_exit(&ldcp->wrlock);
7434647Sraghuram 
7441991Sheppo vgen_tx_exit:
7452793Slm66018 	if (rv == ECONNRESET) {
7462793Slm66018 		/*
7472793Slm66018 		 * Check if either callback thread or another tx thread is
7482793Slm66018 		 * already running. Calling mutex_enter() will result in a
7492793Slm66018 		 * deadlock if the other thread already holds cblock and is
7502793Slm66018 		 * blocked in vnet_modify_fdb() (which is called from
7512793Slm66018 		 * vgen_handle_evt_reset()) waiting for write access on rwlock,
7522793Slm66018 		 * as this transmit thread already holds that lock as a reader
7532793Slm66018 		 * in vnet_m_tx(). See comments in vnet_modify_fdb() in vnet.c.
7542793Slm66018 		 */
7552793Slm66018 		if (mutex_tryenter(&ldcp->cblock)) {
7562793Slm66018 			if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
7574647Sraghuram 				DWARN(vgenp, ldcp, "ldc_status() error\n");
7582793Slm66018 			} else {
7592793Slm66018 				ldcp->ldc_status = istatus;
7602793Slm66018 			}
7612793Slm66018 			if (ldcp->ldc_status != LDC_UP) {
7622793Slm66018 				/*
7632793Slm66018 				 * Second arg is TRUE, as we know that
7642793Slm66018 				 * the caller of this function - vnet_m_tx(),
7652793Slm66018 				 * already holds fdb-rwlock as a reader.
7662793Slm66018 				 */
7672793Slm66018 				vgen_handle_evt_reset(ldcp, B_TRUE);
7682793Slm66018 			}
7692793Slm66018 			mutex_exit(&ldcp->cblock);
7702793Slm66018 		}
7712793Slm66018 	}
7722109Slm66018 	freemsg(mp);
7734647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
7742109Slm66018 	return (VGEN_TX_SUCCESS);
7751991Sheppo }
7761991Sheppo 
7771991Sheppo /* enable/disable a multicast address */
7782311Sseb int
7791991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
7801991Sheppo {
7811991Sheppo 	vgen_t			*vgenp;
7821991Sheppo 	vnet_mcast_msg_t	mcastmsg;
7831991Sheppo 	vio_msg_tag_t		*tagp;
7841991Sheppo 	vgen_port_t		*portp;
7851991Sheppo 	vgen_portlist_t		*plistp;
7861991Sheppo 	vgen_ldc_t		*ldcp;
7871991Sheppo 	vgen_ldclist_t		*ldclp;
7881991Sheppo 	struct ether_addr	*addrp;
7893653Snarayan 	int			rv = DDI_FAILURE;
7901991Sheppo 	uint32_t		i;
7911991Sheppo 
7921991Sheppo 	vgenp = (vgen_t *)arg;
7931991Sheppo 	addrp = (struct ether_addr *)mca;
7941991Sheppo 	tagp = &mcastmsg.tag;
7951991Sheppo 	bzero(&mcastmsg, sizeof (mcastmsg));
7961991Sheppo 
7971991Sheppo 	mutex_enter(&vgenp->lock);
7981991Sheppo 
7991991Sheppo 	plistp = &(vgenp->vgenports);
8001991Sheppo 
8011991Sheppo 	READ_ENTER(&plistp->rwlock);
8021991Sheppo 
8031991Sheppo 	portp = vgenp->vsw_portp;
8041991Sheppo 	if (portp == NULL) {
8051991Sheppo 		RW_EXIT(&plistp->rwlock);
8063653Snarayan 		mutex_exit(&vgenp->lock);
8073653Snarayan 		return (rv);
8081991Sheppo 	}
8091991Sheppo 	ldclp = &portp->ldclist;
8101991Sheppo 
8111991Sheppo 	READ_ENTER(&ldclp->rwlock);
8121991Sheppo 
8131991Sheppo 	ldcp = ldclp->headp;
8143653Snarayan 	if (ldcp == NULL)
8151991Sheppo 		goto vgen_mcast_exit;
8161991Sheppo 
8171991Sheppo 	mutex_enter(&ldcp->cblock);
8181991Sheppo 
8191991Sheppo 	if (ldcp->hphase == VH_DONE) {
8201991Sheppo 		/*
8211991Sheppo 		 * If handshake is done, send a msg to vsw to add/remove
822*5171Ssb155480 		 * the multicast address. Otherwise, we just update this
823*5171Ssb155480 		 * mcast address in our table and the table will be sync'd
824*5171Ssb155480 		 * with vsw when handshake completes.
8251991Sheppo 		 */
8261991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
8271991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
8281991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
8291991Sheppo 		tagp->vio_sid = ldcp->local_sid;
8301991Sheppo 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
8311991Sheppo 		mcastmsg.set = add;
8321991Sheppo 		mcastmsg.count = 1;
8333653Snarayan 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
8343653Snarayan 		    B_FALSE) != VGEN_SUCCESS) {
8354647Sraghuram 			DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
8363653Snarayan 			mutex_exit(&ldcp->cblock);
8373653Snarayan 			goto vgen_mcast_exit;
8381991Sheppo 		}
8391991Sheppo 	}
8401991Sheppo 
8411991Sheppo 	mutex_exit(&ldcp->cblock);
8421991Sheppo 
8431991Sheppo 	if (add) {
8441991Sheppo 
8451991Sheppo 		/* expand multicast table if necessary */
8461991Sheppo 		if (vgenp->mccount >= vgenp->mcsize) {
8471991Sheppo 			struct ether_addr	*newtab;
8481991Sheppo 			uint32_t		newsize;
8491991Sheppo 
8501991Sheppo 
8511991Sheppo 			newsize = vgenp->mcsize * 2;
8521991Sheppo 
8531991Sheppo 			newtab = kmem_zalloc(newsize *
8541991Sheppo 			    sizeof (struct ether_addr), KM_NOSLEEP);
8553653Snarayan 			if (newtab == NULL)
8563653Snarayan 				goto vgen_mcast_exit;
8571991Sheppo 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
8581991Sheppo 			    sizeof (struct ether_addr));
8591991Sheppo 			kmem_free(vgenp->mctab,
8601991Sheppo 			    vgenp->mcsize * sizeof (struct ether_addr));
8611991Sheppo 
8621991Sheppo 			vgenp->mctab = newtab;
8631991Sheppo 			vgenp->mcsize = newsize;
8641991Sheppo 		}
8651991Sheppo 
8661991Sheppo 		/* add address to the table */
8671991Sheppo 		vgenp->mctab[vgenp->mccount++] = *addrp;
8681991Sheppo 
8691991Sheppo 	} else {
8701991Sheppo 
8711991Sheppo 		/* delete address from the table */
8721991Sheppo 		for (i = 0; i < vgenp->mccount; i++) {
8731991Sheppo 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
8741991Sheppo 
8751991Sheppo 				/*
8761991Sheppo 				 * If there's more than one address in this
8771991Sheppo 				 * table, delete the unwanted one by moving
8781991Sheppo 				 * the last one in the list over top of it;
8791991Sheppo 				 * otherwise, just remove it.
8801991Sheppo 				 */
8811991Sheppo 				if (vgenp->mccount > 1) {
8821991Sheppo 					vgenp->mctab[i] =
8834650Sraghuram 					    vgenp->mctab[vgenp->mccount-1];
8841991Sheppo 				}
8851991Sheppo 				vgenp->mccount--;
8861991Sheppo 				break;
8871991Sheppo 			}
8881991Sheppo 		}
8891991Sheppo 	}
8901991Sheppo 
8913653Snarayan 	rv = DDI_SUCCESS;
8923653Snarayan 
8933653Snarayan vgen_mcast_exit:
8941991Sheppo 	RW_EXIT(&ldclp->rwlock);
8951991Sheppo 	RW_EXIT(&plistp->rwlock);
8961991Sheppo 
8971991Sheppo 	mutex_exit(&vgenp->lock);
8983653Snarayan 	return (rv);
8991991Sheppo }
9001991Sheppo 
9011991Sheppo /* set or clear promiscuous mode on the device */
9021991Sheppo static int
9031991Sheppo vgen_promisc(void *arg, boolean_t on)
9041991Sheppo {
9051991Sheppo 	_NOTE(ARGUNUSED(arg, on))
9061991Sheppo 	return (DDI_SUCCESS);
9071991Sheppo }
9081991Sheppo 
9091991Sheppo /* set the unicast mac address of the device */
9101991Sheppo static int
9111991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
9121991Sheppo {
9131991Sheppo 	_NOTE(ARGUNUSED(arg, mca))
9141991Sheppo 	return (DDI_SUCCESS);
9151991Sheppo }
9161991Sheppo 
9171991Sheppo /* get device statistics */
9182311Sseb int
9192311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
9201991Sheppo {
9211991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
9221991Sheppo 	vgen_port_t	*portp;
9231991Sheppo 	vgen_portlist_t	*plistp;
9242311Sseb 
9252311Sseb 	*val = 0;
9261991Sheppo 
9271991Sheppo 	plistp = &(vgenp->vgenports);
9281991Sheppo 	READ_ENTER(&plistp->rwlock);
9291991Sheppo 
9301991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
9312311Sseb 		*val += vgen_port_stat(portp, stat);
9321991Sheppo 	}
9331991Sheppo 
9341991Sheppo 	RW_EXIT(&plistp->rwlock);
9351991Sheppo 
9362311Sseb 	return (0);
9371991Sheppo }
9381991Sheppo 
9391991Sheppo static void
9401991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp)
9411991Sheppo {
9421991Sheppo 	 _NOTE(ARGUNUSED(arg, wq, mp))
9431991Sheppo }
9441991Sheppo 
9451991Sheppo /* vgen internal functions */
9461991Sheppo /* detach all ports from the device */
9471991Sheppo static void
9481991Sheppo vgen_detach_ports(vgen_t *vgenp)
9491991Sheppo {
9501991Sheppo 	vgen_port_t	*portp;
9511991Sheppo 	vgen_portlist_t	*plistp;
9521991Sheppo 
9531991Sheppo 	plistp = &(vgenp->vgenports);
9541991Sheppo 	WRITE_ENTER(&plistp->rwlock);
9551991Sheppo 
9561991Sheppo 	while ((portp = plistp->headp) != NULL) {
9571991Sheppo 		vgen_port_detach(portp);
9581991Sheppo 	}
9591991Sheppo 
9601991Sheppo 	RW_EXIT(&plistp->rwlock);
9611991Sheppo }
9621991Sheppo 
9631991Sheppo /*
9641991Sheppo  * detach the given port.
9651991Sheppo  */
9661991Sheppo static void
9671991Sheppo vgen_port_detach(vgen_port_t *portp)
9681991Sheppo {
9691991Sheppo 	vgen_t		*vgenp;
9701991Sheppo 	vgen_ldclist_t	*ldclp;
9711991Sheppo 	int		port_num;
9721991Sheppo 
9731991Sheppo 	vgenp = portp->vgenp;
9741991Sheppo 	port_num = portp->port_num;
9751991Sheppo 
9764647Sraghuram 	DBG1(vgenp, NULL, "port(%d):enter\n", port_num);
9771991Sheppo 
9781991Sheppo 	/* remove it from port list */
9791991Sheppo 	vgen_port_list_remove(portp);
9801991Sheppo 
9811991Sheppo 	/* detach channels from this port */
9821991Sheppo 	ldclp = &portp->ldclist;
9831991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
9841991Sheppo 	while (ldclp->headp) {
9851991Sheppo 		vgen_ldc_detach(ldclp->headp);
9861991Sheppo 	}
9871991Sheppo 	RW_EXIT(&ldclp->rwlock);
9881991Sheppo 
9891991Sheppo 	if (vgenp->vsw_portp == portp) {
9901991Sheppo 		vgenp->vsw_portp = NULL;
9911991Sheppo 	}
9921991Sheppo 	KMEM_FREE(portp);
9931991Sheppo 
9944647Sraghuram 	DBG1(vgenp, NULL, "port(%d):exit\n", port_num);
9951991Sheppo }
9961991Sheppo 
9971991Sheppo /* add a port to port list */
9981991Sheppo static void
9991991Sheppo vgen_port_list_insert(vgen_port_t *portp)
10001991Sheppo {
10011991Sheppo 	vgen_portlist_t *plistp;
10021991Sheppo 	vgen_t *vgenp;
10031991Sheppo 
10041991Sheppo 	vgenp = portp->vgenp;
10051991Sheppo 	plistp = &(vgenp->vgenports);
10061991Sheppo 
10071991Sheppo 	if (plistp->headp == NULL) {
10081991Sheppo 		plistp->headp = portp;
10091991Sheppo 	} else {
10101991Sheppo 		plistp->tailp->nextp = portp;
10111991Sheppo 	}
10121991Sheppo 	plistp->tailp = portp;
10131991Sheppo 	portp->nextp = NULL;
10141991Sheppo }
10151991Sheppo 
10161991Sheppo /* remove a port from port list */
10171991Sheppo static void
10181991Sheppo vgen_port_list_remove(vgen_port_t *portp)
10191991Sheppo {
10201991Sheppo 	vgen_port_t *prevp;
10211991Sheppo 	vgen_port_t *nextp;
10221991Sheppo 	vgen_portlist_t *plistp;
10231991Sheppo 	vgen_t *vgenp;
10241991Sheppo 
10251991Sheppo 	vgenp = portp->vgenp;
10261991Sheppo 
10271991Sheppo 	plistp = &(vgenp->vgenports);
10281991Sheppo 
10291991Sheppo 	if (plistp->headp == NULL)
10301991Sheppo 		return;
10311991Sheppo 
10321991Sheppo 	if (portp == plistp->headp) {
10331991Sheppo 		plistp->headp = portp->nextp;
10341991Sheppo 		if (portp == plistp->tailp)
10351991Sheppo 			plistp->tailp = plistp->headp;
10361991Sheppo 	} else {
10374650Sraghuram 		for (prevp = plistp->headp;
10384650Sraghuram 		    ((nextp = prevp->nextp) != NULL) && (nextp != portp);
10394650Sraghuram 		    prevp = nextp)
10404650Sraghuram 			;
10411991Sheppo 		if (nextp == portp) {
10421991Sheppo 			prevp->nextp = portp->nextp;
10431991Sheppo 		}
10441991Sheppo 		if (portp == plistp->tailp)
10451991Sheppo 			plistp->tailp = prevp;
10461991Sheppo 	}
10471991Sheppo }
10481991Sheppo 
10491991Sheppo /* lookup a port in the list based on port_num */
10501991Sheppo static vgen_port_t *
10511991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
10521991Sheppo {
10531991Sheppo 	vgen_port_t *portp = NULL;
10541991Sheppo 
10551991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10561991Sheppo 		if (portp->port_num == port_num) {
10571991Sheppo 			break;
10581991Sheppo 		}
10591991Sheppo 	}
10601991Sheppo 
10611991Sheppo 	return (portp);
10621991Sheppo }
10631991Sheppo 
10641991Sheppo /* enable ports for transmit/receive */
10651991Sheppo static void
10661991Sheppo vgen_init_ports(vgen_t *vgenp)
10671991Sheppo {
10681991Sheppo 	vgen_port_t	*portp;
10691991Sheppo 	vgen_portlist_t	*plistp;
10701991Sheppo 
10711991Sheppo 	plistp = &(vgenp->vgenports);
10721991Sheppo 	READ_ENTER(&plistp->rwlock);
10731991Sheppo 
10741991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10751991Sheppo 		vgen_port_init(portp);
10761991Sheppo 	}
10771991Sheppo 
10781991Sheppo 	RW_EXIT(&plistp->rwlock);
10791991Sheppo }
10801991Sheppo 
10811991Sheppo static void
10821991Sheppo vgen_port_init(vgen_port_t *portp)
10831991Sheppo {
10841991Sheppo 	vgen_t *vgenp;
10851991Sheppo 
10861991Sheppo 	vgenp = portp->vgenp;
10871991Sheppo 	/*
10881991Sheppo 	 * Create fdb entry in vnet, corresponding to the mac
10891991Sheppo 	 * address of this port. Note that the port specified
10901991Sheppo 	 * is vsw-port. This is done so that vsw-port acts
10911991Sheppo 	 * as the route to reach this macaddr, until the
10921991Sheppo 	 * channel for this port comes up (LDC_UP) and
10931991Sheppo 	 * handshake is done successfully.
10941991Sheppo 	 * eg, if the peer is OBP-vnet, it may not bring the
10951991Sheppo 	 * channel up for this port and may communicate via
10961991Sheppo 	 * vsw to reach this port.
10971991Sheppo 	 * Later, when Solaris-vnet comes up at the other end
10981991Sheppo 	 * of the channel for this port and brings up the channel,
10991991Sheppo 	 * it is an indication that peer vnet is capable of
11001991Sheppo 	 * distributed switching, so the direct route through this
11011991Sheppo 	 * port is specified in fdb, using vnet_modify_fdb(macaddr);
11021991Sheppo 	 */
11031991Sheppo 	vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr,
11041991Sheppo 	    vgen_tx, vgenp->vsw_portp);
11051991Sheppo 
11061991Sheppo 	if (portp == vgenp->vsw_portp) {
11071991Sheppo 		/*
11081991Sheppo 		 * create the default route entry in vnet's fdb.
11091991Sheppo 		 * This is the entry used by vnet to reach
11101991Sheppo 		 * unknown destinations, which basically goes
11111991Sheppo 		 * through vsw on domain0 and out through the
11121991Sheppo 		 * physical device bound to vsw.
11131991Sheppo 		 */
11141991Sheppo 		vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp);
11151991Sheppo 	}
11161991Sheppo 
11171991Sheppo 	/* Bring up the channels of this port */
11181991Sheppo 	vgen_init_ldcs(portp);
11191991Sheppo }
11201991Sheppo 
11211991Sheppo /* disable transmit/receive on ports */
11221991Sheppo static void
11231991Sheppo vgen_uninit_ports(vgen_t *vgenp)
11241991Sheppo {
11251991Sheppo 	vgen_port_t	*portp;
11261991Sheppo 	vgen_portlist_t	*plistp;
11271991Sheppo 
11281991Sheppo 	plistp = &(vgenp->vgenports);
11291991Sheppo 	READ_ENTER(&plistp->rwlock);
11301991Sheppo 
11311991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
11321991Sheppo 		vgen_port_uninit(portp);
11331991Sheppo 	}
11341991Sheppo 
11351991Sheppo 	RW_EXIT(&plistp->rwlock);
11361991Sheppo }
11371991Sheppo 
11381991Sheppo static void
11391991Sheppo vgen_port_uninit(vgen_port_t *portp)
11401991Sheppo {
11411991Sheppo 	vgen_t *vgenp;
11421991Sheppo 
11431991Sheppo 	vgenp = portp->vgenp;
11441991Sheppo 
11451991Sheppo 	vgen_uninit_ldcs(portp);
11461991Sheppo 	/* delete the entry in vnet's fdb for this port */
11471991Sheppo 	vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr);
11481991Sheppo 	if (portp == vgenp->vsw_portp) {
11491991Sheppo 		/*
11501991Sheppo 		 * if this is vsw-port, then delete the default
11511991Sheppo 		 * route entry in vnet's fdb.
11521991Sheppo 		 */
11531991Sheppo 		vnet_del_def_rte(vgenp->vnetp);
11541991Sheppo 	}
11551991Sheppo }
11561991Sheppo 
11571991Sheppo /* register with MD event generator */
11581991Sheppo static int
11591991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
11601991Sheppo {
11611991Sheppo 	mdeg_prop_spec_t	*pspecp;
11621991Sheppo 	mdeg_node_spec_t	*parentp;
11631991Sheppo 	uint_t			templatesz;
11641991Sheppo 	int			rv;
11651991Sheppo 	mdeg_handle_t		hdl;
11661991Sheppo 	int			i;
11671991Sheppo 
11681991Sheppo 	i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip,
11694650Sraghuram 	    DDI_PROP_DONTPASS, reg_propname, -1);
11701991Sheppo 	if (i == -1) {
11711991Sheppo 		return (DDI_FAILURE);
11721991Sheppo 	}
11731991Sheppo 	templatesz = sizeof (vgen_prop_template);
11741991Sheppo 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
11751991Sheppo 	if (pspecp == NULL) {
11761991Sheppo 		return (DDI_FAILURE);
11771991Sheppo 	}
11781991Sheppo 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
11791991Sheppo 	if (parentp == NULL) {
11801991Sheppo 		kmem_free(pspecp, templatesz);
11811991Sheppo 		return (DDI_FAILURE);
11821991Sheppo 	}
11831991Sheppo 
11841991Sheppo 	bcopy(vgen_prop_template, pspecp, templatesz);
11851991Sheppo 
11861991Sheppo 	/*
11871991Sheppo 	 * NOTE: The instance here refers to the value of "reg" property and
11881991Sheppo 	 * not the dev_info instance (ddi_get_instance()) of vnet.
11891991Sheppo 	 */
11901991Sheppo 	VGEN_SET_MDEG_PROP_INST(pspecp, i);
11911991Sheppo 
11921991Sheppo 	parentp->namep = "virtual-device";
11931991Sheppo 	parentp->specp = pspecp;
11941991Sheppo 
11951991Sheppo 	/* save parentp in vgen_t */
11961991Sheppo 	vgenp->mdeg_parentp = parentp;
11971991Sheppo 
11981991Sheppo 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl);
11991991Sheppo 	if (rv != MDEG_SUCCESS) {
12004647Sraghuram 		DERR(vgenp, NULL, "mdeg_register failed\n");
12011991Sheppo 		KMEM_FREE(parentp);
12021991Sheppo 		kmem_free(pspecp, templatesz);
12031991Sheppo 		vgenp->mdeg_parentp = NULL;
12041991Sheppo 		return (DDI_FAILURE);
12051991Sheppo 	}
12061991Sheppo 
12071991Sheppo 	/* save mdeg handle in vgen_t */
12081991Sheppo 	vgenp->mdeg_hdl = hdl;
12091991Sheppo 
12101991Sheppo 	return (DDI_SUCCESS);
12111991Sheppo }
12121991Sheppo 
12131991Sheppo /* unregister with MD event generator */
12141991Sheppo static void
12151991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
12161991Sheppo {
12171991Sheppo 	(void) mdeg_unregister(vgenp->mdeg_hdl);
12183297Ssb155480 	kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template));
12191991Sheppo 	KMEM_FREE(vgenp->mdeg_parentp);
12201991Sheppo 	vgenp->mdeg_parentp = NULL;
12211991Sheppo 	vgenp->mdeg_hdl = NULL;
12221991Sheppo }
12231991Sheppo 
12241991Sheppo /* callback function registered with MD event generator */
12251991Sheppo static int
12261991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
12271991Sheppo {
12281991Sheppo 	int idx;
12291991Sheppo 	int vsw_idx = -1;
12301991Sheppo 	uint64_t val;
12311991Sheppo 	vgen_t *vgenp;
12321991Sheppo 
12331991Sheppo 	if ((resp == NULL) || (cb_argp == NULL)) {
12341991Sheppo 		return (MDEG_FAILURE);
12351991Sheppo 	}
12361991Sheppo 
12371991Sheppo 	vgenp = (vgen_t *)cb_argp;
12384647Sraghuram 	DBG1(vgenp, NULL, "enter\n");
12391991Sheppo 
12401991Sheppo 	mutex_enter(&vgenp->lock);
12411991Sheppo 
12424647Sraghuram 	DBG1(vgenp, NULL, "ports: removed(%x), "
12434647Sraghuram 	"added(%x), updated(%x)\n", resp->removed.nelem,
12444647Sraghuram 	    resp->added.nelem, resp->match_curr.nelem);
12451991Sheppo 
12461991Sheppo 	for (idx = 0; idx < resp->removed.nelem; idx++) {
12471991Sheppo 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
12481991Sheppo 		    resp->removed.mdep[idx]);
12491991Sheppo 	}
12501991Sheppo 
12511991Sheppo 	if (vgenp->vsw_portp == NULL) {
12521991Sheppo 		/*
12531991Sheppo 		 * find vsw_port and add it first, because other ports need
12541991Sheppo 		 * this when adding fdb entry (see vgen_port_init()).
12551991Sheppo 		 */
12561991Sheppo 		for (idx = 0; idx < resp->added.nelem; idx++) {
12571991Sheppo 			if (!(md_get_prop_val(resp->added.mdp,
12581991Sheppo 			    resp->added.mdep[idx], swport_propname, &val))) {
12591991Sheppo 				if (val == 0) {
12601991Sheppo 					/*
12611991Sheppo 					 * This port is connected to the
12621991Sheppo 					 * vsw on dom0.
12631991Sheppo 					 */
12641991Sheppo 					vsw_idx = idx;
12654663Szk194757 					if (vgen_add_port(vgenp,
12661991Sheppo 					    resp->added.mdp,
12674663Szk194757 					    resp->added.mdep[idx]) !=
12684663Szk194757 					    DDI_SUCCESS) {
12694663Szk194757 						cmn_err(CE_NOTE, "vnet%d Could "
12704663Szk194757 						    "not initialize virtual "
12714663Szk194757 						    "switch port.",
12724663Szk194757 						    ddi_get_instance(vgenp->
12734663Szk194757 						    vnetdip));
12744663Szk194757 						mutex_exit(&vgenp->lock);
12754663Szk194757 						return (MDEG_FAILURE);
12764663Szk194757 					}
12771991Sheppo 					break;
12781991Sheppo 				}
12791991Sheppo 			}
12801991Sheppo 		}
12814666Szk194757 		if (vsw_idx == -1) {
12824647Sraghuram 			DWARN(vgenp, NULL, "can't find vsw_port\n");
12834663Szk194757 			mutex_exit(&vgenp->lock);
12841991Sheppo 			return (MDEG_FAILURE);
12851991Sheppo 		}
12861991Sheppo 	}
12871991Sheppo 
12881991Sheppo 	for (idx = 0; idx < resp->added.nelem; idx++) {
12891991Sheppo 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
12901991Sheppo 			continue;
12914663Szk194757 
12924663Szk194757 		/* If this port can't be added just skip it. */
12931991Sheppo 		(void) vgen_add_port(vgenp, resp->added.mdp,
12941991Sheppo 		    resp->added.mdep[idx]);
12951991Sheppo 	}
12961991Sheppo 
12971991Sheppo 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
12981991Sheppo 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
12991991Sheppo 		    resp->match_curr.mdep[idx],
13001991Sheppo 		    resp->match_prev.mdp,
13011991Sheppo 		    resp->match_prev.mdep[idx]);
13021991Sheppo 	}
13031991Sheppo 
13041991Sheppo 	mutex_exit(&vgenp->lock);
13054647Sraghuram 	DBG1(vgenp, NULL, "exit\n");
13061991Sheppo 	return (MDEG_SUCCESS);
13071991Sheppo }
13081991Sheppo 
13091991Sheppo /* add a new port to the device */
13101991Sheppo static int
13111991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
13121991Sheppo {
13131991Sheppo 	uint64_t	port_num;
13141991Sheppo 	uint64_t	*ldc_ids;
13151991Sheppo 	uint64_t	macaddr;
13161991Sheppo 	uint64_t	val;
13171991Sheppo 	int		num_ldcs;
13181991Sheppo 	int		vsw_port = B_FALSE;
13191991Sheppo 	int		i;
13201991Sheppo 	int		addrsz;
13211991Sheppo 	int		num_nodes = 0;
13221991Sheppo 	int		listsz = 0;
13234663Szk194757 	int		rv = DDI_SUCCESS;
13241991Sheppo 	mde_cookie_t	*listp = NULL;
13251991Sheppo 	uint8_t		*addrp;
13261991Sheppo 	struct ether_addr	ea;
13271991Sheppo 
13281991Sheppo 	/* read "id" property to get the port number */
13291991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
13304647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
13311991Sheppo 		return (DDI_FAILURE);
13321991Sheppo 	}
13331991Sheppo 
13341991Sheppo 	/*
13351991Sheppo 	 * Find the channel endpoint node(s) under this port node.
13361991Sheppo 	 */
13371991Sheppo 	if ((num_nodes = md_node_count(mdp)) <= 0) {
13384647Sraghuram 		DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
13394647Sraghuram 		    num_nodes);
13401991Sheppo 		return (DDI_FAILURE);
13411991Sheppo 	}
13421991Sheppo 
13431991Sheppo 	/* allocate space for node list */
13441991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
13451991Sheppo 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
13461991Sheppo 	if (listp == NULL)
13471991Sheppo 		return (DDI_FAILURE);
13481991Sheppo 
13491991Sheppo 	num_ldcs = md_scan_dag(mdp, mdex,
13504650Sraghuram 	    md_find_name(mdp, channel_propname),
13514650Sraghuram 	    md_find_name(mdp, "fwd"), listp);
13521991Sheppo 
13531991Sheppo 	if (num_ldcs <= 0) {
13544647Sraghuram 		DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
13551991Sheppo 		kmem_free(listp, listsz);
13561991Sheppo 		return (DDI_FAILURE);
13571991Sheppo 	}
13581991Sheppo 
13594647Sraghuram 	DBG2(vgenp, NULL, "num_ldcs %d", num_ldcs);
13601991Sheppo 
13611991Sheppo 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
13621991Sheppo 	if (ldc_ids == NULL) {
13631991Sheppo 		kmem_free(listp, listsz);
13641991Sheppo 		return (DDI_FAILURE);
13651991Sheppo 	}
13661991Sheppo 
13671991Sheppo 	for (i = 0; i < num_ldcs; i++) {
13681991Sheppo 		/* read channel ids */
13691991Sheppo 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
13704647Sraghuram 			DWARN(vgenp, NULL, "prop(%s) not found\n",
13714647Sraghuram 			    id_propname);
13721991Sheppo 			kmem_free(listp, listsz);
13731991Sheppo 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13741991Sheppo 			return (DDI_FAILURE);
13751991Sheppo 		}
13764647Sraghuram 		DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]);
13771991Sheppo 	}
13781991Sheppo 
13791991Sheppo 	kmem_free(listp, listsz);
13801991Sheppo 
13811991Sheppo 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
13821991Sheppo 	    &addrsz)) {
13834647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
13841991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13851991Sheppo 		return (DDI_FAILURE);
13861991Sheppo 	}
13871991Sheppo 
13881991Sheppo 	if (addrsz < ETHERADDRL) {
13894647Sraghuram 		DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
13901991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13911991Sheppo 		return (DDI_FAILURE);
13921991Sheppo 	}
13931991Sheppo 
13941991Sheppo 	macaddr = *((uint64_t *)addrp);
13951991Sheppo 
13964647Sraghuram 	DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
13971991Sheppo 
13981991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
13991991Sheppo 		ea.ether_addr_octet[i] = macaddr & 0xFF;
14001991Sheppo 		macaddr >>= 8;
14011991Sheppo 	}
14021991Sheppo 
14031991Sheppo 	if (vgenp->vsw_portp == NULL) {
14041991Sheppo 		if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
14051991Sheppo 			if (val == 0) {
14061991Sheppo 				/* This port is connected to the vsw on dom0 */
14071991Sheppo 				vsw_port = B_TRUE;
14081991Sheppo 			}
14091991Sheppo 		}
14101991Sheppo 	}
14114663Szk194757 	if (vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
14124663Szk194757 	    &ea, vsw_port) != DDI_SUCCESS) {
14134663Szk194757 		cmn_err(CE_NOTE, "vnet%d failed to attach port %d remote MAC "
14144663Szk194757 		    "address %s", ddi_get_instance(vgenp->vnetdip),
14154663Szk194757 		    (int)port_num, ether_sprintf(&ea));
14164663Szk194757 		rv = DDI_FAILURE;
14174663Szk194757 	}
14181991Sheppo 
14191991Sheppo 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
14201991Sheppo 
14214663Szk194757 	return (rv);
14221991Sheppo }
14231991Sheppo 
14241991Sheppo /* remove a port from the device */
14251991Sheppo static int
14261991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
14271991Sheppo {
14281991Sheppo 	uint64_t	port_num;
14291991Sheppo 	vgen_port_t	*portp;
14301991Sheppo 	vgen_portlist_t	*plistp;
14311991Sheppo 
14321991Sheppo 	/* read "id" property to get the port number */
14331991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
14344647Sraghuram 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
14351991Sheppo 		return (DDI_FAILURE);
14361991Sheppo 	}
14371991Sheppo 
14381991Sheppo 	plistp = &(vgenp->vgenports);
14391991Sheppo 
14401991Sheppo 	WRITE_ENTER(&plistp->rwlock);
14411991Sheppo 	portp = vgen_port_lookup(plistp, (int)port_num);
14421991Sheppo 	if (portp == NULL) {
14434647Sraghuram 		DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
14441991Sheppo 		RW_EXIT(&plistp->rwlock);
14451991Sheppo 		return (DDI_FAILURE);
14461991Sheppo 	}
14471991Sheppo 
14481991Sheppo 	vgen_port_detach_mdeg(portp);
14491991Sheppo 	RW_EXIT(&plistp->rwlock);
14501991Sheppo 
14511991Sheppo 	return (DDI_SUCCESS);
14521991Sheppo }
14531991Sheppo 
14541991Sheppo /* attach a port to the device based on mdeg data */
14551991Sheppo static int
14561991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
14571991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port)
14581991Sheppo {
14591991Sheppo 	vgen_port_t		*portp;
14601991Sheppo 	vgen_portlist_t		*plistp;
14611991Sheppo 	int			i;
14621991Sheppo 
14631991Sheppo 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP);
14641991Sheppo 	if (portp == NULL) {
14651991Sheppo 		return (DDI_FAILURE);
14661991Sheppo 	}
14671991Sheppo 	portp->vgenp = vgenp;
14681991Sheppo 	portp->port_num = port_num;
14691991Sheppo 
14704647Sraghuram 	DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num);
14711991Sheppo 
14721991Sheppo 	portp->ldclist.num_ldcs = 0;
14731991Sheppo 	portp->ldclist.headp = NULL;
14741991Sheppo 	rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
14751991Sheppo 
14761991Sheppo 	ether_copy(macaddr, &portp->macaddr);
14771991Sheppo 	for (i = 0; i < num_ids; i++) {
14784647Sraghuram 		DBG2(vgenp, NULL, "ldcid (%lx)\n", ldcids[i]);
14794663Szk194757 		if (vgen_ldc_attach(portp, ldcids[i]) == DDI_FAILURE) {
14804663Szk194757 			rw_destroy(&portp->ldclist.rwlock);
14814663Szk194757 			vgen_port_detach(portp);
14824663Szk194757 			return (DDI_FAILURE);
14834663Szk194757 		}
14841991Sheppo 	}
14851991Sheppo 
14861991Sheppo 	/* link it into the list of ports */
14871991Sheppo 	plistp = &(vgenp->vgenports);
14881991Sheppo 	WRITE_ENTER(&plistp->rwlock);
14891991Sheppo 	vgen_port_list_insert(portp);
14901991Sheppo 	RW_EXIT(&plistp->rwlock);
14911991Sheppo 
14921991Sheppo 	/* This port is connected to the vsw on domain0 */
14931991Sheppo 	if (vsw_port)
14941991Sheppo 		vgenp->vsw_portp = portp;
14951991Sheppo 
14961991Sheppo 	if (vgenp->flags & VGEN_STARTED) {	/* interface is configured */
14971991Sheppo 		vgen_port_init(portp);
14981991Sheppo 	}
14991991Sheppo 
15004647Sraghuram 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
15011991Sheppo 	return (DDI_SUCCESS);
15021991Sheppo }
15031991Sheppo 
15041991Sheppo /* detach a port from the device based on mdeg data */
15051991Sheppo static void
15061991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
15071991Sheppo {
15081991Sheppo 	vgen_t *vgenp = portp->vgenp;
15091991Sheppo 
15104647Sraghuram 	DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
15111991Sheppo 	/* stop the port if needed */
15121991Sheppo 	if (vgenp->flags & VGEN_STARTED) {
15131991Sheppo 		vgen_port_uninit(portp);
15141991Sheppo 	}
15151991Sheppo 	vgen_port_detach(portp);
15161991Sheppo 
15174647Sraghuram 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
15181991Sheppo }
15191991Sheppo 
15201991Sheppo static int
15211991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
15221991Sheppo 	md_t *prev_mdp, mde_cookie_t prev_mdex)
15231991Sheppo {
15241991Sheppo 	 _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex))
15251991Sheppo 
15262793Slm66018 	/* NOTE: TBD */
15271991Sheppo 	return (DDI_SUCCESS);
15281991Sheppo }
15291991Sheppo 
15301991Sheppo static uint64_t
15312311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
15321991Sheppo {
15331991Sheppo 	vgen_ldclist_t	*ldclp;
15341991Sheppo 	vgen_ldc_t *ldcp;
15351991Sheppo 	uint64_t	val;
15361991Sheppo 
15371991Sheppo 	val = 0;
15381991Sheppo 	ldclp = &portp->ldclist;
15391991Sheppo 
15401991Sheppo 	READ_ENTER(&ldclp->rwlock);
15411991Sheppo 	for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
15421991Sheppo 		val += vgen_ldc_stat(ldcp, stat);
15431991Sheppo 	}
15441991Sheppo 	RW_EXIT(&ldclp->rwlock);
15451991Sheppo 
15461991Sheppo 	return (val);
15471991Sheppo }
15481991Sheppo 
15491991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
15501991Sheppo static int
15511991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
15521991Sheppo {
15531991Sheppo 	vgen_t 		*vgenp;
15541991Sheppo 	vgen_ldclist_t	*ldclp;
15551991Sheppo 	vgen_ldc_t 	*ldcp, **prev_ldcp;
15561991Sheppo 	ldc_attr_t 	attr;
15571991Sheppo 	int 		status;
15581991Sheppo 	ldc_status_t	istatus;
15594647Sraghuram 	enum	{AST_init = 0x0, AST_ldc_alloc = 0x1,
15604647Sraghuram 		AST_mutex_init = 0x2, AST_ldc_init = 0x4,
15614647Sraghuram 		AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10,
15624647Sraghuram 		AST_create_rxmblks = 0x20, AST_add_softintr = 0x40,
15634647Sraghuram 		AST_create_rcv_thread = 0x80} attach_state;
15641991Sheppo 
15651991Sheppo 	attach_state = AST_init;
15661991Sheppo 	vgenp = portp->vgenp;
15671991Sheppo 	ldclp = &portp->ldclist;
15681991Sheppo 
15691991Sheppo 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
15701991Sheppo 	if (ldcp == NULL) {
15711991Sheppo 		goto ldc_attach_failed;
15721991Sheppo 	}
15731991Sheppo 	ldcp->ldc_id = ldc_id;
15741991Sheppo 	ldcp->portp = portp;
15751991Sheppo 
15761991Sheppo 	attach_state |= AST_ldc_alloc;
15771991Sheppo 
15781991Sheppo 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
15791991Sheppo 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
15801991Sheppo 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
15814647Sraghuram 	mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
15824647Sraghuram 	mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
15831991Sheppo 
15841991Sheppo 	attach_state |= AST_mutex_init;
15851991Sheppo 
15861991Sheppo 	attr.devclass = LDC_DEV_NT;
15871991Sheppo 	attr.instance = ddi_get_instance(vgenp->vnetdip);
15881991Sheppo 	attr.mode = LDC_MODE_UNRELIABLE;
15892410Slm66018 	attr.mtu = vnet_ldc_mtu;
15901991Sheppo 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
15911991Sheppo 	if (status != 0) {
15924647Sraghuram 		DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
15931991Sheppo 		goto ldc_attach_failed;
15941991Sheppo 	}
15951991Sheppo 	attach_state |= AST_ldc_init;
15961991Sheppo 
15974647Sraghuram 	if (vgen_rcv_thread_enabled) {
15984647Sraghuram 		ldcp->rcv_thr_flags = 0;
15994647Sraghuram 		ldcp->rcv_mhead = ldcp->rcv_mtail = NULL;
16004647Sraghuram 		ldcp->soft_pri = PIL_6;
16014647Sraghuram 
16024647Sraghuram 		status = ddi_intr_add_softint(vgenp->vnetdip,
16034650Sraghuram 		    &ldcp->soft_handle, ldcp->soft_pri,
16044650Sraghuram 		    vgen_ldc_rcv_softintr, (void *)ldcp);
16054647Sraghuram 		if (status != DDI_SUCCESS) {
16064647Sraghuram 			DWARN(vgenp, ldcp, "add_softint failed, rv (%d)\n",
16074647Sraghuram 			    status);
16084647Sraghuram 			goto ldc_attach_failed;
16094647Sraghuram 		}
16104647Sraghuram 
16114647Sraghuram 		/*
16124650Sraghuram 		 * Initialize the soft_lock with the same priority as
16134650Sraghuram 		 * the soft interrupt to protect from the soft interrupt.
16144650Sraghuram 		 */
16154647Sraghuram 		mutex_init(&ldcp->soft_lock, NULL, MUTEX_DRIVER,
16164647Sraghuram 		    DDI_INTR_PRI(ldcp->soft_pri));
16174647Sraghuram 		attach_state |= AST_add_softintr;
16184647Sraghuram 
16194647Sraghuram 		mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL);
16204647Sraghuram 		cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL);
16214647Sraghuram 		ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
16224647Sraghuram 		    vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
16234647Sraghuram 
16244647Sraghuram 		attach_state |= AST_create_rcv_thread;
16254647Sraghuram 		if (ldcp->rcv_thread == NULL) {
16264647Sraghuram 			DWARN(vgenp, ldcp, "Failed to create worker thread");
16274647Sraghuram 			goto ldc_attach_failed;
16284647Sraghuram 		}
16294647Sraghuram 	}
16304647Sraghuram 
16311991Sheppo 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
16321991Sheppo 	if (status != 0) {
16334647Sraghuram 		DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
16344647Sraghuram 		    status);
16351991Sheppo 		goto ldc_attach_failed;
16361991Sheppo 	}
16371991Sheppo 	attach_state |= AST_ldc_reg_cb;
16381991Sheppo 
16391991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
16401991Sheppo 	ASSERT(istatus == LDC_INIT);
16411991Sheppo 	ldcp->ldc_status = istatus;
16421991Sheppo 
16431991Sheppo 	/* allocate transmit resources */
16441991Sheppo 	status = vgen_alloc_tx_ring(ldcp);
16451991Sheppo 	if (status != 0) {
16461991Sheppo 		goto ldc_attach_failed;
16471991Sheppo 	}
16481991Sheppo 	attach_state |= AST_alloc_tx_ring;
16491991Sheppo 
16502336Snarayan 	/* allocate receive resources */
16514647Sraghuram 	status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS,
16524650Sraghuram 	    vgen_rbufsz1, vgen_rbufsz2, vgen_rbufsz3,
16534650Sraghuram 	    vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3);
16542336Snarayan 	if (status != 0) {
16552336Snarayan 		goto ldc_attach_failed;
16562336Snarayan 	}
16572336Snarayan 	attach_state |= AST_create_rxmblks;
16582336Snarayan 
16591991Sheppo 	/* Setup kstats for the channel */
16601991Sheppo 	status = vgen_setup_kstats(ldcp);
16611991Sheppo 	if (status != VGEN_SUCCESS) {
16621991Sheppo 		goto ldc_attach_failed;
16631991Sheppo 	}
16641991Sheppo 
16651991Sheppo 	/* initialize vgen_versions supported */
16661991Sheppo 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
16671991Sheppo 
16681991Sheppo 	/* link it into the list of channels for this port */
16691991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
16701991Sheppo 	prev_ldcp = (vgen_ldc_t **)(&ldclp->headp);
16711991Sheppo 	ldcp->nextp = *prev_ldcp;
16721991Sheppo 	*prev_ldcp = ldcp;
16731991Sheppo 	ldclp->num_ldcs++;
16741991Sheppo 	RW_EXIT(&ldclp->rwlock);
16751991Sheppo 
16761991Sheppo 	ldcp->flags |= CHANNEL_ATTACHED;
16771991Sheppo 	return (DDI_SUCCESS);
16781991Sheppo 
16791991Sheppo ldc_attach_failed:
16804647Sraghuram 	if (attach_state & AST_ldc_reg_cb) {
16814647Sraghuram 		(void) ldc_unreg_callback(ldcp->ldc_handle);
16824647Sraghuram 	}
16834647Sraghuram 	if (attach_state & AST_add_softintr) {
16844647Sraghuram 		(void) ddi_intr_remove_softint(ldcp->soft_handle);
16854647Sraghuram 		mutex_destroy(&ldcp->soft_lock);
16864647Sraghuram 	}
16874647Sraghuram 	if (attach_state & AST_create_rcv_thread) {
16884647Sraghuram 		if (ldcp->rcv_thread != NULL) {
16894647Sraghuram 			vgen_stop_rcv_thread(ldcp);
16904647Sraghuram 		}
16914647Sraghuram 		mutex_destroy(&ldcp->rcv_thr_lock);
16924647Sraghuram 		cv_destroy(&ldcp->rcv_thr_cv);
16934647Sraghuram 	}
16942336Snarayan 	if (attach_state & AST_create_rxmblks) {
16954647Sraghuram 		vio_mblk_pool_t *fvmp = NULL;
16964647Sraghuram 
16974647Sraghuram 		vio_destroy_multipools(&ldcp->vmp, &fvmp);
16984647Sraghuram 		ASSERT(fvmp == NULL);
16992336Snarayan 	}
17001991Sheppo 	if (attach_state & AST_alloc_tx_ring) {
17011991Sheppo 		vgen_free_tx_ring(ldcp);
17021991Sheppo 	}
17031991Sheppo 	if (attach_state & AST_ldc_init) {
17041991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
17051991Sheppo 	}
17061991Sheppo 	if (attach_state & AST_mutex_init) {
17071991Sheppo 		mutex_destroy(&ldcp->tclock);
17081991Sheppo 		mutex_destroy(&ldcp->txlock);
17091991Sheppo 		mutex_destroy(&ldcp->cblock);
17104647Sraghuram 		mutex_destroy(&ldcp->wrlock);
17114647Sraghuram 		mutex_destroy(&ldcp->rxlock);
17121991Sheppo 	}
17131991Sheppo 	if (attach_state & AST_ldc_alloc) {
17141991Sheppo 		KMEM_FREE(ldcp);
17151991Sheppo 	}
17161991Sheppo 	return (DDI_FAILURE);
17171991Sheppo }
17181991Sheppo 
17191991Sheppo /* detach a channel from the port */
17201991Sheppo static void
17211991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
17221991Sheppo {
17231991Sheppo 	vgen_port_t	*portp;
17241991Sheppo 	vgen_t 		*vgenp;
17251991Sheppo 	vgen_ldc_t 	*pldcp;
17261991Sheppo 	vgen_ldc_t	**prev_ldcp;
17271991Sheppo 	vgen_ldclist_t	*ldclp;
17281991Sheppo 
17291991Sheppo 	portp = ldcp->portp;
17301991Sheppo 	vgenp = portp->vgenp;
17311991Sheppo 	ldclp = &portp->ldclist;
17321991Sheppo 
17331991Sheppo 	prev_ldcp =  (vgen_ldc_t **)&ldclp->headp;
17341991Sheppo 	for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
17351991Sheppo 		if (pldcp == ldcp) {
17361991Sheppo 			break;
17371991Sheppo 		}
17381991Sheppo 	}
17391991Sheppo 
17401991Sheppo 	if (pldcp == NULL) {
17411991Sheppo 		/* invalid ldcp? */
17421991Sheppo 		return;
17431991Sheppo 	}
17441991Sheppo 
17451991Sheppo 	if (ldcp->ldc_status != LDC_INIT) {
17464647Sraghuram 		DWARN(vgenp, ldcp, "ldc_status is not INIT\n");
17471991Sheppo 	}
17481991Sheppo 
17491991Sheppo 	if (ldcp->flags & CHANNEL_ATTACHED) {
17501991Sheppo 		ldcp->flags &= ~(CHANNEL_ATTACHED);
17511991Sheppo 
17524647Sraghuram 		(void) ldc_unreg_callback(ldcp->ldc_handle);
17534647Sraghuram 		if (ldcp->rcv_thread != NULL) {
17544647Sraghuram 			/* First stop the receive thread */
17554647Sraghuram 			vgen_stop_rcv_thread(ldcp);
17564647Sraghuram 			(void) ddi_intr_remove_softint(ldcp->soft_handle);
17574647Sraghuram 			mutex_destroy(&ldcp->soft_lock);
17584647Sraghuram 			mutex_destroy(&ldcp->rcv_thr_lock);
17594647Sraghuram 			cv_destroy(&ldcp->rcv_thr_cv);
17604647Sraghuram 		}
17614647Sraghuram 		/* Free any queued messages */
17624647Sraghuram 		if (ldcp->rcv_mhead != NULL) {
17634647Sraghuram 			freemsgchain(ldcp->rcv_mhead);
17644647Sraghuram 			ldcp->rcv_mhead = NULL;
17654647Sraghuram 		}
17664647Sraghuram 
17671991Sheppo 		vgen_destroy_kstats(ldcp);
17684647Sraghuram 		/*
17694647Sraghuram 		 * if we cannot reclaim all mblks, put this
17704647Sraghuram 		 * on the list of pools(vgenp->rmp) to be reclaimed when the
17714647Sraghuram 		 * device gets detached (see vgen_uninit()).
17724647Sraghuram 		 */
17734647Sraghuram 		vio_destroy_multipools(&ldcp->vmp, &vgenp->rmp);
17742336Snarayan 
17751991Sheppo 		/* free transmit resources */
17761991Sheppo 		vgen_free_tx_ring(ldcp);
17772336Snarayan 
17781991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
17791991Sheppo 		mutex_destroy(&ldcp->tclock);
17801991Sheppo 		mutex_destroy(&ldcp->txlock);
17811991Sheppo 		mutex_destroy(&ldcp->cblock);
17824647Sraghuram 		mutex_destroy(&ldcp->wrlock);
17834647Sraghuram 		mutex_destroy(&ldcp->rxlock);
17841991Sheppo 
17851991Sheppo 		/* unlink it from the list */
17861991Sheppo 		*prev_ldcp = ldcp->nextp;
17871991Sheppo 		ldclp->num_ldcs--;
17881991Sheppo 		KMEM_FREE(ldcp);
17891991Sheppo 	}
17901991Sheppo }
17911991Sheppo 
17921991Sheppo /*
17931991Sheppo  * This function allocates transmit resources for the channel.
17941991Sheppo  * The resources consist of a transmit descriptor ring and an associated
17951991Sheppo  * transmit buffer ring.
17961991Sheppo  */
17971991Sheppo static int
17981991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp)
17991991Sheppo {
18001991Sheppo 	void *tbufp;
18011991Sheppo 	ldc_mem_info_t minfo;
18021991Sheppo 	uint32_t txdsize;
18031991Sheppo 	uint32_t tbufsize;
18041991Sheppo 	int status;
18054647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
18061991Sheppo 
18071991Sheppo 	ldcp->num_txds = vnet_ntxds;
18081991Sheppo 	txdsize = sizeof (vnet_public_desc_t);
18091991Sheppo 	tbufsize = sizeof (vgen_private_desc_t);
18101991Sheppo 
18111991Sheppo 	/* allocate transmit buffer ring */
18121991Sheppo 	tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
18131991Sheppo 	if (tbufp == NULL) {
18141991Sheppo 		return (DDI_FAILURE);
18151991Sheppo 	}
18161991Sheppo 
18171991Sheppo 	/* create transmit descriptor ring */
18181991Sheppo 	status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
18191991Sheppo 	    &ldcp->tx_dhandle);
18201991Sheppo 	if (status) {
18214647Sraghuram 		DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n");
18221991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
18231991Sheppo 		return (DDI_FAILURE);
18241991Sheppo 	}
18251991Sheppo 
18261991Sheppo 	/* get the addr of descripror ring */
18271991Sheppo 	status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
18281991Sheppo 	if (status) {
18294647Sraghuram 		DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n");
18301991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
18311991Sheppo 		(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
18321991Sheppo 		ldcp->tbufp = NULL;
18331991Sheppo 		return (DDI_FAILURE);
18341991Sheppo 	}
18351991Sheppo 	ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr);
18361991Sheppo 	ldcp->tbufp = tbufp;
18371991Sheppo 
18381991Sheppo 	ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]);
18391991Sheppo 	ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]);
18401991Sheppo 
18411991Sheppo 	return (DDI_SUCCESS);
18421991Sheppo }
18431991Sheppo 
18441991Sheppo /* Free transmit resources for the channel */
18451991Sheppo static void
18461991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp)
18471991Sheppo {
18481991Sheppo 	int tbufsize = sizeof (vgen_private_desc_t);
18491991Sheppo 
18501991Sheppo 	/* free transmit descriptor ring */
18511991Sheppo 	(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
18521991Sheppo 
18531991Sheppo 	/* free transmit buffer ring */
18541991Sheppo 	kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize);
18551991Sheppo 	ldcp->txdp = ldcp->txdendp = NULL;
18561991Sheppo 	ldcp->tbufp = ldcp->tbufendp = NULL;
18571991Sheppo }
18581991Sheppo 
18591991Sheppo /* enable transmit/receive on the channels for the port */
18601991Sheppo static void
18611991Sheppo vgen_init_ldcs(vgen_port_t *portp)
18621991Sheppo {
18631991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
18641991Sheppo 	vgen_ldc_t	*ldcp;
18651991Sheppo 
18661991Sheppo 	READ_ENTER(&ldclp->rwlock);
18671991Sheppo 	ldcp =  ldclp->headp;
18681991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
18691991Sheppo 		(void) vgen_ldc_init(ldcp);
18701991Sheppo 	}
18711991Sheppo 	RW_EXIT(&ldclp->rwlock);
18721991Sheppo }
18731991Sheppo 
18741991Sheppo /* stop transmit/receive on the channels for the port */
18751991Sheppo static void
18761991Sheppo vgen_uninit_ldcs(vgen_port_t *portp)
18771991Sheppo {
18781991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
18791991Sheppo 	vgen_ldc_t	*ldcp;
18801991Sheppo 
18811991Sheppo 	READ_ENTER(&ldclp->rwlock);
18821991Sheppo 	ldcp =  ldclp->headp;
18831991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
18841991Sheppo 		vgen_ldc_uninit(ldcp);
18851991Sheppo 	}
18861991Sheppo 	RW_EXIT(&ldclp->rwlock);
18871991Sheppo }
18881991Sheppo 
18891991Sheppo /* enable transmit/receive on the channel */
18901991Sheppo static int
18911991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
18921991Sheppo {
18934647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
18941991Sheppo 	ldc_status_t	istatus;
18951991Sheppo 	int		rv;
18962109Slm66018 	uint32_t	retries = 0;
18974647Sraghuram 	enum	{ ST_init = 0x0, ST_ldc_open = 0x1,
18984647Sraghuram 		ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state;
18991991Sheppo 	init_state = ST_init;
19001991Sheppo 
19014647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
19021991Sheppo 	LDC_LOCK(ldcp);
19031991Sheppo 
19041991Sheppo 	rv = ldc_open(ldcp->ldc_handle);
19051991Sheppo 	if (rv != 0) {
19064647Sraghuram 		DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
19071991Sheppo 		goto ldcinit_failed;
19081991Sheppo 	}
19091991Sheppo 	init_state |= ST_ldc_open;
19101991Sheppo 
19111991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
19121991Sheppo 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
19134647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
19141991Sheppo 		goto ldcinit_failed;
19151991Sheppo 	}
19161991Sheppo 	ldcp->ldc_status = istatus;
19171991Sheppo 
19181991Sheppo 	rv = vgen_init_tbufs(ldcp);
19191991Sheppo 	if (rv != 0) {
19204647Sraghuram 		DWARN(vgenp, ldcp, "vgen_init_tbufs() failed\n");
19211991Sheppo 		goto ldcinit_failed;
19221991Sheppo 	}
19231991Sheppo 	init_state |= ST_init_tbufs;
19241991Sheppo 
19252748Slm66018 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
19262748Slm66018 	if (rv != 0) {
19274647Sraghuram 		DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
19282748Slm66018 		goto ldcinit_failed;
19292748Slm66018 	}
19302748Slm66018 
19312748Slm66018 	init_state |= ST_cb_enable;
19322748Slm66018 
19332109Slm66018 	do {
19342109Slm66018 		rv = ldc_up(ldcp->ldc_handle);
19352109Slm66018 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
19364647Sraghuram 			DBG2(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
19372109Slm66018 			drv_usecwait(VGEN_LDC_UP_DELAY);
19382109Slm66018 		}
19392109Slm66018 		if (retries++ >= vgen_ldcup_retries)
19402109Slm66018 			break;
19412109Slm66018 	} while (rv == EWOULDBLOCK);
19421991Sheppo 
19431991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
19442793Slm66018 	if (istatus == LDC_UP) {
19454647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus);
19461991Sheppo 	}
19472793Slm66018 
19481991Sheppo 	ldcp->ldc_status = istatus;
19491991Sheppo 
19501991Sheppo 	/* initialize transmit watchdog timeout */
19511991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
19521991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
19531991Sheppo 
19542793Slm66018 	ldcp->hphase = -1;
19551991Sheppo 	ldcp->flags |= CHANNEL_STARTED;
19561991Sheppo 
19572793Slm66018 	/* if channel is already UP - start handshake */
19582793Slm66018 	if (istatus == LDC_UP) {
19592793Slm66018 		vgen_t *vgenp = LDC_TO_VGEN(ldcp);
19602793Slm66018 		if (ldcp->portp != vgenp->vsw_portp) {
19612793Slm66018 			/*
19622793Slm66018 			 * modify fdb entry to use this port as the
19632793Slm66018 			 * channel is up, instead of going through the
19642793Slm66018 			 * vsw-port (see comments in vgen_port_init())
19652793Slm66018 			 */
19664647Sraghuram 			vnet_modify_fdb(vgenp->vnetp,
19672793Slm66018 			    (uint8_t *)&ldcp->portp->macaddr,
19682793Slm66018 			    vgen_tx, ldcp->portp, B_FALSE);
19692793Slm66018 		}
19702793Slm66018 
19712793Slm66018 		/* Initialize local session id */
19722793Slm66018 		ldcp->local_sid = ddi_get_lbolt();
19732793Slm66018 
19742793Slm66018 		/* clear peer session id */
19752793Slm66018 		ldcp->peer_sid = 0;
19762793Slm66018 		ldcp->hretries = 0;
19772793Slm66018 
19782793Slm66018 		/* Initiate Handshake process with peer ldc endpoint */
19792793Slm66018 		vgen_reset_hphase(ldcp);
19802793Slm66018 
19812793Slm66018 		mutex_exit(&ldcp->tclock);
19822793Slm66018 		mutex_exit(&ldcp->txlock);
19834647Sraghuram 		mutex_exit(&ldcp->wrlock);
19842793Slm66018 		vgen_handshake(vh_nextphase(ldcp));
19854647Sraghuram 		mutex_exit(&ldcp->rxlock);
19862793Slm66018 		mutex_exit(&ldcp->cblock);
19872793Slm66018 	} else {
19882793Slm66018 		LDC_UNLOCK(ldcp);
19892793Slm66018 	}
19902793Slm66018 
19911991Sheppo 	return (DDI_SUCCESS);
19921991Sheppo 
19931991Sheppo ldcinit_failed:
19942748Slm66018 	if (init_state & ST_cb_enable) {
19952748Slm66018 		(void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
19962748Slm66018 	}
19971991Sheppo 	if (init_state & ST_init_tbufs) {
19981991Sheppo 		vgen_uninit_tbufs(ldcp);
19991991Sheppo 	}
20001991Sheppo 	if (init_state & ST_ldc_open) {
20011991Sheppo 		(void) ldc_close(ldcp->ldc_handle);
20021991Sheppo 	}
20031991Sheppo 	LDC_UNLOCK(ldcp);
20044647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
20051991Sheppo 	return (DDI_FAILURE);
20061991Sheppo }
20071991Sheppo 
20081991Sheppo /* stop transmit/receive on the channel */
20091991Sheppo static void
20101991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
20111991Sheppo {
20124647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
20131991Sheppo 	int	rv;
20141991Sheppo 
20154647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
20161991Sheppo 	LDC_LOCK(ldcp);
20171991Sheppo 
20181991Sheppo 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
20191991Sheppo 		LDC_UNLOCK(ldcp);
20204647Sraghuram 		DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
20211991Sheppo 		return;
20221991Sheppo 	}
20231991Sheppo 
20241991Sheppo 	/* disable further callbacks */
20251991Sheppo 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
20261991Sheppo 	if (rv != 0) {
20274647Sraghuram 		DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n");
20281991Sheppo 	}
20291991Sheppo 
20303653Snarayan 	/*
20313653Snarayan 	 * clear handshake done bit and wait for pending tx and cb to finish.
20323653Snarayan 	 * release locks before untimeout(9F) is invoked to cancel timeouts.
20333653Snarayan 	 */
20341991Sheppo 	ldcp->hphase &= ~(VH_DONE);
20351991Sheppo 	LDC_UNLOCK(ldcp);
20363653Snarayan 
20373653Snarayan 	/* cancel handshake watchdog timeout */
20383653Snarayan 	if (ldcp->htid) {
20393653Snarayan 		(void) untimeout(ldcp->htid);
20403653Snarayan 		ldcp->htid = 0;
20413653Snarayan 	}
20423653Snarayan 
20433653Snarayan 	/* cancel transmit watchdog timeout */
20441991Sheppo 	if (ldcp->wd_tid) {
20451991Sheppo 		(void) untimeout(ldcp->wd_tid);
20461991Sheppo 		ldcp->wd_tid = 0;
20471991Sheppo 	}
20481991Sheppo 
20493653Snarayan 	drv_usecwait(1000);
20503653Snarayan 
20513653Snarayan 	/* acquire locks again; any pending transmits and callbacks are done */
20523653Snarayan 	LDC_LOCK(ldcp);
20533653Snarayan 
20543653Snarayan 	vgen_reset_hphase(ldcp);
20553653Snarayan 
20561991Sheppo 	vgen_uninit_tbufs(ldcp);
20571991Sheppo 
20581991Sheppo 	rv = ldc_close(ldcp->ldc_handle);
20591991Sheppo 	if (rv != 0) {
20604647Sraghuram 		DWARN(vgenp, ldcp, "ldc_close err\n");
20611991Sheppo 	}
20621991Sheppo 	ldcp->ldc_status = LDC_INIT;
20631991Sheppo 	ldcp->flags &= ~(CHANNEL_STARTED);
20641991Sheppo 
20651991Sheppo 	LDC_UNLOCK(ldcp);
20661991Sheppo 
20674647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
20681991Sheppo }
20691991Sheppo 
20701991Sheppo /* Initialize the transmit buffer ring for the channel */
20711991Sheppo static int
20721991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp)
20731991Sheppo {
20741991Sheppo 	vgen_private_desc_t	*tbufp;
20751991Sheppo 	vnet_public_desc_t	*txdp;
20761991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
20771991Sheppo 	int 			i;
20781991Sheppo 	int 			rv;
20792109Slm66018 	caddr_t			datap = NULL;
20802109Slm66018 	int			ci;
20812109Slm66018 	uint32_t		ncookies;
20821991Sheppo 
20831991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
20841991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
20851991Sheppo 
20864647Sraghuram 	datap = kmem_zalloc(ldcp->num_txds * VGEN_TXDBLK_SZ, KM_SLEEP);
20872109Slm66018 	ldcp->tx_datap = datap;
20882109Slm66018 
20891991Sheppo 	/*
20902109Slm66018 	 * for each private descriptor, allocate a ldc mem_handle which is
20911991Sheppo 	 * required to map the data during transmit, set the flags
20921991Sheppo 	 * to free (available for use by transmit routine).
20931991Sheppo 	 */
20941991Sheppo 
20951991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
20962109Slm66018 
20971991Sheppo 		tbufp = &(ldcp->tbufp[i]);
20981991Sheppo 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
20994650Sraghuram 		    &(tbufp->memhandle));
21001991Sheppo 		if (rv) {
21011991Sheppo 			tbufp->memhandle = 0;
21021991Sheppo 			goto init_tbufs_failed;
21031991Sheppo 		}
21042109Slm66018 
21052109Slm66018 		/*
21062109Slm66018 		 * bind ldc memhandle to the corresponding transmit buffer.
21072109Slm66018 		 */
21082109Slm66018 		ci = ncookies = 0;
21092109Slm66018 		rv = ldc_mem_bind_handle(tbufp->memhandle,
21104647Sraghuram 		    (caddr_t)datap, VGEN_TXDBLK_SZ, LDC_SHADOW_MAP,
21112109Slm66018 		    LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
21122109Slm66018 		if (rv != 0) {
21132109Slm66018 			goto init_tbufs_failed;
21142109Slm66018 		}
21152109Slm66018 
21162109Slm66018 		/*
21172109Slm66018 		 * successful in binding the handle to tx data buffer.
21182109Slm66018 		 * set datap in the private descr to this buffer.
21192109Slm66018 		 */
21202109Slm66018 		tbufp->datap = datap;
21212109Slm66018 
21222109Slm66018 		if ((ncookies == 0) ||
21234650Sraghuram 		    (ncookies > MAX_COOKIES)) {
21242109Slm66018 			goto init_tbufs_failed;
21252109Slm66018 		}
21262109Slm66018 
21272109Slm66018 		for (ci = 1; ci < ncookies; ci++) {
21282109Slm66018 			rv = ldc_mem_nextcookie(tbufp->memhandle,
21294650Sraghuram 			    &(tbufp->memcookie[ci]));
21302109Slm66018 			if (rv != 0) {
21312109Slm66018 				goto init_tbufs_failed;
21322109Slm66018 			}
21332109Slm66018 		}
21342109Slm66018 
21352109Slm66018 		tbufp->ncookies = ncookies;
21364647Sraghuram 		datap += VGEN_TXDBLK_SZ;
21372109Slm66018 
21381991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
21391991Sheppo 		txdp = &(ldcp->txdp[i]);
21401991Sheppo 		hdrp = &txdp->hdr;
21411991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
21421991Sheppo 		hdrp->ack = B_FALSE;
21431991Sheppo 		tbufp->descp = txdp;
21442109Slm66018 
21451991Sheppo 	}
21461991Sheppo 
21471991Sheppo 	/* reset tbuf walking pointers */
21481991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
21491991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
21501991Sheppo 
21511991Sheppo 	/* initialize tx seqnum and index */
21521991Sheppo 	ldcp->next_txseq = VNET_ISS;
21531991Sheppo 	ldcp->next_txi = 0;
21541991Sheppo 
21552336Snarayan 	ldcp->resched_peer = B_TRUE;
21564647Sraghuram 	ldcp->resched_peer_txi = 0;
21572336Snarayan 
21581991Sheppo 	return (DDI_SUCCESS);
21591991Sheppo 
21601991Sheppo init_tbufs_failed:;
21611991Sheppo 	vgen_uninit_tbufs(ldcp);
21621991Sheppo 	return (DDI_FAILURE);
21631991Sheppo }
21641991Sheppo 
21651991Sheppo /* Uninitialize transmit buffer ring for the channel */
21661991Sheppo static void
21671991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp)
21681991Sheppo {
21691991Sheppo 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
21701991Sheppo 	int 			i;
21711991Sheppo 
21721991Sheppo 	/* for each tbuf (priv_desc), free ldc mem_handle */
21731991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
21741991Sheppo 
21751991Sheppo 		tbufp = &(ldcp->tbufp[i]);
21761991Sheppo 
21772109Slm66018 		if (tbufp->datap) { /* if bound to a ldc memhandle */
21781991Sheppo 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
21792109Slm66018 			tbufp->datap = NULL;
21801991Sheppo 		}
21811991Sheppo 		if (tbufp->memhandle) {
21821991Sheppo 			(void) ldc_mem_free_handle(tbufp->memhandle);
21831991Sheppo 			tbufp->memhandle = 0;
21841991Sheppo 		}
21851991Sheppo 	}
21861991Sheppo 
21872109Slm66018 	if (ldcp->tx_datap) {
21882109Slm66018 		/* prealloc'd tx data buffer */
21894647Sraghuram 		kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_TXDBLK_SZ);
21902109Slm66018 		ldcp->tx_datap = NULL;
21912109Slm66018 	}
21922109Slm66018 
21932748Slm66018 	bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds));
21942748Slm66018 	bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds));
21951991Sheppo }
21961991Sheppo 
21971991Sheppo /* clobber tx descriptor ring */
21981991Sheppo static void
21991991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp)
22001991Sheppo {
22011991Sheppo 	vnet_public_desc_t	*txdp;
22021991Sheppo 	vgen_private_desc_t	*tbufp;
22034647Sraghuram 	vio_dring_entry_hdr_t	*hdrp;
22044647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
22051991Sheppo 	int i;
22061991Sheppo #ifdef DEBUG
22071991Sheppo 	int ndone = 0;
22081991Sheppo #endif
22091991Sheppo 
22101991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
22111991Sheppo 
22121991Sheppo 		tbufp = &(ldcp->tbufp[i]);
22131991Sheppo 		txdp = tbufp->descp;
22141991Sheppo 		hdrp = &txdp->hdr;
22151991Sheppo 
22161991Sheppo 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
22171991Sheppo 			tbufp->flags = VGEN_PRIV_DESC_FREE;
22181991Sheppo #ifdef DEBUG
22191991Sheppo 			if (hdrp->dstate == VIO_DESC_DONE)
22201991Sheppo 				ndone++;
22211991Sheppo #endif
22221991Sheppo 			hdrp->dstate = VIO_DESC_FREE;
22231991Sheppo 			hdrp->ack = B_FALSE;
22241991Sheppo 		}
22251991Sheppo 	}
22261991Sheppo 	/* reset tbuf walking pointers */
22271991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
22281991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
22291991Sheppo 
22301991Sheppo 	/* reset tx seqnum and index */
22311991Sheppo 	ldcp->next_txseq = VNET_ISS;
22321991Sheppo 	ldcp->next_txi = 0;
22332336Snarayan 
22342336Snarayan 	ldcp->resched_peer = B_TRUE;
22354647Sraghuram 	ldcp->resched_peer_txi = 0;
22364647Sraghuram 
22374647Sraghuram 	DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone);
22381991Sheppo }
22391991Sheppo 
22401991Sheppo /* clobber receive descriptor ring */
22411991Sheppo static void
22421991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp)
22431991Sheppo {
22441991Sheppo 	ldcp->rx_dhandle = 0;
22451991Sheppo 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
22461991Sheppo 	ldcp->rxdp = NULL;
22471991Sheppo 	ldcp->next_rxi = 0;
22481991Sheppo 	ldcp->num_rxds = 0;
22491991Sheppo 	ldcp->next_rxseq = VNET_ISS;
22501991Sheppo }
22511991Sheppo 
22521991Sheppo /* initialize receive descriptor ring */
22531991Sheppo static int
22541991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
22551991Sheppo 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
22561991Sheppo {
22571991Sheppo 	int rv;
22581991Sheppo 	ldc_mem_info_t minfo;
22591991Sheppo 
22601991Sheppo 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
22611991Sheppo 	    desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle));
22621991Sheppo 	if (rv != 0) {
22631991Sheppo 		return (DDI_FAILURE);
22641991Sheppo 	}
22651991Sheppo 
22661991Sheppo 	/*
22671991Sheppo 	 * sucessfully mapped, now try to
22681991Sheppo 	 * get info about the mapped dring
22691991Sheppo 	 */
22701991Sheppo 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
22711991Sheppo 	if (rv != 0) {
22721991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
22731991Sheppo 		return (DDI_FAILURE);
22741991Sheppo 	}
22751991Sheppo 
22761991Sheppo 	/*
22771991Sheppo 	 * save ring address, number of descriptors.
22781991Sheppo 	 */
22791991Sheppo 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
22801991Sheppo 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
22811991Sheppo 	ldcp->num_rxdcookies = ncookies;
22821991Sheppo 	ldcp->num_rxds = num_desc;
22831991Sheppo 	ldcp->next_rxi = 0;
22841991Sheppo 	ldcp->next_rxseq = VNET_ISS;
22851991Sheppo 
22861991Sheppo 	return (DDI_SUCCESS);
22871991Sheppo }
22881991Sheppo 
22891991Sheppo /* get channel statistics */
22901991Sheppo static uint64_t
22912311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
22921991Sheppo {
22931991Sheppo 	vgen_stats_t *statsp;
22941991Sheppo 	uint64_t val;
22951991Sheppo 
22961991Sheppo 	val = 0;
22971991Sheppo 	statsp = ldcp->statsp;
22981991Sheppo 	switch (stat) {
22991991Sheppo 
23001991Sheppo 	case MAC_STAT_MULTIRCV:
23011991Sheppo 		val = statsp->multircv;
23021991Sheppo 		break;
23031991Sheppo 
23041991Sheppo 	case MAC_STAT_BRDCSTRCV:
23051991Sheppo 		val = statsp->brdcstrcv;
23061991Sheppo 		break;
23071991Sheppo 
23081991Sheppo 	case MAC_STAT_MULTIXMT:
23091991Sheppo 		val = statsp->multixmt;
23101991Sheppo 		break;
23111991Sheppo 
23121991Sheppo 	case MAC_STAT_BRDCSTXMT:
23131991Sheppo 		val = statsp->brdcstxmt;
23141991Sheppo 		break;
23151991Sheppo 
23161991Sheppo 	case MAC_STAT_NORCVBUF:
23171991Sheppo 		val = statsp->norcvbuf;
23181991Sheppo 		break;
23191991Sheppo 
23201991Sheppo 	case MAC_STAT_IERRORS:
23211991Sheppo 		val = statsp->ierrors;
23221991Sheppo 		break;
23231991Sheppo 
23241991Sheppo 	case MAC_STAT_NOXMTBUF:
23251991Sheppo 		val = statsp->noxmtbuf;
23261991Sheppo 		break;
23271991Sheppo 
23281991Sheppo 	case MAC_STAT_OERRORS:
23291991Sheppo 		val = statsp->oerrors;
23301991Sheppo 		break;
23311991Sheppo 
23321991Sheppo 	case MAC_STAT_COLLISIONS:
23331991Sheppo 		break;
23341991Sheppo 
23351991Sheppo 	case MAC_STAT_RBYTES:
23361991Sheppo 		val = statsp->rbytes;
23371991Sheppo 		break;
23381991Sheppo 
23391991Sheppo 	case MAC_STAT_IPACKETS:
23401991Sheppo 		val = statsp->ipackets;
23411991Sheppo 		break;
23421991Sheppo 
23431991Sheppo 	case MAC_STAT_OBYTES:
23441991Sheppo 		val = statsp->obytes;
23451991Sheppo 		break;
23461991Sheppo 
23471991Sheppo 	case MAC_STAT_OPACKETS:
23481991Sheppo 		val = statsp->opackets;
23491991Sheppo 		break;
23501991Sheppo 
23511991Sheppo 	/* stats not relevant to ldc, return 0 */
23521991Sheppo 	case MAC_STAT_IFSPEED:
23532311Sseb 	case ETHER_STAT_ALIGN_ERRORS:
23542311Sseb 	case ETHER_STAT_FCS_ERRORS:
23552311Sseb 	case ETHER_STAT_FIRST_COLLISIONS:
23562311Sseb 	case ETHER_STAT_MULTI_COLLISIONS:
23572311Sseb 	case ETHER_STAT_DEFER_XMTS:
23582311Sseb 	case ETHER_STAT_TX_LATE_COLLISIONS:
23592311Sseb 	case ETHER_STAT_EX_COLLISIONS:
23602311Sseb 	case ETHER_STAT_MACXMT_ERRORS:
23612311Sseb 	case ETHER_STAT_CARRIER_ERRORS:
23622311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
23632311Sseb 	case ETHER_STAT_XCVR_ADDR:
23642311Sseb 	case ETHER_STAT_XCVR_ID:
23652311Sseb 	case ETHER_STAT_XCVR_INUSE:
23662311Sseb 	case ETHER_STAT_CAP_1000FDX:
23672311Sseb 	case ETHER_STAT_CAP_1000HDX:
23682311Sseb 	case ETHER_STAT_CAP_100FDX:
23692311Sseb 	case ETHER_STAT_CAP_100HDX:
23702311Sseb 	case ETHER_STAT_CAP_10FDX:
23712311Sseb 	case ETHER_STAT_CAP_10HDX:
23722311Sseb 	case ETHER_STAT_CAP_ASMPAUSE:
23732311Sseb 	case ETHER_STAT_CAP_PAUSE:
23742311Sseb 	case ETHER_STAT_CAP_AUTONEG:
23752311Sseb 	case ETHER_STAT_ADV_CAP_1000FDX:
23762311Sseb 	case ETHER_STAT_ADV_CAP_1000HDX:
23772311Sseb 	case ETHER_STAT_ADV_CAP_100FDX:
23782311Sseb 	case ETHER_STAT_ADV_CAP_100HDX:
23792311Sseb 	case ETHER_STAT_ADV_CAP_10FDX:
23802311Sseb 	case ETHER_STAT_ADV_CAP_10HDX:
23812311Sseb 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
23822311Sseb 	case ETHER_STAT_ADV_CAP_PAUSE:
23832311Sseb 	case ETHER_STAT_ADV_CAP_AUTONEG:
23842311Sseb 	case ETHER_STAT_LP_CAP_1000FDX:
23852311Sseb 	case ETHER_STAT_LP_CAP_1000HDX:
23862311Sseb 	case ETHER_STAT_LP_CAP_100FDX:
23872311Sseb 	case ETHER_STAT_LP_CAP_100HDX:
23882311Sseb 	case ETHER_STAT_LP_CAP_10FDX:
23892311Sseb 	case ETHER_STAT_LP_CAP_10HDX:
23902311Sseb 	case ETHER_STAT_LP_CAP_ASMPAUSE:
23912311Sseb 	case ETHER_STAT_LP_CAP_PAUSE:
23922311Sseb 	case ETHER_STAT_LP_CAP_AUTONEG:
23932311Sseb 	case ETHER_STAT_LINK_ASMPAUSE:
23942311Sseb 	case ETHER_STAT_LINK_PAUSE:
23952311Sseb 	case ETHER_STAT_LINK_AUTONEG:
23962311Sseb 	case ETHER_STAT_LINK_DUPLEX:
23971991Sheppo 	default:
23981991Sheppo 		val = 0;
23991991Sheppo 		break;
24001991Sheppo 
24011991Sheppo 	}
24021991Sheppo 	return (val);
24031991Sheppo }
24041991Sheppo 
24052793Slm66018 /*
24062793Slm66018  * LDC channel is UP, start handshake process with peer.
24072793Slm66018  * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
24082793Slm66018  * function is being called from transmit routine, otherwise B_FALSE.
24092793Slm66018  */
24102793Slm66018 static void
24112793Slm66018 vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag)
24122793Slm66018 {
24132793Slm66018 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
24144647Sraghuram 
24154647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
24162793Slm66018 
24172793Slm66018 	ASSERT(MUTEX_HELD(&ldcp->cblock));
24182793Slm66018 
24192793Slm66018 	if (ldcp->portp != vgenp->vsw_portp) {
24202793Slm66018 		/*
24212793Slm66018 		 * modify fdb entry to use this port as the
24222793Slm66018 		 * channel is up, instead of going through the
24232793Slm66018 		 * vsw-port (see comments in vgen_port_init())
24242793Slm66018 		 */
24254647Sraghuram 		vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr,
24262793Slm66018 		    vgen_tx, ldcp->portp, flag);
24272793Slm66018 	}
24282793Slm66018 
24292793Slm66018 	/* Initialize local session id */
24302793Slm66018 	ldcp->local_sid = ddi_get_lbolt();
24312793Slm66018 
24322793Slm66018 	/* clear peer session id */
24332793Slm66018 	ldcp->peer_sid = 0;
24342793Slm66018 	ldcp->hretries = 0;
24352793Slm66018 
24362793Slm66018 	if (ldcp->hphase != VH_PHASE0) {
24372793Slm66018 		vgen_handshake_reset(ldcp);
24382793Slm66018 	}
24392793Slm66018 
24402793Slm66018 	/* Initiate Handshake process with peer ldc endpoint */
24412793Slm66018 	vgen_handshake(vh_nextphase(ldcp));
24422793Slm66018 
24434647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
24442793Slm66018 }
24452793Slm66018 
24462793Slm66018 /*
24472793Slm66018  * LDC channel is Reset, terminate connection with peer and try to
24482793Slm66018  * bring the channel up again.
24492793Slm66018  * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
24502793Slm66018  * function is being called from transmit routine, otherwise B_FALSE.
24512793Slm66018  */
24522793Slm66018 static void
24532793Slm66018 vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag)
24542793Slm66018 {
24552793Slm66018 	ldc_status_t istatus;
24562793Slm66018 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
24572793Slm66018 	int	rv;
24582793Slm66018 
24594647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
24602793Slm66018 
24612793Slm66018 	ASSERT(MUTEX_HELD(&ldcp->cblock));
24622793Slm66018 
24632793Slm66018 	if ((ldcp->portp != vgenp->vsw_portp) &&
24644650Sraghuram 	    (vgenp->vsw_portp != NULL)) {
24652793Slm66018 		/*
24662793Slm66018 		 * modify fdb entry to use vsw-port  as the
24672793Slm66018 		 * channel is reset and we don't have a direct
24682793Slm66018 		 * link to the destination (see comments
24692793Slm66018 		 * in vgen_port_init()).
24702793Slm66018 		 */
24714647Sraghuram 		vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr,
24722793Slm66018 		    vgen_tx, vgenp->vsw_portp, flag);
24732793Slm66018 	}
24742793Slm66018 
24752793Slm66018 	if (ldcp->hphase != VH_PHASE0) {
24762793Slm66018 		vgen_handshake_reset(ldcp);
24772793Slm66018 	}
24782793Slm66018 
24792793Slm66018 	/* try to bring the channel up */
24802793Slm66018 	rv = ldc_up(ldcp->ldc_handle);
24812793Slm66018 	if (rv != 0) {
24824647Sraghuram 		DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
24832793Slm66018 	}
24842793Slm66018 
24852793Slm66018 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
24864647Sraghuram 		DWARN(vgenp, ldcp, "ldc_status err\n");
24872793Slm66018 	} else {
24882793Slm66018 		ldcp->ldc_status = istatus;
24892793Slm66018 	}
24902793Slm66018 
24912793Slm66018 	/* if channel is already UP - restart handshake */
24922793Slm66018 	if (ldcp->ldc_status == LDC_UP) {
24932793Slm66018 		vgen_handle_evt_up(ldcp, flag);
24942793Slm66018 	}
24952793Slm66018 
24964647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
24972793Slm66018 }
24982793Slm66018 
24991991Sheppo /* Interrupt handler for the channel */
25001991Sheppo static uint_t
25011991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
25021991Sheppo {
25031991Sheppo 	_NOTE(ARGUNUSED(event))
25041991Sheppo 	vgen_ldc_t	*ldcp;
25051991Sheppo 	vgen_t		*vgenp;
25061991Sheppo 	ldc_status_t 	istatus;
25071991Sheppo 	mblk_t		*bp = NULL;
25081991Sheppo 	vgen_stats_t	*statsp;
25091991Sheppo 
25101991Sheppo 	ldcp = (vgen_ldc_t *)arg;
25111991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
25121991Sheppo 	statsp = ldcp->statsp;
25131991Sheppo 
25144647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
25151991Sheppo 
25161991Sheppo 	mutex_enter(&ldcp->cblock);
25171991Sheppo 	statsp->callbacks++;
25181991Sheppo 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
25194647Sraghuram 		DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n",
25204647Sraghuram 		    ldcp->ldc_status);
25211991Sheppo 		mutex_exit(&ldcp->cblock);
25221991Sheppo 		return (LDC_SUCCESS);
25231991Sheppo 	}
25241991Sheppo 
25252793Slm66018 	/*
25262793Slm66018 	 * NOTE: not using switch() as event could be triggered by
25272793Slm66018 	 * a state change and a read request. Also the ordering	of the
25282793Slm66018 	 * check for the event types is deliberate.
25292793Slm66018 	 */
25302793Slm66018 	if (event & LDC_EVT_UP) {
25312793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
25324647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status err\n");
25332793Slm66018 		} else {
25341991Sheppo 			ldcp->ldc_status = istatus;
25352793Slm66018 		}
25362793Slm66018 		ASSERT(ldcp->ldc_status == LDC_UP);
25374647Sraghuram 		DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n",
25384647Sraghuram 		    event, ldcp->ldc_status);
25392793Slm66018 
25402793Slm66018 		vgen_handle_evt_up(ldcp, B_FALSE);
25412793Slm66018 
25422793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
25432793Slm66018 	}
25442793Slm66018 
25452793Slm66018 	if (event & LDC_EVT_READ) {
25464647Sraghuram 		DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n",
25474647Sraghuram 		    event, ldcp->ldc_status);
25482793Slm66018 
25492793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
25504647Sraghuram 
25514647Sraghuram 		if (ldcp->rcv_thread != NULL) {
25524647Sraghuram 			/*
25534647Sraghuram 			 * If the receive thread is enabled, then
25544647Sraghuram 			 * wakeup the receive thread to process the
25554647Sraghuram 			 * LDC messages.
25564647Sraghuram 			 */
25574647Sraghuram 			mutex_exit(&ldcp->cblock);
25584647Sraghuram 			mutex_enter(&ldcp->rcv_thr_lock);
25594647Sraghuram 			if (!(ldcp->rcv_thr_flags & VGEN_WTHR_DATARCVD)) {
25604647Sraghuram 				ldcp->rcv_thr_flags |= VGEN_WTHR_DATARCVD;
25614647Sraghuram 				cv_signal(&ldcp->rcv_thr_cv);
25624647Sraghuram 			}
25634647Sraghuram 			mutex_exit(&ldcp->rcv_thr_lock);
25644647Sraghuram 			mutex_enter(&ldcp->cblock);
25654647Sraghuram 		} else  {
25664647Sraghuram 			vgen_handle_evt_read(ldcp);
25674647Sraghuram 			bp = ldcp->rcv_mhead;
25684647Sraghuram 			ldcp->rcv_mhead = ldcp->rcv_mtail = NULL;
25694647Sraghuram 		}
25702793Slm66018 	}
25712793Slm66018 
25722793Slm66018 	if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
25732793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
25744647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status error\n");
25752793Slm66018 		} else {
25762793Slm66018 			ldcp->ldc_status = istatus;
25771991Sheppo 		}
25784647Sraghuram 		DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
25794647Sraghuram 		    event, ldcp->ldc_status);
25802793Slm66018 
25812793Slm66018 		vgen_handle_evt_reset(ldcp, B_FALSE);
25821991Sheppo 	}
25832793Slm66018 	mutex_exit(&ldcp->cblock);
25844647Sraghuram 
25854647Sraghuram 	/* send up the received packets to MAC layer */
25864647Sraghuram 	if (bp != NULL) {
25874647Sraghuram 		vnet_rx(vgenp->vnetp, NULL, bp);
25884647Sraghuram 	}
25894647Sraghuram 
25904647Sraghuram 	if (ldcp->cancel_htid) {
25914647Sraghuram 		/*
25924647Sraghuram 		 * Cancel handshake timer.
25934647Sraghuram 		 * untimeout(9F) will not return until the pending callback is
25944647Sraghuram 		 * cancelled or has run. No problems will result from calling
25954647Sraghuram 		 * untimeout if the handler has already completed.
25964647Sraghuram 		 * If the timeout handler did run, then it would just
25974647Sraghuram 		 * return as cancel_htid is set.
25984647Sraghuram 		 */
25994647Sraghuram 		(void) untimeout(ldcp->cancel_htid);
26004647Sraghuram 		ldcp->cancel_htid = 0;
26014647Sraghuram 	}
26024647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
26034647Sraghuram 
26044647Sraghuram 	return (LDC_SUCCESS);
26054647Sraghuram }
26064647Sraghuram 
26074647Sraghuram static void
26084647Sraghuram vgen_handle_evt_read(vgen_ldc_t *ldcp)
26094647Sraghuram {
26104647Sraghuram 	int		rv;
26114647Sraghuram 	uint64_t	ldcmsg[7];
26124647Sraghuram 	size_t		msglen;
26134647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
26144647Sraghuram 	vio_msg_tag_t	*tagp;
26154647Sraghuram 	ldc_status_t 	istatus;
26164647Sraghuram 	boolean_t 	has_data;
26174647Sraghuram 
26184647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
26194647Sraghuram 
26204647Sraghuram 	/*
26214647Sraghuram 	 * If the receive thread is enabled, then the cblock
26224647Sraghuram 	 * need to be acquired here. If not, the vgen_ldc_cb()
26234647Sraghuram 	 * calls this function with cblock held already.
26244647Sraghuram 	 */
26254647Sraghuram 	if (ldcp->rcv_thread != NULL) {
26264647Sraghuram 		mutex_enter(&ldcp->cblock);
26274647Sraghuram 	} else {
26284647Sraghuram 		ASSERT(MUTEX_HELD(&ldcp->cblock));
26294647Sraghuram 	}
26304647Sraghuram 
26314647Sraghuram vgen_evt_read:
26321991Sheppo 	do {
26331991Sheppo 		msglen = sizeof (ldcmsg);
26341991Sheppo 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
26351991Sheppo 
26361991Sheppo 		if (rv != 0) {
26374647Sraghuram 			DWARN(vgenp, ldcp, "err rv(%d) len(%d)\n",
26384647Sraghuram 			    rv, msglen);
26392793Slm66018 			if (rv == ECONNRESET)
26404647Sraghuram 				goto vgen_evtread_error;
26411991Sheppo 			break;
26421991Sheppo 		}
26431991Sheppo 		if (msglen == 0) {
26444647Sraghuram 			DBG2(vgenp, ldcp, "ldc_read NODATA");
26451991Sheppo 			break;
26461991Sheppo 		}
26474647Sraghuram 		DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen);
26481991Sheppo 
26491991Sheppo 		tagp = (vio_msg_tag_t *)ldcmsg;
26501991Sheppo 
26511991Sheppo 		if (ldcp->peer_sid) {
26521991Sheppo 			/*
26531991Sheppo 			 * check sid only after we have received peer's sid
26541991Sheppo 			 * in the version negotiate msg.
26551991Sheppo 			 */
26561991Sheppo #ifdef DEBUG
26571991Sheppo 			if (vgen_hdbg & HDBG_BAD_SID) {
26581991Sheppo 				/* simulate bad sid condition */
26591991Sheppo 				tagp->vio_sid = 0;
26601991Sheppo 				vgen_hdbg &= ~(HDBG_BAD_SID);
26611991Sheppo 			}
26621991Sheppo #endif
26632793Slm66018 			rv = vgen_check_sid(ldcp, tagp);
26642793Slm66018 			if (rv != VGEN_SUCCESS) {
26651991Sheppo 				/*
26661991Sheppo 				 * If sid mismatch is detected,
26671991Sheppo 				 * reset the channel.
26681991Sheppo 				 */
26691991Sheppo 				ldcp->need_ldc_reset = B_TRUE;
26704647Sraghuram 				goto vgen_evtread_error;
26711991Sheppo 			}
26721991Sheppo 		}
26731991Sheppo 
26741991Sheppo 		switch (tagp->vio_msgtype) {
26751991Sheppo 		case VIO_TYPE_CTRL:
26762793Slm66018 			rv = vgen_handle_ctrlmsg(ldcp, tagp);
26771991Sheppo 			break;
26781991Sheppo 
26791991Sheppo 		case VIO_TYPE_DATA:
26804647Sraghuram 			rv = vgen_handle_datamsg(ldcp, tagp);
26811991Sheppo 			break;
26821991Sheppo 
26831991Sheppo 		case VIO_TYPE_ERR:
26841991Sheppo 			vgen_handle_errmsg(ldcp, tagp);
26851991Sheppo 			break;
26861991Sheppo 
26871991Sheppo 		default:
26884647Sraghuram 			DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n",
26894647Sraghuram 			    tagp->vio_msgtype);
26901991Sheppo 			break;
26911991Sheppo 		}
26921991Sheppo 
26934647Sraghuram 		/*
26944647Sraghuram 		 * If an error is encountered, stop processing and
26954647Sraghuram 		 * handle the error.
26964647Sraghuram 		 */
26974647Sraghuram 		if (rv != 0) {
26984647Sraghuram 			goto vgen_evtread_error;
26992793Slm66018 		}
27002793Slm66018 
27011991Sheppo 	} while (msglen);
27021991Sheppo 
27034647Sraghuram 	/* check once more before exiting */
27044647Sraghuram 	rv = ldc_chkq(ldcp->ldc_handle, &has_data);
27054647Sraghuram 	if ((rv == 0) && (has_data == B_TRUE)) {
27064647Sraghuram 		DTRACE_PROBE(vgen_chkq);
27074647Sraghuram 		goto vgen_evt_read;
27084647Sraghuram 	}
27094647Sraghuram 
27104647Sraghuram vgen_evtread_error:
27114647Sraghuram 	if (rv == ECONNRESET) {
27124647Sraghuram 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
27134647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status err\n");
27144647Sraghuram 		} else {
27154647Sraghuram 			ldcp->ldc_status = istatus;
27164647Sraghuram 		}
27174647Sraghuram 		vgen_handle_evt_reset(ldcp, B_FALSE);
27184647Sraghuram 	} else if (rv) {
27194647Sraghuram 		vgen_handshake_retry(ldcp);
27204647Sraghuram 	}
27214647Sraghuram 
27224647Sraghuram 	/*
27234647Sraghuram 	 * If the receive thread is not enabled, then cancel the
27244647Sraghuram 	 * handshake timeout here.
27254647Sraghuram 	 */
27264647Sraghuram 	if (ldcp->rcv_thread != NULL) {
27274647Sraghuram 		mutex_exit(&ldcp->cblock);
27284647Sraghuram 		if (ldcp->cancel_htid) {
27294647Sraghuram 			/*
27304647Sraghuram 			 * Cancel handshake timer. untimeout(9F) will
27314647Sraghuram 			 * not return until the pending callback is cancelled
27324647Sraghuram 			 * or has run. No problems will result from calling
27334647Sraghuram 			 * untimeout if the handler has already completed.
27344647Sraghuram 			 * If the timeout handler did run, then it would just
27354647Sraghuram 			 * return as cancel_htid is set.
27364647Sraghuram 			 */
27374647Sraghuram 			(void) untimeout(ldcp->cancel_htid);
27384647Sraghuram 			ldcp->cancel_htid = 0;
27394647Sraghuram 		}
27404647Sraghuram 	}
27414647Sraghuram 
27424647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
27431991Sheppo }
27441991Sheppo 
27451991Sheppo /* vgen handshake functions */
27461991Sheppo 
27471991Sheppo /* change the hphase for the channel to the next phase */
27481991Sheppo static vgen_ldc_t *
27491991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
27501991Sheppo {
27511991Sheppo 	if (ldcp->hphase == VH_PHASE3) {
27521991Sheppo 		ldcp->hphase = VH_DONE;
27531991Sheppo 	} else {
27541991Sheppo 		ldcp->hphase++;
27551991Sheppo 	}
27561991Sheppo 	return (ldcp);
27571991Sheppo }
27581991Sheppo 
27591991Sheppo /*
27601991Sheppo  * Check whether the given version is supported or not and
27611991Sheppo  * return VGEN_SUCCESS if supported.
27621991Sheppo  */
27631991Sheppo static int
27641991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
27651991Sheppo uint16_t ver_minor)
27661991Sheppo {
27671991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
27681991Sheppo 	int		i = 0;
27691991Sheppo 
27701991Sheppo 	while (i < VGEN_NUM_VER) {
27711991Sheppo 		if ((versions[i].ver_major == 0) &&
27721991Sheppo 		    (versions[i].ver_minor == 0)) {
27731991Sheppo 			break;
27741991Sheppo 		}
27751991Sheppo 		if ((versions[i].ver_major == ver_major) &&
27764650Sraghuram 		    (versions[i].ver_minor == ver_minor)) {
27771991Sheppo 			return (VGEN_SUCCESS);
27781991Sheppo 		}
27791991Sheppo 		i++;
27801991Sheppo 	}
27811991Sheppo 	return (VGEN_FAILURE);
27821991Sheppo }
27831991Sheppo 
27841991Sheppo /*
27851991Sheppo  * Given a version, return VGEN_SUCCESS if a lower version is supported.
27861991Sheppo  */
27871991Sheppo static int
27881991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp)
27891991Sheppo {
27901991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
27911991Sheppo 	int		i = 0;
27921991Sheppo 
27931991Sheppo 	while (i < VGEN_NUM_VER) {
27941991Sheppo 		if ((versions[i].ver_major == 0) &&
27951991Sheppo 		    (versions[i].ver_minor == 0)) {
27961991Sheppo 			break;
27971991Sheppo 		}
27981991Sheppo 		/*
27991991Sheppo 		 * if we support a lower minor version within the same major
28001991Sheppo 		 * version, or if we support a lower major version,
28011991Sheppo 		 * update the verp parameter with this lower version and
28021991Sheppo 		 * return success.
28031991Sheppo 		 */
28041991Sheppo 		if (((versions[i].ver_major == verp->ver_major) &&
28054650Sraghuram 		    (versions[i].ver_minor < verp->ver_minor)) ||
28064650Sraghuram 		    (versions[i].ver_major < verp->ver_major)) {
28074650Sraghuram 			verp->ver_major = versions[i].ver_major;
28084650Sraghuram 			verp->ver_minor = versions[i].ver_minor;
28094650Sraghuram 			return (VGEN_SUCCESS);
28101991Sheppo 		}
28111991Sheppo 		i++;
28121991Sheppo 	}
28131991Sheppo 
28141991Sheppo 	return (VGEN_FAILURE);
28151991Sheppo }
28161991Sheppo 
28171991Sheppo /*
28181991Sheppo  * wrapper routine to send the given message over ldc using ldc_write().
28191991Sheppo  */
28201991Sheppo static int
28211991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
28221991Sheppo     boolean_t caller_holds_lock)
28231991Sheppo {
28241991Sheppo 	int	rv;
28251991Sheppo 	size_t	len;
28261991Sheppo 	uint32_t retries = 0;
28274647Sraghuram 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
28281991Sheppo 
28291991Sheppo 	len = msglen;
28301991Sheppo 	if ((len == 0) || (msg == NULL))
28311991Sheppo 		return (VGEN_FAILURE);
28321991Sheppo 
28331991Sheppo 	if (!caller_holds_lock) {
28344647Sraghuram 		mutex_enter(&ldcp->wrlock);
28351991Sheppo 	}
28361991Sheppo 
28371991Sheppo 	do {
28381991Sheppo 		len = msglen;
28391991Sheppo 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
28401991Sheppo 		if (retries++ >= vgen_ldcwr_retries)
28411991Sheppo 			break;
28421991Sheppo 	} while (rv == EWOULDBLOCK);
28431991Sheppo 
28441991Sheppo 	if (!caller_holds_lock) {
28454647Sraghuram 		mutex_exit(&ldcp->wrlock);
28461991Sheppo 	}
28471991Sheppo 
28482793Slm66018 	if (rv != 0) {
28494647Sraghuram 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d)\n",
28504647Sraghuram 		    rv, msglen);
28512793Slm66018 		return (rv);
28522793Slm66018 	}
28532793Slm66018 
28542793Slm66018 	if (len != msglen) {
28554647Sraghuram 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n",
28564647Sraghuram 		    rv, msglen);
28571991Sheppo 		return (VGEN_FAILURE);
28581991Sheppo 	}
28592793Slm66018 
28601991Sheppo 	return (VGEN_SUCCESS);
28611991Sheppo }
28621991Sheppo 
28631991Sheppo /* send version negotiate message to the peer over ldc */
28641991Sheppo static int
28651991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
28661991Sheppo {
28674647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
28681991Sheppo 	vio_ver_msg_t	vermsg;
28691991Sheppo 	vio_msg_tag_t	*tagp = &vermsg.tag;
28701991Sheppo 	int		rv;
28711991Sheppo 
28721991Sheppo 	bzero(&vermsg, sizeof (vermsg));
28731991Sheppo 
28741991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
28751991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
28761991Sheppo 	tagp->vio_subtype_env = VIO_VER_INFO;
28771991Sheppo 	tagp->vio_sid = ldcp->local_sid;
28781991Sheppo 
28791991Sheppo 	/* get version msg payload from ldcp->local */
28801991Sheppo 	vermsg.ver_major = ldcp->local_hparams.ver_major;
28811991Sheppo 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
28821991Sheppo 	vermsg.dev_class = ldcp->local_hparams.dev_class;
28831991Sheppo 
28841991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
28851991Sheppo 	if (rv != VGEN_SUCCESS) {
28864647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
28872793Slm66018 		return (rv);
28881991Sheppo 	}
28891991Sheppo 
28901991Sheppo 	ldcp->hstate |= VER_INFO_SENT;
28914647Sraghuram 	DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n",
28924647Sraghuram 	    vermsg.ver_major, vermsg.ver_minor);
28931991Sheppo 
28941991Sheppo 	return (VGEN_SUCCESS);
28951991Sheppo }
28961991Sheppo 
28971991Sheppo /* send attr info message to the peer over ldc */
28981991Sheppo static int
28991991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
29001991Sheppo {
29014647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
29021991Sheppo 	vnet_attr_msg_t	attrmsg;
29031991Sheppo 	vio_msg_tag_t	*tagp = &attrmsg.tag;
29041991Sheppo 	int		rv;
29051991Sheppo 
29061991Sheppo 	bzero(&attrmsg, sizeof (attrmsg));
29071991Sheppo 
29081991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
29091991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
29101991Sheppo 	tagp->vio_subtype_env = VIO_ATTR_INFO;
29111991Sheppo 	tagp->vio_sid = ldcp->local_sid;
29121991Sheppo 
29131991Sheppo 	/* get attr msg payload from ldcp->local */
29141991Sheppo 	attrmsg.mtu = ldcp->local_hparams.mtu;
29151991Sheppo 	attrmsg.addr = ldcp->local_hparams.addr;
29161991Sheppo 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
29171991Sheppo 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
29181991Sheppo 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
29191991Sheppo 
29201991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
29211991Sheppo 	if (rv != VGEN_SUCCESS) {
29224647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
29232793Slm66018 		return (rv);
29241991Sheppo 	}
29251991Sheppo 
29261991Sheppo 	ldcp->hstate |= ATTR_INFO_SENT;
29274647Sraghuram 	DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n");
29281991Sheppo 
29291991Sheppo 	return (VGEN_SUCCESS);
29301991Sheppo }
29311991Sheppo 
29321991Sheppo /* send descriptor ring register message to the peer over ldc */
29331991Sheppo static int
29341991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp)
29351991Sheppo {
29364647Sraghuram 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
29371991Sheppo 	vio_dring_reg_msg_t	msg;
29381991Sheppo 	vio_msg_tag_t		*tagp = &msg.tag;
29391991Sheppo 	int		rv;
29401991Sheppo 
29411991Sheppo 	bzero(&msg, sizeof (msg));
29421991Sheppo 
29431991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
29441991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
29451991Sheppo 	tagp->vio_subtype_env = VIO_DRING_REG;
29461991Sheppo 	tagp->vio_sid = ldcp->local_sid;
29471991Sheppo 
29481991Sheppo 	/* get dring info msg payload from ldcp->local */
29491991Sheppo 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
29504650Sraghuram 	    sizeof (ldc_mem_cookie_t));
29511991Sheppo 	msg.ncookies = ldcp->local_hparams.num_dcookies;
29521991Sheppo 	msg.num_descriptors = ldcp->local_hparams.num_desc;
29531991Sheppo 	msg.descriptor_size = ldcp->local_hparams.desc_size;
29541991Sheppo 
29551991Sheppo 	/*
29561991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
29571991Sheppo 	 * value and sends it in the ack, which is saved in
29581991Sheppo 	 * vgen_handle_dring_reg().
29591991Sheppo 	 */
29601991Sheppo 	msg.dring_ident = 0;
29611991Sheppo 
29621991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
29631991Sheppo 	if (rv != VGEN_SUCCESS) {
29644647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
29652793Slm66018 		return (rv);
29661991Sheppo 	}
29671991Sheppo 
29681991Sheppo 	ldcp->hstate |= DRING_INFO_SENT;
29694647Sraghuram 	DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
29701991Sheppo 
29711991Sheppo 	return (VGEN_SUCCESS);
29721991Sheppo }
29731991Sheppo 
29741991Sheppo static int
29751991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
29761991Sheppo {
29774647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
29781991Sheppo 	vio_rdx_msg_t	rdxmsg;
29791991Sheppo 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
29801991Sheppo 	int		rv;
29811991Sheppo 
29821991Sheppo 	bzero(&rdxmsg, sizeof (rdxmsg));
29831991Sheppo 
29841991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
29851991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
29861991Sheppo 	tagp->vio_subtype_env = VIO_RDX;
29871991Sheppo 	tagp->vio_sid = ldcp->local_sid;
29881991Sheppo 
29891991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
29901991Sheppo 	if (rv != VGEN_SUCCESS) {
29914647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
29922793Slm66018 		return (rv);
29931991Sheppo 	}
29941991Sheppo 
29951991Sheppo 	ldcp->hstate |= RDX_INFO_SENT;
29964647Sraghuram 	DBG2(vgenp, ldcp, "RDX_INFO_SENT\n");
29971991Sheppo 
29981991Sheppo 	return (VGEN_SUCCESS);
29991991Sheppo }
30001991Sheppo 
30011991Sheppo /* send descriptor ring data message to the peer over ldc */
30021991Sheppo static int
30032336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
30041991Sheppo {
30054647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
30061991Sheppo 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
30071991Sheppo 	vio_msg_tag_t	*tagp = &msgp->tag;
30081991Sheppo 	int		rv;
30091991Sheppo 
30101991Sheppo 	bzero(msgp, sizeof (*msgp));
30111991Sheppo 
30121991Sheppo 	tagp->vio_msgtype = VIO_TYPE_DATA;
30131991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
30141991Sheppo 	tagp->vio_subtype_env = VIO_DRING_DATA;
30151991Sheppo 	tagp->vio_sid = ldcp->local_sid;
30161991Sheppo 
30172336Snarayan 	msgp->seq_num = ldcp->next_txseq;
30181991Sheppo 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
30191991Sheppo 	msgp->start_idx = start;
30201991Sheppo 	msgp->end_idx = end;
30211991Sheppo 
30221991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
30231991Sheppo 	if (rv != VGEN_SUCCESS) {
30244647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
30252793Slm66018 		return (rv);
30261991Sheppo 	}
30271991Sheppo 
30282336Snarayan 	ldcp->next_txseq++;
30292336Snarayan 	ldcp->statsp->dring_data_msgs++;
30302336Snarayan 
30314647Sraghuram 	DBG2(vgenp, ldcp, "DRING_DATA_SENT \n");
30321991Sheppo 
30331991Sheppo 	return (VGEN_SUCCESS);
30341991Sheppo }
30351991Sheppo 
30361991Sheppo /* send multicast addr info message to vsw */
30371991Sheppo static int
30381991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
30391991Sheppo {
30401991Sheppo 	vnet_mcast_msg_t	mcastmsg;
30411991Sheppo 	vnet_mcast_msg_t	*msgp;
30421991Sheppo 	vio_msg_tag_t		*tagp;
30431991Sheppo 	vgen_t			*vgenp;
30441991Sheppo 	struct ether_addr	*mca;
30451991Sheppo 	int			rv;
30461991Sheppo 	int			i;
30471991Sheppo 	uint32_t		size;
30481991Sheppo 	uint32_t		mccount;
30491991Sheppo 	uint32_t		n;
30501991Sheppo 
30511991Sheppo 	msgp = &mcastmsg;
30521991Sheppo 	tagp = &msgp->tag;
30531991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
30541991Sheppo 
30551991Sheppo 	mccount = vgenp->mccount;
30561991Sheppo 	i = 0;
30571991Sheppo 
30581991Sheppo 	do {
30591991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
30601991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
30611991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
30621991Sheppo 		tagp->vio_sid = ldcp->local_sid;
30631991Sheppo 
30641991Sheppo 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
30651991Sheppo 		size = n * sizeof (struct ether_addr);
30661991Sheppo 
30671991Sheppo 		mca = &(vgenp->mctab[i]);
30681991Sheppo 		bcopy(mca, (msgp->mca), size);
30691991Sheppo 		msgp->set = B_TRUE;
30701991Sheppo 		msgp->count = n;
30711991Sheppo 
30721991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
30731991Sheppo 		    B_FALSE);
30741991Sheppo 		if (rv != VGEN_SUCCESS) {
30754647Sraghuram 			DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv);
30762793Slm66018 			return (rv);
30771991Sheppo 		}
30781991Sheppo 
30791991Sheppo 		mccount -= n;
30801991Sheppo 		i += n;
30811991Sheppo 
30821991Sheppo 	} while (mccount);
30831991Sheppo 
30841991Sheppo 	return (VGEN_SUCCESS);
30851991Sheppo }
30861991Sheppo 
30871991Sheppo /* Initiate Phase 2 of handshake */
30881991Sheppo static int
30891991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
30901991Sheppo {
30911991Sheppo 	int rv;
30922793Slm66018 	uint32_t ncookies = 0;
30934647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
30944647Sraghuram 
30951991Sheppo #ifdef DEBUG
30961991Sheppo 	if (vgen_hdbg & HDBG_OUT_STATE) {
30971991Sheppo 		/* simulate out of state condition */
30981991Sheppo 		vgen_hdbg &= ~(HDBG_OUT_STATE);
30991991Sheppo 		rv = vgen_send_rdx_info(ldcp);
31001991Sheppo 		return (rv);
31011991Sheppo 	}
31021991Sheppo 	if (vgen_hdbg & HDBG_TIMEOUT) {
31031991Sheppo 		/* simulate timeout condition */
31041991Sheppo 		vgen_hdbg &= ~(HDBG_TIMEOUT);
31051991Sheppo 		return (VGEN_SUCCESS);
31061991Sheppo 	}
31071991Sheppo #endif
31082793Slm66018 	rv = vgen_send_attr_info(ldcp);
31092793Slm66018 	if (rv != VGEN_SUCCESS) {
31101991Sheppo 		return (rv);
31111991Sheppo 	}
31122793Slm66018 
31132793Slm66018 	/* Bind descriptor ring to the channel */
31142793Slm66018 	if (ldcp->num_txdcookies == 0) {
31152793Slm66018 		rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
31162793Slm66018 		    LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
31172793Slm66018 		if (rv != 0) {
31184647Sraghuram 			DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed "
31194650Sraghuram 			    "rv(%x)\n", rv);
31202793Slm66018 			return (rv);
31212793Slm66018 		}
31222793Slm66018 		ASSERT(ncookies == 1);
31232793Slm66018 		ldcp->num_txdcookies = ncookies;
31242793Slm66018 	}
31252793Slm66018 
31262793Slm66018 	/* update local dring_info params */
31272793Slm66018 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
31284650Sraghuram 	    sizeof (ldc_mem_cookie_t));
31292793Slm66018 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
31302793Slm66018 	ldcp->local_hparams.num_desc = ldcp->num_txds;
31312793Slm66018 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
31322793Slm66018 
31332793Slm66018 	rv = vgen_send_dring_reg(ldcp);
31342793Slm66018 	if (rv != VGEN_SUCCESS) {
31351991Sheppo 		return (rv);
31361991Sheppo 	}
31371991Sheppo 
31381991Sheppo 	return (VGEN_SUCCESS);
31391991Sheppo }
31401991Sheppo 
31411991Sheppo /*
31421991Sheppo  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
31431991Sheppo  * This can happen after a channel comes up (status: LDC_UP) or
31441991Sheppo  * when handshake gets terminated due to various conditions.
31451991Sheppo  */
31461991Sheppo static void
31471991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp)
31481991Sheppo {
31494647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
31501991Sheppo 	ldc_status_t istatus;
31512793Slm66018 	int rv;
31521991Sheppo 
31534647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
31541991Sheppo 	/* reset hstate and hphase */
31551991Sheppo 	ldcp->hstate = 0;
31561991Sheppo 	ldcp->hphase = VH_PHASE0;
31571991Sheppo 
31583653Snarayan 	/*
31593653Snarayan 	 * Save the id of pending handshake timer in cancel_htid.
31603653Snarayan 	 * This will be checked in vgen_ldc_cb() and the handshake timer will
31613653Snarayan 	 * be cancelled after releasing cblock.
31623653Snarayan 	 */
31631991Sheppo 	if (ldcp->htid) {
31643653Snarayan 		ldcp->cancel_htid = ldcp->htid;
31651991Sheppo 		ldcp->htid = 0;
31661991Sheppo 	}
31671991Sheppo 
31681991Sheppo 	if (ldcp->local_hparams.dring_ready) {
31691991Sheppo 		ldcp->local_hparams.dring_ready = B_FALSE;
31702793Slm66018 	}
31712793Slm66018 
31722793Slm66018 	/* Unbind tx descriptor ring from the channel */
31732793Slm66018 	if (ldcp->num_txdcookies) {
31742793Slm66018 		rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
31752793Slm66018 		if (rv != 0) {
31764647Sraghuram 			DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n");
31772793Slm66018 		}
31782793Slm66018 		ldcp->num_txdcookies = 0;
31791991Sheppo 	}
31801991Sheppo 
31811991Sheppo 	if (ldcp->peer_hparams.dring_ready) {
31821991Sheppo 		ldcp->peer_hparams.dring_ready = B_FALSE;
31831991Sheppo 		/* Unmap peer's dring */
31841991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
31851991Sheppo 		vgen_clobber_rxds(ldcp);
31861991Sheppo 	}
31871991Sheppo 
31881991Sheppo 	vgen_clobber_tbufs(ldcp);
31891991Sheppo 
31901991Sheppo 	/*
31911991Sheppo 	 * clear local handshake params and initialize.
31921991Sheppo 	 */
31931991Sheppo 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
31941991Sheppo 
31951991Sheppo 	/* set version to the highest version supported */
31961991Sheppo 	ldcp->local_hparams.ver_major =
31974650Sraghuram 	    ldcp->vgen_versions[0].ver_major;
31981991Sheppo 	ldcp->local_hparams.ver_minor =
31994650Sraghuram 	    ldcp->vgen_versions[0].ver_minor;
32001991Sheppo 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
32011991Sheppo 
32021991Sheppo 	/* set attr_info params */
32031991Sheppo 	ldcp->local_hparams.mtu = ETHERMAX;
32041991Sheppo 	ldcp->local_hparams.addr =
32054650Sraghuram 	    vgen_macaddr_strtoul(vgenp->macaddr);
32061991Sheppo 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
32071991Sheppo 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE;
32081991Sheppo 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
32091991Sheppo 
32101991Sheppo 	/*
32112793Slm66018 	 * Note: dring is created, but not bound yet.
32122793Slm66018 	 * local dring_info params will be updated when we bind the dring in
32132793Slm66018 	 * vgen_handshake_phase2().
32141991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
32151991Sheppo 	 * value and sends it in the ack, which is saved in
32161991Sheppo 	 * vgen_handle_dring_reg().
32171991Sheppo 	 */
32181991Sheppo 	ldcp->local_hparams.dring_ident = 0;
32191991Sheppo 
32201991Sheppo 	/* clear peer_hparams */
32211991Sheppo 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
32221991Sheppo 
32231991Sheppo 	/* reset the channel if required */
32241991Sheppo 	if (ldcp->need_ldc_reset) {
32254647Sraghuram 		DWARN(vgenp, ldcp, "Doing Channel Reset...\n");
32261991Sheppo 		ldcp->need_ldc_reset = B_FALSE;
32272410Slm66018 		(void) ldc_down(ldcp->ldc_handle);
32281991Sheppo 		(void) ldc_status(ldcp->ldc_handle, &istatus);
32294647Sraghuram 		DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus);
32301991Sheppo 		ldcp->ldc_status = istatus;
32312793Slm66018 
32321991Sheppo 		/* clear sids */
32331991Sheppo 		ldcp->local_sid = 0;
32341991Sheppo 		ldcp->peer_sid = 0;
32352793Slm66018 
32362793Slm66018 		/* try to bring the channel up */
32372793Slm66018 		rv = ldc_up(ldcp->ldc_handle);
32382793Slm66018 		if (rv != 0) {
32394647Sraghuram 			DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
32402793Slm66018 		}
32412793Slm66018 
32422793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
32434647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status err\n");
32442793Slm66018 		} else {
32452793Slm66018 			ldcp->ldc_status = istatus;
32462793Slm66018 		}
32471991Sheppo 	}
32481991Sheppo }
32491991Sheppo 
32501991Sheppo /* wrapper function for vgen_reset_hphase */
32511991Sheppo static void
32521991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp)
32531991Sheppo {
32541991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->cblock));
32554647Sraghuram 	mutex_enter(&ldcp->rxlock);
32564647Sraghuram 	mutex_enter(&ldcp->wrlock);
32571991Sheppo 	mutex_enter(&ldcp->txlock);
32581991Sheppo 	mutex_enter(&ldcp->tclock);
32591991Sheppo 
32601991Sheppo 	vgen_reset_hphase(ldcp);
32611991Sheppo 
32621991Sheppo 	mutex_exit(&ldcp->tclock);
32631991Sheppo 	mutex_exit(&ldcp->txlock);
32644647Sraghuram 	mutex_exit(&ldcp->wrlock);
32654647Sraghuram 	mutex_exit(&ldcp->rxlock);
32661991Sheppo }
32671991Sheppo 
32681991Sheppo /*
32691991Sheppo  * Initiate handshake with the peer by sending various messages
32701991Sheppo  * based on the handshake-phase that the channel is currently in.
32711991Sheppo  */
32721991Sheppo static void
32731991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
32741991Sheppo {
32751991Sheppo 	uint32_t hphase = ldcp->hphase;
32761991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
32772793Slm66018 	ldc_status_t	istatus;
32782793Slm66018 	int	rv = 0;
32791991Sheppo 
32801991Sheppo 	switch (hphase) {
32811991Sheppo 
32821991Sheppo 	case VH_PHASE1:
32831991Sheppo 
32841991Sheppo 		/*
32851991Sheppo 		 * start timer, for entire handshake process, turn this timer
32861991Sheppo 		 * off if all phases of handshake complete successfully and
32871991Sheppo 		 * hphase goes to VH_DONE(below) or
32881991Sheppo 		 * vgen_reset_hphase() gets called or
32891991Sheppo 		 * channel is reset due to errors or
32901991Sheppo 		 * vgen_ldc_uninit() is invoked(vgen_stop).
32911991Sheppo 		 */
32921991Sheppo 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
3293*5171Ssb155480 		    drv_usectohz(vgen_hwd_interval * MICROSEC));
32941991Sheppo 
32951991Sheppo 		/* Phase 1 involves negotiating the version */
32962793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
32971991Sheppo 		break;
32981991Sheppo 
32991991Sheppo 	case VH_PHASE2:
33002793Slm66018 		rv = vgen_handshake_phase2(ldcp);
33011991Sheppo 		break;
33021991Sheppo 
33031991Sheppo 	case VH_PHASE3:
33042793Slm66018 		rv = vgen_send_rdx_info(ldcp);
33051991Sheppo 		break;
33061991Sheppo 
33071991Sheppo 	case VH_DONE:
33083653Snarayan 		/*
33093653Snarayan 		 * Save the id of pending handshake timer in cancel_htid.
33103653Snarayan 		 * This will be checked in vgen_ldc_cb() and the handshake
33113653Snarayan 		 * timer will be cancelled after releasing cblock.
33123653Snarayan 		 */
33131991Sheppo 		if (ldcp->htid) {
33143653Snarayan 			ldcp->cancel_htid = ldcp->htid;
33151991Sheppo 			ldcp->htid = 0;
33161991Sheppo 		}
33171991Sheppo 		ldcp->hretries = 0;
33184647Sraghuram 		DBG1(vgenp, ldcp, "Handshake Done\n");
33191991Sheppo 
3320*5171Ssb155480 		if (ldcp->portp == vgenp->vsw_portp) {
3321*5171Ssb155480 			/*
3322*5171Ssb155480 			 * If this channel(port) is connected to vsw,
3323*5171Ssb155480 			 * need to sync multicast table with vsw.
3324*5171Ssb155480 			 */
33251991Sheppo 			mutex_exit(&ldcp->cblock);
33261991Sheppo 
33271991Sheppo 			mutex_enter(&vgenp->lock);
33282793Slm66018 			rv = vgen_send_mcast_info(ldcp);
33291991Sheppo 			mutex_exit(&vgenp->lock);
33301991Sheppo 
33311991Sheppo 			mutex_enter(&ldcp->cblock);
33322793Slm66018 			if (rv != VGEN_SUCCESS)
33332793Slm66018 				break;
33341991Sheppo 		}
33352793Slm66018 
33362793Slm66018 		/*
33372793Slm66018 		 * Check if mac layer should be notified to restart
33382793Slm66018 		 * transmissions. This can happen if the channel got
33392793Slm66018 		 * reset and vgen_clobber_tbufs() is called, while
33402793Slm66018 		 * need_resched is set.
33412793Slm66018 		 */
33422793Slm66018 		mutex_enter(&ldcp->tclock);
33432793Slm66018 		if (ldcp->need_resched) {
33442793Slm66018 			ldcp->need_resched = B_FALSE;
33452793Slm66018 			vnet_tx_update(vgenp->vnetp);
33462793Slm66018 		}
33472793Slm66018 		mutex_exit(&ldcp->tclock);
33482793Slm66018 
33491991Sheppo 		break;
33501991Sheppo 
33511991Sheppo 	default:
33521991Sheppo 		break;
33531991Sheppo 	}
33542793Slm66018 
33552793Slm66018 	if (rv == ECONNRESET) {
33562793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
33574647Sraghuram 			DWARN(vgenp, ldcp, "ldc_status err\n");
33582793Slm66018 		} else {
33592793Slm66018 			ldcp->ldc_status = istatus;
33602793Slm66018 		}
33612793Slm66018 		vgen_handle_evt_reset(ldcp, B_FALSE);
33622793Slm66018 	} else if (rv) {
33632793Slm66018 		vgen_handshake_reset(ldcp);
33642793Slm66018 	}
33651991Sheppo }
33661991Sheppo 
33671991Sheppo /*
33681991Sheppo  * Check if the current handshake phase has completed successfully and
33691991Sheppo  * return the status.
33701991Sheppo  */
33711991Sheppo static int
33721991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
33731991Sheppo {
33744647Sraghuram 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
33751991Sheppo 	uint32_t	hphase = ldcp->hphase;
33761991Sheppo 	int 		status = 0;
33771991Sheppo 
33781991Sheppo 	switch (hphase) {
33791991Sheppo 
33801991Sheppo 	case VH_PHASE1:
33811991Sheppo 		/*
33821991Sheppo 		 * Phase1 is done, if version negotiation
33831991Sheppo 		 * completed successfully.
33841991Sheppo 		 */
33851991Sheppo 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
33864650Sraghuram 		    VER_NEGOTIATED);
33871991Sheppo 		break;
33881991Sheppo 
33891991Sheppo 	case VH_PHASE2:
33901991Sheppo 		/*
33911991Sheppo 		 * Phase 2 is done, if attr info and dring info
33921991Sheppo 		 * have been exchanged successfully.
33931991Sheppo 		 */
33941991Sheppo 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
33954650Sraghuram 		    ATTR_INFO_EXCHANGED) &&
33964650Sraghuram 		    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
33974650Sraghuram 		    DRING_INFO_EXCHANGED));
33981991Sheppo 		break;
33991991Sheppo 
34001991Sheppo 	case VH_PHASE3:
34011991Sheppo 		/* Phase 3 is done, if rdx msg has been exchanged */
34021991Sheppo 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
34034650Sraghuram 		    RDX_EXCHANGED);
34041991Sheppo 		break;
34051991Sheppo 
34061991Sheppo 	default:
34071991Sheppo 		break;
34081991Sheppo 	}
34091991Sheppo 
34101991Sheppo 	if (status == 0) {
34111991Sheppo 		return (VGEN_FAILURE);
34121991Sheppo 	}
34134647Sraghuram 	DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase);
34141991Sheppo 	return (VGEN_SUCCESS);
34151991Sheppo }
34161991Sheppo 
34171991Sheppo /* retry handshake on failure */
34181991Sheppo static void
34191991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp)
34201991Sheppo {
34211991Sheppo 	/* reset handshake phase */
34221991Sheppo 	vgen_handshake_reset(ldcp);
34233653Snarayan 
34243653Snarayan 	/* handshake retry is specified and the channel is UP */
34253653Snarayan 	if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) {
34263653Snarayan 		if (ldcp->hretries++ < vgen_max_hretries) {
34273653Snarayan 			ldcp->local_sid = ddi_get_lbolt();
34281991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
34293653Snarayan 		}
34301991Sheppo 	}
34311991Sheppo }
34321991Sheppo 
34331991Sheppo /*
34341991Sheppo  * Handle a version info msg from the peer or an ACK/NACK from the peer
34351991Sheppo  * to a version info msg that we sent.
34361991Sheppo  */
34372793Slm66018 static int
34381991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
34391991Sheppo {
34404647Sraghuram 	vgen_t		*vgenp;
34411991Sheppo 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
34421991Sheppo 	int		ack = 0;
34431991Sheppo 	int		failed = 0;
34441991Sheppo 	int		idx;
34451991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
34462793Slm66018 	int		rv = 0;
34471991Sheppo 
34484647Sraghuram 	vgenp = LDC_TO_VGEN(ldcp);
34494647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
34501991Sheppo 	switch (tagp->vio_subtype) {
34511991Sheppo 	case VIO_SUBTYPE_INFO:
34521991Sheppo 
34531991Sheppo 		/*  Cache sid of peer if this is the first time */
34541991Sheppo 		if (ldcp->peer_sid == 0) {
34554647Sraghuram 			DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n",
34564647Sraghuram 			    tagp->vio_sid);
34571991Sheppo 			ldcp->peer_sid = tagp->vio_sid;
34581991Sheppo 		}
34591991Sheppo 
34601991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
34611991Sheppo 			/*
34621991Sheppo 			 * If we are not already in VH_PHASE1, reset to
34631991Sheppo 			 * pre-handshake state, and initiate handshake
34641991Sheppo 			 * to the peer too.
34651991Sheppo 			 */
34661991Sheppo 			vgen_handshake_reset(ldcp);
34671991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
34681991Sheppo 		}
34691991Sheppo 		ldcp->hstate |= VER_INFO_RCVD;
34701991Sheppo 
34711991Sheppo 		/* save peer's requested values */
34721991Sheppo 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
34731991Sheppo 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
34741991Sheppo 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
34751991Sheppo 
34761991Sheppo 		if ((vermsg->dev_class != VDEV_NETWORK) &&
34771991Sheppo 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
34781991Sheppo 			/* unsupported dev_class, send NACK */
34791991Sheppo 
34804647Sraghuram 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
34812793Slm66018 
34821991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
34831991Sheppo 			tagp->vio_sid = ldcp->local_sid;
34841991Sheppo 			/* send reply msg back to peer */
34852793Slm66018 			rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
34861991Sheppo 			    sizeof (*vermsg), B_FALSE);
34872793Slm66018 			if (rv != VGEN_SUCCESS) {
34882793Slm66018 				return (rv);
34892793Slm66018 			}
34902793Slm66018 			return (VGEN_FAILURE);
34911991Sheppo 		}
34921991Sheppo 
34934647Sraghuram 		DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n",
34944647Sraghuram 		    vermsg->ver_major,  vermsg->ver_minor);
34951991Sheppo 
34961991Sheppo 		idx = 0;
34971991Sheppo 
34981991Sheppo 		for (;;) {
34991991Sheppo 
35001991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
35011991Sheppo 
35021991Sheppo 				/* nack with next lower version */
35031991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
35041991Sheppo 				vermsg->ver_major = versions[idx].ver_major;
35051991Sheppo 				vermsg->ver_minor = versions[idx].ver_minor;
35061991Sheppo 				break;
35071991Sheppo 			}
35081991Sheppo 
35091991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
35101991Sheppo 
35111991Sheppo 				/* major version match - ACK version */
35121991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
35131991Sheppo 				ack = 1;
35141991Sheppo 
35151991Sheppo 				/*
35161991Sheppo 				 * lower minor version to the one this endpt
35171991Sheppo 				 * supports, if necessary
35181991Sheppo 				 */
35191991Sheppo 				if (vermsg->ver_minor >
35201991Sheppo 				    versions[idx].ver_minor) {
35211991Sheppo 					vermsg->ver_minor =
35224650Sraghuram 					    versions[idx].ver_minor;
35231991Sheppo 					ldcp->peer_hparams.ver_minor =
35244650Sraghuram 					    versions[idx].ver_minor;
35251991Sheppo 				}
35261991Sheppo 				break;
35271991Sheppo 			}
35281991Sheppo 
35291991Sheppo 			idx++;
35301991Sheppo 
35311991Sheppo 			if (idx == VGEN_NUM_VER) {
35321991Sheppo 
35331991Sheppo 				/* no version match - send NACK */
35341991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
35351991Sheppo 				vermsg->ver_major = 0;
35361991Sheppo 				vermsg->ver_minor = 0;
35371991Sheppo 				failed = 1;
35381991Sheppo 				break;
35391991Sheppo 			}
35401991Sheppo 
35411991Sheppo 		}
35421991Sheppo 
35431991Sheppo 		tagp->vio_sid = ldcp->local_sid;
35441991Sheppo 
35451991Sheppo 		/* send reply msg back to peer */
35462793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
35472793Slm66018 		    B_FALSE);
35482793Slm66018 		if (rv != VGEN_SUCCESS) {
35492793Slm66018 			return (rv);
35501991Sheppo 		}
35511991Sheppo 
35521991Sheppo 		if (ack) {
35531991Sheppo 			ldcp->hstate |= VER_ACK_SENT;
35544647Sraghuram 			DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n",
35554647Sraghuram 			    vermsg->ver_major, vermsg->ver_minor);
35561991Sheppo 		}
35571991Sheppo 		if (failed) {
35584647Sraghuram 			DWARN(vgenp, ldcp, "Negotiation Failed\n");
35592793Slm66018 			return (VGEN_FAILURE);
35601991Sheppo 		}
35611991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
35621991Sheppo 
35631991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
35641991Sheppo 
35651991Sheppo 			/* local and peer versions match? */
35661991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
35674650Sraghuram 			    ldcp->peer_hparams.ver_major) &&
35684650Sraghuram 			    (ldcp->local_hparams.ver_minor ==
35694650Sraghuram 			    ldcp->peer_hparams.ver_minor));
35701991Sheppo 
35711991Sheppo 			/* move to the next phase */
35721991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
35731991Sheppo 		}
35741991Sheppo 
35751991Sheppo 		break;
35761991Sheppo 
35771991Sheppo 	case VIO_SUBTYPE_ACK:
35781991Sheppo 
35791991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
35801991Sheppo 			/*  This should not happen. */
35814647Sraghuram 			DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
35822793Slm66018 			return (VGEN_FAILURE);
35831991Sheppo 		}
35841991Sheppo 
35851991Sheppo 		/* SUCCESS - we have agreed on a version */
35861991Sheppo 		ldcp->local_hparams.ver_major = vermsg->ver_major;
35871991Sheppo 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
35881991Sheppo 		ldcp->hstate |= VER_ACK_RCVD;
35891991Sheppo 
35904647Sraghuram 		DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n",
35914647Sraghuram 		    vermsg->ver_major,  vermsg->ver_minor);
35921991Sheppo 
35931991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
35941991Sheppo 
35951991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
35961991Sheppo 
35971991Sheppo 			/* local and peer versions match? */
35981991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
35994650Sraghuram 			    ldcp->peer_hparams.ver_major) &&
36004650Sraghuram 			    (ldcp->local_hparams.ver_minor ==
36014650Sraghuram 			    ldcp->peer_hparams.ver_minor));
36021991Sheppo 
36031991Sheppo 			/* move to the next phase */
36041991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
36051991Sheppo 		}
36061991Sheppo 		break;
36071991Sheppo 
36081991Sheppo 	case VIO_SUBTYPE_NACK:
36091991Sheppo 
36101991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
36111991Sheppo 			/*  This should not happen.  */
36124647Sraghuram 			DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid "
36134647Sraghuram 			"Phase(%u)\n", ldcp->hphase);
36142793Slm66018 			return (VGEN_FAILURE);
36151991Sheppo 		}
36161991Sheppo 
36174647Sraghuram 		DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n",
36184647Sraghuram 		    vermsg->ver_major, vermsg->ver_minor);
36191991Sheppo 
36201991Sheppo 		/* check if version in NACK is zero */
36211991Sheppo 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
36221991Sheppo 			/*
36231991Sheppo 			 * Version Negotiation has failed.
36241991Sheppo 			 */
36254647Sraghuram 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
36262793Slm66018 			return (VGEN_FAILURE);
36271991Sheppo 		}
36281991Sheppo 
36291991Sheppo 		idx = 0;
36301991Sheppo 
36311991Sheppo 		for (;;) {
36321991Sheppo 
36331991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
36341991Sheppo 				/* select next lower version */
36351991Sheppo 
36361991Sheppo 				ldcp->local_hparams.ver_major =
36374650Sraghuram 				    versions[idx].ver_major;
36381991Sheppo 				ldcp->local_hparams.ver_minor =
36394650Sraghuram 				    versions[idx].ver_minor;
36401991Sheppo 				break;
36411991Sheppo 			}
36421991Sheppo 
36431991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
36441991Sheppo 				/* major version match */
36451991Sheppo 
36461991Sheppo 				ldcp->local_hparams.ver_major =
36474650Sraghuram 				    versions[idx].ver_major;
36481991Sheppo 
36491991Sheppo 				ldcp->local_hparams.ver_minor =
36504650Sraghuram 				    versions[idx].ver_minor;
36511991Sheppo 				break;
36521991Sheppo 			}
36531991Sheppo 
36541991Sheppo 			idx++;
36551991Sheppo 
36561991Sheppo 			if (idx == VGEN_NUM_VER) {
36571991Sheppo 				/*
36581991Sheppo 				 * no version match.
36591991Sheppo 				 * Version Negotiation has failed.
36601991Sheppo 				 */
36614647Sraghuram 				DWARN(vgenp, ldcp,
36624647Sraghuram 				    "Version Negotiation Failed\n");
36632793Slm66018 				return (VGEN_FAILURE);
36641991Sheppo 			}
36651991Sheppo 
36661991Sheppo 		}
36671991Sheppo 
36682793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
36692793Slm66018 		if (rv != VGEN_SUCCESS) {
36702793Slm66018 			return (rv);
36711991Sheppo 		}
36721991Sheppo 
36731991Sheppo 		break;
36741991Sheppo 	}
36752793Slm66018 
36764647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
36772793Slm66018 	return (VGEN_SUCCESS);
36781991Sheppo }
36791991Sheppo 
36801991Sheppo /* Check if the attributes are supported */
36811991Sheppo static int
36821991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
36831991Sheppo {
36841991Sheppo 	_NOTE(ARGUNUSED(ldcp))
36851991Sheppo 
36861991Sheppo 	/*
36871991Sheppo 	 * currently, we support these attr values:
36881991Sheppo 	 * mtu of ethernet, addr_type of mac, xfer_mode of
36891991Sheppo 	 * ldc shared memory, ack_freq of 0 (data is acked if
36901991Sheppo 	 * the ack bit is set in the descriptor) and the address should
36911991Sheppo 	 * match the address in the port node.
36921991Sheppo 	 */
36931991Sheppo 	if ((msg->mtu != ETHERMAX) ||
36941991Sheppo 	    (msg->addr_type != ADDR_TYPE_MAC) ||
36951991Sheppo 	    (msg->xfer_mode != VIO_DRING_MODE) ||
36961991Sheppo 	    (msg->ack_freq > 64)) {
36971991Sheppo 		return (VGEN_FAILURE);
36981991Sheppo 	}
36991991Sheppo 
37001991Sheppo 	return (VGEN_SUCCESS);
37011991Sheppo }
37021991Sheppo 
37031991Sheppo /*
37041991Sheppo  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
37051991Sheppo  * to an attr info msg that we sent.
37061991Sheppo  */
37072793Slm66018 static int
37081991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
37091991Sheppo {
37104647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
37111991Sheppo 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
37121991Sheppo 	int		ack = 0;
37132793Slm66018 	int		rv = 0;
37141991Sheppo 
37154647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
37161991Sheppo 	if (ldcp->hphase != VH_PHASE2) {
37174647Sraghuram 		DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d),"
37184647Sraghuram 		" Invalid Phase(%u)\n",
37194647Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
37202793Slm66018 		return (VGEN_FAILURE);
37211991Sheppo 	}
37221991Sheppo 	switch (tagp->vio_subtype) {
37231991Sheppo 	case VIO_SUBTYPE_INFO:
37241991Sheppo 
37254647Sraghuram 		DBG2(vgenp, ldcp, "ATTR_INFO_RCVD \n");
37261991Sheppo 		ldcp->hstate |= ATTR_INFO_RCVD;
37271991Sheppo 
37281991Sheppo 		/* save peer's values */
37291991Sheppo 		ldcp->peer_hparams.mtu = attrmsg->mtu;
37301991Sheppo 		ldcp->peer_hparams.addr = attrmsg->addr;
37311991Sheppo 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
37321991Sheppo 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
37331991Sheppo 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
37341991Sheppo 
37351991Sheppo 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
37361991Sheppo 			/* unsupported attr, send NACK */
37371991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
37381991Sheppo 		} else {
37391991Sheppo 			ack = 1;
37401991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
37411991Sheppo 		}
37421991Sheppo 		tagp->vio_sid = ldcp->local_sid;
37431991Sheppo 
37441991Sheppo 		/* send reply msg back to peer */
37452793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
37462793Slm66018 		    B_FALSE);
37472793Slm66018 		if (rv != VGEN_SUCCESS) {
37482793Slm66018 			return (rv);
37491991Sheppo 		}
37501991Sheppo 
37511991Sheppo 		if (ack) {
37521991Sheppo 			ldcp->hstate |= ATTR_ACK_SENT;
37534647Sraghuram 			DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n");
37541991Sheppo 		} else {
37551991Sheppo 			/* failed */
37564647Sraghuram 			DWARN(vgenp, ldcp, "ATTR_NACK_SENT \n");
37572793Slm66018 			return (VGEN_FAILURE);
37581991Sheppo 		}
37591991Sheppo 
37601991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
37611991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
37621991Sheppo 		}
37631991Sheppo 
37641991Sheppo 		break;
37651991Sheppo 
37661991Sheppo 	case VIO_SUBTYPE_ACK:
37671991Sheppo 
37681991Sheppo 		ldcp->hstate |= ATTR_ACK_RCVD;
37691991Sheppo 
37704647Sraghuram 		DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n");
37711991Sheppo 
37721991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
37731991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
37741991Sheppo 		}
37751991Sheppo 		break;
37761991Sheppo 
37771991Sheppo 	case VIO_SUBTYPE_NACK:
37781991Sheppo 
37794647Sraghuram 		DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n");
37802793Slm66018 		return (VGEN_FAILURE);
37811991Sheppo 	}
37824647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
37832793Slm66018 	return (VGEN_SUCCESS);
37841991Sheppo }
37851991Sheppo 
37861991Sheppo /* Check if the dring info msg is ok */
37871991Sheppo static int
37881991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
37891991Sheppo {
37901991Sheppo 	/* check if msg contents are ok */
37911991Sheppo 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
37921991Sheppo 	    sizeof (vnet_public_desc_t))) {
37931991Sheppo 		return (VGEN_FAILURE);
37941991Sheppo 	}
37951991Sheppo 	return (VGEN_SUCCESS);
37961991Sheppo }
37971991Sheppo 
37981991Sheppo /*
37991991Sheppo  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
38001991Sheppo  * the peer to a dring register msg that we sent.
38011991Sheppo  */
38022793Slm66018 static int
38031991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
38041991Sheppo {
38051991Sheppo 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
38061991Sheppo 	ldc_mem_cookie_t dcookie;
38074647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
38081991Sheppo 	int ack = 0;
38091991Sheppo 	int rv = 0;
38101991Sheppo 
38114647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
38121991Sheppo 	if (ldcp->hphase < VH_PHASE2) {
38131991Sheppo 		/* dring_info can be rcvd in any of the phases after Phase1 */
38144647Sraghuram 		DWARN(vgenp, ldcp,
38154647Sraghuram 		    "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n",
38164650Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
38172793Slm66018 		return (VGEN_FAILURE);
38181991Sheppo 	}
38191991Sheppo 	switch (tagp->vio_subtype) {
38201991Sheppo 	case VIO_SUBTYPE_INFO:
38211991Sheppo 
38224647Sraghuram 		DBG2(vgenp, ldcp, "DRING_INFO_RCVD \n");
38231991Sheppo 		ldcp->hstate |= DRING_INFO_RCVD;
38241991Sheppo 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
38251991Sheppo 
38261991Sheppo 		ASSERT(msg->ncookies == 1);
38271991Sheppo 
38281991Sheppo 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
38291991Sheppo 			/*
38301991Sheppo 			 * verified dring info msg to be ok,
38311991Sheppo 			 * now try to map the remote dring.
38321991Sheppo 			 */
38331991Sheppo 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
38341991Sheppo 			    msg->descriptor_size, &dcookie,
38351991Sheppo 			    msg->ncookies);
38361991Sheppo 			if (rv == DDI_SUCCESS) {
38371991Sheppo 				/* now we can ack the peer */
38381991Sheppo 				ack = 1;
38391991Sheppo 			}
38401991Sheppo 		}
38411991Sheppo 		if (ack == 0) {
38421991Sheppo 			/* failed, send NACK */
38431991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
38441991Sheppo 		} else {
38451991Sheppo 			if (!(ldcp->peer_hparams.dring_ready)) {
38461991Sheppo 
38471991Sheppo 				/* save peer's dring_info values */
38481991Sheppo 				bcopy(&dcookie,
38491991Sheppo 				    &(ldcp->peer_hparams.dring_cookie),
38501991Sheppo 				    sizeof (dcookie));
38511991Sheppo 				ldcp->peer_hparams.num_desc =
38524650Sraghuram 				    msg->num_descriptors;
38531991Sheppo 				ldcp->peer_hparams.desc_size =
38544650Sraghuram 				    msg->descriptor_size;
38551991Sheppo 				ldcp->peer_hparams.num_dcookies =
38564650Sraghuram 				    msg->ncookies;
38571991Sheppo 
38581991Sheppo 				/* set dring_ident for the peer */
38591991Sheppo 				ldcp->peer_hparams.dring_ident =
38604650Sraghuram 				    (uint64_t)ldcp->rxdp;
38611991Sheppo 				/* return the dring_ident in ack msg */
38621991Sheppo 				msg->dring_ident =
38634650Sraghuram 				    (uint64_t)ldcp->rxdp;
38641991Sheppo 
38651991Sheppo 				ldcp->peer_hparams.dring_ready = B_TRUE;
38661991Sheppo 			}
38671991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
38681991Sheppo 		}
38691991Sheppo 		tagp->vio_sid = ldcp->local_sid;
38701991Sheppo 		/* send reply msg back to peer */
38712793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
38722793Slm66018 		    B_FALSE);
38732793Slm66018 		if (rv != VGEN_SUCCESS) {
38742793Slm66018 			return (rv);
38751991Sheppo 		}
38761991Sheppo 
38771991Sheppo 		if (ack) {
38781991Sheppo 			ldcp->hstate |= DRING_ACK_SENT;
38794647Sraghuram 			DBG2(vgenp, ldcp, "DRING_ACK_SENT");
38801991Sheppo 		} else {
38814647Sraghuram 			DWARN(vgenp, ldcp, "DRING_NACK_SENT");
38822793Slm66018 			return (VGEN_FAILURE);
38831991Sheppo 		}
38841991Sheppo 
38851991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
38861991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
38871991Sheppo 		}
38881991Sheppo 
38891991Sheppo 		break;
38901991Sheppo 
38911991Sheppo 	case VIO_SUBTYPE_ACK:
38921991Sheppo 
38931991Sheppo 		ldcp->hstate |= DRING_ACK_RCVD;
38941991Sheppo 
38954647Sraghuram 		DBG2(vgenp, ldcp, "DRING_ACK_RCVD");
38961991Sheppo 
38971991Sheppo 		if (!(ldcp->local_hparams.dring_ready)) {
38981991Sheppo 			/* local dring is now ready */
38991991Sheppo 			ldcp->local_hparams.dring_ready = B_TRUE;
39001991Sheppo 
39011991Sheppo 			/* save dring_ident acked by peer */
39021991Sheppo 			ldcp->local_hparams.dring_ident =
39034650Sraghuram 			    msg->dring_ident;
39041991Sheppo 		}
39051991Sheppo 
39061991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
39071991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
39081991Sheppo 		}
39091991Sheppo 
39101991Sheppo 		break;
39111991Sheppo 
39121991Sheppo 	case VIO_SUBTYPE_NACK:
39131991Sheppo 
39144647Sraghuram 		DBG2(vgenp, ldcp, "DRING_NACK_RCVD");
39152793Slm66018 		return (VGEN_FAILURE);
39161991Sheppo 	}
39174647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
39182793Slm66018 	return (VGEN_SUCCESS);
39191991Sheppo }
39201991Sheppo 
39211991Sheppo /*
39221991Sheppo  * Handle a rdx info msg from the peer or an ACK/NACK
39231991Sheppo  * from the peer to a rdx info msg that we sent.
39241991Sheppo  */
39252793Slm66018 static int
39261991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
39271991Sheppo {
39282793Slm66018 	int rv = 0;
39294647Sraghuram 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
39304647Sraghuram 
39314647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
39321991Sheppo 	if (ldcp->hphase != VH_PHASE3) {
39334647Sraghuram 		DWARN(vgenp, ldcp,
39344647Sraghuram 		    "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n",
39354650Sraghuram 		    tagp->vio_subtype, ldcp->hphase);
39362793Slm66018 		return (VGEN_FAILURE);
39371991Sheppo 	}
39381991Sheppo 	switch (tagp->vio_subtype) {
39391991Sheppo 	case VIO_SUBTYPE_INFO:
39401991Sheppo 
39414647Sraghuram 		DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n");
39421991Sheppo 		ldcp->hstate |= RDX_INFO_RCVD;
39431991Sheppo 
39441991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
39451991Sheppo 		tagp->vio_sid = ldcp->local_sid;
39461991Sheppo 		/* send reply msg back to peer */
39472793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
39482793Slm66018 		    B_FALSE);
39492793Slm66018 		if (rv != VGEN_SUCCESS) {
39502793Slm66018 			return (rv);
39511991Sheppo 		}
39521991Sheppo 
39531991Sheppo 		ldcp->hstate |= RDX_ACK_SENT;
39544647Sraghuram 		DBG2(vgenp, ldcp, "RDX_ACK_SENT \n");
39551991Sheppo 
39561991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
39571991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
39581991Sheppo 		}
39591991Sheppo 
39601991Sheppo 		break;
39611991Sheppo 
39621991Sheppo 	case VIO_SUBTYPE_ACK:
39631991Sheppo 
39641991Sheppo 		ldcp->hstate |= RDX_ACK_RCVD;
39651991Sheppo 
39664647Sraghuram 		DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n");
39671991Sheppo 
39681991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
39691991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
39701991Sheppo 		}
39711991Sheppo 		break;
39721991Sheppo 
39731991Sheppo 	case VIO_SUBTYPE_NACK:
39741991Sheppo 
39754647Sraghuram 		DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n");
39762793Slm66018 		return (VGEN_FAILURE);
39771991Sheppo 	}
39784647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
39792793Slm66018 	return (VGEN_SUCCESS);
39801991Sheppo }
39811991Sheppo 
39821991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
39832793Slm66018 static int
39841991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
39851991Sheppo {
39861991Sheppo 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
39871991Sheppo 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
39881991Sheppo 	struct ether_addr *addrp;
39891991Sheppo 	int count;
39901991Sheppo 	int i;
39911991Sheppo 
39924647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
39931991Sheppo 	switch (tagp->vio_subtype) {
39941991Sheppo 
39951991Sheppo 	case VIO_SUBTYPE_INFO:
39961991Sheppo 
39971991Sheppo 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
39984647Sraghuram 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n");
39991991Sheppo 		break;
40001991Sheppo 
40011991Sheppo 	case VIO_SUBTYPE_ACK:
40021991Sheppo 
40031991Sheppo 		/* success adding/removing multicast addr */
40044647Sraghuram 		DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n");
40051991Sheppo 		break;
40061991Sheppo 
40071991Sheppo 	case VIO_SUBTYPE_NACK:
40081991Sheppo 
40094647Sraghuram 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n");
40101991Sheppo 		if (!(msgp->set)) {
40111991Sheppo 			/* multicast remove request failed */
40121991Sheppo 			break;
40131991Sheppo 		}
40141991Sheppo 
40151991Sheppo 		/* multicast add request failed */
40161991Sheppo 		for (count = 0; count < msgp->count; count++) {
40171991Sheppo 			addrp = &(msgp->mca[count]);
40181991Sheppo 
40191991Sheppo 			/* delete address from the table */
40201991Sheppo 			for (i = 0; i < vgenp->mccount; i++) {
40211991Sheppo 				if (ether_cmp(addrp,
40221991Sheppo 				    &(vgenp->mctab[i])) == 0) {
40231991Sheppo 					if (vgenp->mccount > 1) {
40244647Sraghuram 						int t = vgenp->mccount - 1;
40251991Sheppo 						vgenp->mctab[i] =
40264650Sraghuram 						    vgenp->mctab[t];
40271991Sheppo 					}
40281991Sheppo 					vgenp->mccount--;
40291991Sheppo 					break;
40301991Sheppo 				}
40311991Sheppo 			}
40321991Sheppo 		}
40331991Sheppo 		break;
40341991Sheppo 
40351991Sheppo 	}
40364647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
40372793Slm66018 
40382793Slm66018 	return (VGEN_SUCCESS);
40391991Sheppo }
40401991Sheppo 
40411991Sheppo /* handler for control messages received from the peer ldc end-point */
40422793Slm66018 static int
40431991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
40441991Sheppo {
40452793Slm66018 	int rv = 0;
40464647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
40474647Sraghuram 
40484647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
40491991Sheppo 	switch (tagp->vio_subtype_env) {
40501991Sheppo 
40511991Sheppo 	case VIO_VER_INFO:
40522793Slm66018 		rv = vgen_handle_version_negotiate(ldcp, tagp);
40531991Sheppo 		break;
40541991Sheppo 
40551991Sheppo 	case VIO_ATTR_INFO:
40562793Slm66018 		rv = vgen_handle_attr_info(ldcp, tagp);
40571991Sheppo 		break;
40581991Sheppo 
40591991Sheppo 	case VIO_DRING_REG:
40602793Slm66018 		rv = vgen_handle_dring_reg(ldcp, tagp);
40611991Sheppo 		break;
40621991Sheppo 
40631991Sheppo 	case VIO_RDX:
40642793Slm66018 		rv = vgen_handle_rdx_info(ldcp, tagp);
40651991Sheppo 		break;
40661991Sheppo 
40671991Sheppo 	case VNET_MCAST_INFO:
40682793Slm66018 		rv = vgen_handle_mcast_info(ldcp, tagp);
40691991Sheppo 		break;
40701991Sheppo 
40711991Sheppo 	}
40722793Slm66018 
40734647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
40742793Slm66018 	return (rv);
40751991Sheppo }
40761991Sheppo 
40771991Sheppo /* handler for data messages received from the peer ldc end-point */
40782793Slm66018 static int
40794647Sraghuram vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
40801991Sheppo {
40812793Slm66018 	int rv = 0;
40824647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
40834647Sraghuram 
40844647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
40851991Sheppo 
40861991Sheppo 	if (ldcp->hphase != VH_DONE)
40872793Slm66018 		return (rv);
40881991Sheppo 	switch (tagp->vio_subtype_env) {
40891991Sheppo 	case VIO_DRING_DATA:
40904647Sraghuram 		rv = vgen_handle_dring_data(ldcp, tagp);
40911991Sheppo 		break;
40921991Sheppo 	default:
40931991Sheppo 		break;
40941991Sheppo 	}
40951991Sheppo 
40964647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
40972793Slm66018 	return (rv);
40981991Sheppo }
40991991Sheppo 
41002793Slm66018 static int
41012336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
41022336Snarayan     int32_t end, uint8_t pstate)
41032336Snarayan {
41044647Sraghuram 	int rv = 0;
41054647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
41062336Snarayan 	vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp;
41072336Snarayan 
41082336Snarayan 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
41092336Snarayan 	tagp->vio_sid = ldcp->local_sid;
41102336Snarayan 	msgp->start_idx = start;
41112336Snarayan 	msgp->end_idx = end;
41122336Snarayan 	msgp->dring_process_state = pstate;
41132793Slm66018 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE);
41142793Slm66018 	if (rv != VGEN_SUCCESS) {
41154647Sraghuram 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
41162336Snarayan 	}
41172793Slm66018 	return (rv);
41182336Snarayan }
41192336Snarayan 
41202793Slm66018 static int
41214647Sraghuram vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
41221991Sheppo {
41232793Slm66018 	int rv = 0;
41244647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
41254647Sraghuram 
41264647Sraghuram 
41274647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
41281991Sheppo 	switch (tagp->vio_subtype) {
41291991Sheppo 
41301991Sheppo 	case VIO_SUBTYPE_INFO:
41311991Sheppo 		/*
41324647Sraghuram 		 * To reduce the locking contention, release the
41334647Sraghuram 		 * cblock here and re-acquire it once we are done
41344647Sraghuram 		 * receiving packets.
41351991Sheppo 		 */
41364647Sraghuram 		mutex_exit(&ldcp->cblock);
41374647Sraghuram 		mutex_enter(&ldcp->rxlock);
41384647Sraghuram 		rv = vgen_handle_dring_data_info(ldcp, tagp);
41394647Sraghuram 		mutex_exit(&ldcp->rxlock);
41404647Sraghuram 		mutex_enter(&ldcp->cblock);
41414647Sraghuram 		break;
41424647Sraghuram 
41434647Sraghuram 	case VIO_SUBTYPE_ACK:
41444647Sraghuram 		rv = vgen_handle_dring_data_ack(ldcp, tagp);
41454647Sraghuram 		break;
41464647Sraghuram 
41474647Sraghuram 	case VIO_SUBTYPE_NACK:
41484647Sraghuram 		rv = vgen_handle_dring_data_nack(ldcp, tagp);
41494647Sraghuram 		break;
41504647Sraghuram 	}
41514647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
41524647Sraghuram 	return (rv);
41534647Sraghuram }
41544647Sraghuram 
41554647Sraghuram static int
41564647Sraghuram vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
41574647Sraghuram {
41584647Sraghuram 	uint32_t start;
41594647Sraghuram 	int32_t end;
41604647Sraghuram 	int rv = 0;
41614647Sraghuram 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
41624647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
41634647Sraghuram #ifdef VGEN_HANDLE_LOST_PKTS
41644647Sraghuram 	vgen_stats_t *statsp = ldcp->statsp;
41654647Sraghuram 	uint32_t rxi;
41664647Sraghuram 	int n;
41674647Sraghuram #endif
41684647Sraghuram 
41694647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
41704647Sraghuram 
41714647Sraghuram 	start = dringmsg->start_idx;
41724647Sraghuram 	end = dringmsg->end_idx;
41734647Sraghuram 	/*
41744647Sraghuram 	 * received a data msg, which contains the start and end
41754647Sraghuram 	 * indices of the descriptors within the rx ring holding data,
41764647Sraghuram 	 * the seq_num of data packet corresponding to the start index,
41774647Sraghuram 	 * and the dring_ident.
41784647Sraghuram 	 * We can now read the contents of each of these descriptors
41794647Sraghuram 	 * and gather data from it.
41804647Sraghuram 	 */
41814647Sraghuram 	DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n",
41824650Sraghuram 	    start, end);
41834647Sraghuram 
41844647Sraghuram 	/* validate rx start and end indeces */
41854647Sraghuram 	if (!(CHECK_RXI(start, ldcp)) || ((end != -1) &&
41864647Sraghuram 	    !(CHECK_RXI(end, ldcp)))) {
41874647Sraghuram 		DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n",
41884647Sraghuram 		    start, end);
41894647Sraghuram 		/* drop the message if invalid index */
41904647Sraghuram 		return (rv);
41914647Sraghuram 	}
41924647Sraghuram 
41934647Sraghuram 	/* validate dring_ident */
41944647Sraghuram 	if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
41954647Sraghuram 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
41964647Sraghuram 		    dringmsg->dring_ident);
41974647Sraghuram 		/* invalid dring_ident, drop the msg */
41984647Sraghuram 		return (rv);
41994647Sraghuram 	}
42001991Sheppo #ifdef DEBUG
42014647Sraghuram 	if (vgen_trigger_rxlost) {
42024647Sraghuram 		/* drop this msg to simulate lost pkts for debugging */
42034647Sraghuram 		vgen_trigger_rxlost = 0;
42044647Sraghuram 		return (rv);
42054647Sraghuram 	}
42061991Sheppo #endif
42071991Sheppo 
42081991Sheppo #ifdef	VGEN_HANDLE_LOST_PKTS
42091991Sheppo 
42104647Sraghuram 	/* receive start index doesn't match expected index */
42114647Sraghuram 	if (ldcp->next_rxi != start) {
42124647Sraghuram 		DWARN(vgenp, ldcp, "next_rxi(%d) != start(%d)\n",
42134647Sraghuram 		    ldcp->next_rxi, start);
42144647Sraghuram 
42154647Sraghuram 		/* calculate the number of pkts lost */
42164647Sraghuram 		if (start >= ldcp->next_rxi) {
42174647Sraghuram 			n = start - ldcp->next_rxi;
42184647Sraghuram 		} else  {
42194647Sraghuram 			n = ldcp->num_rxds - (ldcp->next_rxi - start);
42204647Sraghuram 		}
42214647Sraghuram 
42224647Sraghuram 		/*
42234647Sraghuram 		 * sequence number of dring data message
42244647Sraghuram 		 * is less than the next sequence number that
42254647Sraghuram 		 * is expected:
42264647Sraghuram 		 *
42274647Sraghuram 		 * drop the message and the corresponding packets.
42284647Sraghuram 		 */
42294647Sraghuram 		if (ldcp->next_rxseq > dringmsg->seq_num) {
42304647Sraghuram 			DWARN(vgenp, ldcp, "dropping pkts, expected "
42314647Sraghuram 			"rxseq(0x%lx) > recvd(0x%lx)\n",
42324647Sraghuram 			    ldcp->next_rxseq, dringmsg->seq_num);
42331991Sheppo 			/*
42344647Sraghuram 			 * duplicate/multiple retransmissions from
42354647Sraghuram 			 * sender?? drop this msg.
42361991Sheppo 			 */
42374647Sraghuram 			return (rv);
42381991Sheppo 		}
42391991Sheppo 
42401991Sheppo 		/*
42414647Sraghuram 		 * sequence number of dring data message
42424647Sraghuram 		 * is greater than the next expected sequence number
42434647Sraghuram 		 *
42444647Sraghuram 		 * send a NACK back to the peer to indicate lost
42454647Sraghuram 		 * packets.
42461991Sheppo 		 */
42474647Sraghuram 		if (dringmsg->seq_num > ldcp->next_rxseq) {
42484647Sraghuram 			statsp->rx_lost_pkts += n;
42494647Sraghuram 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
42504647Sraghuram 			tagp->vio_sid = ldcp->local_sid;
42514647Sraghuram 			/* indicate the range of lost descriptors */
42524647Sraghuram 			dringmsg->start_idx = ldcp->next_rxi;
42534647Sraghuram 			rxi = start;
42544647Sraghuram 			DECR_RXI(rxi, ldcp);
42554647Sraghuram 			dringmsg->end_idx = rxi;
42564647Sraghuram 			/* dring ident is left unchanged */
42574647Sraghuram 			rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
42584647Sraghuram 			    sizeof (*dringmsg), B_FALSE);
42594647Sraghuram 			if (rv != VGEN_SUCCESS) {
42604647Sraghuram 				DWARN(vgenp, ldcp,
42614647Sraghuram 				    "vgen_sendmsg failed, stype:NACK\n");
42624647Sraghuram 				return (rv);
42632336Snarayan 			}
42644647Sraghuram #ifdef VGEN_REXMIT
42654647Sraghuram 			/*
42664647Sraghuram 			 * stop further processing until peer
42674647Sraghuram 			 * retransmits with the right index.
42684647Sraghuram 			 * update next_rxseq expected.
42694647Sraghuram 			 */
42704647Sraghuram 			ldcp->next_rxseq += 1;
42714647Sraghuram 			return (rv);
42724647Sraghuram #else	/* VGEN_REXMIT */
42734647Sraghuram 			/*
42744647Sraghuram 			 * treat this range of descrs/pkts as dropped
42754647Sraghuram 			 * and set the new expected values for next_rxi
42764647Sraghuram 			 * and next_rxseq. continue(below) to process
42774647Sraghuram 			 * from the new start index.
42784647Sraghuram 			 */
42794647Sraghuram 			ldcp->next_rxi = start;
42804647Sraghuram 			ldcp->next_rxseq += 1;
42814647Sraghuram #endif	/* VGEN_REXMIT */
42824647Sraghuram 
42834647Sraghuram 		} else if (dringmsg->seq_num == ldcp->next_rxseq) {
42844647Sraghuram 			/*
42854647Sraghuram 			 * expected and received seqnums match, but
42864647Sraghuram 			 * the descriptor indeces don't?
42874647Sraghuram 			 *
42884647Sraghuram 			 * restart handshake with peer.
42894647Sraghuram 			 */
42904647Sraghuram 			DWARN(vgenp, ldcp, "next_rxseq(0x%lx)=="
42914650Sraghuram 			    "seq_num(0x%lx)\n", ldcp->next_rxseq,
42924650Sraghuram 			    dringmsg->seq_num);
42934647Sraghuram 
42944647Sraghuram 		}
42954647Sraghuram 
42964647Sraghuram 	} else {
42974647Sraghuram 		/* expected and start dring indeces match */
42984647Sraghuram 
42994647Sraghuram 		if (dringmsg->seq_num != ldcp->next_rxseq) {
43004647Sraghuram 
43014647Sraghuram 			/* seqnums don't match */
43024647Sraghuram 
43034647Sraghuram 			DWARN(vgenp, ldcp,
43044647Sraghuram 			    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
43054647Sraghuram 			    ldcp->next_rxseq, dringmsg->seq_num);
43064647Sraghuram 		}
43074647Sraghuram 	}
43084647Sraghuram 
43094647Sraghuram #endif	/* VGEN_HANDLE_LOST_PKTS */
43104647Sraghuram 
43114647Sraghuram 	/* Now receive messages */
43124647Sraghuram 	rv = vgen_process_dring_data(ldcp, tagp);
43134647Sraghuram 
43144647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
43154647Sraghuram 	return (rv);
43164647Sraghuram }
43174647Sraghuram 
43184647Sraghuram static int
43194647Sraghuram vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
43204647Sraghuram {
43214647Sraghuram 	boolean_t set_ack_start = B_FALSE;
43224647Sraghuram 	uint32_t start;
43234647Sraghuram 	uint32_t ack_end;
43244647Sraghuram 	uint32_t next_rxi;
43254647Sraghuram 	uint32_t rxi;
43264647Sraghuram 	int count = 0;
43274647Sraghuram 	int rv = 0;
43284647Sraghuram 	uint32_t retries = 0;
43294647Sraghuram 	vgen_stats_t *statsp;
43304647Sraghuram 	vnet_public_desc_t *rxdp;
43314647Sraghuram 	vio_dring_entry_hdr_t *hdrp;
43324647Sraghuram 	mblk_t *bp = NULL;
43334647Sraghuram 	mblk_t *bpt = NULL;
43344647Sraghuram 	uint32_t ack_start;
43354647Sraghuram 	uint32_t datalen;
43364647Sraghuram 	uint32_t ncookies;
43374647Sraghuram 	boolean_t rxd_err = B_FALSE;
43384647Sraghuram 	mblk_t *mp = NULL;
43394647Sraghuram 	size_t nbytes;
43404647Sraghuram 	boolean_t ack_needed = B_FALSE;
43414647Sraghuram 	size_t nread;
43424647Sraghuram 	uint64_t off = 0;
43434647Sraghuram 	struct ether_header *ehp;
43444647Sraghuram 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
43454647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
43464647Sraghuram 
43474647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
43484647Sraghuram 
43494647Sraghuram 	statsp = ldcp->statsp;
43504647Sraghuram 	start = dringmsg->start_idx;
43514647Sraghuram 
43524647Sraghuram 	/*
43534647Sraghuram 	 * start processing the descriptors from the specified
43544647Sraghuram 	 * start index, up to the index a descriptor is not ready
43554647Sraghuram 	 * to be processed or we process the entire descriptor ring
43564647Sraghuram 	 * and wrap around upto the start index.
43574647Sraghuram 	 */
43584647Sraghuram 
43594647Sraghuram 	/* need to set the start index of descriptors to be ack'd */
43604647Sraghuram 	set_ack_start = B_TRUE;
43614647Sraghuram 
43624647Sraghuram 	/* index upto which we have ack'd */
43634647Sraghuram 	ack_end = start;
43644647Sraghuram 	DECR_RXI(ack_end, ldcp);
43654647Sraghuram 
43664647Sraghuram 	next_rxi = rxi =  start;
43674647Sraghuram 	do {
43684647Sraghuram vgen_recv_retry:
43694647Sraghuram 		rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi);
43704647Sraghuram 		if (rv != 0) {
43714647Sraghuram 			DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed"
43724647Sraghuram 			    " rv(%d)\n", rv);
43734647Sraghuram 			statsp->ierrors++;
43744647Sraghuram 			return (rv);
43754647Sraghuram 		}
43764647Sraghuram 
43774647Sraghuram 		rxdp = &(ldcp->rxdp[rxi]);
43784647Sraghuram 		hdrp = &rxdp->hdr;
43794647Sraghuram 
43804647Sraghuram 		if (hdrp->dstate != VIO_DESC_READY) {
43814647Sraghuram 			/*
43824647Sraghuram 			 * Before waiting and retry here, queue
43834647Sraghuram 			 * the messages that are received already.
43844647Sraghuram 			 * This will help the soft interrupt to
43854647Sraghuram 			 * send them up with less latency.
43864647Sraghuram 			 */
43874647Sraghuram 			if (bp != NULL) {
43884647Sraghuram 				DTRACE_PROBE1(vgen_rcv_msgs, int, count);
43894647Sraghuram 				vgen_ldc_queue_data(ldcp, bp, bpt);
43904647Sraghuram 				count = 0;
43914647Sraghuram 				bp = bpt = NULL;
43924647Sraghuram 			}
43934647Sraghuram 			/*
43944647Sraghuram 			 * descriptor is not ready.
43954647Sraghuram 			 * retry descriptor acquire, stop processing
43964647Sraghuram 			 * after max # retries.
43974647Sraghuram 			 */
43984647Sraghuram 			if (retries == vgen_recv_retries)
43994647Sraghuram 				break;
44004647Sraghuram 			retries++;
44014647Sraghuram 			drv_usecwait(vgen_recv_delay);
44024647Sraghuram 			goto vgen_recv_retry;
44034647Sraghuram 		}
44044647Sraghuram 		retries = 0;
44054647Sraghuram 
44064647Sraghuram 		if (set_ack_start) {
44074647Sraghuram 			/*
44084647Sraghuram 			 * initialize the start index of the range
44094647Sraghuram 			 * of descriptors to be ack'd.
44104647Sraghuram 			 */
44114647Sraghuram 			ack_start = rxi;
44124647Sraghuram 			set_ack_start = B_FALSE;
44134647Sraghuram 		}
44144647Sraghuram 
44154647Sraghuram 		datalen = rxdp->nbytes;
44164647Sraghuram 		ncookies = rxdp->ncookies;
44174647Sraghuram 		if ((datalen < ETHERMIN) ||
44184647Sraghuram 		    (ncookies == 0) ||
44194647Sraghuram 		    (ncookies > MAX_COOKIES)) {
44204647Sraghuram 			rxd_err = B_TRUE;
44214647Sraghuram 		} else {
44224647Sraghuram 			/*
44234647Sraghuram 			 * Try to allocate an mblk from the free pool
44244647Sraghuram 			 * of recv mblks for the channel.
44254647Sraghuram 			 * If this fails, use allocb().
44264647Sraghuram 			 */
44274647Sraghuram 			nbytes = (VNET_IPALIGN + datalen + 7) & ~7;
44284647Sraghuram 			mp = vio_multipool_allocb(&ldcp->vmp, nbytes);
44294647Sraghuram 			if (!mp) {
44302336Snarayan 				/*
44314647Sraghuram 				 * The data buffer returned by
44324647Sraghuram 				 * allocb(9F) is 8byte aligned. We
44334647Sraghuram 				 * allocate extra 8 bytes to ensure
44344647Sraghuram 				 * size is multiple of 8 bytes for
44354647Sraghuram 				 * ldc_mem_copy().
44361991Sheppo 				 */
44374647Sraghuram 				statsp->rx_vio_allocb_fail++;
44384647Sraghuram 				mp = allocb(VNET_IPALIGN + datalen + 8,
44394647Sraghuram 				    BPRI_MED);
44401991Sheppo 			}
44414647Sraghuram 		}
44424647Sraghuram 		if ((rxd_err) || (mp == NULL)) {
44434647Sraghuram 			/*
44444647Sraghuram 			 * rxd_err or allocb() failure,
44454647Sraghuram 			 * drop this packet, get next.
44464647Sraghuram 			 */
44474647Sraghuram 			if (rxd_err) {
44482793Slm66018 				statsp->ierrors++;
44494647Sraghuram 				rxd_err = B_FALSE;
44504647Sraghuram 			} else {
44514647Sraghuram 				statsp->rx_allocb_fail++;
44522793Slm66018 			}
44532793Slm66018 
44542793Slm66018 			ack_needed = hdrp->ack;
44554647Sraghuram 
44564647Sraghuram 			/* set descriptor done bit */
44571991Sheppo 			hdrp->dstate = VIO_DESC_DONE;
44581991Sheppo 
44594647Sraghuram 			rv = ldc_mem_dring_release(ldcp->rx_dhandle,
44604647Sraghuram 			    rxi, rxi);
44612793Slm66018 			if (rv != 0) {
44624647Sraghuram 				DWARN(vgenp, ldcp,
44634647Sraghuram 				    "ldc_mem_dring_release err rv(%d)\n", rv);
44644647Sraghuram 				return (rv);
44652793Slm66018 			}
44662336Snarayan 
44672793Slm66018 			if (ack_needed) {
44682793Slm66018 				ack_needed = B_FALSE;
44691991Sheppo 				/*
44702336Snarayan 				 * sender needs ack for this packet,
44712336Snarayan 				 * ack pkts upto this index.
44721991Sheppo 				 */
44732336Snarayan 				ack_end = rxi;
44742336Snarayan 
44752793Slm66018 				rv = vgen_send_dring_ack(ldcp, tagp,
44764647Sraghuram 				    ack_start, ack_end,
44774647Sraghuram 				    VIO_DP_ACTIVE);
44782793Slm66018 				if (rv != VGEN_SUCCESS) {
44792793Slm66018 					goto error_ret;
44802793Slm66018 				}
44812336Snarayan 
44822336Snarayan 				/* need to set new ack start index */
44832336Snarayan 				set_ack_start = B_TRUE;
44841991Sheppo 			}
44854647Sraghuram 			goto vgen_next_rxi;
44864647Sraghuram 		}
44874647Sraghuram 
44884647Sraghuram 		nread = nbytes;
44894647Sraghuram 		rv = ldc_mem_copy(ldcp->ldc_handle,
44904647Sraghuram 		    (caddr_t)mp->b_rptr, off, &nread,
44914647Sraghuram 		    rxdp->memcookie, ncookies, LDC_COPY_IN);
44924647Sraghuram 
44934647Sraghuram 		/* if ldc_mem_copy() failed */
44944647Sraghuram 		if (rv) {
44954647Sraghuram 			DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv);
44964647Sraghuram 			statsp->ierrors++;
44974647Sraghuram 			freemsg(mp);
44984647Sraghuram 			goto error_ret;
44994647Sraghuram 		}
45004647Sraghuram 
45014647Sraghuram 		ack_needed = hdrp->ack;
45024647Sraghuram 		hdrp->dstate = VIO_DESC_DONE;
45034647Sraghuram 
45044647Sraghuram 		rv = ldc_mem_dring_release(ldcp->rx_dhandle, rxi, rxi);
45054647Sraghuram 		if (rv != 0) {
45064647Sraghuram 			DWARN(vgenp, ldcp,
45074647Sraghuram 			    "ldc_mem_dring_release err rv(%d)\n", rv);
45084647Sraghuram 			goto error_ret;
45094647Sraghuram 		}
45104647Sraghuram 
45114647Sraghuram 		mp->b_rptr += VNET_IPALIGN;
45124647Sraghuram 
45134647Sraghuram 		if (ack_needed) {
45144647Sraghuram 			ack_needed = B_FALSE;
45154647Sraghuram 			/*
45164647Sraghuram 			 * sender needs ack for this packet,
45174647Sraghuram 			 * ack pkts upto this index.
45184647Sraghuram 			 */
45194647Sraghuram 			ack_end = rxi;
45204647Sraghuram 
45214647Sraghuram 			rv = vgen_send_dring_ack(ldcp, tagp,
45224647Sraghuram 			    ack_start, ack_end, VIO_DP_ACTIVE);
45234647Sraghuram 			if (rv != VGEN_SUCCESS) {
45244647Sraghuram 				goto error_ret;
45251991Sheppo 			}
45261991Sheppo 
45274647Sraghuram 			/* need to set new ack start index */
45284647Sraghuram 			set_ack_start = B_TRUE;
45294647Sraghuram 		}
45304647Sraghuram 
45314647Sraghuram 		if (nread != nbytes) {
45324647Sraghuram 			DWARN(vgenp, ldcp,
45334647Sraghuram 			    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
45344647Sraghuram 			    nread, nbytes);
45354647Sraghuram 			statsp->ierrors++;
45364647Sraghuram 			freemsg(mp);
45374647Sraghuram 			goto vgen_next_rxi;
45384647Sraghuram 		}
45394647Sraghuram 
45404647Sraghuram 		/* point to the actual end of data */
45414647Sraghuram 		mp->b_wptr = mp->b_rptr + datalen;
45424647Sraghuram 
45434647Sraghuram 		/* update stats */
45444647Sraghuram 		statsp->ipackets++;
45454647Sraghuram 		statsp->rbytes += datalen;
45464647Sraghuram 		ehp = (struct ether_header *)mp->b_rptr;
45474647Sraghuram 		if (IS_BROADCAST(ehp))
45484647Sraghuram 			statsp->brdcstrcv++;
45494647Sraghuram 		else if (IS_MULTICAST(ehp))
45504647Sraghuram 			statsp->multircv++;
45514647Sraghuram 
45524647Sraghuram 		/* build a chain of received packets */
45534647Sraghuram 		if (bp == NULL) {
45544647Sraghuram 			/* first pkt */
45554647Sraghuram 			bp = mp;
45564647Sraghuram 			bpt = bp;
45574647Sraghuram 			bpt->b_next = NULL;
45584647Sraghuram 		} else {
45594647Sraghuram 			mp->b_next = NULL;
45604647Sraghuram 			bpt->b_next = mp;
45614647Sraghuram 			bpt = mp;
45624647Sraghuram 		}
45634647Sraghuram 
45644647Sraghuram 		if (count++ > vgen_chain_len) {
45654647Sraghuram 			DTRACE_PROBE1(vgen_rcv_msgs, int, count);
45664647Sraghuram 			vgen_ldc_queue_data(ldcp, bp, bpt);
45674647Sraghuram 			count = 0;
45684647Sraghuram 			bp = bpt = NULL;
45694647Sraghuram 		}
45702336Snarayan 
45712336Snarayan vgen_next_rxi:
45724647Sraghuram 		/* update end index of range of descrs to be ack'd */
45734647Sraghuram 		ack_end = rxi;
45744647Sraghuram 
45754647Sraghuram 		/* update the next index to be processed */
45764647Sraghuram 		INCR_RXI(next_rxi, ldcp);
45774647Sraghuram 		if (next_rxi == start) {
45782336Snarayan 			/*
45794647Sraghuram 			 * processed the entire descriptor ring upto
45804647Sraghuram 			 * the index at which we started.
45812336Snarayan 			 */
45822336Snarayan 			break;
45832336Snarayan 		}
45842336Snarayan 
45854647Sraghuram 		rxi = next_rxi;
45864647Sraghuram 
45874647Sraghuram 	_NOTE(CONSTCOND)
45884647Sraghuram 	} while (1);
45894647Sraghuram 
45904647Sraghuram 	/*
45914647Sraghuram 	 * send an ack message to peer indicating that we have stopped
45924647Sraghuram 	 * processing descriptors.
45934647Sraghuram 	 */
45944647Sraghuram 	if (set_ack_start) {
45952336Snarayan 		/*
45964647Sraghuram 		 * We have ack'd upto some index and we have not
45974647Sraghuram 		 * processed any descriptors beyond that index.
45984647Sraghuram 		 * Use the last ack'd index as both the start and
45994647Sraghuram 		 * end of range of descrs being ack'd.
46004647Sraghuram 		 * Note: This results in acking the last index twice
46014647Sraghuram 		 * and should be harmless.
46022336Snarayan 		 */
46034647Sraghuram 		ack_start = ack_end;
46044647Sraghuram 	}
46054647Sraghuram 
46064647Sraghuram 	rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
46074647Sraghuram 	    VIO_DP_STOPPED);
46084647Sraghuram 	if (rv != VGEN_SUCCESS) {
46094647Sraghuram 		goto error_ret;
46104647Sraghuram 	}
46114647Sraghuram 
46124647Sraghuram 	/* save new recv index and expected seqnum of next dring msg */
46134647Sraghuram 	ldcp->next_rxi = next_rxi;
46144647Sraghuram 	ldcp->next_rxseq += 1;
46154647Sraghuram 
46164647Sraghuram error_ret:
46174647Sraghuram 	/* queue the packets received so far */
46184647Sraghuram 	if (bp != NULL) {
46194647Sraghuram 		DTRACE_PROBE1(vgen_rcv_msgs, int, count);
46204647Sraghuram 		vgen_ldc_queue_data(ldcp, bp, bpt);
46214647Sraghuram 		bp = bpt = NULL;
46224647Sraghuram 	}
46234647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
46244647Sraghuram 	return (rv);
46254647Sraghuram 
46264647Sraghuram }
46274647Sraghuram 
46284647Sraghuram static int
46294647Sraghuram vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
46304647Sraghuram {
46314647Sraghuram 	int rv = 0;
46324647Sraghuram 	uint32_t start;
46334647Sraghuram 	int32_t end;
46344647Sraghuram 	uint32_t txi;
46354647Sraghuram 	boolean_t ready_txd = B_FALSE;
46364647Sraghuram 	vgen_stats_t *statsp;
46374647Sraghuram 	vgen_private_desc_t *tbufp;
46384647Sraghuram 	vnet_public_desc_t *txdp;
46394647Sraghuram 	vio_dring_entry_hdr_t *hdrp;
46404647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
46414647Sraghuram 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
46424647Sraghuram 
46434647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
46444647Sraghuram 	start = dringmsg->start_idx;
46454647Sraghuram 	end = dringmsg->end_idx;
46464647Sraghuram 	statsp = ldcp->statsp;
46474647Sraghuram 
46484647Sraghuram 	/*
46494647Sraghuram 	 * received an ack corresponding to a specific descriptor for
46504647Sraghuram 	 * which we had set the ACK bit in the descriptor (during
46514647Sraghuram 	 * transmit). This enables us to reclaim descriptors.
46524647Sraghuram 	 */
46534647Sraghuram 
46544647Sraghuram 	DBG2(vgenp, ldcp, "ACK:  start(%d), end(%d)\n", start, end);
46554647Sraghuram 
46564647Sraghuram 	/* validate start and end indeces in the tx ack msg */
46574647Sraghuram 	if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
46584647Sraghuram 		/* drop the message if invalid index */
46594647Sraghuram 		DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n",
46604647Sraghuram 		    start, end);
46614647Sraghuram 		return (rv);
46624647Sraghuram 	}
46634647Sraghuram 	/* validate dring_ident */
46644647Sraghuram 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
46654647Sraghuram 		/* invalid dring_ident, drop the msg */
46664647Sraghuram 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
46674647Sraghuram 		    dringmsg->dring_ident);
46684647Sraghuram 		return (rv);
46694647Sraghuram 	}
46704647Sraghuram 	statsp->dring_data_acks++;
46714647Sraghuram 
46724647Sraghuram 	/* reclaim descriptors that are done */
46734647Sraghuram 	vgen_reclaim(ldcp);
46744647Sraghuram 
46754647Sraghuram 	if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
46762336Snarayan 		/*
46774647Sraghuram 		 * receiver continued processing descriptors after
46784647Sraghuram 		 * sending us the ack.
46792336Snarayan 		 */
46804647Sraghuram 		return (rv);
46814647Sraghuram 	}
46824647Sraghuram 
46834647Sraghuram 	statsp->dring_stopped_acks++;
46844647Sraghuram 
46854647Sraghuram 	/* receiver stopped processing descriptors */
46864647Sraghuram 	mutex_enter(&ldcp->wrlock);
46874647Sraghuram 	mutex_enter(&ldcp->tclock);
46884647Sraghuram 
46894647Sraghuram 	/*
46904647Sraghuram 	 * determine if there are any pending tx descriptors
46914647Sraghuram 	 * ready to be processed by the receiver(peer) and if so,
46924647Sraghuram 	 * send a message to the peer to restart receiving.
46934647Sraghuram 	 */
46944647Sraghuram 	ready_txd = B_FALSE;
46954647Sraghuram 
46964647Sraghuram 	/*
46974647Sraghuram 	 * using the end index of the descriptor range for which
46984647Sraghuram 	 * we received the ack, check if the next descriptor is
46994647Sraghuram 	 * ready.
47004647Sraghuram 	 */
47014647Sraghuram 	txi = end;
47024647Sraghuram 	INCR_TXI(txi, ldcp);
47034647Sraghuram 	tbufp = &ldcp->tbufp[txi];
47044647Sraghuram 	txdp = tbufp->descp;
47054647Sraghuram 	hdrp = &txdp->hdr;
47064647Sraghuram 	if (hdrp->dstate == VIO_DESC_READY) {
47074647Sraghuram 		ready_txd = B_TRUE;
47084647Sraghuram 	} else {
47094647Sraghuram 		/*
47104647Sraghuram 		 * descr next to the end of ack'd descr range is not
47114647Sraghuram 		 * ready.
47124647Sraghuram 		 * starting from the current reclaim index, check
47134647Sraghuram 		 * if any descriptor is ready.
47144647Sraghuram 		 */
47154647Sraghuram 
47164647Sraghuram 		txi = ldcp->cur_tbufp - ldcp->tbufp;
47172336Snarayan 		tbufp = &ldcp->tbufp[txi];
47184647Sraghuram 
47192336Snarayan 		txdp = tbufp->descp;
47202336Snarayan 		hdrp = &txdp->hdr;
47212336Snarayan 		if (hdrp->dstate == VIO_DESC_READY) {
47222336Snarayan 			ready_txd = B_TRUE;
47234647Sraghuram 		}
47244647Sraghuram 
47254647Sraghuram 	}
47264647Sraghuram 
47274647Sraghuram 	if (ready_txd) {
47284647Sraghuram 		/*
47294647Sraghuram 		 * we have tx descriptor(s) ready to be
47304647Sraghuram 		 * processed by the receiver.
47314647Sraghuram 		 * send a message to the peer with the start index
47324647Sraghuram 		 * of ready descriptors.
47334647Sraghuram 		 */
47344647Sraghuram 		rv = vgen_send_dring_data(ldcp, txi, -1);
47354647Sraghuram 		if (rv != VGEN_SUCCESS) {
47364647Sraghuram 			ldcp->resched_peer = B_TRUE;
47374647Sraghuram 			ldcp->resched_peer_txi = txi;
47384647Sraghuram 			mutex_exit(&ldcp->tclock);
47394647Sraghuram 			mutex_exit(&ldcp->wrlock);
47404647Sraghuram 			return (rv);
47412336Snarayan 		}
47424647Sraghuram 	} else {
47434647Sraghuram 		/*
47444647Sraghuram 		 * no ready tx descriptors. set the flag to send a
47454647Sraghuram 		 * message to peer when tx descriptors are ready in
47464647Sraghuram 		 * transmit routine.
47474647Sraghuram 		 */
47484647Sraghuram 		ldcp->resched_peer = B_TRUE;
47494647Sraghuram 		ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp;
47504647Sraghuram 	}
47514647Sraghuram 
47524647Sraghuram 	mutex_exit(&ldcp->tclock);
47534647Sraghuram 	mutex_exit(&ldcp->wrlock);
47544647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
47554647Sraghuram 	return (rv);
47564647Sraghuram }
47574647Sraghuram 
47584647Sraghuram static int
47594647Sraghuram vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
47604647Sraghuram {
47614647Sraghuram 	int rv = 0;
47624647Sraghuram 	uint32_t start;
47634647Sraghuram 	int32_t end;
47644647Sraghuram 	uint32_t txi;
47654647Sraghuram 	vnet_public_desc_t *txdp;
47664647Sraghuram 	vio_dring_entry_hdr_t *hdrp;
47674647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
47684647Sraghuram 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
47694647Sraghuram #ifdef VGEN_REXMIT
47704647Sraghuram 	vgen_stats_t *statsp = ldcp->statsp;
47714647Sraghuram #endif
47724647Sraghuram 
47734647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
47744647Sraghuram 	start = dringmsg->start_idx;
47754647Sraghuram 	end = dringmsg->end_idx;
47764647Sraghuram 
47774647Sraghuram 	/*
47784647Sraghuram 	 * peer sent a NACK msg to indicate lost packets.
47794647Sraghuram 	 * The start and end correspond to the range of descriptors
47804647Sraghuram 	 * for which the peer didn't receive a dring data msg and so
47814647Sraghuram 	 * didn't receive the corresponding data.
47824647Sraghuram 	 */
47834647Sraghuram 	DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end);
47844647Sraghuram 
47854647Sraghuram 	/* validate start and end indeces in the tx nack msg */
47864647Sraghuram 	if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
47874647Sraghuram 		/* drop the message if invalid index */
47884647Sraghuram 		DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n",
47894647Sraghuram 		    start, end);
47904647Sraghuram 		return (rv);
47914647Sraghuram 	}
47924647Sraghuram 	/* validate dring_ident */
47934647Sraghuram 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
47944647Sraghuram 		/* invalid dring_ident, drop the msg */
47954647Sraghuram 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
47964647Sraghuram 		    dringmsg->dring_ident);
47974647Sraghuram 		return (rv);
47984647Sraghuram 	}
47994647Sraghuram 	mutex_enter(&ldcp->txlock);
48004647Sraghuram 	mutex_enter(&ldcp->tclock);
48014647Sraghuram 
48024647Sraghuram 	if (ldcp->next_tbufp == ldcp->cur_tbufp) {
48034647Sraghuram 		/* no busy descriptors, bogus nack ? */
48042336Snarayan 		mutex_exit(&ldcp->tclock);
48052336Snarayan 		mutex_exit(&ldcp->txlock);
48064647Sraghuram 		return (rv);
48074647Sraghuram 	}
48081991Sheppo 
48091991Sheppo #ifdef VGEN_REXMIT
48104647Sraghuram 	/* send a new dring data msg including the lost descrs */
48114647Sraghuram 	end = ldcp->next_tbufp - ldcp->tbufp;
48124647Sraghuram 	DECR_TXI(end, ldcp);
48134647Sraghuram 	rv = vgen_send_dring_data(ldcp, start, end);
48144647Sraghuram 	if (rv != 0) {
48154647Sraghuram 		/*
48164647Sraghuram 		 * vgen_send_dring_data() error: drop all packets
48174647Sraghuram 		 * in this descr range
48184647Sraghuram 		 */
48194647Sraghuram 		DWARN(vgenp, ldcp, "vgen_send_dring_data failed: rv(%d)\n", rv);
48204647Sraghuram 		for (txi = start; txi <= end; ) {
48214647Sraghuram 			tbufp = &(ldcp->tbufp[txi]);
48224647Sraghuram 			txdp = tbufp->descp;
48234647Sraghuram 			hdrp = &txdp->hdr;
48244647Sraghuram 			tbufp->flags = VGEN_PRIV_DESC_FREE;
48254647Sraghuram 			hdrp->dstate = VIO_DESC_FREE;
48264647Sraghuram 			hdrp->ack = B_FALSE;
48274647Sraghuram 			statsp->oerrors++;
48281991Sheppo 		}
48294647Sraghuram 
48304647Sraghuram 		/* update next pointer */
48314647Sraghuram 		ldcp->next_tbufp = &(ldcp->tbufp[start]);
48324647Sraghuram 		ldcp->next_txi = start;
48334647Sraghuram 	}
48344647Sraghuram 	DBG2(vgenp, ldcp, "rexmit: start(%d) end(%d)\n", start, end);
48351991Sheppo #else	/* VGEN_REXMIT */
48364647Sraghuram 	/* we just mark the descrs as done so they can be reclaimed */
48374647Sraghuram 	for (txi = start; txi <= end; ) {
48384647Sraghuram 		txdp = &(ldcp->txdp[txi]);
48394647Sraghuram 		hdrp = &txdp->hdr;
48404647Sraghuram 		if (hdrp->dstate == VIO_DESC_READY)
48414647Sraghuram 			hdrp->dstate = VIO_DESC_DONE;
48424647Sraghuram 		INCR_TXI(txi, ldcp);
48434647Sraghuram 	}
48441991Sheppo #endif	/* VGEN_REXMIT */
48454647Sraghuram 	mutex_exit(&ldcp->tclock);
48464647Sraghuram 	mutex_exit(&ldcp->txlock);
48474647Sraghuram 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
48482793Slm66018 	return (rv);
48491991Sheppo }
48501991Sheppo 
48511991Sheppo static void
48521991Sheppo vgen_reclaim(vgen_ldc_t *ldcp)
48531991Sheppo {
48542336Snarayan 	mutex_enter(&ldcp->tclock);
48552336Snarayan 
48561991Sheppo 	vgen_reclaim_dring(ldcp);
48571991Sheppo 	ldcp->reclaim_lbolt = ddi_get_lbolt();
48582336Snarayan 
48591991Sheppo 	mutex_exit(&ldcp->tclock);
48601991Sheppo }
48611991Sheppo 
48621991Sheppo /*
48631991Sheppo  * transmit reclaim function. starting from the current reclaim index
48641991Sheppo  * look for descriptors marked DONE and reclaim the descriptor and the
48651991Sheppo  * corresponding buffers (tbuf).
48661991Sheppo  */
48671991Sheppo static void
48681991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp)
48691991Sheppo {
48705022Sraghuram 	int count = 0;
48711991Sheppo 	vnet_public_desc_t *txdp;
48721991Sheppo 	vgen_private_desc_t *tbufp;
48731991Sheppo 	vio_dring_entry_hdr_t	*hdrp;
48742336Snarayan 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
48751991Sheppo 
48761991Sheppo #ifdef DEBUG
48771991Sheppo 	if (vgen_trigger_txtimeout)
48781991Sheppo 		return;
48791991Sheppo #endif
48801991Sheppo 
48811991Sheppo 	tbufp = ldcp->cur_tbufp;
48821991Sheppo 	txdp = tbufp->descp;
48831991Sheppo 	hdrp = &txdp->hdr;
48841991Sheppo 
48851991Sheppo 	while ((hdrp->dstate == VIO_DESC_DONE) &&
48861991Sheppo 	    (tbufp != ldcp->next_tbufp)) {
48871991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
48881991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
48891991Sheppo 		hdrp->ack = B_FALSE;
48901991Sheppo 
48911991Sheppo 		tbufp = NEXTTBUF(ldcp, tbufp);
48921991Sheppo 		txdp = tbufp->descp;
48931991Sheppo 		hdrp = &txdp->hdr;
48945022Sraghuram 		count++;
48951991Sheppo 	}
48961991Sheppo 
48971991Sheppo 	ldcp->cur_tbufp = tbufp;
48981991Sheppo 
48991991Sheppo 	/*
49001991Sheppo 	 * Check if mac layer should be notified to restart transmissions
49011991Sheppo 	 */
49025022Sraghuram 	if ((ldcp->need_resched) && (count > 0)) {
49031991Sheppo 		ldcp->need_resched = B_FALSE;
49042311Sseb 		vnet_tx_update(vgenp->vnetp);
49051991Sheppo 	}
49061991Sheppo }
49071991Sheppo 
49081991Sheppo /* return the number of pending transmits for the channel */
49091991Sheppo static int
49101991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp)
49111991Sheppo {
49121991Sheppo 	int n;
49131991Sheppo 
49141991Sheppo 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
49151991Sheppo 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
49161991Sheppo 	} else  {
49171991Sheppo 		/* cur_tbufp > next_tbufp */
49181991Sheppo 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
49191991Sheppo 	}
49201991Sheppo 
49211991Sheppo 	return (n);
49221991Sheppo }
49231991Sheppo 
49241991Sheppo /* determine if the transmit descriptor ring is full */
49251991Sheppo static int
49261991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp)
49271991Sheppo {
49281991Sheppo 	vgen_private_desc_t	*tbufp;
49291991Sheppo 	vgen_private_desc_t	*ntbufp;
49301991Sheppo 
49311991Sheppo 	tbufp = ldcp->next_tbufp;
49321991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
49331991Sheppo 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
49341991Sheppo 		return (VGEN_SUCCESS);
49351991Sheppo 	}
49361991Sheppo 	return (VGEN_FAILURE);
49371991Sheppo }
49381991Sheppo 
49391991Sheppo /* determine if timeout condition has occured */
49401991Sheppo static int
49411991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
49421991Sheppo {
49431991Sheppo 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
49444650Sraghuram 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
49454650Sraghuram 	    (vnet_ldcwd_txtimeout) &&
49464650Sraghuram 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
49471991Sheppo 		return (VGEN_SUCCESS);
49481991Sheppo 	} else {
49491991Sheppo 		return (VGEN_FAILURE);
49501991Sheppo 	}
49511991Sheppo }
49521991Sheppo 
49531991Sheppo /* transmit watchdog timeout handler */
49541991Sheppo static void
49551991Sheppo vgen_ldc_watchdog(void *arg)
49561991Sheppo {
49571991Sheppo 	vgen_ldc_t *ldcp;
49582336Snarayan 	vgen_t *vgenp;
49591991Sheppo 	int rv;
49601991Sheppo 
49611991Sheppo 	ldcp = (vgen_ldc_t *)arg;
49622336Snarayan 	vgenp = LDC_TO_VGEN(ldcp);
49631991Sheppo 
49641991Sheppo 	rv = vgen_ldc_txtimeout(ldcp);
49651991Sheppo 	if (rv == VGEN_SUCCESS) {
49664647Sraghuram 		DWARN(vgenp, ldcp, "transmit timeout\n");
49671991Sheppo #ifdef DEBUG
49681991Sheppo 		if (vgen_trigger_txtimeout) {
49691991Sheppo 			/* tx timeout triggered for debugging */
49701991Sheppo 			vgen_trigger_txtimeout = 0;
49711991Sheppo 		}
49721991Sheppo #endif
49731991Sheppo 		mutex_enter(&ldcp->cblock);
49742793Slm66018 		ldcp->need_ldc_reset = B_TRUE;
49753653Snarayan 		vgen_handshake_retry(ldcp);
49761991Sheppo 		mutex_exit(&ldcp->cblock);
49771991Sheppo 		if (ldcp->need_resched) {
49781991Sheppo 			ldcp->need_resched = B_FALSE;
49792336Snarayan 			vnet_tx_update(vgenp->vnetp);
49801991Sheppo 		}
49811991Sheppo 	}
49821991Sheppo 
49831991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
49841991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
49851991Sheppo }
49861991Sheppo 
49871991Sheppo static int
49881991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp)
49891991Sheppo {
49901991Sheppo 	vgen_t *vgenp;
49911991Sheppo 	struct kstat *ksp;
49921991Sheppo 	vgen_stats_t *statsp;
49931991Sheppo 	vgen_kstats_t *ldckp;
49941991Sheppo 	int instance;
49951991Sheppo 	size_t size;
49961991Sheppo 	char name[MAXNAMELEN];
49971991Sheppo 
49981991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
49991991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
50001991Sheppo 	(void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id);
50011991Sheppo 	statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
50021991Sheppo 	if (statsp == NULL) {
50031991Sheppo 		return (VGEN_FAILURE);
50041991Sheppo 	}
50051991Sheppo 	size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
50061991Sheppo 	ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
50074650Sraghuram 	    size, 0);
50081991Sheppo 	if (ksp == NULL) {
50091991Sheppo 		KMEM_FREE(statsp);
50101991Sheppo 		return (VGEN_FAILURE);
50111991Sheppo 	}
50121991Sheppo 
50131991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
50141991Sheppo 	kstat_named_init(&ldckp->ipackets,		"ipackets",
50154650Sraghuram 	    KSTAT_DATA_ULONG);
50161991Sheppo 	kstat_named_init(&ldckp->ipackets64,		"ipackets64",
50174650Sraghuram 	    KSTAT_DATA_ULONGLONG);
50181991Sheppo 	kstat_named_init(&ldckp->ierrors,		"ierrors",
50194650Sraghuram 	    KSTAT_DATA_ULONG);
50201991Sheppo 	kstat_named_init(&ldckp->opackets,		"opackets",
50214650Sraghuram 	    KSTAT_DATA_ULONG);
50221991Sheppo 	kstat_named_init(&ldckp->opackets64,		"opackets64",
50234650Sraghuram 	    KSTAT_DATA_ULONGLONG);
50241991Sheppo 	kstat_named_init(&ldckp->oerrors,		"oerrors",
50254650Sraghuram 	    KSTAT_DATA_ULONG);
50261991Sheppo 
50271991Sheppo 
50281991Sheppo 	/* MIB II kstat variables */
50291991Sheppo 	kstat_named_init(&ldckp->rbytes,		"rbytes",
50304650Sraghuram 	    KSTAT_DATA_ULONG);
50311991Sheppo 	kstat_named_init(&ldckp->rbytes64,		"rbytes64",
50324650Sraghuram 	    KSTAT_DATA_ULONGLONG);
50331991Sheppo 	kstat_named_init(&ldckp->obytes,		"obytes",
50344650Sraghuram 	    KSTAT_DATA_ULONG);
50351991Sheppo 	kstat_named_init(&ldckp->obytes64,		"obytes64",
50364650Sraghuram 	    KSTAT_DATA_ULONGLONG);
50371991Sheppo 	kstat_named_init(&ldckp->multircv,		"multircv",
50384650Sraghuram 	    KSTAT_DATA_ULONG);
50391991Sheppo 	kstat_named_init(&ldckp->multixmt,		"multixmt",
50404650Sraghuram 	    KSTAT_DATA_ULONG);
50411991Sheppo 	kstat_named_init(&ldckp->brdcstrcv,		"brdcstrcv",
50424650Sraghuram 	    KSTAT_DATA_ULONG);
50431991Sheppo 	kstat_named_init(&ldckp->brdcstxmt,		"brdcstxmt",
50444650Sraghuram 	    KSTAT_DATA_ULONG);
50451991Sheppo 	kstat_named_init(&ldckp->norcvbuf,		"norcvbuf",
50464650Sraghuram 	    KSTAT_DATA_ULONG);
50471991Sheppo 	kstat_named_init(&ldckp->noxmtbuf,		"noxmtbuf",
50484650Sraghuram 	    KSTAT_DATA_ULONG);
50491991Sheppo 
50501991Sheppo 	/* Tx stats */
50511991Sheppo 	kstat_named_init(&ldckp->tx_no_desc,		"tx_no_desc",
50524650Sraghuram 	    KSTAT_DATA_ULONG);
50531991Sheppo 
50541991Sheppo 	/* Rx stats */
50552336Snarayan 	kstat_named_init(&ldckp->rx_allocb_fail,	"rx_allocb_fail",
50564650Sraghuram 	    KSTAT_DATA_ULONG);
50572336Snarayan 	kstat_named_init(&ldckp->rx_vio_allocb_fail,	"rx_vio_allocb_fail",
50584650Sraghuram 	    KSTAT_DATA_ULONG);
50591991Sheppo 	kstat_named_init(&ldckp->rx_lost_pkts,		"rx_lost_pkts",
50604650Sraghuram 	    KSTAT_DATA_ULONG);
50611991Sheppo 
50621991Sheppo 	/* Interrupt stats */
50631991Sheppo 	kstat_named_init(&ldckp->callbacks,		"callbacks",
50644650Sraghuram 	    KSTAT_DATA_ULONG);
50651991Sheppo 	kstat_named_init(&ldckp->dring_data_acks,	"dring_data_acks",
50664650Sraghuram 	    KSTAT_DATA_ULONG);
50672336Snarayan 	kstat_named_init(&ldckp->dring_stopped_acks,	"dring_stopped_acks",
50684650Sraghuram 	    KSTAT_DATA_ULONG);
50692336Snarayan 	kstat_named_init(&ldckp->dring_data_msgs,	"dring_data_msgs",
50704650Sraghuram 	    KSTAT_DATA_ULONG);
50711991Sheppo 
50721991Sheppo 	ksp->ks_update = vgen_kstat_update;
50731991Sheppo 	ksp->ks_private = (void *)ldcp;
50741991Sheppo 	kstat_install(ksp);
50751991Sheppo 
50761991Sheppo 	ldcp->ksp = ksp;
50771991Sheppo 	ldcp->statsp = statsp;
50781991Sheppo 	return (VGEN_SUCCESS);
50791991Sheppo }
50801991Sheppo 
50811991Sheppo static void
50821991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp)
50831991Sheppo {
50841991Sheppo 	if (ldcp->ksp)
50851991Sheppo 		kstat_delete(ldcp->ksp);
50861991Sheppo 	KMEM_FREE(ldcp->statsp);
50871991Sheppo }
50881991Sheppo 
50891991Sheppo static int
50901991Sheppo vgen_kstat_update(kstat_t *ksp, int rw)
50911991Sheppo {
50921991Sheppo 	vgen_ldc_t *ldcp;
50931991Sheppo 	vgen_stats_t *statsp;
50941991Sheppo 	vgen_kstats_t *ldckp;
50951991Sheppo 
50961991Sheppo 	ldcp = (vgen_ldc_t *)ksp->ks_private;
50971991Sheppo 	statsp = ldcp->statsp;
50981991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
50991991Sheppo 
51001991Sheppo 	if (rw == KSTAT_READ) {
51011991Sheppo 		ldckp->ipackets.value.ul	= (uint32_t)statsp->ipackets;
51021991Sheppo 		ldckp->ipackets64.value.ull	= statsp->ipackets;
51031991Sheppo 		ldckp->ierrors.value.ul		= statsp->ierrors;
51041991Sheppo 		ldckp->opackets.value.ul	= (uint32_t)statsp->opackets;
51051991Sheppo 		ldckp->opackets64.value.ull	= statsp->opackets;
51061991Sheppo 		ldckp->oerrors.value.ul		= statsp->oerrors;
51071991Sheppo 
51081991Sheppo 		/*
51091991Sheppo 		 * MIB II kstat variables
51101991Sheppo 		 */
51111991Sheppo 		ldckp->rbytes.value.ul		= (uint32_t)statsp->rbytes;
51121991Sheppo 		ldckp->rbytes64.value.ull	= statsp->rbytes;
51131991Sheppo 		ldckp->obytes.value.ul		= (uint32_t)statsp->obytes;
51141991Sheppo 		ldckp->obytes64.value.ull	= statsp->obytes;
51151991Sheppo 		ldckp->multircv.value.ul	= statsp->multircv;
51161991Sheppo 		ldckp->multixmt.value.ul	= statsp->multixmt;
51171991Sheppo 		ldckp->brdcstrcv.value.ul	= statsp->brdcstrcv;
51181991Sheppo 		ldckp->brdcstxmt.value.ul	= statsp->brdcstxmt;
51191991Sheppo 		ldckp->norcvbuf.value.ul	= statsp->norcvbuf;
51201991Sheppo 		ldckp->noxmtbuf.value.ul	= statsp->noxmtbuf;
51211991Sheppo 
51221991Sheppo 		ldckp->tx_no_desc.value.ul	= statsp->tx_no_desc;
51232336Snarayan 
51241991Sheppo 		ldckp->rx_allocb_fail.value.ul	= statsp->rx_allocb_fail;
51252336Snarayan 		ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail;
51261991Sheppo 		ldckp->rx_lost_pkts.value.ul	= statsp->rx_lost_pkts;
51271991Sheppo 
51281991Sheppo 		ldckp->callbacks.value.ul	= statsp->callbacks;
51291991Sheppo 		ldckp->dring_data_acks.value.ul	= statsp->dring_data_acks;
51302336Snarayan 		ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks;
51312336Snarayan 		ldckp->dring_data_msgs.value.ul	= statsp->dring_data_msgs;
51321991Sheppo 	} else {
51331991Sheppo 		statsp->ipackets	= ldckp->ipackets64.value.ull;
51341991Sheppo 		statsp->ierrors		= ldckp->ierrors.value.ul;
51351991Sheppo 		statsp->opackets	= ldckp->opackets64.value.ull;
51361991Sheppo 		statsp->oerrors		= ldckp->oerrors.value.ul;
51371991Sheppo 
51381991Sheppo 		/*
51391991Sheppo 		 * MIB II kstat variables
51401991Sheppo 		 */
51411991Sheppo 		statsp->rbytes		= ldckp->rbytes64.value.ull;
51421991Sheppo 		statsp->obytes		= ldckp->obytes64.value.ull;
51431991Sheppo 		statsp->multircv	= ldckp->multircv.value.ul;
51441991Sheppo 		statsp->multixmt	= ldckp->multixmt.value.ul;
51451991Sheppo 		statsp->brdcstrcv	= ldckp->brdcstrcv.value.ul;
51461991Sheppo 		statsp->brdcstxmt	= ldckp->brdcstxmt.value.ul;
51471991Sheppo 		statsp->norcvbuf	= ldckp->norcvbuf.value.ul;
51481991Sheppo 		statsp->noxmtbuf	= ldckp->noxmtbuf.value.ul;
51491991Sheppo 
51501991Sheppo 		statsp->tx_no_desc	= ldckp->tx_no_desc.value.ul;
51512336Snarayan 
51521991Sheppo 		statsp->rx_allocb_fail	= ldckp->rx_allocb_fail.value.ul;
51532336Snarayan 		statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul;
51541991Sheppo 		statsp->rx_lost_pkts	= ldckp->rx_lost_pkts.value.ul;
51551991Sheppo 
51561991Sheppo 		statsp->callbacks	= ldckp->callbacks.value.ul;
51571991Sheppo 		statsp->dring_data_acks	= ldckp->dring_data_acks.value.ul;
51582336Snarayan 		statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul;
51592336Snarayan 		statsp->dring_data_msgs	= ldckp->dring_data_msgs.value.ul;
51601991Sheppo 	}
51611991Sheppo 
51621991Sheppo 	return (VGEN_SUCCESS);
51631991Sheppo }
51641991Sheppo 
51651991Sheppo /* handler for error messages received from the peer ldc end-point */
51661991Sheppo static void
51671991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51681991Sheppo {
51691991Sheppo 	_NOTE(ARGUNUSED(ldcp, tagp))
51701991Sheppo }
51711991Sheppo 
51721991Sheppo /* Check if the session id in the received message is valid */
51731991Sheppo static int
51741991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51751991Sheppo {
51764647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
51774647Sraghuram 
51781991Sheppo 	if (tagp->vio_sid != ldcp->peer_sid) {
51794647Sraghuram 		DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
51804647Sraghuram 		    ldcp->peer_sid, tagp->vio_sid);
51811991Sheppo 		return (VGEN_FAILURE);
51821991Sheppo 	}
51831991Sheppo 	else
51841991Sheppo 		return (VGEN_SUCCESS);
51851991Sheppo }
51861991Sheppo 
51871991Sheppo /* convert mac address from string to uint64_t */
51881991Sheppo static uint64_t
51891991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr)
51901991Sheppo {
51911991Sheppo 	uint64_t val = 0;
51921991Sheppo 	int i;
51931991Sheppo 
51941991Sheppo 	for (i = 0; i < ETHERADDRL; i++) {
51951991Sheppo 		val <<= 8;
51961991Sheppo 		val |= macaddr[i];
51971991Sheppo 	}
51981991Sheppo 
51991991Sheppo 	return (val);
52001991Sheppo }
52011991Sheppo 
52021991Sheppo /* convert mac address from uint64_t to string */
52031991Sheppo static int
52041991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
52051991Sheppo {
52061991Sheppo 	int i;
52071991Sheppo 	uint64_t value;
52081991Sheppo 
52091991Sheppo 	value = val;
52101991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
52111991Sheppo 		macaddr[i] = value & 0xFF;
52121991Sheppo 		value >>= 8;
52131991Sheppo 	}
52141991Sheppo 	return (VGEN_SUCCESS);
52151991Sheppo }
52161991Sheppo 
52171991Sheppo static caddr_t
52181991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf)
52191991Sheppo {
52201991Sheppo 	(void) sprintf(ebuf,
52214650Sraghuram 	    "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
52221991Sheppo 	return (ebuf);
52231991Sheppo }
52241991Sheppo 
52251991Sheppo /* Handshake watchdog timeout handler */
52261991Sheppo static void
52271991Sheppo vgen_hwatchdog(void *arg)
52281991Sheppo {
52291991Sheppo 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
52304647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
52314647Sraghuram 
52324647Sraghuram 	DWARN(vgenp, ldcp,
52334647Sraghuram 	    "handshake timeout ldc(%lx) phase(%x) state(%x)\n",
52344647Sraghuram 	    ldcp->hphase, ldcp->hstate);
52351991Sheppo 
52361991Sheppo 	mutex_enter(&ldcp->cblock);
52373653Snarayan 	if (ldcp->cancel_htid) {
52383653Snarayan 		ldcp->cancel_htid = 0;
52393653Snarayan 		mutex_exit(&ldcp->cblock);
52403653Snarayan 		return;
52413653Snarayan 	}
52421991Sheppo 	ldcp->htid = 0;
52432841Snarayan 	ldcp->need_ldc_reset = B_TRUE;
52441991Sheppo 	vgen_handshake_retry(ldcp);
52451991Sheppo 	mutex_exit(&ldcp->cblock);
52461991Sheppo }
52471991Sheppo 
52481991Sheppo static void
52491991Sheppo vgen_print_hparams(vgen_hparams_t *hp)
52501991Sheppo {
52511991Sheppo 	uint8_t	addr[6];
52521991Sheppo 	char	ea[6];
52531991Sheppo 	ldc_mem_cookie_t *dc;
52541991Sheppo 
52551991Sheppo 	cmn_err(CE_CONT, "version_info:\n");
52561991Sheppo 	cmn_err(CE_CONT,
52571991Sheppo 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
52581991Sheppo 	    hp->ver_major, hp->ver_minor, hp->dev_class);
52591991Sheppo 
52601991Sheppo 	(void) vgen_macaddr_ultostr(hp->addr, addr);
52611991Sheppo 	cmn_err(CE_CONT, "attr_info:\n");
52621991Sheppo 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
52631991Sheppo 	    vgen_print_ethaddr(addr, ea));
52641991Sheppo 	cmn_err(CE_CONT,
52651991Sheppo 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
52661991Sheppo 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
52671991Sheppo 
52681991Sheppo 	dc = &hp->dring_cookie;
52691991Sheppo 	cmn_err(CE_CONT, "dring_info:\n");
52701991Sheppo 	cmn_err(CE_CONT,
52711991Sheppo 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
52721991Sheppo 	cmn_err(CE_CONT,
52731991Sheppo 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
52741991Sheppo 	    dc->addr, dc->size);
52751991Sheppo 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
52761991Sheppo }
52771991Sheppo 
52781991Sheppo static void
52791991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp)
52801991Sheppo {
52811991Sheppo 	vgen_hparams_t *hp;
52821991Sheppo 
52831991Sheppo 	cmn_err(CE_CONT, "Channel Information:\n");
52841991Sheppo 	cmn_err(CE_CONT,
52851991Sheppo 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
52861991Sheppo 	    ldcp->ldc_id, ldcp->ldc_status);
52871991Sheppo 	cmn_err(CE_CONT,
52881991Sheppo 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
52891991Sheppo 	    ldcp->local_sid, ldcp->peer_sid);
52901991Sheppo 	cmn_err(CE_CONT,
52911991Sheppo 	    "\thphase: 0x%x, hstate: 0x%x\n",
52921991Sheppo 	    ldcp->hphase, ldcp->hstate);
52931991Sheppo 
52941991Sheppo 	cmn_err(CE_CONT, "Local handshake params:\n");
52951991Sheppo 	hp = &ldcp->local_hparams;
52961991Sheppo 	vgen_print_hparams(hp);
52971991Sheppo 
52981991Sheppo 	cmn_err(CE_CONT, "Peer handshake params:\n");
52991991Sheppo 	hp = &ldcp->peer_hparams;
53001991Sheppo 	vgen_print_hparams(hp);
53011991Sheppo }
53024647Sraghuram 
53034647Sraghuram /*
53044647Sraghuram  * vgen_ldc_queue_data -- Queue data in the LDC.
53054647Sraghuram  */
53064647Sraghuram static void
53074647Sraghuram vgen_ldc_queue_data(vgen_ldc_t *ldcp, mblk_t *rhead, mblk_t *rtail)
53084647Sraghuram {
53094647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
53104647Sraghuram 
53114647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
53124647Sraghuram 	/*
53134647Sraghuram 	 * If the receive thread is enabled, then the queue
53144647Sraghuram 	 * is protected by the soft_lock. After queuing, trigger
53154647Sraghuram 	 * the soft interrupt so that the interrupt handler sends these
53164647Sraghuram 	 * messages up the stack.
53174647Sraghuram 	 *
53184647Sraghuram 	 * If the receive thread is not enabled, then the list is
53194647Sraghuram 	 * automatically protected by the cblock lock, so no need
53204647Sraghuram 	 * to hold any additional locks.
53214647Sraghuram 	 */
53224647Sraghuram 	if (ldcp->rcv_thread != NULL) {
53234647Sraghuram 		mutex_enter(&ldcp->soft_lock);
53244647Sraghuram 	}
53254647Sraghuram 	if (ldcp->rcv_mhead == NULL) {
53264647Sraghuram 		ldcp->rcv_mhead = rhead;
53274647Sraghuram 		ldcp->rcv_mtail = rtail;
53284647Sraghuram 	} else {
53294647Sraghuram 		ldcp->rcv_mtail->b_next = rhead;
53304647Sraghuram 		ldcp->rcv_mtail = rtail;
53314647Sraghuram 	}
53324647Sraghuram 	if (ldcp->rcv_thread != NULL) {
53334647Sraghuram 		mutex_exit(&ldcp->soft_lock);
53344647Sraghuram 		(void) ddi_intr_trigger_softint(ldcp->soft_handle, NULL);
53354647Sraghuram 	}
53364647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
53374647Sraghuram }
53384647Sraghuram 
53394647Sraghuram /*
53404647Sraghuram  * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data.
53414647Sraghuram  * This thread is woken up by the LDC interrupt handler to process
53424647Sraghuram  * LDC packets and receive data.
53434647Sraghuram  */
53444647Sraghuram static void
53454647Sraghuram vgen_ldc_rcv_worker(void *arg)
53464647Sraghuram {
53474647Sraghuram 	callb_cpr_t	cprinfo;
53484647Sraghuram 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
53494647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
53504647Sraghuram 
53514647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
53524647Sraghuram 	CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr,
53534650Sraghuram 	    "vnet_rcv_thread");
53544647Sraghuram 	mutex_enter(&ldcp->rcv_thr_lock);
53554647Sraghuram 	ldcp->rcv_thr_flags |= VGEN_WTHR_RUNNING;
53564647Sraghuram 	while (!(ldcp->rcv_thr_flags & VGEN_WTHR_STOP)) {
53574647Sraghuram 
53584647Sraghuram 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
53594647Sraghuram 		/*
53604647Sraghuram 		 * Wait until the data is received or a stop
53614647Sraghuram 		 * request is received.
53624647Sraghuram 		 */
53634647Sraghuram 		while (!(ldcp->rcv_thr_flags &
53644647Sraghuram 		    (VGEN_WTHR_DATARCVD | VGEN_WTHR_STOP))) {
53654647Sraghuram 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
53664647Sraghuram 		}
53674647Sraghuram 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock)
53684647Sraghuram 
53694647Sraghuram 		/*
53704647Sraghuram 		 * First process the stop request.
53714647Sraghuram 		 */
53724647Sraghuram 		if (ldcp->rcv_thr_flags & VGEN_WTHR_STOP) {
53734647Sraghuram 			DBG2(vgenp, ldcp, "stopped\n");
53744647Sraghuram 			break;
53754647Sraghuram 		}
53764647Sraghuram 		ldcp->rcv_thr_flags &= ~VGEN_WTHR_DATARCVD;
53774647Sraghuram 		mutex_exit(&ldcp->rcv_thr_lock);
53784647Sraghuram 		DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n");
53794647Sraghuram 		vgen_handle_evt_read(ldcp);
53804647Sraghuram 		mutex_enter(&ldcp->rcv_thr_lock);
53814647Sraghuram 	}
53824647Sraghuram 
53834647Sraghuram 	/*
53844647Sraghuram 	 * Update the run status and wakeup the thread that
53854647Sraghuram 	 * has sent the stop request.
53864647Sraghuram 	 */
53874647Sraghuram 	ldcp->rcv_thr_flags &= ~VGEN_WTHR_RUNNING;
53884647Sraghuram 	cv_signal(&ldcp->rcv_thr_cv);
53894647Sraghuram 	CALLB_CPR_EXIT(&cprinfo);
53904647Sraghuram 	thread_exit();
53914647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
53924647Sraghuram }
53934647Sraghuram 
53944647Sraghuram /* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */
53954647Sraghuram static void
53964647Sraghuram vgen_stop_rcv_thread(vgen_ldc_t *ldcp)
53974647Sraghuram {
53984647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
53994647Sraghuram 
54004647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
54014647Sraghuram 	/*
54024647Sraghuram 	 * Send a stop request by setting the stop flag and
54034647Sraghuram 	 * wait until the receive thread stops.
54044647Sraghuram 	 */
54054647Sraghuram 	mutex_enter(&ldcp->rcv_thr_lock);
54064647Sraghuram 	if (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) {
54074647Sraghuram 		ldcp->rcv_thr_flags |= VGEN_WTHR_STOP;
54084647Sraghuram 		cv_signal(&ldcp->rcv_thr_cv);
54094647Sraghuram 		DBG2(vgenp, ldcp, "waiting...");
54104647Sraghuram 		while (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) {
54114647Sraghuram 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
54124647Sraghuram 		}
54134647Sraghuram 	}
54144647Sraghuram 	mutex_exit(&ldcp->rcv_thr_lock);
54154647Sraghuram 	ldcp->rcv_thread = NULL;
54164647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
54174647Sraghuram }
54184647Sraghuram 
54194647Sraghuram /*
54204647Sraghuram  * vgen_ldc_rcv_softintr -- LDC Soft interrupt handler function.
54214647Sraghuram  * Its job is to pickup the recieved packets that are queued in the
54224647Sraghuram  * LDC and send them up.
54234647Sraghuram  *
54244647Sraghuram  * NOTE: An interrupt handler is being used to handle the upper
54254647Sraghuram  * layer(s) requirement to send up only at interrupt context.
54264647Sraghuram  */
54274647Sraghuram /* ARGSUSED */
54284647Sraghuram static uint_t
54294647Sraghuram vgen_ldc_rcv_softintr(caddr_t arg1, caddr_t arg2)
54304647Sraghuram {
54314647Sraghuram 	mblk_t *mp;
54324647Sraghuram 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1;
54334647Sraghuram 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
54344647Sraghuram 
54354647Sraghuram 	DBG1(vgenp, ldcp, "enter\n");
54364647Sraghuram 	DTRACE_PROBE1(vgen_soft_intr, uint64_t, ldcp->ldc_id);
54374647Sraghuram 	mutex_enter(&ldcp->soft_lock);
54384647Sraghuram 	mp = ldcp->rcv_mhead;
54394647Sraghuram 	ldcp->rcv_mhead = ldcp->rcv_mtail = NULL;
54404647Sraghuram 	mutex_exit(&ldcp->soft_lock);
54414647Sraghuram 	if (mp != NULL) {
54424647Sraghuram 		vnet_rx(vgenp->vnetp, NULL, mp);
54434647Sraghuram 	}
54444647Sraghuram 	DBG1(vgenp, ldcp, "exit\n");
54454647Sraghuram 	return (DDI_INTR_CLAIMED);
54464647Sraghuram }
54474647Sraghuram 
54484647Sraghuram #if DEBUG
54494647Sraghuram 
54504647Sraghuram /*
54514647Sraghuram  * Print debug messages - set to 0xf to enable all msgs
54524647Sraghuram  */
54534647Sraghuram static void
54544647Sraghuram debug_printf(const char *fname, vgen_t *vgenp,
54554647Sraghuram     vgen_ldc_t *ldcp, const char *fmt, ...)
54564647Sraghuram {
54574647Sraghuram 	char    buf[256];
54584647Sraghuram 	char    *bufp = buf;
54594647Sraghuram 	va_list ap;
54604647Sraghuram 
54614647Sraghuram 	if ((vgenp != NULL) && (vgenp->vnetp != NULL)) {
54624647Sraghuram 		(void) sprintf(bufp, "vnet%d:",
54634650Sraghuram 		    ((vnet_t *)(vgenp->vnetp))->instance);
54644647Sraghuram 		bufp += strlen(bufp);
54654647Sraghuram 	}
54664647Sraghuram 	if (ldcp != NULL) {
54674647Sraghuram 		(void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id);
54684647Sraghuram 		bufp += strlen(bufp);
54694647Sraghuram 	}
54704647Sraghuram 	(void) sprintf(bufp, "%s: ", fname);
54714647Sraghuram 	bufp += strlen(bufp);
54724647Sraghuram 
54734647Sraghuram 	va_start(ap, fmt);
54744647Sraghuram 	(void) vsprintf(bufp, fmt, ap);
54754647Sraghuram 	va_end(ap);
54764647Sraghuram 
54774647Sraghuram 	if ((ldcp == NULL) ||(vgendbg_ldcid == -1) ||
54784647Sraghuram 	    (vgendbg_ldcid == ldcp->ldc_id)) {
54794647Sraghuram 		cmn_err(CE_CONT, "%s\n", buf);
54804647Sraghuram 	}
54814647Sraghuram }
54824647Sraghuram #endif
5483