xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_gen.c (revision 2336:f53e467a926f)
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 /*
231991Sheppo  * Copyright 2006 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>
53*2336Snarayan #include <sys/vnet_mailbox.h>
54*2336Snarayan #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);
68*2336Snarayan 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);
821991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
831991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
841991Sheppo void vnet_del_def_rte(void *arg);
852311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
862311Sseb void vnet_tx_update(void *arg);
871991Sheppo 
881991Sheppo /* vgen internal functions */
891991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
901991Sheppo static void vgen_port_detach(vgen_port_t *portp);
911991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
921991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
931991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
941991Sheppo 	int port_num);
951991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
961991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
971991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
981991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
991991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1001991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1011991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port);
1021991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp);
1031991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1041991Sheppo 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
1052311Sseb static uint64_t	vgen_port_stat(vgen_port_t *portp, uint_t stat);
1061991Sheppo 
1071991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1081991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1091991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp);
1101991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp);
1111991Sheppo static void vgen_init_ports(vgen_t *vgenp);
1121991Sheppo static void vgen_port_init(vgen_port_t *portp);
1131991Sheppo static void vgen_uninit_ports(vgen_t *vgenp);
1141991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1151991Sheppo static void vgen_init_ldcs(vgen_port_t *portp);
1161991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp);
1171991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1181991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
1191991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp);
1201991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp);
1211991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp);
1221991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp);
1232311Sseb static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
1241991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
1251991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1261991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp);
1271991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp);
1281991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp);
1291991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp);
1301991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp);
1311991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp);
1321991Sheppo static void vgen_ldc_watchdog(void *arg);
1331991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp);
1341991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp);
1351991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw);
1361991Sheppo 
1371991Sheppo /* vgen handshake functions */
1381991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
1391991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
1401991Sheppo 	uint16_t ver_minor);
1411991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp);
1421991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
1431991Sheppo 	boolean_t caller_holds_lock);
1441991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1451991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
1461991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp);
1471991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
148*2336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1491991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1501991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
1511991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp);
1521991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp);
1531991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp);
1541991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp);
1551991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp);
1561991Sheppo static void vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1571991Sheppo 	vio_msg_tag_t *tagp);
1581991Sheppo static void vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1591991Sheppo static void vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1601991Sheppo static void vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1611991Sheppo static void vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1621991Sheppo static void vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1631991Sheppo static void vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1641991Sheppo 	mblk_t **headp, mblk_t **tailp);
165*2336Snarayan static void vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
166*2336Snarayan 	uint32_t start, int32_t end, uint8_t pstate);
1671991Sheppo static void vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1681991Sheppo 	mblk_t **headp, mblk_t **tailp);
1691991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1701991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1711991Sheppo static uint64_t	vgen_macaddr_strtoul(const uint8_t *macaddr);
1721991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr);
1731991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
1741991Sheppo static void vgen_hwatchdog(void *arg);
1751991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
1761991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp);
1771991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp);
1781991Sheppo 
1791991Sheppo /*
1801991Sheppo  * The handshake process consists of 5 phases defined below, with VH_PHASE0
1811991Sheppo  * being the pre-handshake phase and VH_DONE is the phase to indicate
1821991Sheppo  * successful completion of all phases.
1831991Sheppo  * Each phase may have one to several handshake states which are required
1841991Sheppo  * to complete successfully to move to the next phase.
1851991Sheppo  * Refer to the functions vgen_handshake() and vgen_handshake_done() for
1861991Sheppo  * more details.
1871991Sheppo  */
1881991Sheppo /* handshake phases */
1891991Sheppo enum {	VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
1901991Sheppo 
1911991Sheppo /* handshake states */
1921991Sheppo enum {
1931991Sheppo 
1941991Sheppo 	VER_INFO_SENT	=	0x1,
1951991Sheppo 	VER_ACK_RCVD	=	0x2,
1961991Sheppo 	VER_INFO_RCVD	=	0x4,
1971991Sheppo 	VER_ACK_SENT	=	0x8,
1981991Sheppo 	VER_NEGOTIATED	=	(VER_ACK_RCVD | VER_ACK_SENT),
1991991Sheppo 
2001991Sheppo 	ATTR_INFO_SENT	=	0x10,
2011991Sheppo 	ATTR_ACK_RCVD	=	0x20,
2021991Sheppo 	ATTR_INFO_RCVD	=	0x40,
2031991Sheppo 	ATTR_ACK_SENT	=	0x80,
2041991Sheppo 	ATTR_INFO_EXCHANGED	=	(ATTR_ACK_RCVD | ATTR_ACK_SENT),
2051991Sheppo 
2061991Sheppo 	DRING_INFO_SENT	=	0x100,
2071991Sheppo 	DRING_ACK_RCVD	=	0x200,
2081991Sheppo 	DRING_INFO_RCVD	=	0x400,
2091991Sheppo 	DRING_ACK_SENT	=	0x800,
2101991Sheppo 	DRING_INFO_EXCHANGED	=	(DRING_ACK_RCVD | DRING_ACK_SENT),
2111991Sheppo 
2121991Sheppo 	RDX_INFO_SENT	=	0x1000,
2131991Sheppo 	RDX_ACK_RCVD	=	0x2000,
2141991Sheppo 	RDX_INFO_RCVD	=	0x4000,
2151991Sheppo 	RDX_ACK_SENT	=	0x8000,
2161991Sheppo 	RDX_EXCHANGED	=	(RDX_ACK_RCVD | RDX_ACK_SENT)
2171991Sheppo 
2181991Sheppo };
2191991Sheppo 
2201991Sheppo #define	LDC_LOCK(ldcp)	\
2211991Sheppo 				mutex_enter(&((ldcp)->cblock));\
2221991Sheppo 				mutex_enter(&((ldcp)->txlock));\
2231991Sheppo 				mutex_enter(&((ldcp)->tclock));
2241991Sheppo #define	LDC_UNLOCK(ldcp)	\
2251991Sheppo 				mutex_exit(&((ldcp)->tclock));\
2261991Sheppo 				mutex_exit(&((ldcp)->txlock));\
2271991Sheppo 				mutex_exit(&((ldcp)->cblock));
2281991Sheppo 
2291991Sheppo static struct ether_addr etherbroadcastaddr = {
2301991Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2311991Sheppo };
2321991Sheppo /*
2331991Sheppo  * MIB II broadcast/multicast packets
2341991Sheppo  */
2351991Sheppo #define	IS_BROADCAST(ehp) \
2361991Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
2371991Sheppo #define	IS_MULTICAST(ehp) \
2381991Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
2391991Sheppo 
2401991Sheppo /*
2411991Sheppo  * Property names
2421991Sheppo  */
2431991Sheppo static char macaddr_propname[] = "mac-address";
2441991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2451991Sheppo static char channel_propname[] = "channel-endpoint";
2461991Sheppo static char reg_propname[] = "reg";
2471991Sheppo static char port_propname[] = "port";
2481991Sheppo static char swport_propname[] = "switch-port";
2491991Sheppo static char id_propname[] = "id";
2501991Sheppo 
2511991Sheppo /* versions supported - in decreasing order */
2521991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} };
2531991Sheppo 
2541991Sheppo /* Tunables */
2551991Sheppo uint32_t vgen_hwd_interval = 1000;	/* handshake watchdog freq in msec */
2561991Sheppo uint32_t vgen_max_hretries = 1;		/* max # of handshake retries */
2571991Sheppo uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
2582109Slm66018 uint32_t vgen_ldcup_retries = 5;	/* max # of ldc_up() retries */
259*2336Snarayan uint32_t vgen_recv_delay = 1;		/* delay when rx descr not ready */
260*2336Snarayan uint32_t vgen_recv_retries = 10;	/* retry when rx descr not ready */
2611991Sheppo 
2621991Sheppo #ifdef DEBUG
2631991Sheppo /* flags to simulate error conditions for debugging */
2641991Sheppo int vgen_trigger_txtimeout = 0;
2651991Sheppo int vgen_trigger_rxlost = 0;
2661991Sheppo #endif
2671991Sheppo 
2681991Sheppo /* MD update matching structure */
2691991Sheppo static md_prop_match_t	vport_prop_match[] = {
2701991Sheppo 	{ MDET_PROP_VAL,	"id" },
2711991Sheppo 	{ MDET_LIST_END,	NULL }
2721991Sheppo };
2731991Sheppo 
2741991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
2751991Sheppo 					vport_prop_match };
2761991Sheppo 
2771991Sheppo /* template for matching a particular vnet instance */
2781991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
2791991Sheppo 	{ MDET_PROP_STR,	"name",		"network" },
2801991Sheppo 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
2811991Sheppo 	{ MDET_LIST_END,	NULL,		NULL }
2821991Sheppo };
2831991Sheppo 
2841991Sheppo #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
2851991Sheppo 
2861991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
2871991Sheppo 
2882311Sseb static mac_callbacks_t vgen_m_callbacks = {
2892311Sseb 	0,
2902311Sseb 	vgen_stat,
2912311Sseb 	vgen_start,
2922311Sseb 	vgen_stop,
2932311Sseb 	vgen_promisc,
2942311Sseb 	vgen_multicst,
2952311Sseb 	vgen_unicst,
2962311Sseb 	vgen_tx,
2972311Sseb 	NULL,
2982311Sseb 	NULL,
2992311Sseb 	NULL
3002311Sseb };
3012311Sseb 
3021991Sheppo /* externs */
3031991Sheppo extern uint32_t vnet_ntxds;
3041991Sheppo extern uint32_t vnet_reclaim_lowat;
3051991Sheppo extern uint32_t vnet_reclaim_hiwat;
3061991Sheppo extern uint32_t vnet_ldcwd_interval;
3071991Sheppo extern uint32_t vnet_ldcwd_txtimeout;
3081991Sheppo extern uint32_t vnet_ldc_qlen;
309*2336Snarayan extern uint32_t vnet_nrbufs;
3101991Sheppo extern int _vnet_dbglevel;
3111991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...);
3121991Sheppo 
3131991Sheppo #ifdef DEBUG
3141991Sheppo 
3151991Sheppo /*
3161991Sheppo  * XXX: definitions below need to be in sync with those in vnet.c
3171991Sheppo  */
3181991Sheppo 
3191991Sheppo /*
3201991Sheppo  * debug levels:
3211991Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
3221991Sheppo  * DBG_LEVEL2:	Info messages
3231991Sheppo  * DBG_LEVEL3:	Warning messages
3241991Sheppo  * DBG_LEVEL4:	Error messages
3251991Sheppo  */
3261991Sheppo 
3271991Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
3281991Sheppo 	    DBG_LEVEL4 = 0x08 };
3291991Sheppo 
3301991Sheppo #define	DBG1(_s)	do {						\
3311991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
3321991Sheppo 					_vnetdebug_printf _s;		\
3331991Sheppo 			    }					\
3341991Sheppo 			_NOTE(CONSTCOND) } while (0)
3351991Sheppo 
3361991Sheppo #define	DBG2(_s)	do {						\
3371991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
3381991Sheppo 					_vnetdebug_printf _s;		\
3391991Sheppo 			    }					\
3401991Sheppo 			_NOTE(CONSTCOND) } while (0)
3411991Sheppo 
3421991Sheppo #define	DWARN(_s)	do {						\
3431991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
3441991Sheppo 					_vnetdebug_printf _s;		\
3451991Sheppo 			    }					\
3461991Sheppo 			_NOTE(CONSTCOND) } while (0)
3471991Sheppo 
3481991Sheppo #define	DERR(_s)	do {						\
3491991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
3501991Sheppo 					_vnetdebug_printf _s;		\
3511991Sheppo 			    }					\
3521991Sheppo 			_NOTE(CONSTCOND) } while (0)
3531991Sheppo 
3541991Sheppo #else
3551991Sheppo 
3561991Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
3571991Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
3581991Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
3591991Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
3601991Sheppo 
3611991Sheppo #endif
3621991Sheppo 
3631991Sheppo #ifdef DEBUG
3641991Sheppo 
3651991Sheppo /* simulate handshake error conditions for debug */
3661991Sheppo uint32_t vgen_hdbg;
3671991Sheppo #define	HDBG_VERSION	0x1
3681991Sheppo #define	HDBG_TIMEOUT	0x2
3691991Sheppo #define	HDBG_BAD_SID	0x4
3701991Sheppo #define	HDBG_OUT_STATE	0x8
3711991Sheppo 
3721991Sheppo #endif
3731991Sheppo 
374*2336Snarayan 
3751991Sheppo 
3761991Sheppo /*
3771991Sheppo  * vgen_init() is called by an instance of vnet driver to initialize the
3781991Sheppo  * corresponding generic proxy transport layer. The arguments passed by vnet
3791991Sheppo  * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
3802311Sseb  * the mac address of the vnet device, and a pointer to mac_register_t of
3812311Sseb  * the generic transport is returned in the last argument.
3821991Sheppo  */
3831991Sheppo int
3842311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
3852311Sseb     mac_register_t **vgenmacp)
3861991Sheppo {
3871991Sheppo 	vgen_t *vgenp;
3882311Sseb 	mac_register_t *macp;
3891991Sheppo 	int instance;
3901991Sheppo 
3912311Sseb 	if ((vnetp == NULL) || (vnetdip == NULL))
3921991Sheppo 		return (DDI_FAILURE);
3931991Sheppo 
3941991Sheppo 	instance = ddi_get_instance(vnetdip);
3951991Sheppo 
3961991Sheppo 	DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance));
3971991Sheppo 
3981991Sheppo 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
3991991Sheppo 
4001991Sheppo 	vgenp->vnetp = vnetp;
4011991Sheppo 	vgenp->vnetdip = vnetdip;
4021991Sheppo 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
4031991Sheppo 
4042311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4052311Sseb 		KMEM_FREE(vgenp);
4062311Sseb 		return (DDI_FAILURE);
4072311Sseb 	}
4082311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4092311Sseb 	macp->m_driver = vgenp;
4102311Sseb 	macp->m_dip = vnetdip;
4112311Sseb 	macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
4122311Sseb 	macp->m_callbacks = &vgen_m_callbacks;
4132311Sseb 	macp->m_min_sdu = 0;
4142311Sseb 	macp->m_max_sdu = ETHERMTU;
4152311Sseb 	vgenp->macp = macp;
4162311Sseb 
4171991Sheppo 	/* allocate multicast table */
4181991Sheppo 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
4191991Sheppo 	    sizeof (struct ether_addr), KM_SLEEP);
4201991Sheppo 	vgenp->mccount = 0;
4211991Sheppo 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
4221991Sheppo 
4231991Sheppo 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
4241991Sheppo 
4251991Sheppo 	/* register with MD event generator */
4261991Sheppo 	if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) {
4271991Sheppo 		mutex_destroy(&vgenp->lock);
4281991Sheppo 		kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
4291991Sheppo 		    sizeof (struct ether_addr));
4302311Sseb 		mac_free(vgenp->macp);
4311991Sheppo 		KMEM_FREE(vgenp);
4321991Sheppo 		return (DDI_FAILURE);
4331991Sheppo 	}
4341991Sheppo 
4352311Sseb 	/* register macp of this vgen_t with vnet */
4362311Sseb 	*vgenmacp = vgenp->macp;
4371991Sheppo 
4381991Sheppo 	DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance));
4391991Sheppo 	return (DDI_SUCCESS);
4401991Sheppo }
4411991Sheppo 
4421991Sheppo /*
4431991Sheppo  * Called by vnet to undo the initializations done by vgen_init().
4441991Sheppo  * The handle provided by generic transport during vgen_init() is the argument.
4451991Sheppo  */
446*2336Snarayan int
4471991Sheppo vgen_uninit(void *arg)
4481991Sheppo {
4491991Sheppo 	vgen_t	*vgenp = (vgen_t *)arg;
4501991Sheppo 	void	*vnetp;
4511991Sheppo 	int instance;
452*2336Snarayan 	vio_mblk_pool_t *rp, *nrp;
453*2336Snarayan 
454*2336Snarayan 	if (vgenp == NULL) {
455*2336Snarayan 		return (DDI_FAILURE);
456*2336Snarayan 	}
4571991Sheppo 
4581991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
4591991Sheppo 	vnetp = vgenp->vnetp;
4601991Sheppo 
4611991Sheppo 	DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance));
4621991Sheppo 
4631991Sheppo 	/* unregister with MD event generator */
4641991Sheppo 	vgen_mdeg_unreg(vgenp);
4651991Sheppo 
4661991Sheppo 	mutex_enter(&vgenp->lock);
4671991Sheppo 
4681991Sheppo 	/* detach all ports from the device */
4691991Sheppo 	vgen_detach_ports(vgenp);
4701991Sheppo 
471*2336Snarayan 	/*
472*2336Snarayan 	 * free any pending rx mblk pools,
473*2336Snarayan 	 * that couldn't be freed previously during channel detach.
474*2336Snarayan 	 */
475*2336Snarayan 	rp = vgenp->rmp;
476*2336Snarayan 	while (rp != NULL) {
477*2336Snarayan 		nrp = vgenp->rmp = rp->nextp;
478*2336Snarayan 		if (vio_destroy_mblks(rp)) {
479*2336Snarayan 			vgenp->rmp = rp;
480*2336Snarayan 			mutex_exit(&vgenp->lock);
481*2336Snarayan 			return (DDI_FAILURE);
482*2336Snarayan 		}
483*2336Snarayan 		rp = nrp;
484*2336Snarayan 	}
485*2336Snarayan 
4861991Sheppo 	/* free multicast table */
4871991Sheppo 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
4881991Sheppo 
4892311Sseb 	mac_free(vgenp->macp);
4902311Sseb 
4911991Sheppo 	mutex_exit(&vgenp->lock);
4921991Sheppo 
4931991Sheppo 	mutex_destroy(&vgenp->lock);
4941991Sheppo 
4951991Sheppo 	KMEM_FREE(vgenp);
4961991Sheppo 
4971991Sheppo 	DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance));
498*2336Snarayan 
499*2336Snarayan 	return (DDI_SUCCESS);
5001991Sheppo }
5011991Sheppo 
5021991Sheppo /* enable transmit/receive for the device */
5032311Sseb int
5041991Sheppo vgen_start(void *arg)
5051991Sheppo {
5061991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5071991Sheppo 
5081991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: enter\n"));
5091991Sheppo 
5101991Sheppo 	mutex_enter(&vgenp->lock);
5111991Sheppo 	vgen_init_ports(vgenp);
5121991Sheppo 	vgenp->flags |= VGEN_STARTED;
5131991Sheppo 	mutex_exit(&vgenp->lock);
5141991Sheppo 
5151991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: exit\n"));
5161991Sheppo 	return (DDI_SUCCESS);
5171991Sheppo }
5181991Sheppo 
5191991Sheppo /* stop transmit/receive */
5202311Sseb void
5211991Sheppo vgen_stop(void *arg)
5221991Sheppo {
5231991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
5241991Sheppo 
5251991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: enter\n"));
5261991Sheppo 
5271991Sheppo 	mutex_enter(&vgenp->lock);
5281991Sheppo 	vgen_uninit_ports(vgenp);
5291991Sheppo 	vgenp->flags &= ~(VGEN_STARTED);
5301991Sheppo 	mutex_exit(&vgenp->lock);
5311991Sheppo 
5321991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: exit\n"));
5331991Sheppo }
5341991Sheppo 
5351991Sheppo /* vgen transmit function */
5361991Sheppo static mblk_t *
5371991Sheppo vgen_tx(void *arg, mblk_t *mp)
5381991Sheppo {
5391991Sheppo 	vgen_port_t *portp;
5401991Sheppo 	int status;
5411991Sheppo 
5421991Sheppo 	portp = (vgen_port_t *)arg;
5431991Sheppo 	status = vgen_portsend(portp, mp);
5441991Sheppo 	if (status != VGEN_SUCCESS) {
5451991Sheppo 		/* failure */
5461991Sheppo 		return (mp);
5471991Sheppo 	}
5481991Sheppo 	/* success */
5491991Sheppo 	return (NULL);
5501991Sheppo }
5511991Sheppo 
5521991Sheppo /* transmit packets over the given port */
5531991Sheppo static int
5541991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
5551991Sheppo {
5561991Sheppo 	vgen_ldclist_t	*ldclp;
5571991Sheppo 	vgen_ldc_t *ldcp;
5581991Sheppo 	int status;
5591991Sheppo 
5601991Sheppo 	ldclp = &portp->ldclist;
5611991Sheppo 	READ_ENTER(&ldclp->rwlock);
5621991Sheppo 	/*
563*2336Snarayan 	 * NOTE: for now, we will assume we have a single channel.
5641991Sheppo 	 */
5651991Sheppo 	if (ldclp->headp == NULL) {
5661991Sheppo 		RW_EXIT(&ldclp->rwlock);
5671991Sheppo 		return (VGEN_FAILURE);
5681991Sheppo 	}
5691991Sheppo 	ldcp = ldclp->headp;
5701991Sheppo 
5711991Sheppo 	if (ldcp->need_resched) {
5721991Sheppo 		/* out of tx resources, see vgen_ldcsend() for details. */
5731991Sheppo 		mutex_enter(&ldcp->txlock);
5741991Sheppo 		ldcp->statsp->tx_no_desc++;
5751991Sheppo 		mutex_exit(&ldcp->txlock);
5761991Sheppo 
5771991Sheppo 		RW_EXIT(&ldclp->rwlock);
578*2336Snarayan 		return (VGEN_FAILURE);
5791991Sheppo 	}
5801991Sheppo 
5811991Sheppo 	status  = vgen_ldcsend(ldcp, mp);
5821991Sheppo 	RW_EXIT(&ldclp->rwlock);
5831991Sheppo 
5841991Sheppo 	if (status != VGEN_TX_SUCCESS)
5851991Sheppo 		return (VGEN_FAILURE);
5861991Sheppo 
5871991Sheppo 	return (VGEN_SUCCESS);
5881991Sheppo }
5891991Sheppo 
5901991Sheppo /* channel transmit function */
5911991Sheppo static int
5921991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp)
5931991Sheppo {
5941991Sheppo 	void		*vnetp;
5951991Sheppo 	size_t		size;
5961991Sheppo 	int		rv;
597*2336Snarayan 	uint64_t	tbuf_ix;
5981991Sheppo 	vgen_private_desc_t	*tbufp;
5991991Sheppo 	vgen_private_desc_t	*ntbufp;
6001991Sheppo 	vnet_public_desc_t	*txdp;
6011991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
6021991Sheppo 	vgen_stats_t		*statsp;
6031991Sheppo 	struct ether_header	*ehp;
6041991Sheppo 	boolean_t	is_bcast = B_FALSE;
6051991Sheppo 	boolean_t	is_mcast = B_FALSE;
6061991Sheppo 	boolean_t	need_intr = B_FALSE;
607*2336Snarayan 	size_t		mblksz;
608*2336Snarayan 	caddr_t		dst;
609*2336Snarayan 	mblk_t		*bp;
6101991Sheppo 
6111991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
6121991Sheppo 	statsp = ldcp->statsp;
6132109Slm66018 	size = msgsize(mp);
6142109Slm66018 
6151991Sheppo 	DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id));
6161991Sheppo 
6172109Slm66018 	mutex_enter(&ldcp->txlock);
6182109Slm66018 
6192109Slm66018 	/* drop the packet if ldc is not up or handshake is not done */
6202109Slm66018 	if (ldcp->ldc_status != LDC_UP) {
6211991Sheppo 		DWARN((vnetp,
6221991Sheppo 		    "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
6231991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
6242109Slm66018 		/* retry ldc_up() if needed */
6252109Slm66018 		if (ldcp->flags & CHANNEL_STARTED)
6262109Slm66018 			(void) ldc_up(ldcp->ldc_handle);
6272109Slm66018 		goto vgen_tx_exit;
6281991Sheppo 	}
6291991Sheppo 
6302109Slm66018 	if (ldcp->hphase != VH_DONE) {
6312109Slm66018 		DWARN((vnetp,
6322109Slm66018 		    "vgen_ldcsend: id(%lx) hphase(%x), dropping packet\n",
6332109Slm66018 		    ldcp->ldc_id, ldcp->hphase));
6342109Slm66018 		goto vgen_tx_exit;
6352109Slm66018 	}
6362109Slm66018 
6371991Sheppo 	if (size > (size_t)ETHERMAX) {
6381991Sheppo 		DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n",
6391991Sheppo 		    ldcp->ldc_id, size));
6401991Sheppo 		goto vgen_tx_exit;
6411991Sheppo 	}
6421991Sheppo 
6431991Sheppo 	/*
6441991Sheppo 	 * allocate a descriptor
6451991Sheppo 	 */
6461991Sheppo 	tbufp = ldcp->next_tbufp;
6471991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
648*2336Snarayan 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
6491991Sheppo 
6501991Sheppo 		mutex_enter(&ldcp->tclock);
651*2336Snarayan 		if (ntbufp == ldcp->cur_tbufp) {
6521991Sheppo 			ldcp->need_resched = B_TRUE;
653*2336Snarayan 			mutex_exit(&ldcp->tclock);
654*2336Snarayan 
655*2336Snarayan 			statsp->tx_no_desc++;
656*2336Snarayan 			mutex_exit(&ldcp->txlock);
657*2336Snarayan 
658*2336Snarayan 			return (VGEN_TX_NORESOURCES);
659*2336Snarayan 		}
6601991Sheppo 		mutex_exit(&ldcp->tclock);
6611991Sheppo 	}
6621991Sheppo 
6632109Slm66018 	if (size < ETHERMIN)
6642109Slm66018 		size = ETHERMIN;
6652109Slm66018 
6662109Slm66018 	/* copy data into pre-allocated transmit buffer */
667*2336Snarayan 	dst = tbufp->datap + VNET_IPALIGN;
668*2336Snarayan 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
669*2336Snarayan 		mblksz = MBLKL(bp);
670*2336Snarayan 		bcopy(bp->b_rptr, dst, mblksz);
671*2336Snarayan 		dst += mblksz;
6721991Sheppo 	}
6731991Sheppo 
674*2336Snarayan 	tbuf_ix = tbufp - ldcp->tbufp;
6751991Sheppo 
6762109Slm66018 	ehp = (struct ether_header *)tbufp->datap;
6771991Sheppo 	is_bcast = IS_BROADCAST(ehp);
6781991Sheppo 	is_mcast = IS_MULTICAST(ehp);
6792109Slm66018 
6801991Sheppo 	tbufp->flags = VGEN_PRIV_DESC_BUSY;
6812109Slm66018 	tbufp->datalen = size;
6821991Sheppo 
6831991Sheppo 	/* initialize the corresponding public descriptor (txd) */
6841991Sheppo 	txdp = tbufp->descp;
6851991Sheppo 	hdrp = &txdp->hdr;
6861991Sheppo 	if (need_intr)
6871991Sheppo 		hdrp->ack = B_TRUE;
6882109Slm66018 	txdp->nbytes = size;
6892109Slm66018 	txdp->ncookies = tbufp->ncookies;
6901991Sheppo 	bcopy((tbufp->memcookie), (txdp->memcookie),
691*2336Snarayan 		tbufp->ncookies * sizeof (ldc_mem_cookie_t));
692*2336Snarayan 	hdrp->dstate = VIO_DESC_READY;
6931991Sheppo 
6941991Sheppo 	/* send dring datamsg to the peer */
695*2336Snarayan 	if (ldcp->resched_peer) {
696*2336Snarayan 		rv = vgen_send_dring_data(ldcp, (uint32_t)tbuf_ix, -1);
697*2336Snarayan 		if (rv != 0) {
698*2336Snarayan 			/* vgen_send_dring_data() error: drop the packet */
699*2336Snarayan 			DWARN((vnetp,
700*2336Snarayan 			    "vgen_ldcsend: vgen_send_dring_data():  failed: "
701*2336Snarayan 			    "id(%lx) rv(%d) len (%d)\n",
702*2336Snarayan 			    ldcp->ldc_id, rv, size));
703*2336Snarayan 			tbufp->flags = VGEN_PRIV_DESC_FREE;	/* free tbuf */
704*2336Snarayan 			hdrp->dstate = VIO_DESC_FREE;	/* free txd */
705*2336Snarayan 			hdrp->ack = B_FALSE;
706*2336Snarayan 			statsp->oerrors++;
707*2336Snarayan 			goto vgen_tx_exit;
708*2336Snarayan 		}
709*2336Snarayan 		ldcp->resched_peer = B_FALSE;
7101991Sheppo 	}
7111991Sheppo 
7121991Sheppo 	/* update next available tbuf in the ring */
7131991Sheppo 	ldcp->next_tbufp = ntbufp;
714*2336Snarayan 
715*2336Snarayan 	/* update tx index */
7161991Sheppo 	INCR_TXI(ldcp->next_txi, ldcp);
7171991Sheppo 
7181991Sheppo 	/* update stats */
7191991Sheppo 	statsp->opackets++;
7202109Slm66018 	statsp->obytes += size;
7211991Sheppo 	if (is_bcast)
7221991Sheppo 		statsp->brdcstxmt++;
7231991Sheppo 	else if (is_mcast)
7241991Sheppo 		statsp->multixmt++;
7251991Sheppo 
7261991Sheppo vgen_tx_exit:
7271991Sheppo 	mutex_exit(&ldcp->txlock);
7281991Sheppo 
7291991Sheppo 	DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id));
7301991Sheppo 
7312109Slm66018 	freemsg(mp);
7322109Slm66018 	return (VGEN_TX_SUCCESS);
7331991Sheppo }
7341991Sheppo 
7351991Sheppo /* enable/disable a multicast address */
7362311Sseb int
7371991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
7381991Sheppo {
7391991Sheppo 	vgen_t			*vgenp;
7401991Sheppo 	vnet_mcast_msg_t	mcastmsg;
7411991Sheppo 	vio_msg_tag_t		*tagp;
7421991Sheppo 	vgen_port_t		*portp;
7431991Sheppo 	vgen_portlist_t		*plistp;
7441991Sheppo 	vgen_ldc_t		*ldcp;
7451991Sheppo 	vgen_ldclist_t		*ldclp;
7461991Sheppo 	void			*vnetp;
7471991Sheppo 	struct ether_addr	*addrp;
7481991Sheppo 	int			rv;
7491991Sheppo 	uint32_t		i;
7501991Sheppo 
7511991Sheppo 	vgenp = (vgen_t *)arg;
7521991Sheppo 	vnetp = vgenp->vnetp;
7531991Sheppo 	addrp = (struct ether_addr *)mca;
7541991Sheppo 	tagp = &mcastmsg.tag;
7551991Sheppo 	bzero(&mcastmsg, sizeof (mcastmsg));
7561991Sheppo 
7571991Sheppo 	mutex_enter(&vgenp->lock);
7581991Sheppo 
7591991Sheppo 	plistp = &(vgenp->vgenports);
7601991Sheppo 
7611991Sheppo 	READ_ENTER(&plistp->rwlock);
7621991Sheppo 
7631991Sheppo 	portp = vgenp->vsw_portp;
7641991Sheppo 	if (portp == NULL) {
7651991Sheppo 		RW_EXIT(&plistp->rwlock);
7661991Sheppo 		goto vgen_mcast_exit;
7671991Sheppo 	}
7681991Sheppo 	ldclp = &portp->ldclist;
7691991Sheppo 
7701991Sheppo 	READ_ENTER(&ldclp->rwlock);
7711991Sheppo 
7721991Sheppo 	ldcp = ldclp->headp;
7731991Sheppo 	if (ldcp == NULL) {
7741991Sheppo 		RW_EXIT(&ldclp->rwlock);
7751991Sheppo 		RW_EXIT(&plistp->rwlock);
7761991Sheppo 		goto vgen_mcast_exit;
7771991Sheppo 	}
7781991Sheppo 
7791991Sheppo 	mutex_enter(&ldcp->cblock);
7801991Sheppo 
7811991Sheppo 	if (ldcp->hphase == VH_DONE) {
7821991Sheppo 		/*
7831991Sheppo 		 * If handshake is done, send a msg to vsw to add/remove
7841991Sheppo 		 * the multicast address.
7851991Sheppo 		 */
7861991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
7871991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
7881991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
7891991Sheppo 		tagp->vio_sid = ldcp->local_sid;
7901991Sheppo 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
7911991Sheppo 		mcastmsg.set = add;
7921991Sheppo 		mcastmsg.count = 1;
7931991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
7941991Sheppo 		    B_FALSE);
7951991Sheppo 		if (rv != VGEN_SUCCESS) {
7961991Sheppo 			DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed"
7971991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
7981991Sheppo 		}
7991991Sheppo 	} else {
8001991Sheppo 		/* set the flag to send a msg to vsw after handshake is done */
8011991Sheppo 		ldcp->need_mcast_sync = B_TRUE;
8021991Sheppo 	}
8031991Sheppo 
8041991Sheppo 	mutex_exit(&ldcp->cblock);
8051991Sheppo 
8061991Sheppo 	if (add) {
8071991Sheppo 
8081991Sheppo 		/* expand multicast table if necessary */
8091991Sheppo 		if (vgenp->mccount >= vgenp->mcsize) {
8101991Sheppo 			struct ether_addr	*newtab;
8111991Sheppo 			uint32_t		newsize;
8121991Sheppo 
8131991Sheppo 
8141991Sheppo 			newsize = vgenp->mcsize * 2;
8151991Sheppo 
8161991Sheppo 			newtab = kmem_zalloc(newsize *
8171991Sheppo 			    sizeof (struct ether_addr), KM_NOSLEEP);
8181991Sheppo 
8191991Sheppo 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
8201991Sheppo 			    sizeof (struct ether_addr));
8211991Sheppo 			kmem_free(vgenp->mctab,
8221991Sheppo 			    vgenp->mcsize * sizeof (struct ether_addr));
8231991Sheppo 
8241991Sheppo 			vgenp->mctab = newtab;
8251991Sheppo 			vgenp->mcsize = newsize;
8261991Sheppo 		}
8271991Sheppo 
8281991Sheppo 		/* add address to the table */
8291991Sheppo 		vgenp->mctab[vgenp->mccount++] = *addrp;
8301991Sheppo 
8311991Sheppo 	} else {
8321991Sheppo 
8331991Sheppo 		/* delete address from the table */
8341991Sheppo 		for (i = 0; i < vgenp->mccount; i++) {
8351991Sheppo 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
8361991Sheppo 
8371991Sheppo 				/*
8381991Sheppo 				 * If there's more than one address in this
8391991Sheppo 				 * table, delete the unwanted one by moving
8401991Sheppo 				 * the last one in the list over top of it;
8411991Sheppo 				 * otherwise, just remove it.
8421991Sheppo 				 */
8431991Sheppo 				if (vgenp->mccount > 1) {
8441991Sheppo 					vgenp->mctab[i] =
8451991Sheppo 						vgenp->mctab[vgenp->mccount-1];
8461991Sheppo 				}
8471991Sheppo 				vgenp->mccount--;
8481991Sheppo 				break;
8491991Sheppo 			}
8501991Sheppo 		}
8511991Sheppo 	}
8521991Sheppo 
8531991Sheppo 	RW_EXIT(&ldclp->rwlock);
8541991Sheppo 	RW_EXIT(&plistp->rwlock);
8551991Sheppo 
8561991Sheppo vgen_mcast_exit:
8571991Sheppo 	mutex_exit(&vgenp->lock);
8581991Sheppo 	return (DDI_SUCCESS);
8591991Sheppo }
8601991Sheppo 
8611991Sheppo /* set or clear promiscuous mode on the device */
8621991Sheppo static int
8631991Sheppo vgen_promisc(void *arg, boolean_t on)
8641991Sheppo {
8651991Sheppo 	_NOTE(ARGUNUSED(arg, on))
8661991Sheppo 	return (DDI_SUCCESS);
8671991Sheppo }
8681991Sheppo 
8691991Sheppo /* set the unicast mac address of the device */
8701991Sheppo static int
8711991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
8721991Sheppo {
8731991Sheppo 	_NOTE(ARGUNUSED(arg, mca))
8741991Sheppo 	return (DDI_SUCCESS);
8751991Sheppo }
8761991Sheppo 
8771991Sheppo /* get device statistics */
8782311Sseb int
8792311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
8801991Sheppo {
8811991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
8821991Sheppo 	vgen_port_t	*portp;
8831991Sheppo 	vgen_portlist_t	*plistp;
8842311Sseb 
8852311Sseb 	*val = 0;
8861991Sheppo 
8871991Sheppo 	plistp = &(vgenp->vgenports);
8881991Sheppo 	READ_ENTER(&plistp->rwlock);
8891991Sheppo 
8901991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
8912311Sseb 		*val += vgen_port_stat(portp, stat);
8921991Sheppo 	}
8931991Sheppo 
8941991Sheppo 	RW_EXIT(&plistp->rwlock);
8951991Sheppo 
8962311Sseb 	return (0);
8971991Sheppo }
8981991Sheppo 
8991991Sheppo static void
9001991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp)
9011991Sheppo {
9021991Sheppo 	 _NOTE(ARGUNUSED(arg, wq, mp))
9031991Sheppo }
9041991Sheppo 
9051991Sheppo /* vgen internal functions */
9061991Sheppo /* detach all ports from the device */
9071991Sheppo static void
9081991Sheppo vgen_detach_ports(vgen_t *vgenp)
9091991Sheppo {
9101991Sheppo 	vgen_port_t	*portp;
9111991Sheppo 	vgen_portlist_t	*plistp;
9121991Sheppo 
9131991Sheppo 	plistp = &(vgenp->vgenports);
9141991Sheppo 	WRITE_ENTER(&plistp->rwlock);
9151991Sheppo 
9161991Sheppo 	while ((portp = plistp->headp) != NULL) {
9171991Sheppo 		vgen_port_detach(portp);
9181991Sheppo 	}
9191991Sheppo 
9201991Sheppo 	RW_EXIT(&plistp->rwlock);
9211991Sheppo }
9221991Sheppo 
9231991Sheppo /*
9241991Sheppo  * detach the given port.
9251991Sheppo  */
9261991Sheppo static void
9271991Sheppo vgen_port_detach(vgen_port_t *portp)
9281991Sheppo {
9291991Sheppo 	vgen_t		*vgenp;
9301991Sheppo 	vgen_ldclist_t	*ldclp;
9311991Sheppo 	int		port_num;
9321991Sheppo 
9331991Sheppo 	vgenp = portp->vgenp;
9341991Sheppo 	port_num = portp->port_num;
9351991Sheppo 
9361991Sheppo 	DBG1((vgenp->vnetp,
9371991Sheppo 	    "vgen_port_detach: enter: port_num(%d)\n", port_num));
9381991Sheppo 
9391991Sheppo 	/* remove it from port list */
9401991Sheppo 	vgen_port_list_remove(portp);
9411991Sheppo 
9421991Sheppo 	/* detach channels from this port */
9431991Sheppo 	ldclp = &portp->ldclist;
9441991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
9451991Sheppo 	while (ldclp->headp) {
9461991Sheppo 		vgen_ldc_detach(ldclp->headp);
9471991Sheppo 	}
9481991Sheppo 	RW_EXIT(&ldclp->rwlock);
9491991Sheppo 
9501991Sheppo 	if (vgenp->vsw_portp == portp) {
9511991Sheppo 		vgenp->vsw_portp = NULL;
9521991Sheppo 	}
9531991Sheppo 	KMEM_FREE(portp);
9541991Sheppo 
9551991Sheppo 	DBG1((vgenp->vnetp,
9561991Sheppo 	    "vgen_port_detach: exit: port_num(%d)\n", port_num));
9571991Sheppo }
9581991Sheppo 
9591991Sheppo /* add a port to port list */
9601991Sheppo static void
9611991Sheppo vgen_port_list_insert(vgen_port_t *portp)
9621991Sheppo {
9631991Sheppo 	vgen_portlist_t *plistp;
9641991Sheppo 	vgen_t *vgenp;
9651991Sheppo 
9661991Sheppo 	vgenp = portp->vgenp;
9671991Sheppo 	plistp = &(vgenp->vgenports);
9681991Sheppo 
9691991Sheppo 	if (plistp->headp == NULL) {
9701991Sheppo 		plistp->headp = portp;
9711991Sheppo 	} else {
9721991Sheppo 		plistp->tailp->nextp = portp;
9731991Sheppo 	}
9741991Sheppo 	plistp->tailp = portp;
9751991Sheppo 	portp->nextp = NULL;
9761991Sheppo }
9771991Sheppo 
9781991Sheppo /* remove a port from port list */
9791991Sheppo static void
9801991Sheppo vgen_port_list_remove(vgen_port_t *portp)
9811991Sheppo {
9821991Sheppo 	vgen_port_t *prevp;
9831991Sheppo 	vgen_port_t *nextp;
9841991Sheppo 	vgen_portlist_t *plistp;
9851991Sheppo 	vgen_t *vgenp;
9861991Sheppo 
9871991Sheppo 	vgenp = portp->vgenp;
9881991Sheppo 
9891991Sheppo 	plistp = &(vgenp->vgenports);
9901991Sheppo 
9911991Sheppo 	if (plistp->headp == NULL)
9921991Sheppo 		return;
9931991Sheppo 
9941991Sheppo 	if (portp == plistp->headp) {
9951991Sheppo 		plistp->headp = portp->nextp;
9961991Sheppo 		if (portp == plistp->tailp)
9971991Sheppo 			plistp->tailp = plistp->headp;
9981991Sheppo 	} else {
9991991Sheppo 		for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) &&
10001991Sheppo 		    (nextp != portp); prevp = nextp);
10011991Sheppo 		if (nextp == portp) {
10021991Sheppo 			prevp->nextp = portp->nextp;
10031991Sheppo 		}
10041991Sheppo 		if (portp == plistp->tailp)
10051991Sheppo 			plistp->tailp = prevp;
10061991Sheppo 	}
10071991Sheppo }
10081991Sheppo 
10091991Sheppo /* lookup a port in the list based on port_num */
10101991Sheppo static vgen_port_t *
10111991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
10121991Sheppo {
10131991Sheppo 	vgen_port_t *portp = NULL;
10141991Sheppo 
10151991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10161991Sheppo 		if (portp->port_num == port_num) {
10171991Sheppo 			break;
10181991Sheppo 		}
10191991Sheppo 	}
10201991Sheppo 
10211991Sheppo 	return (portp);
10221991Sheppo }
10231991Sheppo 
10241991Sheppo /* enable ports for transmit/receive */
10251991Sheppo static void
10261991Sheppo vgen_init_ports(vgen_t *vgenp)
10271991Sheppo {
10281991Sheppo 	vgen_port_t	*portp;
10291991Sheppo 	vgen_portlist_t	*plistp;
10301991Sheppo 
10311991Sheppo 	plistp = &(vgenp->vgenports);
10321991Sheppo 	READ_ENTER(&plistp->rwlock);
10331991Sheppo 
10341991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10351991Sheppo 		vgen_port_init(portp);
10361991Sheppo 	}
10371991Sheppo 
10381991Sheppo 	RW_EXIT(&plistp->rwlock);
10391991Sheppo }
10401991Sheppo 
10411991Sheppo static void
10421991Sheppo vgen_port_init(vgen_port_t *portp)
10431991Sheppo {
10441991Sheppo 	vgen_t *vgenp;
10451991Sheppo 
10461991Sheppo 	vgenp = portp->vgenp;
10471991Sheppo 	/*
10481991Sheppo 	 * Create fdb entry in vnet, corresponding to the mac
10491991Sheppo 	 * address of this port. Note that the port specified
10501991Sheppo 	 * is vsw-port. This is done so that vsw-port acts
10511991Sheppo 	 * as the route to reach this macaddr, until the
10521991Sheppo 	 * channel for this port comes up (LDC_UP) and
10531991Sheppo 	 * handshake is done successfully.
10541991Sheppo 	 * eg, if the peer is OBP-vnet, it may not bring the
10551991Sheppo 	 * channel up for this port and may communicate via
10561991Sheppo 	 * vsw to reach this port.
10571991Sheppo 	 * Later, when Solaris-vnet comes up at the other end
10581991Sheppo 	 * of the channel for this port and brings up the channel,
10591991Sheppo 	 * it is an indication that peer vnet is capable of
10601991Sheppo 	 * distributed switching, so the direct route through this
10611991Sheppo 	 * port is specified in fdb, using vnet_modify_fdb(macaddr);
10621991Sheppo 	 */
10631991Sheppo 	vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr,
10641991Sheppo 	    vgen_tx, vgenp->vsw_portp);
10651991Sheppo 
10661991Sheppo 	if (portp == vgenp->vsw_portp) {
10671991Sheppo 		/*
10681991Sheppo 		 * create the default route entry in vnet's fdb.
10691991Sheppo 		 * This is the entry used by vnet to reach
10701991Sheppo 		 * unknown destinations, which basically goes
10711991Sheppo 		 * through vsw on domain0 and out through the
10721991Sheppo 		 * physical device bound to vsw.
10731991Sheppo 		 */
10741991Sheppo 		vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp);
10751991Sheppo 	}
10761991Sheppo 
10771991Sheppo 	/* Bring up the channels of this port */
10781991Sheppo 	vgen_init_ldcs(portp);
10791991Sheppo }
10801991Sheppo 
10811991Sheppo /* disable transmit/receive on ports */
10821991Sheppo static void
10831991Sheppo vgen_uninit_ports(vgen_t *vgenp)
10841991Sheppo {
10851991Sheppo 	vgen_port_t	*portp;
10861991Sheppo 	vgen_portlist_t	*plistp;
10871991Sheppo 
10881991Sheppo 	plistp = &(vgenp->vgenports);
10891991Sheppo 	READ_ENTER(&plistp->rwlock);
10901991Sheppo 
10911991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
10921991Sheppo 		vgen_port_uninit(portp);
10931991Sheppo 	}
10941991Sheppo 
10951991Sheppo 	RW_EXIT(&plistp->rwlock);
10961991Sheppo }
10971991Sheppo 
10981991Sheppo static void
10991991Sheppo vgen_port_uninit(vgen_port_t *portp)
11001991Sheppo {
11011991Sheppo 	vgen_t *vgenp;
11021991Sheppo 
11031991Sheppo 	vgenp = portp->vgenp;
11041991Sheppo 
11051991Sheppo 	vgen_uninit_ldcs(portp);
11061991Sheppo 	/* delete the entry in vnet's fdb for this port */
11071991Sheppo 	vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr);
11081991Sheppo 	if (portp == vgenp->vsw_portp) {
11091991Sheppo 		/*
11101991Sheppo 		 * if this is vsw-port, then delete the default
11111991Sheppo 		 * route entry in vnet's fdb.
11121991Sheppo 		 */
11131991Sheppo 		vnet_del_def_rte(vgenp->vnetp);
11141991Sheppo 	}
11151991Sheppo }
11161991Sheppo 
11171991Sheppo /* register with MD event generator */
11181991Sheppo static int
11191991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
11201991Sheppo {
11211991Sheppo 	mdeg_prop_spec_t	*pspecp;
11221991Sheppo 	mdeg_node_spec_t	*parentp;
11231991Sheppo 	uint_t			templatesz;
11241991Sheppo 	int			rv;
11251991Sheppo 	mdeg_handle_t		hdl;
11261991Sheppo 	int			i;
11271991Sheppo 	void			*vnetp = vgenp->vnetp;
11281991Sheppo 
11291991Sheppo 	i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip,
11301991Sheppo 			DDI_PROP_DONTPASS, reg_propname, -1);
11311991Sheppo 	if (i == -1) {
11321991Sheppo 		return (DDI_FAILURE);
11331991Sheppo 	}
11341991Sheppo 	templatesz = sizeof (vgen_prop_template);
11351991Sheppo 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
11361991Sheppo 	if (pspecp == NULL) {
11371991Sheppo 		return (DDI_FAILURE);
11381991Sheppo 	}
11391991Sheppo 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
11401991Sheppo 	if (parentp == NULL) {
11411991Sheppo 		kmem_free(pspecp, templatesz);
11421991Sheppo 		return (DDI_FAILURE);
11431991Sheppo 	}
11441991Sheppo 
11451991Sheppo 	bcopy(vgen_prop_template, pspecp, templatesz);
11461991Sheppo 
11471991Sheppo 	/*
11481991Sheppo 	 * NOTE: The instance here refers to the value of "reg" property and
11491991Sheppo 	 * not the dev_info instance (ddi_get_instance()) of vnet.
11501991Sheppo 	 */
11511991Sheppo 	VGEN_SET_MDEG_PROP_INST(pspecp, i);
11521991Sheppo 
11531991Sheppo 	parentp->namep = "virtual-device";
11541991Sheppo 	parentp->specp = pspecp;
11551991Sheppo 
11561991Sheppo 	/* save parentp in vgen_t */
11571991Sheppo 	vgenp->mdeg_parentp = parentp;
11581991Sheppo 
11591991Sheppo 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl);
11601991Sheppo 	if (rv != MDEG_SUCCESS) {
11611991Sheppo 		DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n"));
11621991Sheppo 		KMEM_FREE(parentp);
11631991Sheppo 		kmem_free(pspecp, templatesz);
11641991Sheppo 		vgenp->mdeg_parentp = NULL;
11651991Sheppo 		return (DDI_FAILURE);
11661991Sheppo 	}
11671991Sheppo 
11681991Sheppo 	/* save mdeg handle in vgen_t */
11691991Sheppo 	vgenp->mdeg_hdl = hdl;
11701991Sheppo 
11711991Sheppo 	return (DDI_SUCCESS);
11721991Sheppo }
11731991Sheppo 
11741991Sheppo /* unregister with MD event generator */
11751991Sheppo static void
11761991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
11771991Sheppo {
11781991Sheppo 	(void) mdeg_unregister(vgenp->mdeg_hdl);
11791991Sheppo 	KMEM_FREE(vgenp->mdeg_parentp);
11801991Sheppo 	vgenp->mdeg_parentp = NULL;
11811991Sheppo 	vgenp->mdeg_hdl = NULL;
11821991Sheppo }
11831991Sheppo 
11841991Sheppo /* callback function registered with MD event generator */
11851991Sheppo static int
11861991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
11871991Sheppo {
11881991Sheppo 	int idx;
11891991Sheppo 	int vsw_idx = -1;
11901991Sheppo 	uint64_t val;
11911991Sheppo 	vgen_t *vgenp;
11921991Sheppo 
11931991Sheppo 	if ((resp == NULL) || (cb_argp == NULL)) {
11941991Sheppo 		return (MDEG_FAILURE);
11951991Sheppo 	}
11961991Sheppo 
11971991Sheppo 	vgenp = (vgen_t *)cb_argp;
11981991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n"));
11991991Sheppo 
12001991Sheppo 	mutex_enter(&vgenp->lock);
12011991Sheppo 
12021991Sheppo 	DBG1((vgenp->vnetp,
12031991Sheppo 	    "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n",
12041991Sheppo 	    resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem));
12051991Sheppo 
12061991Sheppo 	for (idx = 0; idx < resp->removed.nelem; idx++) {
12071991Sheppo 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
12081991Sheppo 		    resp->removed.mdep[idx]);
12091991Sheppo 	}
12101991Sheppo 
12111991Sheppo 	if (vgenp->vsw_portp == NULL) {
12121991Sheppo 		/*
12131991Sheppo 		 * find vsw_port and add it first, because other ports need
12141991Sheppo 		 * this when adding fdb entry (see vgen_port_init()).
12151991Sheppo 		 */
12161991Sheppo 		for (idx = 0; idx < resp->added.nelem; idx++) {
12171991Sheppo 			if (!(md_get_prop_val(resp->added.mdp,
12181991Sheppo 			    resp->added.mdep[idx], swport_propname, &val))) {
12191991Sheppo 				if (val == 0) {
12201991Sheppo 					/*
12211991Sheppo 					 * This port is connected to the
12221991Sheppo 					 * vsw on dom0.
12231991Sheppo 					 */
12241991Sheppo 					vsw_idx = idx;
12251991Sheppo 					(void) vgen_add_port(vgenp,
12261991Sheppo 					    resp->added.mdp,
12271991Sheppo 					    resp->added.mdep[idx]);
12281991Sheppo 					break;
12291991Sheppo 				}
12301991Sheppo 			}
12311991Sheppo 		}
12321991Sheppo 		if (vsw_idx == -1) {
12331991Sheppo 			DWARN((vgenp->vnetp, "vgen_mdeg_cb: "
12341991Sheppo 			    "can't find vsw_port\n"));
12351991Sheppo 			return (MDEG_FAILURE);
12361991Sheppo 		}
12371991Sheppo 	}
12381991Sheppo 
12391991Sheppo 	for (idx = 0; idx < resp->added.nelem; idx++) {
12401991Sheppo 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
12411991Sheppo 			continue;
12421991Sheppo 		(void) vgen_add_port(vgenp, resp->added.mdp,
12431991Sheppo 		    resp->added.mdep[idx]);
12441991Sheppo 	}
12451991Sheppo 
12461991Sheppo 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
12471991Sheppo 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
12481991Sheppo 		    resp->match_curr.mdep[idx],
12491991Sheppo 		    resp->match_prev.mdp,
12501991Sheppo 		    resp->match_prev.mdep[idx]);
12511991Sheppo 	}
12521991Sheppo 
12531991Sheppo 	mutex_exit(&vgenp->lock);
12541991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n"));
12551991Sheppo 	return (MDEG_SUCCESS);
12561991Sheppo }
12571991Sheppo 
12581991Sheppo /* add a new port to the device */
12591991Sheppo static int
12601991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
12611991Sheppo {
12621991Sheppo 	uint64_t	port_num;
12631991Sheppo 	uint64_t	*ldc_ids;
12641991Sheppo 	uint64_t	macaddr;
12651991Sheppo 	uint64_t	val;
12661991Sheppo 	int		num_ldcs;
12671991Sheppo 	int		vsw_port = B_FALSE;
12681991Sheppo 	int		i;
12691991Sheppo 	int		addrsz;
12701991Sheppo 	int		num_nodes = 0;
12711991Sheppo 	int		listsz = 0;
12721991Sheppo 	mde_cookie_t	*listp = NULL;
12731991Sheppo 	uint8_t		*addrp;
12741991Sheppo 	struct ether_addr	ea;
12751991Sheppo 
12761991Sheppo 	/* read "id" property to get the port number */
12771991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
12781991Sheppo 		DWARN((vgenp->vnetp,
12791991Sheppo 		    "vgen_add_port: prop(%s) not found\n", id_propname));
12801991Sheppo 		return (DDI_FAILURE);
12811991Sheppo 	}
12821991Sheppo 
12831991Sheppo 	/*
12841991Sheppo 	 * Find the channel endpoint node(s) under this port node.
12851991Sheppo 	 */
12861991Sheppo 	if ((num_nodes = md_node_count(mdp)) <= 0) {
12871991Sheppo 		DWARN((vgenp->vnetp,
12881991Sheppo 		    "vgen_add_port: invalid number of nodes found (%d)",
12891991Sheppo 		    num_nodes));
12901991Sheppo 		return (DDI_FAILURE);
12911991Sheppo 	}
12921991Sheppo 
12931991Sheppo 	/* allocate space for node list */
12941991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
12951991Sheppo 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
12961991Sheppo 	if (listp == NULL)
12971991Sheppo 		return (DDI_FAILURE);
12981991Sheppo 
12991991Sheppo 	num_ldcs = md_scan_dag(mdp, mdex,
13001991Sheppo 		md_find_name(mdp, channel_propname),
13011991Sheppo 		md_find_name(mdp, "fwd"), listp);
13021991Sheppo 
13031991Sheppo 	if (num_ldcs <= 0) {
13041991Sheppo 		DWARN((vgenp->vnetp,
13051991Sheppo 		    "vgen_add_port: can't find %s nodes", channel_propname));
13061991Sheppo 		kmem_free(listp, listsz);
13071991Sheppo 		return (DDI_FAILURE);
13081991Sheppo 	}
13091991Sheppo 
13101991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs));
13111991Sheppo 
13121991Sheppo 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
13131991Sheppo 	if (ldc_ids == NULL) {
13141991Sheppo 		kmem_free(listp, listsz);
13151991Sheppo 		return (DDI_FAILURE);
13161991Sheppo 	}
13171991Sheppo 
13181991Sheppo 	for (i = 0; i < num_ldcs; i++) {
13191991Sheppo 		/* read channel ids */
13201991Sheppo 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
13211991Sheppo 			DWARN((vgenp->vnetp,
13221991Sheppo 			    "vgen_add_port: prop(%s) not found\n",
13231991Sheppo 			    id_propname));
13241991Sheppo 			kmem_free(listp, listsz);
13251991Sheppo 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13261991Sheppo 			return (DDI_FAILURE);
13271991Sheppo 		}
13281991Sheppo 		DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx",
13291991Sheppo 		    ldc_ids[i]));
13301991Sheppo 	}
13311991Sheppo 
13321991Sheppo 	kmem_free(listp, listsz);
13331991Sheppo 
13341991Sheppo 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
13351991Sheppo 	    &addrsz)) {
13361991Sheppo 		DWARN((vgenp->vnetp,
13371991Sheppo 		    "vgen_add_port: prop(%s) not found\n", rmacaddr_propname));
13381991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13391991Sheppo 		return (DDI_FAILURE);
13401991Sheppo 	}
13411991Sheppo 
13421991Sheppo 	if (addrsz < ETHERADDRL) {
13431991Sheppo 		DWARN((vgenp->vnetp,
13441991Sheppo 		    "vgen_add_port: invalid address size (%d)\n", addrsz));
13451991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13461991Sheppo 		return (DDI_FAILURE);
13471991Sheppo 	}
13481991Sheppo 
13491991Sheppo 	macaddr = *((uint64_t *)addrp);
13501991Sheppo 
13511991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n",
13521991Sheppo 	    macaddr));
13531991Sheppo 
13541991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
13551991Sheppo 		ea.ether_addr_octet[i] = macaddr & 0xFF;
13561991Sheppo 		macaddr >>= 8;
13571991Sheppo 	}
13581991Sheppo 
13591991Sheppo 	if (vgenp->vsw_portp == NULL) {
13601991Sheppo 		if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
13611991Sheppo 			if (val == 0) {
13621991Sheppo 				/* This port is connected to the vsw on dom0 */
13631991Sheppo 				vsw_port = B_TRUE;
13641991Sheppo 			}
13651991Sheppo 		}
13661991Sheppo 	}
13671991Sheppo 	(void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
13681991Sheppo 	    &ea, vsw_port);
13691991Sheppo 
13701991Sheppo 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
13711991Sheppo 
13721991Sheppo 	return (DDI_SUCCESS);
13731991Sheppo }
13741991Sheppo 
13751991Sheppo /* remove a port from the device */
13761991Sheppo static int
13771991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
13781991Sheppo {
13791991Sheppo 	uint64_t	port_num;
13801991Sheppo 	vgen_port_t	*portp;
13811991Sheppo 	vgen_portlist_t	*plistp;
13821991Sheppo 
13831991Sheppo 	/* read "id" property to get the port number */
13841991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
13851991Sheppo 		DWARN((vgenp->vnetp,
13861991Sheppo 		    "vgen_remove_port: prop(%s) not found\n", id_propname));
13871991Sheppo 		return (DDI_FAILURE);
13881991Sheppo 	}
13891991Sheppo 
13901991Sheppo 	plistp = &(vgenp->vgenports);
13911991Sheppo 
13921991Sheppo 	WRITE_ENTER(&plistp->rwlock);
13931991Sheppo 	portp = vgen_port_lookup(plistp, (int)port_num);
13941991Sheppo 	if (portp == NULL) {
13951991Sheppo 		DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n",
13961991Sheppo 		    port_num));
13971991Sheppo 		RW_EXIT(&plistp->rwlock);
13981991Sheppo 		return (DDI_FAILURE);
13991991Sheppo 	}
14001991Sheppo 
14011991Sheppo 	vgen_port_detach_mdeg(portp);
14021991Sheppo 	RW_EXIT(&plistp->rwlock);
14031991Sheppo 
14041991Sheppo 	return (DDI_SUCCESS);
14051991Sheppo }
14061991Sheppo 
14071991Sheppo /* attach a port to the device based on mdeg data */
14081991Sheppo static int
14091991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
14101991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port)
14111991Sheppo {
14121991Sheppo 	vgen_port_t		*portp;
14131991Sheppo 	vgen_portlist_t		*plistp;
14141991Sheppo 	int			i;
14151991Sheppo 
14161991Sheppo 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP);
14171991Sheppo 	if (portp == NULL) {
14181991Sheppo 		return (DDI_FAILURE);
14191991Sheppo 	}
14201991Sheppo 	portp->vgenp = vgenp;
14211991Sheppo 	portp->port_num = port_num;
14221991Sheppo 
14231991Sheppo 	DBG1((vgenp->vnetp,
14241991Sheppo 	    "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num));
14251991Sheppo 
14261991Sheppo 	portp->ldclist.num_ldcs = 0;
14271991Sheppo 	portp->ldclist.headp = NULL;
14281991Sheppo 	rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
14291991Sheppo 
14301991Sheppo 	ether_copy(macaddr, &portp->macaddr);
14311991Sheppo 	for (i = 0; i < num_ids; i++) {
14321991Sheppo 		DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n",
14331991Sheppo 		    ldcids[i]));
14341991Sheppo 		(void) vgen_ldc_attach(portp, ldcids[i]);
14351991Sheppo 	}
14361991Sheppo 
14371991Sheppo 	/* link it into the list of ports */
14381991Sheppo 	plistp = &(vgenp->vgenports);
14391991Sheppo 	WRITE_ENTER(&plistp->rwlock);
14401991Sheppo 	vgen_port_list_insert(portp);
14411991Sheppo 	RW_EXIT(&plistp->rwlock);
14421991Sheppo 
14431991Sheppo 	/* This port is connected to the vsw on domain0 */
14441991Sheppo 	if (vsw_port)
14451991Sheppo 		vgenp->vsw_portp = portp;
14461991Sheppo 
14471991Sheppo 	if (vgenp->flags & VGEN_STARTED) {	/* interface is configured */
14481991Sheppo 		vgen_port_init(portp);
14491991Sheppo 	}
14501991Sheppo 
14511991Sheppo 	DBG1((vgenp->vnetp,
14521991Sheppo 	    "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num));
14531991Sheppo 	return (DDI_SUCCESS);
14541991Sheppo }
14551991Sheppo 
14561991Sheppo /* detach a port from the device based on mdeg data */
14571991Sheppo static void
14581991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
14591991Sheppo {
14601991Sheppo 	vgen_t *vgenp = portp->vgenp;
14611991Sheppo 
14621991Sheppo 	DBG1((vgenp->vnetp,
14631991Sheppo 	    "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num));
14641991Sheppo 	/* stop the port if needed */
14651991Sheppo 	if (vgenp->flags & VGEN_STARTED) {
14661991Sheppo 		vgen_port_uninit(portp);
14671991Sheppo 	}
14681991Sheppo 	vgen_port_detach(portp);
14691991Sheppo 
14701991Sheppo 	DBG1((vgenp->vnetp,
14711991Sheppo 	    "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num));
14721991Sheppo }
14731991Sheppo 
14741991Sheppo static int
14751991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
14761991Sheppo 	md_t *prev_mdp, mde_cookie_t prev_mdex)
14771991Sheppo {
14781991Sheppo 	 _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex))
14791991Sheppo 
14801991Sheppo 	/* XXX: TBD */
14811991Sheppo 	return (DDI_SUCCESS);
14821991Sheppo }
14831991Sheppo 
14841991Sheppo static uint64_t
14852311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
14861991Sheppo {
14871991Sheppo 	vgen_ldclist_t	*ldclp;
14881991Sheppo 	vgen_ldc_t *ldcp;
14891991Sheppo 	uint64_t	val;
14901991Sheppo 
14911991Sheppo 	val = 0;
14921991Sheppo 	ldclp = &portp->ldclist;
14931991Sheppo 
14941991Sheppo 	READ_ENTER(&ldclp->rwlock);
14951991Sheppo 	for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
14961991Sheppo 		val += vgen_ldc_stat(ldcp, stat);
14971991Sheppo 	}
14981991Sheppo 	RW_EXIT(&ldclp->rwlock);
14991991Sheppo 
15001991Sheppo 	return (val);
15011991Sheppo }
15021991Sheppo 
15031991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
15041991Sheppo static int
15051991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
15061991Sheppo {
15071991Sheppo 	vgen_t 		*vgenp;
15081991Sheppo 	vgen_ldclist_t	*ldclp;
15091991Sheppo 	vgen_ldc_t 	*ldcp, **prev_ldcp;
15101991Sheppo 	ldc_attr_t 	attr;
15111991Sheppo 	int 		status;
15121991Sheppo 	ldc_status_t	istatus;
15131991Sheppo 	enum		{AST_init = 0x0, AST_ldc_alloc = 0x1,
15141991Sheppo 			AST_mutex_init = 0x2, AST_ldc_init = 0x4,
1515*2336Snarayan 			AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10,
1516*2336Snarayan 			AST_create_rxmblks = 0x20}
15171991Sheppo 			attach_state;
15181991Sheppo 
15191991Sheppo 	attach_state = AST_init;
15201991Sheppo 	vgenp = portp->vgenp;
15211991Sheppo 	ldclp = &portp->ldclist;
15221991Sheppo 
15231991Sheppo 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
15241991Sheppo 	if (ldcp == NULL) {
15251991Sheppo 		goto ldc_attach_failed;
15261991Sheppo 	}
15271991Sheppo 	ldcp->ldc_id = ldc_id;
15281991Sheppo 	ldcp->portp = portp;
15291991Sheppo 	ldcp->reclaim_lowat = vnet_reclaim_lowat;
15301991Sheppo 	ldcp->reclaim_hiwat = vnet_reclaim_hiwat;
15311991Sheppo 
15321991Sheppo 	attach_state |= AST_ldc_alloc;
15331991Sheppo 
15341991Sheppo 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
15351991Sheppo 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
15361991Sheppo 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
15371991Sheppo 
15381991Sheppo 	attach_state |= AST_mutex_init;
15391991Sheppo 
15401991Sheppo 	attr.devclass = LDC_DEV_NT;
15411991Sheppo 	attr.instance = ddi_get_instance(vgenp->vnetdip);
15421991Sheppo 	attr.mode = LDC_MODE_UNRELIABLE;
15431991Sheppo 	attr.qlen = vnet_ldc_qlen;
15441991Sheppo 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
15451991Sheppo 	if (status != 0) {
15461991Sheppo 		DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n",
15471991Sheppo 		    ldc_id, status));
15481991Sheppo 		goto ldc_attach_failed;
15491991Sheppo 	}
15501991Sheppo 	attach_state |= AST_ldc_init;
15511991Sheppo 
15521991Sheppo 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
15531991Sheppo 	if (status != 0) {
15541991Sheppo 		DWARN((vgenp->vnetp,
15551991Sheppo 		    "ldc_reg_callback failed, id (%lx) rv (%d)\n",
15561991Sheppo 		    ldc_id, status));
15571991Sheppo 		goto ldc_attach_failed;
15581991Sheppo 	}
15591991Sheppo 	attach_state |= AST_ldc_reg_cb;
15601991Sheppo 
15611991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
15621991Sheppo 	ASSERT(istatus == LDC_INIT);
15631991Sheppo 	ldcp->ldc_status = istatus;
15641991Sheppo 
15651991Sheppo 	/* allocate transmit resources */
15661991Sheppo 	status = vgen_alloc_tx_ring(ldcp);
15671991Sheppo 	if (status != 0) {
15681991Sheppo 		goto ldc_attach_failed;
15691991Sheppo 	}
15701991Sheppo 	attach_state |= AST_alloc_tx_ring;
15711991Sheppo 
1572*2336Snarayan 	/* allocate receive resources */
1573*2336Snarayan 	ldcp->num_rbufs = vnet_nrbufs;
1574*2336Snarayan 	ldcp->rmp = NULL;
1575*2336Snarayan 	status = vio_create_mblks(ldcp->num_rbufs, VGEN_DBLK_SZ,
1576*2336Snarayan 		&(ldcp->rmp));
1577*2336Snarayan 	if (status != 0) {
1578*2336Snarayan 		goto ldc_attach_failed;
1579*2336Snarayan 	}
1580*2336Snarayan 	attach_state |= AST_create_rxmblks;
1581*2336Snarayan 
15821991Sheppo 	/* Setup kstats for the channel */
15831991Sheppo 	status = vgen_setup_kstats(ldcp);
15841991Sheppo 	if (status != VGEN_SUCCESS) {
15851991Sheppo 		goto ldc_attach_failed;
15861991Sheppo 	}
15871991Sheppo 
15881991Sheppo 	/* initialize vgen_versions supported */
15891991Sheppo 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
15901991Sheppo 
15911991Sheppo 	/* link it into the list of channels for this port */
15921991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
15931991Sheppo 	prev_ldcp = (vgen_ldc_t **)(&ldclp->headp);
15941991Sheppo 	ldcp->nextp = *prev_ldcp;
15951991Sheppo 	*prev_ldcp = ldcp;
15961991Sheppo 	ldclp->num_ldcs++;
15971991Sheppo 	RW_EXIT(&ldclp->rwlock);
15981991Sheppo 
15991991Sheppo 	ldcp->flags |= CHANNEL_ATTACHED;
16001991Sheppo 	return (DDI_SUCCESS);
16011991Sheppo 
16021991Sheppo ldc_attach_failed:
1603*2336Snarayan 	if (attach_state & AST_create_rxmblks) {
1604*2336Snarayan 		(void) vio_destroy_mblks(ldcp->rmp);
1605*2336Snarayan 	}
16061991Sheppo 	if (attach_state & AST_alloc_tx_ring) {
16071991Sheppo 		vgen_free_tx_ring(ldcp);
16081991Sheppo 	}
16091991Sheppo 	if (attach_state & AST_ldc_reg_cb) {
16101991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
16111991Sheppo 	}
16121991Sheppo 	if (attach_state & AST_ldc_init) {
16131991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
16141991Sheppo 	}
16151991Sheppo 	if (attach_state & AST_mutex_init) {
16161991Sheppo 		mutex_destroy(&ldcp->tclock);
16171991Sheppo 		mutex_destroy(&ldcp->txlock);
16181991Sheppo 		mutex_destroy(&ldcp->cblock);
16191991Sheppo 	}
16201991Sheppo 	if (attach_state & AST_ldc_alloc) {
16211991Sheppo 		KMEM_FREE(ldcp);
16221991Sheppo 	}
16231991Sheppo 	return (DDI_FAILURE);
16241991Sheppo }
16251991Sheppo 
16261991Sheppo /* detach a channel from the port */
16271991Sheppo static void
16281991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
16291991Sheppo {
16301991Sheppo 	vgen_port_t	*portp;
16311991Sheppo 	vgen_t 		*vgenp;
16321991Sheppo 	vgen_ldc_t 	*pldcp;
16331991Sheppo 	vgen_ldc_t	**prev_ldcp;
16341991Sheppo 	vgen_ldclist_t	*ldclp;
16351991Sheppo 
16361991Sheppo 	portp = ldcp->portp;
16371991Sheppo 	vgenp = portp->vgenp;
16381991Sheppo 	ldclp = &portp->ldclist;
16391991Sheppo 
16401991Sheppo 	prev_ldcp =  (vgen_ldc_t **)&ldclp->headp;
16411991Sheppo 	for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
16421991Sheppo 		if (pldcp == ldcp) {
16431991Sheppo 			break;
16441991Sheppo 		}
16451991Sheppo 	}
16461991Sheppo 
16471991Sheppo 	if (pldcp == NULL) {
16481991Sheppo 		/* invalid ldcp? */
16491991Sheppo 		return;
16501991Sheppo 	}
16511991Sheppo 
16521991Sheppo 	if (ldcp->ldc_status != LDC_INIT) {
16531991Sheppo 		DWARN((vgenp->vnetp,
16541991Sheppo 		    "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n",
16551991Sheppo 			    ldcp->ldc_id));
16561991Sheppo 	}
16571991Sheppo 
16581991Sheppo 	if (ldcp->flags & CHANNEL_ATTACHED) {
16591991Sheppo 		ldcp->flags &= ~(CHANNEL_ATTACHED);
16601991Sheppo 
16611991Sheppo 		vgen_destroy_kstats(ldcp);
1662*2336Snarayan 
1663*2336Snarayan 		/* free receive resources */
1664*2336Snarayan 		if (vio_destroy_mblks(ldcp->rmp)) {
1665*2336Snarayan 			/*
1666*2336Snarayan 			 * if we cannot reclaim all mblks, put this
1667*2336Snarayan 			 * on the list of pools to be reclaimed when the
1668*2336Snarayan 			 * device gets detached (see vgen_uninit()).
1669*2336Snarayan 			 */
1670*2336Snarayan 			ldcp->rmp->nextp =  vgenp->rmp;
1671*2336Snarayan 			vgenp->rmp = ldcp->rmp;
1672*2336Snarayan 		}
1673*2336Snarayan 
16741991Sheppo 		/* free transmit resources */
16751991Sheppo 		vgen_free_tx_ring(ldcp);
1676*2336Snarayan 
16771991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
16781991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
16791991Sheppo 		mutex_destroy(&ldcp->tclock);
16801991Sheppo 		mutex_destroy(&ldcp->txlock);
16811991Sheppo 		mutex_destroy(&ldcp->cblock);
16821991Sheppo 
16831991Sheppo 		/* unlink it from the list */
16841991Sheppo 		*prev_ldcp = ldcp->nextp;
16851991Sheppo 		ldclp->num_ldcs--;
16861991Sheppo 		KMEM_FREE(ldcp);
16871991Sheppo 	}
16881991Sheppo }
16891991Sheppo 
16901991Sheppo /*
16911991Sheppo  * This function allocates transmit resources for the channel.
16921991Sheppo  * The resources consist of a transmit descriptor ring and an associated
16931991Sheppo  * transmit buffer ring.
16941991Sheppo  */
16951991Sheppo static int
16961991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp)
16971991Sheppo {
16981991Sheppo 	void *tbufp;
16991991Sheppo 	ldc_mem_info_t minfo;
17001991Sheppo 	uint32_t txdsize;
17011991Sheppo 	uint32_t tbufsize;
17021991Sheppo 	int status;
17031991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
17041991Sheppo 
17051991Sheppo 	ldcp->num_txds = vnet_ntxds;
17061991Sheppo 	txdsize = sizeof (vnet_public_desc_t);
17071991Sheppo 	tbufsize = sizeof (vgen_private_desc_t);
17081991Sheppo 
17091991Sheppo 	/* allocate transmit buffer ring */
17101991Sheppo 	tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
17111991Sheppo 	if (tbufp == NULL) {
17121991Sheppo 		return (DDI_FAILURE);
17131991Sheppo 	}
17141991Sheppo 
17151991Sheppo 	/* create transmit descriptor ring */
17161991Sheppo 	status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
17171991Sheppo 	    &ldcp->tx_dhandle);
17181991Sheppo 	if (status) {
17191991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() "
17201991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
17211991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
17221991Sheppo 		return (DDI_FAILURE);
17231991Sheppo 	}
17241991Sheppo 
17251991Sheppo 	/* get the addr of descripror ring */
17261991Sheppo 	status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
17271991Sheppo 	if (status) {
17281991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() "
17291991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
17301991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
17311991Sheppo 		(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
17321991Sheppo 		ldcp->tbufp = NULL;
17331991Sheppo 		return (DDI_FAILURE);
17341991Sheppo 	}
17351991Sheppo 	ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr);
17361991Sheppo 	ldcp->tbufp = tbufp;
17371991Sheppo 
17381991Sheppo 	ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]);
17391991Sheppo 	ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]);
17401991Sheppo 
17411991Sheppo 	return (DDI_SUCCESS);
17421991Sheppo }
17431991Sheppo 
17441991Sheppo /* Free transmit resources for the channel */
17451991Sheppo static void
17461991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp)
17471991Sheppo {
17481991Sheppo 	int tbufsize = sizeof (vgen_private_desc_t);
17491991Sheppo 
17501991Sheppo 	/* free transmit descriptor ring */
17511991Sheppo 	(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
17521991Sheppo 
17531991Sheppo 	/* free transmit buffer ring */
17541991Sheppo 	kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize);
17551991Sheppo 	ldcp->txdp = ldcp->txdendp = NULL;
17561991Sheppo 	ldcp->tbufp = ldcp->tbufendp = NULL;
17571991Sheppo }
17581991Sheppo 
17591991Sheppo /* enable transmit/receive on the channels for the port */
17601991Sheppo static void
17611991Sheppo vgen_init_ldcs(vgen_port_t *portp)
17621991Sheppo {
17631991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
17641991Sheppo 	vgen_ldc_t	*ldcp;
17651991Sheppo 
17661991Sheppo 	READ_ENTER(&ldclp->rwlock);
17671991Sheppo 	ldcp =  ldclp->headp;
17681991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
17691991Sheppo 		(void) vgen_ldc_init(ldcp);
17701991Sheppo 	}
17711991Sheppo 	RW_EXIT(&ldclp->rwlock);
17721991Sheppo }
17731991Sheppo 
17741991Sheppo /* stop transmit/receive on the channels for the port */
17751991Sheppo static void
17761991Sheppo vgen_uninit_ldcs(vgen_port_t *portp)
17771991Sheppo {
17781991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
17791991Sheppo 	vgen_ldc_t	*ldcp;
17801991Sheppo 
17811991Sheppo 	READ_ENTER(&ldclp->rwlock);
17821991Sheppo 	ldcp =  ldclp->headp;
17831991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
17841991Sheppo 		vgen_ldc_uninit(ldcp);
17851991Sheppo 	}
17861991Sheppo 	RW_EXIT(&ldclp->rwlock);
17871991Sheppo }
17881991Sheppo 
17891991Sheppo /* enable transmit/receive on the channel */
17901991Sheppo static int
17911991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
17921991Sheppo {
17931991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
17941991Sheppo 	ldc_status_t	istatus;
17951991Sheppo 	int		rv;
17961991Sheppo 	enum		{ ST_init = 0x0, ST_init_tbufs = 0x1,
17971991Sheppo 			    ST_ldc_open = 0x2, ST_dring_bind = 0x4
17981991Sheppo 			    }
17991991Sheppo 			init_state;
18001991Sheppo 	uint32_t	ncookies = 0;
18012109Slm66018 	uint32_t	retries = 0;
18021991Sheppo 
18031991Sheppo 	init_state = ST_init;
18041991Sheppo 
18051991Sheppo 	LDC_LOCK(ldcp);
18061991Sheppo 
18071991Sheppo 	rv = ldc_open(ldcp->ldc_handle);
18081991Sheppo 	if (rv != 0) {
18091991Sheppo 		DWARN((vnetp,
18101991Sheppo 		    "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
18111991Sheppo 		    ldcp->ldc_id, rv));
18121991Sheppo 		goto ldcinit_failed;
18131991Sheppo 	}
18141991Sheppo 	init_state |= ST_ldc_open;
18151991Sheppo 
18161991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
18171991Sheppo 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
18181991Sheppo 		DWARN((vnetp,
18191991Sheppo 		    "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
18201991Sheppo 		    ldcp->ldc_id, istatus));
18211991Sheppo 		goto ldcinit_failed;
18221991Sheppo 	}
18231991Sheppo 	ldcp->ldc_status = istatus;
18241991Sheppo 
18251991Sheppo 	rv = vgen_init_tbufs(ldcp);
18261991Sheppo 	if (rv != 0) {
18271991Sheppo 		DWARN((vnetp,
18281991Sheppo 		    "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
18291991Sheppo 		    ldcp->ldc_id));
18301991Sheppo 		goto ldcinit_failed;
18311991Sheppo 	}
18321991Sheppo 	init_state |= ST_init_tbufs;
18331991Sheppo 
18341991Sheppo 	/* Bind descriptor ring to the channel */
18351991Sheppo 	rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
18361991Sheppo 	    LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
18371991Sheppo 	if (rv != 0) {
18381991Sheppo 		DWARN((vnetp, "vgen_ldcinit: id (%lx) "
1839*2336Snarayan 		    "ldc_mem_dring_bind failed rv(%x)\n", ldcp->ldc_id, rv));
18401991Sheppo 		goto ldcinit_failed;
18411991Sheppo 	}
18421991Sheppo 
18431991Sheppo 	ASSERT(ncookies == 1);
18441991Sheppo 	ldcp->num_txdcookies = ncookies;
18451991Sheppo 
18461991Sheppo 	init_state |= ST_dring_bind;
18471991Sheppo 
18482109Slm66018 	do {
18492109Slm66018 		rv = ldc_up(ldcp->ldc_handle);
18502109Slm66018 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
18512109Slm66018 			DBG2((vnetp,
18522109Slm66018 			    "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
18532109Slm66018 			    ldcp->ldc_id, rv));
18542109Slm66018 			drv_usecwait(VGEN_LDC_UP_DELAY);
18552109Slm66018 		}
18562109Slm66018 		if (retries++ >= vgen_ldcup_retries)
18572109Slm66018 			break;
18582109Slm66018 	} while (rv == EWOULDBLOCK);
18591991Sheppo 
18601991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
18611991Sheppo 	if (istatus != LDC_UP) {
18621991Sheppo 		DBG2((vnetp, "vgen_ldcinit: id(%lx) status(%d) is not UP\n",
18631991Sheppo 		    ldcp->ldc_id, istatus));
18641991Sheppo 	}
18651991Sheppo 	ldcp->ldc_status = istatus;
18661991Sheppo 
18671991Sheppo 	/* initialize transmit watchdog timeout */
18681991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
18691991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
18701991Sheppo 
18711991Sheppo 	ldcp->flags |= CHANNEL_STARTED;
18721991Sheppo 
18731991Sheppo 	LDC_UNLOCK(ldcp);
18741991Sheppo 	return (DDI_SUCCESS);
18751991Sheppo 
18761991Sheppo ldcinit_failed:
18771991Sheppo 	if (init_state & ST_dring_bind) {
18781991Sheppo 		(void) ldc_mem_dring_unbind(ldcp->tx_dhandle);
18791991Sheppo 	}
18801991Sheppo 	if (init_state & ST_init_tbufs) {
18811991Sheppo 		vgen_uninit_tbufs(ldcp);
18821991Sheppo 	}
18831991Sheppo 	if (init_state & ST_ldc_open) {
18841991Sheppo 		(void) ldc_close(ldcp->ldc_handle);
18851991Sheppo 	}
18861991Sheppo 	LDC_UNLOCK(ldcp);
18871991Sheppo 	return (DDI_FAILURE);
18881991Sheppo }
18891991Sheppo 
18901991Sheppo /* stop transmit/receive on the channel */
18911991Sheppo static void
18921991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
18931991Sheppo {
18941991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
18951991Sheppo 	int	rv;
18961991Sheppo 
18971991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id));
18981991Sheppo 	LDC_LOCK(ldcp);
18991991Sheppo 
19001991Sheppo 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
19011991Sheppo 		LDC_UNLOCK(ldcp);
19021991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED"
19031991Sheppo 		    " flag is not set\n", ldcp->ldc_id));
19041991Sheppo 		return;
19051991Sheppo 	}
19061991Sheppo 
19071991Sheppo 	/* disable further callbacks */
19081991Sheppo 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
19091991Sheppo 	if (rv != 0) {
19101991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id (%lx) "
19111991Sheppo 		    "ldc_set_cb_mode failed\n", ldcp->ldc_id));
19121991Sheppo 	}
19131991Sheppo 
19141991Sheppo 	/* clear handshake done bit and wait for pending tx and cb to finish */
19151991Sheppo 	ldcp->hphase &= ~(VH_DONE);
19161991Sheppo 	LDC_UNLOCK(ldcp);
19171991Sheppo 	drv_usecwait(1000);
19181991Sheppo 	LDC_LOCK(ldcp);
19191991Sheppo 
19201991Sheppo 	vgen_reset_hphase(ldcp);
19211991Sheppo 
19221991Sheppo 	/* reset transmit watchdog timeout */
19231991Sheppo 	if (ldcp->wd_tid) {
19241991Sheppo 		(void) untimeout(ldcp->wd_tid);
19251991Sheppo 		ldcp->wd_tid = 0;
19261991Sheppo 	}
19271991Sheppo 
19281991Sheppo 	/* unbind tx descriptor ring from the channel */
19291991Sheppo 	rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
19301991Sheppo 	if (rv != 0) {
19311991Sheppo 		DWARN((vnetp, "vgen_ldcuninit: ldc_mem_dring_unbind "
19321991Sheppo 		    "failed id(%lx)\n", ldcp->ldc_id));
19331991Sheppo 	}
19341991Sheppo 
19351991Sheppo 	vgen_uninit_tbufs(ldcp);
19361991Sheppo 
19371991Sheppo 	rv = ldc_close(ldcp->ldc_handle);
19381991Sheppo 	if (rv != 0) {
19391991Sheppo 		DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n",
19401991Sheppo 		    ldcp->ldc_id));
19411991Sheppo 	}
19421991Sheppo 	ldcp->ldc_status = LDC_INIT;
19431991Sheppo 	ldcp->flags &= ~(CHANNEL_STARTED);
19441991Sheppo 
19451991Sheppo 	LDC_UNLOCK(ldcp);
19461991Sheppo 
19471991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id));
19481991Sheppo }
19491991Sheppo 
19501991Sheppo /* Initialize the transmit buffer ring for the channel */
19511991Sheppo static int
19521991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp)
19531991Sheppo {
19541991Sheppo 	vgen_private_desc_t	*tbufp;
19551991Sheppo 	vnet_public_desc_t	*txdp;
19561991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
19571991Sheppo 	int 			i;
19581991Sheppo 	int 			rv;
19592109Slm66018 	caddr_t			datap = NULL;
19602109Slm66018 	int			ci;
19612109Slm66018 	uint32_t		ncookies;
19621991Sheppo 
19631991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
19641991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
19651991Sheppo 
1966*2336Snarayan 	datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP);
19672109Slm66018 	ldcp->tx_datap = datap;
19682109Slm66018 
19691991Sheppo 	/*
19702109Slm66018 	 * for each private descriptor, allocate a ldc mem_handle which is
19711991Sheppo 	 * required to map the data during transmit, set the flags
19721991Sheppo 	 * to free (available for use by transmit routine).
19731991Sheppo 	 */
19741991Sheppo 
19751991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
19762109Slm66018 
19771991Sheppo 		tbufp = &(ldcp->tbufp[i]);
19781991Sheppo 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
19791991Sheppo 			&(tbufp->memhandle));
19801991Sheppo 		if (rv) {
19811991Sheppo 			tbufp->memhandle = 0;
19821991Sheppo 			goto init_tbufs_failed;
19831991Sheppo 		}
19842109Slm66018 
19852109Slm66018 		/*
19862109Slm66018 		 * bind ldc memhandle to the corresponding transmit buffer.
19872109Slm66018 		 */
19882109Slm66018 		ci = ncookies = 0;
19892109Slm66018 		rv = ldc_mem_bind_handle(tbufp->memhandle,
1990*2336Snarayan 		    (caddr_t)datap, VGEN_DBLK_SZ, LDC_SHADOW_MAP,
19912109Slm66018 		    LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
19922109Slm66018 		if (rv != 0) {
19932109Slm66018 			goto init_tbufs_failed;
19942109Slm66018 		}
19952109Slm66018 
19962109Slm66018 		/*
19972109Slm66018 		 * successful in binding the handle to tx data buffer.
19982109Slm66018 		 * set datap in the private descr to this buffer.
19992109Slm66018 		 */
20002109Slm66018 		tbufp->datap = datap;
20012109Slm66018 
20022109Slm66018 		if ((ncookies == 0) ||
2003*2336Snarayan 			(ncookies > MAX_COOKIES)) {
20042109Slm66018 			goto init_tbufs_failed;
20052109Slm66018 		}
20062109Slm66018 
20072109Slm66018 		for (ci = 1; ci < ncookies; ci++) {
20082109Slm66018 			rv = ldc_mem_nextcookie(tbufp->memhandle,
2009*2336Snarayan 				&(tbufp->memcookie[ci]));
20102109Slm66018 			if (rv != 0) {
20112109Slm66018 				goto init_tbufs_failed;
20122109Slm66018 			}
20132109Slm66018 		}
20142109Slm66018 
20152109Slm66018 		tbufp->ncookies = ncookies;
2016*2336Snarayan 		datap += VGEN_DBLK_SZ;
20172109Slm66018 
20181991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
20191991Sheppo 		txdp = &(ldcp->txdp[i]);
20201991Sheppo 		hdrp = &txdp->hdr;
20211991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
20221991Sheppo 		hdrp->ack = B_FALSE;
20231991Sheppo 		tbufp->descp = txdp;
20242109Slm66018 
20251991Sheppo 	}
20261991Sheppo 
20271991Sheppo 	/* reset tbuf walking pointers */
20281991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
20291991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
20301991Sheppo 
20311991Sheppo 	/* initialize tx seqnum and index */
20321991Sheppo 	ldcp->next_txseq = VNET_ISS;
20331991Sheppo 	ldcp->next_txi = 0;
20341991Sheppo 
2035*2336Snarayan 	ldcp->resched_peer = B_TRUE;
2036*2336Snarayan 
20371991Sheppo 	return (DDI_SUCCESS);
20381991Sheppo 
20391991Sheppo init_tbufs_failed:;
20401991Sheppo 	vgen_uninit_tbufs(ldcp);
20411991Sheppo 	return (DDI_FAILURE);
20421991Sheppo }
20431991Sheppo 
20441991Sheppo /* Uninitialize transmit buffer ring for the channel */
20451991Sheppo static void
20461991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp)
20471991Sheppo {
20481991Sheppo 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
20491991Sheppo 	vnet_public_desc_t	*txdp;
20501991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
20511991Sheppo 	int 			i;
20521991Sheppo 
20531991Sheppo 	/* for each tbuf (priv_desc), free ldc mem_handle */
20541991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
20551991Sheppo 
20561991Sheppo 		tbufp = &(ldcp->tbufp[i]);
20571991Sheppo 		txdp = tbufp->descp;
20581991Sheppo 		hdrp = &txdp->hdr;
20591991Sheppo 
20602109Slm66018 		if (tbufp->datap) { /* if bound to a ldc memhandle */
20611991Sheppo 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
20622109Slm66018 			tbufp->datap = NULL;
20631991Sheppo 		}
20642109Slm66018 		tbufp->flags = VGEN_PRIV_DESC_FREE;
20652109Slm66018 		hdrp->dstate = VIO_DESC_FREE;
20662109Slm66018 		hdrp->ack = B_FALSE;
20671991Sheppo 		if (tbufp->memhandle) {
20681991Sheppo 			(void) ldc_mem_free_handle(tbufp->memhandle);
20691991Sheppo 			tbufp->memhandle = 0;
20701991Sheppo 		}
20711991Sheppo 		tbufp->descp = NULL;
20721991Sheppo 	}
20731991Sheppo 
20742109Slm66018 	if (ldcp->tx_datap) {
20752109Slm66018 		/* prealloc'd tx data buffer */
2076*2336Snarayan 		kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ);
20772109Slm66018 		ldcp->tx_datap = NULL;
20782109Slm66018 	}
20792109Slm66018 
20801991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
20811991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
20821991Sheppo }
20831991Sheppo 
20841991Sheppo /* clobber tx descriptor ring */
20851991Sheppo static void
20861991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp)
20871991Sheppo {
20881991Sheppo 	vnet_public_desc_t	*txdp;
20891991Sheppo 	vgen_private_desc_t	*tbufp;
20901991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
20911991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
20921991Sheppo 	int i;
20931991Sheppo #ifdef DEBUG
20941991Sheppo 	int ndone = 0;
20951991Sheppo #endif
20961991Sheppo 
20971991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
20981991Sheppo 
20991991Sheppo 		tbufp = &(ldcp->tbufp[i]);
21001991Sheppo 		txdp = tbufp->descp;
21011991Sheppo 		hdrp = &txdp->hdr;
21021991Sheppo 
21031991Sheppo 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
21041991Sheppo 			tbufp->flags = VGEN_PRIV_DESC_FREE;
21051991Sheppo #ifdef DEBUG
21061991Sheppo 			if (hdrp->dstate == VIO_DESC_DONE)
21071991Sheppo 				ndone++;
21081991Sheppo #endif
21091991Sheppo 			hdrp->dstate = VIO_DESC_FREE;
21101991Sheppo 			hdrp->ack = B_FALSE;
21111991Sheppo 		}
21121991Sheppo 	}
21131991Sheppo 	/* reset tbuf walking pointers */
21141991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
21151991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
21161991Sheppo 
21171991Sheppo 	/* reset tx seqnum and index */
21181991Sheppo 	ldcp->next_txseq = VNET_ISS;
21191991Sheppo 	ldcp->next_txi = 0;
2120*2336Snarayan 
2121*2336Snarayan 	ldcp->resched_peer = B_TRUE;
2122*2336Snarayan 
21231991Sheppo #ifdef DEBUG
21241991Sheppo 	DBG2((vnetp,
21251991Sheppo 	    "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
21261991Sheppo 	    ldcp->ldc_id, ndone));
21271991Sheppo #endif
21281991Sheppo }
21291991Sheppo 
21301991Sheppo /* clobber receive descriptor ring */
21311991Sheppo static void
21321991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp)
21331991Sheppo {
21341991Sheppo 	ldcp->rx_dhandle = 0;
21351991Sheppo 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
21361991Sheppo 	ldcp->rxdp = NULL;
21371991Sheppo 	ldcp->next_rxi = 0;
21381991Sheppo 	ldcp->num_rxds = 0;
21391991Sheppo 	ldcp->next_rxseq = VNET_ISS;
21401991Sheppo }
21411991Sheppo 
21421991Sheppo /* initialize receive descriptor ring */
21431991Sheppo static int
21441991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
21451991Sheppo 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
21461991Sheppo {
21471991Sheppo 	int rv;
21481991Sheppo 	ldc_mem_info_t minfo;
21491991Sheppo 
21501991Sheppo 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
21511991Sheppo 	    desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle));
21521991Sheppo 	if (rv != 0) {
21531991Sheppo 		return (DDI_FAILURE);
21541991Sheppo 	}
21551991Sheppo 
21561991Sheppo 	/*
21571991Sheppo 	 * sucessfully mapped, now try to
21581991Sheppo 	 * get info about the mapped dring
21591991Sheppo 	 */
21601991Sheppo 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
21611991Sheppo 	if (rv != 0) {
21621991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
21631991Sheppo 		return (DDI_FAILURE);
21641991Sheppo 	}
21651991Sheppo 
21661991Sheppo 	/*
21671991Sheppo 	 * save ring address, number of descriptors.
21681991Sheppo 	 */
21691991Sheppo 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
21701991Sheppo 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
21711991Sheppo 	ldcp->num_rxdcookies = ncookies;
21721991Sheppo 	ldcp->num_rxds = num_desc;
21731991Sheppo 	ldcp->next_rxi = 0;
21741991Sheppo 	ldcp->next_rxseq = VNET_ISS;
21751991Sheppo 
21761991Sheppo 	return (DDI_SUCCESS);
21771991Sheppo }
21781991Sheppo 
21791991Sheppo /* get channel statistics */
21801991Sheppo static uint64_t
21812311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
21821991Sheppo {
21831991Sheppo 	vgen_stats_t *statsp;
21841991Sheppo 	uint64_t val;
21851991Sheppo 
21861991Sheppo 	val = 0;
21871991Sheppo 	statsp = ldcp->statsp;
21881991Sheppo 	switch (stat) {
21891991Sheppo 
21901991Sheppo 	case MAC_STAT_MULTIRCV:
21911991Sheppo 		val = statsp->multircv;
21921991Sheppo 		break;
21931991Sheppo 
21941991Sheppo 	case MAC_STAT_BRDCSTRCV:
21951991Sheppo 		val = statsp->brdcstrcv;
21961991Sheppo 		break;
21971991Sheppo 
21981991Sheppo 	case MAC_STAT_MULTIXMT:
21991991Sheppo 		val = statsp->multixmt;
22001991Sheppo 		break;
22011991Sheppo 
22021991Sheppo 	case MAC_STAT_BRDCSTXMT:
22031991Sheppo 		val = statsp->brdcstxmt;
22041991Sheppo 		break;
22051991Sheppo 
22061991Sheppo 	case MAC_STAT_NORCVBUF:
22071991Sheppo 		val = statsp->norcvbuf;
22081991Sheppo 		break;
22091991Sheppo 
22101991Sheppo 	case MAC_STAT_IERRORS:
22111991Sheppo 		val = statsp->ierrors;
22121991Sheppo 		break;
22131991Sheppo 
22141991Sheppo 	case MAC_STAT_NOXMTBUF:
22151991Sheppo 		val = statsp->noxmtbuf;
22161991Sheppo 		break;
22171991Sheppo 
22181991Sheppo 	case MAC_STAT_OERRORS:
22191991Sheppo 		val = statsp->oerrors;
22201991Sheppo 		break;
22211991Sheppo 
22221991Sheppo 	case MAC_STAT_COLLISIONS:
22231991Sheppo 		break;
22241991Sheppo 
22251991Sheppo 	case MAC_STAT_RBYTES:
22261991Sheppo 		val = statsp->rbytes;
22271991Sheppo 		break;
22281991Sheppo 
22291991Sheppo 	case MAC_STAT_IPACKETS:
22301991Sheppo 		val = statsp->ipackets;
22311991Sheppo 		break;
22321991Sheppo 
22331991Sheppo 	case MAC_STAT_OBYTES:
22341991Sheppo 		val = statsp->obytes;
22351991Sheppo 		break;
22361991Sheppo 
22371991Sheppo 	case MAC_STAT_OPACKETS:
22381991Sheppo 		val = statsp->opackets;
22391991Sheppo 		break;
22401991Sheppo 
22411991Sheppo 	/* stats not relevant to ldc, return 0 */
22421991Sheppo 	case MAC_STAT_IFSPEED:
22432311Sseb 	case ETHER_STAT_ALIGN_ERRORS:
22442311Sseb 	case ETHER_STAT_FCS_ERRORS:
22452311Sseb 	case ETHER_STAT_FIRST_COLLISIONS:
22462311Sseb 	case ETHER_STAT_MULTI_COLLISIONS:
22472311Sseb 	case ETHER_STAT_DEFER_XMTS:
22482311Sseb 	case ETHER_STAT_TX_LATE_COLLISIONS:
22492311Sseb 	case ETHER_STAT_EX_COLLISIONS:
22502311Sseb 	case ETHER_STAT_MACXMT_ERRORS:
22512311Sseb 	case ETHER_STAT_CARRIER_ERRORS:
22522311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
22532311Sseb 	case ETHER_STAT_XCVR_ADDR:
22542311Sseb 	case ETHER_STAT_XCVR_ID:
22552311Sseb 	case ETHER_STAT_XCVR_INUSE:
22562311Sseb 	case ETHER_STAT_CAP_1000FDX:
22572311Sseb 	case ETHER_STAT_CAP_1000HDX:
22582311Sseb 	case ETHER_STAT_CAP_100FDX:
22592311Sseb 	case ETHER_STAT_CAP_100HDX:
22602311Sseb 	case ETHER_STAT_CAP_10FDX:
22612311Sseb 	case ETHER_STAT_CAP_10HDX:
22622311Sseb 	case ETHER_STAT_CAP_ASMPAUSE:
22632311Sseb 	case ETHER_STAT_CAP_PAUSE:
22642311Sseb 	case ETHER_STAT_CAP_AUTONEG:
22652311Sseb 	case ETHER_STAT_ADV_CAP_1000FDX:
22662311Sseb 	case ETHER_STAT_ADV_CAP_1000HDX:
22672311Sseb 	case ETHER_STAT_ADV_CAP_100FDX:
22682311Sseb 	case ETHER_STAT_ADV_CAP_100HDX:
22692311Sseb 	case ETHER_STAT_ADV_CAP_10FDX:
22702311Sseb 	case ETHER_STAT_ADV_CAP_10HDX:
22712311Sseb 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
22722311Sseb 	case ETHER_STAT_ADV_CAP_PAUSE:
22732311Sseb 	case ETHER_STAT_ADV_CAP_AUTONEG:
22742311Sseb 	case ETHER_STAT_LP_CAP_1000FDX:
22752311Sseb 	case ETHER_STAT_LP_CAP_1000HDX:
22762311Sseb 	case ETHER_STAT_LP_CAP_100FDX:
22772311Sseb 	case ETHER_STAT_LP_CAP_100HDX:
22782311Sseb 	case ETHER_STAT_LP_CAP_10FDX:
22792311Sseb 	case ETHER_STAT_LP_CAP_10HDX:
22802311Sseb 	case ETHER_STAT_LP_CAP_ASMPAUSE:
22812311Sseb 	case ETHER_STAT_LP_CAP_PAUSE:
22822311Sseb 	case ETHER_STAT_LP_CAP_AUTONEG:
22832311Sseb 	case ETHER_STAT_LINK_ASMPAUSE:
22842311Sseb 	case ETHER_STAT_LINK_PAUSE:
22852311Sseb 	case ETHER_STAT_LINK_AUTONEG:
22862311Sseb 	case ETHER_STAT_LINK_DUPLEX:
22871991Sheppo 	default:
22881991Sheppo 		val = 0;
22891991Sheppo 		break;
22901991Sheppo 
22911991Sheppo 	}
22921991Sheppo 	return (val);
22931991Sheppo }
22941991Sheppo 
22951991Sheppo /* Interrupt handler for the channel */
22961991Sheppo static uint_t
22971991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
22981991Sheppo {
22991991Sheppo 	_NOTE(ARGUNUSED(event))
23001991Sheppo 	vgen_ldc_t	*ldcp;
23011991Sheppo 	void 		*vnetp;
23021991Sheppo 	vgen_t		*vgenp;
23031991Sheppo 	size_t		msglen;
23041991Sheppo 	ldc_status_t 	istatus;
23051991Sheppo 	uint64_t	ldcmsg[7];
23061991Sheppo 	int 		rv;
23071991Sheppo 	vio_msg_tag_t	*tagp;
23081991Sheppo 	mblk_t		*mp = NULL;
23091991Sheppo 	mblk_t		*bp = NULL;
23101991Sheppo 	mblk_t		*bpt = NULL;
23111991Sheppo 	mblk_t		*headp = NULL;
23121991Sheppo 	mblk_t		*tailp = NULL;
23131991Sheppo 	vgen_stats_t	*statsp;
23141991Sheppo 
23151991Sheppo 	ldcp = (vgen_ldc_t *)arg;
23161991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
23171991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
23181991Sheppo 	statsp = ldcp->statsp;
23191991Sheppo 
23201991Sheppo 	DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id));
23211991Sheppo 
23221991Sheppo 	mutex_enter(&ldcp->cblock);
23231991Sheppo 	statsp->callbacks++;
23241991Sheppo 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
23251991Sheppo 		DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
23261991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
23271991Sheppo 		mutex_exit(&ldcp->cblock);
23281991Sheppo 		return (LDC_SUCCESS);
23291991Sheppo 	}
23301991Sheppo 
23311991Sheppo 	/* check ldc status change events first */
23321991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
23331991Sheppo 
23341991Sheppo 	if (istatus != ldcp->ldc_status) {
23351991Sheppo 		switch (istatus) {
23361991Sheppo 		case LDC_UP:
23371991Sheppo 			ldcp->ldc_status = istatus;
23381991Sheppo 			DBG1((vnetp,
23391991Sheppo 			    "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n",
23401991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
23411991Sheppo 
23421991Sheppo 			if (ldcp->portp != vgenp->vsw_portp) {
23431991Sheppo 				/*
23441991Sheppo 				 * modify fdb entry to use this port as the
23451991Sheppo 				 * channel is up, instead of going through the
23461991Sheppo 				 * vsw-port (see comments in vgen_port_init())
23471991Sheppo 				 */
23481991Sheppo 				vnet_modify_fdb(vnetp,
23491991Sheppo 				    (uint8_t *)&ldcp->portp->macaddr,
23501991Sheppo 				    vgen_tx, ldcp->portp);
23511991Sheppo 			}
23521991Sheppo 			/* Initialize local session id */
23531991Sheppo 			ldcp->local_sid = ddi_get_lbolt();
23541991Sheppo 			/* clear peer session id */
23551991Sheppo 			ldcp->peer_sid = 0;
23561991Sheppo 			ldcp->hretries = 0;
23571991Sheppo 			/* Initiate Handshake process with peer ldc endpoint */
23581991Sheppo 			vgen_handshake_reset(ldcp);
23591991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
23601991Sheppo 			break;
23611991Sheppo 
23621991Sheppo 		case LDC_OPEN:
23631991Sheppo 		case LDC_READY:
23641991Sheppo 			ldcp->ldc_status = istatus;
23651991Sheppo 			if ((ldcp->portp != vgenp->vsw_portp) &&
23661991Sheppo 				(vgenp->vsw_portp != NULL)) {
23671991Sheppo 				/*
23681991Sheppo 				 * modify fdb entry to use vsw-port  as the
23691991Sheppo 				 * channel is reset and we don't have a direct
23701991Sheppo 				 * link to the destination (see comments
23711991Sheppo 				 * in vgen_port_init()).
23721991Sheppo 				 */
23731991Sheppo 				vnet_modify_fdb(vnetp,
23741991Sheppo 				    (uint8_t *)&ldcp->portp->macaddr,
23751991Sheppo 				    vgen_tx, vgenp->vsw_portp);
23761991Sheppo 			}
23771991Sheppo 			/* clear sids */
23781991Sheppo 			ldcp->local_sid = 0;
23791991Sheppo 			ldcp->peer_sid = 0;
23801991Sheppo 			if (ldcp->hphase != VH_PHASE0) {
23811991Sheppo 				vgen_handshake_reset(ldcp);
23821991Sheppo 			}
23831991Sheppo 			DBG1((vnetp,
23841991Sheppo 			    "vgen_ldc_cb: id(%lx) status is (%d)\n",
23851991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
23861991Sheppo 			break;
23871991Sheppo 
23881991Sheppo 		default:
23891991Sheppo 			DWARN((vnetp,
23901991Sheppo 			    "vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is"
23911991Sheppo 			    " *UNKNOWN*\n",
23921991Sheppo 			    ldcp->ldc_id, istatus, ldcp->ldc_status));
23931991Sheppo 			break;
23941991Sheppo 		}
23951991Sheppo 	}
23961991Sheppo 
23971991Sheppo 	if (istatus != LDC_UP) {
23981991Sheppo 		DBG1((vnetp, "vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n",
23991991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
24001991Sheppo 		mutex_exit(&ldcp->cblock);
24011991Sheppo 		return (LDC_SUCCESS);
24021991Sheppo 	}
24031991Sheppo 
24041991Sheppo 	/* if ldc_status is UP, receive all packets */
24051991Sheppo 	do {
24061991Sheppo 		msglen = sizeof (ldcmsg);
24071991Sheppo 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
24081991Sheppo 
24091991Sheppo 		if (rv != 0) {
24101991Sheppo 			DWARN((vnetp,
24111991Sheppo 			    "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) "
24121991Sheppo 			    "len(%d)\n", ldcp->ldc_id, rv, msglen));
24131991Sheppo 			break;
24141991Sheppo 		}
24151991Sheppo 		if (msglen == 0) {
24161991Sheppo 			DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA",
24171991Sheppo 			ldcp->ldc_id));
24181991Sheppo 			break;
24191991Sheppo 		}
24201991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
24211991Sheppo 		    ldcp->ldc_id, msglen));
24221991Sheppo 
24231991Sheppo 		tagp = (vio_msg_tag_t *)ldcmsg;
24241991Sheppo 
24251991Sheppo 		if (ldcp->peer_sid) {
24261991Sheppo 			/*
24271991Sheppo 			 * check sid only after we have received peer's sid
24281991Sheppo 			 * in the version negotiate msg.
24291991Sheppo 			 */
24301991Sheppo #ifdef DEBUG
24311991Sheppo 			if (vgen_hdbg & HDBG_BAD_SID) {
24321991Sheppo 				/* simulate bad sid condition */
24331991Sheppo 				tagp->vio_sid = 0;
24341991Sheppo 				vgen_hdbg &= ~(HDBG_BAD_SID);
24351991Sheppo 			}
24361991Sheppo #endif
24371991Sheppo 			if (vgen_check_sid(ldcp, tagp) == VGEN_FAILURE) {
24381991Sheppo 				/*
24391991Sheppo 				 * If sid mismatch is detected,
24401991Sheppo 				 * reset the channel.
24411991Sheppo 				 */
24421991Sheppo 				ldcp->need_ldc_reset = B_TRUE;
24431991Sheppo 				vgen_handshake_reset(ldcp);
24441991Sheppo 				mutex_exit(&ldcp->cblock);
24451991Sheppo 				return (LDC_SUCCESS);
24461991Sheppo 			}
24471991Sheppo 		}
24481991Sheppo 
24491991Sheppo 		switch (tagp->vio_msgtype) {
24501991Sheppo 		case VIO_TYPE_CTRL:
24511991Sheppo 			vgen_handle_ctrlmsg(ldcp, tagp);
24521991Sheppo 			break;
24531991Sheppo 
24541991Sheppo 		case VIO_TYPE_DATA:
24551991Sheppo 			headp = tailp = NULL;
24561991Sheppo 			vgen_handle_datamsg(ldcp, tagp, &headp, &tailp);
24571991Sheppo 			/* build a chain of received packets */
24581991Sheppo 			if (headp != NULL) {
24591991Sheppo 				if (bp == NULL) {
24601991Sheppo 					bp = headp;
24611991Sheppo 					bpt = tailp;
24621991Sheppo 				} else {
24631991Sheppo 					bpt->b_next = headp;
24641991Sheppo 					bpt = tailp;
24651991Sheppo 				}
24661991Sheppo 			}
24671991Sheppo 			break;
24681991Sheppo 
24691991Sheppo 		case VIO_TYPE_ERR:
24701991Sheppo 			vgen_handle_errmsg(ldcp, tagp);
24711991Sheppo 			break;
24721991Sheppo 
24731991Sheppo 		default:
24741991Sheppo 			DWARN((vnetp,
24751991Sheppo 			    "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
24761991Sheppo 			    tagp->vio_msgtype));
24771991Sheppo 			break;
24781991Sheppo 		}
24791991Sheppo 
24801991Sheppo 	} while (msglen);
24811991Sheppo 
24821991Sheppo 	mutex_exit(&ldcp->cblock);
24831991Sheppo 	/* send up the received packets to MAC layer */
24841991Sheppo 	while (bp != NULL) {
24851991Sheppo 		mp = bp;
24861991Sheppo 		bp = bp->b_next;
24871991Sheppo 		mp->b_next = mp->b_prev = NULL;
24881991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
24891991Sheppo 		    ldcp->ldc_id, MBLKL(mp)));
24902311Sseb 		vnet_rx(vgenp->vnetp, NULL, mp);
24911991Sheppo 	}
24921991Sheppo 	DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id));
24931991Sheppo 
24941991Sheppo 	return (LDC_SUCCESS);
24951991Sheppo }
24961991Sheppo 
24971991Sheppo /* vgen handshake functions */
24981991Sheppo 
24991991Sheppo /* change the hphase for the channel to the next phase */
25001991Sheppo static vgen_ldc_t *
25011991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
25021991Sheppo {
25031991Sheppo 	if (ldcp->hphase == VH_PHASE3) {
25041991Sheppo 		ldcp->hphase = VH_DONE;
25051991Sheppo 	} else {
25061991Sheppo 		ldcp->hphase++;
25071991Sheppo 	}
25081991Sheppo 	return (ldcp);
25091991Sheppo }
25101991Sheppo 
25111991Sheppo /*
25121991Sheppo  * Check whether the given version is supported or not and
25131991Sheppo  * return VGEN_SUCCESS if supported.
25141991Sheppo  */
25151991Sheppo static int
25161991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
25171991Sheppo uint16_t ver_minor)
25181991Sheppo {
25191991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
25201991Sheppo 	int		i = 0;
25211991Sheppo 
25221991Sheppo 	while (i < VGEN_NUM_VER) {
25231991Sheppo 		if ((versions[i].ver_major == 0) &&
25241991Sheppo 		    (versions[i].ver_minor == 0)) {
25251991Sheppo 			break;
25261991Sheppo 		}
25271991Sheppo 		if ((versions[i].ver_major == ver_major) &&
25281991Sheppo 			(versions[i].ver_minor == ver_minor)) {
25291991Sheppo 			return (VGEN_SUCCESS);
25301991Sheppo 		}
25311991Sheppo 		i++;
25321991Sheppo 	}
25331991Sheppo 	return (VGEN_FAILURE);
25341991Sheppo }
25351991Sheppo 
25361991Sheppo /*
25371991Sheppo  * Given a version, return VGEN_SUCCESS if a lower version is supported.
25381991Sheppo  */
25391991Sheppo static int
25401991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp)
25411991Sheppo {
25421991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
25431991Sheppo 	int		i = 0;
25441991Sheppo 
25451991Sheppo 	while (i < VGEN_NUM_VER) {
25461991Sheppo 		if ((versions[i].ver_major == 0) &&
25471991Sheppo 		    (versions[i].ver_minor == 0)) {
25481991Sheppo 			break;
25491991Sheppo 		}
25501991Sheppo 		/*
25511991Sheppo 		 * if we support a lower minor version within the same major
25521991Sheppo 		 * version, or if we support a lower major version,
25531991Sheppo 		 * update the verp parameter with this lower version and
25541991Sheppo 		 * return success.
25551991Sheppo 		 */
25561991Sheppo 		if (((versions[i].ver_major == verp->ver_major) &&
25571991Sheppo 			(versions[i].ver_minor < verp->ver_minor)) ||
25581991Sheppo 			(versions[i].ver_major < verp->ver_major)) {
25591991Sheppo 				verp->ver_major = versions[i].ver_major;
25601991Sheppo 				verp->ver_minor = versions[i].ver_minor;
25611991Sheppo 				return (VGEN_SUCCESS);
25621991Sheppo 		}
25631991Sheppo 		i++;
25641991Sheppo 	}
25651991Sheppo 
25661991Sheppo 	return (VGEN_FAILURE);
25671991Sheppo }
25681991Sheppo 
25691991Sheppo /*
25701991Sheppo  * wrapper routine to send the given message over ldc using ldc_write().
25711991Sheppo  */
25721991Sheppo static int
25731991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
25741991Sheppo     boolean_t caller_holds_lock)
25751991Sheppo {
25761991Sheppo 	int	rv;
25771991Sheppo 	size_t	len;
25781991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
25791991Sheppo 	uint32_t retries = 0;
25801991Sheppo 
25811991Sheppo 	len = msglen;
25821991Sheppo 	if ((len == 0) || (msg == NULL))
25831991Sheppo 		return (VGEN_FAILURE);
25841991Sheppo 
25851991Sheppo 	if (!caller_holds_lock) {
25861991Sheppo 		mutex_enter(&ldcp->txlock);
25871991Sheppo 	}
25881991Sheppo 
25891991Sheppo 	do {
25901991Sheppo 		len = msglen;
25911991Sheppo 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
25921991Sheppo 		if (retries++ >= vgen_ldcwr_retries)
25931991Sheppo 			break;
25941991Sheppo 	} while (rv == EWOULDBLOCK);
25951991Sheppo 
25961991Sheppo 	if (!caller_holds_lock) {
25971991Sheppo 		mutex_exit(&ldcp->txlock);
25981991Sheppo 	}
25991991Sheppo 
26001991Sheppo 	if ((rv != 0) || (len != msglen)) {
26011991Sheppo 		DWARN((vnetp,
26021991Sheppo 		    "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)"
26031991Sheppo 		    " msglen (%d)\n", ldcp->ldc_id, rv, msglen));
26041991Sheppo 		return (VGEN_FAILURE);
26051991Sheppo 	}
26061991Sheppo 	return (VGEN_SUCCESS);
26071991Sheppo }
26081991Sheppo 
26091991Sheppo /* send version negotiate message to the peer over ldc */
26101991Sheppo static int
26111991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
26121991Sheppo {
26131991Sheppo 	vio_ver_msg_t	vermsg;
26141991Sheppo 	vio_msg_tag_t	*tagp = &vermsg.tag;
26151991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
26161991Sheppo 	int		rv;
26171991Sheppo 
26181991Sheppo 	bzero(&vermsg, sizeof (vermsg));
26191991Sheppo 
26201991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
26211991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
26221991Sheppo 	tagp->vio_subtype_env = VIO_VER_INFO;
26231991Sheppo 	tagp->vio_sid = ldcp->local_sid;
26241991Sheppo 
26251991Sheppo 	/* get version msg payload from ldcp->local */
26261991Sheppo 	vermsg.ver_major = ldcp->local_hparams.ver_major;
26271991Sheppo 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
26281991Sheppo 	vermsg.dev_class = ldcp->local_hparams.dev_class;
26291991Sheppo 
26301991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
26311991Sheppo 	if (rv != VGEN_SUCCESS) {
26321991Sheppo 		DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed"
26331991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
26341991Sheppo 		return (VGEN_FAILURE);
26351991Sheppo 	}
26361991Sheppo 
26371991Sheppo 	ldcp->hstate |= VER_INFO_SENT;
26381991Sheppo 	DBG2((vnetp,
26391991Sheppo 	    "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
26401991Sheppo 	    ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor));
26411991Sheppo 
26421991Sheppo 	return (VGEN_SUCCESS);
26431991Sheppo }
26441991Sheppo 
26451991Sheppo /* send attr info message to the peer over ldc */
26461991Sheppo static int
26471991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
26481991Sheppo {
26491991Sheppo 	vnet_attr_msg_t	attrmsg;
26501991Sheppo 	vio_msg_tag_t	*tagp = &attrmsg.tag;
26511991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
26521991Sheppo 	int		rv;
26531991Sheppo 
26541991Sheppo 	bzero(&attrmsg, sizeof (attrmsg));
26551991Sheppo 
26561991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
26571991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
26581991Sheppo 	tagp->vio_subtype_env = VIO_ATTR_INFO;
26591991Sheppo 	tagp->vio_sid = ldcp->local_sid;
26601991Sheppo 
26611991Sheppo 	/* get attr msg payload from ldcp->local */
26621991Sheppo 	attrmsg.mtu = ldcp->local_hparams.mtu;
26631991Sheppo 	attrmsg.addr = ldcp->local_hparams.addr;
26641991Sheppo 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
26651991Sheppo 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
26661991Sheppo 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
26671991Sheppo 
26681991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
26691991Sheppo 	if (rv != VGEN_SUCCESS) {
26701991Sheppo 		DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed"
26711991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
26721991Sheppo 		return (VGEN_FAILURE);
26731991Sheppo 	}
26741991Sheppo 
26751991Sheppo 	ldcp->hstate |= ATTR_INFO_SENT;
26761991Sheppo 	DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
26771991Sheppo 	    ldcp->ldc_id));
26781991Sheppo 
26791991Sheppo 	return (VGEN_SUCCESS);
26801991Sheppo }
26811991Sheppo 
26821991Sheppo /* send descriptor ring register message to the peer over ldc */
26831991Sheppo static int
26841991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp)
26851991Sheppo {
26861991Sheppo 	vio_dring_reg_msg_t	msg;
26871991Sheppo 	vio_msg_tag_t		*tagp = &msg.tag;
26881991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
26891991Sheppo 	int		rv;
26901991Sheppo 
26911991Sheppo 	bzero(&msg, sizeof (msg));
26921991Sheppo 
26931991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
26941991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
26951991Sheppo 	tagp->vio_subtype_env = VIO_DRING_REG;
26961991Sheppo 	tagp->vio_sid = ldcp->local_sid;
26971991Sheppo 
26981991Sheppo 	/* get dring info msg payload from ldcp->local */
26991991Sheppo 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
27001991Sheppo 		sizeof (ldc_mem_cookie_t));
27011991Sheppo 	msg.ncookies = ldcp->local_hparams.num_dcookies;
27021991Sheppo 	msg.num_descriptors = ldcp->local_hparams.num_desc;
27031991Sheppo 	msg.descriptor_size = ldcp->local_hparams.desc_size;
27041991Sheppo 
27051991Sheppo 	/*
27061991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
27071991Sheppo 	 * value and sends it in the ack, which is saved in
27081991Sheppo 	 * vgen_handle_dring_reg().
27091991Sheppo 	 */
27101991Sheppo 	msg.dring_ident = 0;
27111991Sheppo 
27121991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
27131991Sheppo 	if (rv != VGEN_SUCCESS) {
27141991Sheppo 		DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed"
27151991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
27161991Sheppo 		return (VGEN_FAILURE);
27171991Sheppo 	}
27181991Sheppo 
27191991Sheppo 	ldcp->hstate |= DRING_INFO_SENT;
27201991Sheppo 	DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
27211991Sheppo 	    ldcp->ldc_id));
27221991Sheppo 
27231991Sheppo 	return (VGEN_SUCCESS);
27241991Sheppo }
27251991Sheppo 
27261991Sheppo static int
27271991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
27281991Sheppo {
27291991Sheppo 	vio_rdx_msg_t	rdxmsg;
27301991Sheppo 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
27311991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
27321991Sheppo 	int		rv;
27331991Sheppo 
27341991Sheppo 	bzero(&rdxmsg, sizeof (rdxmsg));
27351991Sheppo 
27361991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
27371991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
27381991Sheppo 	tagp->vio_subtype_env = VIO_RDX;
27391991Sheppo 	tagp->vio_sid = ldcp->local_sid;
27401991Sheppo 
27411991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
27421991Sheppo 	if (rv != VGEN_SUCCESS) {
27431991Sheppo 		DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed"
27441991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
27451991Sheppo 		return (VGEN_FAILURE);
27461991Sheppo 	}
27471991Sheppo 
27481991Sheppo 	ldcp->hstate |= RDX_INFO_SENT;
27491991Sheppo 	DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
27501991Sheppo 	    ldcp->ldc_id));
27511991Sheppo 
27521991Sheppo 	return (VGEN_SUCCESS);
27531991Sheppo }
27541991Sheppo 
27551991Sheppo /* send descriptor ring data message to the peer over ldc */
27561991Sheppo static int
2757*2336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
27581991Sheppo {
27591991Sheppo 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
27601991Sheppo 	vio_msg_tag_t	*tagp = &msgp->tag;
27611991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
27621991Sheppo 	int		rv;
27631991Sheppo 
27641991Sheppo 	bzero(msgp, sizeof (*msgp));
27651991Sheppo 
27661991Sheppo 	tagp->vio_msgtype = VIO_TYPE_DATA;
27671991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
27681991Sheppo 	tagp->vio_subtype_env = VIO_DRING_DATA;
27691991Sheppo 	tagp->vio_sid = ldcp->local_sid;
27701991Sheppo 
2771*2336Snarayan 	msgp->seq_num = ldcp->next_txseq;
27721991Sheppo 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
27731991Sheppo 	msgp->start_idx = start;
27741991Sheppo 	msgp->end_idx = end;
27751991Sheppo 
27761991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
27771991Sheppo 	if (rv != VGEN_SUCCESS) {
27781991Sheppo 		DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed"
27791991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
27801991Sheppo 		return (VGEN_FAILURE);
27811991Sheppo 	}
27821991Sheppo 
2783*2336Snarayan 	ldcp->next_txseq++;
2784*2336Snarayan 	ldcp->statsp->dring_data_msgs++;
2785*2336Snarayan 
27861991Sheppo 	DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
27871991Sheppo 	    ldcp->ldc_id));
27881991Sheppo 
27891991Sheppo 	return (VGEN_SUCCESS);
27901991Sheppo }
27911991Sheppo 
27921991Sheppo /* send multicast addr info message to vsw */
27931991Sheppo static int
27941991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
27951991Sheppo {
27961991Sheppo 	vnet_mcast_msg_t	mcastmsg;
27971991Sheppo 	vnet_mcast_msg_t	*msgp;
27981991Sheppo 	vio_msg_tag_t		*tagp;
27991991Sheppo 	vgen_t			*vgenp;
28001991Sheppo 	void			*vnetp;
28011991Sheppo 	struct ether_addr	*mca;
28021991Sheppo 	int			rv;
28031991Sheppo 	int			i;
28041991Sheppo 	uint32_t		size;
28051991Sheppo 	uint32_t		mccount;
28061991Sheppo 	uint32_t		n;
28071991Sheppo 
28081991Sheppo 	msgp = &mcastmsg;
28091991Sheppo 	tagp = &msgp->tag;
28101991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
28111991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
28121991Sheppo 
28131991Sheppo 	mccount = vgenp->mccount;
28141991Sheppo 	i = 0;
28151991Sheppo 
28161991Sheppo 	do {
28171991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
28181991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
28191991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
28201991Sheppo 		tagp->vio_sid = ldcp->local_sid;
28211991Sheppo 
28221991Sheppo 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
28231991Sheppo 		size = n * sizeof (struct ether_addr);
28241991Sheppo 
28251991Sheppo 		mca = &(vgenp->mctab[i]);
28261991Sheppo 		bcopy(mca, (msgp->mca), size);
28271991Sheppo 		msgp->set = B_TRUE;
28281991Sheppo 		msgp->count = n;
28291991Sheppo 
28301991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
28311991Sheppo 		    B_FALSE);
28321991Sheppo 		if (rv != VGEN_SUCCESS) {
28331991Sheppo 			DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err"
28341991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
28351991Sheppo 			return (VGEN_FAILURE);
28361991Sheppo 		}
28371991Sheppo 
28381991Sheppo 		mccount -= n;
28391991Sheppo 		i += n;
28401991Sheppo 
28411991Sheppo 	} while (mccount);
28421991Sheppo 
28431991Sheppo 	return (VGEN_SUCCESS);
28441991Sheppo }
28451991Sheppo 
28461991Sheppo /* Initiate Phase 2 of handshake */
28471991Sheppo static int
28481991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
28491991Sheppo {
28501991Sheppo 	int rv;
28511991Sheppo #ifdef DEBUG
28521991Sheppo 	if (vgen_hdbg & HDBG_OUT_STATE) {
28531991Sheppo 		/* simulate out of state condition */
28541991Sheppo 		vgen_hdbg &= ~(HDBG_OUT_STATE);
28551991Sheppo 		rv = vgen_send_rdx_info(ldcp);
28561991Sheppo 		return (rv);
28571991Sheppo 	}
28581991Sheppo 	if (vgen_hdbg & HDBG_TIMEOUT) {
28591991Sheppo 		/* simulate timeout condition */
28601991Sheppo 		vgen_hdbg &= ~(HDBG_TIMEOUT);
28611991Sheppo 		return (VGEN_SUCCESS);
28621991Sheppo 	}
28631991Sheppo #endif
28641991Sheppo 	if ((rv = vgen_send_attr_info(ldcp)) != VGEN_SUCCESS) {
28651991Sheppo 		return (rv);
28661991Sheppo 	}
28671991Sheppo 	if ((rv = vgen_send_dring_reg(ldcp)) != VGEN_SUCCESS) {
28681991Sheppo 		return (rv);
28691991Sheppo 	}
28701991Sheppo 
28711991Sheppo 	return (VGEN_SUCCESS);
28721991Sheppo }
28731991Sheppo 
28741991Sheppo /*
28751991Sheppo  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
28761991Sheppo  * This can happen after a channel comes up (status: LDC_UP) or
28771991Sheppo  * when handshake gets terminated due to various conditions.
28781991Sheppo  */
28791991Sheppo static void
28801991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp)
28811991Sheppo {
28821991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
28831991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
28841991Sheppo 	ldc_status_t istatus;
28851991Sheppo 
28861991Sheppo 	DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id));
28871991Sheppo 	/* reset hstate and hphase */
28881991Sheppo 	ldcp->hstate = 0;
28891991Sheppo 	ldcp->hphase = VH_PHASE0;
28901991Sheppo 
28911991Sheppo 	/* reset handshake watchdog timeout */
28921991Sheppo 	if (ldcp->htid) {
28931991Sheppo 		(void) untimeout(ldcp->htid);
28941991Sheppo 		ldcp->htid = 0;
28951991Sheppo 	}
28961991Sheppo 
28971991Sheppo 	/*
28981991Sheppo 	 * Unmap drings, if dring_ready is set.
28991991Sheppo 	 */
29001991Sheppo 	if (ldcp->local_hparams.dring_ready) {
29011991Sheppo 		ldcp->local_hparams.dring_ready = B_FALSE;
29021991Sheppo 		/* do not unbind our dring */
29031991Sheppo 	}
29041991Sheppo 
29051991Sheppo 	if (ldcp->peer_hparams.dring_ready) {
29061991Sheppo 		ldcp->peer_hparams.dring_ready = B_FALSE;
29071991Sheppo 		/* Unmap peer's dring */
29081991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
29091991Sheppo 		vgen_clobber_rxds(ldcp);
29101991Sheppo 	}
29111991Sheppo 
29121991Sheppo 	vgen_clobber_tbufs(ldcp);
29131991Sheppo 
29141991Sheppo 	/*
29151991Sheppo 	 * clear local handshake params and initialize.
29161991Sheppo 	 */
29171991Sheppo 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
29181991Sheppo 
29191991Sheppo 	/* set version to the highest version supported */
29201991Sheppo 	ldcp->local_hparams.ver_major =
29211991Sheppo 			ldcp->vgen_versions[0].ver_major;
29221991Sheppo 	ldcp->local_hparams.ver_minor =
29231991Sheppo 			ldcp->vgen_versions[0].ver_minor;
29241991Sheppo 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
29251991Sheppo 
29261991Sheppo 	/* set attr_info params */
29271991Sheppo 	ldcp->local_hparams.mtu = ETHERMAX;
29281991Sheppo 	ldcp->local_hparams.addr =
29291991Sheppo 		vgen_macaddr_strtoul(vgenp->macaddr);
29301991Sheppo 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
29311991Sheppo 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE;
29321991Sheppo 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
29331991Sheppo 
29341991Sheppo 	/*
29351991Sheppo 	 * set dring_info params.
29361991Sheppo 	 * Note: dring is already created and bound.
29371991Sheppo 	 */
29381991Sheppo 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
29391991Sheppo 		sizeof (ldc_mem_cookie_t));
29401991Sheppo 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
29411991Sheppo 	ldcp->local_hparams.num_desc = ldcp->num_txds;
29421991Sheppo 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
29431991Sheppo 
29441991Sheppo 	/*
29451991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
29461991Sheppo 	 * value and sends it in the ack, which is saved in
29471991Sheppo 	 * vgen_handle_dring_reg().
29481991Sheppo 	 */
29491991Sheppo 	ldcp->local_hparams.dring_ident = 0;
29501991Sheppo 
29511991Sheppo 	/* clear peer_hparams */
29521991Sheppo 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
29531991Sheppo 
29541991Sheppo 	/* reset the channel if required */
29551991Sheppo 	if (ldcp->need_ldc_reset) {
29561991Sheppo 		DWARN((vnetp,
29571991Sheppo 		    "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
29581991Sheppo 		    ldcp->ldc_id));
29591991Sheppo 		ldcp->need_ldc_reset = B_FALSE;
29601991Sheppo 		(void) ldc_reset(ldcp->ldc_handle);
29611991Sheppo 		(void) ldc_status(ldcp->ldc_handle, &istatus);
29621991Sheppo 		DBG2((vnetp,
29631991Sheppo 		    "vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n",
29641991Sheppo 		    ldcp->ldc_id, istatus));
29651991Sheppo 		ldcp->ldc_status = istatus;
29661991Sheppo 		/* clear sids */
29671991Sheppo 		ldcp->local_sid = 0;
29681991Sheppo 		ldcp->peer_sid = 0;
29691991Sheppo 		(void) ldc_up(ldcp->ldc_handle);
29701991Sheppo 	}
29711991Sheppo }
29721991Sheppo 
29731991Sheppo /* wrapper function for vgen_reset_hphase */
29741991Sheppo static void
29751991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp)
29761991Sheppo {
29771991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->cblock));
29781991Sheppo 	mutex_enter(&ldcp->txlock);
29791991Sheppo 	mutex_enter(&ldcp->tclock);
29801991Sheppo 
29811991Sheppo 	vgen_reset_hphase(ldcp);
29821991Sheppo 
29831991Sheppo 	mutex_exit(&ldcp->tclock);
29841991Sheppo 	mutex_exit(&ldcp->txlock);
29851991Sheppo }
29861991Sheppo 
29871991Sheppo /*
29881991Sheppo  * Initiate handshake with the peer by sending various messages
29891991Sheppo  * based on the handshake-phase that the channel is currently in.
29901991Sheppo  */
29911991Sheppo static void
29921991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
29931991Sheppo {
29941991Sheppo 	uint32_t hphase = ldcp->hphase;
29951991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
29961991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
29971991Sheppo 
29981991Sheppo 	switch (hphase) {
29991991Sheppo 
30001991Sheppo 	case VH_PHASE1:
30011991Sheppo 
30021991Sheppo 		/*
30031991Sheppo 		 * start timer, for entire handshake process, turn this timer
30041991Sheppo 		 * off if all phases of handshake complete successfully and
30051991Sheppo 		 * hphase goes to VH_DONE(below) or
30061991Sheppo 		 * vgen_reset_hphase() gets called or
30071991Sheppo 		 * channel is reset due to errors or
30081991Sheppo 		 * vgen_ldc_uninit() is invoked(vgen_stop).
30091991Sheppo 		 */
30101991Sheppo 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
30111991Sheppo 		    drv_usectohz(vgen_hwd_interval * 1000));
30121991Sheppo 
30131991Sheppo 		/* Phase 1 involves negotiating the version */
30141991Sheppo 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
30151991Sheppo 			vgen_handshake_reset(ldcp);
30161991Sheppo 		}
30171991Sheppo 		break;
30181991Sheppo 
30191991Sheppo 	case VH_PHASE2:
30201991Sheppo 		if (vgen_handshake_phase2(ldcp) != VGEN_SUCCESS) {
30211991Sheppo 			vgen_handshake_reset(ldcp);
30221991Sheppo 		}
30231991Sheppo 		break;
30241991Sheppo 
30251991Sheppo 	case VH_PHASE3:
30261991Sheppo 		if (vgen_send_rdx_info(ldcp) != VGEN_SUCCESS) {
30271991Sheppo 			vgen_handshake_reset(ldcp);
30281991Sheppo 		}
30291991Sheppo 		break;
30301991Sheppo 
30311991Sheppo 	case VH_DONE:
30321991Sheppo 		/* reset handshake watchdog timeout */
30331991Sheppo 		if (ldcp->htid) {
30341991Sheppo 			(void) untimeout(ldcp->htid);
30351991Sheppo 			ldcp->htid = 0;
30361991Sheppo 		}
30371991Sheppo 		ldcp->hretries = 0;
30381991Sheppo #if 0
30391991Sheppo 		vgen_print_ldcinfo(ldcp);
30401991Sheppo #endif
30411991Sheppo 		DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n",
30421991Sheppo 		    ldcp->ldc_id));
30431991Sheppo 
30441991Sheppo 		if (ldcp->need_mcast_sync) {
30451991Sheppo 			/* need to sync multicast table with vsw */
30461991Sheppo 
30471991Sheppo 			ldcp->need_mcast_sync = B_FALSE;
30481991Sheppo 			mutex_exit(&ldcp->cblock);
30491991Sheppo 
30501991Sheppo 			mutex_enter(&vgenp->lock);
30511991Sheppo 			(void) vgen_send_mcast_info(ldcp);
30521991Sheppo 			mutex_exit(&vgenp->lock);
30531991Sheppo 
30541991Sheppo 			mutex_enter(&ldcp->cblock);
30551991Sheppo 
30561991Sheppo 		}
30571991Sheppo 		break;
30581991Sheppo 
30591991Sheppo 	default:
30601991Sheppo 		break;
30611991Sheppo 	}
30621991Sheppo }
30631991Sheppo 
30641991Sheppo /*
30651991Sheppo  * Check if the current handshake phase has completed successfully and
30661991Sheppo  * return the status.
30671991Sheppo  */
30681991Sheppo static int
30691991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
30701991Sheppo {
30711991Sheppo 	uint32_t	hphase = ldcp->hphase;
30721991Sheppo 	int 		status = 0;
30731991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
30741991Sheppo 
30751991Sheppo 	switch (hphase) {
30761991Sheppo 
30771991Sheppo 	case VH_PHASE1:
30781991Sheppo 		/*
30791991Sheppo 		 * Phase1 is done, if version negotiation
30801991Sheppo 		 * completed successfully.
30811991Sheppo 		 */
30821991Sheppo 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
30831991Sheppo 			VER_NEGOTIATED);
30841991Sheppo 		break;
30851991Sheppo 
30861991Sheppo 	case VH_PHASE2:
30871991Sheppo 		/*
30881991Sheppo 		 * Phase 2 is done, if attr info and dring info
30891991Sheppo 		 * have been exchanged successfully.
30901991Sheppo 		 */
30911991Sheppo 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
30921991Sheppo 			    ATTR_INFO_EXCHANGED) &&
30931991Sheppo 			    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
30941991Sheppo 			    DRING_INFO_EXCHANGED));
30951991Sheppo 		break;
30961991Sheppo 
30971991Sheppo 	case VH_PHASE3:
30981991Sheppo 		/* Phase 3 is done, if rdx msg has been exchanged */
30991991Sheppo 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
31001991Sheppo 			RDX_EXCHANGED);
31011991Sheppo 		break;
31021991Sheppo 
31031991Sheppo 	default:
31041991Sheppo 		break;
31051991Sheppo 	}
31061991Sheppo 
31071991Sheppo 	if (status == 0) {
31081991Sheppo 		return (VGEN_FAILURE);
31091991Sheppo 	}
31101991Sheppo 	DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase));
31111991Sheppo 	return (VGEN_SUCCESS);
31121991Sheppo }
31131991Sheppo 
31141991Sheppo /* retry handshake on failure */
31151991Sheppo static void
31161991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp)
31171991Sheppo {
31181991Sheppo 	/* reset handshake phase */
31191991Sheppo 	vgen_handshake_reset(ldcp);
31201991Sheppo 	if (vgen_max_hretries) {	/* handshake retry is specified */
31211991Sheppo 		if (ldcp->hretries++ < vgen_max_hretries)
31221991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
31231991Sheppo 	}
31241991Sheppo }
31251991Sheppo 
31261991Sheppo /*
31271991Sheppo  * Handle a version info msg from the peer or an ACK/NACK from the peer
31281991Sheppo  * to a version info msg that we sent.
31291991Sheppo  */
31301991Sheppo static void
31311991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
31321991Sheppo {
31331991Sheppo 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
31341991Sheppo 	int		ack = 0;
31351991Sheppo 	int		failed = 0;
31361991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
31371991Sheppo 	int		idx;
31381991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
31391991Sheppo 
31401991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: enter\n"));
31411991Sheppo 	switch (tagp->vio_subtype) {
31421991Sheppo 	case VIO_SUBTYPE_INFO:
31431991Sheppo 
31441991Sheppo 		/*  Cache sid of peer if this is the first time */
31451991Sheppo 		if (ldcp->peer_sid == 0) {
31461991Sheppo 			DBG2((vnetp,
31471991Sheppo 			    "vgen_handle_version_negotiate: id (%lx) Caching"
31481991Sheppo 			    " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid));
31491991Sheppo 			ldcp->peer_sid = tagp->vio_sid;
31501991Sheppo 		}
31511991Sheppo 
31521991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
31531991Sheppo 			/*
31541991Sheppo 			 * If we are not already in VH_PHASE1, reset to
31551991Sheppo 			 * pre-handshake state, and initiate handshake
31561991Sheppo 			 * to the peer too.
31571991Sheppo 			 */
31581991Sheppo 			vgen_handshake_reset(ldcp);
31591991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
31601991Sheppo 		}
31611991Sheppo 		ldcp->hstate |= VER_INFO_RCVD;
31621991Sheppo 
31631991Sheppo 		/* save peer's requested values */
31641991Sheppo 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
31651991Sheppo 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
31661991Sheppo 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
31671991Sheppo 
31681991Sheppo 		if ((vermsg->dev_class != VDEV_NETWORK) &&
31691991Sheppo 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
31701991Sheppo 			/* unsupported dev_class, send NACK */
31711991Sheppo 
31721991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
31731991Sheppo 			tagp->vio_sid = ldcp->local_sid;
31741991Sheppo 			/* send reply msg back to peer */
31751991Sheppo 			(void) vgen_sendmsg(ldcp, (caddr_t)tagp,
31761991Sheppo 			    sizeof (*vermsg), B_FALSE);
31771991Sheppo 			DWARN((vnetp,
31781991Sheppo 			    "vgen_handle_version_negotiate: Version"
31791991Sheppo 			    " Negotiation Failed id (%lx)\n", ldcp->ldc_id));
31801991Sheppo 			vgen_handshake_reset(ldcp);
31811991Sheppo 			return;
31821991Sheppo 		}
31831991Sheppo 
31841991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD,"
31851991Sheppo 		    " id (%lx), ver(%d,%d)\n", ldcp->ldc_id,
31861991Sheppo 		    vermsg->ver_major,  vermsg->ver_minor));
31871991Sheppo 
31881991Sheppo 		idx = 0;
31891991Sheppo 
31901991Sheppo 		for (;;) {
31911991Sheppo 
31921991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
31931991Sheppo 
31941991Sheppo 				/* nack with next lower version */
31951991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
31961991Sheppo 				vermsg->ver_major = versions[idx].ver_major;
31971991Sheppo 				vermsg->ver_minor = versions[idx].ver_minor;
31981991Sheppo 				break;
31991991Sheppo 			}
32001991Sheppo 
32011991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
32021991Sheppo 
32031991Sheppo 				/* major version match - ACK version */
32041991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
32051991Sheppo 				ack = 1;
32061991Sheppo 
32071991Sheppo 				/*
32081991Sheppo 				 * lower minor version to the one this endpt
32091991Sheppo 				 * supports, if necessary
32101991Sheppo 				 */
32111991Sheppo 				if (vermsg->ver_minor >
32121991Sheppo 				    versions[idx].ver_minor) {
32131991Sheppo 					vermsg->ver_minor =
32141991Sheppo 						versions[idx].ver_minor;
32151991Sheppo 					ldcp->peer_hparams.ver_minor =
32161991Sheppo 						versions[idx].ver_minor;
32171991Sheppo 				}
32181991Sheppo 				break;
32191991Sheppo 			}
32201991Sheppo 
32211991Sheppo 			idx++;
32221991Sheppo 
32231991Sheppo 			if (idx == VGEN_NUM_VER) {
32241991Sheppo 
32251991Sheppo 				/* no version match - send NACK */
32261991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
32271991Sheppo 				vermsg->ver_major = 0;
32281991Sheppo 				vermsg->ver_minor = 0;
32291991Sheppo 				failed = 1;
32301991Sheppo 				break;
32311991Sheppo 			}
32321991Sheppo 
32331991Sheppo 		}
32341991Sheppo 
32351991Sheppo 		tagp->vio_sid = ldcp->local_sid;
32361991Sheppo 
32371991Sheppo 		/* send reply msg back to peer */
32381991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
32391991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
32401991Sheppo 			vgen_handshake_reset(ldcp);
32411991Sheppo 			return;
32421991Sheppo 		}
32431991Sheppo 
32441991Sheppo 		if (ack) {
32451991Sheppo 			ldcp->hstate |= VER_ACK_SENT;
32461991Sheppo 			DBG2((vnetp, "vgen_handle_version_negotiate:"
32471991Sheppo 			    " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
32481991Sheppo 			    ldcp->ldc_id, vermsg->ver_major,
32491991Sheppo 			    vermsg->ver_minor));
32501991Sheppo 		}
32511991Sheppo 		if (failed) {
32521991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
32531991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
32541991Sheppo 			    ldcp->ldc_id));
32551991Sheppo 			vgen_handshake_reset(ldcp);
32561991Sheppo 			return;
32571991Sheppo 		}
32581991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
32591991Sheppo 
32601991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
32611991Sheppo 
32621991Sheppo 			/* local and peer versions match? */
32631991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
32641991Sheppo 				ldcp->peer_hparams.ver_major) &&
32651991Sheppo 				(ldcp->local_hparams.ver_minor ==
32661991Sheppo 				ldcp->peer_hparams.ver_minor));
32671991Sheppo 
32681991Sheppo 			/* move to the next phase */
32691991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
32701991Sheppo 		}
32711991Sheppo 
32721991Sheppo 		break;
32731991Sheppo 
32741991Sheppo 	case VIO_SUBTYPE_ACK:
32751991Sheppo 
32761991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
32771991Sheppo 			/*  This should not happen. */
32781991Sheppo 			DWARN((vnetp,
32791991Sheppo 			    "vgen_handle_version_negotiate:"
32801991Sheppo 			    " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
32811991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
32821991Sheppo 			vgen_handshake_reset(ldcp);
32831991Sheppo 			return;
32841991Sheppo 		}
32851991Sheppo 
32861991Sheppo 		/* SUCCESS - we have agreed on a version */
32871991Sheppo 		ldcp->local_hparams.ver_major = vermsg->ver_major;
32881991Sheppo 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
32891991Sheppo 		ldcp->hstate |= VER_ACK_RCVD;
32901991Sheppo 
32911991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
32921991Sheppo 		    " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
32931991Sheppo 		    ldcp->ldc_id, vermsg->ver_major,  vermsg->ver_minor));
32941991Sheppo 
32951991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
32961991Sheppo 
32971991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
32981991Sheppo 
32991991Sheppo 			/* local and peer versions match? */
33001991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
33011991Sheppo 				ldcp->peer_hparams.ver_major) &&
33021991Sheppo 				(ldcp->local_hparams.ver_minor ==
33031991Sheppo 				ldcp->peer_hparams.ver_minor));
33041991Sheppo 
33051991Sheppo 			/* move to the next phase */
33061991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
33071991Sheppo 		}
33081991Sheppo 		break;
33091991Sheppo 
33101991Sheppo 	case VIO_SUBTYPE_NACK:
33111991Sheppo 
33121991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
33131991Sheppo 			/*  This should not happen.  */
33141991Sheppo 			DWARN((vnetp,
33151991Sheppo 			    "vgen_handle_version_negotiate:"
33161991Sheppo 			    " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
33171991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
33181991Sheppo 			vgen_handshake_reset(ldcp);
33191991Sheppo 			return;
33201991Sheppo 		}
33211991Sheppo 
33221991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
33231991Sheppo 		    " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
33241991Sheppo 		    ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor));
33251991Sheppo 
33261991Sheppo 		/* check if version in NACK is zero */
33271991Sheppo 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
33281991Sheppo 			/*
33291991Sheppo 			 * Version Negotiation has failed.
33301991Sheppo 			 */
33311991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
33321991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
33331991Sheppo 			    ldcp->ldc_id));
33341991Sheppo 			vgen_handshake_reset(ldcp);
33351991Sheppo 			return;
33361991Sheppo 		}
33371991Sheppo 
33381991Sheppo 		idx = 0;
33391991Sheppo 
33401991Sheppo 		for (;;) {
33411991Sheppo 
33421991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
33431991Sheppo 				/* select next lower version */
33441991Sheppo 
33451991Sheppo 				ldcp->local_hparams.ver_major =
33461991Sheppo 					versions[idx].ver_major;
33471991Sheppo 				ldcp->local_hparams.ver_minor =
33481991Sheppo 					versions[idx].ver_minor;
33491991Sheppo 				break;
33501991Sheppo 			}
33511991Sheppo 
33521991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
33531991Sheppo 				/* major version match */
33541991Sheppo 
33551991Sheppo 				ldcp->local_hparams.ver_major =
33561991Sheppo 					versions[idx].ver_major;
33571991Sheppo 
33581991Sheppo 				ldcp->local_hparams.ver_minor =
33591991Sheppo 					versions[idx].ver_minor;
33601991Sheppo 				break;
33611991Sheppo 			}
33621991Sheppo 
33631991Sheppo 			idx++;
33641991Sheppo 
33651991Sheppo 			if (idx == VGEN_NUM_VER) {
33661991Sheppo 				/*
33671991Sheppo 				 * no version match.
33681991Sheppo 				 * Version Negotiation has failed.
33691991Sheppo 				 */
33701991Sheppo 				DWARN((vnetp, "vgen_handle_version_negotiate:"
33711991Sheppo 				    " Version Negotiation Failed id (%lx)\n",
33721991Sheppo 				    ldcp->ldc_id));
33731991Sheppo 				vgen_handshake_reset(ldcp);
33741991Sheppo 				return;
33751991Sheppo 			}
33761991Sheppo 
33771991Sheppo 		}
33781991Sheppo 
33791991Sheppo 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
33801991Sheppo 			vgen_handshake_reset(ldcp);
33811991Sheppo 			return;
33821991Sheppo 		}
33831991Sheppo 
33841991Sheppo 		break;
33851991Sheppo 	}
33861991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: exit\n"));
33871991Sheppo }
33881991Sheppo 
33891991Sheppo /* Check if the attributes are supported */
33901991Sheppo static int
33911991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
33921991Sheppo {
33931991Sheppo 	_NOTE(ARGUNUSED(ldcp))
33941991Sheppo 
33951991Sheppo #if 0
33961991Sheppo 	uint64_t port_macaddr;
33971991Sheppo 	port_macaddr = vgen_macaddr_strtoul((uint8_t *)
33981991Sheppo 				&(ldcp->portp->macaddr));
33991991Sheppo #endif
34001991Sheppo 	/*
34011991Sheppo 	 * currently, we support these attr values:
34021991Sheppo 	 * mtu of ethernet, addr_type of mac, xfer_mode of
34031991Sheppo 	 * ldc shared memory, ack_freq of 0 (data is acked if
34041991Sheppo 	 * the ack bit is set in the descriptor) and the address should
34051991Sheppo 	 * match the address in the port node.
34061991Sheppo 	 */
34071991Sheppo 	if ((msg->mtu != ETHERMAX) ||
34081991Sheppo 	    (msg->addr_type != ADDR_TYPE_MAC) ||
34091991Sheppo 	    (msg->xfer_mode != VIO_DRING_MODE) ||
34101991Sheppo 	    (msg->ack_freq > 64)) {
34111991Sheppo #if 0
34121991Sheppo 	    (msg->addr != port_macaddr))
34131991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
34141991Sheppo 	msg->addr, port_macaddr);
34151991Sheppo #endif
34161991Sheppo 		return (VGEN_FAILURE);
34171991Sheppo 	}
34181991Sheppo 
34191991Sheppo 	return (VGEN_SUCCESS);
34201991Sheppo }
34211991Sheppo 
34221991Sheppo /*
34231991Sheppo  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
34241991Sheppo  * to an attr info msg that we sent.
34251991Sheppo  */
34261991Sheppo static void
34271991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
34281991Sheppo {
34291991Sheppo 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
34301991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
34311991Sheppo 	int		ack = 0;
34321991Sheppo 
34331991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: enter\n"));
34341991Sheppo 	if (ldcp->hphase != VH_PHASE2) {
34351991Sheppo 		DWARN((vnetp,
34361991Sheppo 		    "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)"
34371991Sheppo 		    " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
34381991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
34391991Sheppo 		vgen_handshake_reset(ldcp);
34401991Sheppo 		return;
34411991Sheppo 	}
34421991Sheppo 	switch (tagp->vio_subtype) {
34431991Sheppo 	case VIO_SUBTYPE_INFO:
34441991Sheppo 
34451991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
34461991Sheppo 		    ldcp->ldc_id));
34471991Sheppo 		ldcp->hstate |= ATTR_INFO_RCVD;
34481991Sheppo 
34491991Sheppo 		/* save peer's values */
34501991Sheppo 		ldcp->peer_hparams.mtu = attrmsg->mtu;
34511991Sheppo 		ldcp->peer_hparams.addr = attrmsg->addr;
34521991Sheppo 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
34531991Sheppo 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
34541991Sheppo 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
34551991Sheppo 
34561991Sheppo 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
34571991Sheppo 			/* unsupported attr, send NACK */
34581991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
34591991Sheppo 		} else {
34601991Sheppo 			ack = 1;
34611991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
34621991Sheppo 		}
34631991Sheppo 		tagp->vio_sid = ldcp->local_sid;
34641991Sheppo 
34651991Sheppo 		/* send reply msg back to peer */
34661991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
34671991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
34681991Sheppo 			vgen_handshake_reset(ldcp);
34691991Sheppo 			return;
34701991Sheppo 		}
34711991Sheppo 
34721991Sheppo 		if (ack) {
34731991Sheppo 			ldcp->hstate |= ATTR_ACK_SENT;
34741991Sheppo 			DBG2((vnetp, "vgen_handle_attr_info:"
34751991Sheppo 			    " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id));
34761991Sheppo 		} else {
34771991Sheppo 			/* failed */
34781991Sheppo 			DWARN((vnetp, "vgen_handle_attr_info:"
34791991Sheppo 			    " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id));
34801991Sheppo 			vgen_handshake_reset(ldcp);
34811991Sheppo 			return;
34821991Sheppo 		}
34831991Sheppo 
34841991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
34851991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
34861991Sheppo 		}
34871991Sheppo 
34881991Sheppo 		break;
34891991Sheppo 
34901991Sheppo 	case VIO_SUBTYPE_ACK:
34911991Sheppo 
34921991Sheppo 		ldcp->hstate |= ATTR_ACK_RCVD;
34931991Sheppo 
34941991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
34951991Sheppo 		    ldcp->ldc_id));
34961991Sheppo 
34971991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
34981991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
34991991Sheppo 		}
35001991Sheppo 		break;
35011991Sheppo 
35021991Sheppo 	case VIO_SUBTYPE_NACK:
35031991Sheppo 
35041991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
35051991Sheppo 		    ldcp->ldc_id));
35061991Sheppo 		vgen_handshake_reset(ldcp);
35071991Sheppo 		break;
35081991Sheppo 	}
35091991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: exit\n"));
35101991Sheppo }
35111991Sheppo 
35121991Sheppo /* Check if the dring info msg is ok */
35131991Sheppo static int
35141991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
35151991Sheppo {
35161991Sheppo 	/* check if msg contents are ok */
35171991Sheppo 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
35181991Sheppo 	    sizeof (vnet_public_desc_t))) {
35191991Sheppo 		return (VGEN_FAILURE);
35201991Sheppo 	}
35211991Sheppo 	return (VGEN_SUCCESS);
35221991Sheppo }
35231991Sheppo 
35241991Sheppo /*
35251991Sheppo  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
35261991Sheppo  * the peer to a dring register msg that we sent.
35271991Sheppo  */
35281991Sheppo static void
35291991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
35301991Sheppo {
35311991Sheppo 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
35321991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
35331991Sheppo 	ldc_mem_cookie_t dcookie;
35341991Sheppo 	int ack = 0;
35351991Sheppo 	int rv = 0;
35361991Sheppo 
35371991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: enter\n"));
35381991Sheppo 	if (ldcp->hphase < VH_PHASE2) {
35391991Sheppo 		/* dring_info can be rcvd in any of the phases after Phase1 */
35401991Sheppo 		DWARN((vnetp,
35411991Sheppo 		    "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)"
35421991Sheppo 		    " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
35431991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
35441991Sheppo 		vgen_handshake_reset(ldcp);
35451991Sheppo 		return;
35461991Sheppo 	}
35471991Sheppo 	switch (tagp->vio_subtype) {
35481991Sheppo 	case VIO_SUBTYPE_INFO:
35491991Sheppo 
35501991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
35511991Sheppo 		    ldcp->ldc_id));
35521991Sheppo 		ldcp->hstate |= DRING_INFO_RCVD;
35531991Sheppo 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
35541991Sheppo 
35551991Sheppo 		ASSERT(msg->ncookies == 1);
35561991Sheppo 
35571991Sheppo 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
35581991Sheppo 			/*
35591991Sheppo 			 * verified dring info msg to be ok,
35601991Sheppo 			 * now try to map the remote dring.
35611991Sheppo 			 */
35621991Sheppo 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
35631991Sheppo 			    msg->descriptor_size, &dcookie,
35641991Sheppo 			    msg->ncookies);
35651991Sheppo 			if (rv == DDI_SUCCESS) {
35661991Sheppo 				/* now we can ack the peer */
35671991Sheppo 				ack = 1;
35681991Sheppo 			}
35691991Sheppo 		}
35701991Sheppo 		if (ack == 0) {
35711991Sheppo 			/* failed, send NACK */
35721991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
35731991Sheppo 		} else {
35741991Sheppo 			if (!(ldcp->peer_hparams.dring_ready)) {
35751991Sheppo 
35761991Sheppo 				/* save peer's dring_info values */
35771991Sheppo 				bcopy(&dcookie,
35781991Sheppo 				    &(ldcp->peer_hparams.dring_cookie),
35791991Sheppo 				    sizeof (dcookie));
35801991Sheppo 				ldcp->peer_hparams.num_desc =
35811991Sheppo 						msg->num_descriptors;
35821991Sheppo 				ldcp->peer_hparams.desc_size =
35831991Sheppo 						msg->descriptor_size;
35841991Sheppo 				ldcp->peer_hparams.num_dcookies =
35851991Sheppo 						msg->ncookies;
35861991Sheppo 
35871991Sheppo 				/* set dring_ident for the peer */
35881991Sheppo 				ldcp->peer_hparams.dring_ident =
35891991Sheppo 							(uint64_t)ldcp->rxdp;
35901991Sheppo 				/* return the dring_ident in ack msg */
35911991Sheppo 				msg->dring_ident =
35921991Sheppo 							(uint64_t)ldcp->rxdp;
35931991Sheppo 
35941991Sheppo 				ldcp->peer_hparams.dring_ready = B_TRUE;
35951991Sheppo 			}
35961991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
35971991Sheppo 		}
35981991Sheppo 		tagp->vio_sid = ldcp->local_sid;
35991991Sheppo 		/* send reply msg back to peer */
36001991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
36011991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
36021991Sheppo 			vgen_handshake_reset(ldcp);
36031991Sheppo 			return;
36041991Sheppo 		}
36051991Sheppo 
36061991Sheppo 		if (ack) {
36071991Sheppo 			ldcp->hstate |= DRING_ACK_SENT;
36081991Sheppo 			DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT"
36091991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
36101991Sheppo 		} else {
36111991Sheppo 			DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT"
36121991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
36131991Sheppo 			vgen_handshake_reset(ldcp);
36141991Sheppo 			return;
36151991Sheppo 		}
36161991Sheppo 
36171991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
36181991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
36191991Sheppo 		}
36201991Sheppo 
36211991Sheppo 		break;
36221991Sheppo 
36231991Sheppo 	case VIO_SUBTYPE_ACK:
36241991Sheppo 
36251991Sheppo 		ldcp->hstate |= DRING_ACK_RCVD;
36261991Sheppo 
36271991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD"
36281991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
36291991Sheppo 
36301991Sheppo 		if (!(ldcp->local_hparams.dring_ready)) {
36311991Sheppo 			/* local dring is now ready */
36321991Sheppo 			ldcp->local_hparams.dring_ready = B_TRUE;
36331991Sheppo 
36341991Sheppo 			/* save dring_ident acked by peer */
36351991Sheppo 			ldcp->local_hparams.dring_ident =
36361991Sheppo 				msg->dring_ident;
36371991Sheppo 		}
36381991Sheppo 
36391991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
36401991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
36411991Sheppo 		}
36421991Sheppo 
36431991Sheppo 		break;
36441991Sheppo 
36451991Sheppo 	case VIO_SUBTYPE_NACK:
36461991Sheppo 
36471991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD"
36481991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
36491991Sheppo 		vgen_handshake_reset(ldcp);
36501991Sheppo 		break;
36511991Sheppo 	}
36521991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: exit\n"));
36531991Sheppo }
36541991Sheppo 
36551991Sheppo /*
36561991Sheppo  * Handle a rdx info msg from the peer or an ACK/NACK
36571991Sheppo  * from the peer to a rdx info msg that we sent.
36581991Sheppo  */
36591991Sheppo static void
36601991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
36611991Sheppo {
36621991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
36631991Sheppo 
36641991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: enter\n"));
36651991Sheppo 	if (ldcp->hphase != VH_PHASE3) {
36661991Sheppo 		DWARN((vnetp,
36671991Sheppo 		    "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)"
36681991Sheppo 		    "  Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
36691991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
36701991Sheppo 		vgen_handshake_reset(ldcp);
36711991Sheppo 		return;
36721991Sheppo 	}
36731991Sheppo 	switch (tagp->vio_subtype) {
36741991Sheppo 	case VIO_SUBTYPE_INFO:
36751991Sheppo 
36761991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
36771991Sheppo 		    ldcp->ldc_id));
36781991Sheppo 		ldcp->hstate |= RDX_INFO_RCVD;
36791991Sheppo 
36801991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
36811991Sheppo 		tagp->vio_sid = ldcp->local_sid;
36821991Sheppo 		/* send reply msg back to peer */
36831991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp,
36841991Sheppo 		    sizeof (vio_rdx_msg_t), B_FALSE) != VGEN_SUCCESS) {
36851991Sheppo 			vgen_handshake_reset(ldcp);
36861991Sheppo 			return;
36871991Sheppo 		}
36881991Sheppo 
36891991Sheppo 		ldcp->hstate |= RDX_ACK_SENT;
36901991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
36911991Sheppo 		    ldcp->ldc_id));
36921991Sheppo 
36931991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
36941991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
36951991Sheppo 		}
36961991Sheppo 
36971991Sheppo 		break;
36981991Sheppo 
36991991Sheppo 	case VIO_SUBTYPE_ACK:
37001991Sheppo 
37011991Sheppo 		ldcp->hstate |= RDX_ACK_RCVD;
37021991Sheppo 
37031991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
37041991Sheppo 		    ldcp->ldc_id));
37051991Sheppo 
37061991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
37071991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
37081991Sheppo 		}
37091991Sheppo 		break;
37101991Sheppo 
37111991Sheppo 	case VIO_SUBTYPE_NACK:
37121991Sheppo 
37131991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
37141991Sheppo 		    ldcp->ldc_id));
37151991Sheppo 		vgen_handshake_reset(ldcp);
37161991Sheppo 		break;
37171991Sheppo 	}
37181991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: exit\n"));
37191991Sheppo }
37201991Sheppo 
37211991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
37221991Sheppo static void
37231991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
37241991Sheppo {
37251991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
37261991Sheppo 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
37271991Sheppo 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
37281991Sheppo 	struct ether_addr *addrp;
37291991Sheppo 	int count;
37301991Sheppo 	int i;
37311991Sheppo 
37321991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: enter\n"));
37331991Sheppo 	switch (tagp->vio_subtype) {
37341991Sheppo 
37351991Sheppo 	case VIO_SUBTYPE_INFO:
37361991Sheppo 
37371991Sheppo 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
37381991Sheppo 		DWARN((vnetp,
37391991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
37401991Sheppo 		    ldcp->ldc_id));
37411991Sheppo 		break;
37421991Sheppo 
37431991Sheppo 	case VIO_SUBTYPE_ACK:
37441991Sheppo 
37451991Sheppo 		/* success adding/removing multicast addr */
37461991Sheppo 		DBG2((vnetp,
37471991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
37481991Sheppo 		    ldcp->ldc_id));
37491991Sheppo 		break;
37501991Sheppo 
37511991Sheppo 	case VIO_SUBTYPE_NACK:
37521991Sheppo 
37531991Sheppo 		DWARN((vnetp,
37541991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
37551991Sheppo 		    ldcp->ldc_id));
37561991Sheppo 		if (!(msgp->set)) {
37571991Sheppo 			/* multicast remove request failed */
37581991Sheppo 			break;
37591991Sheppo 		}
37601991Sheppo 
37611991Sheppo 		/* multicast add request failed */
37621991Sheppo 		for (count = 0; count < msgp->count; count++) {
37631991Sheppo 			addrp = &(msgp->mca[count]);
37641991Sheppo 
37651991Sheppo 			/* delete address from the table */
37661991Sheppo 			for (i = 0; i < vgenp->mccount; i++) {
37671991Sheppo 				if (ether_cmp(addrp,
37681991Sheppo 				    &(vgenp->mctab[i])) == 0) {
37691991Sheppo 					if (vgenp->mccount > 1) {
37701991Sheppo 						vgenp->mctab[i] =
37711991Sheppo 						vgenp->mctab[vgenp->mccount-1];
37721991Sheppo 					}
37731991Sheppo 					vgenp->mccount--;
37741991Sheppo 					break;
37751991Sheppo 				}
37761991Sheppo 			}
37771991Sheppo 		}
37781991Sheppo 		break;
37791991Sheppo 
37801991Sheppo 	}
37811991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: exit\n"));
37821991Sheppo }
37831991Sheppo 
37841991Sheppo /* handler for control messages received from the peer ldc end-point */
37851991Sheppo static void
37861991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
37871991Sheppo {
37881991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
37891991Sheppo 
37901991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n"));
37911991Sheppo 	switch (tagp->vio_subtype_env) {
37921991Sheppo 
37931991Sheppo 	case VIO_VER_INFO:
37941991Sheppo 		vgen_handle_version_negotiate(ldcp, tagp);
37951991Sheppo 		break;
37961991Sheppo 
37971991Sheppo 	case VIO_ATTR_INFO:
37981991Sheppo 		vgen_handle_attr_info(ldcp, tagp);
37991991Sheppo 		break;
38001991Sheppo 
38011991Sheppo 	case VIO_DRING_REG:
38021991Sheppo 		vgen_handle_dring_reg(ldcp, tagp);
38031991Sheppo 		break;
38041991Sheppo 
38051991Sheppo 	case VIO_RDX:
38061991Sheppo 		vgen_handle_rdx_info(ldcp, tagp);
38071991Sheppo 		break;
38081991Sheppo 
38091991Sheppo 	case VNET_MCAST_INFO:
38101991Sheppo 		vgen_handle_mcast_info(ldcp, tagp);
38111991Sheppo 		break;
38121991Sheppo 
38131991Sheppo 	}
38141991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n"));
38151991Sheppo }
38161991Sheppo 
38171991Sheppo /* handler for data messages received from the peer ldc end-point */
38181991Sheppo static void
38191991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
38201991Sheppo 	mblk_t **headp, mblk_t **tailp)
38211991Sheppo {
38221991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
38231991Sheppo 
38241991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: enter\n"));
38251991Sheppo 
38261991Sheppo 	if (ldcp->hphase != VH_DONE)
38271991Sheppo 		return;
38281991Sheppo 	switch (tagp->vio_subtype_env) {
38291991Sheppo 	case VIO_DRING_DATA:
38301991Sheppo 		vgen_handle_dring_data(ldcp, tagp, headp, tailp);
38311991Sheppo 		break;
38321991Sheppo 	default:
38331991Sheppo 		break;
38341991Sheppo 	}
38351991Sheppo 
38361991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: exit\n"));
38371991Sheppo }
38381991Sheppo 
38391991Sheppo static void
3840*2336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
3841*2336Snarayan     int32_t end, uint8_t pstate)
3842*2336Snarayan {
3843*2336Snarayan 	vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp;
3844*2336Snarayan 	void *vnetp = LDC_TO_VNET(ldcp);
3845*2336Snarayan 
3846*2336Snarayan 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
3847*2336Snarayan 	tagp->vio_sid = ldcp->local_sid;
3848*2336Snarayan 	msgp->start_idx = start;
3849*2336Snarayan 	msgp->end_idx = end;
3850*2336Snarayan 	msgp->dring_process_state = pstate;
3851*2336Snarayan 	if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE)) {
3852*2336Snarayan 		DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg "
3853*2336Snarayan 		    "failed\n", (ldcp)->ldc_id));
3854*2336Snarayan 	}
3855*2336Snarayan }
3856*2336Snarayan 
3857*2336Snarayan static void
38581991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
38591991Sheppo 	mblk_t **headp, mblk_t **tailp)
38601991Sheppo {
38611991Sheppo 	vio_dring_msg_t *dringmsg;
38621991Sheppo 	vnet_public_desc_t *rxdp;
38631991Sheppo 	vnet_public_desc_t *txdp;
38641991Sheppo 	vio_dring_entry_hdr_t *hdrp;
38651991Sheppo 	vgen_stats_t *statsp;
38661991Sheppo 	struct ether_header *ehp;
38671991Sheppo 	mblk_t *mp = NULL;
38681991Sheppo 	mblk_t *bp = NULL;
38691991Sheppo 	mblk_t *bpt = NULL;
38701991Sheppo 	size_t nbytes;
38711991Sheppo 	size_t nread;
38721991Sheppo 	uint64_t off = 0;
38731991Sheppo 	uint32_t start;
3874*2336Snarayan 	int32_t end;
38751991Sheppo 	uint32_t datalen;
38761991Sheppo 	uint32_t ncookies;
3877*2336Snarayan 	uint32_t ack_start;
3878*2336Snarayan 	uint32_t ack_end;
38791991Sheppo 	uint32_t rxi;
38801991Sheppo 	uint32_t txi;
38811991Sheppo 	int rv;
38821991Sheppo 	boolean_t rxd_err = B_FALSE;
3883*2336Snarayan 	boolean_t set_ack_start = B_FALSE;
3884*2336Snarayan 	vgen_private_desc_t *tbufp;
3885*2336Snarayan 	uint32_t next_rxi;
3886*2336Snarayan 	boolean_t ready_txd = B_FALSE;
3887*2336Snarayan 	uint32_t retries = 0;
38881991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS
38891991Sheppo 	int n;
38901991Sheppo #endif
38911991Sheppo #ifdef VGEN_REXMIT
38921991Sheppo 	uint64_t seqnum;
38931991Sheppo #endif
38941991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
38951991Sheppo 
38961991Sheppo 	dringmsg = (vio_dring_msg_t *)tagp;
38971991Sheppo 	start = dringmsg->start_idx;
38981991Sheppo 	end = dringmsg->end_idx;
38991991Sheppo 	statsp = ldcp->statsp;
39001991Sheppo 
39011991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: enter\n"));
39021991Sheppo 	switch (tagp->vio_subtype) {
39031991Sheppo 
39041991Sheppo 	case VIO_SUBTYPE_INFO:
39051991Sheppo 		/*
39061991Sheppo 		 * received a data msg, which contains the start and end
39071991Sheppo 		 * indeces of the descriptors within the rx ring holding data,
39081991Sheppo 		 * the seq_num of data packet corresponding to the start index,
39091991Sheppo 		 * and the dring_ident.
39101991Sheppo 		 * We can now read the contents of each of these descriptors
39111991Sheppo 		 * and gather data from it.
39121991Sheppo 		 */
39131991Sheppo 		DBG2((vnetp,
39141991Sheppo 		    "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
39151991Sheppo 		    start, end));
39161991Sheppo 
39171991Sheppo 		/* validate rx start and end indeces */
3918*2336Snarayan 		if (!(CHECK_RXI(start, ldcp)) || ((end != -1) &&
3919*2336Snarayan 		    !(CHECK_RXI(end, ldcp)))) {
39201991Sheppo 			/* drop the message if invalid index */
39211991Sheppo 			break;
39221991Sheppo 		}
39231991Sheppo 
39241991Sheppo 		/* validate dring_ident */
39251991Sheppo 		if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
39261991Sheppo 			/* invalid dring_ident, drop the msg */
39271991Sheppo 			break;
39281991Sheppo 		}
39291991Sheppo #ifdef DEBUG
39301991Sheppo 		if (vgen_trigger_rxlost) {
39311991Sheppo 			/* drop this msg to simulate lost pkts for debugging */
39321991Sheppo 			vgen_trigger_rxlost = 0;
39331991Sheppo 			break;
39341991Sheppo 		}
39351991Sheppo #endif
39361991Sheppo 
39371991Sheppo #ifdef	VGEN_HANDLE_LOST_PKTS
39381991Sheppo 
39391991Sheppo 		/* receive start index doesn't match expected index */
39401991Sheppo 		if (ldcp->next_rxi != start) {
39411991Sheppo 
39421991Sheppo 			DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
39431991Sheppo 			    "next_rxi(%d) != start(%d)\n",
39441991Sheppo 			    ldcp->ldc_id, ldcp->next_rxi, start));
39451991Sheppo 
39461991Sheppo 			/* calculate the number of pkts lost */
39471991Sheppo 			if (start >= ldcp->next_rxi) {
39481991Sheppo 				n = start - ldcp->next_rxi;
39491991Sheppo 			} else  {
39501991Sheppo 				n = ldcp->num_rxds - (ldcp->next_rxi - start);
39511991Sheppo 			}
39521991Sheppo 
39531991Sheppo 			/*
3954*2336Snarayan 			 * sequence number of dring data message
39551991Sheppo 			 * is less than the next sequence number that
39561991Sheppo 			 * is expected:
39571991Sheppo 			 *
39581991Sheppo 			 * drop the message and the corresponding packets.
39591991Sheppo 			 */
39601991Sheppo 			if (ldcp->next_rxseq > dringmsg->seq_num) {
39611991Sheppo 				DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
39621991Sheppo 				    "dropping pkts, expected rxseq(0x%lx) "
39631991Sheppo 				    "> recvd(0x%lx)\n",
39641991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
39651991Sheppo 				    dringmsg->seq_num));
39661991Sheppo 				/*
39671991Sheppo 				 * duplicate/multiple retransmissions from
39681991Sheppo 				 * sender?? drop this msg.
39691991Sheppo 				 */
39701991Sheppo 				break;
39711991Sheppo 			}
39721991Sheppo 
39731991Sheppo 			/*
3974*2336Snarayan 			 * sequence number of dring data message
39751991Sheppo 			 * is greater than the next expected sequence number
39761991Sheppo 			 *
39771991Sheppo 			 * send a NACK back to the peer to indicate lost
39781991Sheppo 			 * packets.
39791991Sheppo 			 */
39801991Sheppo 			if (dringmsg->seq_num > ldcp->next_rxseq) {
39811991Sheppo 				statsp->rx_lost_pkts += n;
39821991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
39831991Sheppo 				tagp->vio_sid = ldcp->local_sid;
39841991Sheppo 				/* indicate the range of lost descriptors */
39851991Sheppo 				dringmsg->start_idx = ldcp->next_rxi;
39861991Sheppo 				rxi = start;
39871991Sheppo 				DECR_RXI(rxi, ldcp);
39881991Sheppo 				dringmsg->end_idx = rxi;
39891991Sheppo 				/* dring ident is left unchanged */
39901991Sheppo 				if (vgen_sendmsg(ldcp, (caddr_t)tagp,
39911991Sheppo 				    sizeof (*dringmsg), B_FALSE)) {
39921991Sheppo 					DWARN((vnetp,
39931991Sheppo 					    "vgen_handle_dring_data: id(%lx) "
39941991Sheppo 					    "vgen_sendmsg failed, "
39951991Sheppo 					    "stype: NACK\n", ldcp->ldc_id));
39961991Sheppo 				}
39971991Sheppo #ifdef VGEN_REXMIT
39981991Sheppo 				/*
39991991Sheppo 				 * stop further processing until peer
4000*2336Snarayan 				 * retransmits with the right index.
4001*2336Snarayan 				 * update next_rxseq expected.
40021991Sheppo 				 */
4003*2336Snarayan 				ldcp->next_rxseq += 1;
40041991Sheppo 				break;
40051991Sheppo #else	/* VGEN_REXMIT */
40061991Sheppo 				/*
40071991Sheppo 				 * treat this range of descrs/pkts as dropped
40081991Sheppo 				 * and set the new expected values for next_rxi
40091991Sheppo 				 * and next_rxseq. continue(below) to process
40101991Sheppo 				 * from the new start index.
40111991Sheppo 				 */
40121991Sheppo 				ldcp->next_rxi = start;
4013*2336Snarayan 				ldcp->next_rxseq += 1;
40141991Sheppo #endif	/* VGEN_REXMIT */
40151991Sheppo 
40161991Sheppo 			} else if (dringmsg->seq_num == ldcp->next_rxseq) {
40171991Sheppo 				/*
4018*2336Snarayan 				 * expected and received seqnums match, but
40191991Sheppo 				 * the descriptor indeces don't?
40201991Sheppo 				 *
40211991Sheppo 				 * restart handshake with peer.
40221991Sheppo 				 */
40231991Sheppo 				DWARN((vnetp,
40241991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
40251991Sheppo 				    "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
40261991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
40271991Sheppo 				    dringmsg->seq_num));
40281991Sheppo 
40291991Sheppo 			}
40301991Sheppo 
40311991Sheppo 		} else {
40321991Sheppo 			/* expected and start dring indeces match */
40331991Sheppo 
40341991Sheppo 			if (dringmsg->seq_num != ldcp->next_rxseq) {
40351991Sheppo 
40361991Sheppo 				/* seqnums don't match */
40371991Sheppo 
40381991Sheppo 				DWARN((vnetp,
40391991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
40401991Sheppo 				    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
40411991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
40421991Sheppo 				    dringmsg->seq_num));
40431991Sheppo 			}
40441991Sheppo 		}
40451991Sheppo 
40461991Sheppo #endif	/* VGEN_HANDLE_LOST_PKTS */
40471991Sheppo 
40481991Sheppo 		/*
4049*2336Snarayan 		 * start processing the descriptors from the specified
4050*2336Snarayan 		 * start index, up to the index a descriptor is not ready
4051*2336Snarayan 		 * to be processed or we process the entire descriptor ring
4052*2336Snarayan 		 * and wrap around upto the start index.
40531991Sheppo 		 */
4054*2336Snarayan 
4055*2336Snarayan 		/* need to set the start index of descriptors to be ack'd */
4056*2336Snarayan 		set_ack_start = B_TRUE;
4057*2336Snarayan 
4058*2336Snarayan 		/* index upto which we have ack'd */
4059*2336Snarayan 		ack_end = start;
4060*2336Snarayan 		DECR_RXI(ack_end, ldcp);
4061*2336Snarayan 
4062*2336Snarayan 		next_rxi = rxi =  start;
40631991Sheppo 		do {
4064*2336Snarayan 
4065*2336Snarayan vgen_recv_retry:	if (ldc_mem_dring_acquire(ldcp->rx_dhandle,
4066*2336Snarayan 			    rxi, rxi)) {
4067*2336Snarayan 				DWARN((vnetp, "vgen_handle_dring_data: "
4068*2336Snarayan 				    "id(%lx), ldc_mem_dring_acquire() failed\n",
4069*2336Snarayan 				    ldcp->ldc_id));
4070*2336Snarayan 				statsp->ierrors++;
4071*2336Snarayan 				break;
4072*2336Snarayan 			}
40731991Sheppo 
40741991Sheppo 			rxdp = &(ldcp->rxdp[rxi]);
40751991Sheppo 			hdrp = &rxdp->hdr;
40761991Sheppo 
4077*2336Snarayan 			if (hdrp->dstate != VIO_DESC_READY) {
4078*2336Snarayan 				/*
4079*2336Snarayan 				 * descriptor is not ready.
4080*2336Snarayan 				 * retry descriptor acquire, stop processing
4081*2336Snarayan 				 * after max # retries.
4082*2336Snarayan 				 */
4083*2336Snarayan 				if (retries == vgen_recv_retries)
4084*2336Snarayan 					break;
4085*2336Snarayan 				retries++;
4086*2336Snarayan 				drv_usecwait(vgen_recv_delay);
4087*2336Snarayan 				goto vgen_recv_retry;
4088*2336Snarayan 			}
4089*2336Snarayan 			retries = 0;
4090*2336Snarayan 
4091*2336Snarayan 			if (set_ack_start) {
4092*2336Snarayan 				/*
4093*2336Snarayan 				 * initialize the start index of the range
4094*2336Snarayan 				 * of descriptors to be ack'd.
4095*2336Snarayan 				 */
4096*2336Snarayan 				ack_start = rxi;
4097*2336Snarayan 				set_ack_start = B_FALSE;
4098*2336Snarayan 			}
4099*2336Snarayan 
41001991Sheppo 			datalen = rxdp->nbytes;
41011991Sheppo 			ncookies = rxdp->ncookies;
41021991Sheppo 			if ((datalen < ETHERMIN) ||
41031991Sheppo 			    (ncookies == 0) ||
4104*2336Snarayan 			    (ncookies > MAX_COOKIES)) {
41051991Sheppo 				rxd_err = B_TRUE;
41061991Sheppo 			} else {
41071991Sheppo 				/*
4108*2336Snarayan 				 * Try to allocate an mblk from the free pool
4109*2336Snarayan 				 * of recv mblks for the channel.
4110*2336Snarayan 				 * If this fails, use allocb().
41111991Sheppo 				 */
4112*2336Snarayan 				mp = vio_allocb(ldcp->rmp);
4113*2336Snarayan 				if (!mp) {
4114*2336Snarayan 					/*
4115*2336Snarayan 					 * The data buffer returned by
4116*2336Snarayan 					 * allocb(9F) is 8byte aligned. We
4117*2336Snarayan 					 * allocate extra 8 bytes to ensure
4118*2336Snarayan 					 * size is multiple of 8 bytes for
4119*2336Snarayan 					 * ldc_mem_copy().
4120*2336Snarayan 					 */
4121*2336Snarayan 					statsp->rx_vio_allocb_fail++;
4122*2336Snarayan 					mp = allocb(VNET_IPALIGN + datalen + 8,
4123*2336Snarayan 					    BPRI_MED);
4124*2336Snarayan 				}
4125*2336Snarayan 				nbytes = (VNET_IPALIGN + datalen + 7) & ~7;
41261991Sheppo 			}
41271991Sheppo 			if ((rxd_err) || (mp == NULL)) {
41281991Sheppo 				/*
41291991Sheppo 				 * rxd_err or allocb() failure,
41301991Sheppo 				 * drop this packet, get next.
41311991Sheppo 				 */
41321991Sheppo 				if (rxd_err) {
41331991Sheppo 					statsp->ierrors++;
41341991Sheppo 					rxd_err = B_FALSE;
41351991Sheppo 				} else {
41361991Sheppo 					statsp->rx_allocb_fail++;
41371991Sheppo 				}
41381991Sheppo 
41391991Sheppo 				/* set descriptor done bit */
41401991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
41411991Sheppo 
4142*2336Snarayan 				(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4143*2336Snarayan 				    rxi, rxi);
4144*2336Snarayan 
41451991Sheppo 				if (hdrp->ack) {
41461991Sheppo 					/*
4147*2336Snarayan 					 * sender needs ack for this packet,
4148*2336Snarayan 					 * ack pkts upto this index.
41491991Sheppo 					 */
4150*2336Snarayan 					ack_end = rxi;
4151*2336Snarayan 
4152*2336Snarayan 					vgen_send_dring_ack(ldcp, tagp,
4153*2336Snarayan 					    ack_start, ack_end,
4154*2336Snarayan 					    VIO_DP_ACTIVE);
4155*2336Snarayan 
4156*2336Snarayan 					/* need to set new ack start index */
4157*2336Snarayan 					set_ack_start = B_TRUE;
41581991Sheppo 				}
41591991Sheppo 				goto vgen_next_rxi;
41601991Sheppo 			}
41611991Sheppo 
41621991Sheppo 			nread = nbytes;
41631991Sheppo 			rv = ldc_mem_copy(ldcp->ldc_handle,
41641991Sheppo 			    (caddr_t)mp->b_rptr, off, &nread,
41651991Sheppo 			    rxdp->memcookie, ncookies, LDC_COPY_IN);
41661991Sheppo 
41671991Sheppo 			/* set done bit irrespective of rv of ldc_mem_copy() */
41681991Sheppo 			hdrp->dstate = VIO_DESC_DONE;
41691991Sheppo 
4170*2336Snarayan 			(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4171*2336Snarayan 			    rxi, rxi);
4172*2336Snarayan 
4173*2336Snarayan 			mp->b_rptr += VNET_IPALIGN;
4174*2336Snarayan 
41751991Sheppo 			if (hdrp->ack) {
41761991Sheppo 				/*
4177*2336Snarayan 				 * sender needs ack for this packet,
4178*2336Snarayan 				 * ack pkts upto this index.
41791991Sheppo 				 */
4180*2336Snarayan 				ack_end = rxi;
4181*2336Snarayan 
4182*2336Snarayan 				vgen_send_dring_ack(ldcp, tagp,
4183*2336Snarayan 				    ack_start, ack_end, VIO_DP_ACTIVE);
4184*2336Snarayan 
4185*2336Snarayan 				/* need to set new ack start index */
4186*2336Snarayan 				set_ack_start = B_TRUE;
41871991Sheppo 			}
4188*2336Snarayan 
41891991Sheppo 			/* if ldc_mem_copy() failed */
41901991Sheppo 			if (rv) {
41911991Sheppo 				DWARN((vnetp,
41921991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
41931991Sheppo 				    "ldc_mem_copy failed\n", ldcp->ldc_id));
41941991Sheppo 				statsp->ierrors++;
41951991Sheppo 				freemsg(mp);
41961991Sheppo 				goto vgen_next_rxi;
41971991Sheppo 			}
41981991Sheppo 			if (nread != nbytes) {
41991991Sheppo 				DWARN((vnetp,
42001991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
42011991Sheppo 				    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
42021991Sheppo 				    ldcp->ldc_id, nread, nbytes));
42031991Sheppo 				statsp->ierrors++;
42041991Sheppo 				freemsg(mp);
42051991Sheppo 				goto vgen_next_rxi;
42061991Sheppo 			}
42071991Sheppo 
42081991Sheppo 			/* point to the actual end of data */
42091991Sheppo 			mp->b_wptr = mp->b_rptr + datalen;
42101991Sheppo 
42111991Sheppo 			/* update stats */
42121991Sheppo 			statsp->ipackets++;
42131991Sheppo 			statsp->rbytes += datalen;
42141991Sheppo 			ehp = (struct ether_header *)mp->b_rptr;
42151991Sheppo 			if (IS_BROADCAST(ehp))
42161991Sheppo 				statsp->brdcstrcv++;
42171991Sheppo 			else if (IS_MULTICAST(ehp))
42181991Sheppo 				statsp->multircv++;
42191991Sheppo 
42201991Sheppo 			/* build a chain of received packets */
42211991Sheppo 			if (bp == NULL) {
42221991Sheppo 				/* first pkt */
42231991Sheppo 				bp = mp;
42241991Sheppo 				bpt = bp;
42251991Sheppo 				bpt->b_next = NULL;
42261991Sheppo 			} else {
42271991Sheppo 				mp->b_next = NULL;
42281991Sheppo 				bpt->b_next = mp;
42291991Sheppo 				bpt = mp;
42301991Sheppo 			}
42311991Sheppo 
4232*2336Snarayan 
4233*2336Snarayan vgen_next_rxi:
4234*2336Snarayan 			/* update end index of range of descrs to be ack'd */
4235*2336Snarayan 			ack_end = rxi;
4236*2336Snarayan 
4237*2336Snarayan 			/* update the next index to be processed */
4238*2336Snarayan 			INCR_RXI(next_rxi, ldcp);
4239*2336Snarayan 			if (next_rxi == start) {
4240*2336Snarayan 				/*
4241*2336Snarayan 				 * processed the entire descriptor ring upto
4242*2336Snarayan 				 * the index at which we started.
4243*2336Snarayan 				 */
42441991Sheppo 				break;
42451991Sheppo 			}
4246*2336Snarayan 
4247*2336Snarayan 			rxi = next_rxi;
42481991Sheppo 
42491991Sheppo 		_NOTE(CONSTCOND)
42501991Sheppo 		} while (1);
42511991Sheppo 
4252*2336Snarayan 		/*
4253*2336Snarayan 		 * send an ack message to peer indicating that we have stopped
4254*2336Snarayan 		 * processing descriptors.
4255*2336Snarayan 		 */
4256*2336Snarayan 		if (set_ack_start) {
4257*2336Snarayan 			/*
4258*2336Snarayan 			 * We have ack'd upto some index and we have not
4259*2336Snarayan 			 * processed any descriptors beyond that index.
4260*2336Snarayan 			 * Use the last ack'd index as both the start and
4261*2336Snarayan 			 * end of range of descrs being ack'd.
4262*2336Snarayan 			 * Note: This results in acking the last index twice
4263*2336Snarayan 			 * and should be harmless.
4264*2336Snarayan 			 */
4265*2336Snarayan 			ack_start = ack_end;
42661991Sheppo 		}
42671991Sheppo 
4268*2336Snarayan 		vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
4269*2336Snarayan 		    VIO_DP_STOPPED);
4270*2336Snarayan 
4271*2336Snarayan 		/* save new recv index and expected seqnum of next dring msg */
4272*2336Snarayan 		ldcp->next_rxi = next_rxi;
4273*2336Snarayan 		ldcp->next_rxseq += 1;
4274*2336Snarayan 
42751991Sheppo 		break;
42761991Sheppo 
42771991Sheppo 	case VIO_SUBTYPE_ACK:
42781991Sheppo 		/*
42791991Sheppo 		 * received an ack corresponding to a specific descriptor for
42801991Sheppo 		 * which we had set the ACK bit in the descriptor (during
42811991Sheppo 		 * transmit). This enables us to reclaim descriptors.
42821991Sheppo 		 */
4283*2336Snarayan 
42841991Sheppo 		DBG2((vnetp,
42851991Sheppo 		    "vgen_handle_dring_data: ACK:  start(%d), end(%d)\n",
42861991Sheppo 		    start, end));
42871991Sheppo 
42881991Sheppo 		/* validate start and end indeces in the tx ack msg */
42891991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
42901991Sheppo 			/* drop the message if invalid index */
42911991Sheppo 			break;
42921991Sheppo 		}
42931991Sheppo 		/* validate dring_ident */
42941991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
42951991Sheppo 			/* invalid dring_ident, drop the msg */
42961991Sheppo 			break;
42971991Sheppo 		}
42981991Sheppo 		statsp->dring_data_acks++;
4299*2336Snarayan 
4300*2336Snarayan 		/* reclaim descriptors that are done */
43011991Sheppo 		vgen_reclaim(ldcp);
4302*2336Snarayan 
4303*2336Snarayan 		if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
4304*2336Snarayan 			/*
4305*2336Snarayan 			 * receiver continued processing descriptors after
4306*2336Snarayan 			 * sending us the ack.
4307*2336Snarayan 			 */
4308*2336Snarayan 			break;
4309*2336Snarayan 		}
4310*2336Snarayan 
4311*2336Snarayan 		statsp->dring_stopped_acks++;
4312*2336Snarayan 
4313*2336Snarayan 		/* receiver stopped processing descriptors */
4314*2336Snarayan 		mutex_enter(&ldcp->txlock);
4315*2336Snarayan 		mutex_enter(&ldcp->tclock);
4316*2336Snarayan 
4317*2336Snarayan 		/*
4318*2336Snarayan 		 * determine if there are any pending tx descriptors
4319*2336Snarayan 		 * ready to be processed by the receiver(peer) and if so,
4320*2336Snarayan 		 * send a message to the peer to restart receiving.
4321*2336Snarayan 		 */
4322*2336Snarayan 		ready_txd = B_FALSE;
4323*2336Snarayan 
4324*2336Snarayan 		/*
4325*2336Snarayan 		 * using the end index of the descriptor range for which
4326*2336Snarayan 		 * we received the ack, check if the next descriptor is
4327*2336Snarayan 		 * ready.
4328*2336Snarayan 		 */
4329*2336Snarayan 		txi = end;
4330*2336Snarayan 		INCR_TXI(txi, ldcp);
4331*2336Snarayan 		tbufp = &ldcp->tbufp[txi];
4332*2336Snarayan 		txdp = tbufp->descp;
4333*2336Snarayan 		hdrp = &txdp->hdr;
4334*2336Snarayan 		if (hdrp->dstate == VIO_DESC_READY) {
4335*2336Snarayan 			ready_txd = B_TRUE;
4336*2336Snarayan 		} else {
4337*2336Snarayan 			/*
4338*2336Snarayan 			 * descr next to the end of ack'd descr range is not
4339*2336Snarayan 			 * ready.
4340*2336Snarayan 			 * starting from the current reclaim index, check
4341*2336Snarayan 			 * if any descriptor is ready.
4342*2336Snarayan 			 */
4343*2336Snarayan 
4344*2336Snarayan 			txi = ldcp->cur_tbufp - ldcp->tbufp;
4345*2336Snarayan 			tbufp = &ldcp->tbufp[txi];
4346*2336Snarayan 
4347*2336Snarayan 			while (tbufp != ldcp->next_tbufp) {
4348*2336Snarayan 
4349*2336Snarayan 				txdp = tbufp->descp;
4350*2336Snarayan 				hdrp = &txdp->hdr;
4351*2336Snarayan 				if (hdrp->dstate == VIO_DESC_READY) {
4352*2336Snarayan 					break;
4353*2336Snarayan 				}
4354*2336Snarayan 
4355*2336Snarayan 				INCR_TXI(txi, ldcp);
4356*2336Snarayan 				tbufp = &ldcp->tbufp[txi];
4357*2336Snarayan 
4358*2336Snarayan 			}
4359*2336Snarayan 
4360*2336Snarayan 			if (tbufp != ldcp->next_tbufp)
4361*2336Snarayan 				ready_txd = B_TRUE;
4362*2336Snarayan 		}
4363*2336Snarayan 
4364*2336Snarayan 		if (ready_txd) {
4365*2336Snarayan 			/*
4366*2336Snarayan 			 * we have tx descriptor(s) ready to be
4367*2336Snarayan 			 * processed by the receiver.
4368*2336Snarayan 			 * send a message to the peer with the start index
4369*2336Snarayan 			 * of ready descriptors.
4370*2336Snarayan 			 */
4371*2336Snarayan 			rv = vgen_send_dring_data(ldcp, txi, -1);
4372*2336Snarayan 			if (rv != 0) {
4373*2336Snarayan 				ldcp->resched_peer = B_TRUE;
4374*2336Snarayan 			}
4375*2336Snarayan 		} else {
4376*2336Snarayan 			/*
4377*2336Snarayan 			 * no ready tx descriptors. set the flag to send a
4378*2336Snarayan 			 * message to peer when tx descriptors are ready in
4379*2336Snarayan 			 * transmit routine.
4380*2336Snarayan 			 */
4381*2336Snarayan 			ldcp->resched_peer = B_TRUE;
4382*2336Snarayan 		}
4383*2336Snarayan 
4384*2336Snarayan 		mutex_exit(&ldcp->tclock);
4385*2336Snarayan 		mutex_exit(&ldcp->txlock);
4386*2336Snarayan 
43871991Sheppo 		break;
43881991Sheppo 
43891991Sheppo 	case VIO_SUBTYPE_NACK:
43901991Sheppo 		/*
43911991Sheppo 		 * peer sent a NACK msg to indicate lost packets.
43921991Sheppo 		 * The start and end correspond to the range of descriptors
43931991Sheppo 		 * for which the peer didn't receive a dring data msg and so
43941991Sheppo 		 * didn't receive the corresponding data.
43951991Sheppo 		 */
43961991Sheppo 		DWARN((vnetp,
43971991Sheppo 		    "vgen_handle_dring_data: NACK:  start(%d), end(%d)\n",
43981991Sheppo 		    start, end));
43991991Sheppo 
44001991Sheppo 		/* validate start and end indeces in the tx nack msg */
44011991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
44021991Sheppo 			/* drop the message if invalid index */
44031991Sheppo 			break;
44041991Sheppo 		}
44051991Sheppo 		/* validate dring_ident */
44061991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
44071991Sheppo 			/* invalid dring_ident, drop the msg */
44081991Sheppo 			break;
44091991Sheppo 		}
44101991Sheppo 		mutex_enter(&ldcp->txlock);
44111991Sheppo 		mutex_enter(&ldcp->tclock);
44121991Sheppo 
44131991Sheppo 		if (ldcp->next_tbufp == ldcp->cur_tbufp) {
44141991Sheppo 			/* no busy descriptors, bogus nack ? */
44151991Sheppo 			mutex_exit(&ldcp->tclock);
44161991Sheppo 			mutex_exit(&ldcp->txlock);
44171991Sheppo 			break;
44181991Sheppo 		}
44191991Sheppo 
44201991Sheppo #ifdef VGEN_REXMIT
44211991Sheppo 		/* send a new dring data msg including the lost descrs */
44221991Sheppo 		end = ldcp->next_tbufp - ldcp->tbufp;
44231991Sheppo 		DECR_TXI(end, ldcp);
4424*2336Snarayan 		rv = vgen_send_dring_data(ldcp, start, end);
44251991Sheppo 		if (rv != 0) {
44261991Sheppo 			/*
44271991Sheppo 			 * vgen_send_dring_data() error: drop all packets
44281991Sheppo 			 * in this descr range
44291991Sheppo 			 */
44301991Sheppo 			DWARN((vnetp,
44311991Sheppo 			    "vgen_handle_dring_data: "
44321991Sheppo 			    "vgen_send_dring_data failed :"
44331991Sheppo 			    "id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
44341991Sheppo 			for (txi = start; txi <= end; ) {
44351991Sheppo 				tbufp = &(ldcp->tbufp[txi]);
44361991Sheppo 				txdp = tbufp->descp;
44371991Sheppo 				hdrp = &txdp->hdr;
44381991Sheppo 				tbufp->flags = VGEN_PRIV_DESC_FREE;
44391991Sheppo 				hdrp->dstate = VIO_DESC_FREE;
44401991Sheppo 				hdrp->ack = B_FALSE;
44411991Sheppo 				statsp->oerrors++;
44421991Sheppo 			}
44431991Sheppo 
44441991Sheppo 			/* update next pointer */
44451991Sheppo 			ldcp->next_tbufp = &(ldcp->tbufp[start]);
44461991Sheppo 			ldcp->next_txi = start;
44471991Sheppo 		}
44481991Sheppo 		DBG2((vnetp,
44491991Sheppo 		    "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
44501991Sheppo 		    start, end));
44511991Sheppo #else	/* VGEN_REXMIT */
44521991Sheppo 		/* we just mark the descrs as done so they can be reclaimed */
44531991Sheppo 		for (txi = start; txi <= end; ) {
44541991Sheppo 			txdp = &(ldcp->txdp[txi]);
44551991Sheppo 			hdrp = &txdp->hdr;
44561991Sheppo 			if (hdrp->dstate == VIO_DESC_READY)
44571991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
44581991Sheppo 			INCR_TXI(txi, ldcp);
44591991Sheppo 		}
44601991Sheppo #endif	/* VGEN_REXMIT */
44611991Sheppo 		mutex_exit(&ldcp->tclock);
44621991Sheppo 		mutex_exit(&ldcp->txlock);
44631991Sheppo 
44641991Sheppo 		break;
44651991Sheppo 	}
44661991Sheppo 
44671991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: exit\n"));
44681991Sheppo 	*headp = bp;
44691991Sheppo 	*tailp = bpt;
4470*2336Snarayan 
44711991Sheppo }
44721991Sheppo 
44731991Sheppo static void
44741991Sheppo vgen_reclaim(vgen_ldc_t *ldcp)
44751991Sheppo {
4476*2336Snarayan 	mutex_enter(&ldcp->tclock);
4477*2336Snarayan 
44781991Sheppo 	vgen_reclaim_dring(ldcp);
44791991Sheppo 	ldcp->reclaim_lbolt = ddi_get_lbolt();
4480*2336Snarayan 
44811991Sheppo 	mutex_exit(&ldcp->tclock);
44821991Sheppo }
44831991Sheppo 
44841991Sheppo /*
44851991Sheppo  * transmit reclaim function. starting from the current reclaim index
44861991Sheppo  * look for descriptors marked DONE and reclaim the descriptor and the
44871991Sheppo  * corresponding buffers (tbuf).
44881991Sheppo  */
44891991Sheppo static void
44901991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp)
44911991Sheppo {
44921991Sheppo 	vnet_public_desc_t *txdp;
44931991Sheppo 	vgen_private_desc_t *tbufp;
44941991Sheppo 	vio_dring_entry_hdr_t	*hdrp;
4495*2336Snarayan 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
44961991Sheppo 
44971991Sheppo #ifdef DEBUG
44981991Sheppo 	if (vgen_trigger_txtimeout)
44991991Sheppo 		return;
45001991Sheppo #endif
45011991Sheppo 
45021991Sheppo 	tbufp = ldcp->cur_tbufp;
45031991Sheppo 	txdp = tbufp->descp;
45041991Sheppo 	hdrp = &txdp->hdr;
45051991Sheppo 
45061991Sheppo 	while ((hdrp->dstate == VIO_DESC_DONE) &&
45071991Sheppo 	    (tbufp != ldcp->next_tbufp)) {
45081991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
45091991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
45101991Sheppo 		hdrp->ack = B_FALSE;
45111991Sheppo 
45121991Sheppo 		tbufp = NEXTTBUF(ldcp, tbufp);
45131991Sheppo 		txdp = tbufp->descp;
45141991Sheppo 		hdrp = &txdp->hdr;
45151991Sheppo 	}
45161991Sheppo 
45171991Sheppo 	ldcp->cur_tbufp = tbufp;
45181991Sheppo 
45191991Sheppo 	/*
45201991Sheppo 	 * Check if mac layer should be notified to restart transmissions
45211991Sheppo 	 */
45221991Sheppo 	if (ldcp->need_resched) {
45231991Sheppo 		ldcp->need_resched = B_FALSE;
45242311Sseb 		vnet_tx_update(vgenp->vnetp);
45251991Sheppo 	}
45261991Sheppo }
45271991Sheppo 
45281991Sheppo /* return the number of pending transmits for the channel */
45291991Sheppo static int
45301991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp)
45311991Sheppo {
45321991Sheppo 	int n;
45331991Sheppo 
45341991Sheppo 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
45351991Sheppo 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
45361991Sheppo 	} else  {
45371991Sheppo 		/* cur_tbufp > next_tbufp */
45381991Sheppo 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
45391991Sheppo 	}
45401991Sheppo 
45411991Sheppo 	return (n);
45421991Sheppo }
45431991Sheppo 
45441991Sheppo /* determine if the transmit descriptor ring is full */
45451991Sheppo static int
45461991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp)
45471991Sheppo {
45481991Sheppo 	vgen_private_desc_t	*tbufp;
45491991Sheppo 	vgen_private_desc_t	*ntbufp;
45501991Sheppo 
45511991Sheppo 	tbufp = ldcp->next_tbufp;
45521991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
45531991Sheppo 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
45541991Sheppo 		return (VGEN_SUCCESS);
45551991Sheppo 	}
45561991Sheppo 	return (VGEN_FAILURE);
45571991Sheppo }
45581991Sheppo 
45591991Sheppo /* determine if timeout condition has occured */
45601991Sheppo static int
45611991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
45621991Sheppo {
45631991Sheppo 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
45641991Sheppo 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
45651991Sheppo 	    (vnet_ldcwd_txtimeout) &&
45661991Sheppo 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
45671991Sheppo 		return (VGEN_SUCCESS);
45681991Sheppo 	} else {
45691991Sheppo 		return (VGEN_FAILURE);
45701991Sheppo 	}
45711991Sheppo }
45721991Sheppo 
45731991Sheppo /* transmit watchdog timeout handler */
45741991Sheppo static void
45751991Sheppo vgen_ldc_watchdog(void *arg)
45761991Sheppo {
45771991Sheppo 	vgen_ldc_t *ldcp;
4578*2336Snarayan 	vgen_t *vgenp;
45791991Sheppo 	void *vnetp;
45801991Sheppo 	int rv;
45811991Sheppo 
45821991Sheppo 	ldcp = (vgen_ldc_t *)arg;
4583*2336Snarayan 	vgenp = LDC_TO_VGEN(ldcp);
45841991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
45851991Sheppo 
45861991Sheppo 	rv = vgen_ldc_txtimeout(ldcp);
45871991Sheppo 	if (rv == VGEN_SUCCESS) {
45881991Sheppo 		DWARN((vnetp,
45891991Sheppo 		    "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
45901991Sheppo 		    ldcp->ldc_id));
45911991Sheppo #ifdef DEBUG
45921991Sheppo 		if (vgen_trigger_txtimeout) {
45931991Sheppo 			/* tx timeout triggered for debugging */
45941991Sheppo 			vgen_trigger_txtimeout = 0;
45951991Sheppo 		}
45961991Sheppo #endif
45971991Sheppo 		mutex_enter(&ldcp->cblock);
45981991Sheppo 		vgen_handshake_retry(ldcp);
45991991Sheppo 		mutex_exit(&ldcp->cblock);
46001991Sheppo 		if (ldcp->need_resched) {
46011991Sheppo 			ldcp->need_resched = B_FALSE;
4602*2336Snarayan 			vnet_tx_update(vgenp->vnetp);
46031991Sheppo 		}
46041991Sheppo 	}
46051991Sheppo 
46061991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
46071991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
46081991Sheppo }
46091991Sheppo 
46101991Sheppo static int
46111991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp)
46121991Sheppo {
46131991Sheppo 	vgen_t *vgenp;
46141991Sheppo 	struct kstat *ksp;
46151991Sheppo 	vgen_stats_t *statsp;
46161991Sheppo 	vgen_kstats_t *ldckp;
46171991Sheppo 	int instance;
46181991Sheppo 	size_t size;
46191991Sheppo 	char name[MAXNAMELEN];
46201991Sheppo 
46211991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
46221991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
46231991Sheppo 	(void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id);
46241991Sheppo 	statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
46251991Sheppo 	if (statsp == NULL) {
46261991Sheppo 		return (VGEN_FAILURE);
46271991Sheppo 	}
46281991Sheppo 	size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
46291991Sheppo 	ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
46301991Sheppo 		size, 0);
46311991Sheppo 	if (ksp == NULL) {
46321991Sheppo 		KMEM_FREE(statsp);
46331991Sheppo 		return (VGEN_FAILURE);
46341991Sheppo 	}
46351991Sheppo 
46361991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
46371991Sheppo 	kstat_named_init(&ldckp->ipackets,		"ipackets",
46381991Sheppo 		KSTAT_DATA_ULONG);
46391991Sheppo 	kstat_named_init(&ldckp->ipackets64,		"ipackets64",
46401991Sheppo 		KSTAT_DATA_ULONGLONG);
46411991Sheppo 	kstat_named_init(&ldckp->ierrors,		"ierrors",
46421991Sheppo 		KSTAT_DATA_ULONG);
46431991Sheppo 	kstat_named_init(&ldckp->opackets,		"opackets",
46441991Sheppo 		KSTAT_DATA_ULONG);
46451991Sheppo 	kstat_named_init(&ldckp->opackets64,		"opackets64",
46461991Sheppo 		KSTAT_DATA_ULONGLONG);
46471991Sheppo 	kstat_named_init(&ldckp->oerrors,		"oerrors",
46481991Sheppo 		KSTAT_DATA_ULONG);
46491991Sheppo 
46501991Sheppo 
46511991Sheppo 	/* MIB II kstat variables */
46521991Sheppo 	kstat_named_init(&ldckp->rbytes,		"rbytes",
46531991Sheppo 		KSTAT_DATA_ULONG);
46541991Sheppo 	kstat_named_init(&ldckp->rbytes64,		"rbytes64",
46551991Sheppo 		KSTAT_DATA_ULONGLONG);
46561991Sheppo 	kstat_named_init(&ldckp->obytes,		"obytes",
46571991Sheppo 		KSTAT_DATA_ULONG);
46581991Sheppo 	kstat_named_init(&ldckp->obytes64,		"obytes64",
46591991Sheppo 		KSTAT_DATA_ULONGLONG);
46601991Sheppo 	kstat_named_init(&ldckp->multircv,		"multircv",
46611991Sheppo 		KSTAT_DATA_ULONG);
46621991Sheppo 	kstat_named_init(&ldckp->multixmt,		"multixmt",
46631991Sheppo 		KSTAT_DATA_ULONG);
46641991Sheppo 	kstat_named_init(&ldckp->brdcstrcv,		"brdcstrcv",
46651991Sheppo 		KSTAT_DATA_ULONG);
46661991Sheppo 	kstat_named_init(&ldckp->brdcstxmt,		"brdcstxmt",
46671991Sheppo 		KSTAT_DATA_ULONG);
46681991Sheppo 	kstat_named_init(&ldckp->norcvbuf,		"norcvbuf",
46691991Sheppo 		KSTAT_DATA_ULONG);
46701991Sheppo 	kstat_named_init(&ldckp->noxmtbuf,		"noxmtbuf",
46711991Sheppo 		KSTAT_DATA_ULONG);
46721991Sheppo 
46731991Sheppo 	/* Tx stats */
46741991Sheppo 	kstat_named_init(&ldckp->tx_no_desc,		"tx_no_desc",
46751991Sheppo 		KSTAT_DATA_ULONG);
46761991Sheppo 
46771991Sheppo 	/* Rx stats */
4678*2336Snarayan 	kstat_named_init(&ldckp->rx_allocb_fail,	"rx_allocb_fail",
46791991Sheppo 		KSTAT_DATA_ULONG);
4680*2336Snarayan 	kstat_named_init(&ldckp->rx_vio_allocb_fail,	"rx_vio_allocb_fail",
46811991Sheppo 		KSTAT_DATA_ULONG);
46821991Sheppo 	kstat_named_init(&ldckp->rx_lost_pkts,		"rx_lost_pkts",
46831991Sheppo 		KSTAT_DATA_ULONG);
46841991Sheppo 
46851991Sheppo 	/* Interrupt stats */
46861991Sheppo 	kstat_named_init(&ldckp->callbacks,		"callbacks",
46871991Sheppo 		KSTAT_DATA_ULONG);
46881991Sheppo 	kstat_named_init(&ldckp->dring_data_acks,	"dring_data_acks",
46891991Sheppo 		KSTAT_DATA_ULONG);
4690*2336Snarayan 	kstat_named_init(&ldckp->dring_stopped_acks,	"dring_stopped_acks",
4691*2336Snarayan 		KSTAT_DATA_ULONG);
4692*2336Snarayan 	kstat_named_init(&ldckp->dring_data_msgs,	"dring_data_msgs",
4693*2336Snarayan 		KSTAT_DATA_ULONG);
46941991Sheppo 
46951991Sheppo 	ksp->ks_update = vgen_kstat_update;
46961991Sheppo 	ksp->ks_private = (void *)ldcp;
46971991Sheppo 	kstat_install(ksp);
46981991Sheppo 
46991991Sheppo 	ldcp->ksp = ksp;
47001991Sheppo 	ldcp->statsp = statsp;
47011991Sheppo 	return (VGEN_SUCCESS);
47021991Sheppo }
47031991Sheppo 
47041991Sheppo static void
47051991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp)
47061991Sheppo {
47071991Sheppo 	if (ldcp->ksp)
47081991Sheppo 		kstat_delete(ldcp->ksp);
47091991Sheppo 	KMEM_FREE(ldcp->statsp);
47101991Sheppo }
47111991Sheppo 
47121991Sheppo static int
47131991Sheppo vgen_kstat_update(kstat_t *ksp, int rw)
47141991Sheppo {
47151991Sheppo 	vgen_ldc_t *ldcp;
47161991Sheppo 	vgen_stats_t *statsp;
47171991Sheppo 	vgen_kstats_t *ldckp;
47181991Sheppo 
47191991Sheppo 	ldcp = (vgen_ldc_t *)ksp->ks_private;
47201991Sheppo 	statsp = ldcp->statsp;
47211991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
47221991Sheppo 
47231991Sheppo 	if (rw == KSTAT_READ) {
47241991Sheppo 		ldckp->ipackets.value.ul	= (uint32_t)statsp->ipackets;
47251991Sheppo 		ldckp->ipackets64.value.ull	= statsp->ipackets;
47261991Sheppo 		ldckp->ierrors.value.ul		= statsp->ierrors;
47271991Sheppo 		ldckp->opackets.value.ul	= (uint32_t)statsp->opackets;
47281991Sheppo 		ldckp->opackets64.value.ull	= statsp->opackets;
47291991Sheppo 		ldckp->oerrors.value.ul		= statsp->oerrors;
47301991Sheppo 
47311991Sheppo 		/*
47321991Sheppo 		 * MIB II kstat variables
47331991Sheppo 		 */
47341991Sheppo 		ldckp->rbytes.value.ul		= (uint32_t)statsp->rbytes;
47351991Sheppo 		ldckp->rbytes64.value.ull	= statsp->rbytes;
47361991Sheppo 		ldckp->obytes.value.ul		= (uint32_t)statsp->obytes;
47371991Sheppo 		ldckp->obytes64.value.ull	= statsp->obytes;
47381991Sheppo 		ldckp->multircv.value.ul	= statsp->multircv;
47391991Sheppo 		ldckp->multixmt.value.ul	= statsp->multixmt;
47401991Sheppo 		ldckp->brdcstrcv.value.ul	= statsp->brdcstrcv;
47411991Sheppo 		ldckp->brdcstxmt.value.ul	= statsp->brdcstxmt;
47421991Sheppo 		ldckp->norcvbuf.value.ul	= statsp->norcvbuf;
47431991Sheppo 		ldckp->noxmtbuf.value.ul	= statsp->noxmtbuf;
47441991Sheppo 
47451991Sheppo 		ldckp->tx_no_desc.value.ul	= statsp->tx_no_desc;
4746*2336Snarayan 
47471991Sheppo 		ldckp->rx_allocb_fail.value.ul	= statsp->rx_allocb_fail;
4748*2336Snarayan 		ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail;
47491991Sheppo 		ldckp->rx_lost_pkts.value.ul	= statsp->rx_lost_pkts;
47501991Sheppo 
47511991Sheppo 		ldckp->callbacks.value.ul	= statsp->callbacks;
47521991Sheppo 		ldckp->dring_data_acks.value.ul	= statsp->dring_data_acks;
4753*2336Snarayan 		ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks;
4754*2336Snarayan 		ldckp->dring_data_msgs.value.ul	= statsp->dring_data_msgs;
47551991Sheppo 	} else {
47561991Sheppo 		statsp->ipackets	= ldckp->ipackets64.value.ull;
47571991Sheppo 		statsp->ierrors		= ldckp->ierrors.value.ul;
47581991Sheppo 		statsp->opackets	= ldckp->opackets64.value.ull;
47591991Sheppo 		statsp->oerrors		= ldckp->oerrors.value.ul;
47601991Sheppo 
47611991Sheppo 		/*
47621991Sheppo 		 * MIB II kstat variables
47631991Sheppo 		 */
47641991Sheppo 		statsp->rbytes		= ldckp->rbytes64.value.ull;
47651991Sheppo 		statsp->obytes		= ldckp->obytes64.value.ull;
47661991Sheppo 		statsp->multircv	= ldckp->multircv.value.ul;
47671991Sheppo 		statsp->multixmt	= ldckp->multixmt.value.ul;
47681991Sheppo 		statsp->brdcstrcv	= ldckp->brdcstrcv.value.ul;
47691991Sheppo 		statsp->brdcstxmt	= ldckp->brdcstxmt.value.ul;
47701991Sheppo 		statsp->norcvbuf	= ldckp->norcvbuf.value.ul;
47711991Sheppo 		statsp->noxmtbuf	= ldckp->noxmtbuf.value.ul;
47721991Sheppo 
47731991Sheppo 		statsp->tx_no_desc	= ldckp->tx_no_desc.value.ul;
4774*2336Snarayan 
47751991Sheppo 		statsp->rx_allocb_fail	= ldckp->rx_allocb_fail.value.ul;
4776*2336Snarayan 		statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul;
47771991Sheppo 		statsp->rx_lost_pkts	= ldckp->rx_lost_pkts.value.ul;
47781991Sheppo 
47791991Sheppo 		statsp->callbacks	= ldckp->callbacks.value.ul;
47801991Sheppo 		statsp->dring_data_acks	= ldckp->dring_data_acks.value.ul;
4781*2336Snarayan 		statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul;
4782*2336Snarayan 		statsp->dring_data_msgs	= ldckp->dring_data_msgs.value.ul;
47831991Sheppo 	}
47841991Sheppo 
47851991Sheppo 	return (VGEN_SUCCESS);
47861991Sheppo }
47871991Sheppo 
47881991Sheppo /* handler for error messages received from the peer ldc end-point */
47891991Sheppo static void
47901991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
47911991Sheppo {
47921991Sheppo 	_NOTE(ARGUNUSED(ldcp, tagp))
47931991Sheppo }
47941991Sheppo 
47951991Sheppo /* Check if the session id in the received message is valid */
47961991Sheppo static int
47971991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
47981991Sheppo {
47991991Sheppo 	if (tagp->vio_sid != ldcp->peer_sid) {
48001991Sheppo 		void *vnetp = LDC_TO_VNET(ldcp);
48011991Sheppo 		DWARN((vnetp,
48021991Sheppo 		    "sid mismatch: expected(%x), rcvd(%x)\n",
48031991Sheppo 		    ldcp->peer_sid, tagp->vio_sid));
48041991Sheppo 		return (VGEN_FAILURE);
48051991Sheppo 	}
48061991Sheppo 	else
48071991Sheppo 		return (VGEN_SUCCESS);
48081991Sheppo }
48091991Sheppo 
48101991Sheppo /* convert mac address from string to uint64_t */
48111991Sheppo static uint64_t
48121991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr)
48131991Sheppo {
48141991Sheppo 	uint64_t val = 0;
48151991Sheppo 	int i;
48161991Sheppo 
48171991Sheppo 	for (i = 0; i < ETHERADDRL; i++) {
48181991Sheppo 		val <<= 8;
48191991Sheppo 		val |= macaddr[i];
48201991Sheppo 	}
48211991Sheppo 
48221991Sheppo 	return (val);
48231991Sheppo }
48241991Sheppo 
48251991Sheppo /* convert mac address from uint64_t to string */
48261991Sheppo static int
48271991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
48281991Sheppo {
48291991Sheppo 	int i;
48301991Sheppo 	uint64_t value;
48311991Sheppo 
48321991Sheppo 	value = val;
48331991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
48341991Sheppo 		macaddr[i] = value & 0xFF;
48351991Sheppo 		value >>= 8;
48361991Sheppo 	}
48371991Sheppo 	return (VGEN_SUCCESS);
48381991Sheppo }
48391991Sheppo 
48401991Sheppo static caddr_t
48411991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf)
48421991Sheppo {
48431991Sheppo 	(void) sprintf(ebuf,
48441991Sheppo 		"%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
48451991Sheppo 	return (ebuf);
48461991Sheppo }
48471991Sheppo 
48481991Sheppo /* Handshake watchdog timeout handler */
48491991Sheppo static void
48501991Sheppo vgen_hwatchdog(void *arg)
48511991Sheppo {
48521991Sheppo 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
48531991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
48541991Sheppo 
48551991Sheppo 	DWARN((vnetp,
48561991Sheppo 	    "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
48571991Sheppo 	    ldcp->ldc_id, ldcp->hphase, ldcp->hstate));
48581991Sheppo 
48591991Sheppo 	mutex_enter(&ldcp->cblock);
48601991Sheppo 	ldcp->htid = 0;
48611991Sheppo 	vgen_handshake_retry(ldcp);
48621991Sheppo 	mutex_exit(&ldcp->cblock);
48631991Sheppo }
48641991Sheppo 
48651991Sheppo static void
48661991Sheppo vgen_print_hparams(vgen_hparams_t *hp)
48671991Sheppo {
48681991Sheppo 	uint8_t	addr[6];
48691991Sheppo 	char	ea[6];
48701991Sheppo 	ldc_mem_cookie_t *dc;
48711991Sheppo 
48721991Sheppo 	cmn_err(CE_CONT, "version_info:\n");
48731991Sheppo 	cmn_err(CE_CONT,
48741991Sheppo 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
48751991Sheppo 	    hp->ver_major, hp->ver_minor, hp->dev_class);
48761991Sheppo 
48771991Sheppo 	(void) vgen_macaddr_ultostr(hp->addr, addr);
48781991Sheppo 	cmn_err(CE_CONT, "attr_info:\n");
48791991Sheppo 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
48801991Sheppo 	    vgen_print_ethaddr(addr, ea));
48811991Sheppo 	cmn_err(CE_CONT,
48821991Sheppo 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
48831991Sheppo 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
48841991Sheppo 
48851991Sheppo 	dc = &hp->dring_cookie;
48861991Sheppo 	cmn_err(CE_CONT, "dring_info:\n");
48871991Sheppo 	cmn_err(CE_CONT,
48881991Sheppo 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
48891991Sheppo 	cmn_err(CE_CONT,
48901991Sheppo 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
48911991Sheppo 	    dc->addr, dc->size);
48921991Sheppo 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
48931991Sheppo }
48941991Sheppo 
48951991Sheppo static void
48961991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp)
48971991Sheppo {
48981991Sheppo 	vgen_hparams_t *hp;
48991991Sheppo 
49001991Sheppo 	cmn_err(CE_CONT, "Channel Information:\n");
49011991Sheppo 	cmn_err(CE_CONT,
49021991Sheppo 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
49031991Sheppo 	    ldcp->ldc_id, ldcp->ldc_status);
49041991Sheppo 	cmn_err(CE_CONT,
49051991Sheppo 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
49061991Sheppo 	    ldcp->local_sid, ldcp->peer_sid);
49071991Sheppo 	cmn_err(CE_CONT,
49081991Sheppo 	    "\thphase: 0x%x, hstate: 0x%x\n",
49091991Sheppo 	    ldcp->hphase, ldcp->hstate);
49101991Sheppo 
49111991Sheppo 	cmn_err(CE_CONT, "Local handshake params:\n");
49121991Sheppo 	hp = &ldcp->local_hparams;
49131991Sheppo 	vgen_print_hparams(hp);
49141991Sheppo 
49151991Sheppo 	cmn_err(CE_CONT, "Peer handshake params:\n");
49161991Sheppo 	hp = &ldcp->peer_hparams;
49171991Sheppo 	vgen_print_hparams(hp);
49181991Sheppo }
4919