xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_gen.c (revision 3653:b023d36e83d9)
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 /*
23*3653Snarayan  * 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>
331991Sheppo #include <sys/kmem.h>
341991Sheppo #include <sys/conf.h>
351991Sheppo #include <sys/devops.h>
361991Sheppo #include <sys/ksynch.h>
371991Sheppo #include <sys/stat.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/ddi.h>
421991Sheppo #include <sys/sunddi.h>
431991Sheppo #include <sys/strsun.h>
441991Sheppo #include <sys/note.h>
451991Sheppo #include <sys/mac.h>
462311Sseb #include <sys/mac_ether.h>
471991Sheppo #include <sys/ldc.h>
481991Sheppo #include <sys/mach_descrip.h>
491991Sheppo #include <sys/mdeg.h>
501991Sheppo #include <sys/vio_mailbox.h>
511991Sheppo #include <sys/vio_common.h>
521991Sheppo #include <sys/vnet_common.h>
532336Snarayan #include <sys/vnet_mailbox.h>
542336Snarayan #include <sys/vio_util.h>
551991Sheppo #include <sys/vnet_gen.h>
561991Sheppo 
571991Sheppo /*
581991Sheppo  * Implementation of the mac functionality for vnet using the
591991Sheppo  * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
601991Sheppo  */
611991Sheppo 
621991Sheppo /*
631991Sheppo  * Function prototypes.
641991Sheppo  */
651991Sheppo /* vgen proxy entry points */
662311Sseb int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
672311Sseb 	mac_register_t **vgenmacp);
682336Snarayan int vgen_uninit(void *arg);
691991Sheppo static int vgen_start(void *arg);
701991Sheppo static void vgen_stop(void *arg);
711991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
721991Sheppo static int vgen_multicst(void *arg, boolean_t add,
731991Sheppo 	const uint8_t *mca);
741991Sheppo static int vgen_promisc(void *arg, boolean_t on);
751991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
762311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
771991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp);
781991Sheppo 
791991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */
801991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
811991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
822793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx,
832793Slm66018 	void *txarg, boolean_t upgrade);
841991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
851991Sheppo void vnet_del_def_rte(void *arg);
862311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
872311Sseb void vnet_tx_update(void *arg);
881991Sheppo 
891991Sheppo /* vgen internal functions */
901991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
911991Sheppo static void vgen_port_detach(vgen_port_t *portp);
921991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
931991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
941991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
951991Sheppo 	int port_num);
961991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
971991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
981991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
991991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1001991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1011991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1021991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port);
1031991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp);
1041991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1051991Sheppo 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
1062311Sseb static uint64_t	vgen_port_stat(vgen_port_t *portp, uint_t stat);
1071991Sheppo 
1081991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1091991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1101991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp);
1111991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp);
1121991Sheppo static void vgen_init_ports(vgen_t *vgenp);
1131991Sheppo static void vgen_port_init(vgen_port_t *portp);
1141991Sheppo static void vgen_uninit_ports(vgen_t *vgenp);
1151991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1161991Sheppo static void vgen_init_ldcs(vgen_port_t *portp);
1171991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp);
1181991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1191991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
1201991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp);
1211991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp);
1221991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp);
1231991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp);
1242311Sseb static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
1251991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
1261991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1271991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp);
1281991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp);
1291991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp);
1301991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp);
1311991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp);
1321991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp);
1331991Sheppo static void vgen_ldc_watchdog(void *arg);
1341991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp);
1351991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp);
1361991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw);
1371991Sheppo 
1381991Sheppo /* vgen handshake functions */
1391991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
1401991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
1411991Sheppo 	uint16_t ver_minor);
1421991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp);
1431991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
1441991Sheppo 	boolean_t caller_holds_lock);
1451991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1461991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
1471991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp);
1481991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
1492336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1501991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1511991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
1521991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp);
1531991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp);
1541991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp);
1551991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp);
1561991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp);
1572793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1581991Sheppo 	vio_msg_tag_t *tagp);
1592793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1602793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1612793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1622793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1632793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1642793Slm66018 static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1651991Sheppo 	mblk_t **headp, mblk_t **tailp);
1662793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1672336Snarayan 	uint32_t start, int32_t end, uint8_t pstate);
1682793Slm66018 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1691991Sheppo 	mblk_t **headp, mblk_t **tailp);
1701991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1712793Slm66018 static void vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag);
1722793Slm66018 static void vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag);
1731991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1741991Sheppo static uint64_t	vgen_macaddr_strtoul(const uint8_t *macaddr);
1751991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr);
1761991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
1771991Sheppo static void vgen_hwatchdog(void *arg);
1781991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
1791991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp);
1801991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp);
1811991Sheppo 
1821991Sheppo /*
1831991Sheppo  * The handshake process consists of 5 phases defined below, with VH_PHASE0
1841991Sheppo  * being the pre-handshake phase and VH_DONE is the phase to indicate
1851991Sheppo  * successful completion of all phases.
1861991Sheppo  * Each phase may have one to several handshake states which are required
1871991Sheppo  * to complete successfully to move to the next phase.
1881991Sheppo  * Refer to the functions vgen_handshake() and vgen_handshake_done() for
1891991Sheppo  * more details.
1901991Sheppo  */
1911991Sheppo /* handshake phases */
1921991Sheppo enum {	VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
1931991Sheppo 
1941991Sheppo /* handshake states */
1951991Sheppo enum {
1961991Sheppo 
1971991Sheppo 	VER_INFO_SENT	=	0x1,
1981991Sheppo 	VER_ACK_RCVD	=	0x2,
1991991Sheppo 	VER_INFO_RCVD	=	0x4,
2001991Sheppo 	VER_ACK_SENT	=	0x8,
2011991Sheppo 	VER_NEGOTIATED	=	(VER_ACK_RCVD | VER_ACK_SENT),
2021991Sheppo 
2031991Sheppo 	ATTR_INFO_SENT	=	0x10,
2041991Sheppo 	ATTR_ACK_RCVD	=	0x20,
2051991Sheppo 	ATTR_INFO_RCVD	=	0x40,
2061991Sheppo 	ATTR_ACK_SENT	=	0x80,
2071991Sheppo 	ATTR_INFO_EXCHANGED	=	(ATTR_ACK_RCVD | ATTR_ACK_SENT),
2081991Sheppo 
2091991Sheppo 	DRING_INFO_SENT	=	0x100,
2101991Sheppo 	DRING_ACK_RCVD	=	0x200,
2111991Sheppo 	DRING_INFO_RCVD	=	0x400,
2121991Sheppo 	DRING_ACK_SENT	=	0x800,
2131991Sheppo 	DRING_INFO_EXCHANGED	=	(DRING_ACK_RCVD | DRING_ACK_SENT),
2141991Sheppo 
2151991Sheppo 	RDX_INFO_SENT	=	0x1000,
2161991Sheppo 	RDX_ACK_RCVD	=	0x2000,
2171991Sheppo 	RDX_INFO_RCVD	=	0x4000,
2181991Sheppo 	RDX_ACK_SENT	=	0x8000,
2191991Sheppo 	RDX_EXCHANGED	=	(RDX_ACK_RCVD | RDX_ACK_SENT)
2201991Sheppo 
2211991Sheppo };
2221991Sheppo 
2231991Sheppo #define	LDC_LOCK(ldcp)	\
2241991Sheppo 				mutex_enter(&((ldcp)->cblock));\
2251991Sheppo 				mutex_enter(&((ldcp)->txlock));\
2261991Sheppo 				mutex_enter(&((ldcp)->tclock));
2271991Sheppo #define	LDC_UNLOCK(ldcp)	\
2281991Sheppo 				mutex_exit(&((ldcp)->tclock));\
2291991Sheppo 				mutex_exit(&((ldcp)->txlock));\
2301991Sheppo 				mutex_exit(&((ldcp)->cblock));
2311991Sheppo 
2321991Sheppo static struct ether_addr etherbroadcastaddr = {
2331991Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2341991Sheppo };
2351991Sheppo /*
2361991Sheppo  * MIB II broadcast/multicast packets
2371991Sheppo  */
2381991Sheppo #define	IS_BROADCAST(ehp) \
2391991Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
2401991Sheppo #define	IS_MULTICAST(ehp) \
2411991Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
2421991Sheppo 
2431991Sheppo /*
2441991Sheppo  * Property names
2451991Sheppo  */
2461991Sheppo static char macaddr_propname[] = "mac-address";
2471991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2481991Sheppo static char channel_propname[] = "channel-endpoint";
2491991Sheppo static char reg_propname[] = "reg";
2501991Sheppo static char port_propname[] = "port";
2511991Sheppo static char swport_propname[] = "switch-port";
2521991Sheppo static char id_propname[] = "id";
2531991Sheppo 
2541991Sheppo /* versions supported - in decreasing order */
2551991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} };
2561991Sheppo 
2571991Sheppo /* Tunables */
2581991Sheppo uint32_t vgen_hwd_interval = 1000;	/* handshake watchdog freq in msec */
2593297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */
2601991Sheppo uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
2612109Slm66018 uint32_t vgen_ldcup_retries = 5;	/* max # of ldc_up() retries */
2622336Snarayan uint32_t vgen_recv_delay = 1;		/* delay when rx descr not ready */
2632336Snarayan uint32_t vgen_recv_retries = 10;	/* retry when rx descr not ready */
2641991Sheppo 
2651991Sheppo #ifdef DEBUG
2661991Sheppo /* flags to simulate error conditions for debugging */
2671991Sheppo int vgen_trigger_txtimeout = 0;
2681991Sheppo int vgen_trigger_rxlost = 0;
2691991Sheppo #endif
2701991Sheppo 
2711991Sheppo /* MD update matching structure */
2721991Sheppo static md_prop_match_t	vport_prop_match[] = {
2731991Sheppo 	{ MDET_PROP_VAL,	"id" },
2741991Sheppo 	{ MDET_LIST_END,	NULL }
2751991Sheppo };
2761991Sheppo 
2771991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
2781991Sheppo 					vport_prop_match };
2791991Sheppo 
2801991Sheppo /* template for matching a particular vnet instance */
2811991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
2821991Sheppo 	{ MDET_PROP_STR,	"name",		"network" },
2831991Sheppo 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
2841991Sheppo 	{ MDET_LIST_END,	NULL,		NULL }
2851991Sheppo };
2861991Sheppo 
2871991Sheppo #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
2881991Sheppo 
2891991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
2901991Sheppo 
2912311Sseb static mac_callbacks_t vgen_m_callbacks = {
2922311Sseb 	0,
2932311Sseb 	vgen_stat,
2942311Sseb 	vgen_start,
2952311Sseb 	vgen_stop,
2962311Sseb 	vgen_promisc,
2972311Sseb 	vgen_multicst,
2982311Sseb 	vgen_unicst,
2992311Sseb 	vgen_tx,
3002311Sseb 	NULL,
3012311Sseb 	NULL,
3022311Sseb 	NULL
3032311Sseb };
3042311Sseb 
3051991Sheppo /* externs */
3061991Sheppo extern uint32_t vnet_ntxds;
3071991Sheppo extern uint32_t vnet_ldcwd_interval;
3081991Sheppo extern uint32_t vnet_ldcwd_txtimeout;
3092410Slm66018 extern uint32_t vnet_ldc_mtu;
3102336Snarayan extern uint32_t vnet_nrbufs;
3111991Sheppo extern int _vnet_dbglevel;
3121991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...);
3131991Sheppo 
3141991Sheppo #ifdef DEBUG
3151991Sheppo 
3161991Sheppo /*
3172793Slm66018  * NOTE: definitions below need to be in sync with those in vnet.c
3181991Sheppo  */
3191991Sheppo 
3201991Sheppo /*
3211991Sheppo  * debug levels:
3221991Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
3231991Sheppo  * DBG_LEVEL2:	Info messages
3241991Sheppo  * DBG_LEVEL3:	Warning messages
3251991Sheppo  * DBG_LEVEL4:	Error messages
3261991Sheppo  */
3271991Sheppo 
3281991Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
3291991Sheppo 	    DBG_LEVEL4 = 0x08 };
3301991Sheppo 
3311991Sheppo #define	DBG1(_s)	do {						\
3321991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
3331991Sheppo 					_vnetdebug_printf _s;		\
3341991Sheppo 			    }					\
3351991Sheppo 			_NOTE(CONSTCOND) } while (0)
3361991Sheppo 
3371991Sheppo #define	DBG2(_s)	do {						\
3381991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
3391991Sheppo 					_vnetdebug_printf _s;		\
3401991Sheppo 			    }					\
3411991Sheppo 			_NOTE(CONSTCOND) } while (0)
3421991Sheppo 
3431991Sheppo #define	DWARN(_s)	do {						\
3441991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
3451991Sheppo 					_vnetdebug_printf _s;		\
3461991Sheppo 			    }					\
3471991Sheppo 			_NOTE(CONSTCOND) } while (0)
3481991Sheppo 
3491991Sheppo #define	DERR(_s)	do {						\
3501991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
3511991Sheppo 					_vnetdebug_printf _s;		\
3521991Sheppo 			    }					\
3531991Sheppo 			_NOTE(CONSTCOND) } while (0)
3541991Sheppo 
3551991Sheppo #else
3561991Sheppo 
3571991Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
3581991Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
3591991Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
3601991Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
3611991Sheppo 
3621991Sheppo #endif
3631991Sheppo 
3641991Sheppo #ifdef DEBUG
3651991Sheppo 
3661991Sheppo /* simulate handshake error conditions for debug */
3671991Sheppo uint32_t vgen_hdbg;
3681991Sheppo #define	HDBG_VERSION	0x1
3691991Sheppo #define	HDBG_TIMEOUT	0x2
3701991Sheppo #define	HDBG_BAD_SID	0x4
3711991Sheppo #define	HDBG_OUT_STATE	0x8
3721991Sheppo 
3731991Sheppo #endif
3741991Sheppo 
3752336Snarayan 
3761991Sheppo 
3771991Sheppo /*
3781991Sheppo  * vgen_init() is called by an instance of vnet driver to initialize the
3791991Sheppo  * corresponding generic proxy transport layer. The arguments passed by vnet
3801991Sheppo  * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
3812311Sseb  * the mac address of the vnet device, and a pointer to mac_register_t of
3822311Sseb  * the generic transport is returned in the last argument.
3831991Sheppo  */
3841991Sheppo int
3852311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
3862311Sseb     mac_register_t **vgenmacp)
3871991Sheppo {
3881991Sheppo 	vgen_t *vgenp;
3892311Sseb 	mac_register_t *macp;
3901991Sheppo 	int instance;
3911991Sheppo 
3922311Sseb 	if ((vnetp == NULL) || (vnetdip == NULL))
3931991Sheppo 		return (DDI_FAILURE);
3941991Sheppo 
3951991Sheppo 	instance = ddi_get_instance(vnetdip);
3961991Sheppo 
3971991Sheppo 	DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance));
3981991Sheppo 
3991991Sheppo 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
4001991Sheppo 
4011991Sheppo 	vgenp->vnetp = vnetp;
4021991Sheppo 	vgenp->vnetdip = vnetdip;
4031991Sheppo 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
4041991Sheppo 
4052311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4062311Sseb 		KMEM_FREE(vgenp);
4072311Sseb 		return (DDI_FAILURE);
4082311Sseb 	}
4092311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4102311Sseb 	macp->m_driver = vgenp;
4112311Sseb 	macp->m_dip = vnetdip;
4122311Sseb 	macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
4132311Sseb 	macp->m_callbacks = &vgen_m_callbacks;
4142311Sseb 	macp->m_min_sdu = 0;
4152311Sseb 	macp->m_max_sdu = ETHERMTU;
4162311Sseb 	vgenp->macp = macp;
4172311Sseb 
4181991Sheppo 	/* allocate multicast table */
4191991Sheppo 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
4201991Sheppo 	    sizeof (struct ether_addr), KM_SLEEP);
4211991Sheppo 	vgenp->mccount = 0;
4221991Sheppo 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
4231991Sheppo 
4241991Sheppo 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
4251991Sheppo 
4261991Sheppo 	/* register with MD event generator */
4271991Sheppo 	if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) {
4281991Sheppo 		mutex_destroy(&vgenp->lock);
4291991Sheppo 		kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
4301991Sheppo 		    sizeof (struct ether_addr));
4312311Sseb 		mac_free(vgenp->macp);
4321991Sheppo 		KMEM_FREE(vgenp);
4331991Sheppo 		return (DDI_FAILURE);
4341991Sheppo 	}
4351991Sheppo 
4362311Sseb 	/* register macp of this vgen_t with vnet */
4372311Sseb 	*vgenmacp = vgenp->macp;
4381991Sheppo 
4391991Sheppo 	DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance));
4401991Sheppo 	return (DDI_SUCCESS);
4411991Sheppo }
4421991Sheppo 
4431991Sheppo /*
4441991Sheppo  * Called by vnet to undo the initializations done by vgen_init().
4451991Sheppo  * The handle provided by generic transport during vgen_init() is the argument.
4461991Sheppo  */
4472336Snarayan int
4481991Sheppo vgen_uninit(void *arg)
4491991Sheppo {
4501991Sheppo 	vgen_t	*vgenp = (vgen_t *)arg;
4511991Sheppo 	void	*vnetp;
4521991Sheppo 	int instance;
4532336Snarayan 	vio_mblk_pool_t *rp, *nrp;
4542336Snarayan 
4552336Snarayan 	if (vgenp == NULL) {
4562336Snarayan 		return (DDI_FAILURE);
4572336Snarayan 	}
4581991Sheppo 
4591991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
4601991Sheppo 	vnetp = vgenp->vnetp;
4611991Sheppo 
4621991Sheppo 	DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance));
4631991Sheppo 
4641991Sheppo 	/* unregister with MD event generator */
4651991Sheppo 	vgen_mdeg_unreg(vgenp);
4661991Sheppo 
4671991Sheppo 	mutex_enter(&vgenp->lock);
4681991Sheppo 
4691991Sheppo 	/* detach all ports from the device */
4701991Sheppo 	vgen_detach_ports(vgenp);
4711991Sheppo 
4722336Snarayan 	/*
4732336Snarayan 	 * free any pending rx mblk pools,
4742336Snarayan 	 * that couldn't be freed previously during channel detach.
4752336Snarayan 	 */
4762336Snarayan 	rp = vgenp->rmp;
4772336Snarayan 	while (rp != NULL) {
4782336Snarayan 		nrp = vgenp->rmp = rp->nextp;
4792336Snarayan 		if (vio_destroy_mblks(rp)) {
4802336Snarayan 			vgenp->rmp = rp;
4812336Snarayan 			mutex_exit(&vgenp->lock);
4822336Snarayan 			return (DDI_FAILURE);
4832336Snarayan 		}
4842336Snarayan 		rp = nrp;
4852336Snarayan 	}
4862336Snarayan 
4871991Sheppo 	/* free multicast table */
4881991Sheppo 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
4891991Sheppo 
4902311Sseb 	mac_free(vgenp->macp);
4912311Sseb 
4921991Sheppo 	mutex_exit(&vgenp->lock);
4931991Sheppo 
4941991Sheppo 	mutex_destroy(&vgenp->lock);
4951991Sheppo 
4961991Sheppo 	KMEM_FREE(vgenp);
4971991Sheppo 
4981991Sheppo 	DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance));
4992336Snarayan 
5002336Snarayan 	return (DDI_SUCCESS);
5011991Sheppo }
5021991Sheppo 
5031991Sheppo /* enable transmit/receive for the device */
5042311Sseb int
5051991Sheppo vgen_start(void *arg)
5061991Sheppo {
5071991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5081991Sheppo 
5091991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: enter\n"));
5101991Sheppo 
5111991Sheppo 	mutex_enter(&vgenp->lock);
5121991Sheppo 	vgen_init_ports(vgenp);
5131991Sheppo 	vgenp->flags |= VGEN_STARTED;
5141991Sheppo 	mutex_exit(&vgenp->lock);
5151991Sheppo 
5161991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: exit\n"));
5171991Sheppo 	return (DDI_SUCCESS);
5181991Sheppo }
5191991Sheppo 
5201991Sheppo /* stop transmit/receive */
5212311Sseb void
5221991Sheppo vgen_stop(void *arg)
5231991Sheppo {
5241991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5251991Sheppo 
5261991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: enter\n"));
5271991Sheppo 
5281991Sheppo 	mutex_enter(&vgenp->lock);
5291991Sheppo 	vgen_uninit_ports(vgenp);
5301991Sheppo 	vgenp->flags &= ~(VGEN_STARTED);
5311991Sheppo 	mutex_exit(&vgenp->lock);
5321991Sheppo 
5331991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: exit\n"));
5341991Sheppo }
5351991Sheppo 
5361991Sheppo /* vgen transmit function */
5371991Sheppo static mblk_t *
5381991Sheppo vgen_tx(void *arg, mblk_t *mp)
5391991Sheppo {
5401991Sheppo 	vgen_port_t *portp;
5411991Sheppo 	int status;
5421991Sheppo 
5431991Sheppo 	portp = (vgen_port_t *)arg;
5441991Sheppo 	status = vgen_portsend(portp, mp);
5451991Sheppo 	if (status != VGEN_SUCCESS) {
5461991Sheppo 		/* failure */
5471991Sheppo 		return (mp);
5481991Sheppo 	}
5491991Sheppo 	/* success */
5501991Sheppo 	return (NULL);
5511991Sheppo }
5521991Sheppo 
5531991Sheppo /* transmit packets over the given port */
5541991Sheppo static int
5551991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
5561991Sheppo {
5571991Sheppo 	vgen_ldclist_t	*ldclp;
5581991Sheppo 	vgen_ldc_t *ldcp;
5591991Sheppo 	int status;
5601991Sheppo 
5611991Sheppo 	ldclp = &portp->ldclist;
5621991Sheppo 	READ_ENTER(&ldclp->rwlock);
5631991Sheppo 	/*
5642336Snarayan 	 * NOTE: for now, we will assume we have a single channel.
5651991Sheppo 	 */
5661991Sheppo 	if (ldclp->headp == NULL) {
5671991Sheppo 		RW_EXIT(&ldclp->rwlock);
5681991Sheppo 		return (VGEN_FAILURE);
5691991Sheppo 	}
5701991Sheppo 	ldcp = ldclp->headp;
5711991Sheppo 
5721991Sheppo 	if (ldcp->need_resched) {
5731991Sheppo 		/* out of tx resources, see vgen_ldcsend() for details. */
5741991Sheppo 		mutex_enter(&ldcp->txlock);
5751991Sheppo 		ldcp->statsp->tx_no_desc++;
5761991Sheppo 		mutex_exit(&ldcp->txlock);
5771991Sheppo 
5781991Sheppo 		RW_EXIT(&ldclp->rwlock);
5792336Snarayan 		return (VGEN_FAILURE);
5801991Sheppo 	}
5811991Sheppo 
5821991Sheppo 	status  = vgen_ldcsend(ldcp, mp);
5831991Sheppo 	RW_EXIT(&ldclp->rwlock);
5841991Sheppo 
5851991Sheppo 	if (status != VGEN_TX_SUCCESS)
5861991Sheppo 		return (VGEN_FAILURE);
5871991Sheppo 
5881991Sheppo 	return (VGEN_SUCCESS);
5891991Sheppo }
5901991Sheppo 
5911991Sheppo /* channel transmit function */
5921991Sheppo static int
5931991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp)
5941991Sheppo {
5951991Sheppo 	void		*vnetp;
5961991Sheppo 	size_t		size;
5972793Slm66018 	int		rv = 0;
5982336Snarayan 	uint64_t	tbuf_ix;
5991991Sheppo 	vgen_private_desc_t	*tbufp;
6001991Sheppo 	vgen_private_desc_t	*ntbufp;
6011991Sheppo 	vnet_public_desc_t	*txdp;
6021991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
6031991Sheppo 	vgen_stats_t		*statsp;
6041991Sheppo 	struct ether_header	*ehp;
6051991Sheppo 	boolean_t	is_bcast = B_FALSE;
6061991Sheppo 	boolean_t	is_mcast = B_FALSE;
6072336Snarayan 	size_t		mblksz;
6082336Snarayan 	caddr_t		dst;
6092336Snarayan 	mblk_t		*bp;
6102793Slm66018 	ldc_status_t	istatus;
6111991Sheppo 
6121991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
6131991Sheppo 	statsp = ldcp->statsp;
6142109Slm66018 	size = msgsize(mp);
6152109Slm66018 
6161991Sheppo 	DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id));
6171991Sheppo 
6182109Slm66018 	mutex_enter(&ldcp->txlock);
6192109Slm66018 
6202109Slm66018 	/* drop the packet if ldc is not up or handshake is not done */
6212109Slm66018 	if (ldcp->ldc_status != LDC_UP) {
6221991Sheppo 		DWARN((vnetp,
6231991Sheppo 		    "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
6241991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
6252109Slm66018 		/* retry ldc_up() if needed */
6262109Slm66018 		if (ldcp->flags & CHANNEL_STARTED)
6272109Slm66018 			(void) ldc_up(ldcp->ldc_handle);
6282109Slm66018 		goto vgen_tx_exit;
6291991Sheppo 	}
6301991Sheppo 
6312109Slm66018 	if (ldcp->hphase != VH_DONE) {
6322109Slm66018 		DWARN((vnetp,
6332109Slm66018 		    "vgen_ldcsend: id(%lx) hphase(%x), dropping packet\n",
6342109Slm66018 		    ldcp->ldc_id, ldcp->hphase));
6352109Slm66018 		goto vgen_tx_exit;
6362109Slm66018 	}
6372109Slm66018 
6381991Sheppo 	if (size > (size_t)ETHERMAX) {
6391991Sheppo 		DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n",
6401991Sheppo 		    ldcp->ldc_id, size));
6411991Sheppo 		goto vgen_tx_exit;
6421991Sheppo 	}
6431991Sheppo 
6441991Sheppo 	/*
6451991Sheppo 	 * allocate a descriptor
6461991Sheppo 	 */
6471991Sheppo 	tbufp = ldcp->next_tbufp;
6481991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
6492336Snarayan 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
6501991Sheppo 
6511991Sheppo 		mutex_enter(&ldcp->tclock);
6522336Snarayan 		if (ntbufp == ldcp->cur_tbufp) {
6531991Sheppo 			ldcp->need_resched = B_TRUE;
6542336Snarayan 			mutex_exit(&ldcp->tclock);
6552336Snarayan 
6562336Snarayan 			statsp->tx_no_desc++;
6572336Snarayan 			mutex_exit(&ldcp->txlock);
6582336Snarayan 
6592336Snarayan 			return (VGEN_TX_NORESOURCES);
6602336Snarayan 		}
6611991Sheppo 		mutex_exit(&ldcp->tclock);
6621991Sheppo 	}
6631991Sheppo 
6642109Slm66018 	if (size < ETHERMIN)
6652109Slm66018 		size = ETHERMIN;
6662109Slm66018 
6672109Slm66018 	/* copy data into pre-allocated transmit buffer */
6682336Snarayan 	dst = tbufp->datap + VNET_IPALIGN;
6692336Snarayan 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
6702336Snarayan 		mblksz = MBLKL(bp);
6712336Snarayan 		bcopy(bp->b_rptr, dst, mblksz);
6722336Snarayan 		dst += mblksz;
6731991Sheppo 	}
6741991Sheppo 
6752336Snarayan 	tbuf_ix = tbufp - ldcp->tbufp;
6761991Sheppo 
6772109Slm66018 	ehp = (struct ether_header *)tbufp->datap;
6781991Sheppo 	is_bcast = IS_BROADCAST(ehp);
6791991Sheppo 	is_mcast = IS_MULTICAST(ehp);
6802109Slm66018 
6811991Sheppo 	tbufp->flags = VGEN_PRIV_DESC_BUSY;
6822109Slm66018 	tbufp->datalen = size;
6831991Sheppo 
6841991Sheppo 	/* initialize the corresponding public descriptor (txd) */
6851991Sheppo 	txdp = tbufp->descp;
6861991Sheppo 	hdrp = &txdp->hdr;
6872109Slm66018 	txdp->nbytes = size;
6882109Slm66018 	txdp->ncookies = tbufp->ncookies;
6891991Sheppo 	bcopy((tbufp->memcookie), (txdp->memcookie),
6902336Snarayan 		tbufp->ncookies * sizeof (ldc_mem_cookie_t));
6912336Snarayan 	hdrp->dstate = VIO_DESC_READY;
6921991Sheppo 
6931991Sheppo 	/* send dring datamsg to the peer */
6942336Snarayan 	if (ldcp->resched_peer) {
6952336Snarayan 		rv = vgen_send_dring_data(ldcp, (uint32_t)tbuf_ix, -1);
6962336Snarayan 		if (rv != 0) {
6972336Snarayan 			/* vgen_send_dring_data() error: drop the packet */
6982336Snarayan 			DWARN((vnetp,
6992336Snarayan 			    "vgen_ldcsend: vgen_send_dring_data():  failed: "
7002336Snarayan 			    "id(%lx) rv(%d) len (%d)\n",
7012336Snarayan 			    ldcp->ldc_id, rv, size));
7022336Snarayan 			tbufp->flags = VGEN_PRIV_DESC_FREE;	/* free tbuf */
7032336Snarayan 			hdrp->dstate = VIO_DESC_FREE;	/* free txd */
7042336Snarayan 			hdrp->ack = B_FALSE;
7052336Snarayan 			statsp->oerrors++;
7062336Snarayan 			goto vgen_tx_exit;
7072336Snarayan 		}
7082336Snarayan 		ldcp->resched_peer = B_FALSE;
7091991Sheppo 	}
7101991Sheppo 
7111991Sheppo 	/* update next available tbuf in the ring */
7121991Sheppo 	ldcp->next_tbufp = ntbufp;
7132336Snarayan 
7142336Snarayan 	/* update tx index */
7151991Sheppo 	INCR_TXI(ldcp->next_txi, ldcp);
7161991Sheppo 
7171991Sheppo 	/* update stats */
7181991Sheppo 	statsp->opackets++;
7192109Slm66018 	statsp->obytes += size;
7201991Sheppo 	if (is_bcast)
7211991Sheppo 		statsp->brdcstxmt++;
7221991Sheppo 	else if (is_mcast)
7231991Sheppo 		statsp->multixmt++;
7241991Sheppo 
7251991Sheppo vgen_tx_exit:
7261991Sheppo 	mutex_exit(&ldcp->txlock);
7271991Sheppo 
7282793Slm66018 	if (rv == ECONNRESET) {
7292793Slm66018 		/*
7302793Slm66018 		 * Check if either callback thread or another tx thread is
7312793Slm66018 		 * already running. Calling mutex_enter() will result in a
7322793Slm66018 		 * deadlock if the other thread already holds cblock and is
7332793Slm66018 		 * blocked in vnet_modify_fdb() (which is called from
7342793Slm66018 		 * vgen_handle_evt_reset()) waiting for write access on rwlock,
7352793Slm66018 		 * as this transmit thread already holds that lock as a reader
7362793Slm66018 		 * in vnet_m_tx(). See comments in vnet_modify_fdb() in vnet.c.
7372793Slm66018 		 */
7382793Slm66018 		if (mutex_tryenter(&ldcp->cblock)) {
7392793Slm66018 			if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
7402793Slm66018 				DWARN((vnetp,
7412793Slm66018 				    "vgen_ldcsend: ldc_status err id(%lx)\n"));
7422793Slm66018 			} else {
7432793Slm66018 				ldcp->ldc_status = istatus;
7442793Slm66018 			}
7452793Slm66018 			if (ldcp->ldc_status != LDC_UP) {
7462793Slm66018 				/*
7472793Slm66018 				 * Second arg is TRUE, as we know that
7482793Slm66018 				 * the caller of this function - vnet_m_tx(),
7492793Slm66018 				 * already holds fdb-rwlock as a reader.
7502793Slm66018 				 */
7512793Slm66018 				vgen_handle_evt_reset(ldcp, B_TRUE);
7522793Slm66018 			}
7532793Slm66018 			mutex_exit(&ldcp->cblock);
7542793Slm66018 		}
7552793Slm66018 	}
7562793Slm66018 
7571991Sheppo 	DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id));
7581991Sheppo 
7592109Slm66018 	freemsg(mp);
7602109Slm66018 	return (VGEN_TX_SUCCESS);
7611991Sheppo }
7621991Sheppo 
7631991Sheppo /* enable/disable a multicast address */
7642311Sseb int
7651991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
7661991Sheppo {
7671991Sheppo 	vgen_t			*vgenp;
7681991Sheppo 	vnet_mcast_msg_t	mcastmsg;
7691991Sheppo 	vio_msg_tag_t		*tagp;
7701991Sheppo 	vgen_port_t		*portp;
7711991Sheppo 	vgen_portlist_t		*plistp;
7721991Sheppo 	vgen_ldc_t		*ldcp;
7731991Sheppo 	vgen_ldclist_t		*ldclp;
7741991Sheppo 	void			*vnetp;
7751991Sheppo 	struct ether_addr	*addrp;
776*3653Snarayan 	int			rv = DDI_FAILURE;
7771991Sheppo 	uint32_t		i;
7781991Sheppo 
7791991Sheppo 	vgenp = (vgen_t *)arg;
7801991Sheppo 	vnetp = vgenp->vnetp;
7811991Sheppo 	addrp = (struct ether_addr *)mca;
7821991Sheppo 	tagp = &mcastmsg.tag;
7831991Sheppo 	bzero(&mcastmsg, sizeof (mcastmsg));
7841991Sheppo 
7851991Sheppo 	mutex_enter(&vgenp->lock);
7861991Sheppo 
7871991Sheppo 	plistp = &(vgenp->vgenports);
7881991Sheppo 
7891991Sheppo 	READ_ENTER(&plistp->rwlock);
7901991Sheppo 
7911991Sheppo 	portp = vgenp->vsw_portp;
7921991Sheppo 	if (portp == NULL) {
7931991Sheppo 		RW_EXIT(&plistp->rwlock);
794*3653Snarayan 		mutex_exit(&vgenp->lock);
795*3653Snarayan 		return (rv);
7961991Sheppo 	}
7971991Sheppo 	ldclp = &portp->ldclist;
7981991Sheppo 
7991991Sheppo 	READ_ENTER(&ldclp->rwlock);
8001991Sheppo 
8011991Sheppo 	ldcp = ldclp->headp;
802*3653Snarayan 	if (ldcp == NULL)
8031991Sheppo 		goto vgen_mcast_exit;
8041991Sheppo 
8051991Sheppo 	mutex_enter(&ldcp->cblock);
8061991Sheppo 
8071991Sheppo 	if (ldcp->hphase == VH_DONE) {
8081991Sheppo 		/*
8091991Sheppo 		 * If handshake is done, send a msg to vsw to add/remove
8101991Sheppo 		 * the multicast address.
8111991Sheppo 		 */
8121991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
8131991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
8141991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
8151991Sheppo 		tagp->vio_sid = ldcp->local_sid;
8161991Sheppo 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
8171991Sheppo 		mcastmsg.set = add;
8181991Sheppo 		mcastmsg.count = 1;
819*3653Snarayan 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
820*3653Snarayan 		    B_FALSE) != VGEN_SUCCESS) {
8211991Sheppo 			DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed"
8221991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
823*3653Snarayan 			mutex_exit(&ldcp->cblock);
824*3653Snarayan 			goto vgen_mcast_exit;
8251991Sheppo 		}
8261991Sheppo 	} else {
8271991Sheppo 		/* set the flag to send a msg to vsw after handshake is done */
8281991Sheppo 		ldcp->need_mcast_sync = B_TRUE;
8291991Sheppo 	}
8301991Sheppo 
8311991Sheppo 	mutex_exit(&ldcp->cblock);
8321991Sheppo 
8331991Sheppo 	if (add) {
8341991Sheppo 
8351991Sheppo 		/* expand multicast table if necessary */
8361991Sheppo 		if (vgenp->mccount >= vgenp->mcsize) {
8371991Sheppo 			struct ether_addr	*newtab;
8381991Sheppo 			uint32_t		newsize;
8391991Sheppo 
8401991Sheppo 
8411991Sheppo 			newsize = vgenp->mcsize * 2;
8421991Sheppo 
8431991Sheppo 			newtab = kmem_zalloc(newsize *
8441991Sheppo 			    sizeof (struct ether_addr), KM_NOSLEEP);
845*3653Snarayan 			if (newtab == NULL)
846*3653Snarayan 				goto vgen_mcast_exit;
8471991Sheppo 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
8481991Sheppo 			    sizeof (struct ether_addr));
8491991Sheppo 			kmem_free(vgenp->mctab,
8501991Sheppo 			    vgenp->mcsize * sizeof (struct ether_addr));
8511991Sheppo 
8521991Sheppo 			vgenp->mctab = newtab;
8531991Sheppo 			vgenp->mcsize = newsize;
8541991Sheppo 		}
8551991Sheppo 
8561991Sheppo 		/* add address to the table */
8571991Sheppo 		vgenp->mctab[vgenp->mccount++] = *addrp;
8581991Sheppo 
8591991Sheppo 	} else {
8601991Sheppo 
8611991Sheppo 		/* delete address from the table */
8621991Sheppo 		for (i = 0; i < vgenp->mccount; i++) {
8631991Sheppo 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
8641991Sheppo 
8651991Sheppo 				/*
8661991Sheppo 				 * If there's more than one address in this
8671991Sheppo 				 * table, delete the unwanted one by moving
8681991Sheppo 				 * the last one in the list over top of it;
8691991Sheppo 				 * otherwise, just remove it.
8701991Sheppo 				 */
8711991Sheppo 				if (vgenp->mccount > 1) {
8721991Sheppo 					vgenp->mctab[i] =
8731991Sheppo 						vgenp->mctab[vgenp->mccount-1];
8741991Sheppo 				}
8751991Sheppo 				vgenp->mccount--;
8761991Sheppo 				break;
8771991Sheppo 			}
8781991Sheppo 		}
8791991Sheppo 	}
8801991Sheppo 
881*3653Snarayan 	rv = DDI_SUCCESS;
882*3653Snarayan 
883*3653Snarayan vgen_mcast_exit:
8841991Sheppo 	RW_EXIT(&ldclp->rwlock);
8851991Sheppo 	RW_EXIT(&plistp->rwlock);
8861991Sheppo 
8871991Sheppo 	mutex_exit(&vgenp->lock);
888*3653Snarayan 	return (rv);
8891991Sheppo }
8901991Sheppo 
8911991Sheppo /* set or clear promiscuous mode on the device */
8921991Sheppo static int
8931991Sheppo vgen_promisc(void *arg, boolean_t on)
8941991Sheppo {
8951991Sheppo 	_NOTE(ARGUNUSED(arg, on))
8961991Sheppo 	return (DDI_SUCCESS);
8971991Sheppo }
8981991Sheppo 
8991991Sheppo /* set the unicast mac address of the device */
9001991Sheppo static int
9011991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
9021991Sheppo {
9031991Sheppo 	_NOTE(ARGUNUSED(arg, mca))
9041991Sheppo 	return (DDI_SUCCESS);
9051991Sheppo }
9061991Sheppo 
9071991Sheppo /* get device statistics */
9082311Sseb int
9092311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
9101991Sheppo {
9111991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
9121991Sheppo 	vgen_port_t	*portp;
9131991Sheppo 	vgen_portlist_t	*plistp;
9142311Sseb 
9152311Sseb 	*val = 0;
9161991Sheppo 
9171991Sheppo 	plistp = &(vgenp->vgenports);
9181991Sheppo 	READ_ENTER(&plistp->rwlock);
9191991Sheppo 
9201991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
9212311Sseb 		*val += vgen_port_stat(portp, stat);
9221991Sheppo 	}
9231991Sheppo 
9241991Sheppo 	RW_EXIT(&plistp->rwlock);
9251991Sheppo 
9262311Sseb 	return (0);
9271991Sheppo }
9281991Sheppo 
9291991Sheppo static void
9301991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp)
9311991Sheppo {
9321991Sheppo 	 _NOTE(ARGUNUSED(arg, wq, mp))
9331991Sheppo }
9341991Sheppo 
9351991Sheppo /* vgen internal functions */
9361991Sheppo /* detach all ports from the device */
9371991Sheppo static void
9381991Sheppo vgen_detach_ports(vgen_t *vgenp)
9391991Sheppo {
9401991Sheppo 	vgen_port_t	*portp;
9411991Sheppo 	vgen_portlist_t	*plistp;
9421991Sheppo 
9431991Sheppo 	plistp = &(vgenp->vgenports);
9441991Sheppo 	WRITE_ENTER(&plistp->rwlock);
9451991Sheppo 
9461991Sheppo 	while ((portp = plistp->headp) != NULL) {
9471991Sheppo 		vgen_port_detach(portp);
9481991Sheppo 	}
9491991Sheppo 
9501991Sheppo 	RW_EXIT(&plistp->rwlock);
9511991Sheppo }
9521991Sheppo 
9531991Sheppo /*
9541991Sheppo  * detach the given port.
9551991Sheppo  */
9561991Sheppo static void
9571991Sheppo vgen_port_detach(vgen_port_t *portp)
9581991Sheppo {
9591991Sheppo 	vgen_t		*vgenp;
9601991Sheppo 	vgen_ldclist_t	*ldclp;
9611991Sheppo 	int		port_num;
9621991Sheppo 
9631991Sheppo 	vgenp = portp->vgenp;
9641991Sheppo 	port_num = portp->port_num;
9651991Sheppo 
9661991Sheppo 	DBG1((vgenp->vnetp,
9671991Sheppo 	    "vgen_port_detach: enter: port_num(%d)\n", port_num));
9681991Sheppo 
9691991Sheppo 	/* remove it from port list */
9701991Sheppo 	vgen_port_list_remove(portp);
9711991Sheppo 
9721991Sheppo 	/* detach channels from this port */
9731991Sheppo 	ldclp = &portp->ldclist;
9741991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
9751991Sheppo 	while (ldclp->headp) {
9761991Sheppo 		vgen_ldc_detach(ldclp->headp);
9771991Sheppo 	}
9781991Sheppo 	RW_EXIT(&ldclp->rwlock);
9791991Sheppo 
9801991Sheppo 	if (vgenp->vsw_portp == portp) {
9811991Sheppo 		vgenp->vsw_portp = NULL;
9821991Sheppo 	}
9831991Sheppo 	KMEM_FREE(portp);
9841991Sheppo 
9851991Sheppo 	DBG1((vgenp->vnetp,
9861991Sheppo 	    "vgen_port_detach: exit: port_num(%d)\n", port_num));
9871991Sheppo }
9881991Sheppo 
9891991Sheppo /* add a port to port list */
9901991Sheppo static void
9911991Sheppo vgen_port_list_insert(vgen_port_t *portp)
9921991Sheppo {
9931991Sheppo 	vgen_portlist_t *plistp;
9941991Sheppo 	vgen_t *vgenp;
9951991Sheppo 
9961991Sheppo 	vgenp = portp->vgenp;
9971991Sheppo 	plistp = &(vgenp->vgenports);
9981991Sheppo 
9991991Sheppo 	if (plistp->headp == NULL) {
10001991Sheppo 		plistp->headp = portp;
10011991Sheppo 	} else {
10021991Sheppo 		plistp->tailp->nextp = portp;
10031991Sheppo 	}
10041991Sheppo 	plistp->tailp = portp;
10051991Sheppo 	portp->nextp = NULL;
10061991Sheppo }
10071991Sheppo 
10081991Sheppo /* remove a port from port list */
10091991Sheppo static void
10101991Sheppo vgen_port_list_remove(vgen_port_t *portp)
10111991Sheppo {
10121991Sheppo 	vgen_port_t *prevp;
10131991Sheppo 	vgen_port_t *nextp;
10141991Sheppo 	vgen_portlist_t *plistp;
10151991Sheppo 	vgen_t *vgenp;
10161991Sheppo 
10171991Sheppo 	vgenp = portp->vgenp;
10181991Sheppo 
10191991Sheppo 	plistp = &(vgenp->vgenports);
10201991Sheppo 
10211991Sheppo 	if (plistp->headp == NULL)
10221991Sheppo 		return;
10231991Sheppo 
10241991Sheppo 	if (portp == plistp->headp) {
10251991Sheppo 		plistp->headp = portp->nextp;
10261991Sheppo 		if (portp == plistp->tailp)
10271991Sheppo 			plistp->tailp = plistp->headp;
10281991Sheppo 	} else {
10291991Sheppo 		for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) &&
10301991Sheppo 		    (nextp != portp); prevp = nextp);
10311991Sheppo 		if (nextp == portp) {
10321991Sheppo 			prevp->nextp = portp->nextp;
10331991Sheppo 		}
10341991Sheppo 		if (portp == plistp->tailp)
10351991Sheppo 			plistp->tailp = prevp;
10361991Sheppo 	}
10371991Sheppo }
10381991Sheppo 
10391991Sheppo /* lookup a port in the list based on port_num */
10401991Sheppo static vgen_port_t *
10411991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
10421991Sheppo {
10431991Sheppo 	vgen_port_t *portp = NULL;
10441991Sheppo 
10451991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10461991Sheppo 		if (portp->port_num == port_num) {
10471991Sheppo 			break;
10481991Sheppo 		}
10491991Sheppo 	}
10501991Sheppo 
10511991Sheppo 	return (portp);
10521991Sheppo }
10531991Sheppo 
10541991Sheppo /* enable ports for transmit/receive */
10551991Sheppo static void
10561991Sheppo vgen_init_ports(vgen_t *vgenp)
10571991Sheppo {
10581991Sheppo 	vgen_port_t	*portp;
10591991Sheppo 	vgen_portlist_t	*plistp;
10601991Sheppo 
10611991Sheppo 	plistp = &(vgenp->vgenports);
10621991Sheppo 	READ_ENTER(&plistp->rwlock);
10631991Sheppo 
10641991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10651991Sheppo 		vgen_port_init(portp);
10661991Sheppo 	}
10671991Sheppo 
10681991Sheppo 	RW_EXIT(&plistp->rwlock);
10691991Sheppo }
10701991Sheppo 
10711991Sheppo static void
10721991Sheppo vgen_port_init(vgen_port_t *portp)
10731991Sheppo {
10741991Sheppo 	vgen_t *vgenp;
10751991Sheppo 
10761991Sheppo 	vgenp = portp->vgenp;
10771991Sheppo 	/*
10781991Sheppo 	 * Create fdb entry in vnet, corresponding to the mac
10791991Sheppo 	 * address of this port. Note that the port specified
10801991Sheppo 	 * is vsw-port. This is done so that vsw-port acts
10811991Sheppo 	 * as the route to reach this macaddr, until the
10821991Sheppo 	 * channel for this port comes up (LDC_UP) and
10831991Sheppo 	 * handshake is done successfully.
10841991Sheppo 	 * eg, if the peer is OBP-vnet, it may not bring the
10851991Sheppo 	 * channel up for this port and may communicate via
10861991Sheppo 	 * vsw to reach this port.
10871991Sheppo 	 * Later, when Solaris-vnet comes up at the other end
10881991Sheppo 	 * of the channel for this port and brings up the channel,
10891991Sheppo 	 * it is an indication that peer vnet is capable of
10901991Sheppo 	 * distributed switching, so the direct route through this
10911991Sheppo 	 * port is specified in fdb, using vnet_modify_fdb(macaddr);
10921991Sheppo 	 */
10931991Sheppo 	vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr,
10941991Sheppo 	    vgen_tx, vgenp->vsw_portp);
10951991Sheppo 
10961991Sheppo 	if (portp == vgenp->vsw_portp) {
10971991Sheppo 		/*
10981991Sheppo 		 * create the default route entry in vnet's fdb.
10991991Sheppo 		 * This is the entry used by vnet to reach
11001991Sheppo 		 * unknown destinations, which basically goes
11011991Sheppo 		 * through vsw on domain0 and out through the
11021991Sheppo 		 * physical device bound to vsw.
11031991Sheppo 		 */
11041991Sheppo 		vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp);
11051991Sheppo 	}
11061991Sheppo 
11071991Sheppo 	/* Bring up the channels of this port */
11081991Sheppo 	vgen_init_ldcs(portp);
11091991Sheppo }
11101991Sheppo 
11111991Sheppo /* disable transmit/receive on ports */
11121991Sheppo static void
11131991Sheppo vgen_uninit_ports(vgen_t *vgenp)
11141991Sheppo {
11151991Sheppo 	vgen_port_t	*portp;
11161991Sheppo 	vgen_portlist_t	*plistp;
11171991Sheppo 
11181991Sheppo 	plistp = &(vgenp->vgenports);
11191991Sheppo 	READ_ENTER(&plistp->rwlock);
11201991Sheppo 
11211991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
11221991Sheppo 		vgen_port_uninit(portp);
11231991Sheppo 	}
11241991Sheppo 
11251991Sheppo 	RW_EXIT(&plistp->rwlock);
11261991Sheppo }
11271991Sheppo 
11281991Sheppo static void
11291991Sheppo vgen_port_uninit(vgen_port_t *portp)
11301991Sheppo {
11311991Sheppo 	vgen_t *vgenp;
11321991Sheppo 
11331991Sheppo 	vgenp = portp->vgenp;
11341991Sheppo 
11351991Sheppo 	vgen_uninit_ldcs(portp);
11361991Sheppo 	/* delete the entry in vnet's fdb for this port */
11371991Sheppo 	vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr);
11381991Sheppo 	if (portp == vgenp->vsw_portp) {
11391991Sheppo 		/*
11401991Sheppo 		 * if this is vsw-port, then delete the default
11411991Sheppo 		 * route entry in vnet's fdb.
11421991Sheppo 		 */
11431991Sheppo 		vnet_del_def_rte(vgenp->vnetp);
11441991Sheppo 	}
11451991Sheppo }
11461991Sheppo 
11471991Sheppo /* register with MD event generator */
11481991Sheppo static int
11491991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
11501991Sheppo {
11511991Sheppo 	mdeg_prop_spec_t	*pspecp;
11521991Sheppo 	mdeg_node_spec_t	*parentp;
11531991Sheppo 	uint_t			templatesz;
11541991Sheppo 	int			rv;
11551991Sheppo 	mdeg_handle_t		hdl;
11561991Sheppo 	int			i;
11571991Sheppo 	void			*vnetp = vgenp->vnetp;
11581991Sheppo 
11591991Sheppo 	i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip,
11601991Sheppo 			DDI_PROP_DONTPASS, reg_propname, -1);
11611991Sheppo 	if (i == -1) {
11621991Sheppo 		return (DDI_FAILURE);
11631991Sheppo 	}
11641991Sheppo 	templatesz = sizeof (vgen_prop_template);
11651991Sheppo 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
11661991Sheppo 	if (pspecp == NULL) {
11671991Sheppo 		return (DDI_FAILURE);
11681991Sheppo 	}
11691991Sheppo 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
11701991Sheppo 	if (parentp == NULL) {
11711991Sheppo 		kmem_free(pspecp, templatesz);
11721991Sheppo 		return (DDI_FAILURE);
11731991Sheppo 	}
11741991Sheppo 
11751991Sheppo 	bcopy(vgen_prop_template, pspecp, templatesz);
11761991Sheppo 
11771991Sheppo 	/*
11781991Sheppo 	 * NOTE: The instance here refers to the value of "reg" property and
11791991Sheppo 	 * not the dev_info instance (ddi_get_instance()) of vnet.
11801991Sheppo 	 */
11811991Sheppo 	VGEN_SET_MDEG_PROP_INST(pspecp, i);
11821991Sheppo 
11831991Sheppo 	parentp->namep = "virtual-device";
11841991Sheppo 	parentp->specp = pspecp;
11851991Sheppo 
11861991Sheppo 	/* save parentp in vgen_t */
11871991Sheppo 	vgenp->mdeg_parentp = parentp;
11881991Sheppo 
11891991Sheppo 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl);
11901991Sheppo 	if (rv != MDEG_SUCCESS) {
11911991Sheppo 		DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n"));
11921991Sheppo 		KMEM_FREE(parentp);
11931991Sheppo 		kmem_free(pspecp, templatesz);
11941991Sheppo 		vgenp->mdeg_parentp = NULL;
11951991Sheppo 		return (DDI_FAILURE);
11961991Sheppo 	}
11971991Sheppo 
11981991Sheppo 	/* save mdeg handle in vgen_t */
11991991Sheppo 	vgenp->mdeg_hdl = hdl;
12001991Sheppo 
12011991Sheppo 	return (DDI_SUCCESS);
12021991Sheppo }
12031991Sheppo 
12041991Sheppo /* unregister with MD event generator */
12051991Sheppo static void
12061991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
12071991Sheppo {
12081991Sheppo 	(void) mdeg_unregister(vgenp->mdeg_hdl);
12093297Ssb155480 	kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template));
12101991Sheppo 	KMEM_FREE(vgenp->mdeg_parentp);
12111991Sheppo 	vgenp->mdeg_parentp = NULL;
12121991Sheppo 	vgenp->mdeg_hdl = NULL;
12131991Sheppo }
12141991Sheppo 
12151991Sheppo /* callback function registered with MD event generator */
12161991Sheppo static int
12171991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
12181991Sheppo {
12191991Sheppo 	int idx;
12201991Sheppo 	int vsw_idx = -1;
12211991Sheppo 	uint64_t val;
12221991Sheppo 	vgen_t *vgenp;
12231991Sheppo 
12241991Sheppo 	if ((resp == NULL) || (cb_argp == NULL)) {
12251991Sheppo 		return (MDEG_FAILURE);
12261991Sheppo 	}
12271991Sheppo 
12281991Sheppo 	vgenp = (vgen_t *)cb_argp;
12291991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n"));
12301991Sheppo 
12311991Sheppo 	mutex_enter(&vgenp->lock);
12321991Sheppo 
12331991Sheppo 	DBG1((vgenp->vnetp,
12341991Sheppo 	    "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n",
12351991Sheppo 	    resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem));
12361991Sheppo 
12371991Sheppo 	for (idx = 0; idx < resp->removed.nelem; idx++) {
12381991Sheppo 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
12391991Sheppo 		    resp->removed.mdep[idx]);
12401991Sheppo 	}
12411991Sheppo 
12421991Sheppo 	if (vgenp->vsw_portp == NULL) {
12431991Sheppo 		/*
12441991Sheppo 		 * find vsw_port and add it first, because other ports need
12451991Sheppo 		 * this when adding fdb entry (see vgen_port_init()).
12461991Sheppo 		 */
12471991Sheppo 		for (idx = 0; idx < resp->added.nelem; idx++) {
12481991Sheppo 			if (!(md_get_prop_val(resp->added.mdp,
12491991Sheppo 			    resp->added.mdep[idx], swport_propname, &val))) {
12501991Sheppo 				if (val == 0) {
12511991Sheppo 					/*
12521991Sheppo 					 * This port is connected to the
12531991Sheppo 					 * vsw on dom0.
12541991Sheppo 					 */
12551991Sheppo 					vsw_idx = idx;
12561991Sheppo 					(void) vgen_add_port(vgenp,
12571991Sheppo 					    resp->added.mdp,
12581991Sheppo 					    resp->added.mdep[idx]);
12591991Sheppo 					break;
12601991Sheppo 				}
12611991Sheppo 			}
12621991Sheppo 		}
12631991Sheppo 		if (vsw_idx == -1) {
12641991Sheppo 			DWARN((vgenp->vnetp, "vgen_mdeg_cb: "
12651991Sheppo 			    "can't find vsw_port\n"));
12661991Sheppo 			return (MDEG_FAILURE);
12671991Sheppo 		}
12681991Sheppo 	}
12691991Sheppo 
12701991Sheppo 	for (idx = 0; idx < resp->added.nelem; idx++) {
12711991Sheppo 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
12721991Sheppo 			continue;
12731991Sheppo 		(void) vgen_add_port(vgenp, resp->added.mdp,
12741991Sheppo 		    resp->added.mdep[idx]);
12751991Sheppo 	}
12761991Sheppo 
12771991Sheppo 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
12781991Sheppo 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
12791991Sheppo 		    resp->match_curr.mdep[idx],
12801991Sheppo 		    resp->match_prev.mdp,
12811991Sheppo 		    resp->match_prev.mdep[idx]);
12821991Sheppo 	}
12831991Sheppo 
12841991Sheppo 	mutex_exit(&vgenp->lock);
12851991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n"));
12861991Sheppo 	return (MDEG_SUCCESS);
12871991Sheppo }
12881991Sheppo 
12891991Sheppo /* add a new port to the device */
12901991Sheppo static int
12911991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
12921991Sheppo {
12931991Sheppo 	uint64_t	port_num;
12941991Sheppo 	uint64_t	*ldc_ids;
12951991Sheppo 	uint64_t	macaddr;
12961991Sheppo 	uint64_t	val;
12971991Sheppo 	int		num_ldcs;
12981991Sheppo 	int		vsw_port = B_FALSE;
12991991Sheppo 	int		i;
13001991Sheppo 	int		addrsz;
13011991Sheppo 	int		num_nodes = 0;
13021991Sheppo 	int		listsz = 0;
13031991Sheppo 	mde_cookie_t	*listp = NULL;
13041991Sheppo 	uint8_t		*addrp;
13051991Sheppo 	struct ether_addr	ea;
13061991Sheppo 
13071991Sheppo 	/* read "id" property to get the port number */
13081991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
13091991Sheppo 		DWARN((vgenp->vnetp,
13101991Sheppo 		    "vgen_add_port: prop(%s) not found\n", id_propname));
13111991Sheppo 		return (DDI_FAILURE);
13121991Sheppo 	}
13131991Sheppo 
13141991Sheppo 	/*
13151991Sheppo 	 * Find the channel endpoint node(s) under this port node.
13161991Sheppo 	 */
13171991Sheppo 	if ((num_nodes = md_node_count(mdp)) <= 0) {
13181991Sheppo 		DWARN((vgenp->vnetp,
13191991Sheppo 		    "vgen_add_port: invalid number of nodes found (%d)",
13201991Sheppo 		    num_nodes));
13211991Sheppo 		return (DDI_FAILURE);
13221991Sheppo 	}
13231991Sheppo 
13241991Sheppo 	/* allocate space for node list */
13251991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
13261991Sheppo 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
13271991Sheppo 	if (listp == NULL)
13281991Sheppo 		return (DDI_FAILURE);
13291991Sheppo 
13301991Sheppo 	num_ldcs = md_scan_dag(mdp, mdex,
13311991Sheppo 		md_find_name(mdp, channel_propname),
13321991Sheppo 		md_find_name(mdp, "fwd"), listp);
13331991Sheppo 
13341991Sheppo 	if (num_ldcs <= 0) {
13351991Sheppo 		DWARN((vgenp->vnetp,
13361991Sheppo 		    "vgen_add_port: can't find %s nodes", channel_propname));
13371991Sheppo 		kmem_free(listp, listsz);
13381991Sheppo 		return (DDI_FAILURE);
13391991Sheppo 	}
13401991Sheppo 
13411991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs));
13421991Sheppo 
13431991Sheppo 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
13441991Sheppo 	if (ldc_ids == NULL) {
13451991Sheppo 		kmem_free(listp, listsz);
13461991Sheppo 		return (DDI_FAILURE);
13471991Sheppo 	}
13481991Sheppo 
13491991Sheppo 	for (i = 0; i < num_ldcs; i++) {
13501991Sheppo 		/* read channel ids */
13511991Sheppo 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
13521991Sheppo 			DWARN((vgenp->vnetp,
13531991Sheppo 			    "vgen_add_port: prop(%s) not found\n",
13541991Sheppo 			    id_propname));
13551991Sheppo 			kmem_free(listp, listsz);
13561991Sheppo 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13571991Sheppo 			return (DDI_FAILURE);
13581991Sheppo 		}
13591991Sheppo 		DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx",
13601991Sheppo 		    ldc_ids[i]));
13611991Sheppo 	}
13621991Sheppo 
13631991Sheppo 	kmem_free(listp, listsz);
13641991Sheppo 
13651991Sheppo 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
13661991Sheppo 	    &addrsz)) {
13671991Sheppo 		DWARN((vgenp->vnetp,
13681991Sheppo 		    "vgen_add_port: prop(%s) not found\n", rmacaddr_propname));
13691991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13701991Sheppo 		return (DDI_FAILURE);
13711991Sheppo 	}
13721991Sheppo 
13731991Sheppo 	if (addrsz < ETHERADDRL) {
13741991Sheppo 		DWARN((vgenp->vnetp,
13751991Sheppo 		    "vgen_add_port: invalid address size (%d)\n", addrsz));
13761991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13771991Sheppo 		return (DDI_FAILURE);
13781991Sheppo 	}
13791991Sheppo 
13801991Sheppo 	macaddr = *((uint64_t *)addrp);
13811991Sheppo 
13821991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n",
13831991Sheppo 	    macaddr));
13841991Sheppo 
13851991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
13861991Sheppo 		ea.ether_addr_octet[i] = macaddr & 0xFF;
13871991Sheppo 		macaddr >>= 8;
13881991Sheppo 	}
13891991Sheppo 
13901991Sheppo 	if (vgenp->vsw_portp == NULL) {
13911991Sheppo 		if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
13921991Sheppo 			if (val == 0) {
13931991Sheppo 				/* This port is connected to the vsw on dom0 */
13941991Sheppo 				vsw_port = B_TRUE;
13951991Sheppo 			}
13961991Sheppo 		}
13971991Sheppo 	}
13981991Sheppo 	(void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
13991991Sheppo 	    &ea, vsw_port);
14001991Sheppo 
14011991Sheppo 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
14021991Sheppo 
14031991Sheppo 	return (DDI_SUCCESS);
14041991Sheppo }
14051991Sheppo 
14061991Sheppo /* remove a port from the device */
14071991Sheppo static int
14081991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
14091991Sheppo {
14101991Sheppo 	uint64_t	port_num;
14111991Sheppo 	vgen_port_t	*portp;
14121991Sheppo 	vgen_portlist_t	*plistp;
14131991Sheppo 
14141991Sheppo 	/* read "id" property to get the port number */
14151991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
14161991Sheppo 		DWARN((vgenp->vnetp,
14171991Sheppo 		    "vgen_remove_port: prop(%s) not found\n", id_propname));
14181991Sheppo 		return (DDI_FAILURE);
14191991Sheppo 	}
14201991Sheppo 
14211991Sheppo 	plistp = &(vgenp->vgenports);
14221991Sheppo 
14231991Sheppo 	WRITE_ENTER(&plistp->rwlock);
14241991Sheppo 	portp = vgen_port_lookup(plistp, (int)port_num);
14251991Sheppo 	if (portp == NULL) {
14261991Sheppo 		DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n",
14271991Sheppo 		    port_num));
14281991Sheppo 		RW_EXIT(&plistp->rwlock);
14291991Sheppo 		return (DDI_FAILURE);
14301991Sheppo 	}
14311991Sheppo 
14321991Sheppo 	vgen_port_detach_mdeg(portp);
14331991Sheppo 	RW_EXIT(&plistp->rwlock);
14341991Sheppo 
14351991Sheppo 	return (DDI_SUCCESS);
14361991Sheppo }
14371991Sheppo 
14381991Sheppo /* attach a port to the device based on mdeg data */
14391991Sheppo static int
14401991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
14411991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port)
14421991Sheppo {
14431991Sheppo 	vgen_port_t		*portp;
14441991Sheppo 	vgen_portlist_t		*plistp;
14451991Sheppo 	int			i;
14461991Sheppo 
14471991Sheppo 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP);
14481991Sheppo 	if (portp == NULL) {
14491991Sheppo 		return (DDI_FAILURE);
14501991Sheppo 	}
14511991Sheppo 	portp->vgenp = vgenp;
14521991Sheppo 	portp->port_num = port_num;
14531991Sheppo 
14541991Sheppo 	DBG1((vgenp->vnetp,
14551991Sheppo 	    "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num));
14561991Sheppo 
14571991Sheppo 	portp->ldclist.num_ldcs = 0;
14581991Sheppo 	portp->ldclist.headp = NULL;
14591991Sheppo 	rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
14601991Sheppo 
14611991Sheppo 	ether_copy(macaddr, &portp->macaddr);
14621991Sheppo 	for (i = 0; i < num_ids; i++) {
14631991Sheppo 		DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n",
14641991Sheppo 		    ldcids[i]));
14651991Sheppo 		(void) vgen_ldc_attach(portp, ldcids[i]);
14661991Sheppo 	}
14671991Sheppo 
14681991Sheppo 	/* link it into the list of ports */
14691991Sheppo 	plistp = &(vgenp->vgenports);
14701991Sheppo 	WRITE_ENTER(&plistp->rwlock);
14711991Sheppo 	vgen_port_list_insert(portp);
14721991Sheppo 	RW_EXIT(&plistp->rwlock);
14731991Sheppo 
14741991Sheppo 	/* This port is connected to the vsw on domain0 */
14751991Sheppo 	if (vsw_port)
14761991Sheppo 		vgenp->vsw_portp = portp;
14771991Sheppo 
14781991Sheppo 	if (vgenp->flags & VGEN_STARTED) {	/* interface is configured */
14791991Sheppo 		vgen_port_init(portp);
14801991Sheppo 	}
14811991Sheppo 
14821991Sheppo 	DBG1((vgenp->vnetp,
14831991Sheppo 	    "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num));
14841991Sheppo 	return (DDI_SUCCESS);
14851991Sheppo }
14861991Sheppo 
14871991Sheppo /* detach a port from the device based on mdeg data */
14881991Sheppo static void
14891991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
14901991Sheppo {
14911991Sheppo 	vgen_t *vgenp = portp->vgenp;
14921991Sheppo 
14931991Sheppo 	DBG1((vgenp->vnetp,
14941991Sheppo 	    "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num));
14951991Sheppo 	/* stop the port if needed */
14961991Sheppo 	if (vgenp->flags & VGEN_STARTED) {
14971991Sheppo 		vgen_port_uninit(portp);
14981991Sheppo 	}
14991991Sheppo 	vgen_port_detach(portp);
15001991Sheppo 
15011991Sheppo 	DBG1((vgenp->vnetp,
15021991Sheppo 	    "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num));
15031991Sheppo }
15041991Sheppo 
15051991Sheppo static int
15061991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
15071991Sheppo 	md_t *prev_mdp, mde_cookie_t prev_mdex)
15081991Sheppo {
15091991Sheppo 	 _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex))
15101991Sheppo 
15112793Slm66018 	/* NOTE: TBD */
15121991Sheppo 	return (DDI_SUCCESS);
15131991Sheppo }
15141991Sheppo 
15151991Sheppo static uint64_t
15162311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
15171991Sheppo {
15181991Sheppo 	vgen_ldclist_t	*ldclp;
15191991Sheppo 	vgen_ldc_t *ldcp;
15201991Sheppo 	uint64_t	val;
15211991Sheppo 
15221991Sheppo 	val = 0;
15231991Sheppo 	ldclp = &portp->ldclist;
15241991Sheppo 
15251991Sheppo 	READ_ENTER(&ldclp->rwlock);
15261991Sheppo 	for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
15271991Sheppo 		val += vgen_ldc_stat(ldcp, stat);
15281991Sheppo 	}
15291991Sheppo 	RW_EXIT(&ldclp->rwlock);
15301991Sheppo 
15311991Sheppo 	return (val);
15321991Sheppo }
15331991Sheppo 
15341991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
15351991Sheppo static int
15361991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
15371991Sheppo {
15381991Sheppo 	vgen_t 		*vgenp;
15391991Sheppo 	vgen_ldclist_t	*ldclp;
15401991Sheppo 	vgen_ldc_t 	*ldcp, **prev_ldcp;
15411991Sheppo 	ldc_attr_t 	attr;
15421991Sheppo 	int 		status;
15431991Sheppo 	ldc_status_t	istatus;
15441991Sheppo 	enum		{AST_init = 0x0, AST_ldc_alloc = 0x1,
15451991Sheppo 			AST_mutex_init = 0x2, AST_ldc_init = 0x4,
15462336Snarayan 			AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10,
15472336Snarayan 			AST_create_rxmblks = 0x20}
15481991Sheppo 			attach_state;
15491991Sheppo 
15501991Sheppo 	attach_state = AST_init;
15511991Sheppo 	vgenp = portp->vgenp;
15521991Sheppo 	ldclp = &portp->ldclist;
15531991Sheppo 
15541991Sheppo 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
15551991Sheppo 	if (ldcp == NULL) {
15561991Sheppo 		goto ldc_attach_failed;
15571991Sheppo 	}
15581991Sheppo 	ldcp->ldc_id = ldc_id;
15591991Sheppo 	ldcp->portp = portp;
15601991Sheppo 
15611991Sheppo 	attach_state |= AST_ldc_alloc;
15621991Sheppo 
15631991Sheppo 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
15641991Sheppo 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
15651991Sheppo 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
15661991Sheppo 
15671991Sheppo 	attach_state |= AST_mutex_init;
15681991Sheppo 
15691991Sheppo 	attr.devclass = LDC_DEV_NT;
15701991Sheppo 	attr.instance = ddi_get_instance(vgenp->vnetdip);
15711991Sheppo 	attr.mode = LDC_MODE_UNRELIABLE;
15722410Slm66018 	attr.mtu = vnet_ldc_mtu;
15731991Sheppo 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
15741991Sheppo 	if (status != 0) {
15751991Sheppo 		DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n",
15761991Sheppo 		    ldc_id, status));
15771991Sheppo 		goto ldc_attach_failed;
15781991Sheppo 	}
15791991Sheppo 	attach_state |= AST_ldc_init;
15801991Sheppo 
15811991Sheppo 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
15821991Sheppo 	if (status != 0) {
15831991Sheppo 		DWARN((vgenp->vnetp,
15841991Sheppo 		    "ldc_reg_callback failed, id (%lx) rv (%d)\n",
15851991Sheppo 		    ldc_id, status));
15861991Sheppo 		goto ldc_attach_failed;
15871991Sheppo 	}
15881991Sheppo 	attach_state |= AST_ldc_reg_cb;
15891991Sheppo 
15901991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
15911991Sheppo 	ASSERT(istatus == LDC_INIT);
15921991Sheppo 	ldcp->ldc_status = istatus;
15931991Sheppo 
15941991Sheppo 	/* allocate transmit resources */
15951991Sheppo 	status = vgen_alloc_tx_ring(ldcp);
15961991Sheppo 	if (status != 0) {
15971991Sheppo 		goto ldc_attach_failed;
15981991Sheppo 	}
15991991Sheppo 	attach_state |= AST_alloc_tx_ring;
16001991Sheppo 
16012336Snarayan 	/* allocate receive resources */
16022336Snarayan 	ldcp->num_rbufs = vnet_nrbufs;
16032336Snarayan 	ldcp->rmp = NULL;
16042336Snarayan 	status = vio_create_mblks(ldcp->num_rbufs, VGEN_DBLK_SZ,
16052336Snarayan 		&(ldcp->rmp));
16062336Snarayan 	if (status != 0) {
16072336Snarayan 		goto ldc_attach_failed;
16082336Snarayan 	}
16092336Snarayan 	attach_state |= AST_create_rxmblks;
16102336Snarayan 
16111991Sheppo 	/* Setup kstats for the channel */
16121991Sheppo 	status = vgen_setup_kstats(ldcp);
16131991Sheppo 	if (status != VGEN_SUCCESS) {
16141991Sheppo 		goto ldc_attach_failed;
16151991Sheppo 	}
16161991Sheppo 
16171991Sheppo 	/* initialize vgen_versions supported */
16181991Sheppo 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
16191991Sheppo 
16201991Sheppo 	/* link it into the list of channels for this port */
16211991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
16221991Sheppo 	prev_ldcp = (vgen_ldc_t **)(&ldclp->headp);
16231991Sheppo 	ldcp->nextp = *prev_ldcp;
16241991Sheppo 	*prev_ldcp = ldcp;
16251991Sheppo 	ldclp->num_ldcs++;
16261991Sheppo 	RW_EXIT(&ldclp->rwlock);
16271991Sheppo 
16281991Sheppo 	ldcp->flags |= CHANNEL_ATTACHED;
16291991Sheppo 	return (DDI_SUCCESS);
16301991Sheppo 
16311991Sheppo ldc_attach_failed:
16322336Snarayan 	if (attach_state & AST_create_rxmblks) {
16332336Snarayan 		(void) vio_destroy_mblks(ldcp->rmp);
16342336Snarayan 	}
16351991Sheppo 	if (attach_state & AST_alloc_tx_ring) {
16361991Sheppo 		vgen_free_tx_ring(ldcp);
16371991Sheppo 	}
16381991Sheppo 	if (attach_state & AST_ldc_reg_cb) {
16391991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
16401991Sheppo 	}
16411991Sheppo 	if (attach_state & AST_ldc_init) {
16421991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
16431991Sheppo 	}
16441991Sheppo 	if (attach_state & AST_mutex_init) {
16451991Sheppo 		mutex_destroy(&ldcp->tclock);
16461991Sheppo 		mutex_destroy(&ldcp->txlock);
16471991Sheppo 		mutex_destroy(&ldcp->cblock);
16481991Sheppo 	}
16491991Sheppo 	if (attach_state & AST_ldc_alloc) {
16501991Sheppo 		KMEM_FREE(ldcp);
16511991Sheppo 	}
16521991Sheppo 	return (DDI_FAILURE);
16531991Sheppo }
16541991Sheppo 
16551991Sheppo /* detach a channel from the port */
16561991Sheppo static void
16571991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
16581991Sheppo {
16591991Sheppo 	vgen_port_t	*portp;
16601991Sheppo 	vgen_t 		*vgenp;
16611991Sheppo 	vgen_ldc_t 	*pldcp;
16621991Sheppo 	vgen_ldc_t	**prev_ldcp;
16631991Sheppo 	vgen_ldclist_t	*ldclp;
16641991Sheppo 
16651991Sheppo 	portp = ldcp->portp;
16661991Sheppo 	vgenp = portp->vgenp;
16671991Sheppo 	ldclp = &portp->ldclist;
16681991Sheppo 
16691991Sheppo 	prev_ldcp =  (vgen_ldc_t **)&ldclp->headp;
16701991Sheppo 	for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
16711991Sheppo 		if (pldcp == ldcp) {
16721991Sheppo 			break;
16731991Sheppo 		}
16741991Sheppo 	}
16751991Sheppo 
16761991Sheppo 	if (pldcp == NULL) {
16771991Sheppo 		/* invalid ldcp? */
16781991Sheppo 		return;
16791991Sheppo 	}
16801991Sheppo 
16811991Sheppo 	if (ldcp->ldc_status != LDC_INIT) {
16821991Sheppo 		DWARN((vgenp->vnetp,
16831991Sheppo 		    "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n",
16841991Sheppo 			    ldcp->ldc_id));
16851991Sheppo 	}
16861991Sheppo 
16871991Sheppo 	if (ldcp->flags & CHANNEL_ATTACHED) {
16881991Sheppo 		ldcp->flags &= ~(CHANNEL_ATTACHED);
16891991Sheppo 
16901991Sheppo 		vgen_destroy_kstats(ldcp);
16912336Snarayan 
16922336Snarayan 		/* free receive resources */
16932336Snarayan 		if (vio_destroy_mblks(ldcp->rmp)) {
16942336Snarayan 			/*
16952336Snarayan 			 * if we cannot reclaim all mblks, put this
16962336Snarayan 			 * on the list of pools to be reclaimed when the
16972336Snarayan 			 * device gets detached (see vgen_uninit()).
16982336Snarayan 			 */
16992336Snarayan 			ldcp->rmp->nextp =  vgenp->rmp;
17002336Snarayan 			vgenp->rmp = ldcp->rmp;
17012336Snarayan 		}
17022336Snarayan 
17031991Sheppo 		/* free transmit resources */
17041991Sheppo 		vgen_free_tx_ring(ldcp);
17052336Snarayan 
17061991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
17071991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
17081991Sheppo 		mutex_destroy(&ldcp->tclock);
17091991Sheppo 		mutex_destroy(&ldcp->txlock);
17101991Sheppo 		mutex_destroy(&ldcp->cblock);
17111991Sheppo 
17121991Sheppo 		/* unlink it from the list */
17131991Sheppo 		*prev_ldcp = ldcp->nextp;
17141991Sheppo 		ldclp->num_ldcs--;
17151991Sheppo 		KMEM_FREE(ldcp);
17161991Sheppo 	}
17171991Sheppo }
17181991Sheppo 
17191991Sheppo /*
17201991Sheppo  * This function allocates transmit resources for the channel.
17211991Sheppo  * The resources consist of a transmit descriptor ring and an associated
17221991Sheppo  * transmit buffer ring.
17231991Sheppo  */
17241991Sheppo static int
17251991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp)
17261991Sheppo {
17271991Sheppo 	void *tbufp;
17281991Sheppo 	ldc_mem_info_t minfo;
17291991Sheppo 	uint32_t txdsize;
17301991Sheppo 	uint32_t tbufsize;
17311991Sheppo 	int status;
17321991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
17331991Sheppo 
17341991Sheppo 	ldcp->num_txds = vnet_ntxds;
17351991Sheppo 	txdsize = sizeof (vnet_public_desc_t);
17361991Sheppo 	tbufsize = sizeof (vgen_private_desc_t);
17371991Sheppo 
17381991Sheppo 	/* allocate transmit buffer ring */
17391991Sheppo 	tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
17401991Sheppo 	if (tbufp == NULL) {
17411991Sheppo 		return (DDI_FAILURE);
17421991Sheppo 	}
17431991Sheppo 
17441991Sheppo 	/* create transmit descriptor ring */
17451991Sheppo 	status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
17461991Sheppo 	    &ldcp->tx_dhandle);
17471991Sheppo 	if (status) {
17481991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() "
17491991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
17501991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
17511991Sheppo 		return (DDI_FAILURE);
17521991Sheppo 	}
17531991Sheppo 
17541991Sheppo 	/* get the addr of descripror ring */
17551991Sheppo 	status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
17561991Sheppo 	if (status) {
17571991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() "
17581991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
17591991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
17601991Sheppo 		(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
17611991Sheppo 		ldcp->tbufp = NULL;
17621991Sheppo 		return (DDI_FAILURE);
17631991Sheppo 	}
17641991Sheppo 	ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr);
17651991Sheppo 	ldcp->tbufp = tbufp;
17661991Sheppo 
17671991Sheppo 	ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]);
17681991Sheppo 	ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]);
17691991Sheppo 
17701991Sheppo 	return (DDI_SUCCESS);
17711991Sheppo }
17721991Sheppo 
17731991Sheppo /* Free transmit resources for the channel */
17741991Sheppo static void
17751991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp)
17761991Sheppo {
17771991Sheppo 	int tbufsize = sizeof (vgen_private_desc_t);
17781991Sheppo 
17791991Sheppo 	/* free transmit descriptor ring */
17801991Sheppo 	(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
17811991Sheppo 
17821991Sheppo 	/* free transmit buffer ring */
17831991Sheppo 	kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize);
17841991Sheppo 	ldcp->txdp = ldcp->txdendp = NULL;
17851991Sheppo 	ldcp->tbufp = ldcp->tbufendp = NULL;
17861991Sheppo }
17871991Sheppo 
17881991Sheppo /* enable transmit/receive on the channels for the port */
17891991Sheppo static void
17901991Sheppo vgen_init_ldcs(vgen_port_t *portp)
17911991Sheppo {
17921991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
17931991Sheppo 	vgen_ldc_t	*ldcp;
17941991Sheppo 
17951991Sheppo 	READ_ENTER(&ldclp->rwlock);
17961991Sheppo 	ldcp =  ldclp->headp;
17971991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
17981991Sheppo 		(void) vgen_ldc_init(ldcp);
17991991Sheppo 	}
18001991Sheppo 	RW_EXIT(&ldclp->rwlock);
18011991Sheppo }
18021991Sheppo 
18031991Sheppo /* stop transmit/receive on the channels for the port */
18041991Sheppo static void
18051991Sheppo vgen_uninit_ldcs(vgen_port_t *portp)
18061991Sheppo {
18071991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
18081991Sheppo 	vgen_ldc_t	*ldcp;
18091991Sheppo 
18101991Sheppo 	READ_ENTER(&ldclp->rwlock);
18111991Sheppo 	ldcp =  ldclp->headp;
18121991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
18131991Sheppo 		vgen_ldc_uninit(ldcp);
18141991Sheppo 	}
18151991Sheppo 	RW_EXIT(&ldclp->rwlock);
18161991Sheppo }
18171991Sheppo 
18181991Sheppo /* enable transmit/receive on the channel */
18191991Sheppo static int
18201991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
18211991Sheppo {
18221991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
18231991Sheppo 	ldc_status_t	istatus;
18241991Sheppo 	int		rv;
18252793Slm66018 	enum		{ ST_init = 0x0, ST_ldc_open = 0x1,
18262793Slm66018 			    ST_init_tbufs = 0x2, ST_cb_enable = 0x4
18271991Sheppo 			    }
18281991Sheppo 			init_state;
18292109Slm66018 	uint32_t	retries = 0;
18301991Sheppo 
18311991Sheppo 	init_state = ST_init;
18321991Sheppo 
18331991Sheppo 	LDC_LOCK(ldcp);
18341991Sheppo 
18351991Sheppo 	rv = ldc_open(ldcp->ldc_handle);
18361991Sheppo 	if (rv != 0) {
18371991Sheppo 		DWARN((vnetp,
18381991Sheppo 		    "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
18391991Sheppo 		    ldcp->ldc_id, rv));
18401991Sheppo 		goto ldcinit_failed;
18411991Sheppo 	}
18421991Sheppo 	init_state |= ST_ldc_open;
18431991Sheppo 
18441991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
18451991Sheppo 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
18461991Sheppo 		DWARN((vnetp,
18471991Sheppo 		    "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
18481991Sheppo 		    ldcp->ldc_id, istatus));
18491991Sheppo 		goto ldcinit_failed;
18501991Sheppo 	}
18511991Sheppo 	ldcp->ldc_status = istatus;
18521991Sheppo 
18531991Sheppo 	rv = vgen_init_tbufs(ldcp);
18541991Sheppo 	if (rv != 0) {
18551991Sheppo 		DWARN((vnetp,
18561991Sheppo 		    "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
18571991Sheppo 		    ldcp->ldc_id));
18581991Sheppo 		goto ldcinit_failed;
18591991Sheppo 	}
18601991Sheppo 	init_state |= ST_init_tbufs;
18611991Sheppo 
18622748Slm66018 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
18632748Slm66018 	if (rv != 0) {
18642793Slm66018 		DWARN((vnetp, "vgen_ldc_init: ldc_set_cb_mode failed: id(%lx) "
18652793Slm66018 		    "rv(%d)\n", ldcp->ldc_id, rv));
18662748Slm66018 		goto ldcinit_failed;
18672748Slm66018 	}
18682748Slm66018 
18692748Slm66018 	init_state |= ST_cb_enable;
18702748Slm66018 
18712109Slm66018 	do {
18722109Slm66018 		rv = ldc_up(ldcp->ldc_handle);
18732109Slm66018 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
18742109Slm66018 			DBG2((vnetp,
18752109Slm66018 			    "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
18762109Slm66018 			    ldcp->ldc_id, rv));
18772109Slm66018 			drv_usecwait(VGEN_LDC_UP_DELAY);
18782109Slm66018 		}
18792109Slm66018 		if (retries++ >= vgen_ldcup_retries)
18802109Slm66018 			break;
18812109Slm66018 	} while (rv == EWOULDBLOCK);
18821991Sheppo 
18831991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
18842793Slm66018 	if (istatus == LDC_UP) {
18852793Slm66018 		DWARN((vnetp, "vgen_ldc_init: id(%lx) status(%d) is UP\n",
18861991Sheppo 		    ldcp->ldc_id, istatus));
18871991Sheppo 	}
18882793Slm66018 
18891991Sheppo 	ldcp->ldc_status = istatus;
18901991Sheppo 
18911991Sheppo 	/* initialize transmit watchdog timeout */
18921991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
18931991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
18941991Sheppo 
18952793Slm66018 	ldcp->hphase = -1;
18961991Sheppo 	ldcp->flags |= CHANNEL_STARTED;
18971991Sheppo 
18982793Slm66018 	/* if channel is already UP - start handshake */
18992793Slm66018 	if (istatus == LDC_UP) {
19002793Slm66018 		vgen_t *vgenp = LDC_TO_VGEN(ldcp);
19012793Slm66018 		if (ldcp->portp != vgenp->vsw_portp) {
19022793Slm66018 			/*
19032793Slm66018 			 * modify fdb entry to use this port as the
19042793Slm66018 			 * channel is up, instead of going through the
19052793Slm66018 			 * vsw-port (see comments in vgen_port_init())
19062793Slm66018 			 */
19072793Slm66018 			vnet_modify_fdb(vnetp,
19082793Slm66018 			    (uint8_t *)&ldcp->portp->macaddr,
19092793Slm66018 			    vgen_tx, ldcp->portp, B_FALSE);
19102793Slm66018 		}
19112793Slm66018 
19122793Slm66018 		/* Initialize local session id */
19132793Slm66018 		ldcp->local_sid = ddi_get_lbolt();
19142793Slm66018 
19152793Slm66018 		/* clear peer session id */
19162793Slm66018 		ldcp->peer_sid = 0;
19172793Slm66018 		ldcp->hretries = 0;
19182793Slm66018 
19192793Slm66018 		/* Initiate Handshake process with peer ldc endpoint */
19202793Slm66018 		vgen_reset_hphase(ldcp);
19212793Slm66018 
19222793Slm66018 		mutex_exit(&ldcp->tclock);
19232793Slm66018 		mutex_exit(&ldcp->txlock);
19242793Slm66018 		vgen_handshake(vh_nextphase(ldcp));
19252793Slm66018 		mutex_exit(&ldcp->cblock);
19262793Slm66018 	} else {
19272793Slm66018 		LDC_UNLOCK(ldcp);
19282793Slm66018 	}
19292793Slm66018 
19301991Sheppo 	return (DDI_SUCCESS);
19311991Sheppo 
19321991Sheppo ldcinit_failed:
19332748Slm66018 	if (init_state & ST_cb_enable) {
19342748Slm66018 		(void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
19352748Slm66018 	}
19361991Sheppo 	if (init_state & ST_init_tbufs) {
19371991Sheppo 		vgen_uninit_tbufs(ldcp);
19381991Sheppo 	}
19391991Sheppo 	if (init_state & ST_ldc_open) {
19401991Sheppo 		(void) ldc_close(ldcp->ldc_handle);
19411991Sheppo 	}
19421991Sheppo 	LDC_UNLOCK(ldcp);
19431991Sheppo 	return (DDI_FAILURE);
19441991Sheppo }
19451991Sheppo 
19461991Sheppo /* stop transmit/receive on the channel */
19471991Sheppo static void
19481991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
19491991Sheppo {
19501991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
19511991Sheppo 	int	rv;
19521991Sheppo 
19531991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id));
19541991Sheppo 	LDC_LOCK(ldcp);
19551991Sheppo 
19561991Sheppo 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
19571991Sheppo 		LDC_UNLOCK(ldcp);
19581991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED"
19591991Sheppo 		    " flag is not set\n", ldcp->ldc_id));
19601991Sheppo 		return;
19611991Sheppo 	}
19621991Sheppo 
19631991Sheppo 	/* disable further callbacks */
19641991Sheppo 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
19651991Sheppo 	if (rv != 0) {
19661991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id (%lx) "
19671991Sheppo 		    "ldc_set_cb_mode failed\n", ldcp->ldc_id));
19681991Sheppo 	}
19691991Sheppo 
1970*3653Snarayan 	/*
1971*3653Snarayan 	 * clear handshake done bit and wait for pending tx and cb to finish.
1972*3653Snarayan 	 * release locks before untimeout(9F) is invoked to cancel timeouts.
1973*3653Snarayan 	 */
19741991Sheppo 	ldcp->hphase &= ~(VH_DONE);
19751991Sheppo 	LDC_UNLOCK(ldcp);
1976*3653Snarayan 
1977*3653Snarayan 	/* cancel handshake watchdog timeout */
1978*3653Snarayan 	if (ldcp->htid) {
1979*3653Snarayan 		(void) untimeout(ldcp->htid);
1980*3653Snarayan 		ldcp->htid = 0;
1981*3653Snarayan 	}
1982*3653Snarayan 
1983*3653Snarayan 	/* cancel transmit watchdog timeout */
19841991Sheppo 	if (ldcp->wd_tid) {
19851991Sheppo 		(void) untimeout(ldcp->wd_tid);
19861991Sheppo 		ldcp->wd_tid = 0;
19871991Sheppo 	}
19881991Sheppo 
1989*3653Snarayan 	drv_usecwait(1000);
1990*3653Snarayan 
1991*3653Snarayan 	/* acquire locks again; any pending transmits and callbacks are done */
1992*3653Snarayan 	LDC_LOCK(ldcp);
1993*3653Snarayan 
1994*3653Snarayan 	vgen_reset_hphase(ldcp);
1995*3653Snarayan 
19961991Sheppo 	vgen_uninit_tbufs(ldcp);
19971991Sheppo 
19981991Sheppo 	rv = ldc_close(ldcp->ldc_handle);
19991991Sheppo 	if (rv != 0) {
20001991Sheppo 		DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n",
20011991Sheppo 		    ldcp->ldc_id));
20021991Sheppo 	}
20031991Sheppo 	ldcp->ldc_status = LDC_INIT;
20041991Sheppo 	ldcp->flags &= ~(CHANNEL_STARTED);
20051991Sheppo 
20061991Sheppo 	LDC_UNLOCK(ldcp);
20071991Sheppo 
20081991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id));
20091991Sheppo }
20101991Sheppo 
20111991Sheppo /* Initialize the transmit buffer ring for the channel */
20121991Sheppo static int
20131991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp)
20141991Sheppo {
20151991Sheppo 	vgen_private_desc_t	*tbufp;
20161991Sheppo 	vnet_public_desc_t	*txdp;
20171991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
20181991Sheppo 	int 			i;
20191991Sheppo 	int 			rv;
20202109Slm66018 	caddr_t			datap = NULL;
20212109Slm66018 	int			ci;
20222109Slm66018 	uint32_t		ncookies;
20231991Sheppo 
20241991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
20251991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
20261991Sheppo 
20272336Snarayan 	datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP);
20282109Slm66018 	ldcp->tx_datap = datap;
20292109Slm66018 
20301991Sheppo 	/*
20312109Slm66018 	 * for each private descriptor, allocate a ldc mem_handle which is
20321991Sheppo 	 * required to map the data during transmit, set the flags
20331991Sheppo 	 * to free (available for use by transmit routine).
20341991Sheppo 	 */
20351991Sheppo 
20361991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
20372109Slm66018 
20381991Sheppo 		tbufp = &(ldcp->tbufp[i]);
20391991Sheppo 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
20401991Sheppo 			&(tbufp->memhandle));
20411991Sheppo 		if (rv) {
20421991Sheppo 			tbufp->memhandle = 0;
20431991Sheppo 			goto init_tbufs_failed;
20441991Sheppo 		}
20452109Slm66018 
20462109Slm66018 		/*
20472109Slm66018 		 * bind ldc memhandle to the corresponding transmit buffer.
20482109Slm66018 		 */
20492109Slm66018 		ci = ncookies = 0;
20502109Slm66018 		rv = ldc_mem_bind_handle(tbufp->memhandle,
20512336Snarayan 		    (caddr_t)datap, VGEN_DBLK_SZ, LDC_SHADOW_MAP,
20522109Slm66018 		    LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
20532109Slm66018 		if (rv != 0) {
20542109Slm66018 			goto init_tbufs_failed;
20552109Slm66018 		}
20562109Slm66018 
20572109Slm66018 		/*
20582109Slm66018 		 * successful in binding the handle to tx data buffer.
20592109Slm66018 		 * set datap in the private descr to this buffer.
20602109Slm66018 		 */
20612109Slm66018 		tbufp->datap = datap;
20622109Slm66018 
20632109Slm66018 		if ((ncookies == 0) ||
20642336Snarayan 			(ncookies > MAX_COOKIES)) {
20652109Slm66018 			goto init_tbufs_failed;
20662109Slm66018 		}
20672109Slm66018 
20682109Slm66018 		for (ci = 1; ci < ncookies; ci++) {
20692109Slm66018 			rv = ldc_mem_nextcookie(tbufp->memhandle,
20702336Snarayan 				&(tbufp->memcookie[ci]));
20712109Slm66018 			if (rv != 0) {
20722109Slm66018 				goto init_tbufs_failed;
20732109Slm66018 			}
20742109Slm66018 		}
20752109Slm66018 
20762109Slm66018 		tbufp->ncookies = ncookies;
20772336Snarayan 		datap += VGEN_DBLK_SZ;
20782109Slm66018 
20791991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
20801991Sheppo 		txdp = &(ldcp->txdp[i]);
20811991Sheppo 		hdrp = &txdp->hdr;
20821991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
20831991Sheppo 		hdrp->ack = B_FALSE;
20841991Sheppo 		tbufp->descp = txdp;
20852109Slm66018 
20861991Sheppo 	}
20871991Sheppo 
20881991Sheppo 	/* reset tbuf walking pointers */
20891991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
20901991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
20911991Sheppo 
20921991Sheppo 	/* initialize tx seqnum and index */
20931991Sheppo 	ldcp->next_txseq = VNET_ISS;
20941991Sheppo 	ldcp->next_txi = 0;
20951991Sheppo 
20962336Snarayan 	ldcp->resched_peer = B_TRUE;
20972336Snarayan 
20981991Sheppo 	return (DDI_SUCCESS);
20991991Sheppo 
21001991Sheppo init_tbufs_failed:;
21011991Sheppo 	vgen_uninit_tbufs(ldcp);
21021991Sheppo 	return (DDI_FAILURE);
21031991Sheppo }
21041991Sheppo 
21051991Sheppo /* Uninitialize transmit buffer ring for the channel */
21061991Sheppo static void
21071991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp)
21081991Sheppo {
21091991Sheppo 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
21101991Sheppo 	int 			i;
21111991Sheppo 
21121991Sheppo 	/* for each tbuf (priv_desc), free ldc mem_handle */
21131991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
21141991Sheppo 
21151991Sheppo 		tbufp = &(ldcp->tbufp[i]);
21161991Sheppo 
21172109Slm66018 		if (tbufp->datap) { /* if bound to a ldc memhandle */
21181991Sheppo 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
21192109Slm66018 			tbufp->datap = NULL;
21201991Sheppo 		}
21211991Sheppo 		if (tbufp->memhandle) {
21221991Sheppo 			(void) ldc_mem_free_handle(tbufp->memhandle);
21231991Sheppo 			tbufp->memhandle = 0;
21241991Sheppo 		}
21251991Sheppo 	}
21261991Sheppo 
21272109Slm66018 	if (ldcp->tx_datap) {
21282109Slm66018 		/* prealloc'd tx data buffer */
21292336Snarayan 		kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ);
21302109Slm66018 		ldcp->tx_datap = NULL;
21312109Slm66018 	}
21322109Slm66018 
21332748Slm66018 	bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds));
21342748Slm66018 	bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds));
21351991Sheppo }
21361991Sheppo 
21371991Sheppo /* clobber tx descriptor ring */
21381991Sheppo static void
21391991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp)
21401991Sheppo {
21411991Sheppo 	vnet_public_desc_t	*txdp;
21421991Sheppo 	vgen_private_desc_t	*tbufp;
21431991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
21441991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
21451991Sheppo 	int i;
21461991Sheppo #ifdef DEBUG
21471991Sheppo 	int ndone = 0;
21481991Sheppo #endif
21491991Sheppo 
21501991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
21511991Sheppo 
21521991Sheppo 		tbufp = &(ldcp->tbufp[i]);
21531991Sheppo 		txdp = tbufp->descp;
21541991Sheppo 		hdrp = &txdp->hdr;
21551991Sheppo 
21561991Sheppo 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
21571991Sheppo 			tbufp->flags = VGEN_PRIV_DESC_FREE;
21581991Sheppo #ifdef DEBUG
21591991Sheppo 			if (hdrp->dstate == VIO_DESC_DONE)
21601991Sheppo 				ndone++;
21611991Sheppo #endif
21621991Sheppo 			hdrp->dstate = VIO_DESC_FREE;
21631991Sheppo 			hdrp->ack = B_FALSE;
21641991Sheppo 		}
21651991Sheppo 	}
21661991Sheppo 	/* reset tbuf walking pointers */
21671991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
21681991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
21691991Sheppo 
21701991Sheppo 	/* reset tx seqnum and index */
21711991Sheppo 	ldcp->next_txseq = VNET_ISS;
21721991Sheppo 	ldcp->next_txi = 0;
21732336Snarayan 
21742336Snarayan 	ldcp->resched_peer = B_TRUE;
21752336Snarayan 
21761991Sheppo #ifdef DEBUG
21771991Sheppo 	DBG2((vnetp,
21781991Sheppo 	    "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
21791991Sheppo 	    ldcp->ldc_id, ndone));
21801991Sheppo #endif
21811991Sheppo }
21821991Sheppo 
21831991Sheppo /* clobber receive descriptor ring */
21841991Sheppo static void
21851991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp)
21861991Sheppo {
21871991Sheppo 	ldcp->rx_dhandle = 0;
21881991Sheppo 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
21891991Sheppo 	ldcp->rxdp = NULL;
21901991Sheppo 	ldcp->next_rxi = 0;
21911991Sheppo 	ldcp->num_rxds = 0;
21921991Sheppo 	ldcp->next_rxseq = VNET_ISS;
21931991Sheppo }
21941991Sheppo 
21951991Sheppo /* initialize receive descriptor ring */
21961991Sheppo static int
21971991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
21981991Sheppo 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
21991991Sheppo {
22001991Sheppo 	int rv;
22011991Sheppo 	ldc_mem_info_t minfo;
22021991Sheppo 
22031991Sheppo 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
22041991Sheppo 	    desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle));
22051991Sheppo 	if (rv != 0) {
22061991Sheppo 		return (DDI_FAILURE);
22071991Sheppo 	}
22081991Sheppo 
22091991Sheppo 	/*
22101991Sheppo 	 * sucessfully mapped, now try to
22111991Sheppo 	 * get info about the mapped dring
22121991Sheppo 	 */
22131991Sheppo 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
22141991Sheppo 	if (rv != 0) {
22151991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
22161991Sheppo 		return (DDI_FAILURE);
22171991Sheppo 	}
22181991Sheppo 
22191991Sheppo 	/*
22201991Sheppo 	 * save ring address, number of descriptors.
22211991Sheppo 	 */
22221991Sheppo 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
22231991Sheppo 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
22241991Sheppo 	ldcp->num_rxdcookies = ncookies;
22251991Sheppo 	ldcp->num_rxds = num_desc;
22261991Sheppo 	ldcp->next_rxi = 0;
22271991Sheppo 	ldcp->next_rxseq = VNET_ISS;
22281991Sheppo 
22291991Sheppo 	return (DDI_SUCCESS);
22301991Sheppo }
22311991Sheppo 
22321991Sheppo /* get channel statistics */
22331991Sheppo static uint64_t
22342311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
22351991Sheppo {
22361991Sheppo 	vgen_stats_t *statsp;
22371991Sheppo 	uint64_t val;
22381991Sheppo 
22391991Sheppo 	val = 0;
22401991Sheppo 	statsp = ldcp->statsp;
22411991Sheppo 	switch (stat) {
22421991Sheppo 
22431991Sheppo 	case MAC_STAT_MULTIRCV:
22441991Sheppo 		val = statsp->multircv;
22451991Sheppo 		break;
22461991Sheppo 
22471991Sheppo 	case MAC_STAT_BRDCSTRCV:
22481991Sheppo 		val = statsp->brdcstrcv;
22491991Sheppo 		break;
22501991Sheppo 
22511991Sheppo 	case MAC_STAT_MULTIXMT:
22521991Sheppo 		val = statsp->multixmt;
22531991Sheppo 		break;
22541991Sheppo 
22551991Sheppo 	case MAC_STAT_BRDCSTXMT:
22561991Sheppo 		val = statsp->brdcstxmt;
22571991Sheppo 		break;
22581991Sheppo 
22591991Sheppo 	case MAC_STAT_NORCVBUF:
22601991Sheppo 		val = statsp->norcvbuf;
22611991Sheppo 		break;
22621991Sheppo 
22631991Sheppo 	case MAC_STAT_IERRORS:
22641991Sheppo 		val = statsp->ierrors;
22651991Sheppo 		break;
22661991Sheppo 
22671991Sheppo 	case MAC_STAT_NOXMTBUF:
22681991Sheppo 		val = statsp->noxmtbuf;
22691991Sheppo 		break;
22701991Sheppo 
22711991Sheppo 	case MAC_STAT_OERRORS:
22721991Sheppo 		val = statsp->oerrors;
22731991Sheppo 		break;
22741991Sheppo 
22751991Sheppo 	case MAC_STAT_COLLISIONS:
22761991Sheppo 		break;
22771991Sheppo 
22781991Sheppo 	case MAC_STAT_RBYTES:
22791991Sheppo 		val = statsp->rbytes;
22801991Sheppo 		break;
22811991Sheppo 
22821991Sheppo 	case MAC_STAT_IPACKETS:
22831991Sheppo 		val = statsp->ipackets;
22841991Sheppo 		break;
22851991Sheppo 
22861991Sheppo 	case MAC_STAT_OBYTES:
22871991Sheppo 		val = statsp->obytes;
22881991Sheppo 		break;
22891991Sheppo 
22901991Sheppo 	case MAC_STAT_OPACKETS:
22911991Sheppo 		val = statsp->opackets;
22921991Sheppo 		break;
22931991Sheppo 
22941991Sheppo 	/* stats not relevant to ldc, return 0 */
22951991Sheppo 	case MAC_STAT_IFSPEED:
22962311Sseb 	case ETHER_STAT_ALIGN_ERRORS:
22972311Sseb 	case ETHER_STAT_FCS_ERRORS:
22982311Sseb 	case ETHER_STAT_FIRST_COLLISIONS:
22992311Sseb 	case ETHER_STAT_MULTI_COLLISIONS:
23002311Sseb 	case ETHER_STAT_DEFER_XMTS:
23012311Sseb 	case ETHER_STAT_TX_LATE_COLLISIONS:
23022311Sseb 	case ETHER_STAT_EX_COLLISIONS:
23032311Sseb 	case ETHER_STAT_MACXMT_ERRORS:
23042311Sseb 	case ETHER_STAT_CARRIER_ERRORS:
23052311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
23062311Sseb 	case ETHER_STAT_XCVR_ADDR:
23072311Sseb 	case ETHER_STAT_XCVR_ID:
23082311Sseb 	case ETHER_STAT_XCVR_INUSE:
23092311Sseb 	case ETHER_STAT_CAP_1000FDX:
23102311Sseb 	case ETHER_STAT_CAP_1000HDX:
23112311Sseb 	case ETHER_STAT_CAP_100FDX:
23122311Sseb 	case ETHER_STAT_CAP_100HDX:
23132311Sseb 	case ETHER_STAT_CAP_10FDX:
23142311Sseb 	case ETHER_STAT_CAP_10HDX:
23152311Sseb 	case ETHER_STAT_CAP_ASMPAUSE:
23162311Sseb 	case ETHER_STAT_CAP_PAUSE:
23172311Sseb 	case ETHER_STAT_CAP_AUTONEG:
23182311Sseb 	case ETHER_STAT_ADV_CAP_1000FDX:
23192311Sseb 	case ETHER_STAT_ADV_CAP_1000HDX:
23202311Sseb 	case ETHER_STAT_ADV_CAP_100FDX:
23212311Sseb 	case ETHER_STAT_ADV_CAP_100HDX:
23222311Sseb 	case ETHER_STAT_ADV_CAP_10FDX:
23232311Sseb 	case ETHER_STAT_ADV_CAP_10HDX:
23242311Sseb 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
23252311Sseb 	case ETHER_STAT_ADV_CAP_PAUSE:
23262311Sseb 	case ETHER_STAT_ADV_CAP_AUTONEG:
23272311Sseb 	case ETHER_STAT_LP_CAP_1000FDX:
23282311Sseb 	case ETHER_STAT_LP_CAP_1000HDX:
23292311Sseb 	case ETHER_STAT_LP_CAP_100FDX:
23302311Sseb 	case ETHER_STAT_LP_CAP_100HDX:
23312311Sseb 	case ETHER_STAT_LP_CAP_10FDX:
23322311Sseb 	case ETHER_STAT_LP_CAP_10HDX:
23332311Sseb 	case ETHER_STAT_LP_CAP_ASMPAUSE:
23342311Sseb 	case ETHER_STAT_LP_CAP_PAUSE:
23352311Sseb 	case ETHER_STAT_LP_CAP_AUTONEG:
23362311Sseb 	case ETHER_STAT_LINK_ASMPAUSE:
23372311Sseb 	case ETHER_STAT_LINK_PAUSE:
23382311Sseb 	case ETHER_STAT_LINK_AUTONEG:
23392311Sseb 	case ETHER_STAT_LINK_DUPLEX:
23401991Sheppo 	default:
23411991Sheppo 		val = 0;
23421991Sheppo 		break;
23431991Sheppo 
23441991Sheppo 	}
23451991Sheppo 	return (val);
23461991Sheppo }
23471991Sheppo 
23482793Slm66018 /*
23492793Slm66018  * LDC channel is UP, start handshake process with peer.
23502793Slm66018  * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
23512793Slm66018  * function is being called from transmit routine, otherwise B_FALSE.
23522793Slm66018  */
23532793Slm66018 static void
23542793Slm66018 vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag)
23552793Slm66018 {
23562793Slm66018 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
23572793Slm66018 	void 	*vnetp = LDC_TO_VNET(ldcp);
23582793Slm66018 
23592793Slm66018 	DBG1((vnetp, "vgen_handle_evt_up: enter: id(%lx)\n", ldcp->ldc_id));
23602793Slm66018 
23612793Slm66018 	ASSERT(MUTEX_HELD(&ldcp->cblock));
23622793Slm66018 
23632793Slm66018 	if (ldcp->portp != vgenp->vsw_portp) {
23642793Slm66018 		/*
23652793Slm66018 		 * modify fdb entry to use this port as the
23662793Slm66018 		 * channel is up, instead of going through the
23672793Slm66018 		 * vsw-port (see comments in vgen_port_init())
23682793Slm66018 		 */
23692793Slm66018 		vnet_modify_fdb(vnetp, (uint8_t *)&ldcp->portp->macaddr,
23702793Slm66018 		    vgen_tx, ldcp->portp, flag);
23712793Slm66018 	}
23722793Slm66018 
23732793Slm66018 	/* Initialize local session id */
23742793Slm66018 	ldcp->local_sid = ddi_get_lbolt();
23752793Slm66018 
23762793Slm66018 	/* clear peer session id */
23772793Slm66018 	ldcp->peer_sid = 0;
23782793Slm66018 	ldcp->hretries = 0;
23792793Slm66018 
23802793Slm66018 	if (ldcp->hphase != VH_PHASE0) {
23812793Slm66018 		vgen_handshake_reset(ldcp);
23822793Slm66018 	}
23832793Slm66018 
23842793Slm66018 	/* Initiate Handshake process with peer ldc endpoint */
23852793Slm66018 	vgen_handshake(vh_nextphase(ldcp));
23862793Slm66018 
23872793Slm66018 	DBG1((vnetp, "vgen_handle_evt_up: exit: id(%lx)\n", ldcp->ldc_id));
23882793Slm66018 }
23892793Slm66018 
23902793Slm66018 /*
23912793Slm66018  * LDC channel is Reset, terminate connection with peer and try to
23922793Slm66018  * bring the channel up again.
23932793Slm66018  * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this
23942793Slm66018  * function is being called from transmit routine, otherwise B_FALSE.
23952793Slm66018  */
23962793Slm66018 static void
23972793Slm66018 vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag)
23982793Slm66018 {
23992793Slm66018 	ldc_status_t istatus;
24002793Slm66018 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
24012793Slm66018 	void	*vnetp = LDC_TO_VNET(ldcp);
24022793Slm66018 	int	rv;
24032793Slm66018 
24042793Slm66018 	DBG1((vnetp, "vgen_handle_evt_reset: enter: id(%lx)\n", ldcp->ldc_id));
24052793Slm66018 
24062793Slm66018 	ASSERT(MUTEX_HELD(&ldcp->cblock));
24072793Slm66018 
24082793Slm66018 	if ((ldcp->portp != vgenp->vsw_portp) &&
24092793Slm66018 		(vgenp->vsw_portp != NULL)) {
24102793Slm66018 		/*
24112793Slm66018 		 * modify fdb entry to use vsw-port  as the
24122793Slm66018 		 * channel is reset and we don't have a direct
24132793Slm66018 		 * link to the destination (see comments
24142793Slm66018 		 * in vgen_port_init()).
24152793Slm66018 		 */
24162793Slm66018 		vnet_modify_fdb(vnetp, (uint8_t *)&ldcp->portp->macaddr,
24172793Slm66018 		    vgen_tx, vgenp->vsw_portp, flag);
24182793Slm66018 	}
24192793Slm66018 
24202793Slm66018 	if (ldcp->hphase != VH_PHASE0) {
24212793Slm66018 		vgen_handshake_reset(ldcp);
24222793Slm66018 	}
24232793Slm66018 
24242793Slm66018 	/* try to bring the channel up */
24252793Slm66018 	rv = ldc_up(ldcp->ldc_handle);
24262793Slm66018 	if (rv != 0) {
24272793Slm66018 		DWARN((vnetp,
24282793Slm66018 		    "vgen_handle_evt_reset: ldc_up err id(%lx) rv(%d)\n",
24292793Slm66018 		    ldcp->ldc_id, rv));
24302793Slm66018 	}
24312793Slm66018 
24322793Slm66018 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
24332793Slm66018 		DWARN((vnetp,
24342793Slm66018 		    "vgen_handle_evt_reset: ldc_status err id(%lx)\n"));
24352793Slm66018 	} else {
24362793Slm66018 		ldcp->ldc_status = istatus;
24372793Slm66018 	}
24382793Slm66018 
24392793Slm66018 	/* if channel is already UP - restart handshake */
24402793Slm66018 	if (ldcp->ldc_status == LDC_UP) {
24412793Slm66018 		vgen_handle_evt_up(ldcp, flag);
24422793Slm66018 	}
24432793Slm66018 
24442793Slm66018 	DBG1((vnetp, "vgen_handle_evt_reset: exit: id(%lx)\n", ldcp->ldc_id));
24452793Slm66018 }
24462793Slm66018 
24471991Sheppo /* Interrupt handler for the channel */
24481991Sheppo static uint_t
24491991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
24501991Sheppo {
24511991Sheppo 	_NOTE(ARGUNUSED(event))
24521991Sheppo 	vgen_ldc_t	*ldcp;
24531991Sheppo 	void 		*vnetp;
24541991Sheppo 	vgen_t		*vgenp;
24551991Sheppo 	size_t		msglen;
24561991Sheppo 	ldc_status_t 	istatus;
24571991Sheppo 	uint64_t	ldcmsg[7];
24582793Slm66018 	int 		rv = 0;
24591991Sheppo 	vio_msg_tag_t	*tagp;
24601991Sheppo 	mblk_t		*mp = NULL;
24611991Sheppo 	mblk_t		*bp = NULL;
24621991Sheppo 	mblk_t		*bpt = NULL;
24631991Sheppo 	mblk_t		*headp = NULL;
24641991Sheppo 	mblk_t		*tailp = NULL;
24651991Sheppo 	vgen_stats_t	*statsp;
24661991Sheppo 
24671991Sheppo 	ldcp = (vgen_ldc_t *)arg;
24681991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
24691991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
24701991Sheppo 	statsp = ldcp->statsp;
24711991Sheppo 
24721991Sheppo 	DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id));
24731991Sheppo 
24741991Sheppo 	mutex_enter(&ldcp->cblock);
24751991Sheppo 	statsp->callbacks++;
24761991Sheppo 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
24771991Sheppo 		DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
24781991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
24791991Sheppo 		mutex_exit(&ldcp->cblock);
24801991Sheppo 		return (LDC_SUCCESS);
24811991Sheppo 	}
24821991Sheppo 
24832793Slm66018 	/*
24842793Slm66018 	 * NOTE: not using switch() as event could be triggered by
24852793Slm66018 	 * a state change and a read request. Also the ordering	of the
24862793Slm66018 	 * check for the event types is deliberate.
24872793Slm66018 	 */
24882793Slm66018 	if (event & LDC_EVT_UP) {
24892793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
24902793Slm66018 			DWARN((vnetp,
24912793Slm66018 			    "vgen_ldc_cb: ldc_status err id(%lx)\n"));
24922793Slm66018 		} else {
24931991Sheppo 			ldcp->ldc_status = istatus;
24942793Slm66018 		}
24952793Slm66018 		ASSERT(ldcp->ldc_status == LDC_UP);
24962793Slm66018 		DWARN((vnetp,
24972793Slm66018 		    "vgen_ldc_cb: id(%lx) event(%lx) UP, status(%d)\n",
24982793Slm66018 		    ldcp->ldc_id, event, ldcp->ldc_status));
24992793Slm66018 
25002793Slm66018 		vgen_handle_evt_up(ldcp, B_FALSE);
25012793Slm66018 
25022793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
25032793Slm66018 	}
25042793Slm66018 
25052793Slm66018 	if (event & LDC_EVT_READ) {
25062793Slm66018 		DBG2((vnetp,
25072793Slm66018 		    "vgen_ldc_cb: id(%lx) event(%lx) READ, status(%d)\n",
25082793Slm66018 		    ldcp->ldc_id, event, ldcp->ldc_status));
25092793Slm66018 
25102793Slm66018 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
25112793Slm66018 		goto vgen_ldccb_rcv;
25122793Slm66018 	}
25132793Slm66018 
25142793Slm66018 	if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
25152793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
25161991Sheppo 			DWARN((vnetp,
25172793Slm66018 			    "vgen_ldc_cb: ldc_status err id(%lx)\n"));
25182793Slm66018 		} else {
25192793Slm66018 			ldcp->ldc_status = istatus;
25201991Sheppo 		}
25212793Slm66018 		DWARN((vnetp,
25222793Slm66018 		    "vgen_ldc_cb: id(%lx) event(%lx) RESET/DOWN, status(%d)\n",
25232793Slm66018 		    ldcp->ldc_id, event, ldcp->ldc_status));
25242793Slm66018 
25252793Slm66018 		vgen_handle_evt_reset(ldcp, B_FALSE);
25261991Sheppo 	}
25271991Sheppo 
25282793Slm66018 	mutex_exit(&ldcp->cblock);
2529*3653Snarayan 	goto vgen_ldccb_exit;
25302793Slm66018 
25312793Slm66018 vgen_ldccb_rcv:
25322793Slm66018 
25332793Slm66018 	/* if event is LDC_EVT_READ, receive all packets */
25341991Sheppo 	do {
25351991Sheppo 		msglen = sizeof (ldcmsg);
25361991Sheppo 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
25371991Sheppo 
25381991Sheppo 		if (rv != 0) {
25391991Sheppo 			DWARN((vnetp,
25401991Sheppo 			    "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) "
25411991Sheppo 			    "len(%d)\n", ldcp->ldc_id, rv, msglen));
25422793Slm66018 			if (rv == ECONNRESET)
2543*3653Snarayan 				goto vgen_ldccb_error;
25441991Sheppo 			break;
25451991Sheppo 		}
25461991Sheppo 		if (msglen == 0) {
25471991Sheppo 			DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA",
25481991Sheppo 			ldcp->ldc_id));
25491991Sheppo 			break;
25501991Sheppo 		}
25511991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
25521991Sheppo 		    ldcp->ldc_id, msglen));
25531991Sheppo 
25541991Sheppo 		tagp = (vio_msg_tag_t *)ldcmsg;
25551991Sheppo 
25561991Sheppo 		if (ldcp->peer_sid) {
25571991Sheppo 			/*
25581991Sheppo 			 * check sid only after we have received peer's sid
25591991Sheppo 			 * in the version negotiate msg.
25601991Sheppo 			 */
25611991Sheppo #ifdef DEBUG
25621991Sheppo 			if (vgen_hdbg & HDBG_BAD_SID) {
25631991Sheppo 				/* simulate bad sid condition */
25641991Sheppo 				tagp->vio_sid = 0;
25651991Sheppo 				vgen_hdbg &= ~(HDBG_BAD_SID);
25661991Sheppo 			}
25671991Sheppo #endif
25682793Slm66018 			rv = vgen_check_sid(ldcp, tagp);
25692793Slm66018 			if (rv != VGEN_SUCCESS) {
25701991Sheppo 				/*
25711991Sheppo 				 * If sid mismatch is detected,
25721991Sheppo 				 * reset the channel.
25731991Sheppo 				 */
25741991Sheppo 				ldcp->need_ldc_reset = B_TRUE;
2575*3653Snarayan 				goto vgen_ldccb_error;
25761991Sheppo 			}
25771991Sheppo 		}
25781991Sheppo 
25791991Sheppo 		switch (tagp->vio_msgtype) {
25801991Sheppo 		case VIO_TYPE_CTRL:
25812793Slm66018 			rv = vgen_handle_ctrlmsg(ldcp, tagp);
25821991Sheppo 			break;
25831991Sheppo 
25841991Sheppo 		case VIO_TYPE_DATA:
25851991Sheppo 			headp = tailp = NULL;
25862793Slm66018 			rv = vgen_handle_datamsg(ldcp, tagp, &headp, &tailp);
25871991Sheppo 			/* build a chain of received packets */
25881991Sheppo 			if (headp != NULL) {
25891991Sheppo 				if (bp == NULL) {
25901991Sheppo 					bp = headp;
25911991Sheppo 					bpt = tailp;
25921991Sheppo 				} else {
25931991Sheppo 					bpt->b_next = headp;
25941991Sheppo 					bpt = tailp;
25951991Sheppo 				}
25961991Sheppo 			}
25971991Sheppo 			break;
25981991Sheppo 
25991991Sheppo 		case VIO_TYPE_ERR:
26001991Sheppo 			vgen_handle_errmsg(ldcp, tagp);
26011991Sheppo 			break;
26021991Sheppo 
26031991Sheppo 		default:
26041991Sheppo 			DWARN((vnetp,
26051991Sheppo 			    "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
26061991Sheppo 			    tagp->vio_msgtype));
26071991Sheppo 			break;
26081991Sheppo 		}
26091991Sheppo 
2610*3653Snarayan vgen_ldccb_error:
26112793Slm66018 		if (rv == ECONNRESET) {
26122793Slm66018 			if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
26132793Slm66018 				DWARN((vnetp,
26142793Slm66018 				    "vgen_ldc_cb: ldc_status err id(%lx)\n"));
26152793Slm66018 			} else {
26162793Slm66018 				ldcp->ldc_status = istatus;
26172793Slm66018 			}
26182793Slm66018 			vgen_handle_evt_reset(ldcp, B_FALSE);
26192793Slm66018 			break;
26202793Slm66018 		} else if (rv) {
26212793Slm66018 			vgen_handshake_retry(ldcp);
26222793Slm66018 			break;
26232793Slm66018 		}
26242793Slm66018 
26251991Sheppo 	} while (msglen);
26261991Sheppo 
26271991Sheppo 	mutex_exit(&ldcp->cblock);
26282793Slm66018 
26291991Sheppo 	/* send up the received packets to MAC layer */
26301991Sheppo 	while (bp != NULL) {
26311991Sheppo 		mp = bp;
26321991Sheppo 		bp = bp->b_next;
26331991Sheppo 		mp->b_next = mp->b_prev = NULL;
26341991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
26351991Sheppo 		    ldcp->ldc_id, MBLKL(mp)));
26362311Sseb 		vnet_rx(vgenp->vnetp, NULL, mp);
26371991Sheppo 	}
2638*3653Snarayan 
2639*3653Snarayan vgen_ldccb_exit:
2640*3653Snarayan 	if (ldcp->cancel_htid) {
2641*3653Snarayan 		/*
2642*3653Snarayan 		 * Cancel handshake timer.
2643*3653Snarayan 		 * untimeout(9F) will not return until the pending callback is
2644*3653Snarayan 		 * cancelled or has run. No problems will result from calling
2645*3653Snarayan 		 * untimeout if the handler has already completed.
2646*3653Snarayan 		 * If the timeout handler did run, then it would just
2647*3653Snarayan 		 * return as cancel_htid is set.
2648*3653Snarayan 		 */
2649*3653Snarayan 		(void) untimeout(ldcp->cancel_htid);
2650*3653Snarayan 		ldcp->cancel_htid = 0;
2651*3653Snarayan 	}
26521991Sheppo 	DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id));
26531991Sheppo 
26541991Sheppo 	return (LDC_SUCCESS);
26551991Sheppo }
26561991Sheppo 
26571991Sheppo /* vgen handshake functions */
26581991Sheppo 
26591991Sheppo /* change the hphase for the channel to the next phase */
26601991Sheppo static vgen_ldc_t *
26611991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
26621991Sheppo {
26631991Sheppo 	if (ldcp->hphase == VH_PHASE3) {
26641991Sheppo 		ldcp->hphase = VH_DONE;
26651991Sheppo 	} else {
26661991Sheppo 		ldcp->hphase++;
26671991Sheppo 	}
26681991Sheppo 	return (ldcp);
26691991Sheppo }
26701991Sheppo 
26711991Sheppo /*
26721991Sheppo  * Check whether the given version is supported or not and
26731991Sheppo  * return VGEN_SUCCESS if supported.
26741991Sheppo  */
26751991Sheppo static int
26761991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
26771991Sheppo uint16_t ver_minor)
26781991Sheppo {
26791991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
26801991Sheppo 	int		i = 0;
26811991Sheppo 
26821991Sheppo 	while (i < VGEN_NUM_VER) {
26831991Sheppo 		if ((versions[i].ver_major == 0) &&
26841991Sheppo 		    (versions[i].ver_minor == 0)) {
26851991Sheppo 			break;
26861991Sheppo 		}
26871991Sheppo 		if ((versions[i].ver_major == ver_major) &&
26881991Sheppo 			(versions[i].ver_minor == ver_minor)) {
26891991Sheppo 			return (VGEN_SUCCESS);
26901991Sheppo 		}
26911991Sheppo 		i++;
26921991Sheppo 	}
26931991Sheppo 	return (VGEN_FAILURE);
26941991Sheppo }
26951991Sheppo 
26961991Sheppo /*
26971991Sheppo  * Given a version, return VGEN_SUCCESS if a lower version is supported.
26981991Sheppo  */
26991991Sheppo static int
27001991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp)
27011991Sheppo {
27021991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
27031991Sheppo 	int		i = 0;
27041991Sheppo 
27051991Sheppo 	while (i < VGEN_NUM_VER) {
27061991Sheppo 		if ((versions[i].ver_major == 0) &&
27071991Sheppo 		    (versions[i].ver_minor == 0)) {
27081991Sheppo 			break;
27091991Sheppo 		}
27101991Sheppo 		/*
27111991Sheppo 		 * if we support a lower minor version within the same major
27121991Sheppo 		 * version, or if we support a lower major version,
27131991Sheppo 		 * update the verp parameter with this lower version and
27141991Sheppo 		 * return success.
27151991Sheppo 		 */
27161991Sheppo 		if (((versions[i].ver_major == verp->ver_major) &&
27171991Sheppo 			(versions[i].ver_minor < verp->ver_minor)) ||
27181991Sheppo 			(versions[i].ver_major < verp->ver_major)) {
27191991Sheppo 				verp->ver_major = versions[i].ver_major;
27201991Sheppo 				verp->ver_minor = versions[i].ver_minor;
27211991Sheppo 				return (VGEN_SUCCESS);
27221991Sheppo 		}
27231991Sheppo 		i++;
27241991Sheppo 	}
27251991Sheppo 
27261991Sheppo 	return (VGEN_FAILURE);
27271991Sheppo }
27281991Sheppo 
27291991Sheppo /*
27301991Sheppo  * wrapper routine to send the given message over ldc using ldc_write().
27311991Sheppo  */
27321991Sheppo static int
27331991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
27341991Sheppo     boolean_t caller_holds_lock)
27351991Sheppo {
27361991Sheppo 	int	rv;
27371991Sheppo 	size_t	len;
27381991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
27391991Sheppo 	uint32_t retries = 0;
27401991Sheppo 
27411991Sheppo 	len = msglen;
27421991Sheppo 	if ((len == 0) || (msg == NULL))
27431991Sheppo 		return (VGEN_FAILURE);
27441991Sheppo 
27451991Sheppo 	if (!caller_holds_lock) {
27461991Sheppo 		mutex_enter(&ldcp->txlock);
27471991Sheppo 	}
27481991Sheppo 
27491991Sheppo 	do {
27501991Sheppo 		len = msglen;
27511991Sheppo 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
27521991Sheppo 		if (retries++ >= vgen_ldcwr_retries)
27531991Sheppo 			break;
27541991Sheppo 	} while (rv == EWOULDBLOCK);
27551991Sheppo 
27561991Sheppo 	if (!caller_holds_lock) {
27571991Sheppo 		mutex_exit(&ldcp->txlock);
27581991Sheppo 	}
27591991Sheppo 
27602793Slm66018 	if (rv != 0) {
27612793Slm66018 		DWARN((vnetp,
27622793Slm66018 		    "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)\n",
27632793Slm66018 		    ldcp->ldc_id, rv, msglen));
27642793Slm66018 		return (rv);
27652793Slm66018 	}
27662793Slm66018 
27672793Slm66018 	if (len != msglen) {
27681991Sheppo 		DWARN((vnetp,
27691991Sheppo 		    "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)"
27701991Sheppo 		    " msglen (%d)\n", ldcp->ldc_id, rv, msglen));
27711991Sheppo 		return (VGEN_FAILURE);
27721991Sheppo 	}
27732793Slm66018 
27741991Sheppo 	return (VGEN_SUCCESS);
27751991Sheppo }
27761991Sheppo 
27771991Sheppo /* send version negotiate message to the peer over ldc */
27781991Sheppo static int
27791991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
27801991Sheppo {
27811991Sheppo 	vio_ver_msg_t	vermsg;
27821991Sheppo 	vio_msg_tag_t	*tagp = &vermsg.tag;
27831991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
27841991Sheppo 	int		rv;
27851991Sheppo 
27861991Sheppo 	bzero(&vermsg, sizeof (vermsg));
27871991Sheppo 
27881991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
27891991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
27901991Sheppo 	tagp->vio_subtype_env = VIO_VER_INFO;
27911991Sheppo 	tagp->vio_sid = ldcp->local_sid;
27921991Sheppo 
27931991Sheppo 	/* get version msg payload from ldcp->local */
27941991Sheppo 	vermsg.ver_major = ldcp->local_hparams.ver_major;
27951991Sheppo 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
27961991Sheppo 	vermsg.dev_class = ldcp->local_hparams.dev_class;
27971991Sheppo 
27981991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
27991991Sheppo 	if (rv != VGEN_SUCCESS) {
28001991Sheppo 		DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed"
28011991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
28022793Slm66018 		return (rv);
28031991Sheppo 	}
28041991Sheppo 
28051991Sheppo 	ldcp->hstate |= VER_INFO_SENT;
28061991Sheppo 	DBG2((vnetp,
28071991Sheppo 	    "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
28081991Sheppo 	    ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor));
28091991Sheppo 
28101991Sheppo 	return (VGEN_SUCCESS);
28111991Sheppo }
28121991Sheppo 
28131991Sheppo /* send attr info message to the peer over ldc */
28141991Sheppo static int
28151991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
28161991Sheppo {
28171991Sheppo 	vnet_attr_msg_t	attrmsg;
28181991Sheppo 	vio_msg_tag_t	*tagp = &attrmsg.tag;
28191991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
28201991Sheppo 	int		rv;
28211991Sheppo 
28221991Sheppo 	bzero(&attrmsg, sizeof (attrmsg));
28231991Sheppo 
28241991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
28251991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
28261991Sheppo 	tagp->vio_subtype_env = VIO_ATTR_INFO;
28271991Sheppo 	tagp->vio_sid = ldcp->local_sid;
28281991Sheppo 
28291991Sheppo 	/* get attr msg payload from ldcp->local */
28301991Sheppo 	attrmsg.mtu = ldcp->local_hparams.mtu;
28311991Sheppo 	attrmsg.addr = ldcp->local_hparams.addr;
28321991Sheppo 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
28331991Sheppo 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
28341991Sheppo 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
28351991Sheppo 
28361991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
28371991Sheppo 	if (rv != VGEN_SUCCESS) {
28381991Sheppo 		DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed"
28391991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
28402793Slm66018 		return (rv);
28411991Sheppo 	}
28421991Sheppo 
28431991Sheppo 	ldcp->hstate |= ATTR_INFO_SENT;
28441991Sheppo 	DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
28451991Sheppo 	    ldcp->ldc_id));
28461991Sheppo 
28471991Sheppo 	return (VGEN_SUCCESS);
28481991Sheppo }
28491991Sheppo 
28501991Sheppo /* send descriptor ring register message to the peer over ldc */
28511991Sheppo static int
28521991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp)
28531991Sheppo {
28541991Sheppo 	vio_dring_reg_msg_t	msg;
28551991Sheppo 	vio_msg_tag_t		*tagp = &msg.tag;
28561991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
28571991Sheppo 	int		rv;
28581991Sheppo 
28591991Sheppo 	bzero(&msg, sizeof (msg));
28601991Sheppo 
28611991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
28621991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
28631991Sheppo 	tagp->vio_subtype_env = VIO_DRING_REG;
28641991Sheppo 	tagp->vio_sid = ldcp->local_sid;
28651991Sheppo 
28661991Sheppo 	/* get dring info msg payload from ldcp->local */
28671991Sheppo 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
28681991Sheppo 		sizeof (ldc_mem_cookie_t));
28691991Sheppo 	msg.ncookies = ldcp->local_hparams.num_dcookies;
28701991Sheppo 	msg.num_descriptors = ldcp->local_hparams.num_desc;
28711991Sheppo 	msg.descriptor_size = ldcp->local_hparams.desc_size;
28721991Sheppo 
28731991Sheppo 	/*
28741991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
28751991Sheppo 	 * value and sends it in the ack, which is saved in
28761991Sheppo 	 * vgen_handle_dring_reg().
28771991Sheppo 	 */
28781991Sheppo 	msg.dring_ident = 0;
28791991Sheppo 
28801991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
28811991Sheppo 	if (rv != VGEN_SUCCESS) {
28821991Sheppo 		DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed"
28831991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
28842793Slm66018 		return (rv);
28851991Sheppo 	}
28861991Sheppo 
28871991Sheppo 	ldcp->hstate |= DRING_INFO_SENT;
28881991Sheppo 	DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
28891991Sheppo 	    ldcp->ldc_id));
28901991Sheppo 
28911991Sheppo 	return (VGEN_SUCCESS);
28921991Sheppo }
28931991Sheppo 
28941991Sheppo static int
28951991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
28961991Sheppo {
28971991Sheppo 	vio_rdx_msg_t	rdxmsg;
28981991Sheppo 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
28991991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
29001991Sheppo 	int		rv;
29011991Sheppo 
29021991Sheppo 	bzero(&rdxmsg, sizeof (rdxmsg));
29031991Sheppo 
29041991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
29051991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
29061991Sheppo 	tagp->vio_subtype_env = VIO_RDX;
29071991Sheppo 	tagp->vio_sid = ldcp->local_sid;
29081991Sheppo 
29091991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
29101991Sheppo 	if (rv != VGEN_SUCCESS) {
29111991Sheppo 		DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed"
29121991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
29132793Slm66018 		return (rv);
29141991Sheppo 	}
29151991Sheppo 
29161991Sheppo 	ldcp->hstate |= RDX_INFO_SENT;
29171991Sheppo 	DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
29181991Sheppo 	    ldcp->ldc_id));
29191991Sheppo 
29201991Sheppo 	return (VGEN_SUCCESS);
29211991Sheppo }
29221991Sheppo 
29231991Sheppo /* send descriptor ring data message to the peer over ldc */
29241991Sheppo static int
29252336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
29261991Sheppo {
29271991Sheppo 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
29281991Sheppo 	vio_msg_tag_t	*tagp = &msgp->tag;
29291991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
29301991Sheppo 	int		rv;
29311991Sheppo 
29321991Sheppo 	bzero(msgp, sizeof (*msgp));
29331991Sheppo 
29341991Sheppo 	tagp->vio_msgtype = VIO_TYPE_DATA;
29351991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
29361991Sheppo 	tagp->vio_subtype_env = VIO_DRING_DATA;
29371991Sheppo 	tagp->vio_sid = ldcp->local_sid;
29381991Sheppo 
29392336Snarayan 	msgp->seq_num = ldcp->next_txseq;
29401991Sheppo 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
29411991Sheppo 	msgp->start_idx = start;
29421991Sheppo 	msgp->end_idx = end;
29431991Sheppo 
29441991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
29451991Sheppo 	if (rv != VGEN_SUCCESS) {
29461991Sheppo 		DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed"
29472793Slm66018 		    " id (%lx)\n", ldcp->ldc_id));
29482793Slm66018 		return (rv);
29491991Sheppo 	}
29501991Sheppo 
29512336Snarayan 	ldcp->next_txseq++;
29522336Snarayan 	ldcp->statsp->dring_data_msgs++;
29532336Snarayan 
29541991Sheppo 	DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
29551991Sheppo 	    ldcp->ldc_id));
29561991Sheppo 
29571991Sheppo 	return (VGEN_SUCCESS);
29581991Sheppo }
29591991Sheppo 
29601991Sheppo /* send multicast addr info message to vsw */
29611991Sheppo static int
29621991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
29631991Sheppo {
29641991Sheppo 	vnet_mcast_msg_t	mcastmsg;
29651991Sheppo 	vnet_mcast_msg_t	*msgp;
29661991Sheppo 	vio_msg_tag_t		*tagp;
29671991Sheppo 	vgen_t			*vgenp;
29681991Sheppo 	void			*vnetp;
29691991Sheppo 	struct ether_addr	*mca;
29701991Sheppo 	int			rv;
29711991Sheppo 	int			i;
29721991Sheppo 	uint32_t		size;
29731991Sheppo 	uint32_t		mccount;
29741991Sheppo 	uint32_t		n;
29751991Sheppo 
29761991Sheppo 	msgp = &mcastmsg;
29771991Sheppo 	tagp = &msgp->tag;
29781991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
29791991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
29801991Sheppo 
29811991Sheppo 	mccount = vgenp->mccount;
29821991Sheppo 	i = 0;
29831991Sheppo 
29841991Sheppo 	do {
29851991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
29861991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
29871991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
29881991Sheppo 		tagp->vio_sid = ldcp->local_sid;
29891991Sheppo 
29901991Sheppo 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
29911991Sheppo 		size = n * sizeof (struct ether_addr);
29921991Sheppo 
29931991Sheppo 		mca = &(vgenp->mctab[i]);
29941991Sheppo 		bcopy(mca, (msgp->mca), size);
29951991Sheppo 		msgp->set = B_TRUE;
29961991Sheppo 		msgp->count = n;
29971991Sheppo 
29981991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
29991991Sheppo 		    B_FALSE);
30001991Sheppo 		if (rv != VGEN_SUCCESS) {
30011991Sheppo 			DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err"
30021991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
30032793Slm66018 			return (rv);
30041991Sheppo 		}
30051991Sheppo 
30061991Sheppo 		mccount -= n;
30071991Sheppo 		i += n;
30081991Sheppo 
30091991Sheppo 	} while (mccount);
30101991Sheppo 
30111991Sheppo 	return (VGEN_SUCCESS);
30121991Sheppo }
30131991Sheppo 
30141991Sheppo /* Initiate Phase 2 of handshake */
30151991Sheppo static int
30161991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
30171991Sheppo {
30181991Sheppo 	int rv;
30192793Slm66018 	uint32_t ncookies = 0;
30202793Slm66018 	void	*vnetp = LDC_TO_VNET(ldcp);
30211991Sheppo #ifdef DEBUG
30221991Sheppo 	if (vgen_hdbg & HDBG_OUT_STATE) {
30231991Sheppo 		/* simulate out of state condition */
30241991Sheppo 		vgen_hdbg &= ~(HDBG_OUT_STATE);
30251991Sheppo 		rv = vgen_send_rdx_info(ldcp);
30261991Sheppo 		return (rv);
30271991Sheppo 	}
30281991Sheppo 	if (vgen_hdbg & HDBG_TIMEOUT) {
30291991Sheppo 		/* simulate timeout condition */
30301991Sheppo 		vgen_hdbg &= ~(HDBG_TIMEOUT);
30311991Sheppo 		return (VGEN_SUCCESS);
30321991Sheppo 	}
30331991Sheppo #endif
30342793Slm66018 	rv = vgen_send_attr_info(ldcp);
30352793Slm66018 	if (rv != VGEN_SUCCESS) {
30361991Sheppo 		return (rv);
30371991Sheppo 	}
30382793Slm66018 
30392793Slm66018 	/* Bind descriptor ring to the channel */
30402793Slm66018 	if (ldcp->num_txdcookies == 0) {
30412793Slm66018 		rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
30422793Slm66018 		    LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
30432793Slm66018 		if (rv != 0) {
30442793Slm66018 			DWARN((vnetp, "vgen_handshake_phase2: id (%lx) "
30452793Slm66018 			    "ldc_mem_dring_bind failed rv(%x)\n",
30462793Slm66018 			    ldcp->ldc_id, rv));
30472793Slm66018 			return (rv);
30482793Slm66018 		}
30492793Slm66018 		ASSERT(ncookies == 1);
30502793Slm66018 		ldcp->num_txdcookies = ncookies;
30512793Slm66018 	}
30522793Slm66018 
30532793Slm66018 	/* update local dring_info params */
30542793Slm66018 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
30552793Slm66018 		sizeof (ldc_mem_cookie_t));
30562793Slm66018 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
30572793Slm66018 	ldcp->local_hparams.num_desc = ldcp->num_txds;
30582793Slm66018 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
30592793Slm66018 
30602793Slm66018 	rv = vgen_send_dring_reg(ldcp);
30612793Slm66018 	if (rv != VGEN_SUCCESS) {
30621991Sheppo 		return (rv);
30631991Sheppo 	}
30641991Sheppo 
30651991Sheppo 	return (VGEN_SUCCESS);
30661991Sheppo }
30671991Sheppo 
30681991Sheppo /*
30691991Sheppo  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
30701991Sheppo  * This can happen after a channel comes up (status: LDC_UP) or
30711991Sheppo  * when handshake gets terminated due to various conditions.
30721991Sheppo  */
30731991Sheppo static void
30741991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp)
30751991Sheppo {
30761991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
30771991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
30781991Sheppo 	ldc_status_t istatus;
30792793Slm66018 	int rv;
30801991Sheppo 
30811991Sheppo 	DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id));
30821991Sheppo 	/* reset hstate and hphase */
30831991Sheppo 	ldcp->hstate = 0;
30841991Sheppo 	ldcp->hphase = VH_PHASE0;
30851991Sheppo 
3086*3653Snarayan 	/*
3087*3653Snarayan 	 * Save the id of pending handshake timer in cancel_htid.
3088*3653Snarayan 	 * This will be checked in vgen_ldc_cb() and the handshake timer will
3089*3653Snarayan 	 * be cancelled after releasing cblock.
3090*3653Snarayan 	 */
30911991Sheppo 	if (ldcp->htid) {
3092*3653Snarayan 		ldcp->cancel_htid = ldcp->htid;
30931991Sheppo 		ldcp->htid = 0;
30941991Sheppo 	}
30951991Sheppo 
30961991Sheppo 	if (ldcp->local_hparams.dring_ready) {
30971991Sheppo 		ldcp->local_hparams.dring_ready = B_FALSE;
30982793Slm66018 	}
30992793Slm66018 
31002793Slm66018 	/* Unbind tx descriptor ring from the channel */
31012793Slm66018 	if (ldcp->num_txdcookies) {
31022793Slm66018 		rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
31032793Slm66018 		if (rv != 0) {
31042793Slm66018 			DWARN((vnetp,
31052793Slm66018 			    "vgen_reset_hphase: ldc_mem_dring_unbind "
31062793Slm66018 			    "failed id(%lx)\n", ldcp->ldc_id));
31072793Slm66018 		}
31082793Slm66018 		ldcp->num_txdcookies = 0;
31091991Sheppo 	}
31101991Sheppo 
31111991Sheppo 	if (ldcp->peer_hparams.dring_ready) {
31121991Sheppo 		ldcp->peer_hparams.dring_ready = B_FALSE;
31131991Sheppo 		/* Unmap peer's dring */
31141991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
31151991Sheppo 		vgen_clobber_rxds(ldcp);
31161991Sheppo 	}
31171991Sheppo 
31181991Sheppo 	vgen_clobber_tbufs(ldcp);
31191991Sheppo 
31201991Sheppo 	/*
31211991Sheppo 	 * clear local handshake params and initialize.
31221991Sheppo 	 */
31231991Sheppo 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
31241991Sheppo 
31251991Sheppo 	/* set version to the highest version supported */
31261991Sheppo 	ldcp->local_hparams.ver_major =
31271991Sheppo 			ldcp->vgen_versions[0].ver_major;
31281991Sheppo 	ldcp->local_hparams.ver_minor =
31291991Sheppo 			ldcp->vgen_versions[0].ver_minor;
31301991Sheppo 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
31311991Sheppo 
31321991Sheppo 	/* set attr_info params */
31331991Sheppo 	ldcp->local_hparams.mtu = ETHERMAX;
31341991Sheppo 	ldcp->local_hparams.addr =
31351991Sheppo 		vgen_macaddr_strtoul(vgenp->macaddr);
31361991Sheppo 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
31371991Sheppo 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE;
31381991Sheppo 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
31391991Sheppo 
31401991Sheppo 	/*
31412793Slm66018 	 * Note: dring is created, but not bound yet.
31422793Slm66018 	 * local dring_info params will be updated when we bind the dring in
31432793Slm66018 	 * vgen_handshake_phase2().
31441991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
31451991Sheppo 	 * value and sends it in the ack, which is saved in
31461991Sheppo 	 * vgen_handle_dring_reg().
31471991Sheppo 	 */
31481991Sheppo 	ldcp->local_hparams.dring_ident = 0;
31491991Sheppo 
31501991Sheppo 	/* clear peer_hparams */
31511991Sheppo 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
31521991Sheppo 
31531991Sheppo 	/* reset the channel if required */
31541991Sheppo 	if (ldcp->need_ldc_reset) {
31551991Sheppo 		DWARN((vnetp,
31561991Sheppo 		    "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
31571991Sheppo 		    ldcp->ldc_id));
31581991Sheppo 		ldcp->need_ldc_reset = B_FALSE;
31592410Slm66018 		(void) ldc_down(ldcp->ldc_handle);
31601991Sheppo 		(void) ldc_status(ldcp->ldc_handle, &istatus);
31611991Sheppo 		DBG2((vnetp,
31622793Slm66018 		    "vgen_reset_hphase: id (%lx), Reset Done,ldc_status(%x)\n",
31631991Sheppo 		    ldcp->ldc_id, istatus));
31641991Sheppo 		ldcp->ldc_status = istatus;
31652793Slm66018 
31661991Sheppo 		/* clear sids */
31671991Sheppo 		ldcp->local_sid = 0;
31681991Sheppo 		ldcp->peer_sid = 0;
31692793Slm66018 
31702793Slm66018 		/* try to bring the channel up */
31712793Slm66018 		rv = ldc_up(ldcp->ldc_handle);
31722793Slm66018 		if (rv != 0) {
31732793Slm66018 			DWARN((vnetp,
31742793Slm66018 			    "vgen_reset_hphase: ldc_up err id(%lx) rv(%d)\n",
31752793Slm66018 			    ldcp->ldc_id, rv));
31762793Slm66018 		}
31772793Slm66018 
31782793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
31792793Slm66018 			DWARN((vnetp,
31802793Slm66018 			    "vgen_reset_hphase: ldc_status err id(%lx)\n"));
31812793Slm66018 		} else {
31822793Slm66018 			ldcp->ldc_status = istatus;
31832793Slm66018 		}
31841991Sheppo 	}
31851991Sheppo }
31861991Sheppo 
31871991Sheppo /* wrapper function for vgen_reset_hphase */
31881991Sheppo static void
31891991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp)
31901991Sheppo {
31911991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->cblock));
31921991Sheppo 	mutex_enter(&ldcp->txlock);
31931991Sheppo 	mutex_enter(&ldcp->tclock);
31941991Sheppo 
31951991Sheppo 	vgen_reset_hphase(ldcp);
31961991Sheppo 
31971991Sheppo 	mutex_exit(&ldcp->tclock);
31981991Sheppo 	mutex_exit(&ldcp->txlock);
31991991Sheppo }
32001991Sheppo 
32011991Sheppo /*
32021991Sheppo  * Initiate handshake with the peer by sending various messages
32031991Sheppo  * based on the handshake-phase that the channel is currently in.
32041991Sheppo  */
32051991Sheppo static void
32061991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
32071991Sheppo {
32081991Sheppo 	uint32_t hphase = ldcp->hphase;
32091991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
32101991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
32112793Slm66018 	ldc_status_t	istatus;
32122793Slm66018 	int	rv = 0;
32131991Sheppo 
32141991Sheppo 	switch (hphase) {
32151991Sheppo 
32161991Sheppo 	case VH_PHASE1:
32171991Sheppo 
32181991Sheppo 		/*
32191991Sheppo 		 * start timer, for entire handshake process, turn this timer
32201991Sheppo 		 * off if all phases of handshake complete successfully and
32211991Sheppo 		 * hphase goes to VH_DONE(below) or
32221991Sheppo 		 * vgen_reset_hphase() gets called or
32231991Sheppo 		 * channel is reset due to errors or
32241991Sheppo 		 * vgen_ldc_uninit() is invoked(vgen_stop).
32251991Sheppo 		 */
32261991Sheppo 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
32271991Sheppo 		    drv_usectohz(vgen_hwd_interval * 1000));
32281991Sheppo 
32291991Sheppo 		/* Phase 1 involves negotiating the version */
32302793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
32311991Sheppo 		break;
32321991Sheppo 
32331991Sheppo 	case VH_PHASE2:
32342793Slm66018 		rv = vgen_handshake_phase2(ldcp);
32351991Sheppo 		break;
32361991Sheppo 
32371991Sheppo 	case VH_PHASE3:
32382793Slm66018 		rv = vgen_send_rdx_info(ldcp);
32391991Sheppo 		break;
32401991Sheppo 
32411991Sheppo 	case VH_DONE:
3242*3653Snarayan 		/*
3243*3653Snarayan 		 * Save the id of pending handshake timer in cancel_htid.
3244*3653Snarayan 		 * This will be checked in vgen_ldc_cb() and the handshake
3245*3653Snarayan 		 * timer will be cancelled after releasing cblock.
3246*3653Snarayan 		 */
32471991Sheppo 		if (ldcp->htid) {
3248*3653Snarayan 			ldcp->cancel_htid = ldcp->htid;
32491991Sheppo 			ldcp->htid = 0;
32501991Sheppo 		}
32511991Sheppo 		ldcp->hretries = 0;
32521991Sheppo #if 0
32531991Sheppo 		vgen_print_ldcinfo(ldcp);
32541991Sheppo #endif
32551991Sheppo 		DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n",
32561991Sheppo 		    ldcp->ldc_id));
32571991Sheppo 
32581991Sheppo 		if (ldcp->need_mcast_sync) {
32591991Sheppo 			/* need to sync multicast table with vsw */
32601991Sheppo 
32611991Sheppo 			ldcp->need_mcast_sync = B_FALSE;
32621991Sheppo 			mutex_exit(&ldcp->cblock);
32631991Sheppo 
32641991Sheppo 			mutex_enter(&vgenp->lock);
32652793Slm66018 			rv = vgen_send_mcast_info(ldcp);
32661991Sheppo 			mutex_exit(&vgenp->lock);
32671991Sheppo 
32681991Sheppo 			mutex_enter(&ldcp->cblock);
32692793Slm66018 			if (rv != VGEN_SUCCESS)
32702793Slm66018 				break;
32711991Sheppo 		}
32722793Slm66018 
32732793Slm66018 		/*
32742793Slm66018 		 * Check if mac layer should be notified to restart
32752793Slm66018 		 * transmissions. This can happen if the channel got
32762793Slm66018 		 * reset and vgen_clobber_tbufs() is called, while
32772793Slm66018 		 * need_resched is set.
32782793Slm66018 		 */
32792793Slm66018 		mutex_enter(&ldcp->tclock);
32802793Slm66018 		if (ldcp->need_resched) {
32812793Slm66018 			ldcp->need_resched = B_FALSE;
32822793Slm66018 			vnet_tx_update(vgenp->vnetp);
32832793Slm66018 		}
32842793Slm66018 		mutex_exit(&ldcp->tclock);
32852793Slm66018 
32861991Sheppo 		break;
32871991Sheppo 
32881991Sheppo 	default:
32891991Sheppo 		break;
32901991Sheppo 	}
32912793Slm66018 
32922793Slm66018 	if (rv == ECONNRESET) {
32932793Slm66018 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
32942793Slm66018 			DWARN((vnetp,
32952793Slm66018 			    "vgen_handshake: ldc_status err id(%lx)\n"));
32962793Slm66018 		} else {
32972793Slm66018 			ldcp->ldc_status = istatus;
32982793Slm66018 		}
32992793Slm66018 		vgen_handle_evt_reset(ldcp, B_FALSE);
33002793Slm66018 	} else if (rv) {
33012793Slm66018 		vgen_handshake_reset(ldcp);
33022793Slm66018 	}
33031991Sheppo }
33041991Sheppo 
33051991Sheppo /*
33061991Sheppo  * Check if the current handshake phase has completed successfully and
33071991Sheppo  * return the status.
33081991Sheppo  */
33091991Sheppo static int
33101991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
33111991Sheppo {
33121991Sheppo 	uint32_t	hphase = ldcp->hphase;
33131991Sheppo 	int 		status = 0;
33141991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
33151991Sheppo 
33161991Sheppo 	switch (hphase) {
33171991Sheppo 
33181991Sheppo 	case VH_PHASE1:
33191991Sheppo 		/*
33201991Sheppo 		 * Phase1 is done, if version negotiation
33211991Sheppo 		 * completed successfully.
33221991Sheppo 		 */
33231991Sheppo 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
33241991Sheppo 			VER_NEGOTIATED);
33251991Sheppo 		break;
33261991Sheppo 
33271991Sheppo 	case VH_PHASE2:
33281991Sheppo 		/*
33291991Sheppo 		 * Phase 2 is done, if attr info and dring info
33301991Sheppo 		 * have been exchanged successfully.
33311991Sheppo 		 */
33321991Sheppo 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
33331991Sheppo 			    ATTR_INFO_EXCHANGED) &&
33341991Sheppo 			    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
33351991Sheppo 			    DRING_INFO_EXCHANGED));
33361991Sheppo 		break;
33371991Sheppo 
33381991Sheppo 	case VH_PHASE3:
33391991Sheppo 		/* Phase 3 is done, if rdx msg has been exchanged */
33401991Sheppo 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
33411991Sheppo 			RDX_EXCHANGED);
33421991Sheppo 		break;
33431991Sheppo 
33441991Sheppo 	default:
33451991Sheppo 		break;
33461991Sheppo 	}
33471991Sheppo 
33481991Sheppo 	if (status == 0) {
33491991Sheppo 		return (VGEN_FAILURE);
33501991Sheppo 	}
33511991Sheppo 	DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase));
33521991Sheppo 	return (VGEN_SUCCESS);
33531991Sheppo }
33541991Sheppo 
33551991Sheppo /* retry handshake on failure */
33561991Sheppo static void
33571991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp)
33581991Sheppo {
33591991Sheppo 	/* reset handshake phase */
33601991Sheppo 	vgen_handshake_reset(ldcp);
3361*3653Snarayan 
3362*3653Snarayan 	/* handshake retry is specified and the channel is UP */
3363*3653Snarayan 	if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) {
3364*3653Snarayan 		if (ldcp->hretries++ < vgen_max_hretries) {
3365*3653Snarayan 			ldcp->local_sid = ddi_get_lbolt();
33661991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3367*3653Snarayan 		}
33681991Sheppo 	}
33691991Sheppo }
33701991Sheppo 
33711991Sheppo /*
33721991Sheppo  * Handle a version info msg from the peer or an ACK/NACK from the peer
33731991Sheppo  * to a version info msg that we sent.
33741991Sheppo  */
33752793Slm66018 static int
33761991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
33771991Sheppo {
33781991Sheppo 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
33791991Sheppo 	int		ack = 0;
33801991Sheppo 	int		failed = 0;
33811991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
33821991Sheppo 	int		idx;
33831991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
33842793Slm66018 	int		rv = 0;
33851991Sheppo 
33861991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: enter\n"));
33871991Sheppo 	switch (tagp->vio_subtype) {
33881991Sheppo 	case VIO_SUBTYPE_INFO:
33891991Sheppo 
33901991Sheppo 		/*  Cache sid of peer if this is the first time */
33911991Sheppo 		if (ldcp->peer_sid == 0) {
33921991Sheppo 			DBG2((vnetp,
33931991Sheppo 			    "vgen_handle_version_negotiate: id (%lx) Caching"
33941991Sheppo 			    " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid));
33951991Sheppo 			ldcp->peer_sid = tagp->vio_sid;
33961991Sheppo 		}
33971991Sheppo 
33981991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
33991991Sheppo 			/*
34001991Sheppo 			 * If we are not already in VH_PHASE1, reset to
34011991Sheppo 			 * pre-handshake state, and initiate handshake
34021991Sheppo 			 * to the peer too.
34031991Sheppo 			 */
34041991Sheppo 			vgen_handshake_reset(ldcp);
34051991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
34061991Sheppo 		}
34071991Sheppo 		ldcp->hstate |= VER_INFO_RCVD;
34081991Sheppo 
34091991Sheppo 		/* save peer's requested values */
34101991Sheppo 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
34111991Sheppo 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
34121991Sheppo 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
34131991Sheppo 
34141991Sheppo 		if ((vermsg->dev_class != VDEV_NETWORK) &&
34151991Sheppo 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
34161991Sheppo 			/* unsupported dev_class, send NACK */
34171991Sheppo 
34182793Slm66018 			DWARN((vnetp,
34192793Slm66018 			    "vgen_handle_version_negotiate: Version"
34202793Slm66018 			    " Negotiation Failed id (%lx)\n", ldcp->ldc_id));
34212793Slm66018 
34221991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
34231991Sheppo 			tagp->vio_sid = ldcp->local_sid;
34241991Sheppo 			/* send reply msg back to peer */
34252793Slm66018 			rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
34261991Sheppo 			    sizeof (*vermsg), B_FALSE);
34272793Slm66018 			if (rv != VGEN_SUCCESS) {
34282793Slm66018 				return (rv);
34292793Slm66018 			}
34302793Slm66018 			return (VGEN_FAILURE);
34311991Sheppo 		}
34321991Sheppo 
34331991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD,"
34341991Sheppo 		    " id (%lx), ver(%d,%d)\n", ldcp->ldc_id,
34351991Sheppo 		    vermsg->ver_major,  vermsg->ver_minor));
34361991Sheppo 
34371991Sheppo 		idx = 0;
34381991Sheppo 
34391991Sheppo 		for (;;) {
34401991Sheppo 
34411991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
34421991Sheppo 
34431991Sheppo 				/* nack with next lower version */
34441991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
34451991Sheppo 				vermsg->ver_major = versions[idx].ver_major;
34461991Sheppo 				vermsg->ver_minor = versions[idx].ver_minor;
34471991Sheppo 				break;
34481991Sheppo 			}
34491991Sheppo 
34501991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
34511991Sheppo 
34521991Sheppo 				/* major version match - ACK version */
34531991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
34541991Sheppo 				ack = 1;
34551991Sheppo 
34561991Sheppo 				/*
34571991Sheppo 				 * lower minor version to the one this endpt
34581991Sheppo 				 * supports, if necessary
34591991Sheppo 				 */
34601991Sheppo 				if (vermsg->ver_minor >
34611991Sheppo 				    versions[idx].ver_minor) {
34621991Sheppo 					vermsg->ver_minor =
34631991Sheppo 						versions[idx].ver_minor;
34641991Sheppo 					ldcp->peer_hparams.ver_minor =
34651991Sheppo 						versions[idx].ver_minor;
34661991Sheppo 				}
34671991Sheppo 				break;
34681991Sheppo 			}
34691991Sheppo 
34701991Sheppo 			idx++;
34711991Sheppo 
34721991Sheppo 			if (idx == VGEN_NUM_VER) {
34731991Sheppo 
34741991Sheppo 				/* no version match - send NACK */
34751991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
34761991Sheppo 				vermsg->ver_major = 0;
34771991Sheppo 				vermsg->ver_minor = 0;
34781991Sheppo 				failed = 1;
34791991Sheppo 				break;
34801991Sheppo 			}
34811991Sheppo 
34821991Sheppo 		}
34831991Sheppo 
34841991Sheppo 		tagp->vio_sid = ldcp->local_sid;
34851991Sheppo 
34861991Sheppo 		/* send reply msg back to peer */
34872793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
34882793Slm66018 		    B_FALSE);
34892793Slm66018 		if (rv != VGEN_SUCCESS) {
34902793Slm66018 			return (rv);
34911991Sheppo 		}
34921991Sheppo 
34931991Sheppo 		if (ack) {
34941991Sheppo 			ldcp->hstate |= VER_ACK_SENT;
34951991Sheppo 			DBG2((vnetp, "vgen_handle_version_negotiate:"
34961991Sheppo 			    " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
34971991Sheppo 			    ldcp->ldc_id, vermsg->ver_major,
34981991Sheppo 			    vermsg->ver_minor));
34991991Sheppo 		}
35001991Sheppo 		if (failed) {
35011991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
35021991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
35031991Sheppo 			    ldcp->ldc_id));
35042793Slm66018 			return (VGEN_FAILURE);
35051991Sheppo 		}
35061991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
35071991Sheppo 
35081991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
35091991Sheppo 
35101991Sheppo 			/* local and peer versions match? */
35111991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
35121991Sheppo 				ldcp->peer_hparams.ver_major) &&
35131991Sheppo 				(ldcp->local_hparams.ver_minor ==
35141991Sheppo 				ldcp->peer_hparams.ver_minor));
35151991Sheppo 
35161991Sheppo 			/* move to the next phase */
35171991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
35181991Sheppo 		}
35191991Sheppo 
35201991Sheppo 		break;
35211991Sheppo 
35221991Sheppo 	case VIO_SUBTYPE_ACK:
35231991Sheppo 
35241991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
35251991Sheppo 			/*  This should not happen. */
35261991Sheppo 			DWARN((vnetp,
35271991Sheppo 			    "vgen_handle_version_negotiate:"
35281991Sheppo 			    " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
35291991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
35302793Slm66018 			return (VGEN_FAILURE);
35311991Sheppo 		}
35321991Sheppo 
35331991Sheppo 		/* SUCCESS - we have agreed on a version */
35341991Sheppo 		ldcp->local_hparams.ver_major = vermsg->ver_major;
35351991Sheppo 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
35361991Sheppo 		ldcp->hstate |= VER_ACK_RCVD;
35371991Sheppo 
35381991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
35391991Sheppo 		    " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
35401991Sheppo 		    ldcp->ldc_id, vermsg->ver_major,  vermsg->ver_minor));
35411991Sheppo 
35421991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
35431991Sheppo 
35441991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
35451991Sheppo 
35461991Sheppo 			/* local and peer versions match? */
35471991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
35481991Sheppo 				ldcp->peer_hparams.ver_major) &&
35491991Sheppo 				(ldcp->local_hparams.ver_minor ==
35501991Sheppo 				ldcp->peer_hparams.ver_minor));
35511991Sheppo 
35521991Sheppo 			/* move to the next phase */
35531991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
35541991Sheppo 		}
35551991Sheppo 		break;
35561991Sheppo 
35571991Sheppo 	case VIO_SUBTYPE_NACK:
35581991Sheppo 
35591991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
35601991Sheppo 			/*  This should not happen.  */
35611991Sheppo 			DWARN((vnetp,
35621991Sheppo 			    "vgen_handle_version_negotiate:"
35631991Sheppo 			    " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
35641991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
35652793Slm66018 			return (VGEN_FAILURE);
35661991Sheppo 		}
35671991Sheppo 
35681991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
35691991Sheppo 		    " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
35701991Sheppo 		    ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor));
35711991Sheppo 
35721991Sheppo 		/* check if version in NACK is zero */
35731991Sheppo 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
35741991Sheppo 			/*
35751991Sheppo 			 * Version Negotiation has failed.
35761991Sheppo 			 */
35771991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
35781991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
35791991Sheppo 			    ldcp->ldc_id));
35802793Slm66018 			return (VGEN_FAILURE);
35811991Sheppo 		}
35821991Sheppo 
35831991Sheppo 		idx = 0;
35841991Sheppo 
35851991Sheppo 		for (;;) {
35861991Sheppo 
35871991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
35881991Sheppo 				/* select next lower version */
35891991Sheppo 
35901991Sheppo 				ldcp->local_hparams.ver_major =
35911991Sheppo 					versions[idx].ver_major;
35921991Sheppo 				ldcp->local_hparams.ver_minor =
35931991Sheppo 					versions[idx].ver_minor;
35941991Sheppo 				break;
35951991Sheppo 			}
35961991Sheppo 
35971991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
35981991Sheppo 				/* major version match */
35991991Sheppo 
36001991Sheppo 				ldcp->local_hparams.ver_major =
36011991Sheppo 					versions[idx].ver_major;
36021991Sheppo 
36031991Sheppo 				ldcp->local_hparams.ver_minor =
36041991Sheppo 					versions[idx].ver_minor;
36051991Sheppo 				break;
36061991Sheppo 			}
36071991Sheppo 
36081991Sheppo 			idx++;
36091991Sheppo 
36101991Sheppo 			if (idx == VGEN_NUM_VER) {
36111991Sheppo 				/*
36121991Sheppo 				 * no version match.
36131991Sheppo 				 * Version Negotiation has failed.
36141991Sheppo 				 */
36151991Sheppo 				DWARN((vnetp, "vgen_handle_version_negotiate:"
36161991Sheppo 				    " Version Negotiation Failed id (%lx)\n",
36171991Sheppo 				    ldcp->ldc_id));
36182793Slm66018 				return (VGEN_FAILURE);
36191991Sheppo 			}
36201991Sheppo 
36211991Sheppo 		}
36221991Sheppo 
36232793Slm66018 		rv = vgen_send_version_negotiate(ldcp);
36242793Slm66018 		if (rv != VGEN_SUCCESS) {
36252793Slm66018 			return (rv);
36261991Sheppo 		}
36271991Sheppo 
36281991Sheppo 		break;
36291991Sheppo 	}
36302793Slm66018 
36311991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: exit\n"));
36322793Slm66018 	return (VGEN_SUCCESS);
36331991Sheppo }
36341991Sheppo 
36351991Sheppo /* Check if the attributes are supported */
36361991Sheppo static int
36371991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
36381991Sheppo {
36391991Sheppo 	_NOTE(ARGUNUSED(ldcp))
36401991Sheppo 
36411991Sheppo #if 0
36421991Sheppo 	uint64_t port_macaddr;
36431991Sheppo 	port_macaddr = vgen_macaddr_strtoul((uint8_t *)
36441991Sheppo 				&(ldcp->portp->macaddr));
36451991Sheppo #endif
36461991Sheppo 	/*
36471991Sheppo 	 * currently, we support these attr values:
36481991Sheppo 	 * mtu of ethernet, addr_type of mac, xfer_mode of
36491991Sheppo 	 * ldc shared memory, ack_freq of 0 (data is acked if
36501991Sheppo 	 * the ack bit is set in the descriptor) and the address should
36511991Sheppo 	 * match the address in the port node.
36521991Sheppo 	 */
36531991Sheppo 	if ((msg->mtu != ETHERMAX) ||
36541991Sheppo 	    (msg->addr_type != ADDR_TYPE_MAC) ||
36551991Sheppo 	    (msg->xfer_mode != VIO_DRING_MODE) ||
36561991Sheppo 	    (msg->ack_freq > 64)) {
36571991Sheppo #if 0
36581991Sheppo 	    (msg->addr != port_macaddr))
36591991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
36601991Sheppo 	msg->addr, port_macaddr);
36611991Sheppo #endif
36621991Sheppo 		return (VGEN_FAILURE);
36631991Sheppo 	}
36641991Sheppo 
36651991Sheppo 	return (VGEN_SUCCESS);
36661991Sheppo }
36671991Sheppo 
36681991Sheppo /*
36691991Sheppo  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
36701991Sheppo  * to an attr info msg that we sent.
36711991Sheppo  */
36722793Slm66018 static int
36731991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
36741991Sheppo {
36751991Sheppo 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
36761991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
36771991Sheppo 	int		ack = 0;
36782793Slm66018 	int		rv = 0;
36791991Sheppo 
36801991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: enter\n"));
36811991Sheppo 	if (ldcp->hphase != VH_PHASE2) {
36821991Sheppo 		DWARN((vnetp,
36831991Sheppo 		    "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)"
36841991Sheppo 		    " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
36851991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
36862793Slm66018 		return (VGEN_FAILURE);
36871991Sheppo 	}
36881991Sheppo 	switch (tagp->vio_subtype) {
36891991Sheppo 	case VIO_SUBTYPE_INFO:
36901991Sheppo 
36911991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
36921991Sheppo 		    ldcp->ldc_id));
36931991Sheppo 		ldcp->hstate |= ATTR_INFO_RCVD;
36941991Sheppo 
36951991Sheppo 		/* save peer's values */
36961991Sheppo 		ldcp->peer_hparams.mtu = attrmsg->mtu;
36971991Sheppo 		ldcp->peer_hparams.addr = attrmsg->addr;
36981991Sheppo 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
36991991Sheppo 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
37001991Sheppo 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
37011991Sheppo 
37021991Sheppo 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
37031991Sheppo 			/* unsupported attr, send NACK */
37041991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
37051991Sheppo 		} else {
37061991Sheppo 			ack = 1;
37071991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
37081991Sheppo 		}
37091991Sheppo 		tagp->vio_sid = ldcp->local_sid;
37101991Sheppo 
37111991Sheppo 		/* send reply msg back to peer */
37122793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
37132793Slm66018 		    B_FALSE);
37142793Slm66018 		if (rv != VGEN_SUCCESS) {
37152793Slm66018 			return (rv);
37161991Sheppo 		}
37171991Sheppo 
37181991Sheppo 		if (ack) {
37191991Sheppo 			ldcp->hstate |= ATTR_ACK_SENT;
37201991Sheppo 			DBG2((vnetp, "vgen_handle_attr_info:"
37211991Sheppo 			    " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id));
37221991Sheppo 		} else {
37231991Sheppo 			/* failed */
37241991Sheppo 			DWARN((vnetp, "vgen_handle_attr_info:"
37251991Sheppo 			    " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id));
37262793Slm66018 			return (VGEN_FAILURE);
37271991Sheppo 		}
37281991Sheppo 
37291991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
37301991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
37311991Sheppo 		}
37321991Sheppo 
37331991Sheppo 		break;
37341991Sheppo 
37351991Sheppo 	case VIO_SUBTYPE_ACK:
37361991Sheppo 
37371991Sheppo 		ldcp->hstate |= ATTR_ACK_RCVD;
37381991Sheppo 
37391991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
37401991Sheppo 		    ldcp->ldc_id));
37411991Sheppo 
37421991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
37431991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
37441991Sheppo 		}
37451991Sheppo 		break;
37461991Sheppo 
37471991Sheppo 	case VIO_SUBTYPE_NACK:
37481991Sheppo 
37491991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
37501991Sheppo 		    ldcp->ldc_id));
37512793Slm66018 		return (VGEN_FAILURE);
37521991Sheppo 	}
37531991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: exit\n"));
37542793Slm66018 	return (VGEN_SUCCESS);
37551991Sheppo }
37561991Sheppo 
37571991Sheppo /* Check if the dring info msg is ok */
37581991Sheppo static int
37591991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
37601991Sheppo {
37611991Sheppo 	/* check if msg contents are ok */
37621991Sheppo 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
37631991Sheppo 	    sizeof (vnet_public_desc_t))) {
37641991Sheppo 		return (VGEN_FAILURE);
37651991Sheppo 	}
37661991Sheppo 	return (VGEN_SUCCESS);
37671991Sheppo }
37681991Sheppo 
37691991Sheppo /*
37701991Sheppo  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
37711991Sheppo  * the peer to a dring register msg that we sent.
37721991Sheppo  */
37732793Slm66018 static int
37741991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
37751991Sheppo {
37761991Sheppo 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
37771991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
37781991Sheppo 	ldc_mem_cookie_t dcookie;
37791991Sheppo 	int ack = 0;
37801991Sheppo 	int rv = 0;
37811991Sheppo 
37821991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: enter\n"));
37831991Sheppo 	if (ldcp->hphase < VH_PHASE2) {
37841991Sheppo 		/* dring_info can be rcvd in any of the phases after Phase1 */
37851991Sheppo 		DWARN((vnetp,
37861991Sheppo 		    "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)"
37871991Sheppo 		    " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
37881991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
37892793Slm66018 		return (VGEN_FAILURE);
37901991Sheppo 	}
37911991Sheppo 	switch (tagp->vio_subtype) {
37921991Sheppo 	case VIO_SUBTYPE_INFO:
37931991Sheppo 
37941991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
37951991Sheppo 		    ldcp->ldc_id));
37961991Sheppo 		ldcp->hstate |= DRING_INFO_RCVD;
37971991Sheppo 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
37981991Sheppo 
37991991Sheppo 		ASSERT(msg->ncookies == 1);
38001991Sheppo 
38011991Sheppo 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
38021991Sheppo 			/*
38031991Sheppo 			 * verified dring info msg to be ok,
38041991Sheppo 			 * now try to map the remote dring.
38051991Sheppo 			 */
38061991Sheppo 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
38071991Sheppo 			    msg->descriptor_size, &dcookie,
38081991Sheppo 			    msg->ncookies);
38091991Sheppo 			if (rv == DDI_SUCCESS) {
38101991Sheppo 				/* now we can ack the peer */
38111991Sheppo 				ack = 1;
38121991Sheppo 			}
38131991Sheppo 		}
38141991Sheppo 		if (ack == 0) {
38151991Sheppo 			/* failed, send NACK */
38161991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
38171991Sheppo 		} else {
38181991Sheppo 			if (!(ldcp->peer_hparams.dring_ready)) {
38191991Sheppo 
38201991Sheppo 				/* save peer's dring_info values */
38211991Sheppo 				bcopy(&dcookie,
38221991Sheppo 				    &(ldcp->peer_hparams.dring_cookie),
38231991Sheppo 				    sizeof (dcookie));
38241991Sheppo 				ldcp->peer_hparams.num_desc =
38251991Sheppo 						msg->num_descriptors;
38261991Sheppo 				ldcp->peer_hparams.desc_size =
38271991Sheppo 						msg->descriptor_size;
38281991Sheppo 				ldcp->peer_hparams.num_dcookies =
38291991Sheppo 						msg->ncookies;
38301991Sheppo 
38311991Sheppo 				/* set dring_ident for the peer */
38321991Sheppo 				ldcp->peer_hparams.dring_ident =
38331991Sheppo 							(uint64_t)ldcp->rxdp;
38341991Sheppo 				/* return the dring_ident in ack msg */
38351991Sheppo 				msg->dring_ident =
38361991Sheppo 							(uint64_t)ldcp->rxdp;
38371991Sheppo 
38381991Sheppo 				ldcp->peer_hparams.dring_ready = B_TRUE;
38391991Sheppo 			}
38401991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
38411991Sheppo 		}
38421991Sheppo 		tagp->vio_sid = ldcp->local_sid;
38431991Sheppo 		/* send reply msg back to peer */
38442793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
38452793Slm66018 		    B_FALSE);
38462793Slm66018 		if (rv != VGEN_SUCCESS) {
38472793Slm66018 			return (rv);
38481991Sheppo 		}
38491991Sheppo 
38501991Sheppo 		if (ack) {
38511991Sheppo 			ldcp->hstate |= DRING_ACK_SENT;
38521991Sheppo 			DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT"
38531991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
38541991Sheppo 		} else {
38551991Sheppo 			DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT"
38561991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
38572793Slm66018 			return (VGEN_FAILURE);
38581991Sheppo 		}
38591991Sheppo 
38601991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
38611991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
38621991Sheppo 		}
38631991Sheppo 
38641991Sheppo 		break;
38651991Sheppo 
38661991Sheppo 	case VIO_SUBTYPE_ACK:
38671991Sheppo 
38681991Sheppo 		ldcp->hstate |= DRING_ACK_RCVD;
38691991Sheppo 
38701991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD"
38711991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
38721991Sheppo 
38731991Sheppo 		if (!(ldcp->local_hparams.dring_ready)) {
38741991Sheppo 			/* local dring is now ready */
38751991Sheppo 			ldcp->local_hparams.dring_ready = B_TRUE;
38761991Sheppo 
38771991Sheppo 			/* save dring_ident acked by peer */
38781991Sheppo 			ldcp->local_hparams.dring_ident =
38791991Sheppo 				msg->dring_ident;
38801991Sheppo 		}
38811991Sheppo 
38821991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
38831991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
38841991Sheppo 		}
38851991Sheppo 
38861991Sheppo 		break;
38871991Sheppo 
38881991Sheppo 	case VIO_SUBTYPE_NACK:
38891991Sheppo 
38901991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD"
38911991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
38922793Slm66018 		return (VGEN_FAILURE);
38931991Sheppo 	}
38941991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: exit\n"));
38952793Slm66018 	return (VGEN_SUCCESS);
38961991Sheppo }
38971991Sheppo 
38981991Sheppo /*
38991991Sheppo  * Handle a rdx info msg from the peer or an ACK/NACK
39001991Sheppo  * from the peer to a rdx info msg that we sent.
39011991Sheppo  */
39022793Slm66018 static int
39031991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
39041991Sheppo {
39051991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
39062793Slm66018 	int rv = 0;
39071991Sheppo 
39081991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: enter\n"));
39091991Sheppo 	if (ldcp->hphase != VH_PHASE3) {
39101991Sheppo 		DWARN((vnetp,
39111991Sheppo 		    "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)"
39121991Sheppo 		    "  Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
39131991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
39142793Slm66018 		return (VGEN_FAILURE);
39151991Sheppo 	}
39161991Sheppo 	switch (tagp->vio_subtype) {
39171991Sheppo 	case VIO_SUBTYPE_INFO:
39181991Sheppo 
39191991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
39201991Sheppo 		    ldcp->ldc_id));
39211991Sheppo 		ldcp->hstate |= RDX_INFO_RCVD;
39221991Sheppo 
39231991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
39241991Sheppo 		tagp->vio_sid = ldcp->local_sid;
39251991Sheppo 		/* send reply msg back to peer */
39262793Slm66018 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
39272793Slm66018 		    B_FALSE);
39282793Slm66018 		if (rv != VGEN_SUCCESS) {
39292793Slm66018 			return (rv);
39301991Sheppo 		}
39311991Sheppo 
39321991Sheppo 		ldcp->hstate |= RDX_ACK_SENT;
39331991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
39341991Sheppo 		    ldcp->ldc_id));
39351991Sheppo 
39361991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
39371991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
39381991Sheppo 		}
39391991Sheppo 
39401991Sheppo 		break;
39411991Sheppo 
39421991Sheppo 	case VIO_SUBTYPE_ACK:
39431991Sheppo 
39441991Sheppo 		ldcp->hstate |= RDX_ACK_RCVD;
39451991Sheppo 
39461991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
39471991Sheppo 		    ldcp->ldc_id));
39481991Sheppo 
39491991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
39501991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
39511991Sheppo 		}
39521991Sheppo 		break;
39531991Sheppo 
39541991Sheppo 	case VIO_SUBTYPE_NACK:
39551991Sheppo 
39561991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
39571991Sheppo 		    ldcp->ldc_id));
39582793Slm66018 		return (VGEN_FAILURE);
39591991Sheppo 	}
39601991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: exit\n"));
39612793Slm66018 	return (VGEN_SUCCESS);
39621991Sheppo }
39631991Sheppo 
39641991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
39652793Slm66018 static int
39661991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
39671991Sheppo {
39681991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
39691991Sheppo 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
39701991Sheppo 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
39711991Sheppo 	struct ether_addr *addrp;
39721991Sheppo 	int count;
39731991Sheppo 	int i;
39741991Sheppo 
39751991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: enter\n"));
39761991Sheppo 	switch (tagp->vio_subtype) {
39771991Sheppo 
39781991Sheppo 	case VIO_SUBTYPE_INFO:
39791991Sheppo 
39801991Sheppo 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
39811991Sheppo 		DWARN((vnetp,
39821991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
39831991Sheppo 		    ldcp->ldc_id));
39841991Sheppo 		break;
39851991Sheppo 
39861991Sheppo 	case VIO_SUBTYPE_ACK:
39871991Sheppo 
39881991Sheppo 		/* success adding/removing multicast addr */
39891991Sheppo 		DBG2((vnetp,
39901991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
39911991Sheppo 		    ldcp->ldc_id));
39921991Sheppo 		break;
39931991Sheppo 
39941991Sheppo 	case VIO_SUBTYPE_NACK:
39951991Sheppo 
39961991Sheppo 		DWARN((vnetp,
39971991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
39981991Sheppo 		    ldcp->ldc_id));
39991991Sheppo 		if (!(msgp->set)) {
40001991Sheppo 			/* multicast remove request failed */
40011991Sheppo 			break;
40021991Sheppo 		}
40031991Sheppo 
40041991Sheppo 		/* multicast add request failed */
40051991Sheppo 		for (count = 0; count < msgp->count; count++) {
40061991Sheppo 			addrp = &(msgp->mca[count]);
40071991Sheppo 
40081991Sheppo 			/* delete address from the table */
40091991Sheppo 			for (i = 0; i < vgenp->mccount; i++) {
40101991Sheppo 				if (ether_cmp(addrp,
40111991Sheppo 				    &(vgenp->mctab[i])) == 0) {
40121991Sheppo 					if (vgenp->mccount > 1) {
40131991Sheppo 						vgenp->mctab[i] =
40141991Sheppo 						vgenp->mctab[vgenp->mccount-1];
40151991Sheppo 					}
40161991Sheppo 					vgenp->mccount--;
40171991Sheppo 					break;
40181991Sheppo 				}
40191991Sheppo 			}
40201991Sheppo 		}
40211991Sheppo 		break;
40221991Sheppo 
40231991Sheppo 	}
40241991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: exit\n"));
40252793Slm66018 
40262793Slm66018 	return (VGEN_SUCCESS);
40271991Sheppo }
40281991Sheppo 
40291991Sheppo /* handler for control messages received from the peer ldc end-point */
40302793Slm66018 static int
40311991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
40321991Sheppo {
40331991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
40342793Slm66018 	int rv = 0;
40351991Sheppo 
40361991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n"));
40371991Sheppo 	switch (tagp->vio_subtype_env) {
40381991Sheppo 
40391991Sheppo 	case VIO_VER_INFO:
40402793Slm66018 		rv = vgen_handle_version_negotiate(ldcp, tagp);
40411991Sheppo 		break;
40421991Sheppo 
40431991Sheppo 	case VIO_ATTR_INFO:
40442793Slm66018 		rv = vgen_handle_attr_info(ldcp, tagp);
40451991Sheppo 		break;
40461991Sheppo 
40471991Sheppo 	case VIO_DRING_REG:
40482793Slm66018 		rv = vgen_handle_dring_reg(ldcp, tagp);
40491991Sheppo 		break;
40501991Sheppo 
40511991Sheppo 	case VIO_RDX:
40522793Slm66018 		rv = vgen_handle_rdx_info(ldcp, tagp);
40531991Sheppo 		break;
40541991Sheppo 
40551991Sheppo 	case VNET_MCAST_INFO:
40562793Slm66018 		rv = vgen_handle_mcast_info(ldcp, tagp);
40571991Sheppo 		break;
40581991Sheppo 
40591991Sheppo 	}
40602793Slm66018 
40611991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n"));
40622793Slm66018 	return (rv);
40631991Sheppo }
40641991Sheppo 
40651991Sheppo /* handler for data messages received from the peer ldc end-point */
40662793Slm66018 static int
40671991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
40681991Sheppo 	mblk_t **headp, mblk_t **tailp)
40691991Sheppo {
40701991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
40712793Slm66018 	int rv = 0;
40721991Sheppo 
40731991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: enter\n"));
40741991Sheppo 
40751991Sheppo 	if (ldcp->hphase != VH_DONE)
40762793Slm66018 		return (rv);
40771991Sheppo 	switch (tagp->vio_subtype_env) {
40781991Sheppo 	case VIO_DRING_DATA:
40792793Slm66018 		rv = vgen_handle_dring_data(ldcp, tagp, headp, tailp);
40801991Sheppo 		break;
40811991Sheppo 	default:
40821991Sheppo 		break;
40831991Sheppo 	}
40841991Sheppo 
40851991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: exit\n"));
40862793Slm66018 	return (rv);
40871991Sheppo }
40881991Sheppo 
40892793Slm66018 static int
40902336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
40912336Snarayan     int32_t end, uint8_t pstate)
40922336Snarayan {
40932336Snarayan 	vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp;
40942336Snarayan 	void *vnetp = LDC_TO_VNET(ldcp);
40952793Slm66018 	int rv = 0;
40962336Snarayan 
40972336Snarayan 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
40982336Snarayan 	tagp->vio_sid = ldcp->local_sid;
40992336Snarayan 	msgp->start_idx = start;
41002336Snarayan 	msgp->end_idx = end;
41012336Snarayan 	msgp->dring_process_state = pstate;
41022793Slm66018 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE);
41032793Slm66018 	if (rv != VGEN_SUCCESS) {
41042336Snarayan 		DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg "
41052336Snarayan 		    "failed\n", (ldcp)->ldc_id));
41062336Snarayan 	}
41072793Slm66018 	return (rv);
41082336Snarayan }
41092336Snarayan 
41102793Slm66018 static int
41111991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
41121991Sheppo 	mblk_t **headp, mblk_t **tailp)
41131991Sheppo {
41141991Sheppo 	vio_dring_msg_t *dringmsg;
41151991Sheppo 	vnet_public_desc_t *rxdp;
41161991Sheppo 	vnet_public_desc_t *txdp;
41171991Sheppo 	vio_dring_entry_hdr_t *hdrp;
41181991Sheppo 	vgen_stats_t *statsp;
41191991Sheppo 	struct ether_header *ehp;
41201991Sheppo 	mblk_t *mp = NULL;
41211991Sheppo 	mblk_t *bp = NULL;
41221991Sheppo 	mblk_t *bpt = NULL;
41231991Sheppo 	size_t nbytes;
41241991Sheppo 	size_t nread;
41251991Sheppo 	uint64_t off = 0;
41261991Sheppo 	uint32_t start;
41272336Snarayan 	int32_t end;
41281991Sheppo 	uint32_t datalen;
41291991Sheppo 	uint32_t ncookies;
41302336Snarayan 	uint32_t ack_start;
41312336Snarayan 	uint32_t ack_end;
41321991Sheppo 	uint32_t rxi;
41331991Sheppo 	uint32_t txi;
41342793Slm66018 	int rv = 0;
41351991Sheppo 	boolean_t rxd_err = B_FALSE;
41362336Snarayan 	boolean_t set_ack_start = B_FALSE;
41372336Snarayan 	vgen_private_desc_t *tbufp;
41382336Snarayan 	uint32_t next_rxi;
41392336Snarayan 	boolean_t ready_txd = B_FALSE;
41402336Snarayan 	uint32_t retries = 0;
41411991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS
41421991Sheppo 	int n;
41431991Sheppo #endif
41441991Sheppo #ifdef VGEN_REXMIT
41451991Sheppo 	uint64_t seqnum;
41461991Sheppo #endif
41471991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
41482793Slm66018 	boolean_t ack_needed = B_FALSE;
41491991Sheppo 
41501991Sheppo 	dringmsg = (vio_dring_msg_t *)tagp;
41511991Sheppo 	start = dringmsg->start_idx;
41521991Sheppo 	end = dringmsg->end_idx;
41531991Sheppo 	statsp = ldcp->statsp;
41541991Sheppo 
41551991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: enter\n"));
41561991Sheppo 	switch (tagp->vio_subtype) {
41571991Sheppo 
41581991Sheppo 	case VIO_SUBTYPE_INFO:
41591991Sheppo 		/*
41601991Sheppo 		 * received a data msg, which contains the start and end
41611991Sheppo 		 * indeces of the descriptors within the rx ring holding data,
41621991Sheppo 		 * the seq_num of data packet corresponding to the start index,
41631991Sheppo 		 * and the dring_ident.
41641991Sheppo 		 * We can now read the contents of each of these descriptors
41651991Sheppo 		 * and gather data from it.
41661991Sheppo 		 */
41671991Sheppo 		DBG2((vnetp,
41681991Sheppo 		    "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
41691991Sheppo 		    start, end));
41701991Sheppo 
41711991Sheppo 		/* validate rx start and end indeces */
41722336Snarayan 		if (!(CHECK_RXI(start, ldcp)) || ((end != -1) &&
41732336Snarayan 		    !(CHECK_RXI(end, ldcp)))) {
41741991Sheppo 			/* drop the message if invalid index */
41751991Sheppo 			break;
41761991Sheppo 		}
41771991Sheppo 
41781991Sheppo 		/* validate dring_ident */
41791991Sheppo 		if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
41801991Sheppo 			/* invalid dring_ident, drop the msg */
41811991Sheppo 			break;
41821991Sheppo 		}
41831991Sheppo #ifdef DEBUG
41841991Sheppo 		if (vgen_trigger_rxlost) {
41851991Sheppo 			/* drop this msg to simulate lost pkts for debugging */
41861991Sheppo 			vgen_trigger_rxlost = 0;
41871991Sheppo 			break;
41881991Sheppo 		}
41891991Sheppo #endif
41901991Sheppo 
41911991Sheppo #ifdef	VGEN_HANDLE_LOST_PKTS
41921991Sheppo 
41931991Sheppo 		/* receive start index doesn't match expected index */
41941991Sheppo 		if (ldcp->next_rxi != start) {
41951991Sheppo 
41961991Sheppo 			DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
41971991Sheppo 			    "next_rxi(%d) != start(%d)\n",
41981991Sheppo 			    ldcp->ldc_id, ldcp->next_rxi, start));
41991991Sheppo 
42001991Sheppo 			/* calculate the number of pkts lost */
42011991Sheppo 			if (start >= ldcp->next_rxi) {
42021991Sheppo 				n = start - ldcp->next_rxi;
42031991Sheppo 			} else  {
42041991Sheppo 				n = ldcp->num_rxds - (ldcp->next_rxi - start);
42051991Sheppo 			}
42061991Sheppo 
42071991Sheppo 			/*
42082336Snarayan 			 * sequence number of dring data message
42091991Sheppo 			 * is less than the next sequence number that
42101991Sheppo 			 * is expected:
42111991Sheppo 			 *
42121991Sheppo 			 * drop the message and the corresponding packets.
42131991Sheppo 			 */
42141991Sheppo 			if (ldcp->next_rxseq > dringmsg->seq_num) {
42151991Sheppo 				DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
42161991Sheppo 				    "dropping pkts, expected rxseq(0x%lx) "
42171991Sheppo 				    "> recvd(0x%lx)\n",
42181991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
42191991Sheppo 				    dringmsg->seq_num));
42201991Sheppo 				/*
42211991Sheppo 				 * duplicate/multiple retransmissions from
42221991Sheppo 				 * sender?? drop this msg.
42231991Sheppo 				 */
42241991Sheppo 				break;
42251991Sheppo 			}
42261991Sheppo 
42271991Sheppo 			/*
42282336Snarayan 			 * sequence number of dring data message
42291991Sheppo 			 * is greater than the next expected sequence number
42301991Sheppo 			 *
42311991Sheppo 			 * send a NACK back to the peer to indicate lost
42321991Sheppo 			 * packets.
42331991Sheppo 			 */
42341991Sheppo 			if (dringmsg->seq_num > ldcp->next_rxseq) {
42351991Sheppo 				statsp->rx_lost_pkts += n;
42361991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
42371991Sheppo 				tagp->vio_sid = ldcp->local_sid;
42381991Sheppo 				/* indicate the range of lost descriptors */
42391991Sheppo 				dringmsg->start_idx = ldcp->next_rxi;
42401991Sheppo 				rxi = start;
42411991Sheppo 				DECR_RXI(rxi, ldcp);
42421991Sheppo 				dringmsg->end_idx = rxi;
42431991Sheppo 				/* dring ident is left unchanged */
42442793Slm66018 				rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
42452793Slm66018 				    sizeof (*dringmsg), B_FALSE);
42462793Slm66018 				if (rv != VGEN_SUCCESS) {
42471991Sheppo 					DWARN((vnetp,
42481991Sheppo 					    "vgen_handle_dring_data: id(%lx) "
42491991Sheppo 					    "vgen_sendmsg failed, "
42501991Sheppo 					    "stype: NACK\n", ldcp->ldc_id));
42512793Slm66018 					goto error_ret;
42521991Sheppo 				}
42531991Sheppo #ifdef VGEN_REXMIT
42541991Sheppo 				/*
42551991Sheppo 				 * stop further processing until peer
42562336Snarayan 				 * retransmits with the right index.
42572336Snarayan 				 * update next_rxseq expected.
42581991Sheppo 				 */
42592336Snarayan 				ldcp->next_rxseq += 1;
42601991Sheppo 				break;
42611991Sheppo #else	/* VGEN_REXMIT */
42621991Sheppo 				/*
42631991Sheppo 				 * treat this range of descrs/pkts as dropped
42641991Sheppo 				 * and set the new expected values for next_rxi
42651991Sheppo 				 * and next_rxseq. continue(below) to process
42661991Sheppo 				 * from the new start index.
42671991Sheppo 				 */
42681991Sheppo 				ldcp->next_rxi = start;
42692336Snarayan 				ldcp->next_rxseq += 1;
42701991Sheppo #endif	/* VGEN_REXMIT */
42711991Sheppo 
42721991Sheppo 			} else if (dringmsg->seq_num == ldcp->next_rxseq) {
42731991Sheppo 				/*
42742336Snarayan 				 * expected and received seqnums match, but
42751991Sheppo 				 * the descriptor indeces don't?
42761991Sheppo 				 *
42771991Sheppo 				 * restart handshake with peer.
42781991Sheppo 				 */
42791991Sheppo 				DWARN((vnetp,
42801991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
42811991Sheppo 				    "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
42821991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
42831991Sheppo 				    dringmsg->seq_num));
42841991Sheppo 
42851991Sheppo 			}
42861991Sheppo 
42871991Sheppo 		} else {
42881991Sheppo 			/* expected and start dring indeces match */
42891991Sheppo 
42901991Sheppo 			if (dringmsg->seq_num != ldcp->next_rxseq) {
42911991Sheppo 
42921991Sheppo 				/* seqnums don't match */
42931991Sheppo 
42941991Sheppo 				DWARN((vnetp,
42951991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
42961991Sheppo 				    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
42971991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
42981991Sheppo 				    dringmsg->seq_num));
42991991Sheppo 			}
43001991Sheppo 		}
43011991Sheppo 
43021991Sheppo #endif	/* VGEN_HANDLE_LOST_PKTS */
43031991Sheppo 
43041991Sheppo 		/*
43052336Snarayan 		 * start processing the descriptors from the specified
43062336Snarayan 		 * start index, up to the index a descriptor is not ready
43072336Snarayan 		 * to be processed or we process the entire descriptor ring
43082336Snarayan 		 * and wrap around upto the start index.
43091991Sheppo 		 */
43102336Snarayan 
43112336Snarayan 		/* need to set the start index of descriptors to be ack'd */
43122336Snarayan 		set_ack_start = B_TRUE;
43132336Snarayan 
43142336Snarayan 		/* index upto which we have ack'd */
43152336Snarayan 		ack_end = start;
43162336Snarayan 		DECR_RXI(ack_end, ldcp);
43172336Snarayan 
43182336Snarayan 		next_rxi = rxi =  start;
43191991Sheppo 		do {
43202336Snarayan 
43212793Slm66018 vgen_recv_retry:	rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi);
43222793Slm66018 			if (rv != 0) {
43232336Snarayan 				DWARN((vnetp, "vgen_handle_dring_data: "
43242793Slm66018 				    "ldc_mem_dring_acquire() failed"
43252793Slm66018 				    " id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
43262336Snarayan 				statsp->ierrors++;
43272793Slm66018 				goto error_ret;
43282336Snarayan 			}
43291991Sheppo 
43301991Sheppo 			rxdp = &(ldcp->rxdp[rxi]);
43311991Sheppo 			hdrp = &rxdp->hdr;
43321991Sheppo 
43332336Snarayan 			if (hdrp->dstate != VIO_DESC_READY) {
43342336Snarayan 				/*
43352336Snarayan 				 * descriptor is not ready.
43362336Snarayan 				 * retry descriptor acquire, stop processing
43372336Snarayan 				 * after max # retries.
43382336Snarayan 				 */
43392336Snarayan 				if (retries == vgen_recv_retries)
43402336Snarayan 					break;
43412336Snarayan 				retries++;
43422336Snarayan 				drv_usecwait(vgen_recv_delay);
43432336Snarayan 				goto vgen_recv_retry;
43442336Snarayan 			}
43452336Snarayan 			retries = 0;
43462336Snarayan 
43472336Snarayan 			if (set_ack_start) {
43482336Snarayan 				/*
43492336Snarayan 				 * initialize the start index of the range
43502336Snarayan 				 * of descriptors to be ack'd.
43512336Snarayan 				 */
43522336Snarayan 				ack_start = rxi;
43532336Snarayan 				set_ack_start = B_FALSE;
43542336Snarayan 			}
43552336Snarayan 
43561991Sheppo 			datalen = rxdp->nbytes;
43571991Sheppo 			ncookies = rxdp->ncookies;
43581991Sheppo 			if ((datalen < ETHERMIN) ||
43591991Sheppo 			    (ncookies == 0) ||
43602336Snarayan 			    (ncookies > MAX_COOKIES)) {
43611991Sheppo 				rxd_err = B_TRUE;
43621991Sheppo 			} else {
43631991Sheppo 				/*
43642336Snarayan 				 * Try to allocate an mblk from the free pool
43652336Snarayan 				 * of recv mblks for the channel.
43662336Snarayan 				 * If this fails, use allocb().
43671991Sheppo 				 */
43682336Snarayan 				mp = vio_allocb(ldcp->rmp);
43692336Snarayan 				if (!mp) {
43702336Snarayan 					/*
43712336Snarayan 					 * The data buffer returned by
43722336Snarayan 					 * allocb(9F) is 8byte aligned. We
43732336Snarayan 					 * allocate extra 8 bytes to ensure
43742336Snarayan 					 * size is multiple of 8 bytes for
43752336Snarayan 					 * ldc_mem_copy().
43762336Snarayan 					 */
43772336Snarayan 					statsp->rx_vio_allocb_fail++;
43782336Snarayan 					mp = allocb(VNET_IPALIGN + datalen + 8,
43792336Snarayan 					    BPRI_MED);
43802336Snarayan 				}
43812336Snarayan 				nbytes = (VNET_IPALIGN + datalen + 7) & ~7;
43821991Sheppo 			}
43831991Sheppo 			if ((rxd_err) || (mp == NULL)) {
43841991Sheppo 				/*
43851991Sheppo 				 * rxd_err or allocb() failure,
43861991Sheppo 				 * drop this packet, get next.
43871991Sheppo 				 */
43881991Sheppo 				if (rxd_err) {
43891991Sheppo 					statsp->ierrors++;
43901991Sheppo 					rxd_err = B_FALSE;
43911991Sheppo 				} else {
43921991Sheppo 					statsp->rx_allocb_fail++;
43931991Sheppo 				}
43941991Sheppo 
43952793Slm66018 				ack_needed = hdrp->ack;
43962793Slm66018 
43971991Sheppo 				/* set descriptor done bit */
43981991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
43991991Sheppo 
44002793Slm66018 				rv = ldc_mem_dring_release(ldcp->rx_dhandle,
44012336Snarayan 				    rxi, rxi);
44022793Slm66018 				if (rv != 0) {
44032793Slm66018 					DWARN((vnetp, "vgen_handle_dring_data: "
44042793Slm66018 					    "ldc_mem_dring_release err id(%lx)"
44052793Slm66018 					    " rv(%d)\n", ldcp->ldc_id, rv));
44062793Slm66018 					goto error_ret;
44072793Slm66018 				}
44082793Slm66018 
44092793Slm66018 				if (ack_needed) {
44102793Slm66018 					ack_needed = B_FALSE;
44111991Sheppo 					/*
44122336Snarayan 					 * sender needs ack for this packet,
44132336Snarayan 					 * ack pkts upto this index.
44141991Sheppo 					 */
44152336Snarayan 					ack_end = rxi;
44162336Snarayan 
44172793Slm66018 					rv = vgen_send_dring_ack(ldcp, tagp,
44182336Snarayan 					    ack_start, ack_end,
44192336Snarayan 					    VIO_DP_ACTIVE);
44202793Slm66018 					if (rv != VGEN_SUCCESS) {
44212793Slm66018 						goto error_ret;
44222793Slm66018 					}
44232336Snarayan 
44242336Snarayan 					/* need to set new ack start index */
44252336Snarayan 					set_ack_start = B_TRUE;
44261991Sheppo 				}
44271991Sheppo 				goto vgen_next_rxi;
44281991Sheppo 			}
44291991Sheppo 
44301991Sheppo 			nread = nbytes;
44311991Sheppo 			rv = ldc_mem_copy(ldcp->ldc_handle,
44321991Sheppo 			    (caddr_t)mp->b_rptr, off, &nread,
44331991Sheppo 			    rxdp->memcookie, ncookies, LDC_COPY_IN);
44341991Sheppo 
44352793Slm66018 			/* if ldc_mem_copy() failed */
44362793Slm66018 			if (rv) {
44372793Slm66018 				DWARN((vnetp,
44382793Slm66018 				    "vgen_handle_dring_data: ldc_mem_copy err "
44392793Slm66018 				    " id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
44402793Slm66018 				statsp->ierrors++;
44412793Slm66018 				freemsg(mp);
44422793Slm66018 				goto error_ret;
44432793Slm66018 			}
44442793Slm66018 
44452793Slm66018 			ack_needed = hdrp->ack;
44461991Sheppo 			hdrp->dstate = VIO_DESC_DONE;
44471991Sheppo 
44482793Slm66018 			rv = ldc_mem_dring_release(ldcp->rx_dhandle, rxi, rxi);
44492793Slm66018 			if (rv != 0) {
44502793Slm66018 				DWARN((vnetp, "vgen_handle_dring_data: "
44512793Slm66018 				    "ldc_mem_dring_release err id(%lx)"
44522793Slm66018 				    " rv(%d)\n", ldcp->ldc_id, rv));
44532793Slm66018 				goto error_ret;
44542793Slm66018 			}
44552336Snarayan 
44562336Snarayan 			mp->b_rptr += VNET_IPALIGN;
44572336Snarayan 
44582793Slm66018 			if (ack_needed) {
44592793Slm66018 				ack_needed = B_FALSE;
44601991Sheppo 				/*
44612336Snarayan 				 * sender needs ack for this packet,
44622336Snarayan 				 * ack pkts upto this index.
44631991Sheppo 				 */
44642336Snarayan 				ack_end = rxi;
44652336Snarayan 
44662793Slm66018 				rv = vgen_send_dring_ack(ldcp, tagp,
44672336Snarayan 				    ack_start, ack_end, VIO_DP_ACTIVE);
44682793Slm66018 				if (rv != VGEN_SUCCESS) {
44692793Slm66018 					goto error_ret;
44702793Slm66018 				}
44712336Snarayan 
44722336Snarayan 				/* need to set new ack start index */
44732336Snarayan 				set_ack_start = B_TRUE;
44741991Sheppo 			}
44752336Snarayan 
44761991Sheppo 			if (nread != nbytes) {
44771991Sheppo 				DWARN((vnetp,
44781991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
44791991Sheppo 				    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
44801991Sheppo 				    ldcp->ldc_id, nread, nbytes));
44811991Sheppo 				statsp->ierrors++;
44821991Sheppo 				freemsg(mp);
44831991Sheppo 				goto vgen_next_rxi;
44841991Sheppo 			}
44851991Sheppo 
44861991Sheppo 			/* point to the actual end of data */
44871991Sheppo 			mp->b_wptr = mp->b_rptr + datalen;
44881991Sheppo 
44891991Sheppo 			/* update stats */
44901991Sheppo 			statsp->ipackets++;
44911991Sheppo 			statsp->rbytes += datalen;
44921991Sheppo 			ehp = (struct ether_header *)mp->b_rptr;
44931991Sheppo 			if (IS_BROADCAST(ehp))
44941991Sheppo 				statsp->brdcstrcv++;
44951991Sheppo 			else if (IS_MULTICAST(ehp))
44961991Sheppo 				statsp->multircv++;
44971991Sheppo 
44981991Sheppo 			/* build a chain of received packets */
44991991Sheppo 			if (bp == NULL) {
45001991Sheppo 				/* first pkt */
45011991Sheppo 				bp = mp;
45021991Sheppo 				bpt = bp;
45031991Sheppo 				bpt->b_next = NULL;
45041991Sheppo 			} else {
45051991Sheppo 				mp->b_next = NULL;
45061991Sheppo 				bpt->b_next = mp;
45071991Sheppo 				bpt = mp;
45081991Sheppo 			}
45091991Sheppo 
45102336Snarayan 
45112336Snarayan vgen_next_rxi:
45122336Snarayan 			/* update end index of range of descrs to be ack'd */
45132336Snarayan 			ack_end = rxi;
45142336Snarayan 
45152336Snarayan 			/* update the next index to be processed */
45162336Snarayan 			INCR_RXI(next_rxi, ldcp);
45172336Snarayan 			if (next_rxi == start) {
45182336Snarayan 				/*
45192336Snarayan 				 * processed the entire descriptor ring upto
45202336Snarayan 				 * the index at which we started.
45212336Snarayan 				 */
45221991Sheppo 				break;
45231991Sheppo 			}
45242336Snarayan 
45252336Snarayan 			rxi = next_rxi;
45261991Sheppo 
45271991Sheppo 		_NOTE(CONSTCOND)
45281991Sheppo 		} while (1);
45291991Sheppo 
45302336Snarayan 		/*
45312336Snarayan 		 * send an ack message to peer indicating that we have stopped
45322336Snarayan 		 * processing descriptors.
45332336Snarayan 		 */
45342336Snarayan 		if (set_ack_start) {
45352336Snarayan 			/*
45362336Snarayan 			 * We have ack'd upto some index and we have not
45372336Snarayan 			 * processed any descriptors beyond that index.
45382336Snarayan 			 * Use the last ack'd index as both the start and
45392336Snarayan 			 * end of range of descrs being ack'd.
45402336Snarayan 			 * Note: This results in acking the last index twice
45412336Snarayan 			 * and should be harmless.
45422336Snarayan 			 */
45432336Snarayan 			ack_start = ack_end;
45441991Sheppo 		}
45451991Sheppo 
45462793Slm66018 		rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
45472336Snarayan 		    VIO_DP_STOPPED);
45482793Slm66018 		if (rv != VGEN_SUCCESS) {
45492793Slm66018 			goto error_ret;
45502793Slm66018 		}
45512336Snarayan 
45522336Snarayan 		/* save new recv index and expected seqnum of next dring msg */
45532336Snarayan 		ldcp->next_rxi = next_rxi;
45542336Snarayan 		ldcp->next_rxseq += 1;
45552336Snarayan 
45561991Sheppo 		break;
45571991Sheppo 
45581991Sheppo 	case VIO_SUBTYPE_ACK:
45591991Sheppo 		/*
45601991Sheppo 		 * received an ack corresponding to a specific descriptor for
45611991Sheppo 		 * which we had set the ACK bit in the descriptor (during
45621991Sheppo 		 * transmit). This enables us to reclaim descriptors.
45631991Sheppo 		 */
45642336Snarayan 
45651991Sheppo 		DBG2((vnetp,
45661991Sheppo 		    "vgen_handle_dring_data: ACK:  start(%d), end(%d)\n",
45671991Sheppo 		    start, end));
45681991Sheppo 
45691991Sheppo 		/* validate start and end indeces in the tx ack msg */
45701991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
45711991Sheppo 			/* drop the message if invalid index */
45721991Sheppo 			break;
45731991Sheppo 		}
45741991Sheppo 		/* validate dring_ident */
45751991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
45761991Sheppo 			/* invalid dring_ident, drop the msg */
45771991Sheppo 			break;
45781991Sheppo 		}
45791991Sheppo 		statsp->dring_data_acks++;
45802336Snarayan 
45812336Snarayan 		/* reclaim descriptors that are done */
45821991Sheppo 		vgen_reclaim(ldcp);
45832336Snarayan 
45842336Snarayan 		if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
45852336Snarayan 			/*
45862336Snarayan 			 * receiver continued processing descriptors after
45872336Snarayan 			 * sending us the ack.
45882336Snarayan 			 */
45892336Snarayan 			break;
45902336Snarayan 		}
45912336Snarayan 
45922336Snarayan 		statsp->dring_stopped_acks++;
45932336Snarayan 
45942336Snarayan 		/* receiver stopped processing descriptors */
45952336Snarayan 		mutex_enter(&ldcp->txlock);
45962336Snarayan 		mutex_enter(&ldcp->tclock);
45972336Snarayan 
45982336Snarayan 		/*
45992336Snarayan 		 * determine if there are any pending tx descriptors
46002336Snarayan 		 * ready to be processed by the receiver(peer) and if so,
46012336Snarayan 		 * send a message to the peer to restart receiving.
46022336Snarayan 		 */
46032336Snarayan 		ready_txd = B_FALSE;
46042336Snarayan 
46052336Snarayan 		/*
46062336Snarayan 		 * using the end index of the descriptor range for which
46072336Snarayan 		 * we received the ack, check if the next descriptor is
46082336Snarayan 		 * ready.
46092336Snarayan 		 */
46102336Snarayan 		txi = end;
46112336Snarayan 		INCR_TXI(txi, ldcp);
46122336Snarayan 		tbufp = &ldcp->tbufp[txi];
46132336Snarayan 		txdp = tbufp->descp;
46142336Snarayan 		hdrp = &txdp->hdr;
46152336Snarayan 		if (hdrp->dstate == VIO_DESC_READY) {
46162336Snarayan 			ready_txd = B_TRUE;
46172336Snarayan 		} else {
46182336Snarayan 			/*
46192336Snarayan 			 * descr next to the end of ack'd descr range is not
46202336Snarayan 			 * ready.
46212336Snarayan 			 * starting from the current reclaim index, check
46222336Snarayan 			 * if any descriptor is ready.
46232336Snarayan 			 */
46242336Snarayan 
46252336Snarayan 			txi = ldcp->cur_tbufp - ldcp->tbufp;
46262336Snarayan 			tbufp = &ldcp->tbufp[txi];
46272336Snarayan 
46282336Snarayan 			while (tbufp != ldcp->next_tbufp) {
46292336Snarayan 
46302336Snarayan 				txdp = tbufp->descp;
46312336Snarayan 				hdrp = &txdp->hdr;
46322336Snarayan 				if (hdrp->dstate == VIO_DESC_READY) {
46332336Snarayan 					break;
46342336Snarayan 				}
46352336Snarayan 
46362336Snarayan 				INCR_TXI(txi, ldcp);
46372336Snarayan 				tbufp = &ldcp->tbufp[txi];
46382336Snarayan 
46392336Snarayan 			}
46402336Snarayan 
46412336Snarayan 			if (tbufp != ldcp->next_tbufp)
46422336Snarayan 				ready_txd = B_TRUE;
46432336Snarayan 		}
46442336Snarayan 
46452336Snarayan 		if (ready_txd) {
46462336Snarayan 			/*
46472336Snarayan 			 * we have tx descriptor(s) ready to be
46482336Snarayan 			 * processed by the receiver.
46492336Snarayan 			 * send a message to the peer with the start index
46502336Snarayan 			 * of ready descriptors.
46512336Snarayan 			 */
46522336Snarayan 			rv = vgen_send_dring_data(ldcp, txi, -1);
46532793Slm66018 			if (rv != VGEN_SUCCESS) {
46542336Snarayan 				ldcp->resched_peer = B_TRUE;
46552793Slm66018 				mutex_exit(&ldcp->tclock);
46562793Slm66018 				mutex_exit(&ldcp->txlock);
46572793Slm66018 				goto error_ret;
46582336Snarayan 			}
46592336Snarayan 		} else {
46602336Snarayan 			/*
46612336Snarayan 			 * no ready tx descriptors. set the flag to send a
46622336Snarayan 			 * message to peer when tx descriptors are ready in
46632336Snarayan 			 * transmit routine.
46642336Snarayan 			 */
46652336Snarayan 			ldcp->resched_peer = B_TRUE;
46662336Snarayan 		}
46672336Snarayan 
46682336Snarayan 		mutex_exit(&ldcp->tclock);
46692336Snarayan 		mutex_exit(&ldcp->txlock);
46702336Snarayan 
46711991Sheppo 		break;
46721991Sheppo 
46731991Sheppo 	case VIO_SUBTYPE_NACK:
46741991Sheppo 		/*
46751991Sheppo 		 * peer sent a NACK msg to indicate lost packets.
46761991Sheppo 		 * The start and end correspond to the range of descriptors
46771991Sheppo 		 * for which the peer didn't receive a dring data msg and so
46781991Sheppo 		 * didn't receive the corresponding data.
46791991Sheppo 		 */
46801991Sheppo 		DWARN((vnetp,
46811991Sheppo 		    "vgen_handle_dring_data: NACK:  start(%d), end(%d)\n",
46821991Sheppo 		    start, end));
46831991Sheppo 
46841991Sheppo 		/* validate start and end indeces in the tx nack msg */
46851991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
46861991Sheppo 			/* drop the message if invalid index */
46871991Sheppo 			break;
46881991Sheppo 		}
46891991Sheppo 		/* validate dring_ident */
46901991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
46911991Sheppo 			/* invalid dring_ident, drop the msg */
46921991Sheppo 			break;
46931991Sheppo 		}
46941991Sheppo 		mutex_enter(&ldcp->txlock);
46951991Sheppo 		mutex_enter(&ldcp->tclock);
46961991Sheppo 
46971991Sheppo 		if (ldcp->next_tbufp == ldcp->cur_tbufp) {
46981991Sheppo 			/* no busy descriptors, bogus nack ? */
46991991Sheppo 			mutex_exit(&ldcp->tclock);
47001991Sheppo 			mutex_exit(&ldcp->txlock);
47011991Sheppo 			break;
47021991Sheppo 		}
47031991Sheppo 
47041991Sheppo #ifdef VGEN_REXMIT
47051991Sheppo 		/* send a new dring data msg including the lost descrs */
47061991Sheppo 		end = ldcp->next_tbufp - ldcp->tbufp;
47071991Sheppo 		DECR_TXI(end, ldcp);
47082336Snarayan 		rv = vgen_send_dring_data(ldcp, start, end);
47091991Sheppo 		if (rv != 0) {
47101991Sheppo 			/*
47111991Sheppo 			 * vgen_send_dring_data() error: drop all packets
47121991Sheppo 			 * in this descr range
47131991Sheppo 			 */
47141991Sheppo 			DWARN((vnetp,
47151991Sheppo 			    "vgen_handle_dring_data: "
47161991Sheppo 			    "vgen_send_dring_data failed :"
47171991Sheppo 			    "id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
47181991Sheppo 			for (txi = start; txi <= end; ) {
47191991Sheppo 				tbufp = &(ldcp->tbufp[txi]);
47201991Sheppo 				txdp = tbufp->descp;
47211991Sheppo 				hdrp = &txdp->hdr;
47221991Sheppo 				tbufp->flags = VGEN_PRIV_DESC_FREE;
47231991Sheppo 				hdrp->dstate = VIO_DESC_FREE;
47241991Sheppo 				hdrp->ack = B_FALSE;
47251991Sheppo 				statsp->oerrors++;
47261991Sheppo 			}
47271991Sheppo 
47281991Sheppo 			/* update next pointer */
47291991Sheppo 			ldcp->next_tbufp = &(ldcp->tbufp[start]);
47301991Sheppo 			ldcp->next_txi = start;
47311991Sheppo 		}
47321991Sheppo 		DBG2((vnetp,
47331991Sheppo 		    "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
47341991Sheppo 		    start, end));
47351991Sheppo #else	/* VGEN_REXMIT */
47361991Sheppo 		/* we just mark the descrs as done so they can be reclaimed */
47371991Sheppo 		for (txi = start; txi <= end; ) {
47381991Sheppo 			txdp = &(ldcp->txdp[txi]);
47391991Sheppo 			hdrp = &txdp->hdr;
47401991Sheppo 			if (hdrp->dstate == VIO_DESC_READY)
47411991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
47421991Sheppo 			INCR_TXI(txi, ldcp);
47431991Sheppo 		}
47441991Sheppo #endif	/* VGEN_REXMIT */
47451991Sheppo 		mutex_exit(&ldcp->tclock);
47461991Sheppo 		mutex_exit(&ldcp->txlock);
47471991Sheppo 
47481991Sheppo 		break;
47491991Sheppo 	}
47501991Sheppo 
47512793Slm66018 error_ret:
47522793Slm66018 
47531991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: exit\n"));
47541991Sheppo 	*headp = bp;
47551991Sheppo 	*tailp = bpt;
47562336Snarayan 
47572793Slm66018 	return (rv);
47581991Sheppo }
47591991Sheppo 
47601991Sheppo static void
47611991Sheppo vgen_reclaim(vgen_ldc_t *ldcp)
47621991Sheppo {
47632336Snarayan 	mutex_enter(&ldcp->tclock);
47642336Snarayan 
47651991Sheppo 	vgen_reclaim_dring(ldcp);
47661991Sheppo 	ldcp->reclaim_lbolt = ddi_get_lbolt();
47672336Snarayan 
47681991Sheppo 	mutex_exit(&ldcp->tclock);
47691991Sheppo }
47701991Sheppo 
47711991Sheppo /*
47721991Sheppo  * transmit reclaim function. starting from the current reclaim index
47731991Sheppo  * look for descriptors marked DONE and reclaim the descriptor and the
47741991Sheppo  * corresponding buffers (tbuf).
47751991Sheppo  */
47761991Sheppo static void
47771991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp)
47781991Sheppo {
47791991Sheppo 	vnet_public_desc_t *txdp;
47801991Sheppo 	vgen_private_desc_t *tbufp;
47811991Sheppo 	vio_dring_entry_hdr_t	*hdrp;
47822336Snarayan 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
47831991Sheppo 
47841991Sheppo #ifdef DEBUG
47851991Sheppo 	if (vgen_trigger_txtimeout)
47861991Sheppo 		return;
47871991Sheppo #endif
47881991Sheppo 
47891991Sheppo 	tbufp = ldcp->cur_tbufp;
47901991Sheppo 	txdp = tbufp->descp;
47911991Sheppo 	hdrp = &txdp->hdr;
47921991Sheppo 
47931991Sheppo 	while ((hdrp->dstate == VIO_DESC_DONE) &&
47941991Sheppo 	    (tbufp != ldcp->next_tbufp)) {
47951991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
47961991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
47971991Sheppo 		hdrp->ack = B_FALSE;
47981991Sheppo 
47991991Sheppo 		tbufp = NEXTTBUF(ldcp, tbufp);
48001991Sheppo 		txdp = tbufp->descp;
48011991Sheppo 		hdrp = &txdp->hdr;
48021991Sheppo 	}
48031991Sheppo 
48041991Sheppo 	ldcp->cur_tbufp = tbufp;
48051991Sheppo 
48061991Sheppo 	/*
48071991Sheppo 	 * Check if mac layer should be notified to restart transmissions
48081991Sheppo 	 */
48091991Sheppo 	if (ldcp->need_resched) {
48101991Sheppo 		ldcp->need_resched = B_FALSE;
48112311Sseb 		vnet_tx_update(vgenp->vnetp);
48121991Sheppo 	}
48131991Sheppo }
48141991Sheppo 
48151991Sheppo /* return the number of pending transmits for the channel */
48161991Sheppo static int
48171991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp)
48181991Sheppo {
48191991Sheppo 	int n;
48201991Sheppo 
48211991Sheppo 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
48221991Sheppo 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
48231991Sheppo 	} else  {
48241991Sheppo 		/* cur_tbufp > next_tbufp */
48251991Sheppo 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
48261991Sheppo 	}
48271991Sheppo 
48281991Sheppo 	return (n);
48291991Sheppo }
48301991Sheppo 
48311991Sheppo /* determine if the transmit descriptor ring is full */
48321991Sheppo static int
48331991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp)
48341991Sheppo {
48351991Sheppo 	vgen_private_desc_t	*tbufp;
48361991Sheppo 	vgen_private_desc_t	*ntbufp;
48371991Sheppo 
48381991Sheppo 	tbufp = ldcp->next_tbufp;
48391991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
48401991Sheppo 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
48411991Sheppo 		return (VGEN_SUCCESS);
48421991Sheppo 	}
48431991Sheppo 	return (VGEN_FAILURE);
48441991Sheppo }
48451991Sheppo 
48461991Sheppo /* determine if timeout condition has occured */
48471991Sheppo static int
48481991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
48491991Sheppo {
48501991Sheppo 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
48511991Sheppo 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
48521991Sheppo 	    (vnet_ldcwd_txtimeout) &&
48531991Sheppo 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
48541991Sheppo 		return (VGEN_SUCCESS);
48551991Sheppo 	} else {
48561991Sheppo 		return (VGEN_FAILURE);
48571991Sheppo 	}
48581991Sheppo }
48591991Sheppo 
48601991Sheppo /* transmit watchdog timeout handler */
48611991Sheppo static void
48621991Sheppo vgen_ldc_watchdog(void *arg)
48631991Sheppo {
48641991Sheppo 	vgen_ldc_t *ldcp;
48652336Snarayan 	vgen_t *vgenp;
48661991Sheppo 	void *vnetp;
48671991Sheppo 	int rv;
48681991Sheppo 
48691991Sheppo 	ldcp = (vgen_ldc_t *)arg;
48702336Snarayan 	vgenp = LDC_TO_VGEN(ldcp);
48711991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
48721991Sheppo 
48731991Sheppo 	rv = vgen_ldc_txtimeout(ldcp);
48741991Sheppo 	if (rv == VGEN_SUCCESS) {
48751991Sheppo 		DWARN((vnetp,
48761991Sheppo 		    "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
48771991Sheppo 		    ldcp->ldc_id));
48781991Sheppo #ifdef DEBUG
48791991Sheppo 		if (vgen_trigger_txtimeout) {
48801991Sheppo 			/* tx timeout triggered for debugging */
48811991Sheppo 			vgen_trigger_txtimeout = 0;
48821991Sheppo 		}
48831991Sheppo #endif
48841991Sheppo 		mutex_enter(&ldcp->cblock);
48852793Slm66018 		ldcp->need_ldc_reset = B_TRUE;
4886*3653Snarayan 		vgen_handshake_retry(ldcp);
48871991Sheppo 		mutex_exit(&ldcp->cblock);
48881991Sheppo 		if (ldcp->need_resched) {
48891991Sheppo 			ldcp->need_resched = B_FALSE;
48902336Snarayan 			vnet_tx_update(vgenp->vnetp);
48911991Sheppo 		}
48921991Sheppo 	}
48931991Sheppo 
48941991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
48951991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
48961991Sheppo }
48971991Sheppo 
48981991Sheppo static int
48991991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp)
49001991Sheppo {
49011991Sheppo 	vgen_t *vgenp;
49021991Sheppo 	struct kstat *ksp;
49031991Sheppo 	vgen_stats_t *statsp;
49041991Sheppo 	vgen_kstats_t *ldckp;
49051991Sheppo 	int instance;
49061991Sheppo 	size_t size;
49071991Sheppo 	char name[MAXNAMELEN];
49081991Sheppo 
49091991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
49101991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
49111991Sheppo 	(void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id);
49121991Sheppo 	statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
49131991Sheppo 	if (statsp == NULL) {
49141991Sheppo 		return (VGEN_FAILURE);
49151991Sheppo 	}
49161991Sheppo 	size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
49171991Sheppo 	ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
49181991Sheppo 		size, 0);
49191991Sheppo 	if (ksp == NULL) {
49201991Sheppo 		KMEM_FREE(statsp);
49211991Sheppo 		return (VGEN_FAILURE);
49221991Sheppo 	}
49231991Sheppo 
49241991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
49251991Sheppo 	kstat_named_init(&ldckp->ipackets,		"ipackets",
49261991Sheppo 		KSTAT_DATA_ULONG);
49271991Sheppo 	kstat_named_init(&ldckp->ipackets64,		"ipackets64",
49281991Sheppo 		KSTAT_DATA_ULONGLONG);
49291991Sheppo 	kstat_named_init(&ldckp->ierrors,		"ierrors",
49301991Sheppo 		KSTAT_DATA_ULONG);
49311991Sheppo 	kstat_named_init(&ldckp->opackets,		"opackets",
49321991Sheppo 		KSTAT_DATA_ULONG);
49331991Sheppo 	kstat_named_init(&ldckp->opackets64,		"opackets64",
49341991Sheppo 		KSTAT_DATA_ULONGLONG);
49351991Sheppo 	kstat_named_init(&ldckp->oerrors,		"oerrors",
49361991Sheppo 		KSTAT_DATA_ULONG);
49371991Sheppo 
49381991Sheppo 
49391991Sheppo 	/* MIB II kstat variables */
49401991Sheppo 	kstat_named_init(&ldckp->rbytes,		"rbytes",
49411991Sheppo 		KSTAT_DATA_ULONG);
49421991Sheppo 	kstat_named_init(&ldckp->rbytes64,		"rbytes64",
49431991Sheppo 		KSTAT_DATA_ULONGLONG);
49441991Sheppo 	kstat_named_init(&ldckp->obytes,		"obytes",
49451991Sheppo 		KSTAT_DATA_ULONG);
49461991Sheppo 	kstat_named_init(&ldckp->obytes64,		"obytes64",
49471991Sheppo 		KSTAT_DATA_ULONGLONG);
49481991Sheppo 	kstat_named_init(&ldckp->multircv,		"multircv",
49491991Sheppo 		KSTAT_DATA_ULONG);
49501991Sheppo 	kstat_named_init(&ldckp->multixmt,		"multixmt",
49511991Sheppo 		KSTAT_DATA_ULONG);
49521991Sheppo 	kstat_named_init(&ldckp->brdcstrcv,		"brdcstrcv",
49531991Sheppo 		KSTAT_DATA_ULONG);
49541991Sheppo 	kstat_named_init(&ldckp->brdcstxmt,		"brdcstxmt",
49551991Sheppo 		KSTAT_DATA_ULONG);
49561991Sheppo 	kstat_named_init(&ldckp->norcvbuf,		"norcvbuf",
49571991Sheppo 		KSTAT_DATA_ULONG);
49581991Sheppo 	kstat_named_init(&ldckp->noxmtbuf,		"noxmtbuf",
49591991Sheppo 		KSTAT_DATA_ULONG);
49601991Sheppo 
49611991Sheppo 	/* Tx stats */
49621991Sheppo 	kstat_named_init(&ldckp->tx_no_desc,		"tx_no_desc",
49631991Sheppo 		KSTAT_DATA_ULONG);
49641991Sheppo 
49651991Sheppo 	/* Rx stats */
49662336Snarayan 	kstat_named_init(&ldckp->rx_allocb_fail,	"rx_allocb_fail",
49671991Sheppo 		KSTAT_DATA_ULONG);
49682336Snarayan 	kstat_named_init(&ldckp->rx_vio_allocb_fail,	"rx_vio_allocb_fail",
49691991Sheppo 		KSTAT_DATA_ULONG);
49701991Sheppo 	kstat_named_init(&ldckp->rx_lost_pkts,		"rx_lost_pkts",
49711991Sheppo 		KSTAT_DATA_ULONG);
49721991Sheppo 
49731991Sheppo 	/* Interrupt stats */
49741991Sheppo 	kstat_named_init(&ldckp->callbacks,		"callbacks",
49751991Sheppo 		KSTAT_DATA_ULONG);
49761991Sheppo 	kstat_named_init(&ldckp->dring_data_acks,	"dring_data_acks",
49771991Sheppo 		KSTAT_DATA_ULONG);
49782336Snarayan 	kstat_named_init(&ldckp->dring_stopped_acks,	"dring_stopped_acks",
49792336Snarayan 		KSTAT_DATA_ULONG);
49802336Snarayan 	kstat_named_init(&ldckp->dring_data_msgs,	"dring_data_msgs",
49812336Snarayan 		KSTAT_DATA_ULONG);
49821991Sheppo 
49831991Sheppo 	ksp->ks_update = vgen_kstat_update;
49841991Sheppo 	ksp->ks_private = (void *)ldcp;
49851991Sheppo 	kstat_install(ksp);
49861991Sheppo 
49871991Sheppo 	ldcp->ksp = ksp;
49881991Sheppo 	ldcp->statsp = statsp;
49891991Sheppo 	return (VGEN_SUCCESS);
49901991Sheppo }
49911991Sheppo 
49921991Sheppo static void
49931991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp)
49941991Sheppo {
49951991Sheppo 	if (ldcp->ksp)
49961991Sheppo 		kstat_delete(ldcp->ksp);
49971991Sheppo 	KMEM_FREE(ldcp->statsp);
49981991Sheppo }
49991991Sheppo 
50001991Sheppo static int
50011991Sheppo vgen_kstat_update(kstat_t *ksp, int rw)
50021991Sheppo {
50031991Sheppo 	vgen_ldc_t *ldcp;
50041991Sheppo 	vgen_stats_t *statsp;
50051991Sheppo 	vgen_kstats_t *ldckp;
50061991Sheppo 
50071991Sheppo 	ldcp = (vgen_ldc_t *)ksp->ks_private;
50081991Sheppo 	statsp = ldcp->statsp;
50091991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
50101991Sheppo 
50111991Sheppo 	if (rw == KSTAT_READ) {
50121991Sheppo 		ldckp->ipackets.value.ul	= (uint32_t)statsp->ipackets;
50131991Sheppo 		ldckp->ipackets64.value.ull	= statsp->ipackets;
50141991Sheppo 		ldckp->ierrors.value.ul		= statsp->ierrors;
50151991Sheppo 		ldckp->opackets.value.ul	= (uint32_t)statsp->opackets;
50161991Sheppo 		ldckp->opackets64.value.ull	= statsp->opackets;
50171991Sheppo 		ldckp->oerrors.value.ul		= statsp->oerrors;
50181991Sheppo 
50191991Sheppo 		/*
50201991Sheppo 		 * MIB II kstat variables
50211991Sheppo 		 */
50221991Sheppo 		ldckp->rbytes.value.ul		= (uint32_t)statsp->rbytes;
50231991Sheppo 		ldckp->rbytes64.value.ull	= statsp->rbytes;
50241991Sheppo 		ldckp->obytes.value.ul		= (uint32_t)statsp->obytes;
50251991Sheppo 		ldckp->obytes64.value.ull	= statsp->obytes;
50261991Sheppo 		ldckp->multircv.value.ul	= statsp->multircv;
50271991Sheppo 		ldckp->multixmt.value.ul	= statsp->multixmt;
50281991Sheppo 		ldckp->brdcstrcv.value.ul	= statsp->brdcstrcv;
50291991Sheppo 		ldckp->brdcstxmt.value.ul	= statsp->brdcstxmt;
50301991Sheppo 		ldckp->norcvbuf.value.ul	= statsp->norcvbuf;
50311991Sheppo 		ldckp->noxmtbuf.value.ul	= statsp->noxmtbuf;
50321991Sheppo 
50331991Sheppo 		ldckp->tx_no_desc.value.ul	= statsp->tx_no_desc;
50342336Snarayan 
50351991Sheppo 		ldckp->rx_allocb_fail.value.ul	= statsp->rx_allocb_fail;
50362336Snarayan 		ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail;
50371991Sheppo 		ldckp->rx_lost_pkts.value.ul	= statsp->rx_lost_pkts;
50381991Sheppo 
50391991Sheppo 		ldckp->callbacks.value.ul	= statsp->callbacks;
50401991Sheppo 		ldckp->dring_data_acks.value.ul	= statsp->dring_data_acks;
50412336Snarayan 		ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks;
50422336Snarayan 		ldckp->dring_data_msgs.value.ul	= statsp->dring_data_msgs;
50431991Sheppo 	} else {
50441991Sheppo 		statsp->ipackets	= ldckp->ipackets64.value.ull;
50451991Sheppo 		statsp->ierrors		= ldckp->ierrors.value.ul;
50461991Sheppo 		statsp->opackets	= ldckp->opackets64.value.ull;
50471991Sheppo 		statsp->oerrors		= ldckp->oerrors.value.ul;
50481991Sheppo 
50491991Sheppo 		/*
50501991Sheppo 		 * MIB II kstat variables
50511991Sheppo 		 */
50521991Sheppo 		statsp->rbytes		= ldckp->rbytes64.value.ull;
50531991Sheppo 		statsp->obytes		= ldckp->obytes64.value.ull;
50541991Sheppo 		statsp->multircv	= ldckp->multircv.value.ul;
50551991Sheppo 		statsp->multixmt	= ldckp->multixmt.value.ul;
50561991Sheppo 		statsp->brdcstrcv	= ldckp->brdcstrcv.value.ul;
50571991Sheppo 		statsp->brdcstxmt	= ldckp->brdcstxmt.value.ul;
50581991Sheppo 		statsp->norcvbuf	= ldckp->norcvbuf.value.ul;
50591991Sheppo 		statsp->noxmtbuf	= ldckp->noxmtbuf.value.ul;
50601991Sheppo 
50611991Sheppo 		statsp->tx_no_desc	= ldckp->tx_no_desc.value.ul;
50622336Snarayan 
50631991Sheppo 		statsp->rx_allocb_fail	= ldckp->rx_allocb_fail.value.ul;
50642336Snarayan 		statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul;
50651991Sheppo 		statsp->rx_lost_pkts	= ldckp->rx_lost_pkts.value.ul;
50661991Sheppo 
50671991Sheppo 		statsp->callbacks	= ldckp->callbacks.value.ul;
50681991Sheppo 		statsp->dring_data_acks	= ldckp->dring_data_acks.value.ul;
50692336Snarayan 		statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul;
50702336Snarayan 		statsp->dring_data_msgs	= ldckp->dring_data_msgs.value.ul;
50711991Sheppo 	}
50721991Sheppo 
50731991Sheppo 	return (VGEN_SUCCESS);
50741991Sheppo }
50751991Sheppo 
50761991Sheppo /* handler for error messages received from the peer ldc end-point */
50771991Sheppo static void
50781991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
50791991Sheppo {
50801991Sheppo 	_NOTE(ARGUNUSED(ldcp, tagp))
50811991Sheppo }
50821991Sheppo 
50831991Sheppo /* Check if the session id in the received message is valid */
50841991Sheppo static int
50851991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
50861991Sheppo {
50871991Sheppo 	if (tagp->vio_sid != ldcp->peer_sid) {
50881991Sheppo 		void *vnetp = LDC_TO_VNET(ldcp);
50891991Sheppo 		DWARN((vnetp,
50901991Sheppo 		    "sid mismatch: expected(%x), rcvd(%x)\n",
50911991Sheppo 		    ldcp->peer_sid, tagp->vio_sid));
50921991Sheppo 		return (VGEN_FAILURE);
50931991Sheppo 	}
50941991Sheppo 	else
50951991Sheppo 		return (VGEN_SUCCESS);
50961991Sheppo }
50971991Sheppo 
50981991Sheppo /* convert mac address from string to uint64_t */
50991991Sheppo static uint64_t
51001991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr)
51011991Sheppo {
51021991Sheppo 	uint64_t val = 0;
51031991Sheppo 	int i;
51041991Sheppo 
51051991Sheppo 	for (i = 0; i < ETHERADDRL; i++) {
51061991Sheppo 		val <<= 8;
51071991Sheppo 		val |= macaddr[i];
51081991Sheppo 	}
51091991Sheppo 
51101991Sheppo 	return (val);
51111991Sheppo }
51121991Sheppo 
51131991Sheppo /* convert mac address from uint64_t to string */
51141991Sheppo static int
51151991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
51161991Sheppo {
51171991Sheppo 	int i;
51181991Sheppo 	uint64_t value;
51191991Sheppo 
51201991Sheppo 	value = val;
51211991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
51221991Sheppo 		macaddr[i] = value & 0xFF;
51231991Sheppo 		value >>= 8;
51241991Sheppo 	}
51251991Sheppo 	return (VGEN_SUCCESS);
51261991Sheppo }
51271991Sheppo 
51281991Sheppo static caddr_t
51291991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf)
51301991Sheppo {
51311991Sheppo 	(void) sprintf(ebuf,
51321991Sheppo 		"%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
51331991Sheppo 	return (ebuf);
51341991Sheppo }
51351991Sheppo 
51361991Sheppo /* Handshake watchdog timeout handler */
51371991Sheppo static void
51381991Sheppo vgen_hwatchdog(void *arg)
51391991Sheppo {
51401991Sheppo 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
51411991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
51421991Sheppo 
51431991Sheppo 	DWARN((vnetp,
51441991Sheppo 	    "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
51451991Sheppo 	    ldcp->ldc_id, ldcp->hphase, ldcp->hstate));
51461991Sheppo 
51471991Sheppo 	mutex_enter(&ldcp->cblock);
5148*3653Snarayan 	if (ldcp->cancel_htid) {
5149*3653Snarayan 		ldcp->cancel_htid = 0;
5150*3653Snarayan 		mutex_exit(&ldcp->cblock);
5151*3653Snarayan 		return;
5152*3653Snarayan 	}
51531991Sheppo 	ldcp->htid = 0;
51542841Snarayan 	ldcp->need_ldc_reset = B_TRUE;
51551991Sheppo 	vgen_handshake_retry(ldcp);
51561991Sheppo 	mutex_exit(&ldcp->cblock);
51571991Sheppo }
51581991Sheppo 
51591991Sheppo static void
51601991Sheppo vgen_print_hparams(vgen_hparams_t *hp)
51611991Sheppo {
51621991Sheppo 	uint8_t	addr[6];
51631991Sheppo 	char	ea[6];
51641991Sheppo 	ldc_mem_cookie_t *dc;
51651991Sheppo 
51661991Sheppo 	cmn_err(CE_CONT, "version_info:\n");
51671991Sheppo 	cmn_err(CE_CONT,
51681991Sheppo 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
51691991Sheppo 	    hp->ver_major, hp->ver_minor, hp->dev_class);
51701991Sheppo 
51711991Sheppo 	(void) vgen_macaddr_ultostr(hp->addr, addr);
51721991Sheppo 	cmn_err(CE_CONT, "attr_info:\n");
51731991Sheppo 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
51741991Sheppo 	    vgen_print_ethaddr(addr, ea));
51751991Sheppo 	cmn_err(CE_CONT,
51761991Sheppo 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
51771991Sheppo 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
51781991Sheppo 
51791991Sheppo 	dc = &hp->dring_cookie;
51801991Sheppo 	cmn_err(CE_CONT, "dring_info:\n");
51811991Sheppo 	cmn_err(CE_CONT,
51821991Sheppo 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
51831991Sheppo 	cmn_err(CE_CONT,
51841991Sheppo 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
51851991Sheppo 	    dc->addr, dc->size);
51861991Sheppo 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
51871991Sheppo }
51881991Sheppo 
51891991Sheppo static void
51901991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp)
51911991Sheppo {
51921991Sheppo 	vgen_hparams_t *hp;
51931991Sheppo 
51941991Sheppo 	cmn_err(CE_CONT, "Channel Information:\n");
51951991Sheppo 	cmn_err(CE_CONT,
51961991Sheppo 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
51971991Sheppo 	    ldcp->ldc_id, ldcp->ldc_status);
51981991Sheppo 	cmn_err(CE_CONT,
51991991Sheppo 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
52001991Sheppo 	    ldcp->local_sid, ldcp->peer_sid);
52011991Sheppo 	cmn_err(CE_CONT,
52021991Sheppo 	    "\thphase: 0x%x, hstate: 0x%x\n",
52031991Sheppo 	    ldcp->hphase, ldcp->hstate);
52041991Sheppo 
52051991Sheppo 	cmn_err(CE_CONT, "Local handshake params:\n");
52061991Sheppo 	hp = &ldcp->local_hparams;
52071991Sheppo 	vgen_print_hparams(hp);
52081991Sheppo 
52091991Sheppo 	cmn_err(CE_CONT, "Peer handshake params:\n");
52101991Sheppo 	hp = &ldcp->peer_hparams;
52111991Sheppo 	vgen_print_hparams(hp);
52121991Sheppo }
5213