xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_gen.c (revision 1991:f29baf5bf770)
1*1991Sheppo /*
2*1991Sheppo  * CDDL HEADER START
3*1991Sheppo  *
4*1991Sheppo  * The contents of this file are subject to the terms of the
5*1991Sheppo  * Common Development and Distribution License (the "License").
6*1991Sheppo  * You may not use this file except in compliance with the License.
7*1991Sheppo  *
8*1991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1991Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1991Sheppo  * See the License for the specific language governing permissions
11*1991Sheppo  * and limitations under the License.
12*1991Sheppo  *
13*1991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1991Sheppo  *
19*1991Sheppo  * CDDL HEADER END
20*1991Sheppo  */
21*1991Sheppo 
22*1991Sheppo /*
23*1991Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1991Sheppo  * Use is subject to license terms.
25*1991Sheppo  */
26*1991Sheppo 
27*1991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1991Sheppo 
29*1991Sheppo #include <sys/types.h>
30*1991Sheppo #include <sys/errno.h>
31*1991Sheppo #include <sys/param.h>
32*1991Sheppo #include <sys/stream.h>
33*1991Sheppo #include <sys/kmem.h>
34*1991Sheppo #include <sys/conf.h>
35*1991Sheppo #include <sys/devops.h>
36*1991Sheppo #include <sys/ksynch.h>
37*1991Sheppo #include <sys/stat.h>
38*1991Sheppo #include <sys/modctl.h>
39*1991Sheppo #include <sys/debug.h>
40*1991Sheppo #include <sys/ethernet.h>
41*1991Sheppo #include <sys/ddi.h>
42*1991Sheppo #include <sys/sunddi.h>
43*1991Sheppo #include <sys/strsun.h>
44*1991Sheppo #include <sys/note.h>
45*1991Sheppo #include <sys/mac.h>
46*1991Sheppo #include <sys/ldc.h>
47*1991Sheppo #include <sys/mach_descrip.h>
48*1991Sheppo #include <sys/mdeg.h>
49*1991Sheppo #include <sys/vio_mailbox.h>
50*1991Sheppo #include <sys/vio_common.h>
51*1991Sheppo #include <sys/vnet_common.h>
52*1991Sheppo #include <sys/vnet_gen.h>
53*1991Sheppo #include <sys/vnet_mailbox.h>
54*1991Sheppo 
55*1991Sheppo /*
56*1991Sheppo  * Implementation of the mac functionality for vnet using the
57*1991Sheppo  * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
58*1991Sheppo  */
59*1991Sheppo 
60*1991Sheppo /*
61*1991Sheppo  * Function prototypes.
62*1991Sheppo  */
63*1991Sheppo /* vgen proxy entry points */
64*1991Sheppo int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp,
65*1991Sheppo 	const uint8_t *macaddr, mac_t **vgenmacp);
66*1991Sheppo void vgen_uninit(void *arg);
67*1991Sheppo static int vgen_start(void *arg);
68*1991Sheppo static void vgen_stop(void *arg);
69*1991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
70*1991Sheppo static void vgen_resources(void *arg);
71*1991Sheppo static int vgen_multicst(void *arg, boolean_t add,
72*1991Sheppo 	const uint8_t *mca);
73*1991Sheppo static int vgen_promisc(void *arg, boolean_t on);
74*1991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
75*1991Sheppo static uint64_t vgen_stat(void *arg, enum mac_stat stat);
76*1991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp);
77*1991Sheppo 
78*1991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */
79*1991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
80*1991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
81*1991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
82*1991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
83*1991Sheppo void vnet_del_def_rte(void *arg);
84*1991Sheppo 
85*1991Sheppo /* vgen internal functions */
86*1991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
87*1991Sheppo static void vgen_port_detach(vgen_port_t *portp);
88*1991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
89*1991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
90*1991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
91*1991Sheppo 	int port_num);
92*1991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
93*1991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
94*1991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
95*1991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
96*1991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
97*1991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
98*1991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port);
99*1991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp);
100*1991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
101*1991Sheppo 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
102*1991Sheppo static uint64_t	vgen_port_stat(vgen_port_t *portp, enum mac_stat stat);
103*1991Sheppo 
104*1991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
105*1991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
106*1991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp);
107*1991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp);
108*1991Sheppo static void vgen_init_ports(vgen_t *vgenp);
109*1991Sheppo static void vgen_port_init(vgen_port_t *portp);
110*1991Sheppo static void vgen_uninit_ports(vgen_t *vgenp);
111*1991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
112*1991Sheppo static void vgen_init_ldcs(vgen_port_t *portp);
113*1991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp);
114*1991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
115*1991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
116*1991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp);
117*1991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp);
118*1991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp);
119*1991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp);
120*1991Sheppo static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, enum mac_stat stat);
121*1991Sheppo static void vgen_init_macp(vgen_t *vgenp, mac_t *macp);
122*1991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
123*1991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
124*1991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp);
125*1991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp);
126*1991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp);
127*1991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp);
128*1991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp);
129*1991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp);
130*1991Sheppo static void vgen_ldc_watchdog(void *arg);
131*1991Sheppo static void vgen_copymsg(mblk_t *mp, void *bufp);
132*1991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp);
133*1991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp);
134*1991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw);
135*1991Sheppo 
136*1991Sheppo /* vgen handshake functions */
137*1991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
138*1991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
139*1991Sheppo 	uint16_t ver_minor);
140*1991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp);
141*1991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
142*1991Sheppo 	boolean_t caller_holds_lock);
143*1991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
144*1991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
145*1991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp);
146*1991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
147*1991Sheppo static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start,
148*1991Sheppo 	uint32_t end, uint64_t next_txseq);
149*1991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
150*1991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
151*1991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp);
152*1991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp);
153*1991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp);
154*1991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp);
155*1991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp);
156*1991Sheppo static void vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
157*1991Sheppo 	vio_msg_tag_t *tagp);
158*1991Sheppo static void vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
159*1991Sheppo static void vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
160*1991Sheppo static void vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
161*1991Sheppo static void vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
162*1991Sheppo static void vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
163*1991Sheppo static void vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
164*1991Sheppo 	mblk_t **headp, mblk_t **tailp);
165*1991Sheppo static void vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
166*1991Sheppo 	mblk_t **headp, mblk_t **tailp);
167*1991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
168*1991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
169*1991Sheppo static uint64_t	vgen_macaddr_strtoul(const uint8_t *macaddr);
170*1991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr);
171*1991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
172*1991Sheppo static void vgen_hwatchdog(void *arg);
173*1991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
174*1991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp);
175*1991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp);
176*1991Sheppo 
177*1991Sheppo /*
178*1991Sheppo  * The handshake process consists of 5 phases defined below, with VH_PHASE0
179*1991Sheppo  * being the pre-handshake phase and VH_DONE is the phase to indicate
180*1991Sheppo  * successful completion of all phases.
181*1991Sheppo  * Each phase may have one to several handshake states which are required
182*1991Sheppo  * to complete successfully to move to the next phase.
183*1991Sheppo  * Refer to the functions vgen_handshake() and vgen_handshake_done() for
184*1991Sheppo  * more details.
185*1991Sheppo  */
186*1991Sheppo /* handshake phases */
187*1991Sheppo enum {	VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
188*1991Sheppo 
189*1991Sheppo /* handshake states */
190*1991Sheppo enum {
191*1991Sheppo 
192*1991Sheppo 	VER_INFO_SENT	=	0x1,
193*1991Sheppo 	VER_ACK_RCVD	=	0x2,
194*1991Sheppo 	VER_INFO_RCVD	=	0x4,
195*1991Sheppo 	VER_ACK_SENT	=	0x8,
196*1991Sheppo 	VER_NEGOTIATED	=	(VER_ACK_RCVD | VER_ACK_SENT),
197*1991Sheppo 
198*1991Sheppo 	ATTR_INFO_SENT	=	0x10,
199*1991Sheppo 	ATTR_ACK_RCVD	=	0x20,
200*1991Sheppo 	ATTR_INFO_RCVD	=	0x40,
201*1991Sheppo 	ATTR_ACK_SENT	=	0x80,
202*1991Sheppo 	ATTR_INFO_EXCHANGED	=	(ATTR_ACK_RCVD | ATTR_ACK_SENT),
203*1991Sheppo 
204*1991Sheppo 	DRING_INFO_SENT	=	0x100,
205*1991Sheppo 	DRING_ACK_RCVD	=	0x200,
206*1991Sheppo 	DRING_INFO_RCVD	=	0x400,
207*1991Sheppo 	DRING_ACK_SENT	=	0x800,
208*1991Sheppo 	DRING_INFO_EXCHANGED	=	(DRING_ACK_RCVD | DRING_ACK_SENT),
209*1991Sheppo 
210*1991Sheppo 	RDX_INFO_SENT	=	0x1000,
211*1991Sheppo 	RDX_ACK_RCVD	=	0x2000,
212*1991Sheppo 	RDX_INFO_RCVD	=	0x4000,
213*1991Sheppo 	RDX_ACK_SENT	=	0x8000,
214*1991Sheppo 	RDX_EXCHANGED	=	(RDX_ACK_RCVD | RDX_ACK_SENT)
215*1991Sheppo 
216*1991Sheppo };
217*1991Sheppo 
218*1991Sheppo #define	LDC_LOCK(ldcp)	\
219*1991Sheppo 				mutex_enter(&((ldcp)->cblock));\
220*1991Sheppo 				mutex_enter(&((ldcp)->txlock));\
221*1991Sheppo 				mutex_enter(&((ldcp)->tclock));
222*1991Sheppo #define	LDC_UNLOCK(ldcp)	\
223*1991Sheppo 				mutex_exit(&((ldcp)->tclock));\
224*1991Sheppo 				mutex_exit(&((ldcp)->txlock));\
225*1991Sheppo 				mutex_exit(&((ldcp)->cblock));
226*1991Sheppo 
227*1991Sheppo static struct ether_addr etherbroadcastaddr = {
228*1991Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
229*1991Sheppo };
230*1991Sheppo /*
231*1991Sheppo  * MIB II broadcast/multicast packets
232*1991Sheppo  */
233*1991Sheppo #define	IS_BROADCAST(ehp) \
234*1991Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
235*1991Sheppo #define	IS_MULTICAST(ehp) \
236*1991Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
237*1991Sheppo 
238*1991Sheppo /*
239*1991Sheppo  * Property names
240*1991Sheppo  */
241*1991Sheppo static char macaddr_propname[] = "mac-address";
242*1991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
243*1991Sheppo static char channel_propname[] = "channel-endpoint";
244*1991Sheppo static char reg_propname[] = "reg";
245*1991Sheppo static char port_propname[] = "port";
246*1991Sheppo static char swport_propname[] = "switch-port";
247*1991Sheppo static char id_propname[] = "id";
248*1991Sheppo 
249*1991Sheppo /* versions supported - in decreasing order */
250*1991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} };
251*1991Sheppo 
252*1991Sheppo /* Tunables */
253*1991Sheppo uint32_t vgen_hwd_interval = 1000;	/* handshake watchdog freq in msec */
254*1991Sheppo uint32_t vgen_max_hretries = 1;		/* max # of handshake retries */
255*1991Sheppo 
256*1991Sheppo uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
257*1991Sheppo 
258*1991Sheppo #ifdef DEBUG
259*1991Sheppo /* flags to simulate error conditions for debugging */
260*1991Sheppo int vgen_trigger_txtimeout = 0;
261*1991Sheppo int vgen_trigger_rxlost = 0;
262*1991Sheppo #endif
263*1991Sheppo 
264*1991Sheppo /* MD update matching structure */
265*1991Sheppo static md_prop_match_t	vport_prop_match[] = {
266*1991Sheppo 	{ MDET_PROP_VAL,	"id" },
267*1991Sheppo 	{ MDET_LIST_END,	NULL }
268*1991Sheppo };
269*1991Sheppo 
270*1991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
271*1991Sheppo 					vport_prop_match };
272*1991Sheppo 
273*1991Sheppo /* template for matching a particular vnet instance */
274*1991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
275*1991Sheppo 	{ MDET_PROP_STR,	"name",		"network" },
276*1991Sheppo 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
277*1991Sheppo 	{ MDET_LIST_END,	NULL,		NULL }
278*1991Sheppo };
279*1991Sheppo 
280*1991Sheppo #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
281*1991Sheppo 
282*1991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
283*1991Sheppo 
284*1991Sheppo /* externs */
285*1991Sheppo extern uint32_t vnet_ntxds;
286*1991Sheppo extern uint32_t vnet_reclaim_lowat;
287*1991Sheppo extern uint32_t vnet_reclaim_hiwat;
288*1991Sheppo extern uint32_t vnet_ldcwd_interval;
289*1991Sheppo extern uint32_t vnet_ldcwd_txtimeout;
290*1991Sheppo extern uint32_t vnet_ldc_qlen;
291*1991Sheppo extern int _vnet_dbglevel;
292*1991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...);
293*1991Sheppo 
294*1991Sheppo #ifdef DEBUG
295*1991Sheppo 
296*1991Sheppo /*
297*1991Sheppo  * XXX: definitions below need to be in sync with those in vnet.c
298*1991Sheppo  */
299*1991Sheppo 
300*1991Sheppo /*
301*1991Sheppo  * debug levels:
302*1991Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
303*1991Sheppo  * DBG_LEVEL2:	Info messages
304*1991Sheppo  * DBG_LEVEL3:	Warning messages
305*1991Sheppo  * DBG_LEVEL4:	Error messages
306*1991Sheppo  */
307*1991Sheppo 
308*1991Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
309*1991Sheppo 	    DBG_LEVEL4 = 0x08 };
310*1991Sheppo 
311*1991Sheppo #define	DBG1(_s)	do {						\
312*1991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
313*1991Sheppo 					_vnetdebug_printf _s;		\
314*1991Sheppo 			    }					\
315*1991Sheppo 			_NOTE(CONSTCOND) } while (0)
316*1991Sheppo 
317*1991Sheppo #define	DBG2(_s)	do {						\
318*1991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
319*1991Sheppo 					_vnetdebug_printf _s;		\
320*1991Sheppo 			    }					\
321*1991Sheppo 			_NOTE(CONSTCOND) } while (0)
322*1991Sheppo 
323*1991Sheppo #define	DWARN(_s)	do {						\
324*1991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
325*1991Sheppo 					_vnetdebug_printf _s;		\
326*1991Sheppo 			    }					\
327*1991Sheppo 			_NOTE(CONSTCOND) } while (0)
328*1991Sheppo 
329*1991Sheppo #define	DERR(_s)	do {						\
330*1991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
331*1991Sheppo 					_vnetdebug_printf _s;		\
332*1991Sheppo 			    }					\
333*1991Sheppo 			_NOTE(CONSTCOND) } while (0)
334*1991Sheppo 
335*1991Sheppo #else
336*1991Sheppo 
337*1991Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
338*1991Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
339*1991Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
340*1991Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
341*1991Sheppo 
342*1991Sheppo #endif
343*1991Sheppo 
344*1991Sheppo #ifdef DEBUG
345*1991Sheppo 
346*1991Sheppo /* simulate handshake error conditions for debug */
347*1991Sheppo uint32_t vgen_hdbg;
348*1991Sheppo #define	HDBG_VERSION	0x1
349*1991Sheppo #define	HDBG_TIMEOUT	0x2
350*1991Sheppo #define	HDBG_BAD_SID	0x4
351*1991Sheppo #define	HDBG_OUT_STATE	0x8
352*1991Sheppo 
353*1991Sheppo #if 0
354*1991Sheppo /* debug version negotiation, need to redefine VGEN_NUM_VER */
355*1991Sheppo vgen_ver_t dbg_vgen_versions[VGEN_NUM_VER] =
356*1991Sheppo 	{ {5, 0}, {3, 0}, {2, 1}, {1, 2}, {1, 1} };
357*1991Sheppo #endif
358*1991Sheppo 
359*1991Sheppo #endif
360*1991Sheppo 
361*1991Sheppo /*
362*1991Sheppo  * vgen_init() is called by an instance of vnet driver to initialize the
363*1991Sheppo  * corresponding generic proxy transport layer. The arguments passed by vnet
364*1991Sheppo  * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
365*1991Sheppo  * mac_t of the vnet device, mac address of the vnet device, and a pointer to
366*1991Sheppo  * the mac_t of the generic transport is returned in the last argument.
367*1991Sheppo  */
368*1991Sheppo int
369*1991Sheppo vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp,
370*1991Sheppo 	const uint8_t *macaddr, mac_t **vgenmacp)
371*1991Sheppo {
372*1991Sheppo 	vgen_t *vgenp;
373*1991Sheppo 	mac_t *macp;
374*1991Sheppo 	int instance;
375*1991Sheppo 
376*1991Sheppo 	if ((vnetp == NULL) || (vnetdip == NULL) ||(vnetmacp == NULL))
377*1991Sheppo 		return (DDI_FAILURE);
378*1991Sheppo 
379*1991Sheppo 	instance = ddi_get_instance(vnetdip);
380*1991Sheppo 
381*1991Sheppo 	DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance));
382*1991Sheppo 
383*1991Sheppo 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
384*1991Sheppo 
385*1991Sheppo 	vgenp->vnetp = vnetp;
386*1991Sheppo 	vgenp->vnetdip = vnetdip;
387*1991Sheppo 	vgenp->vnetmacp = vnetmacp;
388*1991Sheppo 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
389*1991Sheppo 
390*1991Sheppo 	/* allocate multicast table */
391*1991Sheppo 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
392*1991Sheppo 	    sizeof (struct ether_addr), KM_SLEEP);
393*1991Sheppo 	vgenp->mccount = 0;
394*1991Sheppo 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
395*1991Sheppo 
396*1991Sheppo 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
397*1991Sheppo 
398*1991Sheppo 	/* register with MD event generator */
399*1991Sheppo 	if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) {
400*1991Sheppo 		mutex_destroy(&vgenp->lock);
401*1991Sheppo 		kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
402*1991Sheppo 		    sizeof (struct ether_addr));
403*1991Sheppo 		KMEM_FREE(vgenp);
404*1991Sheppo 		return (DDI_FAILURE);
405*1991Sheppo 	}
406*1991Sheppo 
407*1991Sheppo 	macp = &vgenp->vgenmac;
408*1991Sheppo 	vgen_init_macp(vgenp, macp);
409*1991Sheppo 
410*1991Sheppo 	/* register mac_t of this vgen_t with vnet */
411*1991Sheppo 	*vgenmacp = macp;
412*1991Sheppo 
413*1991Sheppo 	DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance));
414*1991Sheppo 	return (DDI_SUCCESS);
415*1991Sheppo }
416*1991Sheppo 
417*1991Sheppo /*
418*1991Sheppo  * Called by vnet to undo the initializations done by vgen_init().
419*1991Sheppo  * The handle provided by generic transport during vgen_init() is the argument.
420*1991Sheppo  */
421*1991Sheppo void
422*1991Sheppo vgen_uninit(void *arg)
423*1991Sheppo {
424*1991Sheppo 	vgen_t	*vgenp = (vgen_t *)arg;
425*1991Sheppo 	void	*vnetp;
426*1991Sheppo 	int instance;
427*1991Sheppo 
428*1991Sheppo 	if (vgenp == NULL)
429*1991Sheppo 		return;
430*1991Sheppo 
431*1991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
432*1991Sheppo 	vnetp = vgenp->vnetp;
433*1991Sheppo 
434*1991Sheppo 	DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance));
435*1991Sheppo 
436*1991Sheppo 	/* unregister with MD event generator */
437*1991Sheppo 	vgen_mdeg_unreg(vgenp);
438*1991Sheppo 
439*1991Sheppo 	mutex_enter(&vgenp->lock);
440*1991Sheppo 
441*1991Sheppo 	/* detach all ports from the device */
442*1991Sheppo 	vgen_detach_ports(vgenp);
443*1991Sheppo 
444*1991Sheppo 	/* free multicast table */
445*1991Sheppo 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
446*1991Sheppo 
447*1991Sheppo 	mutex_exit(&vgenp->lock);
448*1991Sheppo 
449*1991Sheppo 	mutex_destroy(&vgenp->lock);
450*1991Sheppo 
451*1991Sheppo 	KMEM_FREE(vgenp);
452*1991Sheppo 
453*1991Sheppo 	DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance));
454*1991Sheppo }
455*1991Sheppo 
456*1991Sheppo /* enable transmit/receive for the device */
457*1991Sheppo static int
458*1991Sheppo vgen_start(void *arg)
459*1991Sheppo {
460*1991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
461*1991Sheppo 
462*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: enter\n"));
463*1991Sheppo 
464*1991Sheppo 	mutex_enter(&vgenp->lock);
465*1991Sheppo 	vgen_init_ports(vgenp);
466*1991Sheppo 	vgenp->flags |= VGEN_STARTED;
467*1991Sheppo 	mutex_exit(&vgenp->lock);
468*1991Sheppo 
469*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_start: exit\n"));
470*1991Sheppo 	return (DDI_SUCCESS);
471*1991Sheppo }
472*1991Sheppo 
473*1991Sheppo /* stop transmit/receive */
474*1991Sheppo static void
475*1991Sheppo vgen_stop(void *arg)
476*1991Sheppo {
477*1991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
478*1991Sheppo 
479*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: enter\n"));
480*1991Sheppo 
481*1991Sheppo 	mutex_enter(&vgenp->lock);
482*1991Sheppo 	vgen_uninit_ports(vgenp);
483*1991Sheppo 	vgenp->flags &= ~(VGEN_STARTED);
484*1991Sheppo 	mutex_exit(&vgenp->lock);
485*1991Sheppo 
486*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_stop: exit\n"));
487*1991Sheppo }
488*1991Sheppo 
489*1991Sheppo /* vgen transmit function */
490*1991Sheppo static mblk_t *
491*1991Sheppo vgen_tx(void *arg, mblk_t *mp)
492*1991Sheppo {
493*1991Sheppo 	vgen_port_t *portp;
494*1991Sheppo 	int status;
495*1991Sheppo 
496*1991Sheppo 	portp = (vgen_port_t *)arg;
497*1991Sheppo 	status = vgen_portsend(portp, mp);
498*1991Sheppo 	if (status != VGEN_SUCCESS) {
499*1991Sheppo 		/* failure */
500*1991Sheppo 		return (mp);
501*1991Sheppo 	}
502*1991Sheppo 	/* success */
503*1991Sheppo 	return (NULL);
504*1991Sheppo }
505*1991Sheppo 
506*1991Sheppo /* transmit packets over the given port */
507*1991Sheppo static int
508*1991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
509*1991Sheppo {
510*1991Sheppo 	vgen_ldclist_t	*ldclp;
511*1991Sheppo 	vgen_ldc_t *ldcp;
512*1991Sheppo 	vgen_t *vgenp;
513*1991Sheppo 	int status;
514*1991Sheppo 
515*1991Sheppo 	vgenp = portp->vgenp;
516*1991Sheppo 	ldclp = &portp->ldclist;
517*1991Sheppo 	READ_ENTER(&ldclp->rwlock);
518*1991Sheppo 	/*
519*1991Sheppo 	 * XXX - for now, we have a single channel.
520*1991Sheppo 	 */
521*1991Sheppo 	if (ldclp->headp == NULL) {
522*1991Sheppo 		DWARN((vgenp->vnetp, "vgen_portsend: dropping packet\n"));
523*1991Sheppo 		RW_EXIT(&ldclp->rwlock);
524*1991Sheppo 		return (VGEN_FAILURE);
525*1991Sheppo 	}
526*1991Sheppo 	ldcp = ldclp->headp;
527*1991Sheppo 
528*1991Sheppo 	if (ldcp->need_resched) {
529*1991Sheppo 		/* out of tx resources, see vgen_ldcsend() for details. */
530*1991Sheppo 		DWARN((vgenp->vnetp, "vgen_portsend: dropping packet...\n"));
531*1991Sheppo 
532*1991Sheppo 		mutex_enter(&ldcp->txlock);
533*1991Sheppo 		ldcp->statsp->tx_no_desc++;
534*1991Sheppo 		mutex_exit(&ldcp->txlock);
535*1991Sheppo 
536*1991Sheppo 		RW_EXIT(&ldclp->rwlock);
537*1991Sheppo 		freemsg(mp);
538*1991Sheppo 		return (VGEN_SUCCESS);
539*1991Sheppo 	}
540*1991Sheppo 
541*1991Sheppo 	status  = vgen_ldcsend(ldcp, mp);
542*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
543*1991Sheppo 
544*1991Sheppo 	if (status != VGEN_TX_SUCCESS)
545*1991Sheppo 		return (VGEN_FAILURE);
546*1991Sheppo 
547*1991Sheppo 	return (VGEN_SUCCESS);
548*1991Sheppo }
549*1991Sheppo 
550*1991Sheppo /* channel transmit function */
551*1991Sheppo static int
552*1991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp)
553*1991Sheppo {
554*1991Sheppo 	void		*vnetp;
555*1991Sheppo 	size_t		size;
556*1991Sheppo 	uint64_t	datalen;
557*1991Sheppo 	uchar_t		*rptr;
558*1991Sheppo 	mblk_t 		*bp = NULL;
559*1991Sheppo 	int		rv;
560*1991Sheppo 	uint32_t	i;
561*1991Sheppo 	uint32_t	start;
562*1991Sheppo 	uint32_t	end;
563*1991Sheppo 	int		txpending = 0;
564*1991Sheppo 	int		ci;
565*1991Sheppo 	uint32_t	ncookies;
566*1991Sheppo 	uint64_t	nc;
567*1991Sheppo 	vgen_private_desc_t	*tbufp;
568*1991Sheppo 	vgen_private_desc_t	*ntbufp;
569*1991Sheppo 	vnet_public_desc_t	*txdp;
570*1991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
571*1991Sheppo 	vgen_stats_t		*statsp;
572*1991Sheppo 	struct ether_header	*ehp;
573*1991Sheppo 	boolean_t	is_bcast = B_FALSE;
574*1991Sheppo 	boolean_t	is_mcast = B_FALSE;
575*1991Sheppo 	boolean_t	reclaim = B_FALSE;
576*1991Sheppo 	boolean_t	need_intr = B_FALSE;
577*1991Sheppo 	boolean_t	err = B_FALSE;
578*1991Sheppo 
579*1991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
580*1991Sheppo 	statsp = ldcp->statsp;
581*1991Sheppo 	DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id));
582*1991Sheppo 
583*1991Sheppo 	/* drop the packet if handshake is not done or ldc is not up */
584*1991Sheppo 	if ((ldcp->hphase != VH_DONE) || (ldcp->ldc_status != LDC_UP)) {
585*1991Sheppo 		DWARN((vnetp,
586*1991Sheppo 		    "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
587*1991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
588*1991Sheppo 		freemsg(mp);
589*1991Sheppo 		return (VGEN_TX_SUCCESS);
590*1991Sheppo 	}
591*1991Sheppo 
592*1991Sheppo 	size = msgsize(mp);
593*1991Sheppo 	if (size > (size_t)ETHERMAX) {
594*1991Sheppo 		DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n",
595*1991Sheppo 		    ldcp->ldc_id, size));
596*1991Sheppo 		freemsg(mp);
597*1991Sheppo 		return (VGEN_TX_SUCCESS);
598*1991Sheppo 	}
599*1991Sheppo 	if ((size < (size_t)ETHERMIN) ||	/* needs padding to ETHERMIN */
600*1991Sheppo 	    (mp->b_cont) ||			/* more than 1 mblk */
601*1991Sheppo 	    ((uintptr_t)mp->b_rptr & 0x7) ||	/* data not 8 byte aligned */
602*1991Sheppo 	    ((mp->b_wptr - mp->b_rptr) & 0x7)) { /* datalen not multiple of 8 */
603*1991Sheppo 		if (size < ETHERMIN)
604*1991Sheppo 			size = ETHERMIN;
605*1991Sheppo 		/*
606*1991Sheppo 		 * The data buffer returned by allocb(9F) is 8byte aligned.
607*1991Sheppo 		 * We allocate extra 8 bytes to ensure size is multiple of
608*1991Sheppo 		 * 8 bytes for ldc_mem_bind_handle().
609*1991Sheppo 		 */
610*1991Sheppo 		bp = allocb(size + 8, BPRI_MED);
611*1991Sheppo 		if (bp == NULL) {
612*1991Sheppo 			/* drop the packet */
613*1991Sheppo 			freemsg(mp);
614*1991Sheppo 			mutex_enter(&ldcp->txlock);
615*1991Sheppo 			statsp->tx_allocb_fail++;
616*1991Sheppo 			mutex_exit(&ldcp->txlock);
617*1991Sheppo 			return (VGEN_TX_SUCCESS);
618*1991Sheppo 		}
619*1991Sheppo 		vgen_copymsg(mp, bp->b_rptr);
620*1991Sheppo 		bp->b_wptr += size;
621*1991Sheppo 		datalen = size;		/* actual data length without pad */
622*1991Sheppo 		size = (datalen + 7) & ~7;
623*1991Sheppo 		bp->b_wptr += (size - datalen);
624*1991Sheppo 	} else { /* size/alignment are ok */
625*1991Sheppo 		datalen = size;
626*1991Sheppo 	}
627*1991Sheppo 
628*1991Sheppo 	mutex_enter(&ldcp->txlock);
629*1991Sheppo 
630*1991Sheppo 	/*  check if the channel is still up & running */
631*1991Sheppo 	if ((ldcp->hphase != VH_DONE) || (ldcp->ldc_status != LDC_UP)) {
632*1991Sheppo 		DWARN((vnetp,
633*1991Sheppo 		    "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
634*1991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
635*1991Sheppo 		err = B_TRUE;
636*1991Sheppo 		goto vgen_tx_exit;
637*1991Sheppo 	}
638*1991Sheppo 
639*1991Sheppo 	/*
640*1991Sheppo 	 * allocate a descriptor
641*1991Sheppo 	 */
642*1991Sheppo 	tbufp = ldcp->next_tbufp;
643*1991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
644*1991Sheppo 	if (tbufp->flags != VGEN_PRIV_DESC_FREE ||
645*1991Sheppo 	    ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
646*1991Sheppo 
647*1991Sheppo 		mutex_enter(&ldcp->tclock);
648*1991Sheppo 		if (ntbufp == ldcp->cur_tbufp)
649*1991Sheppo 			ldcp->need_resched = B_TRUE;
650*1991Sheppo 		mutex_exit(&ldcp->tclock);
651*1991Sheppo 
652*1991Sheppo 		statsp->tx_no_desc++;
653*1991Sheppo 		mutex_exit(&ldcp->txlock);
654*1991Sheppo 		if (bp)
655*1991Sheppo 			freemsg(bp);
656*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE
657*1991Sheppo 		/*
658*1991Sheppo 		 * This cflag is disabled by default. This can be enabled if we
659*1991Sheppo 		 * want to return failure to the mac layer when we run out of
660*1991Sheppo 		 * descriptors and use mac_tx_update() to restart tx when
661*1991Sheppo 		 * descriptors become available. However, stopping tx would
662*1991Sheppo 		 * affect traffic going over other ports, as upper mac layer
663*1991Sheppo 		 * has no concept of multiple ports within a device.
664*1991Sheppo 		 * So currently, to avoid this, drop packets when we run out
665*1991Sheppo 		 * of descrs and just return success. See the corresponding
666*1991Sheppo 		 * code in vgen_portsend() and vgen_reclaim_dring().
667*1991Sheppo 		 */
668*1991Sheppo 		return (VGEN_TX_NORESOURCES);
669*1991Sheppo #else
670*1991Sheppo 		freemsg(mp);	/* drop the packet */
671*1991Sheppo 		return (VGEN_TX_SUCCESS);
672*1991Sheppo #endif
673*1991Sheppo 	}
674*1991Sheppo 
675*1991Sheppo 	txpending = vgen_num_txpending(ldcp);
676*1991Sheppo 	if (txpending >= ldcp->reclaim_hiwat) {
677*1991Sheppo 		/*
678*1991Sheppo 		 * if num of pending transmits is more than hiwat,
679*1991Sheppo 		 * reclaim now and also enable ack bit.
680*1991Sheppo 		 */
681*1991Sheppo 		reclaim = B_TRUE;
682*1991Sheppo 		need_intr = B_TRUE;
683*1991Sheppo 	} else {
684*1991Sheppo 		if (txpending >= ldcp->reclaim_lowat) {
685*1991Sheppo 			/*
686*1991Sheppo 			 * if the num of pending transmits is more than lowat
687*1991Sheppo 			 * enable ack bit in the descr and reclaim in intr().
688*1991Sheppo 			 */
689*1991Sheppo 			need_intr = B_TRUE;
690*1991Sheppo 		}
691*1991Sheppo 	}
692*1991Sheppo 
693*1991Sheppo 	i = tbufp - ldcp->tbufp;
694*1991Sheppo 
695*1991Sheppo 	rptr = bp ? (bp->b_rptr) : (mp->b_rptr);
696*1991Sheppo 	ci = 0;
697*1991Sheppo 	rv = ldc_mem_bind_handle(tbufp->memhandle, (caddr_t)rptr, size,
698*1991Sheppo 		LDC_SHADOW_MAP, LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
699*1991Sheppo 	if (rv != 0) {
700*1991Sheppo 		DWARN((vnetp, "vgen_ldcsend: id(%lx)ldc_mem_bind_handle failed"
701*1991Sheppo 		    " rv(%d) tbufi(%d)\n", ldcp->ldc_id, rv, i));
702*1991Sheppo 		err = B_TRUE;
703*1991Sheppo 		statsp->oerrors++;
704*1991Sheppo 		goto vgen_tx_exit;
705*1991Sheppo 	}
706*1991Sheppo 
707*1991Sheppo 	if ((ncookies < 0) || (ncookies > (uint64_t)MAX_COOKIES)) {
708*1991Sheppo 		DWARN((vnetp,
709*1991Sheppo 		    "vgen_ldcsend: id(%lx)ldc_mem_bind_handle returned"
710*1991Sheppo 		    " invalid cookies (%d)\n", ldcp->ldc_id, ncookies));
711*1991Sheppo 		err = B_TRUE;
712*1991Sheppo 		statsp->oerrors++;
713*1991Sheppo 		(void) ldc_mem_unbind_handle(tbufp->memhandle);
714*1991Sheppo 		goto vgen_tx_exit;
715*1991Sheppo 	}
716*1991Sheppo 
717*1991Sheppo 	if (ncookies > 1) {
718*1991Sheppo 		nc = ncookies - 1;
719*1991Sheppo 		while (nc) {
720*1991Sheppo 			ci++;
721*1991Sheppo 			rv = ldc_mem_nextcookie(tbufp->memhandle,
722*1991Sheppo 			    &(tbufp->memcookie[ci]));
723*1991Sheppo 			if (rv != 0) {
724*1991Sheppo 				DWARN((vnetp,
725*1991Sheppo 				    "vgen_ldcsend: ldc_mem_nextcookie"
726*1991Sheppo 				    " err(%d)\n", rv));
727*1991Sheppo 				err = B_TRUE;
728*1991Sheppo 				statsp->oerrors++;
729*1991Sheppo 				(void) ldc_mem_unbind_handle(tbufp->memhandle);
730*1991Sheppo 				goto vgen_tx_exit;
731*1991Sheppo 			}
732*1991Sheppo 			nc--;
733*1991Sheppo 		}
734*1991Sheppo 	}
735*1991Sheppo 
736*1991Sheppo 	ehp = (struct ether_header *)rptr;
737*1991Sheppo 	is_bcast = IS_BROADCAST(ehp);
738*1991Sheppo 	is_mcast = IS_MULTICAST(ehp);
739*1991Sheppo 	/* save the packet, free when the descr done flag is set */
740*1991Sheppo 	tbufp->mp = (bp ? bp : mp);
741*1991Sheppo 	tbufp->flags = VGEN_PRIV_DESC_BUSY;
742*1991Sheppo 	tbufp->datalen = datalen;
743*1991Sheppo 	tbufp->ncookies = ncookies;
744*1991Sheppo 	tbufp->seqnum = ldcp->next_txseq;
745*1991Sheppo 
746*1991Sheppo 	/* initialize the corresponding public descriptor (txd) */
747*1991Sheppo 	txdp = tbufp->descp;
748*1991Sheppo 	hdrp = &txdp->hdr;
749*1991Sheppo 	hdrp->dstate = VIO_DESC_READY;
750*1991Sheppo 	if (need_intr)
751*1991Sheppo 		hdrp->ack = B_TRUE;
752*1991Sheppo 	txdp->nbytes = datalen;
753*1991Sheppo 	txdp->ncookies = ncookies;
754*1991Sheppo 	bcopy((tbufp->memcookie), (txdp->memcookie),
755*1991Sheppo 	    ncookies * sizeof (ldc_mem_cookie_t));
756*1991Sheppo 
757*1991Sheppo 	/* send dring datamsg to the peer */
758*1991Sheppo 	start = end = i;
759*1991Sheppo 	rv = vgen_send_dring_data(ldcp, start, end, ldcp->next_txseq);
760*1991Sheppo 	if (rv != 0) {
761*1991Sheppo 		/* vgen_send_dring_data() error: drop the packet */
762*1991Sheppo 		DWARN((vnetp,
763*1991Sheppo 		    "vgen_ldcsend: vgen_send_dring_data():  failed: "
764*1991Sheppo 		    "id(%lx) rv(%d) len (%d)\n", ldcp->ldc_id, rv, datalen));
765*1991Sheppo 		(void) ldc_mem_unbind_handle(tbufp->memhandle);
766*1991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;	/* free tbuf */
767*1991Sheppo 		hdrp->dstate = VIO_DESC_FREE;	/* free txd */
768*1991Sheppo 		hdrp->ack = B_FALSE;
769*1991Sheppo 		statsp->oerrors++;
770*1991Sheppo 		err = B_TRUE;
771*1991Sheppo 		goto vgen_tx_exit;
772*1991Sheppo 	}
773*1991Sheppo 
774*1991Sheppo 	/* update next available tbuf in the ring */
775*1991Sheppo 	ldcp->next_tbufp = ntbufp;
776*1991Sheppo 	/* update tx seqnum and index */
777*1991Sheppo 	ldcp->next_txseq++;
778*1991Sheppo 	INCR_TXI(ldcp->next_txi, ldcp);
779*1991Sheppo 
780*1991Sheppo 	/* update stats */
781*1991Sheppo 	statsp->opackets++;
782*1991Sheppo 	statsp->obytes += datalen;
783*1991Sheppo 	if (is_bcast)
784*1991Sheppo 		statsp->brdcstxmt++;
785*1991Sheppo 	else if (is_mcast)
786*1991Sheppo 		statsp->multixmt++;
787*1991Sheppo 
788*1991Sheppo vgen_tx_exit:
789*1991Sheppo 	mutex_exit(&ldcp->txlock);
790*1991Sheppo 
791*1991Sheppo 	if (reclaim) {
792*1991Sheppo 		vgen_reclaim(ldcp);
793*1991Sheppo 	}
794*1991Sheppo 	DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id));
795*1991Sheppo 
796*1991Sheppo 	if (err) {
797*1991Sheppo 		if (bp)
798*1991Sheppo 			freemsg(bp);
799*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE
800*1991Sheppo 		return (VGEN_TX_FAILURE);	/* transmit failed */
801*1991Sheppo #else
802*1991Sheppo 		freemsg(mp);			/* drop the packet */
803*1991Sheppo 		return (VGEN_TX_SUCCESS);
804*1991Sheppo #endif
805*1991Sheppo 	} else {
806*1991Sheppo 		if (bp)	/* free original pkt, copy is in bp */
807*1991Sheppo 			freemsg(mp);
808*1991Sheppo 		return (VGEN_TX_SUCCESS);
809*1991Sheppo 	}
810*1991Sheppo }
811*1991Sheppo 
812*1991Sheppo /* register resources */
813*1991Sheppo static void
814*1991Sheppo vgen_resources(void *arg)
815*1991Sheppo {
816*1991Sheppo 	vgen_t *vgenp;
817*1991Sheppo 	mac_rx_fifo_t mrf;
818*1991Sheppo 
819*1991Sheppo 	vgenp = (vgen_t *)arg;
820*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_resources: enter\n"));
821*1991Sheppo 
822*1991Sheppo 	mrf.mrf_type = MAC_RX_FIFO;
823*1991Sheppo 	mrf.mrf_blank = NULL;
824*1991Sheppo 	mrf.mrf_arg = NULL;
825*1991Sheppo 	mrf.mrf_normal_blank_time = 0;
826*1991Sheppo 	mrf.mrf_normal_pkt_count = 0;
827*1991Sheppo 	vgenp->mrh = mac_resource_add(vgenp->vnetmacp, (mac_resource_t *)&mrf);
828*1991Sheppo 
829*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_resources: exit\n"));
830*1991Sheppo }
831*1991Sheppo 
832*1991Sheppo /* enable/disable a multicast address */
833*1991Sheppo static int
834*1991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
835*1991Sheppo {
836*1991Sheppo 	vgen_t			*vgenp;
837*1991Sheppo 	vnet_mcast_msg_t	mcastmsg;
838*1991Sheppo 	vio_msg_tag_t		*tagp;
839*1991Sheppo 	vgen_port_t		*portp;
840*1991Sheppo 	vgen_portlist_t		*plistp;
841*1991Sheppo 	vgen_ldc_t		*ldcp;
842*1991Sheppo 	vgen_ldclist_t		*ldclp;
843*1991Sheppo 	void			*vnetp;
844*1991Sheppo 	struct ether_addr	*addrp;
845*1991Sheppo 	int			rv;
846*1991Sheppo 	uint32_t		i;
847*1991Sheppo 
848*1991Sheppo 	vgenp = (vgen_t *)arg;
849*1991Sheppo 	vnetp = vgenp->vnetp;
850*1991Sheppo 	addrp = (struct ether_addr *)mca;
851*1991Sheppo 	tagp = &mcastmsg.tag;
852*1991Sheppo 	bzero(&mcastmsg, sizeof (mcastmsg));
853*1991Sheppo 
854*1991Sheppo 	mutex_enter(&vgenp->lock);
855*1991Sheppo 
856*1991Sheppo 	plistp = &(vgenp->vgenports);
857*1991Sheppo 
858*1991Sheppo 	READ_ENTER(&plistp->rwlock);
859*1991Sheppo 
860*1991Sheppo 	portp = vgenp->vsw_portp;
861*1991Sheppo 	if (portp == NULL) {
862*1991Sheppo 		RW_EXIT(&plistp->rwlock);
863*1991Sheppo 		goto vgen_mcast_exit;
864*1991Sheppo 	}
865*1991Sheppo 	ldclp = &portp->ldclist;
866*1991Sheppo 
867*1991Sheppo 	READ_ENTER(&ldclp->rwlock);
868*1991Sheppo 
869*1991Sheppo 	ldcp = ldclp->headp;
870*1991Sheppo 	if (ldcp == NULL) {
871*1991Sheppo 		RW_EXIT(&ldclp->rwlock);
872*1991Sheppo 		RW_EXIT(&plistp->rwlock);
873*1991Sheppo 		goto vgen_mcast_exit;
874*1991Sheppo 	}
875*1991Sheppo 
876*1991Sheppo 	mutex_enter(&ldcp->cblock);
877*1991Sheppo 
878*1991Sheppo 	if (ldcp->hphase == VH_DONE) {
879*1991Sheppo 		/*
880*1991Sheppo 		 * If handshake is done, send a msg to vsw to add/remove
881*1991Sheppo 		 * the multicast address.
882*1991Sheppo 		 */
883*1991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
884*1991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
885*1991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
886*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
887*1991Sheppo 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
888*1991Sheppo 		mcastmsg.set = add;
889*1991Sheppo 		mcastmsg.count = 1;
890*1991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
891*1991Sheppo 		    B_FALSE);
892*1991Sheppo 		if (rv != VGEN_SUCCESS) {
893*1991Sheppo 			DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed"
894*1991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
895*1991Sheppo 		}
896*1991Sheppo 	} else {
897*1991Sheppo 		/* set the flag to send a msg to vsw after handshake is done */
898*1991Sheppo 		ldcp->need_mcast_sync = B_TRUE;
899*1991Sheppo 	}
900*1991Sheppo 
901*1991Sheppo 	mutex_exit(&ldcp->cblock);
902*1991Sheppo 
903*1991Sheppo 	if (add) {
904*1991Sheppo 
905*1991Sheppo 		/* expand multicast table if necessary */
906*1991Sheppo 		if (vgenp->mccount >= vgenp->mcsize) {
907*1991Sheppo 			struct ether_addr	*newtab;
908*1991Sheppo 			uint32_t		newsize;
909*1991Sheppo 
910*1991Sheppo 
911*1991Sheppo 			newsize = vgenp->mcsize * 2;
912*1991Sheppo 
913*1991Sheppo 			newtab = kmem_zalloc(newsize *
914*1991Sheppo 			    sizeof (struct ether_addr), KM_NOSLEEP);
915*1991Sheppo 
916*1991Sheppo 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
917*1991Sheppo 			    sizeof (struct ether_addr));
918*1991Sheppo 			kmem_free(vgenp->mctab,
919*1991Sheppo 			    vgenp->mcsize * sizeof (struct ether_addr));
920*1991Sheppo 
921*1991Sheppo 			vgenp->mctab = newtab;
922*1991Sheppo 			vgenp->mcsize = newsize;
923*1991Sheppo 		}
924*1991Sheppo 
925*1991Sheppo 		/* add address to the table */
926*1991Sheppo 		vgenp->mctab[vgenp->mccount++] = *addrp;
927*1991Sheppo 
928*1991Sheppo 	} else {
929*1991Sheppo 
930*1991Sheppo 		/* delete address from the table */
931*1991Sheppo 		for (i = 0; i < vgenp->mccount; i++) {
932*1991Sheppo 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
933*1991Sheppo 
934*1991Sheppo 				/*
935*1991Sheppo 				 * If there's more than one address in this
936*1991Sheppo 				 * table, delete the unwanted one by moving
937*1991Sheppo 				 * the last one in the list over top of it;
938*1991Sheppo 				 * otherwise, just remove it.
939*1991Sheppo 				 */
940*1991Sheppo 				if (vgenp->mccount > 1) {
941*1991Sheppo 					vgenp->mctab[i] =
942*1991Sheppo 						vgenp->mctab[vgenp->mccount-1];
943*1991Sheppo 				}
944*1991Sheppo 				vgenp->mccount--;
945*1991Sheppo 				break;
946*1991Sheppo 			}
947*1991Sheppo 		}
948*1991Sheppo 	}
949*1991Sheppo 
950*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
951*1991Sheppo 	RW_EXIT(&plistp->rwlock);
952*1991Sheppo 
953*1991Sheppo vgen_mcast_exit:
954*1991Sheppo 	mutex_exit(&vgenp->lock);
955*1991Sheppo 	return (DDI_SUCCESS);
956*1991Sheppo }
957*1991Sheppo 
958*1991Sheppo /* set or clear promiscuous mode on the device */
959*1991Sheppo static int
960*1991Sheppo vgen_promisc(void *arg, boolean_t on)
961*1991Sheppo {
962*1991Sheppo 	_NOTE(ARGUNUSED(arg, on))
963*1991Sheppo 	return (DDI_SUCCESS);
964*1991Sheppo }
965*1991Sheppo 
966*1991Sheppo /* set the unicast mac address of the device */
967*1991Sheppo static int
968*1991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
969*1991Sheppo {
970*1991Sheppo 	_NOTE(ARGUNUSED(arg, mca))
971*1991Sheppo 	return (DDI_SUCCESS);
972*1991Sheppo }
973*1991Sheppo 
974*1991Sheppo /* get device statistics */
975*1991Sheppo static uint64_t
976*1991Sheppo vgen_stat(void *arg, enum mac_stat stat)
977*1991Sheppo {
978*1991Sheppo 	vgen_t		*vgenp = (vgen_t *)arg;
979*1991Sheppo 	vgen_port_t	*portp;
980*1991Sheppo 	vgen_portlist_t	*plistp;
981*1991Sheppo 	uint64_t val;
982*1991Sheppo 
983*1991Sheppo 	val = 0;
984*1991Sheppo 
985*1991Sheppo 	plistp = &(vgenp->vgenports);
986*1991Sheppo 	READ_ENTER(&plistp->rwlock);
987*1991Sheppo 
988*1991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
989*1991Sheppo 			val += vgen_port_stat(portp, stat);
990*1991Sheppo 	}
991*1991Sheppo 
992*1991Sheppo 	RW_EXIT(&plistp->rwlock);
993*1991Sheppo 
994*1991Sheppo 	return (val);
995*1991Sheppo }
996*1991Sheppo 
997*1991Sheppo static void
998*1991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp)
999*1991Sheppo {
1000*1991Sheppo 	 _NOTE(ARGUNUSED(arg, wq, mp))
1001*1991Sheppo }
1002*1991Sheppo 
1003*1991Sheppo /* vgen internal functions */
1004*1991Sheppo /* detach all ports from the device */
1005*1991Sheppo static void
1006*1991Sheppo vgen_detach_ports(vgen_t *vgenp)
1007*1991Sheppo {
1008*1991Sheppo 	vgen_port_t	*portp;
1009*1991Sheppo 	vgen_portlist_t	*plistp;
1010*1991Sheppo 
1011*1991Sheppo 	plistp = &(vgenp->vgenports);
1012*1991Sheppo 	WRITE_ENTER(&plistp->rwlock);
1013*1991Sheppo 
1014*1991Sheppo 	while ((portp = plistp->headp) != NULL) {
1015*1991Sheppo 		vgen_port_detach(portp);
1016*1991Sheppo 	}
1017*1991Sheppo 
1018*1991Sheppo 	RW_EXIT(&plistp->rwlock);
1019*1991Sheppo }
1020*1991Sheppo 
1021*1991Sheppo /*
1022*1991Sheppo  * detach the given port.
1023*1991Sheppo  */
1024*1991Sheppo static void
1025*1991Sheppo vgen_port_detach(vgen_port_t *portp)
1026*1991Sheppo {
1027*1991Sheppo 	vgen_t		*vgenp;
1028*1991Sheppo 	vgen_ldclist_t	*ldclp;
1029*1991Sheppo 	int		port_num;
1030*1991Sheppo 
1031*1991Sheppo 	vgenp = portp->vgenp;
1032*1991Sheppo 	port_num = portp->port_num;
1033*1991Sheppo 
1034*1991Sheppo 	DBG1((vgenp->vnetp,
1035*1991Sheppo 	    "vgen_port_detach: enter: port_num(%d)\n", port_num));
1036*1991Sheppo 
1037*1991Sheppo 	/* remove it from port list */
1038*1991Sheppo 	vgen_port_list_remove(portp);
1039*1991Sheppo 
1040*1991Sheppo 	/* detach channels from this port */
1041*1991Sheppo 	ldclp = &portp->ldclist;
1042*1991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
1043*1991Sheppo 	while (ldclp->headp) {
1044*1991Sheppo 		vgen_ldc_detach(ldclp->headp);
1045*1991Sheppo 	}
1046*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
1047*1991Sheppo 
1048*1991Sheppo 	if (vgenp->vsw_portp == portp) {
1049*1991Sheppo 		vgenp->vsw_portp = NULL;
1050*1991Sheppo 	}
1051*1991Sheppo 	KMEM_FREE(portp);
1052*1991Sheppo 
1053*1991Sheppo 	DBG1((vgenp->vnetp,
1054*1991Sheppo 	    "vgen_port_detach: exit: port_num(%d)\n", port_num));
1055*1991Sheppo }
1056*1991Sheppo 
1057*1991Sheppo /* add a port to port list */
1058*1991Sheppo static void
1059*1991Sheppo vgen_port_list_insert(vgen_port_t *portp)
1060*1991Sheppo {
1061*1991Sheppo 	vgen_portlist_t *plistp;
1062*1991Sheppo 	vgen_t *vgenp;
1063*1991Sheppo 
1064*1991Sheppo 	vgenp = portp->vgenp;
1065*1991Sheppo 	plistp = &(vgenp->vgenports);
1066*1991Sheppo 
1067*1991Sheppo 	if (plistp->headp == NULL) {
1068*1991Sheppo 		plistp->headp = portp;
1069*1991Sheppo 	} else {
1070*1991Sheppo 		plistp->tailp->nextp = portp;
1071*1991Sheppo 	}
1072*1991Sheppo 	plistp->tailp = portp;
1073*1991Sheppo 	portp->nextp = NULL;
1074*1991Sheppo }
1075*1991Sheppo 
1076*1991Sheppo /* remove a port from port list */
1077*1991Sheppo static void
1078*1991Sheppo vgen_port_list_remove(vgen_port_t *portp)
1079*1991Sheppo {
1080*1991Sheppo 	vgen_port_t *prevp;
1081*1991Sheppo 	vgen_port_t *nextp;
1082*1991Sheppo 	vgen_portlist_t *plistp;
1083*1991Sheppo 	vgen_t *vgenp;
1084*1991Sheppo 
1085*1991Sheppo 	vgenp = portp->vgenp;
1086*1991Sheppo 
1087*1991Sheppo 	plistp = &(vgenp->vgenports);
1088*1991Sheppo 
1089*1991Sheppo 	if (plistp->headp == NULL)
1090*1991Sheppo 		return;
1091*1991Sheppo 
1092*1991Sheppo 	if (portp == plistp->headp) {
1093*1991Sheppo 		plistp->headp = portp->nextp;
1094*1991Sheppo 		if (portp == plistp->tailp)
1095*1991Sheppo 			plistp->tailp = plistp->headp;
1096*1991Sheppo 	} else {
1097*1991Sheppo 		for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) &&
1098*1991Sheppo 		    (nextp != portp); prevp = nextp);
1099*1991Sheppo 		if (nextp == portp) {
1100*1991Sheppo 			prevp->nextp = portp->nextp;
1101*1991Sheppo 		}
1102*1991Sheppo 		if (portp == plistp->tailp)
1103*1991Sheppo 			plistp->tailp = prevp;
1104*1991Sheppo 	}
1105*1991Sheppo }
1106*1991Sheppo 
1107*1991Sheppo /* lookup a port in the list based on port_num */
1108*1991Sheppo static vgen_port_t *
1109*1991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
1110*1991Sheppo {
1111*1991Sheppo 	vgen_port_t *portp = NULL;
1112*1991Sheppo 
1113*1991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1114*1991Sheppo 		if (portp->port_num == port_num) {
1115*1991Sheppo 			break;
1116*1991Sheppo 		}
1117*1991Sheppo 	}
1118*1991Sheppo 
1119*1991Sheppo 	return (portp);
1120*1991Sheppo }
1121*1991Sheppo 
1122*1991Sheppo /* enable ports for transmit/receive */
1123*1991Sheppo static void
1124*1991Sheppo vgen_init_ports(vgen_t *vgenp)
1125*1991Sheppo {
1126*1991Sheppo 	vgen_port_t	*portp;
1127*1991Sheppo 	vgen_portlist_t	*plistp;
1128*1991Sheppo 
1129*1991Sheppo 	plistp = &(vgenp->vgenports);
1130*1991Sheppo 	READ_ENTER(&plistp->rwlock);
1131*1991Sheppo 
1132*1991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1133*1991Sheppo 		vgen_port_init(portp);
1134*1991Sheppo 	}
1135*1991Sheppo 
1136*1991Sheppo 	RW_EXIT(&plistp->rwlock);
1137*1991Sheppo }
1138*1991Sheppo 
1139*1991Sheppo static void
1140*1991Sheppo vgen_port_init(vgen_port_t *portp)
1141*1991Sheppo {
1142*1991Sheppo 	vgen_t *vgenp;
1143*1991Sheppo 
1144*1991Sheppo 	vgenp = portp->vgenp;
1145*1991Sheppo 	/*
1146*1991Sheppo 	 * Create fdb entry in vnet, corresponding to the mac
1147*1991Sheppo 	 * address of this port. Note that the port specified
1148*1991Sheppo 	 * is vsw-port. This is done so that vsw-port acts
1149*1991Sheppo 	 * as the route to reach this macaddr, until the
1150*1991Sheppo 	 * channel for this port comes up (LDC_UP) and
1151*1991Sheppo 	 * handshake is done successfully.
1152*1991Sheppo 	 * eg, if the peer is OBP-vnet, it may not bring the
1153*1991Sheppo 	 * channel up for this port and may communicate via
1154*1991Sheppo 	 * vsw to reach this port.
1155*1991Sheppo 	 * Later, when Solaris-vnet comes up at the other end
1156*1991Sheppo 	 * of the channel for this port and brings up the channel,
1157*1991Sheppo 	 * it is an indication that peer vnet is capable of
1158*1991Sheppo 	 * distributed switching, so the direct route through this
1159*1991Sheppo 	 * port is specified in fdb, using vnet_modify_fdb(macaddr);
1160*1991Sheppo 	 */
1161*1991Sheppo 	vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr,
1162*1991Sheppo 	    vgen_tx, vgenp->vsw_portp);
1163*1991Sheppo 
1164*1991Sheppo 	if (portp == vgenp->vsw_portp) {
1165*1991Sheppo 		/*
1166*1991Sheppo 		 * create the default route entry in vnet's fdb.
1167*1991Sheppo 		 * This is the entry used by vnet to reach
1168*1991Sheppo 		 * unknown destinations, which basically goes
1169*1991Sheppo 		 * through vsw on domain0 and out through the
1170*1991Sheppo 		 * physical device bound to vsw.
1171*1991Sheppo 		 */
1172*1991Sheppo 		vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp);
1173*1991Sheppo 	}
1174*1991Sheppo 
1175*1991Sheppo 	/* Bring up the channels of this port */
1176*1991Sheppo 	vgen_init_ldcs(portp);
1177*1991Sheppo }
1178*1991Sheppo 
1179*1991Sheppo /* disable transmit/receive on ports */
1180*1991Sheppo static void
1181*1991Sheppo vgen_uninit_ports(vgen_t *vgenp)
1182*1991Sheppo {
1183*1991Sheppo 	vgen_port_t	*portp;
1184*1991Sheppo 	vgen_portlist_t	*plistp;
1185*1991Sheppo 
1186*1991Sheppo 	plistp = &(vgenp->vgenports);
1187*1991Sheppo 	READ_ENTER(&plistp->rwlock);
1188*1991Sheppo 
1189*1991Sheppo 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1190*1991Sheppo 		vgen_port_uninit(portp);
1191*1991Sheppo 	}
1192*1991Sheppo 
1193*1991Sheppo 	RW_EXIT(&plistp->rwlock);
1194*1991Sheppo }
1195*1991Sheppo 
1196*1991Sheppo static void
1197*1991Sheppo vgen_port_uninit(vgen_port_t *portp)
1198*1991Sheppo {
1199*1991Sheppo 	vgen_t *vgenp;
1200*1991Sheppo 
1201*1991Sheppo 	vgenp = portp->vgenp;
1202*1991Sheppo 
1203*1991Sheppo 	vgen_uninit_ldcs(portp);
1204*1991Sheppo 	/* delete the entry in vnet's fdb for this port */
1205*1991Sheppo 	vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr);
1206*1991Sheppo 	if (portp == vgenp->vsw_portp) {
1207*1991Sheppo 		/*
1208*1991Sheppo 		 * if this is vsw-port, then delete the default
1209*1991Sheppo 		 * route entry in vnet's fdb.
1210*1991Sheppo 		 */
1211*1991Sheppo 		vnet_del_def_rte(vgenp->vnetp);
1212*1991Sheppo 	}
1213*1991Sheppo }
1214*1991Sheppo 
1215*1991Sheppo /* register with MD event generator */
1216*1991Sheppo static int
1217*1991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
1218*1991Sheppo {
1219*1991Sheppo 	mdeg_prop_spec_t	*pspecp;
1220*1991Sheppo 	mdeg_node_spec_t	*parentp;
1221*1991Sheppo 	uint_t			templatesz;
1222*1991Sheppo 	int			rv;
1223*1991Sheppo 	mdeg_handle_t		hdl;
1224*1991Sheppo 	int			i;
1225*1991Sheppo 	void			*vnetp = vgenp->vnetp;
1226*1991Sheppo 
1227*1991Sheppo 	i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip,
1228*1991Sheppo 			DDI_PROP_DONTPASS, reg_propname, -1);
1229*1991Sheppo 	if (i == -1) {
1230*1991Sheppo 		return (DDI_FAILURE);
1231*1991Sheppo 	}
1232*1991Sheppo 	templatesz = sizeof (vgen_prop_template);
1233*1991Sheppo 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
1234*1991Sheppo 	if (pspecp == NULL) {
1235*1991Sheppo 		return (DDI_FAILURE);
1236*1991Sheppo 	}
1237*1991Sheppo 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
1238*1991Sheppo 	if (parentp == NULL) {
1239*1991Sheppo 		kmem_free(pspecp, templatesz);
1240*1991Sheppo 		return (DDI_FAILURE);
1241*1991Sheppo 	}
1242*1991Sheppo 
1243*1991Sheppo 	bcopy(vgen_prop_template, pspecp, templatesz);
1244*1991Sheppo 
1245*1991Sheppo 	/*
1246*1991Sheppo 	 * NOTE: The instance here refers to the value of "reg" property and
1247*1991Sheppo 	 * not the dev_info instance (ddi_get_instance()) of vnet.
1248*1991Sheppo 	 */
1249*1991Sheppo 	VGEN_SET_MDEG_PROP_INST(pspecp, i);
1250*1991Sheppo 
1251*1991Sheppo 	parentp->namep = "virtual-device";
1252*1991Sheppo 	parentp->specp = pspecp;
1253*1991Sheppo 
1254*1991Sheppo 	/* save parentp in vgen_t */
1255*1991Sheppo 	vgenp->mdeg_parentp = parentp;
1256*1991Sheppo 
1257*1991Sheppo 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl);
1258*1991Sheppo 	if (rv != MDEG_SUCCESS) {
1259*1991Sheppo 		DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n"));
1260*1991Sheppo 		KMEM_FREE(parentp);
1261*1991Sheppo 		kmem_free(pspecp, templatesz);
1262*1991Sheppo 		vgenp->mdeg_parentp = NULL;
1263*1991Sheppo 		return (DDI_FAILURE);
1264*1991Sheppo 	}
1265*1991Sheppo 
1266*1991Sheppo 	/* save mdeg handle in vgen_t */
1267*1991Sheppo 	vgenp->mdeg_hdl = hdl;
1268*1991Sheppo 
1269*1991Sheppo 	return (DDI_SUCCESS);
1270*1991Sheppo }
1271*1991Sheppo 
1272*1991Sheppo /* unregister with MD event generator */
1273*1991Sheppo static void
1274*1991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
1275*1991Sheppo {
1276*1991Sheppo 	(void) mdeg_unregister(vgenp->mdeg_hdl);
1277*1991Sheppo 	KMEM_FREE(vgenp->mdeg_parentp);
1278*1991Sheppo 	vgenp->mdeg_parentp = NULL;
1279*1991Sheppo 	vgenp->mdeg_hdl = NULL;
1280*1991Sheppo }
1281*1991Sheppo 
1282*1991Sheppo /* callback function registered with MD event generator */
1283*1991Sheppo static int
1284*1991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
1285*1991Sheppo {
1286*1991Sheppo 	int idx;
1287*1991Sheppo 	int vsw_idx = -1;
1288*1991Sheppo 	uint64_t val;
1289*1991Sheppo 	vgen_t *vgenp;
1290*1991Sheppo 
1291*1991Sheppo 	if ((resp == NULL) || (cb_argp == NULL)) {
1292*1991Sheppo 		return (MDEG_FAILURE);
1293*1991Sheppo 	}
1294*1991Sheppo 
1295*1991Sheppo 	vgenp = (vgen_t *)cb_argp;
1296*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n"));
1297*1991Sheppo 
1298*1991Sheppo 	mutex_enter(&vgenp->lock);
1299*1991Sheppo 
1300*1991Sheppo 	DBG1((vgenp->vnetp,
1301*1991Sheppo 	    "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n",
1302*1991Sheppo 	    resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem));
1303*1991Sheppo 
1304*1991Sheppo 	for (idx = 0; idx < resp->removed.nelem; idx++) {
1305*1991Sheppo 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
1306*1991Sheppo 		    resp->removed.mdep[idx]);
1307*1991Sheppo 	}
1308*1991Sheppo 
1309*1991Sheppo 	if (vgenp->vsw_portp == NULL) {
1310*1991Sheppo 		/*
1311*1991Sheppo 		 * find vsw_port and add it first, because other ports need
1312*1991Sheppo 		 * this when adding fdb entry (see vgen_port_init()).
1313*1991Sheppo 		 */
1314*1991Sheppo 		for (idx = 0; idx < resp->added.nelem; idx++) {
1315*1991Sheppo 			if (!(md_get_prop_val(resp->added.mdp,
1316*1991Sheppo 			    resp->added.mdep[idx], swport_propname, &val))) {
1317*1991Sheppo 				if (val == 0) {
1318*1991Sheppo 					/*
1319*1991Sheppo 					 * This port is connected to the
1320*1991Sheppo 					 * vsw on dom0.
1321*1991Sheppo 					 */
1322*1991Sheppo 					vsw_idx = idx;
1323*1991Sheppo 					(void) vgen_add_port(vgenp,
1324*1991Sheppo 					    resp->added.mdp,
1325*1991Sheppo 					    resp->added.mdep[idx]);
1326*1991Sheppo 					break;
1327*1991Sheppo 				}
1328*1991Sheppo 			}
1329*1991Sheppo 		}
1330*1991Sheppo 		if (vsw_idx == -1) {
1331*1991Sheppo 			DWARN((vgenp->vnetp, "vgen_mdeg_cb: "
1332*1991Sheppo 			    "can't find vsw_port\n"));
1333*1991Sheppo 			return (MDEG_FAILURE);
1334*1991Sheppo 		}
1335*1991Sheppo 	}
1336*1991Sheppo 
1337*1991Sheppo 	for (idx = 0; idx < resp->added.nelem; idx++) {
1338*1991Sheppo 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
1339*1991Sheppo 			continue;
1340*1991Sheppo 		(void) vgen_add_port(vgenp, resp->added.mdp,
1341*1991Sheppo 		    resp->added.mdep[idx]);
1342*1991Sheppo 	}
1343*1991Sheppo 
1344*1991Sheppo 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
1345*1991Sheppo 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
1346*1991Sheppo 		    resp->match_curr.mdep[idx],
1347*1991Sheppo 		    resp->match_prev.mdp,
1348*1991Sheppo 		    resp->match_prev.mdep[idx]);
1349*1991Sheppo 	}
1350*1991Sheppo 
1351*1991Sheppo 	mutex_exit(&vgenp->lock);
1352*1991Sheppo 	DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n"));
1353*1991Sheppo 	return (MDEG_SUCCESS);
1354*1991Sheppo }
1355*1991Sheppo 
1356*1991Sheppo /* add a new port to the device */
1357*1991Sheppo static int
1358*1991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
1359*1991Sheppo {
1360*1991Sheppo 	uint64_t	port_num;
1361*1991Sheppo 	uint64_t	*ldc_ids;
1362*1991Sheppo 	uint64_t	macaddr;
1363*1991Sheppo 	uint64_t	val;
1364*1991Sheppo 	int		num_ldcs;
1365*1991Sheppo 	int		vsw_port = B_FALSE;
1366*1991Sheppo 	int		i;
1367*1991Sheppo 	int		addrsz;
1368*1991Sheppo 	int		num_nodes = 0;
1369*1991Sheppo 	int		listsz = 0;
1370*1991Sheppo 	mde_cookie_t	*listp = NULL;
1371*1991Sheppo 	uint8_t		*addrp;
1372*1991Sheppo 	struct ether_addr	ea;
1373*1991Sheppo 
1374*1991Sheppo 	/* read "id" property to get the port number */
1375*1991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
1376*1991Sheppo 		DWARN((vgenp->vnetp,
1377*1991Sheppo 		    "vgen_add_port: prop(%s) not found\n", id_propname));
1378*1991Sheppo 		return (DDI_FAILURE);
1379*1991Sheppo 	}
1380*1991Sheppo 
1381*1991Sheppo 	/*
1382*1991Sheppo 	 * Find the channel endpoint node(s) under this port node.
1383*1991Sheppo 	 */
1384*1991Sheppo 	if ((num_nodes = md_node_count(mdp)) <= 0) {
1385*1991Sheppo 		DWARN((vgenp->vnetp,
1386*1991Sheppo 		    "vgen_add_port: invalid number of nodes found (%d)",
1387*1991Sheppo 		    num_nodes));
1388*1991Sheppo 		return (DDI_FAILURE);
1389*1991Sheppo 	}
1390*1991Sheppo 
1391*1991Sheppo 	/* allocate space for node list */
1392*1991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
1393*1991Sheppo 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
1394*1991Sheppo 	if (listp == NULL)
1395*1991Sheppo 		return (DDI_FAILURE);
1396*1991Sheppo 
1397*1991Sheppo 	num_ldcs = md_scan_dag(mdp, mdex,
1398*1991Sheppo 		md_find_name(mdp, channel_propname),
1399*1991Sheppo 		md_find_name(mdp, "fwd"), listp);
1400*1991Sheppo 
1401*1991Sheppo 	if (num_ldcs <= 0) {
1402*1991Sheppo 		DWARN((vgenp->vnetp,
1403*1991Sheppo 		    "vgen_add_port: can't find %s nodes", channel_propname));
1404*1991Sheppo 		kmem_free(listp, listsz);
1405*1991Sheppo 		return (DDI_FAILURE);
1406*1991Sheppo 	}
1407*1991Sheppo 
1408*1991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs));
1409*1991Sheppo 
1410*1991Sheppo 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
1411*1991Sheppo 	if (ldc_ids == NULL) {
1412*1991Sheppo 		kmem_free(listp, listsz);
1413*1991Sheppo 		return (DDI_FAILURE);
1414*1991Sheppo 	}
1415*1991Sheppo 
1416*1991Sheppo 	for (i = 0; i < num_ldcs; i++) {
1417*1991Sheppo 		/* read channel ids */
1418*1991Sheppo 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
1419*1991Sheppo 			DWARN((vgenp->vnetp,
1420*1991Sheppo 			    "vgen_add_port: prop(%s) not found\n",
1421*1991Sheppo 			    id_propname));
1422*1991Sheppo 			kmem_free(listp, listsz);
1423*1991Sheppo 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
1424*1991Sheppo 			return (DDI_FAILURE);
1425*1991Sheppo 		}
1426*1991Sheppo 		DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx",
1427*1991Sheppo 		    ldc_ids[i]));
1428*1991Sheppo 	}
1429*1991Sheppo 
1430*1991Sheppo 	kmem_free(listp, listsz);
1431*1991Sheppo 
1432*1991Sheppo 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
1433*1991Sheppo 	    &addrsz)) {
1434*1991Sheppo 		DWARN((vgenp->vnetp,
1435*1991Sheppo 		    "vgen_add_port: prop(%s) not found\n", rmacaddr_propname));
1436*1991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
1437*1991Sheppo 		return (DDI_FAILURE);
1438*1991Sheppo 	}
1439*1991Sheppo 
1440*1991Sheppo 	if (addrsz < ETHERADDRL) {
1441*1991Sheppo 		DWARN((vgenp->vnetp,
1442*1991Sheppo 		    "vgen_add_port: invalid address size (%d)\n", addrsz));
1443*1991Sheppo 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
1444*1991Sheppo 		return (DDI_FAILURE);
1445*1991Sheppo 	}
1446*1991Sheppo 
1447*1991Sheppo 	macaddr = *((uint64_t *)addrp);
1448*1991Sheppo 
1449*1991Sheppo 	DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n",
1450*1991Sheppo 	    macaddr));
1451*1991Sheppo 
1452*1991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
1453*1991Sheppo 		ea.ether_addr_octet[i] = macaddr & 0xFF;
1454*1991Sheppo 		macaddr >>= 8;
1455*1991Sheppo 	}
1456*1991Sheppo 
1457*1991Sheppo 	if (vgenp->vsw_portp == NULL) {
1458*1991Sheppo 		if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
1459*1991Sheppo 			if (val == 0) {
1460*1991Sheppo 				/* This port is connected to the vsw on dom0 */
1461*1991Sheppo 				vsw_port = B_TRUE;
1462*1991Sheppo 			}
1463*1991Sheppo 		}
1464*1991Sheppo 	}
1465*1991Sheppo 	(void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs,
1466*1991Sheppo 	    &ea, vsw_port);
1467*1991Sheppo 
1468*1991Sheppo 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
1469*1991Sheppo 
1470*1991Sheppo 	return (DDI_SUCCESS);
1471*1991Sheppo }
1472*1991Sheppo 
1473*1991Sheppo /* remove a port from the device */
1474*1991Sheppo static int
1475*1991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
1476*1991Sheppo {
1477*1991Sheppo 	uint64_t	port_num;
1478*1991Sheppo 	vgen_port_t	*portp;
1479*1991Sheppo 	vgen_portlist_t	*plistp;
1480*1991Sheppo 
1481*1991Sheppo 	/* read "id" property to get the port number */
1482*1991Sheppo 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
1483*1991Sheppo 		DWARN((vgenp->vnetp,
1484*1991Sheppo 		    "vgen_remove_port: prop(%s) not found\n", id_propname));
1485*1991Sheppo 		return (DDI_FAILURE);
1486*1991Sheppo 	}
1487*1991Sheppo 
1488*1991Sheppo 	plistp = &(vgenp->vgenports);
1489*1991Sheppo 
1490*1991Sheppo 	WRITE_ENTER(&plistp->rwlock);
1491*1991Sheppo 	portp = vgen_port_lookup(plistp, (int)port_num);
1492*1991Sheppo 	if (portp == NULL) {
1493*1991Sheppo 		DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n",
1494*1991Sheppo 		    port_num));
1495*1991Sheppo 		RW_EXIT(&plistp->rwlock);
1496*1991Sheppo 		return (DDI_FAILURE);
1497*1991Sheppo 	}
1498*1991Sheppo 
1499*1991Sheppo 	vgen_port_detach_mdeg(portp);
1500*1991Sheppo 	RW_EXIT(&plistp->rwlock);
1501*1991Sheppo 
1502*1991Sheppo 	return (DDI_SUCCESS);
1503*1991Sheppo }
1504*1991Sheppo 
1505*1991Sheppo /* attach a port to the device based on mdeg data */
1506*1991Sheppo static int
1507*1991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids,
1508*1991Sheppo 	int num_ids, struct ether_addr *macaddr, boolean_t vsw_port)
1509*1991Sheppo {
1510*1991Sheppo 	vgen_port_t		*portp;
1511*1991Sheppo 	vgen_portlist_t		*plistp;
1512*1991Sheppo 	int			i;
1513*1991Sheppo 
1514*1991Sheppo 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP);
1515*1991Sheppo 	if (portp == NULL) {
1516*1991Sheppo 		return (DDI_FAILURE);
1517*1991Sheppo 	}
1518*1991Sheppo 	portp->vgenp = vgenp;
1519*1991Sheppo 	portp->port_num = port_num;
1520*1991Sheppo 
1521*1991Sheppo 	DBG1((vgenp->vnetp,
1522*1991Sheppo 	    "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num));
1523*1991Sheppo 
1524*1991Sheppo 	portp->ldclist.num_ldcs = 0;
1525*1991Sheppo 	portp->ldclist.headp = NULL;
1526*1991Sheppo 	rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
1527*1991Sheppo 
1528*1991Sheppo 	ether_copy(macaddr, &portp->macaddr);
1529*1991Sheppo 	for (i = 0; i < num_ids; i++) {
1530*1991Sheppo 		DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n",
1531*1991Sheppo 		    ldcids[i]));
1532*1991Sheppo 		(void) vgen_ldc_attach(portp, ldcids[i]);
1533*1991Sheppo 	}
1534*1991Sheppo 
1535*1991Sheppo 	/* link it into the list of ports */
1536*1991Sheppo 	plistp = &(vgenp->vgenports);
1537*1991Sheppo 	WRITE_ENTER(&plistp->rwlock);
1538*1991Sheppo 	vgen_port_list_insert(portp);
1539*1991Sheppo 	RW_EXIT(&plistp->rwlock);
1540*1991Sheppo 
1541*1991Sheppo 	/* This port is connected to the vsw on domain0 */
1542*1991Sheppo 	if (vsw_port)
1543*1991Sheppo 		vgenp->vsw_portp = portp;
1544*1991Sheppo 
1545*1991Sheppo 	if (vgenp->flags & VGEN_STARTED) {	/* interface is configured */
1546*1991Sheppo 		vgen_port_init(portp);
1547*1991Sheppo 	}
1548*1991Sheppo 
1549*1991Sheppo 	DBG1((vgenp->vnetp,
1550*1991Sheppo 	    "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num));
1551*1991Sheppo 	return (DDI_SUCCESS);
1552*1991Sheppo }
1553*1991Sheppo 
1554*1991Sheppo /* detach a port from the device based on mdeg data */
1555*1991Sheppo static void
1556*1991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
1557*1991Sheppo {
1558*1991Sheppo 	vgen_t *vgenp = portp->vgenp;
1559*1991Sheppo 
1560*1991Sheppo 	DBG1((vgenp->vnetp,
1561*1991Sheppo 	    "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num));
1562*1991Sheppo 	/* stop the port if needed */
1563*1991Sheppo 	if (vgenp->flags & VGEN_STARTED) {
1564*1991Sheppo 		vgen_port_uninit(portp);
1565*1991Sheppo 	}
1566*1991Sheppo 	vgen_port_detach(portp);
1567*1991Sheppo 
1568*1991Sheppo 	DBG1((vgenp->vnetp,
1569*1991Sheppo 	    "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num));
1570*1991Sheppo }
1571*1991Sheppo 
1572*1991Sheppo static int
1573*1991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
1574*1991Sheppo 	md_t *prev_mdp, mde_cookie_t prev_mdex)
1575*1991Sheppo {
1576*1991Sheppo 	 _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex))
1577*1991Sheppo 
1578*1991Sheppo 	/* XXX: TBD */
1579*1991Sheppo 	return (DDI_SUCCESS);
1580*1991Sheppo }
1581*1991Sheppo 
1582*1991Sheppo static uint64_t
1583*1991Sheppo vgen_port_stat(vgen_port_t *portp, enum mac_stat stat)
1584*1991Sheppo {
1585*1991Sheppo 	vgen_ldclist_t	*ldclp;
1586*1991Sheppo 	vgen_ldc_t *ldcp;
1587*1991Sheppo 	uint64_t	val;
1588*1991Sheppo 
1589*1991Sheppo 	val = 0;
1590*1991Sheppo 	ldclp = &portp->ldclist;
1591*1991Sheppo 
1592*1991Sheppo 	READ_ENTER(&ldclp->rwlock);
1593*1991Sheppo 	for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
1594*1991Sheppo 		val += vgen_ldc_stat(ldcp, stat);
1595*1991Sheppo 	}
1596*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
1597*1991Sheppo 
1598*1991Sheppo 	return (val);
1599*1991Sheppo }
1600*1991Sheppo 
1601*1991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
1602*1991Sheppo static int
1603*1991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
1604*1991Sheppo {
1605*1991Sheppo 	vgen_t 		*vgenp;
1606*1991Sheppo 	vgen_ldclist_t	*ldclp;
1607*1991Sheppo 	vgen_ldc_t 	*ldcp, **prev_ldcp;
1608*1991Sheppo 	ldc_attr_t 	attr;
1609*1991Sheppo 	int 		status;
1610*1991Sheppo 	ldc_status_t	istatus;
1611*1991Sheppo 	enum		{AST_init = 0x0, AST_ldc_alloc = 0x1,
1612*1991Sheppo 			AST_mutex_init = 0x2, AST_ldc_init = 0x4,
1613*1991Sheppo 			AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10}
1614*1991Sheppo 			attach_state;
1615*1991Sheppo 
1616*1991Sheppo 	attach_state = AST_init;
1617*1991Sheppo 	vgenp = portp->vgenp;
1618*1991Sheppo 	ldclp = &portp->ldclist;
1619*1991Sheppo 
1620*1991Sheppo 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
1621*1991Sheppo 	if (ldcp == NULL) {
1622*1991Sheppo 		goto ldc_attach_failed;
1623*1991Sheppo 	}
1624*1991Sheppo 	ldcp->ldc_id = ldc_id;
1625*1991Sheppo 	ldcp->portp = portp;
1626*1991Sheppo 	ldcp->reclaim_lowat = vnet_reclaim_lowat;
1627*1991Sheppo 	ldcp->reclaim_hiwat = vnet_reclaim_hiwat;
1628*1991Sheppo 
1629*1991Sheppo 	attach_state |= AST_ldc_alloc;
1630*1991Sheppo 
1631*1991Sheppo 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
1632*1991Sheppo 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
1633*1991Sheppo 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
1634*1991Sheppo 
1635*1991Sheppo 	attach_state |= AST_mutex_init;
1636*1991Sheppo 
1637*1991Sheppo 	attr.devclass = LDC_DEV_NT;
1638*1991Sheppo 	attr.instance = ddi_get_instance(vgenp->vnetdip);
1639*1991Sheppo 	attr.mode = LDC_MODE_UNRELIABLE;
1640*1991Sheppo 	attr.qlen = vnet_ldc_qlen;
1641*1991Sheppo 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
1642*1991Sheppo 	if (status != 0) {
1643*1991Sheppo 		DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n",
1644*1991Sheppo 		    ldc_id, status));
1645*1991Sheppo 		goto ldc_attach_failed;
1646*1991Sheppo 	}
1647*1991Sheppo 	attach_state |= AST_ldc_init;
1648*1991Sheppo 
1649*1991Sheppo 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
1650*1991Sheppo 	if (status != 0) {
1651*1991Sheppo 		DWARN((vgenp->vnetp,
1652*1991Sheppo 		    "ldc_reg_callback failed, id (%lx) rv (%d)\n",
1653*1991Sheppo 		    ldc_id, status));
1654*1991Sheppo 		goto ldc_attach_failed;
1655*1991Sheppo 	}
1656*1991Sheppo 	attach_state |= AST_ldc_reg_cb;
1657*1991Sheppo 
1658*1991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
1659*1991Sheppo 	ASSERT(istatus == LDC_INIT);
1660*1991Sheppo 	ldcp->ldc_status = istatus;
1661*1991Sheppo 
1662*1991Sheppo 	/* allocate transmit resources */
1663*1991Sheppo 	status = vgen_alloc_tx_ring(ldcp);
1664*1991Sheppo 	if (status != 0) {
1665*1991Sheppo 		goto ldc_attach_failed;
1666*1991Sheppo 	}
1667*1991Sheppo 	attach_state |= AST_alloc_tx_ring;
1668*1991Sheppo 
1669*1991Sheppo 	/* Setup kstats for the channel */
1670*1991Sheppo 	status = vgen_setup_kstats(ldcp);
1671*1991Sheppo 	if (status != VGEN_SUCCESS) {
1672*1991Sheppo 		goto ldc_attach_failed;
1673*1991Sheppo 	}
1674*1991Sheppo 
1675*1991Sheppo 	/* initialize vgen_versions supported */
1676*1991Sheppo 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
1677*1991Sheppo 
1678*1991Sheppo 	/* link it into the list of channels for this port */
1679*1991Sheppo 	WRITE_ENTER(&ldclp->rwlock);
1680*1991Sheppo 	prev_ldcp = (vgen_ldc_t **)(&ldclp->headp);
1681*1991Sheppo 	ldcp->nextp = *prev_ldcp;
1682*1991Sheppo 	*prev_ldcp = ldcp;
1683*1991Sheppo 	ldclp->num_ldcs++;
1684*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
1685*1991Sheppo 
1686*1991Sheppo 	ldcp->flags |= CHANNEL_ATTACHED;
1687*1991Sheppo 	return (DDI_SUCCESS);
1688*1991Sheppo 
1689*1991Sheppo ldc_attach_failed:
1690*1991Sheppo 	if (attach_state & AST_alloc_tx_ring) {
1691*1991Sheppo 		vgen_free_tx_ring(ldcp);
1692*1991Sheppo 	}
1693*1991Sheppo 	if (attach_state & AST_ldc_reg_cb) {
1694*1991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
1695*1991Sheppo 	}
1696*1991Sheppo 	if (attach_state & AST_ldc_init) {
1697*1991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
1698*1991Sheppo 	}
1699*1991Sheppo 	if (attach_state & AST_mutex_init) {
1700*1991Sheppo 		mutex_destroy(&ldcp->tclock);
1701*1991Sheppo 		mutex_destroy(&ldcp->txlock);
1702*1991Sheppo 		mutex_destroy(&ldcp->cblock);
1703*1991Sheppo 	}
1704*1991Sheppo 	if (attach_state & AST_ldc_alloc) {
1705*1991Sheppo 		KMEM_FREE(ldcp);
1706*1991Sheppo 	}
1707*1991Sheppo 	return (DDI_FAILURE);
1708*1991Sheppo }
1709*1991Sheppo 
1710*1991Sheppo /* detach a channel from the port */
1711*1991Sheppo static void
1712*1991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
1713*1991Sheppo {
1714*1991Sheppo 	vgen_port_t	*portp;
1715*1991Sheppo 	vgen_t 		*vgenp;
1716*1991Sheppo 	vgen_ldc_t 	*pldcp;
1717*1991Sheppo 	vgen_ldc_t	**prev_ldcp;
1718*1991Sheppo 	vgen_ldclist_t	*ldclp;
1719*1991Sheppo 
1720*1991Sheppo 	portp = ldcp->portp;
1721*1991Sheppo 	vgenp = portp->vgenp;
1722*1991Sheppo 	ldclp = &portp->ldclist;
1723*1991Sheppo 
1724*1991Sheppo 	prev_ldcp =  (vgen_ldc_t **)&ldclp->headp;
1725*1991Sheppo 	for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
1726*1991Sheppo 		if (pldcp == ldcp) {
1727*1991Sheppo 			break;
1728*1991Sheppo 		}
1729*1991Sheppo 	}
1730*1991Sheppo 
1731*1991Sheppo 	if (pldcp == NULL) {
1732*1991Sheppo 		/* invalid ldcp? */
1733*1991Sheppo 		return;
1734*1991Sheppo 	}
1735*1991Sheppo 
1736*1991Sheppo 	if (ldcp->ldc_status != LDC_INIT) {
1737*1991Sheppo 		DWARN((vgenp->vnetp,
1738*1991Sheppo 		    "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n",
1739*1991Sheppo 			    ldcp->ldc_id));
1740*1991Sheppo 	}
1741*1991Sheppo 
1742*1991Sheppo 	if (ldcp->flags & CHANNEL_ATTACHED) {
1743*1991Sheppo 		ldcp->flags &= ~(CHANNEL_ATTACHED);
1744*1991Sheppo 
1745*1991Sheppo 		vgen_destroy_kstats(ldcp);
1746*1991Sheppo 		/* free transmit resources */
1747*1991Sheppo 		vgen_free_tx_ring(ldcp);
1748*1991Sheppo 		(void) ldc_unreg_callback(ldcp->ldc_handle);
1749*1991Sheppo 		(void) ldc_fini(ldcp->ldc_handle);
1750*1991Sheppo 		mutex_destroy(&ldcp->tclock);
1751*1991Sheppo 		mutex_destroy(&ldcp->txlock);
1752*1991Sheppo 		mutex_destroy(&ldcp->cblock);
1753*1991Sheppo 
1754*1991Sheppo 		/* unlink it from the list */
1755*1991Sheppo 		*prev_ldcp = ldcp->nextp;
1756*1991Sheppo 		ldclp->num_ldcs--;
1757*1991Sheppo 		KMEM_FREE(ldcp);
1758*1991Sheppo 	}
1759*1991Sheppo }
1760*1991Sheppo 
1761*1991Sheppo /*
1762*1991Sheppo  * This function allocates transmit resources for the channel.
1763*1991Sheppo  * The resources consist of a transmit descriptor ring and an associated
1764*1991Sheppo  * transmit buffer ring.
1765*1991Sheppo  */
1766*1991Sheppo static int
1767*1991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp)
1768*1991Sheppo {
1769*1991Sheppo 	void *tbufp;
1770*1991Sheppo 	ldc_mem_info_t minfo;
1771*1991Sheppo 	uint32_t txdsize;
1772*1991Sheppo 	uint32_t tbufsize;
1773*1991Sheppo 	int status;
1774*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
1775*1991Sheppo 
1776*1991Sheppo 	ldcp->num_txds = vnet_ntxds;
1777*1991Sheppo 	txdsize = sizeof (vnet_public_desc_t);
1778*1991Sheppo 	tbufsize = sizeof (vgen_private_desc_t);
1779*1991Sheppo 
1780*1991Sheppo 	/* allocate transmit buffer ring */
1781*1991Sheppo 	tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
1782*1991Sheppo 	if (tbufp == NULL) {
1783*1991Sheppo 		return (DDI_FAILURE);
1784*1991Sheppo 	}
1785*1991Sheppo 
1786*1991Sheppo 	/* create transmit descriptor ring */
1787*1991Sheppo 	status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
1788*1991Sheppo 	    &ldcp->tx_dhandle);
1789*1991Sheppo 	if (status) {
1790*1991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() "
1791*1991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
1792*1991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
1793*1991Sheppo 		return (DDI_FAILURE);
1794*1991Sheppo 	}
1795*1991Sheppo 
1796*1991Sheppo 	/* get the addr of descripror ring */
1797*1991Sheppo 	status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
1798*1991Sheppo 	if (status) {
1799*1991Sheppo 		DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() "
1800*1991Sheppo 		    "failed, id(%lx)\n", ldcp->ldc_id));
1801*1991Sheppo 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
1802*1991Sheppo 		(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
1803*1991Sheppo 		ldcp->tbufp = NULL;
1804*1991Sheppo 		return (DDI_FAILURE);
1805*1991Sheppo 	}
1806*1991Sheppo 	ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr);
1807*1991Sheppo 	ldcp->tbufp = tbufp;
1808*1991Sheppo 
1809*1991Sheppo 	ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]);
1810*1991Sheppo 	ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]);
1811*1991Sheppo 
1812*1991Sheppo 	return (DDI_SUCCESS);
1813*1991Sheppo }
1814*1991Sheppo 
1815*1991Sheppo /* Free transmit resources for the channel */
1816*1991Sheppo static void
1817*1991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp)
1818*1991Sheppo {
1819*1991Sheppo 	int tbufsize = sizeof (vgen_private_desc_t);
1820*1991Sheppo 
1821*1991Sheppo 	/* free transmit descriptor ring */
1822*1991Sheppo 	(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
1823*1991Sheppo 
1824*1991Sheppo 	/* free transmit buffer ring */
1825*1991Sheppo 	kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize);
1826*1991Sheppo 	ldcp->txdp = ldcp->txdendp = NULL;
1827*1991Sheppo 	ldcp->tbufp = ldcp->tbufendp = NULL;
1828*1991Sheppo }
1829*1991Sheppo 
1830*1991Sheppo /* enable transmit/receive on the channels for the port */
1831*1991Sheppo static void
1832*1991Sheppo vgen_init_ldcs(vgen_port_t *portp)
1833*1991Sheppo {
1834*1991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
1835*1991Sheppo 	vgen_ldc_t	*ldcp;
1836*1991Sheppo 
1837*1991Sheppo 	READ_ENTER(&ldclp->rwlock);
1838*1991Sheppo 	ldcp =  ldclp->headp;
1839*1991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
1840*1991Sheppo 		(void) vgen_ldc_init(ldcp);
1841*1991Sheppo 	}
1842*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
1843*1991Sheppo }
1844*1991Sheppo 
1845*1991Sheppo /* stop transmit/receive on the channels for the port */
1846*1991Sheppo static void
1847*1991Sheppo vgen_uninit_ldcs(vgen_port_t *portp)
1848*1991Sheppo {
1849*1991Sheppo 	vgen_ldclist_t	*ldclp = &portp->ldclist;
1850*1991Sheppo 	vgen_ldc_t	*ldcp;
1851*1991Sheppo 
1852*1991Sheppo 	READ_ENTER(&ldclp->rwlock);
1853*1991Sheppo 	ldcp =  ldclp->headp;
1854*1991Sheppo 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
1855*1991Sheppo 		vgen_ldc_uninit(ldcp);
1856*1991Sheppo 	}
1857*1991Sheppo 	RW_EXIT(&ldclp->rwlock);
1858*1991Sheppo }
1859*1991Sheppo 
1860*1991Sheppo /* enable transmit/receive on the channel */
1861*1991Sheppo static int
1862*1991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
1863*1991Sheppo {
1864*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
1865*1991Sheppo 	ldc_status_t	istatus;
1866*1991Sheppo 	int		rv;
1867*1991Sheppo 	enum		{ ST_init = 0x0, ST_init_tbufs = 0x1,
1868*1991Sheppo 			    ST_ldc_open = 0x2, ST_dring_bind = 0x4
1869*1991Sheppo 			    }
1870*1991Sheppo 			init_state;
1871*1991Sheppo 	uint32_t	ncookies = 0;
1872*1991Sheppo 
1873*1991Sheppo 	init_state = ST_init;
1874*1991Sheppo 
1875*1991Sheppo 	LDC_LOCK(ldcp);
1876*1991Sheppo 
1877*1991Sheppo 	rv = ldc_open(ldcp->ldc_handle);
1878*1991Sheppo 	if (rv != 0) {
1879*1991Sheppo 		DWARN((vnetp,
1880*1991Sheppo 		    "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
1881*1991Sheppo 		    ldcp->ldc_id, rv));
1882*1991Sheppo 		goto ldcinit_failed;
1883*1991Sheppo 	}
1884*1991Sheppo 	init_state |= ST_ldc_open;
1885*1991Sheppo 
1886*1991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
1887*1991Sheppo 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
1888*1991Sheppo 		DWARN((vnetp,
1889*1991Sheppo 		    "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
1890*1991Sheppo 		    ldcp->ldc_id, istatus));
1891*1991Sheppo 		goto ldcinit_failed;
1892*1991Sheppo 	}
1893*1991Sheppo 	ldcp->ldc_status = istatus;
1894*1991Sheppo 
1895*1991Sheppo 	rv = vgen_init_tbufs(ldcp);
1896*1991Sheppo 	if (rv != 0) {
1897*1991Sheppo 		DWARN((vnetp,
1898*1991Sheppo 		    "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
1899*1991Sheppo 		    ldcp->ldc_id));
1900*1991Sheppo 		goto ldcinit_failed;
1901*1991Sheppo 	}
1902*1991Sheppo 	init_state |= ST_init_tbufs;
1903*1991Sheppo 
1904*1991Sheppo 	/* Bind descriptor ring to the channel */
1905*1991Sheppo 	rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
1906*1991Sheppo 	    LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
1907*1991Sheppo 	if (rv != 0) {
1908*1991Sheppo 		DWARN((vnetp, "vgen_ldcinit: id (%lx) "
1909*1991Sheppo 		    "ldc_mem_dring_bind failed\n", ldcp->ldc_id));
1910*1991Sheppo 		goto ldcinit_failed;
1911*1991Sheppo 	}
1912*1991Sheppo 
1913*1991Sheppo 	ASSERT(ncookies == 1);
1914*1991Sheppo 	ldcp->num_txdcookies = ncookies;
1915*1991Sheppo 
1916*1991Sheppo 	init_state |= ST_dring_bind;
1917*1991Sheppo 
1918*1991Sheppo 	rv = ldc_up(ldcp->ldc_handle);
1919*1991Sheppo 	if (rv != 0) {
1920*1991Sheppo 		DBG2((vnetp,
1921*1991Sheppo 		    "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
1922*1991Sheppo 		    ldcp->ldc_id, rv));
1923*1991Sheppo 	}
1924*1991Sheppo 
1925*1991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
1926*1991Sheppo 	if (istatus != LDC_UP) {
1927*1991Sheppo 		DBG2((vnetp, "vgen_ldcinit: id(%lx) status(%d) is not UP\n",
1928*1991Sheppo 		    ldcp->ldc_id, istatus));
1929*1991Sheppo 	}
1930*1991Sheppo 	ldcp->ldc_status = istatus;
1931*1991Sheppo 
1932*1991Sheppo 	/* initialize transmit watchdog timeout */
1933*1991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
1934*1991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
1935*1991Sheppo 
1936*1991Sheppo 	ldcp->flags |= CHANNEL_STARTED;
1937*1991Sheppo 
1938*1991Sheppo 	LDC_UNLOCK(ldcp);
1939*1991Sheppo 	return (DDI_SUCCESS);
1940*1991Sheppo 
1941*1991Sheppo ldcinit_failed:
1942*1991Sheppo 	if (init_state & ST_dring_bind) {
1943*1991Sheppo 		(void) ldc_mem_dring_unbind(ldcp->tx_dhandle);
1944*1991Sheppo 	}
1945*1991Sheppo 	if (init_state & ST_init_tbufs) {
1946*1991Sheppo 		vgen_uninit_tbufs(ldcp);
1947*1991Sheppo 	}
1948*1991Sheppo 	if (init_state & ST_ldc_open) {
1949*1991Sheppo 		(void) ldc_close(ldcp->ldc_handle);
1950*1991Sheppo 	}
1951*1991Sheppo 	LDC_UNLOCK(ldcp);
1952*1991Sheppo 	return (DDI_FAILURE);
1953*1991Sheppo }
1954*1991Sheppo 
1955*1991Sheppo /* stop transmit/receive on the channel */
1956*1991Sheppo static void
1957*1991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
1958*1991Sheppo {
1959*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
1960*1991Sheppo 	int	rv;
1961*1991Sheppo 
1962*1991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id));
1963*1991Sheppo 	LDC_LOCK(ldcp);
1964*1991Sheppo 
1965*1991Sheppo 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
1966*1991Sheppo 		LDC_UNLOCK(ldcp);
1967*1991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED"
1968*1991Sheppo 		    " flag is not set\n", ldcp->ldc_id));
1969*1991Sheppo 		return;
1970*1991Sheppo 	}
1971*1991Sheppo 
1972*1991Sheppo 	/* disable further callbacks */
1973*1991Sheppo 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
1974*1991Sheppo 	if (rv != 0) {
1975*1991Sheppo 		DWARN((vnetp, "vgen_ldc_uninit: id (%lx) "
1976*1991Sheppo 		    "ldc_set_cb_mode failed\n", ldcp->ldc_id));
1977*1991Sheppo 	}
1978*1991Sheppo 
1979*1991Sheppo 	/* clear handshake done bit and wait for pending tx and cb to finish */
1980*1991Sheppo 	ldcp->hphase &= ~(VH_DONE);
1981*1991Sheppo 	LDC_UNLOCK(ldcp);
1982*1991Sheppo 	drv_usecwait(1000);
1983*1991Sheppo 	LDC_LOCK(ldcp);
1984*1991Sheppo 
1985*1991Sheppo 	vgen_reset_hphase(ldcp);
1986*1991Sheppo 
1987*1991Sheppo 	/* reset transmit watchdog timeout */
1988*1991Sheppo 	if (ldcp->wd_tid) {
1989*1991Sheppo 		(void) untimeout(ldcp->wd_tid);
1990*1991Sheppo 		ldcp->wd_tid = 0;
1991*1991Sheppo 	}
1992*1991Sheppo 
1993*1991Sheppo 	/* unbind tx descriptor ring from the channel */
1994*1991Sheppo 	rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
1995*1991Sheppo 	if (rv != 0) {
1996*1991Sheppo 		DWARN((vnetp, "vgen_ldcuninit: ldc_mem_dring_unbind "
1997*1991Sheppo 		    "failed id(%lx)\n", ldcp->ldc_id));
1998*1991Sheppo 	}
1999*1991Sheppo 
2000*1991Sheppo 	vgen_uninit_tbufs(ldcp);
2001*1991Sheppo 
2002*1991Sheppo 	rv = ldc_close(ldcp->ldc_handle);
2003*1991Sheppo 	if (rv != 0) {
2004*1991Sheppo 		DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n",
2005*1991Sheppo 		    ldcp->ldc_id));
2006*1991Sheppo 	}
2007*1991Sheppo 	ldcp->ldc_status = LDC_INIT;
2008*1991Sheppo 	ldcp->flags &= ~(CHANNEL_STARTED);
2009*1991Sheppo 
2010*1991Sheppo 	LDC_UNLOCK(ldcp);
2011*1991Sheppo 
2012*1991Sheppo 	DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id));
2013*1991Sheppo }
2014*1991Sheppo 
2015*1991Sheppo /* Initialize the transmit buffer ring for the channel */
2016*1991Sheppo static int
2017*1991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp)
2018*1991Sheppo {
2019*1991Sheppo 	vgen_private_desc_t	*tbufp;
2020*1991Sheppo 	vnet_public_desc_t	*txdp;
2021*1991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
2022*1991Sheppo 	int 			i;
2023*1991Sheppo 	int 			rv;
2024*1991Sheppo 
2025*1991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
2026*1991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
2027*1991Sheppo 
2028*1991Sheppo 	/*
2029*1991Sheppo 	 * for each tx buf (priv_desc), allocate a ldc mem_handle which is
2030*1991Sheppo 	 * required to map the data during transmit, set the flags
2031*1991Sheppo 	 * to free (available for use by transmit routine).
2032*1991Sheppo 	 */
2033*1991Sheppo 
2034*1991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
2035*1991Sheppo 		tbufp = &(ldcp->tbufp[i]);
2036*1991Sheppo 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
2037*1991Sheppo 			&(tbufp->memhandle));
2038*1991Sheppo 		if (rv) {
2039*1991Sheppo 			tbufp->memhandle = 0;
2040*1991Sheppo 			goto init_tbufs_failed;
2041*1991Sheppo 		}
2042*1991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
2043*1991Sheppo 		txdp = &(ldcp->txdp[i]);
2044*1991Sheppo 		hdrp = &txdp->hdr;
2045*1991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
2046*1991Sheppo 		hdrp->ack = B_FALSE;
2047*1991Sheppo 		tbufp->descp = txdp;
2048*1991Sheppo 	}
2049*1991Sheppo 
2050*1991Sheppo 	/* reset tbuf walking pointers */
2051*1991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
2052*1991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
2053*1991Sheppo 
2054*1991Sheppo 	/* initialize tx seqnum and index */
2055*1991Sheppo 	ldcp->next_txseq = VNET_ISS;
2056*1991Sheppo 	ldcp->next_txi = 0;
2057*1991Sheppo 
2058*1991Sheppo 	return (DDI_SUCCESS);
2059*1991Sheppo 
2060*1991Sheppo init_tbufs_failed:;
2061*1991Sheppo 	vgen_uninit_tbufs(ldcp);
2062*1991Sheppo 	return (DDI_FAILURE);
2063*1991Sheppo }
2064*1991Sheppo 
2065*1991Sheppo /* Uninitialize transmit buffer ring for the channel */
2066*1991Sheppo static void
2067*1991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp)
2068*1991Sheppo {
2069*1991Sheppo 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
2070*1991Sheppo 	vnet_public_desc_t	*txdp;
2071*1991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
2072*1991Sheppo 	int 			i;
2073*1991Sheppo 
2074*1991Sheppo 	/* for each tbuf (priv_desc), free ldc mem_handle */
2075*1991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
2076*1991Sheppo 
2077*1991Sheppo 		tbufp = &(ldcp->tbufp[i]);
2078*1991Sheppo 		txdp = tbufp->descp;
2079*1991Sheppo 		hdrp = &txdp->hdr;
2080*1991Sheppo 
2081*1991Sheppo 		if (tbufp->flags != VGEN_PRIV_DESC_FREE) {
2082*1991Sheppo 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
2083*1991Sheppo 			freemsg(tbufp->mp);
2084*1991Sheppo 			tbufp->mp = NULL;
2085*1991Sheppo 			tbufp->flags = VGEN_PRIV_DESC_FREE;
2086*1991Sheppo 			hdrp->dstate = VIO_DESC_FREE;
2087*1991Sheppo 			hdrp->ack = B_FALSE;
2088*1991Sheppo 		}
2089*1991Sheppo 		if (tbufp->memhandle) {
2090*1991Sheppo 			(void) ldc_mem_free_handle(tbufp->memhandle);
2091*1991Sheppo 			tbufp->memhandle = 0;
2092*1991Sheppo 		}
2093*1991Sheppo 		tbufp->descp = NULL;
2094*1991Sheppo 	}
2095*1991Sheppo 
2096*1991Sheppo 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
2097*1991Sheppo 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
2098*1991Sheppo }
2099*1991Sheppo 
2100*1991Sheppo /* clobber tx descriptor ring */
2101*1991Sheppo static void
2102*1991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp)
2103*1991Sheppo {
2104*1991Sheppo 	vnet_public_desc_t	*txdp;
2105*1991Sheppo 	vgen_private_desc_t	*tbufp;
2106*1991Sheppo 	vio_dring_entry_hdr_t		*hdrp;
2107*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
2108*1991Sheppo 	int i;
2109*1991Sheppo #ifdef DEBUG
2110*1991Sheppo 	int ndone = 0;
2111*1991Sheppo #endif
2112*1991Sheppo 
2113*1991Sheppo 	for (i = 0; i < ldcp->num_txds; i++) {
2114*1991Sheppo 
2115*1991Sheppo 		tbufp = &(ldcp->tbufp[i]);
2116*1991Sheppo 		txdp = tbufp->descp;
2117*1991Sheppo 		hdrp = &txdp->hdr;
2118*1991Sheppo 
2119*1991Sheppo 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
2120*1991Sheppo 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
2121*1991Sheppo 			freemsg(tbufp->mp);
2122*1991Sheppo 			tbufp->mp = NULL;
2123*1991Sheppo 			tbufp->flags = VGEN_PRIV_DESC_FREE;
2124*1991Sheppo #ifdef DEBUG
2125*1991Sheppo 			if (hdrp->dstate == VIO_DESC_DONE)
2126*1991Sheppo 				ndone++;
2127*1991Sheppo #endif
2128*1991Sheppo 			hdrp->dstate = VIO_DESC_FREE;
2129*1991Sheppo 			hdrp->ack = B_FALSE;
2130*1991Sheppo 		}
2131*1991Sheppo 	}
2132*1991Sheppo 	/* reset tbuf walking pointers */
2133*1991Sheppo 	ldcp->next_tbufp = ldcp->tbufp;
2134*1991Sheppo 	ldcp->cur_tbufp = ldcp->tbufp;
2135*1991Sheppo 
2136*1991Sheppo 	/* reset tx seqnum and index */
2137*1991Sheppo 	ldcp->next_txseq = VNET_ISS;
2138*1991Sheppo 	ldcp->next_txi = 0;
2139*1991Sheppo #ifdef DEBUG
2140*1991Sheppo 	DBG2((vnetp,
2141*1991Sheppo 	    "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
2142*1991Sheppo 	    ldcp->ldc_id, ndone));
2143*1991Sheppo #endif
2144*1991Sheppo }
2145*1991Sheppo 
2146*1991Sheppo /* clobber receive descriptor ring */
2147*1991Sheppo static void
2148*1991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp)
2149*1991Sheppo {
2150*1991Sheppo 	ldcp->rx_dhandle = 0;
2151*1991Sheppo 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
2152*1991Sheppo 	ldcp->rxdp = NULL;
2153*1991Sheppo 	ldcp->next_rxi = 0;
2154*1991Sheppo 	ldcp->num_rxds = 0;
2155*1991Sheppo 	ldcp->next_rxseq = VNET_ISS;
2156*1991Sheppo }
2157*1991Sheppo 
2158*1991Sheppo /* initialize receive descriptor ring */
2159*1991Sheppo static int
2160*1991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
2161*1991Sheppo 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
2162*1991Sheppo {
2163*1991Sheppo 	int rv;
2164*1991Sheppo 	ldc_mem_info_t minfo;
2165*1991Sheppo 
2166*1991Sheppo 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
2167*1991Sheppo 	    desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle));
2168*1991Sheppo 	if (rv != 0) {
2169*1991Sheppo 		return (DDI_FAILURE);
2170*1991Sheppo 	}
2171*1991Sheppo 
2172*1991Sheppo 	/*
2173*1991Sheppo 	 * sucessfully mapped, now try to
2174*1991Sheppo 	 * get info about the mapped dring
2175*1991Sheppo 	 */
2176*1991Sheppo 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
2177*1991Sheppo 	if (rv != 0) {
2178*1991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
2179*1991Sheppo 		return (DDI_FAILURE);
2180*1991Sheppo 	}
2181*1991Sheppo 
2182*1991Sheppo 	/*
2183*1991Sheppo 	 * save ring address, number of descriptors.
2184*1991Sheppo 	 */
2185*1991Sheppo 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
2186*1991Sheppo 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
2187*1991Sheppo 	ldcp->num_rxdcookies = ncookies;
2188*1991Sheppo 	ldcp->num_rxds = num_desc;
2189*1991Sheppo 	ldcp->next_rxi = 0;
2190*1991Sheppo 	ldcp->next_rxseq = VNET_ISS;
2191*1991Sheppo 
2192*1991Sheppo 	return (DDI_SUCCESS);
2193*1991Sheppo }
2194*1991Sheppo 
2195*1991Sheppo /* get channel statistics */
2196*1991Sheppo static uint64_t
2197*1991Sheppo vgen_ldc_stat(vgen_ldc_t *ldcp, enum mac_stat stat)
2198*1991Sheppo {
2199*1991Sheppo 	vgen_stats_t *statsp;
2200*1991Sheppo 	uint64_t val;
2201*1991Sheppo 
2202*1991Sheppo 	val = 0;
2203*1991Sheppo 	statsp = ldcp->statsp;
2204*1991Sheppo 	switch (stat) {
2205*1991Sheppo 
2206*1991Sheppo 	case MAC_STAT_MULTIRCV:
2207*1991Sheppo 		val = statsp->multircv;
2208*1991Sheppo 		break;
2209*1991Sheppo 
2210*1991Sheppo 	case MAC_STAT_BRDCSTRCV:
2211*1991Sheppo 		val = statsp->brdcstrcv;
2212*1991Sheppo 		break;
2213*1991Sheppo 
2214*1991Sheppo 	case MAC_STAT_MULTIXMT:
2215*1991Sheppo 		val = statsp->multixmt;
2216*1991Sheppo 		break;
2217*1991Sheppo 
2218*1991Sheppo 	case MAC_STAT_BRDCSTXMT:
2219*1991Sheppo 		val = statsp->brdcstxmt;
2220*1991Sheppo 		break;
2221*1991Sheppo 
2222*1991Sheppo 	case MAC_STAT_NORCVBUF:
2223*1991Sheppo 		val = statsp->norcvbuf;
2224*1991Sheppo 		break;
2225*1991Sheppo 
2226*1991Sheppo 	case MAC_STAT_IERRORS:
2227*1991Sheppo 		val = statsp->ierrors;
2228*1991Sheppo 		break;
2229*1991Sheppo 
2230*1991Sheppo 	case MAC_STAT_NOXMTBUF:
2231*1991Sheppo 		val = statsp->noxmtbuf;
2232*1991Sheppo 		break;
2233*1991Sheppo 
2234*1991Sheppo 	case MAC_STAT_OERRORS:
2235*1991Sheppo 		val = statsp->oerrors;
2236*1991Sheppo 		break;
2237*1991Sheppo 
2238*1991Sheppo 	case MAC_STAT_COLLISIONS:
2239*1991Sheppo 		break;
2240*1991Sheppo 
2241*1991Sheppo 	case MAC_STAT_RBYTES:
2242*1991Sheppo 		val = statsp->rbytes;
2243*1991Sheppo 		break;
2244*1991Sheppo 
2245*1991Sheppo 	case MAC_STAT_IPACKETS:
2246*1991Sheppo 		val = statsp->ipackets;
2247*1991Sheppo 		break;
2248*1991Sheppo 
2249*1991Sheppo 	case MAC_STAT_OBYTES:
2250*1991Sheppo 		val = statsp->obytes;
2251*1991Sheppo 		break;
2252*1991Sheppo 
2253*1991Sheppo 	case MAC_STAT_OPACKETS:
2254*1991Sheppo 		val = statsp->opackets;
2255*1991Sheppo 		break;
2256*1991Sheppo 
2257*1991Sheppo 	/* stats not relevant to ldc, return 0 */
2258*1991Sheppo 	case MAC_STAT_IFSPEED:
2259*1991Sheppo 	case MAC_STAT_ALIGN_ERRORS:
2260*1991Sheppo 	case MAC_STAT_FCS_ERRORS:
2261*1991Sheppo 	case MAC_STAT_FIRST_COLLISIONS:
2262*1991Sheppo 	case MAC_STAT_MULTI_COLLISIONS:
2263*1991Sheppo 	case MAC_STAT_DEFER_XMTS:
2264*1991Sheppo 	case MAC_STAT_TX_LATE_COLLISIONS:
2265*1991Sheppo 	case MAC_STAT_EX_COLLISIONS:
2266*1991Sheppo 	case MAC_STAT_MACXMT_ERRORS:
2267*1991Sheppo 	case MAC_STAT_CARRIER_ERRORS:
2268*1991Sheppo 	case MAC_STAT_TOOLONG_ERRORS:
2269*1991Sheppo 	case MAC_STAT_XCVR_ADDR:
2270*1991Sheppo 	case MAC_STAT_XCVR_ID:
2271*1991Sheppo 	case MAC_STAT_XCVR_INUSE:
2272*1991Sheppo 	case MAC_STAT_CAP_1000FDX:
2273*1991Sheppo 	case MAC_STAT_CAP_1000HDX:
2274*1991Sheppo 	case MAC_STAT_CAP_100FDX:
2275*1991Sheppo 	case MAC_STAT_CAP_100HDX:
2276*1991Sheppo 	case MAC_STAT_CAP_10FDX:
2277*1991Sheppo 	case MAC_STAT_CAP_10HDX:
2278*1991Sheppo 	case MAC_STAT_CAP_ASMPAUSE:
2279*1991Sheppo 	case MAC_STAT_CAP_PAUSE:
2280*1991Sheppo 	case MAC_STAT_CAP_AUTONEG:
2281*1991Sheppo 	case MAC_STAT_ADV_CAP_1000FDX:
2282*1991Sheppo 	case MAC_STAT_ADV_CAP_1000HDX:
2283*1991Sheppo 	case MAC_STAT_ADV_CAP_100FDX:
2284*1991Sheppo 	case MAC_STAT_ADV_CAP_100HDX:
2285*1991Sheppo 	case MAC_STAT_ADV_CAP_10FDX:
2286*1991Sheppo 	case MAC_STAT_ADV_CAP_10HDX:
2287*1991Sheppo 	case MAC_STAT_ADV_CAP_ASMPAUSE:
2288*1991Sheppo 	case MAC_STAT_ADV_CAP_PAUSE:
2289*1991Sheppo 	case MAC_STAT_ADV_CAP_AUTONEG:
2290*1991Sheppo 	case MAC_STAT_LP_CAP_1000FDX:
2291*1991Sheppo 	case MAC_STAT_LP_CAP_1000HDX:
2292*1991Sheppo 	case MAC_STAT_LP_CAP_100FDX:
2293*1991Sheppo 	case MAC_STAT_LP_CAP_100HDX:
2294*1991Sheppo 	case MAC_STAT_LP_CAP_10FDX:
2295*1991Sheppo 	case MAC_STAT_LP_CAP_10HDX:
2296*1991Sheppo 	case MAC_STAT_LP_CAP_ASMPAUSE:
2297*1991Sheppo 	case MAC_STAT_LP_CAP_PAUSE:
2298*1991Sheppo 	case MAC_STAT_LP_CAP_AUTONEG:
2299*1991Sheppo 	case MAC_STAT_LINK_ASMPAUSE:
2300*1991Sheppo 	case MAC_STAT_LINK_PAUSE:
2301*1991Sheppo 	case MAC_STAT_LINK_AUTONEG:
2302*1991Sheppo 	case MAC_STAT_LINK_DUPLEX:
2303*1991Sheppo 	default:
2304*1991Sheppo 		val = 0;
2305*1991Sheppo 		break;
2306*1991Sheppo 
2307*1991Sheppo 	}
2308*1991Sheppo 	return (val);
2309*1991Sheppo }
2310*1991Sheppo 
2311*1991Sheppo static void
2312*1991Sheppo vgen_init_macp(vgen_t *vgenp, mac_t *macp)
2313*1991Sheppo {
2314*1991Sheppo 	macp->m_driver = (void *)vgenp;
2315*1991Sheppo 	macp->m_start = vgen_start;
2316*1991Sheppo 	macp->m_stop = vgen_stop;
2317*1991Sheppo 	macp->m_tx = vgen_tx;
2318*1991Sheppo 	macp->m_resources = vgen_resources;
2319*1991Sheppo 	macp->m_multicst = vgen_multicst;
2320*1991Sheppo 	macp->m_promisc = vgen_promisc;
2321*1991Sheppo 	macp->m_unicst = vgen_unicst;
2322*1991Sheppo 	macp->m_stat = vgen_stat;
2323*1991Sheppo 	macp->m_ioctl = vgen_ioctl;
2324*1991Sheppo }
2325*1991Sheppo 
2326*1991Sheppo /* Interrupt handler for the channel */
2327*1991Sheppo static uint_t
2328*1991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
2329*1991Sheppo {
2330*1991Sheppo 	_NOTE(ARGUNUSED(event))
2331*1991Sheppo 	vgen_ldc_t	*ldcp;
2332*1991Sheppo 	void 		*vnetp;
2333*1991Sheppo 	vgen_t		*vgenp;
2334*1991Sheppo 	size_t		msglen;
2335*1991Sheppo 	ldc_status_t 	istatus;
2336*1991Sheppo 	uint64_t	ldcmsg[7];
2337*1991Sheppo 	int 		rv;
2338*1991Sheppo 	vio_msg_tag_t	*tagp;
2339*1991Sheppo 	mblk_t		*mp = NULL;
2340*1991Sheppo 	mblk_t		*bp = NULL;
2341*1991Sheppo 	mblk_t		*bpt = NULL;
2342*1991Sheppo 	mblk_t		*headp = NULL;
2343*1991Sheppo 	mblk_t		*tailp = NULL;
2344*1991Sheppo 	vgen_stats_t	*statsp;
2345*1991Sheppo 
2346*1991Sheppo 	ldcp = (vgen_ldc_t *)arg;
2347*1991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
2348*1991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
2349*1991Sheppo 	statsp = ldcp->statsp;
2350*1991Sheppo 
2351*1991Sheppo 	DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id));
2352*1991Sheppo 
2353*1991Sheppo 	mutex_enter(&ldcp->cblock);
2354*1991Sheppo 	statsp->callbacks++;
2355*1991Sheppo 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
2356*1991Sheppo 		DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
2357*1991Sheppo 		    ldcp->ldc_id, ldcp->ldc_status));
2358*1991Sheppo 		mutex_exit(&ldcp->cblock);
2359*1991Sheppo 		return (LDC_SUCCESS);
2360*1991Sheppo 	}
2361*1991Sheppo 
2362*1991Sheppo 	/* check ldc status change events first */
2363*1991Sheppo 	(void) ldc_status(ldcp->ldc_handle, &istatus);
2364*1991Sheppo 
2365*1991Sheppo 	if (istatus != ldcp->ldc_status) {
2366*1991Sheppo 		switch (istatus) {
2367*1991Sheppo 		case LDC_UP:
2368*1991Sheppo 			ldcp->ldc_status = istatus;
2369*1991Sheppo 			DBG1((vnetp,
2370*1991Sheppo 			    "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n",
2371*1991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
2372*1991Sheppo 
2373*1991Sheppo 			if (ldcp->portp != vgenp->vsw_portp) {
2374*1991Sheppo 				/*
2375*1991Sheppo 				 * modify fdb entry to use this port as the
2376*1991Sheppo 				 * channel is up, instead of going through the
2377*1991Sheppo 				 * vsw-port (see comments in vgen_port_init())
2378*1991Sheppo 				 */
2379*1991Sheppo 				vnet_modify_fdb(vnetp,
2380*1991Sheppo 				    (uint8_t *)&ldcp->portp->macaddr,
2381*1991Sheppo 				    vgen_tx, ldcp->portp);
2382*1991Sheppo 			}
2383*1991Sheppo 			/* Initialize local session id */
2384*1991Sheppo 			ldcp->local_sid = ddi_get_lbolt();
2385*1991Sheppo 			/* clear peer session id */
2386*1991Sheppo 			ldcp->peer_sid = 0;
2387*1991Sheppo 			ldcp->hretries = 0;
2388*1991Sheppo 			/* Initiate Handshake process with peer ldc endpoint */
2389*1991Sheppo 			vgen_handshake_reset(ldcp);
2390*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
2391*1991Sheppo 			break;
2392*1991Sheppo 
2393*1991Sheppo 		case LDC_OPEN:
2394*1991Sheppo 		case LDC_READY:
2395*1991Sheppo 			ldcp->ldc_status = istatus;
2396*1991Sheppo 			if ((ldcp->portp != vgenp->vsw_portp) &&
2397*1991Sheppo 				(vgenp->vsw_portp != NULL)) {
2398*1991Sheppo 				/*
2399*1991Sheppo 				 * modify fdb entry to use vsw-port  as the
2400*1991Sheppo 				 * channel is reset and we don't have a direct
2401*1991Sheppo 				 * link to the destination (see comments
2402*1991Sheppo 				 * in vgen_port_init()).
2403*1991Sheppo 				 */
2404*1991Sheppo 				vnet_modify_fdb(vnetp,
2405*1991Sheppo 				    (uint8_t *)&ldcp->portp->macaddr,
2406*1991Sheppo 				    vgen_tx, vgenp->vsw_portp);
2407*1991Sheppo 			}
2408*1991Sheppo 			/* clear sids */
2409*1991Sheppo 			ldcp->local_sid = 0;
2410*1991Sheppo 			ldcp->peer_sid = 0;
2411*1991Sheppo 			if (ldcp->hphase != VH_PHASE0) {
2412*1991Sheppo 				vgen_handshake_reset(ldcp);
2413*1991Sheppo 			}
2414*1991Sheppo 			DBG1((vnetp,
2415*1991Sheppo 			    "vgen_ldc_cb: id(%lx) status is (%d)\n",
2416*1991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
2417*1991Sheppo 			break;
2418*1991Sheppo 
2419*1991Sheppo 		default:
2420*1991Sheppo 			DWARN((vnetp,
2421*1991Sheppo 			    "vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is"
2422*1991Sheppo 			    " *UNKNOWN*\n",
2423*1991Sheppo 			    ldcp->ldc_id, istatus, ldcp->ldc_status));
2424*1991Sheppo 			break;
2425*1991Sheppo 		}
2426*1991Sheppo 	}
2427*1991Sheppo 
2428*1991Sheppo 	if (istatus != LDC_UP) {
2429*1991Sheppo 		DBG1((vnetp, "vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n",
2430*1991Sheppo 			    ldcp->ldc_id, ldcp->ldc_status));
2431*1991Sheppo 		mutex_exit(&ldcp->cblock);
2432*1991Sheppo 		return (LDC_SUCCESS);
2433*1991Sheppo 	}
2434*1991Sheppo 
2435*1991Sheppo 	/* if ldc_status is UP, receive all packets */
2436*1991Sheppo 	do {
2437*1991Sheppo 		msglen = sizeof (ldcmsg);
2438*1991Sheppo 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
2439*1991Sheppo 
2440*1991Sheppo 		if (rv != 0) {
2441*1991Sheppo 			DWARN((vnetp,
2442*1991Sheppo 			    "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) "
2443*1991Sheppo 			    "len(%d)\n", ldcp->ldc_id, rv, msglen));
2444*1991Sheppo 			break;
2445*1991Sheppo 		}
2446*1991Sheppo 		if (msglen == 0) {
2447*1991Sheppo 			DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA",
2448*1991Sheppo 			ldcp->ldc_id));
2449*1991Sheppo 			break;
2450*1991Sheppo 		}
2451*1991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
2452*1991Sheppo 		    ldcp->ldc_id, msglen));
2453*1991Sheppo 
2454*1991Sheppo 		tagp = (vio_msg_tag_t *)ldcmsg;
2455*1991Sheppo 
2456*1991Sheppo 		if (ldcp->peer_sid) {
2457*1991Sheppo 			/*
2458*1991Sheppo 			 * check sid only after we have received peer's sid
2459*1991Sheppo 			 * in the version negotiate msg.
2460*1991Sheppo 			 */
2461*1991Sheppo #ifdef DEBUG
2462*1991Sheppo 			if (vgen_hdbg & HDBG_BAD_SID) {
2463*1991Sheppo 				/* simulate bad sid condition */
2464*1991Sheppo 				tagp->vio_sid = 0;
2465*1991Sheppo 				vgen_hdbg &= ~(HDBG_BAD_SID);
2466*1991Sheppo 			}
2467*1991Sheppo #endif
2468*1991Sheppo 			if (vgen_check_sid(ldcp, tagp) == VGEN_FAILURE) {
2469*1991Sheppo 				/*
2470*1991Sheppo 				 * If sid mismatch is detected,
2471*1991Sheppo 				 * reset the channel.
2472*1991Sheppo 				 */
2473*1991Sheppo 				ldcp->need_ldc_reset = B_TRUE;
2474*1991Sheppo 				vgen_handshake_reset(ldcp);
2475*1991Sheppo 				mutex_exit(&ldcp->cblock);
2476*1991Sheppo 				return (LDC_SUCCESS);
2477*1991Sheppo 			}
2478*1991Sheppo 		}
2479*1991Sheppo 
2480*1991Sheppo 		switch (tagp->vio_msgtype) {
2481*1991Sheppo 		case VIO_TYPE_CTRL:
2482*1991Sheppo 			vgen_handle_ctrlmsg(ldcp, tagp);
2483*1991Sheppo 			break;
2484*1991Sheppo 
2485*1991Sheppo 		case VIO_TYPE_DATA:
2486*1991Sheppo 			headp = tailp = NULL;
2487*1991Sheppo 			vgen_handle_datamsg(ldcp, tagp, &headp, &tailp);
2488*1991Sheppo 			/* build a chain of received packets */
2489*1991Sheppo 			if (headp != NULL) {
2490*1991Sheppo 				if (bp == NULL) {
2491*1991Sheppo 					bp = headp;
2492*1991Sheppo 					bpt = tailp;
2493*1991Sheppo 				} else {
2494*1991Sheppo 					bpt->b_next = headp;
2495*1991Sheppo 					bpt = tailp;
2496*1991Sheppo 				}
2497*1991Sheppo 			}
2498*1991Sheppo 			break;
2499*1991Sheppo 
2500*1991Sheppo 		case VIO_TYPE_ERR:
2501*1991Sheppo 			vgen_handle_errmsg(ldcp, tagp);
2502*1991Sheppo 			break;
2503*1991Sheppo 
2504*1991Sheppo 		default:
2505*1991Sheppo 			DWARN((vnetp,
2506*1991Sheppo 			    "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
2507*1991Sheppo 			    tagp->vio_msgtype));
2508*1991Sheppo 			break;
2509*1991Sheppo 		}
2510*1991Sheppo 
2511*1991Sheppo 	} while (msglen);
2512*1991Sheppo 
2513*1991Sheppo 	mutex_exit(&ldcp->cblock);
2514*1991Sheppo 	/* send up the received packets to MAC layer */
2515*1991Sheppo 	while (bp != NULL) {
2516*1991Sheppo 		mp = bp;
2517*1991Sheppo 		bp = bp->b_next;
2518*1991Sheppo 		mp->b_next = mp->b_prev = NULL;
2519*1991Sheppo 		DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
2520*1991Sheppo 		    ldcp->ldc_id, MBLKL(mp)));
2521*1991Sheppo 		mac_rx((mac_t *)vgenp->vnetmacp, vgenp->mrh, mp);
2522*1991Sheppo 	}
2523*1991Sheppo 	DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id));
2524*1991Sheppo 
2525*1991Sheppo 	return (LDC_SUCCESS);
2526*1991Sheppo }
2527*1991Sheppo 
2528*1991Sheppo /* vgen handshake functions */
2529*1991Sheppo 
2530*1991Sheppo /* change the hphase for the channel to the next phase */
2531*1991Sheppo static vgen_ldc_t *
2532*1991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
2533*1991Sheppo {
2534*1991Sheppo 	if (ldcp->hphase == VH_PHASE3) {
2535*1991Sheppo 		ldcp->hphase = VH_DONE;
2536*1991Sheppo 	} else {
2537*1991Sheppo 		ldcp->hphase++;
2538*1991Sheppo 	}
2539*1991Sheppo 	return (ldcp);
2540*1991Sheppo }
2541*1991Sheppo 
2542*1991Sheppo /*
2543*1991Sheppo  * Check whether the given version is supported or not and
2544*1991Sheppo  * return VGEN_SUCCESS if supported.
2545*1991Sheppo  */
2546*1991Sheppo static int
2547*1991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
2548*1991Sheppo uint16_t ver_minor)
2549*1991Sheppo {
2550*1991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
2551*1991Sheppo 	int		i = 0;
2552*1991Sheppo 
2553*1991Sheppo 	while (i < VGEN_NUM_VER) {
2554*1991Sheppo 		if ((versions[i].ver_major == 0) &&
2555*1991Sheppo 		    (versions[i].ver_minor == 0)) {
2556*1991Sheppo 			break;
2557*1991Sheppo 		}
2558*1991Sheppo 		if ((versions[i].ver_major == ver_major) &&
2559*1991Sheppo 			(versions[i].ver_minor == ver_minor)) {
2560*1991Sheppo 			return (VGEN_SUCCESS);
2561*1991Sheppo 		}
2562*1991Sheppo 		i++;
2563*1991Sheppo 	}
2564*1991Sheppo 	return (VGEN_FAILURE);
2565*1991Sheppo }
2566*1991Sheppo 
2567*1991Sheppo /*
2568*1991Sheppo  * Given a version, return VGEN_SUCCESS if a lower version is supported.
2569*1991Sheppo  */
2570*1991Sheppo static int
2571*1991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp)
2572*1991Sheppo {
2573*1991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
2574*1991Sheppo 	int		i = 0;
2575*1991Sheppo 
2576*1991Sheppo 	while (i < VGEN_NUM_VER) {
2577*1991Sheppo 		if ((versions[i].ver_major == 0) &&
2578*1991Sheppo 		    (versions[i].ver_minor == 0)) {
2579*1991Sheppo 			break;
2580*1991Sheppo 		}
2581*1991Sheppo 		/*
2582*1991Sheppo 		 * if we support a lower minor version within the same major
2583*1991Sheppo 		 * version, or if we support a lower major version,
2584*1991Sheppo 		 * update the verp parameter with this lower version and
2585*1991Sheppo 		 * return success.
2586*1991Sheppo 		 */
2587*1991Sheppo 		if (((versions[i].ver_major == verp->ver_major) &&
2588*1991Sheppo 			(versions[i].ver_minor < verp->ver_minor)) ||
2589*1991Sheppo 			(versions[i].ver_major < verp->ver_major)) {
2590*1991Sheppo 				verp->ver_major = versions[i].ver_major;
2591*1991Sheppo 				verp->ver_minor = versions[i].ver_minor;
2592*1991Sheppo 				return (VGEN_SUCCESS);
2593*1991Sheppo 		}
2594*1991Sheppo 		i++;
2595*1991Sheppo 	}
2596*1991Sheppo 
2597*1991Sheppo 	return (VGEN_FAILURE);
2598*1991Sheppo }
2599*1991Sheppo 
2600*1991Sheppo /*
2601*1991Sheppo  * wrapper routine to send the given message over ldc using ldc_write().
2602*1991Sheppo  */
2603*1991Sheppo static int
2604*1991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
2605*1991Sheppo     boolean_t caller_holds_lock)
2606*1991Sheppo {
2607*1991Sheppo 	int	rv;
2608*1991Sheppo 	size_t	len;
2609*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
2610*1991Sheppo 	uint32_t retries = 0;
2611*1991Sheppo 
2612*1991Sheppo 	len = msglen;
2613*1991Sheppo 	if ((len == 0) || (msg == NULL))
2614*1991Sheppo 		return (VGEN_FAILURE);
2615*1991Sheppo 
2616*1991Sheppo 	if (!caller_holds_lock) {
2617*1991Sheppo 		mutex_enter(&ldcp->txlock);
2618*1991Sheppo 	}
2619*1991Sheppo 
2620*1991Sheppo 	do {
2621*1991Sheppo 		len = msglen;
2622*1991Sheppo 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
2623*1991Sheppo 		if (retries++ >= vgen_ldcwr_retries)
2624*1991Sheppo 			break;
2625*1991Sheppo 	} while (rv == EWOULDBLOCK);
2626*1991Sheppo 
2627*1991Sheppo 	if (!caller_holds_lock) {
2628*1991Sheppo 		mutex_exit(&ldcp->txlock);
2629*1991Sheppo 	}
2630*1991Sheppo 
2631*1991Sheppo 	if ((rv != 0) || (len != msglen)) {
2632*1991Sheppo 		DWARN((vnetp,
2633*1991Sheppo 		    "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)"
2634*1991Sheppo 		    " msglen (%d)\n", ldcp->ldc_id, rv, msglen));
2635*1991Sheppo 		return (VGEN_FAILURE);
2636*1991Sheppo 	}
2637*1991Sheppo 	return (VGEN_SUCCESS);
2638*1991Sheppo }
2639*1991Sheppo 
2640*1991Sheppo /* send version negotiate message to the peer over ldc */
2641*1991Sheppo static int
2642*1991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
2643*1991Sheppo {
2644*1991Sheppo 	vio_ver_msg_t	vermsg;
2645*1991Sheppo 	vio_msg_tag_t	*tagp = &vermsg.tag;
2646*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
2647*1991Sheppo 	int		rv;
2648*1991Sheppo 
2649*1991Sheppo 	bzero(&vermsg, sizeof (vermsg));
2650*1991Sheppo 
2651*1991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2652*1991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2653*1991Sheppo 	tagp->vio_subtype_env = VIO_VER_INFO;
2654*1991Sheppo 	tagp->vio_sid = ldcp->local_sid;
2655*1991Sheppo 
2656*1991Sheppo 	/* get version msg payload from ldcp->local */
2657*1991Sheppo 	vermsg.ver_major = ldcp->local_hparams.ver_major;
2658*1991Sheppo 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
2659*1991Sheppo 	vermsg.dev_class = ldcp->local_hparams.dev_class;
2660*1991Sheppo 
2661*1991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
2662*1991Sheppo 	if (rv != VGEN_SUCCESS) {
2663*1991Sheppo 		DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed"
2664*1991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
2665*1991Sheppo 		return (VGEN_FAILURE);
2666*1991Sheppo 	}
2667*1991Sheppo 
2668*1991Sheppo 	ldcp->hstate |= VER_INFO_SENT;
2669*1991Sheppo 	DBG2((vnetp,
2670*1991Sheppo 	    "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
2671*1991Sheppo 	    ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor));
2672*1991Sheppo 
2673*1991Sheppo 	return (VGEN_SUCCESS);
2674*1991Sheppo }
2675*1991Sheppo 
2676*1991Sheppo /* send attr info message to the peer over ldc */
2677*1991Sheppo static int
2678*1991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
2679*1991Sheppo {
2680*1991Sheppo 	vnet_attr_msg_t	attrmsg;
2681*1991Sheppo 	vio_msg_tag_t	*tagp = &attrmsg.tag;
2682*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
2683*1991Sheppo 	int		rv;
2684*1991Sheppo 
2685*1991Sheppo 	bzero(&attrmsg, sizeof (attrmsg));
2686*1991Sheppo 
2687*1991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2688*1991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2689*1991Sheppo 	tagp->vio_subtype_env = VIO_ATTR_INFO;
2690*1991Sheppo 	tagp->vio_sid = ldcp->local_sid;
2691*1991Sheppo 
2692*1991Sheppo 	/* get attr msg payload from ldcp->local */
2693*1991Sheppo 	attrmsg.mtu = ldcp->local_hparams.mtu;
2694*1991Sheppo 	attrmsg.addr = ldcp->local_hparams.addr;
2695*1991Sheppo 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
2696*1991Sheppo 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
2697*1991Sheppo 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
2698*1991Sheppo 
2699*1991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
2700*1991Sheppo 	if (rv != VGEN_SUCCESS) {
2701*1991Sheppo 		DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed"
2702*1991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
2703*1991Sheppo 		return (VGEN_FAILURE);
2704*1991Sheppo 	}
2705*1991Sheppo 
2706*1991Sheppo 	ldcp->hstate |= ATTR_INFO_SENT;
2707*1991Sheppo 	DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
2708*1991Sheppo 	    ldcp->ldc_id));
2709*1991Sheppo 
2710*1991Sheppo 	return (VGEN_SUCCESS);
2711*1991Sheppo }
2712*1991Sheppo 
2713*1991Sheppo /* send descriptor ring register message to the peer over ldc */
2714*1991Sheppo static int
2715*1991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp)
2716*1991Sheppo {
2717*1991Sheppo 	vio_dring_reg_msg_t	msg;
2718*1991Sheppo 	vio_msg_tag_t		*tagp = &msg.tag;
2719*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
2720*1991Sheppo 	int		rv;
2721*1991Sheppo 
2722*1991Sheppo 	bzero(&msg, sizeof (msg));
2723*1991Sheppo 
2724*1991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2725*1991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2726*1991Sheppo 	tagp->vio_subtype_env = VIO_DRING_REG;
2727*1991Sheppo 	tagp->vio_sid = ldcp->local_sid;
2728*1991Sheppo 
2729*1991Sheppo 	/* get dring info msg payload from ldcp->local */
2730*1991Sheppo 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
2731*1991Sheppo 		sizeof (ldc_mem_cookie_t));
2732*1991Sheppo 	msg.ncookies = ldcp->local_hparams.num_dcookies;
2733*1991Sheppo 	msg.num_descriptors = ldcp->local_hparams.num_desc;
2734*1991Sheppo 	msg.descriptor_size = ldcp->local_hparams.desc_size;
2735*1991Sheppo 
2736*1991Sheppo 	/*
2737*1991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
2738*1991Sheppo 	 * value and sends it in the ack, which is saved in
2739*1991Sheppo 	 * vgen_handle_dring_reg().
2740*1991Sheppo 	 */
2741*1991Sheppo 	msg.dring_ident = 0;
2742*1991Sheppo 
2743*1991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
2744*1991Sheppo 	if (rv != VGEN_SUCCESS) {
2745*1991Sheppo 		DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed"
2746*1991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
2747*1991Sheppo 		return (VGEN_FAILURE);
2748*1991Sheppo 	}
2749*1991Sheppo 
2750*1991Sheppo 	ldcp->hstate |= DRING_INFO_SENT;
2751*1991Sheppo 	DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
2752*1991Sheppo 	    ldcp->ldc_id));
2753*1991Sheppo 
2754*1991Sheppo 	return (VGEN_SUCCESS);
2755*1991Sheppo }
2756*1991Sheppo 
2757*1991Sheppo static int
2758*1991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
2759*1991Sheppo {
2760*1991Sheppo 	vio_rdx_msg_t	rdxmsg;
2761*1991Sheppo 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
2762*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
2763*1991Sheppo 	int		rv;
2764*1991Sheppo 
2765*1991Sheppo 	bzero(&rdxmsg, sizeof (rdxmsg));
2766*1991Sheppo 
2767*1991Sheppo 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2768*1991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2769*1991Sheppo 	tagp->vio_subtype_env = VIO_RDX;
2770*1991Sheppo 	tagp->vio_sid = ldcp->local_sid;
2771*1991Sheppo 
2772*1991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
2773*1991Sheppo 	if (rv != VGEN_SUCCESS) {
2774*1991Sheppo 		DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed"
2775*1991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
2776*1991Sheppo 		return (VGEN_FAILURE);
2777*1991Sheppo 	}
2778*1991Sheppo 
2779*1991Sheppo 	ldcp->hstate |= RDX_INFO_SENT;
2780*1991Sheppo 	DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
2781*1991Sheppo 	    ldcp->ldc_id));
2782*1991Sheppo 
2783*1991Sheppo 	return (VGEN_SUCCESS);
2784*1991Sheppo }
2785*1991Sheppo 
2786*1991Sheppo /* send descriptor ring data message to the peer over ldc */
2787*1991Sheppo static int
2788*1991Sheppo vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, uint32_t end,
2789*1991Sheppo 	uint64_t next_txseq)
2790*1991Sheppo {
2791*1991Sheppo 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
2792*1991Sheppo 	vio_msg_tag_t	*tagp = &msgp->tag;
2793*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
2794*1991Sheppo 	int		rv;
2795*1991Sheppo 
2796*1991Sheppo 	bzero(msgp, sizeof (*msgp));
2797*1991Sheppo 
2798*1991Sheppo 	tagp->vio_msgtype = VIO_TYPE_DATA;
2799*1991Sheppo 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2800*1991Sheppo 	tagp->vio_subtype_env = VIO_DRING_DATA;
2801*1991Sheppo 	tagp->vio_sid = ldcp->local_sid;
2802*1991Sheppo 
2803*1991Sheppo 	msgp->seq_num = next_txseq;
2804*1991Sheppo 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
2805*1991Sheppo 	msgp->start_idx = start;
2806*1991Sheppo 	msgp->end_idx = end;
2807*1991Sheppo 
2808*1991Sheppo 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
2809*1991Sheppo 	if (rv != VGEN_SUCCESS) {
2810*1991Sheppo 		DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed"
2811*1991Sheppo 		    "id (%lx)\n", ldcp->ldc_id));
2812*1991Sheppo 		return (VGEN_FAILURE);
2813*1991Sheppo 	}
2814*1991Sheppo 
2815*1991Sheppo 	DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
2816*1991Sheppo 	    ldcp->ldc_id));
2817*1991Sheppo 
2818*1991Sheppo 	return (VGEN_SUCCESS);
2819*1991Sheppo }
2820*1991Sheppo 
2821*1991Sheppo /* send multicast addr info message to vsw */
2822*1991Sheppo static int
2823*1991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
2824*1991Sheppo {
2825*1991Sheppo 	vnet_mcast_msg_t	mcastmsg;
2826*1991Sheppo 	vnet_mcast_msg_t	*msgp;
2827*1991Sheppo 	vio_msg_tag_t		*tagp;
2828*1991Sheppo 	vgen_t			*vgenp;
2829*1991Sheppo 	void			*vnetp;
2830*1991Sheppo 	struct ether_addr	*mca;
2831*1991Sheppo 	int			rv;
2832*1991Sheppo 	int			i;
2833*1991Sheppo 	uint32_t		size;
2834*1991Sheppo 	uint32_t		mccount;
2835*1991Sheppo 	uint32_t		n;
2836*1991Sheppo 
2837*1991Sheppo 	msgp = &mcastmsg;
2838*1991Sheppo 	tagp = &msgp->tag;
2839*1991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
2840*1991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
2841*1991Sheppo 
2842*1991Sheppo 	mccount = vgenp->mccount;
2843*1991Sheppo 	i = 0;
2844*1991Sheppo 
2845*1991Sheppo 	do {
2846*1991Sheppo 		tagp->vio_msgtype = VIO_TYPE_CTRL;
2847*1991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
2848*1991Sheppo 		tagp->vio_subtype_env = VNET_MCAST_INFO;
2849*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
2850*1991Sheppo 
2851*1991Sheppo 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
2852*1991Sheppo 		size = n * sizeof (struct ether_addr);
2853*1991Sheppo 
2854*1991Sheppo 		mca = &(vgenp->mctab[i]);
2855*1991Sheppo 		bcopy(mca, (msgp->mca), size);
2856*1991Sheppo 		msgp->set = B_TRUE;
2857*1991Sheppo 		msgp->count = n;
2858*1991Sheppo 
2859*1991Sheppo 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
2860*1991Sheppo 		    B_FALSE);
2861*1991Sheppo 		if (rv != VGEN_SUCCESS) {
2862*1991Sheppo 			DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err"
2863*1991Sheppo 			    "id (%lx)\n", ldcp->ldc_id));
2864*1991Sheppo 			return (VGEN_FAILURE);
2865*1991Sheppo 		}
2866*1991Sheppo 
2867*1991Sheppo 		mccount -= n;
2868*1991Sheppo 		i += n;
2869*1991Sheppo 
2870*1991Sheppo 	} while (mccount);
2871*1991Sheppo 
2872*1991Sheppo 	return (VGEN_SUCCESS);
2873*1991Sheppo }
2874*1991Sheppo 
2875*1991Sheppo /* Initiate Phase 2 of handshake */
2876*1991Sheppo static int
2877*1991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
2878*1991Sheppo {
2879*1991Sheppo 	int rv;
2880*1991Sheppo #ifdef DEBUG
2881*1991Sheppo 	if (vgen_hdbg & HDBG_OUT_STATE) {
2882*1991Sheppo 		/* simulate out of state condition */
2883*1991Sheppo 		vgen_hdbg &= ~(HDBG_OUT_STATE);
2884*1991Sheppo 		rv = vgen_send_rdx_info(ldcp);
2885*1991Sheppo 		return (rv);
2886*1991Sheppo 	}
2887*1991Sheppo 	if (vgen_hdbg & HDBG_TIMEOUT) {
2888*1991Sheppo 		/* simulate timeout condition */
2889*1991Sheppo 		vgen_hdbg &= ~(HDBG_TIMEOUT);
2890*1991Sheppo 		return (VGEN_SUCCESS);
2891*1991Sheppo 	}
2892*1991Sheppo #endif
2893*1991Sheppo 	if ((rv = vgen_send_attr_info(ldcp)) != VGEN_SUCCESS) {
2894*1991Sheppo 		return (rv);
2895*1991Sheppo 	}
2896*1991Sheppo 	if ((rv = vgen_send_dring_reg(ldcp)) != VGEN_SUCCESS) {
2897*1991Sheppo 		return (rv);
2898*1991Sheppo 	}
2899*1991Sheppo 
2900*1991Sheppo 	return (VGEN_SUCCESS);
2901*1991Sheppo }
2902*1991Sheppo 
2903*1991Sheppo /*
2904*1991Sheppo  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
2905*1991Sheppo  * This can happen after a channel comes up (status: LDC_UP) or
2906*1991Sheppo  * when handshake gets terminated due to various conditions.
2907*1991Sheppo  */
2908*1991Sheppo static void
2909*1991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp)
2910*1991Sheppo {
2911*1991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
2912*1991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
2913*1991Sheppo 	ldc_status_t istatus;
2914*1991Sheppo 
2915*1991Sheppo 	DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id));
2916*1991Sheppo 	/* reset hstate and hphase */
2917*1991Sheppo 	ldcp->hstate = 0;
2918*1991Sheppo 	ldcp->hphase = VH_PHASE0;
2919*1991Sheppo 
2920*1991Sheppo 	/* reset handshake watchdog timeout */
2921*1991Sheppo 	if (ldcp->htid) {
2922*1991Sheppo 		(void) untimeout(ldcp->htid);
2923*1991Sheppo 		ldcp->htid = 0;
2924*1991Sheppo 	}
2925*1991Sheppo 
2926*1991Sheppo 	/*
2927*1991Sheppo 	 * Unmap drings, if dring_ready is set.
2928*1991Sheppo 	 */
2929*1991Sheppo 	if (ldcp->local_hparams.dring_ready) {
2930*1991Sheppo 		ldcp->local_hparams.dring_ready = B_FALSE;
2931*1991Sheppo 		/* do not unbind our dring */
2932*1991Sheppo 	}
2933*1991Sheppo 
2934*1991Sheppo 	if (ldcp->peer_hparams.dring_ready) {
2935*1991Sheppo 		ldcp->peer_hparams.dring_ready = B_FALSE;
2936*1991Sheppo 		/* Unmap peer's dring */
2937*1991Sheppo 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
2938*1991Sheppo 		vgen_clobber_rxds(ldcp);
2939*1991Sheppo 	}
2940*1991Sheppo 
2941*1991Sheppo 	vgen_clobber_tbufs(ldcp);
2942*1991Sheppo 
2943*1991Sheppo 	/*
2944*1991Sheppo 	 * clear local handshake params and initialize.
2945*1991Sheppo 	 */
2946*1991Sheppo 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
2947*1991Sheppo 
2948*1991Sheppo #ifdef DEBUG
2949*1991Sheppo #if 0
2950*1991Sheppo 	if (vgen_hdbg & HDBG_VERSION) {
2951*1991Sheppo 		bcopy(dbg_vgen_versions, ldcp->vgen_versions,
2952*1991Sheppo 		    sizeof (ldcp->vgen_versions));
2953*1991Sheppo 	}
2954*1991Sheppo #endif
2955*1991Sheppo #endif
2956*1991Sheppo 	/* set version to the highest version supported */
2957*1991Sheppo 	ldcp->local_hparams.ver_major =
2958*1991Sheppo 			ldcp->vgen_versions[0].ver_major;
2959*1991Sheppo 	ldcp->local_hparams.ver_minor =
2960*1991Sheppo 			ldcp->vgen_versions[0].ver_minor;
2961*1991Sheppo 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
2962*1991Sheppo 
2963*1991Sheppo 	/* set attr_info params */
2964*1991Sheppo 	ldcp->local_hparams.mtu = ETHERMAX;
2965*1991Sheppo 	ldcp->local_hparams.addr =
2966*1991Sheppo 		vgen_macaddr_strtoul(vgenp->macaddr);
2967*1991Sheppo 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
2968*1991Sheppo 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE;
2969*1991Sheppo 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
2970*1991Sheppo 
2971*1991Sheppo #ifdef DEBUG
2972*1991Sheppo #if 0
2973*1991Sheppo 	vgen_print_attr_info(ldcp, VGEN_LOCAL);
2974*1991Sheppo #endif
2975*1991Sheppo #endif
2976*1991Sheppo 
2977*1991Sheppo 	/*
2978*1991Sheppo 	 * set dring_info params.
2979*1991Sheppo 	 * Note: dring is already created and bound.
2980*1991Sheppo 	 */
2981*1991Sheppo 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
2982*1991Sheppo 		sizeof (ldc_mem_cookie_t));
2983*1991Sheppo 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
2984*1991Sheppo 	ldcp->local_hparams.num_desc = ldcp->num_txds;
2985*1991Sheppo 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
2986*1991Sheppo 
2987*1991Sheppo 	/*
2988*1991Sheppo 	 * dring_ident is set to 0. After mapping the dring, peer sets this
2989*1991Sheppo 	 * value and sends it in the ack, which is saved in
2990*1991Sheppo 	 * vgen_handle_dring_reg().
2991*1991Sheppo 	 */
2992*1991Sheppo 	ldcp->local_hparams.dring_ident = 0;
2993*1991Sheppo 
2994*1991Sheppo 	/* clear peer_hparams */
2995*1991Sheppo 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
2996*1991Sheppo 
2997*1991Sheppo 	/* reset the channel if required */
2998*1991Sheppo 	if (ldcp->need_ldc_reset) {
2999*1991Sheppo 		DWARN((vnetp,
3000*1991Sheppo 		    "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
3001*1991Sheppo 		    ldcp->ldc_id));
3002*1991Sheppo 		ldcp->need_ldc_reset = B_FALSE;
3003*1991Sheppo 		(void) ldc_reset(ldcp->ldc_handle);
3004*1991Sheppo 		(void) ldc_status(ldcp->ldc_handle, &istatus);
3005*1991Sheppo 		DBG2((vnetp,
3006*1991Sheppo 		    "vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n",
3007*1991Sheppo 		    ldcp->ldc_id, istatus));
3008*1991Sheppo 		ldcp->ldc_status = istatus;
3009*1991Sheppo 		/* clear sids */
3010*1991Sheppo 		ldcp->local_sid = 0;
3011*1991Sheppo 		ldcp->peer_sid = 0;
3012*1991Sheppo 		(void) ldc_up(ldcp->ldc_handle);
3013*1991Sheppo 	}
3014*1991Sheppo }
3015*1991Sheppo 
3016*1991Sheppo /* wrapper function for vgen_reset_hphase */
3017*1991Sheppo static void
3018*1991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp)
3019*1991Sheppo {
3020*1991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->cblock));
3021*1991Sheppo 	mutex_enter(&ldcp->txlock);
3022*1991Sheppo 	mutex_enter(&ldcp->tclock);
3023*1991Sheppo 
3024*1991Sheppo 	vgen_reset_hphase(ldcp);
3025*1991Sheppo 
3026*1991Sheppo 	mutex_exit(&ldcp->tclock);
3027*1991Sheppo 	mutex_exit(&ldcp->txlock);
3028*1991Sheppo }
3029*1991Sheppo 
3030*1991Sheppo /*
3031*1991Sheppo  * Initiate handshake with the peer by sending various messages
3032*1991Sheppo  * based on the handshake-phase that the channel is currently in.
3033*1991Sheppo  */
3034*1991Sheppo static void
3035*1991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
3036*1991Sheppo {
3037*1991Sheppo 	uint32_t hphase = ldcp->hphase;
3038*1991Sheppo 	void	*vnetp = LDC_TO_VNET(ldcp);
3039*1991Sheppo 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
3040*1991Sheppo 
3041*1991Sheppo 	switch (hphase) {
3042*1991Sheppo 
3043*1991Sheppo 	case VH_PHASE1:
3044*1991Sheppo 
3045*1991Sheppo 		/*
3046*1991Sheppo 		 * start timer, for entire handshake process, turn this timer
3047*1991Sheppo 		 * off if all phases of handshake complete successfully and
3048*1991Sheppo 		 * hphase goes to VH_DONE(below) or
3049*1991Sheppo 		 * vgen_reset_hphase() gets called or
3050*1991Sheppo 		 * channel is reset due to errors or
3051*1991Sheppo 		 * vgen_ldc_uninit() is invoked(vgen_stop).
3052*1991Sheppo 		 */
3053*1991Sheppo 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
3054*1991Sheppo 		    drv_usectohz(vgen_hwd_interval * 1000));
3055*1991Sheppo 
3056*1991Sheppo 		/* Phase 1 involves negotiating the version */
3057*1991Sheppo 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
3058*1991Sheppo 			vgen_handshake_reset(ldcp);
3059*1991Sheppo 		}
3060*1991Sheppo 		break;
3061*1991Sheppo 
3062*1991Sheppo 	case VH_PHASE2:
3063*1991Sheppo 		if (vgen_handshake_phase2(ldcp) != VGEN_SUCCESS) {
3064*1991Sheppo 			vgen_handshake_reset(ldcp);
3065*1991Sheppo 		}
3066*1991Sheppo 		break;
3067*1991Sheppo 
3068*1991Sheppo 	case VH_PHASE3:
3069*1991Sheppo 		if (vgen_send_rdx_info(ldcp) != VGEN_SUCCESS) {
3070*1991Sheppo 			vgen_handshake_reset(ldcp);
3071*1991Sheppo 		}
3072*1991Sheppo 		break;
3073*1991Sheppo 
3074*1991Sheppo 	case VH_DONE:
3075*1991Sheppo 		/* reset handshake watchdog timeout */
3076*1991Sheppo 		if (ldcp->htid) {
3077*1991Sheppo 			(void) untimeout(ldcp->htid);
3078*1991Sheppo 			ldcp->htid = 0;
3079*1991Sheppo 		}
3080*1991Sheppo 		ldcp->hretries = 0;
3081*1991Sheppo #if 0
3082*1991Sheppo 		vgen_print_ldcinfo(ldcp);
3083*1991Sheppo #endif
3084*1991Sheppo 		DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n",
3085*1991Sheppo 		    ldcp->ldc_id));
3086*1991Sheppo 
3087*1991Sheppo 		if (ldcp->need_mcast_sync) {
3088*1991Sheppo 			/* need to sync multicast table with vsw */
3089*1991Sheppo 
3090*1991Sheppo 			ldcp->need_mcast_sync = B_FALSE;
3091*1991Sheppo 			mutex_exit(&ldcp->cblock);
3092*1991Sheppo 
3093*1991Sheppo 			mutex_enter(&vgenp->lock);
3094*1991Sheppo 			(void) vgen_send_mcast_info(ldcp);
3095*1991Sheppo 			mutex_exit(&vgenp->lock);
3096*1991Sheppo 
3097*1991Sheppo 			mutex_enter(&ldcp->cblock);
3098*1991Sheppo 
3099*1991Sheppo 		}
3100*1991Sheppo 		break;
3101*1991Sheppo 
3102*1991Sheppo 	default:
3103*1991Sheppo 		break;
3104*1991Sheppo 	}
3105*1991Sheppo }
3106*1991Sheppo 
3107*1991Sheppo /*
3108*1991Sheppo  * Check if the current handshake phase has completed successfully and
3109*1991Sheppo  * return the status.
3110*1991Sheppo  */
3111*1991Sheppo static int
3112*1991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
3113*1991Sheppo {
3114*1991Sheppo 	uint32_t	hphase = ldcp->hphase;
3115*1991Sheppo 	int 		status = 0;
3116*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
3117*1991Sheppo 
3118*1991Sheppo 	switch (hphase) {
3119*1991Sheppo 
3120*1991Sheppo 	case VH_PHASE1:
3121*1991Sheppo 		/*
3122*1991Sheppo 		 * Phase1 is done, if version negotiation
3123*1991Sheppo 		 * completed successfully.
3124*1991Sheppo 		 */
3125*1991Sheppo 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
3126*1991Sheppo 			VER_NEGOTIATED);
3127*1991Sheppo 		break;
3128*1991Sheppo 
3129*1991Sheppo 	case VH_PHASE2:
3130*1991Sheppo 		/*
3131*1991Sheppo 		 * Phase 2 is done, if attr info and dring info
3132*1991Sheppo 		 * have been exchanged successfully.
3133*1991Sheppo 		 */
3134*1991Sheppo 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
3135*1991Sheppo 			    ATTR_INFO_EXCHANGED) &&
3136*1991Sheppo 			    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
3137*1991Sheppo 			    DRING_INFO_EXCHANGED));
3138*1991Sheppo 		break;
3139*1991Sheppo 
3140*1991Sheppo 	case VH_PHASE3:
3141*1991Sheppo 		/* Phase 3 is done, if rdx msg has been exchanged */
3142*1991Sheppo 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
3143*1991Sheppo 			RDX_EXCHANGED);
3144*1991Sheppo 		break;
3145*1991Sheppo 
3146*1991Sheppo 	default:
3147*1991Sheppo 		break;
3148*1991Sheppo 	}
3149*1991Sheppo 
3150*1991Sheppo 	if (status == 0) {
3151*1991Sheppo 		return (VGEN_FAILURE);
3152*1991Sheppo 	}
3153*1991Sheppo 	DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase));
3154*1991Sheppo 	return (VGEN_SUCCESS);
3155*1991Sheppo }
3156*1991Sheppo 
3157*1991Sheppo /* retry handshake on failure */
3158*1991Sheppo static void
3159*1991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp)
3160*1991Sheppo {
3161*1991Sheppo 	/* reset handshake phase */
3162*1991Sheppo 	vgen_handshake_reset(ldcp);
3163*1991Sheppo 	if (vgen_max_hretries) {	/* handshake retry is specified */
3164*1991Sheppo 		if (ldcp->hretries++ < vgen_max_hretries)
3165*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3166*1991Sheppo 	}
3167*1991Sheppo }
3168*1991Sheppo 
3169*1991Sheppo /*
3170*1991Sheppo  * Handle a version info msg from the peer or an ACK/NACK from the peer
3171*1991Sheppo  * to a version info msg that we sent.
3172*1991Sheppo  */
3173*1991Sheppo static void
3174*1991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3175*1991Sheppo {
3176*1991Sheppo 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
3177*1991Sheppo 	int		ack = 0;
3178*1991Sheppo 	int		failed = 0;
3179*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
3180*1991Sheppo 	int		idx;
3181*1991Sheppo 	vgen_ver_t	*versions = ldcp->vgen_versions;
3182*1991Sheppo 
3183*1991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: enter\n"));
3184*1991Sheppo 	switch (tagp->vio_subtype) {
3185*1991Sheppo 	case VIO_SUBTYPE_INFO:
3186*1991Sheppo 
3187*1991Sheppo 		/*  Cache sid of peer if this is the first time */
3188*1991Sheppo 		if (ldcp->peer_sid == 0) {
3189*1991Sheppo 			DBG2((vnetp,
3190*1991Sheppo 			    "vgen_handle_version_negotiate: id (%lx) Caching"
3191*1991Sheppo 			    " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid));
3192*1991Sheppo 			ldcp->peer_sid = tagp->vio_sid;
3193*1991Sheppo 		}
3194*1991Sheppo 
3195*1991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
3196*1991Sheppo 			/*
3197*1991Sheppo 			 * If we are not already in VH_PHASE1, reset to
3198*1991Sheppo 			 * pre-handshake state, and initiate handshake
3199*1991Sheppo 			 * to the peer too.
3200*1991Sheppo 			 */
3201*1991Sheppo 			vgen_handshake_reset(ldcp);
3202*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3203*1991Sheppo 		}
3204*1991Sheppo 		ldcp->hstate |= VER_INFO_RCVD;
3205*1991Sheppo 
3206*1991Sheppo 		/* save peer's requested values */
3207*1991Sheppo 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
3208*1991Sheppo 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
3209*1991Sheppo 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
3210*1991Sheppo 
3211*1991Sheppo 		if ((vermsg->dev_class != VDEV_NETWORK) &&
3212*1991Sheppo 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
3213*1991Sheppo 			/* unsupported dev_class, send NACK */
3214*1991Sheppo 
3215*1991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3216*1991Sheppo 			tagp->vio_sid = ldcp->local_sid;
3217*1991Sheppo 			/* send reply msg back to peer */
3218*1991Sheppo 			(void) vgen_sendmsg(ldcp, (caddr_t)tagp,
3219*1991Sheppo 			    sizeof (*vermsg), B_FALSE);
3220*1991Sheppo 			DWARN((vnetp,
3221*1991Sheppo 			    "vgen_handle_version_negotiate: Version"
3222*1991Sheppo 			    " Negotiation Failed id (%lx)\n", ldcp->ldc_id));
3223*1991Sheppo 			vgen_handshake_reset(ldcp);
3224*1991Sheppo 			return;
3225*1991Sheppo 		}
3226*1991Sheppo 
3227*1991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD,"
3228*1991Sheppo 		    " id (%lx), ver(%d,%d)\n", ldcp->ldc_id,
3229*1991Sheppo 		    vermsg->ver_major,  vermsg->ver_minor));
3230*1991Sheppo 
3231*1991Sheppo 		idx = 0;
3232*1991Sheppo 
3233*1991Sheppo 		for (;;) {
3234*1991Sheppo 
3235*1991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
3236*1991Sheppo 
3237*1991Sheppo 				/* nack with next lower version */
3238*1991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
3239*1991Sheppo 				vermsg->ver_major = versions[idx].ver_major;
3240*1991Sheppo 				vermsg->ver_minor = versions[idx].ver_minor;
3241*1991Sheppo 				break;
3242*1991Sheppo 			}
3243*1991Sheppo 
3244*1991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
3245*1991Sheppo 
3246*1991Sheppo 				/* major version match - ACK version */
3247*1991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
3248*1991Sheppo 				ack = 1;
3249*1991Sheppo 
3250*1991Sheppo 				/*
3251*1991Sheppo 				 * lower minor version to the one this endpt
3252*1991Sheppo 				 * supports, if necessary
3253*1991Sheppo 				 */
3254*1991Sheppo 				if (vermsg->ver_minor >
3255*1991Sheppo 				    versions[idx].ver_minor) {
3256*1991Sheppo 					vermsg->ver_minor =
3257*1991Sheppo 						versions[idx].ver_minor;
3258*1991Sheppo 					ldcp->peer_hparams.ver_minor =
3259*1991Sheppo 						versions[idx].ver_minor;
3260*1991Sheppo 				}
3261*1991Sheppo 				break;
3262*1991Sheppo 			}
3263*1991Sheppo 
3264*1991Sheppo 			idx++;
3265*1991Sheppo 
3266*1991Sheppo 			if (idx == VGEN_NUM_VER) {
3267*1991Sheppo 
3268*1991Sheppo 				/* no version match - send NACK */
3269*1991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
3270*1991Sheppo 				vermsg->ver_major = 0;
3271*1991Sheppo 				vermsg->ver_minor = 0;
3272*1991Sheppo 				failed = 1;
3273*1991Sheppo 				break;
3274*1991Sheppo 			}
3275*1991Sheppo 
3276*1991Sheppo 		}
3277*1991Sheppo 
3278*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
3279*1991Sheppo 
3280*1991Sheppo 		/* send reply msg back to peer */
3281*1991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
3282*1991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
3283*1991Sheppo 			vgen_handshake_reset(ldcp);
3284*1991Sheppo 			return;
3285*1991Sheppo 		}
3286*1991Sheppo 
3287*1991Sheppo 		if (ack) {
3288*1991Sheppo 			ldcp->hstate |= VER_ACK_SENT;
3289*1991Sheppo 			DBG2((vnetp, "vgen_handle_version_negotiate:"
3290*1991Sheppo 			    " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
3291*1991Sheppo 			    ldcp->ldc_id, vermsg->ver_major,
3292*1991Sheppo 			    vermsg->ver_minor));
3293*1991Sheppo 		}
3294*1991Sheppo 		if (failed) {
3295*1991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
3296*1991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
3297*1991Sheppo 			    ldcp->ldc_id));
3298*1991Sheppo 			vgen_handshake_reset(ldcp);
3299*1991Sheppo 			return;
3300*1991Sheppo 		}
3301*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3302*1991Sheppo 
3303*1991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
3304*1991Sheppo 
3305*1991Sheppo 			/* local and peer versions match? */
3306*1991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
3307*1991Sheppo 				ldcp->peer_hparams.ver_major) &&
3308*1991Sheppo 				(ldcp->local_hparams.ver_minor ==
3309*1991Sheppo 				ldcp->peer_hparams.ver_minor));
3310*1991Sheppo 
3311*1991Sheppo 			/* move to the next phase */
3312*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3313*1991Sheppo 		}
3314*1991Sheppo 
3315*1991Sheppo 		break;
3316*1991Sheppo 
3317*1991Sheppo 	case VIO_SUBTYPE_ACK:
3318*1991Sheppo 
3319*1991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
3320*1991Sheppo 			/*  This should not happen. */
3321*1991Sheppo 			DWARN((vnetp,
3322*1991Sheppo 			    "vgen_handle_version_negotiate:"
3323*1991Sheppo 			    " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
3324*1991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
3325*1991Sheppo 			vgen_handshake_reset(ldcp);
3326*1991Sheppo 			return;
3327*1991Sheppo 		}
3328*1991Sheppo 
3329*1991Sheppo 		/* SUCCESS - we have agreed on a version */
3330*1991Sheppo 		ldcp->local_hparams.ver_major = vermsg->ver_major;
3331*1991Sheppo 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
3332*1991Sheppo 		ldcp->hstate |= VER_ACK_RCVD;
3333*1991Sheppo 
3334*1991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
3335*1991Sheppo 		    " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
3336*1991Sheppo 		    ldcp->ldc_id, vermsg->ver_major,  vermsg->ver_minor));
3337*1991Sheppo 
3338*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3339*1991Sheppo 
3340*1991Sheppo 			/*  VER_ACK_SENT and VER_ACK_RCVD */
3341*1991Sheppo 
3342*1991Sheppo 			/* local and peer versions match? */
3343*1991Sheppo 			ASSERT((ldcp->local_hparams.ver_major ==
3344*1991Sheppo 				ldcp->peer_hparams.ver_major) &&
3345*1991Sheppo 				(ldcp->local_hparams.ver_minor ==
3346*1991Sheppo 				ldcp->peer_hparams.ver_minor));
3347*1991Sheppo 
3348*1991Sheppo 			/* move to the next phase */
3349*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3350*1991Sheppo 		}
3351*1991Sheppo 		break;
3352*1991Sheppo 
3353*1991Sheppo 	case VIO_SUBTYPE_NACK:
3354*1991Sheppo 
3355*1991Sheppo 		if (ldcp->hphase != VH_PHASE1) {
3356*1991Sheppo 			/*  This should not happen.  */
3357*1991Sheppo 			DWARN((vnetp,
3358*1991Sheppo 			    "vgen_handle_version_negotiate:"
3359*1991Sheppo 			    " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
3360*1991Sheppo 			    ldcp->ldc_id, ldcp->hphase));
3361*1991Sheppo 			vgen_handshake_reset(ldcp);
3362*1991Sheppo 			return;
3363*1991Sheppo 		}
3364*1991Sheppo 
3365*1991Sheppo 		DBG2((vnetp, "vgen_handle_version_negotiate:"
3366*1991Sheppo 		    " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
3367*1991Sheppo 		    ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor));
3368*1991Sheppo 
3369*1991Sheppo 		/* check if version in NACK is zero */
3370*1991Sheppo 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
3371*1991Sheppo 			/*
3372*1991Sheppo 			 * Version Negotiation has failed.
3373*1991Sheppo 			 */
3374*1991Sheppo 			DWARN((vnetp, "vgen_handle_version_negotiate:"
3375*1991Sheppo 			    " Version Negotiation Failed id (%lx)\n",
3376*1991Sheppo 			    ldcp->ldc_id));
3377*1991Sheppo 			vgen_handshake_reset(ldcp);
3378*1991Sheppo 			return;
3379*1991Sheppo 		}
3380*1991Sheppo 
3381*1991Sheppo 		idx = 0;
3382*1991Sheppo 
3383*1991Sheppo 		for (;;) {
3384*1991Sheppo 
3385*1991Sheppo 			if (vermsg->ver_major > versions[idx].ver_major) {
3386*1991Sheppo 				/* select next lower version */
3387*1991Sheppo 
3388*1991Sheppo 				ldcp->local_hparams.ver_major =
3389*1991Sheppo 					versions[idx].ver_major;
3390*1991Sheppo 				ldcp->local_hparams.ver_minor =
3391*1991Sheppo 					versions[idx].ver_minor;
3392*1991Sheppo 				break;
3393*1991Sheppo 			}
3394*1991Sheppo 
3395*1991Sheppo 			if (vermsg->ver_major == versions[idx].ver_major) {
3396*1991Sheppo 				/* major version match */
3397*1991Sheppo 
3398*1991Sheppo 				ldcp->local_hparams.ver_major =
3399*1991Sheppo 					versions[idx].ver_major;
3400*1991Sheppo 
3401*1991Sheppo 				ldcp->local_hparams.ver_minor =
3402*1991Sheppo 					versions[idx].ver_minor;
3403*1991Sheppo 				break;
3404*1991Sheppo 			}
3405*1991Sheppo 
3406*1991Sheppo 			idx++;
3407*1991Sheppo 
3408*1991Sheppo 			if (idx == VGEN_NUM_VER) {
3409*1991Sheppo 				/*
3410*1991Sheppo 				 * no version match.
3411*1991Sheppo 				 * Version Negotiation has failed.
3412*1991Sheppo 				 */
3413*1991Sheppo 				DWARN((vnetp, "vgen_handle_version_negotiate:"
3414*1991Sheppo 				    " Version Negotiation Failed id (%lx)\n",
3415*1991Sheppo 				    ldcp->ldc_id));
3416*1991Sheppo 				vgen_handshake_reset(ldcp);
3417*1991Sheppo 				return;
3418*1991Sheppo 			}
3419*1991Sheppo 
3420*1991Sheppo 		}
3421*1991Sheppo 
3422*1991Sheppo 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
3423*1991Sheppo 			vgen_handshake_reset(ldcp);
3424*1991Sheppo 			return;
3425*1991Sheppo 		}
3426*1991Sheppo 
3427*1991Sheppo 		break;
3428*1991Sheppo 	}
3429*1991Sheppo 	DBG1((vnetp, "vgen_handle_version_negotiate: exit\n"));
3430*1991Sheppo }
3431*1991Sheppo 
3432*1991Sheppo /* Check if the attributes are supported */
3433*1991Sheppo static int
3434*1991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
3435*1991Sheppo {
3436*1991Sheppo 	_NOTE(ARGUNUSED(ldcp))
3437*1991Sheppo 
3438*1991Sheppo #if 0
3439*1991Sheppo 	uint64_t port_macaddr;
3440*1991Sheppo 	port_macaddr = vgen_macaddr_strtoul((uint8_t *)
3441*1991Sheppo 				&(ldcp->portp->macaddr));
3442*1991Sheppo #endif
3443*1991Sheppo 	/*
3444*1991Sheppo 	 * currently, we support these attr values:
3445*1991Sheppo 	 * mtu of ethernet, addr_type of mac, xfer_mode of
3446*1991Sheppo 	 * ldc shared memory, ack_freq of 0 (data is acked if
3447*1991Sheppo 	 * the ack bit is set in the descriptor) and the address should
3448*1991Sheppo 	 * match the address in the port node.
3449*1991Sheppo 	 */
3450*1991Sheppo 	if ((msg->mtu != ETHERMAX) ||
3451*1991Sheppo 	    (msg->addr_type != ADDR_TYPE_MAC) ||
3452*1991Sheppo 	    (msg->xfer_mode != VIO_DRING_MODE) ||
3453*1991Sheppo 	    (msg->ack_freq > 64)) {
3454*1991Sheppo #if 0
3455*1991Sheppo 	    (msg->addr != port_macaddr))
3456*1991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
3457*1991Sheppo 	msg->addr, port_macaddr);
3458*1991Sheppo #endif
3459*1991Sheppo 		return (VGEN_FAILURE);
3460*1991Sheppo 	}
3461*1991Sheppo 
3462*1991Sheppo 	return (VGEN_SUCCESS);
3463*1991Sheppo }
3464*1991Sheppo 
3465*1991Sheppo /*
3466*1991Sheppo  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
3467*1991Sheppo  * to an attr info msg that we sent.
3468*1991Sheppo  */
3469*1991Sheppo static void
3470*1991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3471*1991Sheppo {
3472*1991Sheppo 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
3473*1991Sheppo 	void		*vnetp = LDC_TO_VNET(ldcp);
3474*1991Sheppo 	int		ack = 0;
3475*1991Sheppo 
3476*1991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: enter\n"));
3477*1991Sheppo 	if (ldcp->hphase != VH_PHASE2) {
3478*1991Sheppo 		DWARN((vnetp,
3479*1991Sheppo 		    "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)"
3480*1991Sheppo 		    " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3481*1991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
3482*1991Sheppo 		vgen_handshake_reset(ldcp);
3483*1991Sheppo 		return;
3484*1991Sheppo 	}
3485*1991Sheppo 	switch (tagp->vio_subtype) {
3486*1991Sheppo 	case VIO_SUBTYPE_INFO:
3487*1991Sheppo 
3488*1991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
3489*1991Sheppo 		    ldcp->ldc_id));
3490*1991Sheppo 		ldcp->hstate |= ATTR_INFO_RCVD;
3491*1991Sheppo 
3492*1991Sheppo 		/* save peer's values */
3493*1991Sheppo 		ldcp->peer_hparams.mtu = attrmsg->mtu;
3494*1991Sheppo 		ldcp->peer_hparams.addr = attrmsg->addr;
3495*1991Sheppo 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
3496*1991Sheppo 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
3497*1991Sheppo 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
3498*1991Sheppo 
3499*1991Sheppo 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
3500*1991Sheppo 			/* unsupported attr, send NACK */
3501*1991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3502*1991Sheppo 		} else {
3503*1991Sheppo 			ack = 1;
3504*1991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
3505*1991Sheppo 		}
3506*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
3507*1991Sheppo 
3508*1991Sheppo 		/* send reply msg back to peer */
3509*1991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
3510*1991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
3511*1991Sheppo 			vgen_handshake_reset(ldcp);
3512*1991Sheppo 			return;
3513*1991Sheppo 		}
3514*1991Sheppo 
3515*1991Sheppo 		if (ack) {
3516*1991Sheppo 			ldcp->hstate |= ATTR_ACK_SENT;
3517*1991Sheppo 			DBG2((vnetp, "vgen_handle_attr_info:"
3518*1991Sheppo 			    " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id));
3519*1991Sheppo #ifdef DEBUG
3520*1991Sheppo #if 0
3521*1991Sheppo 			vgen_print_attr_info(ldcp, VGEN_PEER);
3522*1991Sheppo #endif
3523*1991Sheppo #endif
3524*1991Sheppo 		} else {
3525*1991Sheppo 			/* failed */
3526*1991Sheppo 			DWARN((vnetp, "vgen_handle_attr_info:"
3527*1991Sheppo 			    " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id));
3528*1991Sheppo 			vgen_handshake_reset(ldcp);
3529*1991Sheppo 			return;
3530*1991Sheppo 		}
3531*1991Sheppo 
3532*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3533*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3534*1991Sheppo 		}
3535*1991Sheppo 
3536*1991Sheppo 		break;
3537*1991Sheppo 
3538*1991Sheppo 	case VIO_SUBTYPE_ACK:
3539*1991Sheppo 
3540*1991Sheppo 		ldcp->hstate |= ATTR_ACK_RCVD;
3541*1991Sheppo 
3542*1991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
3543*1991Sheppo 		    ldcp->ldc_id));
3544*1991Sheppo 
3545*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3546*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3547*1991Sheppo 		}
3548*1991Sheppo 		break;
3549*1991Sheppo 
3550*1991Sheppo 	case VIO_SUBTYPE_NACK:
3551*1991Sheppo 
3552*1991Sheppo 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
3553*1991Sheppo 		    ldcp->ldc_id));
3554*1991Sheppo 		vgen_handshake_reset(ldcp);
3555*1991Sheppo 		break;
3556*1991Sheppo 	}
3557*1991Sheppo 	DBG1((vnetp, "vgen_handle_attr_info: exit\n"));
3558*1991Sheppo }
3559*1991Sheppo 
3560*1991Sheppo /* Check if the dring info msg is ok */
3561*1991Sheppo static int
3562*1991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
3563*1991Sheppo {
3564*1991Sheppo 	/* check if msg contents are ok */
3565*1991Sheppo 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
3566*1991Sheppo 	    sizeof (vnet_public_desc_t))) {
3567*1991Sheppo 		return (VGEN_FAILURE);
3568*1991Sheppo 	}
3569*1991Sheppo 	return (VGEN_SUCCESS);
3570*1991Sheppo }
3571*1991Sheppo 
3572*1991Sheppo /*
3573*1991Sheppo  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
3574*1991Sheppo  * the peer to a dring register msg that we sent.
3575*1991Sheppo  */
3576*1991Sheppo static void
3577*1991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3578*1991Sheppo {
3579*1991Sheppo 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
3580*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3581*1991Sheppo 	ldc_mem_cookie_t dcookie;
3582*1991Sheppo 	int ack = 0;
3583*1991Sheppo 	int rv = 0;
3584*1991Sheppo 
3585*1991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: enter\n"));
3586*1991Sheppo 	if (ldcp->hphase < VH_PHASE2) {
3587*1991Sheppo 		/* dring_info can be rcvd in any of the phases after Phase1 */
3588*1991Sheppo 		DWARN((vnetp,
3589*1991Sheppo 		    "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)"
3590*1991Sheppo 		    " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3591*1991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
3592*1991Sheppo 		vgen_handshake_reset(ldcp);
3593*1991Sheppo 		return;
3594*1991Sheppo 	}
3595*1991Sheppo 	switch (tagp->vio_subtype) {
3596*1991Sheppo 	case VIO_SUBTYPE_INFO:
3597*1991Sheppo 
3598*1991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
3599*1991Sheppo 		    ldcp->ldc_id));
3600*1991Sheppo 		ldcp->hstate |= DRING_INFO_RCVD;
3601*1991Sheppo 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
3602*1991Sheppo 
3603*1991Sheppo 		ASSERT(msg->ncookies == 1);
3604*1991Sheppo 
3605*1991Sheppo 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
3606*1991Sheppo 			/*
3607*1991Sheppo 			 * verified dring info msg to be ok,
3608*1991Sheppo 			 * now try to map the remote dring.
3609*1991Sheppo 			 */
3610*1991Sheppo 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
3611*1991Sheppo 			    msg->descriptor_size, &dcookie,
3612*1991Sheppo 			    msg->ncookies);
3613*1991Sheppo 			if (rv == DDI_SUCCESS) {
3614*1991Sheppo 				/* now we can ack the peer */
3615*1991Sheppo 				ack = 1;
3616*1991Sheppo 			}
3617*1991Sheppo 		}
3618*1991Sheppo 		if (ack == 0) {
3619*1991Sheppo 			/* failed, send NACK */
3620*1991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3621*1991Sheppo 		} else {
3622*1991Sheppo 			if (!(ldcp->peer_hparams.dring_ready)) {
3623*1991Sheppo 
3624*1991Sheppo 				/* save peer's dring_info values */
3625*1991Sheppo 				bcopy(&dcookie,
3626*1991Sheppo 				    &(ldcp->peer_hparams.dring_cookie),
3627*1991Sheppo 				    sizeof (dcookie));
3628*1991Sheppo 				ldcp->peer_hparams.num_desc =
3629*1991Sheppo 						msg->num_descriptors;
3630*1991Sheppo 				ldcp->peer_hparams.desc_size =
3631*1991Sheppo 						msg->descriptor_size;
3632*1991Sheppo 				ldcp->peer_hparams.num_dcookies =
3633*1991Sheppo 						msg->ncookies;
3634*1991Sheppo 
3635*1991Sheppo 				/* set dring_ident for the peer */
3636*1991Sheppo 				ldcp->peer_hparams.dring_ident =
3637*1991Sheppo 							(uint64_t)ldcp->rxdp;
3638*1991Sheppo 				/* return the dring_ident in ack msg */
3639*1991Sheppo 				msg->dring_ident =
3640*1991Sheppo 							(uint64_t)ldcp->rxdp;
3641*1991Sheppo 
3642*1991Sheppo 				ldcp->peer_hparams.dring_ready = B_TRUE;
3643*1991Sheppo 			}
3644*1991Sheppo 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
3645*1991Sheppo 		}
3646*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
3647*1991Sheppo 		/* send reply msg back to peer */
3648*1991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
3649*1991Sheppo 		    B_FALSE) != VGEN_SUCCESS) {
3650*1991Sheppo 			vgen_handshake_reset(ldcp);
3651*1991Sheppo 			return;
3652*1991Sheppo 		}
3653*1991Sheppo 
3654*1991Sheppo 		if (ack) {
3655*1991Sheppo 			ldcp->hstate |= DRING_ACK_SENT;
3656*1991Sheppo 			DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT"
3657*1991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
3658*1991Sheppo 		} else {
3659*1991Sheppo 			DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT"
3660*1991Sheppo 			    " id (%lx)\n", ldcp->ldc_id));
3661*1991Sheppo 			vgen_handshake_reset(ldcp);
3662*1991Sheppo 			return;
3663*1991Sheppo 		}
3664*1991Sheppo 
3665*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3666*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3667*1991Sheppo 		}
3668*1991Sheppo 
3669*1991Sheppo 		break;
3670*1991Sheppo 
3671*1991Sheppo 	case VIO_SUBTYPE_ACK:
3672*1991Sheppo 
3673*1991Sheppo 		ldcp->hstate |= DRING_ACK_RCVD;
3674*1991Sheppo 
3675*1991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD"
3676*1991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
3677*1991Sheppo 
3678*1991Sheppo 		if (!(ldcp->local_hparams.dring_ready)) {
3679*1991Sheppo 			/* local dring is now ready */
3680*1991Sheppo 			ldcp->local_hparams.dring_ready = B_TRUE;
3681*1991Sheppo 
3682*1991Sheppo 			/* save dring_ident acked by peer */
3683*1991Sheppo 			ldcp->local_hparams.dring_ident =
3684*1991Sheppo 				msg->dring_ident;
3685*1991Sheppo 		}
3686*1991Sheppo 
3687*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3688*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3689*1991Sheppo 		}
3690*1991Sheppo 
3691*1991Sheppo 		break;
3692*1991Sheppo 
3693*1991Sheppo 	case VIO_SUBTYPE_NACK:
3694*1991Sheppo 
3695*1991Sheppo 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD"
3696*1991Sheppo 		    " id (%lx)\n", ldcp->ldc_id));
3697*1991Sheppo 		vgen_handshake_reset(ldcp);
3698*1991Sheppo 		break;
3699*1991Sheppo 	}
3700*1991Sheppo 	DBG1((vnetp, "vgen_handle_dring_reg: exit\n"));
3701*1991Sheppo }
3702*1991Sheppo 
3703*1991Sheppo /*
3704*1991Sheppo  * Handle a rdx info msg from the peer or an ACK/NACK
3705*1991Sheppo  * from the peer to a rdx info msg that we sent.
3706*1991Sheppo  */
3707*1991Sheppo static void
3708*1991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3709*1991Sheppo {
3710*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3711*1991Sheppo 
3712*1991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: enter\n"));
3713*1991Sheppo 	if (ldcp->hphase != VH_PHASE3) {
3714*1991Sheppo 		DWARN((vnetp,
3715*1991Sheppo 		    "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)"
3716*1991Sheppo 		    "  Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3717*1991Sheppo 		    tagp->vio_subtype, ldcp->hphase));
3718*1991Sheppo 		vgen_handshake_reset(ldcp);
3719*1991Sheppo 		return;
3720*1991Sheppo 	}
3721*1991Sheppo 	switch (tagp->vio_subtype) {
3722*1991Sheppo 	case VIO_SUBTYPE_INFO:
3723*1991Sheppo 
3724*1991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
3725*1991Sheppo 		    ldcp->ldc_id));
3726*1991Sheppo 		ldcp->hstate |= RDX_INFO_RCVD;
3727*1991Sheppo 
3728*1991Sheppo 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
3729*1991Sheppo 		tagp->vio_sid = ldcp->local_sid;
3730*1991Sheppo 		/* send reply msg back to peer */
3731*1991Sheppo 		if (vgen_sendmsg(ldcp, (caddr_t)tagp,
3732*1991Sheppo 		    sizeof (vio_rdx_msg_t), B_FALSE) != VGEN_SUCCESS) {
3733*1991Sheppo 			vgen_handshake_reset(ldcp);
3734*1991Sheppo 			return;
3735*1991Sheppo 		}
3736*1991Sheppo 
3737*1991Sheppo 		ldcp->hstate |= RDX_ACK_SENT;
3738*1991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
3739*1991Sheppo 		    ldcp->ldc_id));
3740*1991Sheppo 
3741*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3742*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3743*1991Sheppo 		}
3744*1991Sheppo 
3745*1991Sheppo 		break;
3746*1991Sheppo 
3747*1991Sheppo 	case VIO_SUBTYPE_ACK:
3748*1991Sheppo 
3749*1991Sheppo 		ldcp->hstate |= RDX_ACK_RCVD;
3750*1991Sheppo 
3751*1991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
3752*1991Sheppo 		    ldcp->ldc_id));
3753*1991Sheppo 
3754*1991Sheppo 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3755*1991Sheppo 			vgen_handshake(vh_nextphase(ldcp));
3756*1991Sheppo 		}
3757*1991Sheppo 		break;
3758*1991Sheppo 
3759*1991Sheppo 	case VIO_SUBTYPE_NACK:
3760*1991Sheppo 
3761*1991Sheppo 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
3762*1991Sheppo 		    ldcp->ldc_id));
3763*1991Sheppo 		vgen_handshake_reset(ldcp);
3764*1991Sheppo 		break;
3765*1991Sheppo 	}
3766*1991Sheppo 	DBG1((vnetp, "vgen_handle_rdx_info: exit\n"));
3767*1991Sheppo }
3768*1991Sheppo 
3769*1991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
3770*1991Sheppo static void
3771*1991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3772*1991Sheppo {
3773*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3774*1991Sheppo 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3775*1991Sheppo 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
3776*1991Sheppo 	struct ether_addr *addrp;
3777*1991Sheppo 	int count;
3778*1991Sheppo 	int i;
3779*1991Sheppo 
3780*1991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: enter\n"));
3781*1991Sheppo 	switch (tagp->vio_subtype) {
3782*1991Sheppo 
3783*1991Sheppo 	case VIO_SUBTYPE_INFO:
3784*1991Sheppo 
3785*1991Sheppo 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
3786*1991Sheppo 		DWARN((vnetp,
3787*1991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
3788*1991Sheppo 		    ldcp->ldc_id));
3789*1991Sheppo 		break;
3790*1991Sheppo 
3791*1991Sheppo 	case VIO_SUBTYPE_ACK:
3792*1991Sheppo 
3793*1991Sheppo 		/* success adding/removing multicast addr */
3794*1991Sheppo 		DBG2((vnetp,
3795*1991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
3796*1991Sheppo 		    ldcp->ldc_id));
3797*1991Sheppo 		break;
3798*1991Sheppo 
3799*1991Sheppo 	case VIO_SUBTYPE_NACK:
3800*1991Sheppo 
3801*1991Sheppo 		DWARN((vnetp,
3802*1991Sheppo 		    "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
3803*1991Sheppo 		    ldcp->ldc_id));
3804*1991Sheppo 		if (!(msgp->set)) {
3805*1991Sheppo 			/* multicast remove request failed */
3806*1991Sheppo 			break;
3807*1991Sheppo 		}
3808*1991Sheppo 
3809*1991Sheppo 		/* multicast add request failed */
3810*1991Sheppo 		for (count = 0; count < msgp->count; count++) {
3811*1991Sheppo 			addrp = &(msgp->mca[count]);
3812*1991Sheppo 
3813*1991Sheppo 			/* delete address from the table */
3814*1991Sheppo 			for (i = 0; i < vgenp->mccount; i++) {
3815*1991Sheppo 				if (ether_cmp(addrp,
3816*1991Sheppo 				    &(vgenp->mctab[i])) == 0) {
3817*1991Sheppo 					if (vgenp->mccount > 1) {
3818*1991Sheppo 						vgenp->mctab[i] =
3819*1991Sheppo 						vgenp->mctab[vgenp->mccount-1];
3820*1991Sheppo 					}
3821*1991Sheppo 					vgenp->mccount--;
3822*1991Sheppo 					break;
3823*1991Sheppo 				}
3824*1991Sheppo 			}
3825*1991Sheppo 		}
3826*1991Sheppo 		break;
3827*1991Sheppo 
3828*1991Sheppo 	}
3829*1991Sheppo 	DBG1((vnetp, "vgen_handle_mcast_info: exit\n"));
3830*1991Sheppo }
3831*1991Sheppo 
3832*1991Sheppo /* handler for control messages received from the peer ldc end-point */
3833*1991Sheppo static void
3834*1991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3835*1991Sheppo {
3836*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3837*1991Sheppo 
3838*1991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n"));
3839*1991Sheppo 	switch (tagp->vio_subtype_env) {
3840*1991Sheppo 
3841*1991Sheppo 	case VIO_VER_INFO:
3842*1991Sheppo 		vgen_handle_version_negotiate(ldcp, tagp);
3843*1991Sheppo 		break;
3844*1991Sheppo 
3845*1991Sheppo 	case VIO_ATTR_INFO:
3846*1991Sheppo 		vgen_handle_attr_info(ldcp, tagp);
3847*1991Sheppo 		break;
3848*1991Sheppo 
3849*1991Sheppo 	case VIO_DRING_REG:
3850*1991Sheppo 		vgen_handle_dring_reg(ldcp, tagp);
3851*1991Sheppo 		break;
3852*1991Sheppo 
3853*1991Sheppo 	case VIO_RDX:
3854*1991Sheppo 		vgen_handle_rdx_info(ldcp, tagp);
3855*1991Sheppo 		break;
3856*1991Sheppo 
3857*1991Sheppo 	case VNET_MCAST_INFO:
3858*1991Sheppo 		vgen_handle_mcast_info(ldcp, tagp);
3859*1991Sheppo 		break;
3860*1991Sheppo 
3861*1991Sheppo 	}
3862*1991Sheppo 	DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n"));
3863*1991Sheppo }
3864*1991Sheppo 
3865*1991Sheppo /* handler for data messages received from the peer ldc end-point */
3866*1991Sheppo static void
3867*1991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3868*1991Sheppo 	mblk_t **headp, mblk_t **tailp)
3869*1991Sheppo {
3870*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3871*1991Sheppo 
3872*1991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: enter\n"));
3873*1991Sheppo 
3874*1991Sheppo 	if (ldcp->hphase != VH_DONE)
3875*1991Sheppo 		return;
3876*1991Sheppo 	switch (tagp->vio_subtype_env) {
3877*1991Sheppo 	case VIO_DRING_DATA:
3878*1991Sheppo 		vgen_handle_dring_data(ldcp, tagp, headp, tailp);
3879*1991Sheppo 		break;
3880*1991Sheppo 	default:
3881*1991Sheppo 		break;
3882*1991Sheppo 	}
3883*1991Sheppo 
3884*1991Sheppo 	DBG1((vnetp, "vgen_handle_datamsg: exit\n"));
3885*1991Sheppo }
3886*1991Sheppo 
3887*1991Sheppo static void
3888*1991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3889*1991Sheppo 	mblk_t **headp, mblk_t **tailp)
3890*1991Sheppo {
3891*1991Sheppo 	vio_dring_msg_t *dringmsg;
3892*1991Sheppo 	vnet_public_desc_t *rxdp;
3893*1991Sheppo 	vnet_public_desc_t *txdp;
3894*1991Sheppo 	vio_dring_entry_hdr_t *hdrp;
3895*1991Sheppo 	vgen_stats_t *statsp;
3896*1991Sheppo 	struct ether_header *ehp;
3897*1991Sheppo 	mblk_t *mp = NULL;
3898*1991Sheppo 	mblk_t *bp = NULL;
3899*1991Sheppo 	mblk_t *bpt = NULL;
3900*1991Sheppo 	size_t nbytes;
3901*1991Sheppo 	size_t nread;
3902*1991Sheppo 	uint64_t off = 0;
3903*1991Sheppo 	uint32_t start;
3904*1991Sheppo 	uint32_t end;
3905*1991Sheppo 	uint32_t datalen;
3906*1991Sheppo 	uint32_t ncookies;
3907*1991Sheppo 	uint32_t sync_start;
3908*1991Sheppo 	uint32_t sync_end;
3909*1991Sheppo 	uint32_t rxi;
3910*1991Sheppo 	uint32_t txi;
3911*1991Sheppo 	int rv;
3912*1991Sheppo 	boolean_t rxd_err = B_FALSE;
3913*1991Sheppo 	boolean_t sync_done = B_FALSE;
3914*1991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS
3915*1991Sheppo 	int n;
3916*1991Sheppo #endif
3917*1991Sheppo #ifdef VGEN_REXMIT
3918*1991Sheppo 	uint64_t seqnum;
3919*1991Sheppo 	vgen_private_desc_t *tbufp;
3920*1991Sheppo #endif
3921*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
3922*1991Sheppo 
3923*1991Sheppo 	dringmsg = (vio_dring_msg_t *)tagp;
3924*1991Sheppo 	start = dringmsg->start_idx;
3925*1991Sheppo 	end = dringmsg->end_idx;
3926*1991Sheppo 	statsp = ldcp->statsp;
3927*1991Sheppo 
3928*1991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: enter\n"));
3929*1991Sheppo 	switch (tagp->vio_subtype) {
3930*1991Sheppo 
3931*1991Sheppo 	case VIO_SUBTYPE_INFO:
3932*1991Sheppo 		/*
3933*1991Sheppo 		 * received a data msg, which contains the start and end
3934*1991Sheppo 		 * indeces of the descriptors within the rx ring holding data,
3935*1991Sheppo 		 * the seq_num of data packet corresponding to the start index,
3936*1991Sheppo 		 * and the dring_ident.
3937*1991Sheppo 		 * We can now read the contents of each of these descriptors
3938*1991Sheppo 		 * and gather data from it.
3939*1991Sheppo 		 */
3940*1991Sheppo 		DBG2((vnetp,
3941*1991Sheppo 		    "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
3942*1991Sheppo 		    start, end));
3943*1991Sheppo 
3944*1991Sheppo 		/* validate rx start and end indeces */
3945*1991Sheppo 		if (!(CHECK_RXI(start, ldcp)) || !(CHECK_RXI(end, ldcp))) {
3946*1991Sheppo 			/* drop the message if invalid index */
3947*1991Sheppo 			break;
3948*1991Sheppo 		}
3949*1991Sheppo 
3950*1991Sheppo 		/* validate dring_ident */
3951*1991Sheppo 		if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
3952*1991Sheppo 			/* invalid dring_ident, drop the msg */
3953*1991Sheppo 			break;
3954*1991Sheppo 		}
3955*1991Sheppo #ifdef DEBUG
3956*1991Sheppo 		if (vgen_trigger_rxlost) {
3957*1991Sheppo 			/* drop this msg to simulate lost pkts for debugging */
3958*1991Sheppo 			vgen_trigger_rxlost = 0;
3959*1991Sheppo 			break;
3960*1991Sheppo 		}
3961*1991Sheppo #endif
3962*1991Sheppo 
3963*1991Sheppo #ifdef	VGEN_HANDLE_LOST_PKTS
3964*1991Sheppo 
3965*1991Sheppo 		/* receive start index doesn't match expected index */
3966*1991Sheppo 		if (ldcp->next_rxi != start) {
3967*1991Sheppo 
3968*1991Sheppo 			DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
3969*1991Sheppo 			    "next_rxi(%d) != start(%d)\n",
3970*1991Sheppo 			    ldcp->ldc_id, ldcp->next_rxi, start));
3971*1991Sheppo 
3972*1991Sheppo 			/* calculate the number of pkts lost */
3973*1991Sheppo 			if (start >= ldcp->next_rxi) {
3974*1991Sheppo 				n = start - ldcp->next_rxi;
3975*1991Sheppo 			} else  {
3976*1991Sheppo 				n = ldcp->num_rxds - (ldcp->next_rxi - start);
3977*1991Sheppo 			}
3978*1991Sheppo 
3979*1991Sheppo 			/*
3980*1991Sheppo 			 * Starting sequence number of the received packets
3981*1991Sheppo 			 * is less than the next sequence number that
3982*1991Sheppo 			 * is expected:
3983*1991Sheppo 			 *
3984*1991Sheppo 			 * drop the message and the corresponding packets.
3985*1991Sheppo 			 */
3986*1991Sheppo 			if (ldcp->next_rxseq > dringmsg->seq_num) {
3987*1991Sheppo 				DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
3988*1991Sheppo 				    "dropping pkts, expected rxseq(0x%lx) "
3989*1991Sheppo 				    "> recvd(0x%lx)\n",
3990*1991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
3991*1991Sheppo 				    dringmsg->seq_num));
3992*1991Sheppo 				/*
3993*1991Sheppo 				 * duplicate/multiple retransmissions from
3994*1991Sheppo 				 * sender?? drop this msg.
3995*1991Sheppo 				 */
3996*1991Sheppo 				break;
3997*1991Sheppo 			}
3998*1991Sheppo 
3999*1991Sheppo 			/*
4000*1991Sheppo 			 * Starting sequence number of the received packets
4001*1991Sheppo 			 * is greater than the next expected sequence number
4002*1991Sheppo 			 *
4003*1991Sheppo 			 * send a NACK back to the peer to indicate lost
4004*1991Sheppo 			 * packets.
4005*1991Sheppo 			 */
4006*1991Sheppo 			if (dringmsg->seq_num > ldcp->next_rxseq) {
4007*1991Sheppo 				statsp->rx_lost_pkts += n;
4008*1991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
4009*1991Sheppo 				tagp->vio_sid = ldcp->local_sid;
4010*1991Sheppo 				/* indicate the range of lost descriptors */
4011*1991Sheppo 				dringmsg->start_idx = ldcp->next_rxi;
4012*1991Sheppo 				rxi = start;
4013*1991Sheppo 				DECR_RXI(rxi, ldcp);
4014*1991Sheppo 				dringmsg->end_idx = rxi;
4015*1991Sheppo 				/* dring ident is left unchanged */
4016*1991Sheppo 				if (vgen_sendmsg(ldcp, (caddr_t)tagp,
4017*1991Sheppo 				    sizeof (*dringmsg), B_FALSE)) {
4018*1991Sheppo 					DWARN((vnetp,
4019*1991Sheppo 					    "vgen_handle_dring_data: id(%lx) "
4020*1991Sheppo 					    "vgen_sendmsg failed, "
4021*1991Sheppo 					    "stype: NACK\n", ldcp->ldc_id));
4022*1991Sheppo 				}
4023*1991Sheppo #ifdef VGEN_REXMIT
4024*1991Sheppo 				/*
4025*1991Sheppo 				 * stop further processing until peer
4026*1991Sheppo 				 * retransmits with the right index and seqnum.
4027*1991Sheppo 				 */
4028*1991Sheppo 				break;
4029*1991Sheppo #else	/* VGEN_REXMIT */
4030*1991Sheppo 				/*
4031*1991Sheppo 				 * treat this range of descrs/pkts as dropped
4032*1991Sheppo 				 * and set the new expected values for next_rxi
4033*1991Sheppo 				 * and next_rxseq. continue(below) to process
4034*1991Sheppo 				 * from the new start index.
4035*1991Sheppo 				 */
4036*1991Sheppo 				ldcp->next_rxi = start;
4037*1991Sheppo 				ldcp->next_rxseq += n;
4038*1991Sheppo #endif	/* VGEN_REXMIT */
4039*1991Sheppo 
4040*1991Sheppo 			} else if (dringmsg->seq_num == ldcp->next_rxseq) {
4041*1991Sheppo 				/*
4042*1991Sheppo 				 * expected and starting seqnums match, but
4043*1991Sheppo 				 * the descriptor indeces don't?
4044*1991Sheppo 				 *
4045*1991Sheppo 				 * restart handshake with peer.
4046*1991Sheppo 				 */
4047*1991Sheppo 				DWARN((vnetp,
4048*1991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
4049*1991Sheppo 				    "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
4050*1991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
4051*1991Sheppo 				    dringmsg->seq_num));
4052*1991Sheppo 
4053*1991Sheppo #if 0
4054*1991Sheppo 				vgen_handshake_retry(ldcp);
4055*1991Sheppo 				break;
4056*1991Sheppo #endif
4057*1991Sheppo 
4058*1991Sheppo 			}
4059*1991Sheppo 
4060*1991Sheppo 		} else {
4061*1991Sheppo 			/* expected and start dring indeces match */
4062*1991Sheppo 
4063*1991Sheppo 			if (dringmsg->seq_num != ldcp->next_rxseq) {
4064*1991Sheppo 
4065*1991Sheppo 				/* seqnums don't match */
4066*1991Sheppo 
4067*1991Sheppo 				DWARN((vnetp,
4068*1991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
4069*1991Sheppo 				    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
4070*1991Sheppo 				    ldcp->ldc_id, ldcp->next_rxseq,
4071*1991Sheppo 				    dringmsg->seq_num));
4072*1991Sheppo 
4073*1991Sheppo #if 0
4074*1991Sheppo 				vgen_handshake_retry(ldcp);
4075*1991Sheppo 				break;
4076*1991Sheppo #endif
4077*1991Sheppo 			}
4078*1991Sheppo 		}
4079*1991Sheppo 
4080*1991Sheppo #endif	/* VGEN_HANDLE_LOST_PKTS */
4081*1991Sheppo 
4082*1991Sheppo 		/*
4083*1991Sheppo 		 * Start processing the descriptor range, specified
4084*1991Sheppo 		 * in the dring data msg.
4085*1991Sheppo 		 */
4086*1991Sheppo 		if (ldc_mem_dring_acquire(ldcp->rx_dhandle, start, end)) {
4087*1991Sheppo 			DWARN((vnetp, "vgen_handle_dring_data: "
4088*1991Sheppo 			    "id(%lx), ldc_mem_dring_acquire() failed\n",
4089*1991Sheppo 			    ldcp->ldc_id));
4090*1991Sheppo 			statsp->ierrors++;
4091*1991Sheppo 		}
4092*1991Sheppo 		rxi = start;
4093*1991Sheppo 		sync_start = start;
4094*1991Sheppo 		do {
4095*1991Sheppo 			/* recv packets from 'start' to 'end' */
4096*1991Sheppo 
4097*1991Sheppo 			rxdp = &(ldcp->rxdp[rxi]);
4098*1991Sheppo 			hdrp = &rxdp->hdr;
4099*1991Sheppo 
4100*1991Sheppo 			datalen = rxdp->nbytes;
4101*1991Sheppo 			ncookies = rxdp->ncookies;
4102*1991Sheppo 			if ((datalen < ETHERMIN) ||
4103*1991Sheppo 			    (ncookies == 0) ||
4104*1991Sheppo 			    (ncookies > (uint64_t)MAX_COOKIES) ||
4105*1991Sheppo 			    (hdrp->dstate != VIO_DESC_READY)) {
4106*1991Sheppo 				rxd_err = B_TRUE;
4107*1991Sheppo 			} else {
4108*1991Sheppo 				/*
4109*1991Sheppo 				 * The data buffer returned by allocb(9F) is
4110*1991Sheppo 				 * 8byte aligned. We allocate extra 8 bytes to
4111*1991Sheppo 				 * ensure size is multiple of 8 bytes for
4112*1991Sheppo 				 * ldc_mem_copy().
4113*1991Sheppo 				 */
4114*1991Sheppo 				mp = allocb(datalen + 8, BPRI_MED);
4115*1991Sheppo 				nbytes = (datalen + 7) & ~7;
4116*1991Sheppo 			}
4117*1991Sheppo 			if ((rxd_err) || (mp == NULL)) {
4118*1991Sheppo 				/*
4119*1991Sheppo 				 * rxd_err or allocb() failure,
4120*1991Sheppo 				 * drop this packet, get next.
4121*1991Sheppo 				 */
4122*1991Sheppo 				if (rxd_err) {
4123*1991Sheppo 					statsp->ierrors++;
4124*1991Sheppo 					rxd_err = B_FALSE;
4125*1991Sheppo 				} else {
4126*1991Sheppo 					statsp->rx_allocb_fail++;
4127*1991Sheppo 				}
4128*1991Sheppo 
4129*1991Sheppo 				/* set descriptor done bit */
4130*1991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
4131*1991Sheppo 
4132*1991Sheppo 				if (hdrp->ack) {
4133*1991Sheppo 					/*
4134*1991Sheppo 					 * sender needs ack for this packet.
4135*1991Sheppo 					 * sync pkts upto this index and
4136*1991Sheppo 					 * send the ack to the peer.
4137*1991Sheppo 					 */
4138*1991Sheppo 					sync_end = rxi;
4139*1991Sheppo 					(void) ldc_mem_dring_release(
4140*1991Sheppo 					    ldcp->rx_dhandle, sync_start,
4141*1991Sheppo 					    sync_end);
4142*1991Sheppo 					tagp->vio_subtype = VIO_SUBTYPE_ACK;
4143*1991Sheppo 					tagp->vio_sid = ldcp->local_sid;
4144*1991Sheppo 					dringmsg = (vio_dring_msg_t *)tagp;
4145*1991Sheppo 					dringmsg->start_idx = sync_start;
4146*1991Sheppo 					dringmsg->end_idx = sync_end;
4147*1991Sheppo 					if (vgen_sendmsg(ldcp, (caddr_t)tagp,
4148*1991Sheppo 					    sizeof (*dringmsg), B_FALSE)) {
4149*1991Sheppo 						DWARN((vnetp,
4150*1991Sheppo 						    "vgen_handle_dring_data: "
4151*1991Sheppo 						    "id(%lx) vgen_sendmsg "
4152*1991Sheppo 						    "failed, stype: ACK\n",
4153*1991Sheppo 						    ldcp->ldc_id));
4154*1991Sheppo 					}
4155*1991Sheppo 					/* save new sync index start */
4156*1991Sheppo 					if (sync_end != end) {
4157*1991Sheppo 						INCR_RXI(sync_end, ldcp);
4158*1991Sheppo 						sync_start = sync_end;
4159*1991Sheppo 					} else
4160*1991Sheppo 						sync_done = B_TRUE;
4161*1991Sheppo 				}
4162*1991Sheppo 				goto vgen_next_rxi;
4163*1991Sheppo 			}
4164*1991Sheppo 
4165*1991Sheppo 			nread = nbytes;
4166*1991Sheppo 			rv = ldc_mem_copy(ldcp->ldc_handle,
4167*1991Sheppo 			    (caddr_t)mp->b_rptr, off, &nread,
4168*1991Sheppo 			    rxdp->memcookie, ncookies, LDC_COPY_IN);
4169*1991Sheppo 
4170*1991Sheppo 			/* set done bit irrespective of rv of ldc_mem_copy() */
4171*1991Sheppo 			hdrp->dstate = VIO_DESC_DONE;
4172*1991Sheppo 
4173*1991Sheppo 			if (hdrp->ack) {
4174*1991Sheppo 				/*
4175*1991Sheppo 				 * sender needs ack for this packet.
4176*1991Sheppo 				 * sync pkts upto this index and
4177*1991Sheppo 				 * send the ack to the peer.
4178*1991Sheppo 				 */
4179*1991Sheppo 				sync_end = rxi;
4180*1991Sheppo 				(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4181*1991Sheppo 				    sync_start, sync_end);
4182*1991Sheppo 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
4183*1991Sheppo 				tagp->vio_sid = ldcp->local_sid;
4184*1991Sheppo 				dringmsg = (vio_dring_msg_t *)tagp;
4185*1991Sheppo 				dringmsg->start_idx = sync_start;
4186*1991Sheppo 				dringmsg->end_idx = sync_end;
4187*1991Sheppo 				if (vgen_sendmsg(ldcp, (caddr_t)tagp,
4188*1991Sheppo 				    sizeof (*dringmsg), B_FALSE)) {
4189*1991Sheppo 					DWARN((vnetp,
4190*1991Sheppo 					    "vgen_handle_dring_data: id(%lx) "
4191*1991Sheppo 					    "vgen_sendmsg failed stype: ACK\n",
4192*1991Sheppo 					    ldcp->ldc_id));
4193*1991Sheppo 				}
4194*1991Sheppo 				/* save new sync index start */
4195*1991Sheppo 				if (sync_end != end) {
4196*1991Sheppo 					INCR_RXI(sync_end, ldcp);
4197*1991Sheppo 					sync_start = sync_end;
4198*1991Sheppo 				} else
4199*1991Sheppo 					sync_done = B_TRUE;
4200*1991Sheppo 			}
4201*1991Sheppo 			/* if ldc_mem_copy() failed */
4202*1991Sheppo 			if (rv) {
4203*1991Sheppo 				DWARN((vnetp,
4204*1991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
4205*1991Sheppo 				    "ldc_mem_copy failed\n", ldcp->ldc_id));
4206*1991Sheppo 				statsp->ierrors++;
4207*1991Sheppo 				freemsg(mp);
4208*1991Sheppo 				goto vgen_next_rxi;
4209*1991Sheppo 			}
4210*1991Sheppo 			if (nread != nbytes) {
4211*1991Sheppo 				DWARN((vnetp,
4212*1991Sheppo 				    "vgen_handle_dring_data: id(%lx) "
4213*1991Sheppo 				    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
4214*1991Sheppo 				    ldcp->ldc_id, nread, nbytes));
4215*1991Sheppo 				statsp->ierrors++;
4216*1991Sheppo 				freemsg(mp);
4217*1991Sheppo 				goto vgen_next_rxi;
4218*1991Sheppo 			}
4219*1991Sheppo 
4220*1991Sheppo 			/* point to the actual end of data */
4221*1991Sheppo 			mp->b_wptr = mp->b_rptr + datalen;
4222*1991Sheppo 
4223*1991Sheppo 			/* update stats */
4224*1991Sheppo 			statsp->ipackets++;
4225*1991Sheppo 			statsp->rbytes += datalen;
4226*1991Sheppo 			ehp = (struct ether_header *)mp->b_rptr;
4227*1991Sheppo 			if (IS_BROADCAST(ehp))
4228*1991Sheppo 				statsp->brdcstrcv++;
4229*1991Sheppo 			else if (IS_MULTICAST(ehp))
4230*1991Sheppo 				statsp->multircv++;
4231*1991Sheppo 
4232*1991Sheppo 			/* build a chain of received packets */
4233*1991Sheppo 			if (bp == NULL) {
4234*1991Sheppo 				/* first pkt */
4235*1991Sheppo 				bp = mp;
4236*1991Sheppo 				bpt = bp;
4237*1991Sheppo 				bpt->b_next = NULL;
4238*1991Sheppo 			} else {
4239*1991Sheppo 				mp->b_next = NULL;
4240*1991Sheppo 				bpt->b_next = mp;
4241*1991Sheppo 				bpt = mp;
4242*1991Sheppo 			}
4243*1991Sheppo 
4244*1991Sheppo vgen_next_rxi:		if (rxi == end) {
4245*1991Sheppo 				break;
4246*1991Sheppo 			}
4247*1991Sheppo 			/* increment recv index */
4248*1991Sheppo 			INCR_RXI(rxi, ldcp);
4249*1991Sheppo 
4250*1991Sheppo 		_NOTE(CONSTCOND)
4251*1991Sheppo 		} while (1);
4252*1991Sheppo 
4253*1991Sheppo 		if (!sync_done) {
4254*1991Sheppo 			/* sync remote descriptor range */
4255*1991Sheppo 			sync_end = rxi;
4256*1991Sheppo 			(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4257*1991Sheppo 			    sync_start, sync_end);
4258*1991Sheppo 			DBG2((vnetp,
4259*1991Sheppo 			    "vgen_handle_dring_data: not sending ACK\n"));
4260*1991Sheppo 		}
4261*1991Sheppo 
4262*1991Sheppo 		/* save new recv index */
4263*1991Sheppo 		INCR_RXI(rxi, ldcp);
4264*1991Sheppo 		ldcp->next_rxi = rxi;
4265*1991Sheppo 		ldcp->next_rxseq += ((end >= start) ?
4266*1991Sheppo 			((end - start) + 1) : (start - end));
4267*1991Sheppo 
4268*1991Sheppo 		/* try to reclaim transmit descrs also */
4269*1991Sheppo 		vgen_reclaim(ldcp);
4270*1991Sheppo 		break;
4271*1991Sheppo 
4272*1991Sheppo 	case VIO_SUBTYPE_ACK:
4273*1991Sheppo 		/*
4274*1991Sheppo 		 * received an ack corresponding to a specific descriptor for
4275*1991Sheppo 		 * which we had set the ACK bit in the descriptor (during
4276*1991Sheppo 		 * transmit). This enables us to reclaim descriptors.
4277*1991Sheppo 		 */
4278*1991Sheppo 		DBG2((vnetp,
4279*1991Sheppo 		    "vgen_handle_dring_data: ACK:  start(%d), end(%d)\n",
4280*1991Sheppo 		    start, end));
4281*1991Sheppo 
4282*1991Sheppo 		/* validate start and end indeces in the tx ack msg */
4283*1991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
4284*1991Sheppo 			/* drop the message if invalid index */
4285*1991Sheppo 			break;
4286*1991Sheppo 		}
4287*1991Sheppo 		/* validate dring_ident */
4288*1991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
4289*1991Sheppo 			/* invalid dring_ident, drop the msg */
4290*1991Sheppo 			break;
4291*1991Sheppo 		}
4292*1991Sheppo 		statsp->dring_data_acks++;
4293*1991Sheppo 		vgen_reclaim(ldcp);
4294*1991Sheppo 		break;
4295*1991Sheppo 
4296*1991Sheppo 	case VIO_SUBTYPE_NACK:
4297*1991Sheppo 		/*
4298*1991Sheppo 		 * peer sent a NACK msg to indicate lost packets.
4299*1991Sheppo 		 * The start and end correspond to the range of descriptors
4300*1991Sheppo 		 * for which the peer didn't receive a dring data msg and so
4301*1991Sheppo 		 * didn't receive the corresponding data.
4302*1991Sheppo 		 */
4303*1991Sheppo 		DWARN((vnetp,
4304*1991Sheppo 		    "vgen_handle_dring_data: NACK:  start(%d), end(%d)\n",
4305*1991Sheppo 		    start, end));
4306*1991Sheppo 
4307*1991Sheppo 		/* validate start and end indeces in the tx nack msg */
4308*1991Sheppo 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
4309*1991Sheppo 			/* drop the message if invalid index */
4310*1991Sheppo 			break;
4311*1991Sheppo 		}
4312*1991Sheppo 		/* validate dring_ident */
4313*1991Sheppo 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
4314*1991Sheppo 			/* invalid dring_ident, drop the msg */
4315*1991Sheppo 			break;
4316*1991Sheppo 		}
4317*1991Sheppo 		mutex_enter(&ldcp->txlock);
4318*1991Sheppo 		mutex_enter(&ldcp->tclock);
4319*1991Sheppo 
4320*1991Sheppo 		if (ldcp->next_tbufp == ldcp->cur_tbufp) {
4321*1991Sheppo 			/* no busy descriptors, bogus nack ? */
4322*1991Sheppo 			mutex_exit(&ldcp->tclock);
4323*1991Sheppo 			mutex_exit(&ldcp->txlock);
4324*1991Sheppo 			break;
4325*1991Sheppo 		}
4326*1991Sheppo 
4327*1991Sheppo #ifdef VGEN_REXMIT
4328*1991Sheppo 		/* send a new dring data msg including the lost descrs */
4329*1991Sheppo 		end = ldcp->next_tbufp - ldcp->tbufp;
4330*1991Sheppo 		DECR_TXI(end, ldcp);
4331*1991Sheppo 		seqnum = ldcp->tbufp[start].seqnum;
4332*1991Sheppo 		/* no need to increment ldcp->next_txseq as this is rexmit */
4333*1991Sheppo 		rv = vgen_send_dring_data(ldcp, start, end, seqnum);
4334*1991Sheppo 		if (rv != 0) {
4335*1991Sheppo 			/*
4336*1991Sheppo 			 * vgen_send_dring_data() error: drop all packets
4337*1991Sheppo 			 * in this descr range
4338*1991Sheppo 			 */
4339*1991Sheppo 			DWARN((vnetp,
4340*1991Sheppo 			    "vgen_handle_dring_data: "
4341*1991Sheppo 			    "vgen_send_dring_data failed :"
4342*1991Sheppo 			    "id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
4343*1991Sheppo 			for (txi = start; txi <= end; ) {
4344*1991Sheppo 				tbufp = &(ldcp->tbufp[txi]);
4345*1991Sheppo 				txdp = tbufp->descp;
4346*1991Sheppo 				hdrp = &txdp->hdr;
4347*1991Sheppo 				(void) ldc_mem_unbind_handle(tbufp->memhandle);
4348*1991Sheppo 				freemsg(tbufp->mp);
4349*1991Sheppo 				tbufp->flags = VGEN_PRIV_DESC_FREE;
4350*1991Sheppo 				hdrp->dstate = VIO_DESC_FREE;
4351*1991Sheppo 				hdrp->ack = B_FALSE;
4352*1991Sheppo 				statsp->oerrors++;
4353*1991Sheppo 			}
4354*1991Sheppo 
4355*1991Sheppo 			/* update next pointer */
4356*1991Sheppo 			ldcp->next_tbufp = &(ldcp->tbufp[start]);
4357*1991Sheppo 			ldcp->next_txseq = seqnum;
4358*1991Sheppo 			ldcp->next_txi = start;
4359*1991Sheppo 		}
4360*1991Sheppo 		DBG2((vnetp,
4361*1991Sheppo 		    "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
4362*1991Sheppo 		    start, end));
4363*1991Sheppo #else	/* VGEN_REXMIT */
4364*1991Sheppo 		/* we just mark the descrs as done so they can be reclaimed */
4365*1991Sheppo 		for (txi = start; txi <= end; ) {
4366*1991Sheppo 			txdp = &(ldcp->txdp[txi]);
4367*1991Sheppo 			hdrp = &txdp->hdr;
4368*1991Sheppo 			if (hdrp->dstate == VIO_DESC_READY)
4369*1991Sheppo 				hdrp->dstate = VIO_DESC_DONE;
4370*1991Sheppo 			INCR_TXI(txi, ldcp);
4371*1991Sheppo 		}
4372*1991Sheppo #endif	/* VGEN_REXMIT */
4373*1991Sheppo 		mutex_exit(&ldcp->tclock);
4374*1991Sheppo 		mutex_exit(&ldcp->txlock);
4375*1991Sheppo 
4376*1991Sheppo 		vgen_reclaim(ldcp);
4377*1991Sheppo 
4378*1991Sheppo 		break;
4379*1991Sheppo 	}
4380*1991Sheppo 
4381*1991Sheppo 	DBG1((vnetp, "vgen_handle_dring_data: exit\n"));
4382*1991Sheppo 	*headp = bp;
4383*1991Sheppo 	*tailp = bpt;
4384*1991Sheppo }
4385*1991Sheppo 
4386*1991Sheppo static void
4387*1991Sheppo vgen_reclaim(vgen_ldc_t *ldcp)
4388*1991Sheppo {
4389*1991Sheppo 	if (mutex_tryenter(&ldcp->tclock) == 0)
4390*1991Sheppo 		return;			/* already in progress */
4391*1991Sheppo 	vgen_reclaim_dring(ldcp);
4392*1991Sheppo 	ldcp->reclaim_lbolt = ddi_get_lbolt();
4393*1991Sheppo 	mutex_exit(&ldcp->tclock);
4394*1991Sheppo }
4395*1991Sheppo 
4396*1991Sheppo /*
4397*1991Sheppo  * transmit reclaim function. starting from the current reclaim index
4398*1991Sheppo  * look for descriptors marked DONE and reclaim the descriptor and the
4399*1991Sheppo  * corresponding buffers (tbuf).
4400*1991Sheppo  */
4401*1991Sheppo static void
4402*1991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp)
4403*1991Sheppo {
4404*1991Sheppo 	vnet_public_desc_t *txdp;
4405*1991Sheppo 	vgen_private_desc_t *tbufp;
4406*1991Sheppo 	vio_dring_entry_hdr_t	*hdrp;
4407*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE
4408*1991Sheppo 	vgen_t	*vgenp = (vgen_t *)ldcp->vgenp;
4409*1991Sheppo #endif
4410*1991Sheppo 
4411*1991Sheppo #ifdef DEBUG
4412*1991Sheppo 	if (vgen_trigger_txtimeout)
4413*1991Sheppo 		return;
4414*1991Sheppo #endif
4415*1991Sheppo 
4416*1991Sheppo 	tbufp = ldcp->cur_tbufp;
4417*1991Sheppo 	txdp = tbufp->descp;
4418*1991Sheppo 	hdrp = &txdp->hdr;
4419*1991Sheppo 
4420*1991Sheppo 	while ((hdrp->dstate == VIO_DESC_DONE) &&
4421*1991Sheppo 	    (tbufp != ldcp->next_tbufp)) {
4422*1991Sheppo 		(void) ldc_mem_unbind_handle(tbufp->memhandle);
4423*1991Sheppo 		freemsg(tbufp->mp);
4424*1991Sheppo 		tbufp->mp = NULL;
4425*1991Sheppo 		tbufp->flags = VGEN_PRIV_DESC_FREE;
4426*1991Sheppo 		hdrp->dstate = VIO_DESC_FREE;
4427*1991Sheppo 		hdrp->ack = B_FALSE;
4428*1991Sheppo 
4429*1991Sheppo 		tbufp = NEXTTBUF(ldcp, tbufp);
4430*1991Sheppo 		txdp = tbufp->descp;
4431*1991Sheppo 		hdrp = &txdp->hdr;
4432*1991Sheppo 	}
4433*1991Sheppo 
4434*1991Sheppo 	ldcp->cur_tbufp = tbufp;
4435*1991Sheppo 
4436*1991Sheppo 	/*
4437*1991Sheppo 	 * Check if mac layer should be notified to restart transmissions
4438*1991Sheppo 	 */
4439*1991Sheppo 	if (ldcp->need_resched) {
4440*1991Sheppo 		ldcp->need_resched = B_FALSE;
4441*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE
4442*1991Sheppo 		mac_tx_update(vgenp->vnetmacp);
4443*1991Sheppo #endif
4444*1991Sheppo 	}
4445*1991Sheppo }
4446*1991Sheppo 
4447*1991Sheppo /* return the number of pending transmits for the channel */
4448*1991Sheppo static int
4449*1991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp)
4450*1991Sheppo {
4451*1991Sheppo 	int n;
4452*1991Sheppo 
4453*1991Sheppo 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
4454*1991Sheppo 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
4455*1991Sheppo 	} else  {
4456*1991Sheppo 		/* cur_tbufp > next_tbufp */
4457*1991Sheppo 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
4458*1991Sheppo 	}
4459*1991Sheppo 
4460*1991Sheppo 	return (n);
4461*1991Sheppo }
4462*1991Sheppo 
4463*1991Sheppo /* determine if the transmit descriptor ring is full */
4464*1991Sheppo static int
4465*1991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp)
4466*1991Sheppo {
4467*1991Sheppo 	vgen_private_desc_t	*tbufp;
4468*1991Sheppo 	vgen_private_desc_t	*ntbufp;
4469*1991Sheppo 
4470*1991Sheppo 	tbufp = ldcp->next_tbufp;
4471*1991Sheppo 	ntbufp = NEXTTBUF(ldcp, tbufp);
4472*1991Sheppo 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
4473*1991Sheppo #if 0
4474*1991Sheppo 		void *vnetp = LDC_TO_VNET(ldcp);
4475*1991Sheppo 		DWARN((vnetp, "vgen_tx_dring_full: id(%lx)\n",
4476*1991Sheppo 		    ldcp->ldc_id));
4477*1991Sheppo #endif
4478*1991Sheppo 		return (VGEN_SUCCESS);
4479*1991Sheppo 	}
4480*1991Sheppo 	return (VGEN_FAILURE);
4481*1991Sheppo }
4482*1991Sheppo 
4483*1991Sheppo /* determine if timeout condition has occured */
4484*1991Sheppo static int
4485*1991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
4486*1991Sheppo {
4487*1991Sheppo 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
4488*1991Sheppo 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
4489*1991Sheppo 	    (vnet_ldcwd_txtimeout) &&
4490*1991Sheppo 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
4491*1991Sheppo #if 0
4492*1991Sheppo 		void *vnetp = LDC_TO_VNET(ldcp);
4493*1991Sheppo 		DWARN((vnetp, "vgen_ldc_txtimeout: id(%lx)\n",
4494*1991Sheppo 		    ldcp->ldc_id));
4495*1991Sheppo #endif
4496*1991Sheppo 		return (VGEN_SUCCESS);
4497*1991Sheppo 	} else {
4498*1991Sheppo 		return (VGEN_FAILURE);
4499*1991Sheppo 	}
4500*1991Sheppo }
4501*1991Sheppo 
4502*1991Sheppo /* transmit watchdog timeout handler */
4503*1991Sheppo static void
4504*1991Sheppo vgen_ldc_watchdog(void *arg)
4505*1991Sheppo {
4506*1991Sheppo 	vgen_ldc_t *ldcp;
4507*1991Sheppo 	void *vnetp;
4508*1991Sheppo 	int rv;
4509*1991Sheppo 
4510*1991Sheppo 	ldcp = (vgen_ldc_t *)arg;
4511*1991Sheppo 	vnetp = LDC_TO_VNET(ldcp);
4512*1991Sheppo 
4513*1991Sheppo 	rv = vgen_ldc_txtimeout(ldcp);
4514*1991Sheppo 	if (rv == VGEN_SUCCESS) {
4515*1991Sheppo 		DWARN((vnetp,
4516*1991Sheppo 		    "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
4517*1991Sheppo 		    ldcp->ldc_id));
4518*1991Sheppo #ifdef DEBUG
4519*1991Sheppo 		if (vgen_trigger_txtimeout) {
4520*1991Sheppo 			/* tx timeout triggered for debugging */
4521*1991Sheppo 			vgen_trigger_txtimeout = 0;
4522*1991Sheppo 		}
4523*1991Sheppo #endif
4524*1991Sheppo 		mutex_enter(&ldcp->cblock);
4525*1991Sheppo 		vgen_handshake_retry(ldcp);
4526*1991Sheppo 		mutex_exit(&ldcp->cblock);
4527*1991Sheppo 		if (ldcp->need_resched) {
4528*1991Sheppo 			ldcp->need_resched = B_FALSE;
4529*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE
4530*1991Sheppo 			mac_tx_update(ldcp->vgenp->vnetmacp);
4531*1991Sheppo #endif
4532*1991Sheppo 		}
4533*1991Sheppo 	}
4534*1991Sheppo 
4535*1991Sheppo 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
4536*1991Sheppo 	    drv_usectohz(vnet_ldcwd_interval * 1000));
4537*1991Sheppo }
4538*1991Sheppo 
4539*1991Sheppo /* based on mcopymsg() */
4540*1991Sheppo static void
4541*1991Sheppo vgen_copymsg(mblk_t *mp, void *bufp)
4542*1991Sheppo {
4543*1991Sheppo 	caddr_t	dest = bufp;
4544*1991Sheppo 	mblk_t	*bp;
4545*1991Sheppo 	size_t	n;
4546*1991Sheppo 
4547*1991Sheppo 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
4548*1991Sheppo 		n = MBLKL(bp);
4549*1991Sheppo 		bcopy(bp->b_rptr, dest, n);
4550*1991Sheppo 		dest += n;
4551*1991Sheppo 	}
4552*1991Sheppo }
4553*1991Sheppo 
4554*1991Sheppo static int
4555*1991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp)
4556*1991Sheppo {
4557*1991Sheppo 	vgen_t *vgenp;
4558*1991Sheppo 	struct kstat *ksp;
4559*1991Sheppo 	vgen_stats_t *statsp;
4560*1991Sheppo 	vgen_kstats_t *ldckp;
4561*1991Sheppo 	int instance;
4562*1991Sheppo 	size_t size;
4563*1991Sheppo 	char name[MAXNAMELEN];
4564*1991Sheppo 
4565*1991Sheppo 	vgenp = LDC_TO_VGEN(ldcp);
4566*1991Sheppo 	instance = ddi_get_instance(vgenp->vnetdip);
4567*1991Sheppo 	(void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id);
4568*1991Sheppo 	statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
4569*1991Sheppo 	if (statsp == NULL) {
4570*1991Sheppo 		return (VGEN_FAILURE);
4571*1991Sheppo 	}
4572*1991Sheppo 	size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
4573*1991Sheppo 	ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
4574*1991Sheppo 		size, 0);
4575*1991Sheppo 	if (ksp == NULL) {
4576*1991Sheppo 		KMEM_FREE(statsp);
4577*1991Sheppo 		return (VGEN_FAILURE);
4578*1991Sheppo 	}
4579*1991Sheppo 
4580*1991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
4581*1991Sheppo 	kstat_named_init(&ldckp->ipackets,		"ipackets",
4582*1991Sheppo 		KSTAT_DATA_ULONG);
4583*1991Sheppo 	kstat_named_init(&ldckp->ipackets64,		"ipackets64",
4584*1991Sheppo 		KSTAT_DATA_ULONGLONG);
4585*1991Sheppo 	kstat_named_init(&ldckp->ierrors,		"ierrors",
4586*1991Sheppo 		KSTAT_DATA_ULONG);
4587*1991Sheppo 	kstat_named_init(&ldckp->opackets,		"opackets",
4588*1991Sheppo 		KSTAT_DATA_ULONG);
4589*1991Sheppo 	kstat_named_init(&ldckp->opackets64,		"opackets64",
4590*1991Sheppo 		KSTAT_DATA_ULONGLONG);
4591*1991Sheppo 	kstat_named_init(&ldckp->oerrors,		"oerrors",
4592*1991Sheppo 		KSTAT_DATA_ULONG);
4593*1991Sheppo 
4594*1991Sheppo 
4595*1991Sheppo 	/* MIB II kstat variables */
4596*1991Sheppo 	kstat_named_init(&ldckp->rbytes,		"rbytes",
4597*1991Sheppo 		KSTAT_DATA_ULONG);
4598*1991Sheppo 	kstat_named_init(&ldckp->rbytes64,		"rbytes64",
4599*1991Sheppo 		KSTAT_DATA_ULONGLONG);
4600*1991Sheppo 	kstat_named_init(&ldckp->obytes,		"obytes",
4601*1991Sheppo 		KSTAT_DATA_ULONG);
4602*1991Sheppo 	kstat_named_init(&ldckp->obytes64,		"obytes64",
4603*1991Sheppo 		KSTAT_DATA_ULONGLONG);
4604*1991Sheppo 	kstat_named_init(&ldckp->multircv,		"multircv",
4605*1991Sheppo 		KSTAT_DATA_ULONG);
4606*1991Sheppo 	kstat_named_init(&ldckp->multixmt,		"multixmt",
4607*1991Sheppo 		KSTAT_DATA_ULONG);
4608*1991Sheppo 	kstat_named_init(&ldckp->brdcstrcv,		"brdcstrcv",
4609*1991Sheppo 		KSTAT_DATA_ULONG);
4610*1991Sheppo 	kstat_named_init(&ldckp->brdcstxmt,		"brdcstxmt",
4611*1991Sheppo 		KSTAT_DATA_ULONG);
4612*1991Sheppo 	kstat_named_init(&ldckp->norcvbuf,		"norcvbuf",
4613*1991Sheppo 		KSTAT_DATA_ULONG);
4614*1991Sheppo 	kstat_named_init(&ldckp->noxmtbuf,		"noxmtbuf",
4615*1991Sheppo 		KSTAT_DATA_ULONG);
4616*1991Sheppo 
4617*1991Sheppo 	/* Tx stats */
4618*1991Sheppo 	kstat_named_init(&ldckp->tx_no_desc,		"tx_no_desc",
4619*1991Sheppo 		KSTAT_DATA_ULONG);
4620*1991Sheppo 	kstat_named_init(&ldckp->tx_allocb_fail,	"tx_allocb_fail",
4621*1991Sheppo 		KSTAT_DATA_ULONG);
4622*1991Sheppo 
4623*1991Sheppo 	/* Rx stats */
4624*1991Sheppo 	kstat_named_init(&ldckp->rx_no_desc,		"rx_no_desc",
4625*1991Sheppo 		KSTAT_DATA_ULONG);
4626*1991Sheppo 	kstat_named_init(&ldckp->rx_allocb_fail,	"rx_allocb_fail",
4627*1991Sheppo 		KSTAT_DATA_ULONG);
4628*1991Sheppo 	kstat_named_init(&ldckp->rx_lost_pkts,		"rx_lost_pkts",
4629*1991Sheppo 		KSTAT_DATA_ULONG);
4630*1991Sheppo 
4631*1991Sheppo 	/* Interrupt stats */
4632*1991Sheppo 	kstat_named_init(&ldckp->callbacks,		"callbacks",
4633*1991Sheppo 		KSTAT_DATA_ULONG);
4634*1991Sheppo 	kstat_named_init(&ldckp->dring_data_acks,	"dring_data_acks",
4635*1991Sheppo 		KSTAT_DATA_ULONG);
4636*1991Sheppo 
4637*1991Sheppo 	ksp->ks_update = vgen_kstat_update;
4638*1991Sheppo 	ksp->ks_private = (void *)ldcp;
4639*1991Sheppo 	kstat_install(ksp);
4640*1991Sheppo 
4641*1991Sheppo 	ldcp->ksp = ksp;
4642*1991Sheppo 	ldcp->statsp = statsp;
4643*1991Sheppo 	return (VGEN_SUCCESS);
4644*1991Sheppo }
4645*1991Sheppo 
4646*1991Sheppo static void
4647*1991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp)
4648*1991Sheppo {
4649*1991Sheppo 	if (ldcp->ksp)
4650*1991Sheppo 		kstat_delete(ldcp->ksp);
4651*1991Sheppo 	KMEM_FREE(ldcp->statsp);
4652*1991Sheppo }
4653*1991Sheppo 
4654*1991Sheppo static int
4655*1991Sheppo vgen_kstat_update(kstat_t *ksp, int rw)
4656*1991Sheppo {
4657*1991Sheppo 	vgen_ldc_t *ldcp;
4658*1991Sheppo 	vgen_stats_t *statsp;
4659*1991Sheppo 	vgen_kstats_t *ldckp;
4660*1991Sheppo 
4661*1991Sheppo 	ldcp = (vgen_ldc_t *)ksp->ks_private;
4662*1991Sheppo 	statsp = ldcp->statsp;
4663*1991Sheppo 	ldckp = (vgen_kstats_t *)ksp->ks_data;
4664*1991Sheppo 
4665*1991Sheppo 	if (rw == KSTAT_READ) {
4666*1991Sheppo 		ldckp->ipackets.value.ul	= (uint32_t)statsp->ipackets;
4667*1991Sheppo 		ldckp->ipackets64.value.ull	= statsp->ipackets;
4668*1991Sheppo 		ldckp->ierrors.value.ul		= statsp->ierrors;
4669*1991Sheppo 		ldckp->opackets.value.ul	= (uint32_t)statsp->opackets;
4670*1991Sheppo 		ldckp->opackets64.value.ull	= statsp->opackets;
4671*1991Sheppo 		ldckp->oerrors.value.ul		= statsp->oerrors;
4672*1991Sheppo 
4673*1991Sheppo 		/*
4674*1991Sheppo 		 * MIB II kstat variables
4675*1991Sheppo 		 */
4676*1991Sheppo 		ldckp->rbytes.value.ul		= (uint32_t)statsp->rbytes;
4677*1991Sheppo 		ldckp->rbytes64.value.ull	= statsp->rbytes;
4678*1991Sheppo 		ldckp->obytes.value.ul		= (uint32_t)statsp->obytes;
4679*1991Sheppo 		ldckp->obytes64.value.ull	= statsp->obytes;
4680*1991Sheppo 		ldckp->multircv.value.ul	= statsp->multircv;
4681*1991Sheppo 		ldckp->multixmt.value.ul	= statsp->multixmt;
4682*1991Sheppo 		ldckp->brdcstrcv.value.ul	= statsp->brdcstrcv;
4683*1991Sheppo 		ldckp->brdcstxmt.value.ul	= statsp->brdcstxmt;
4684*1991Sheppo 		ldckp->norcvbuf.value.ul	= statsp->norcvbuf;
4685*1991Sheppo 		ldckp->noxmtbuf.value.ul	= statsp->noxmtbuf;
4686*1991Sheppo 
4687*1991Sheppo 		ldckp->tx_no_desc.value.ul	= statsp->tx_no_desc;
4688*1991Sheppo 		ldckp->tx_allocb_fail.value.ul	= statsp->tx_allocb_fail;
4689*1991Sheppo 
4690*1991Sheppo 		ldckp->rx_no_desc.value.ul	= statsp->rx_no_desc;
4691*1991Sheppo 		ldckp->rx_allocb_fail.value.ul	= statsp->rx_allocb_fail;
4692*1991Sheppo 		ldckp->rx_lost_pkts.value.ul	= statsp->rx_lost_pkts;
4693*1991Sheppo 
4694*1991Sheppo 		ldckp->callbacks.value.ul	= statsp->callbacks;
4695*1991Sheppo 		ldckp->dring_data_acks.value.ul	= statsp->dring_data_acks;
4696*1991Sheppo 	} else {
4697*1991Sheppo 		statsp->ipackets	= ldckp->ipackets64.value.ull;
4698*1991Sheppo 		statsp->ierrors		= ldckp->ierrors.value.ul;
4699*1991Sheppo 		statsp->opackets	= ldckp->opackets64.value.ull;
4700*1991Sheppo 		statsp->oerrors		= ldckp->oerrors.value.ul;
4701*1991Sheppo 
4702*1991Sheppo 		/*
4703*1991Sheppo 		 * MIB II kstat variables
4704*1991Sheppo 		 */
4705*1991Sheppo 		statsp->rbytes		= ldckp->rbytes64.value.ull;
4706*1991Sheppo 		statsp->obytes		= ldckp->obytes64.value.ull;
4707*1991Sheppo 		statsp->multircv	= ldckp->multircv.value.ul;
4708*1991Sheppo 		statsp->multixmt	= ldckp->multixmt.value.ul;
4709*1991Sheppo 		statsp->brdcstrcv	= ldckp->brdcstrcv.value.ul;
4710*1991Sheppo 		statsp->brdcstxmt	= ldckp->brdcstxmt.value.ul;
4711*1991Sheppo 		statsp->norcvbuf	= ldckp->norcvbuf.value.ul;
4712*1991Sheppo 		statsp->noxmtbuf	= ldckp->noxmtbuf.value.ul;
4713*1991Sheppo 
4714*1991Sheppo 		statsp->tx_no_desc	= ldckp->tx_no_desc.value.ul;
4715*1991Sheppo 		statsp->tx_allocb_fail	= ldckp->tx_allocb_fail.value.ul;
4716*1991Sheppo 
4717*1991Sheppo 		statsp->rx_no_desc	= ldckp->rx_no_desc.value.ul;
4718*1991Sheppo 		statsp->rx_allocb_fail	= ldckp->rx_allocb_fail.value.ul;
4719*1991Sheppo 		statsp->rx_lost_pkts	= ldckp->rx_lost_pkts.value.ul;
4720*1991Sheppo 
4721*1991Sheppo 		statsp->callbacks	= ldckp->callbacks.value.ul;
4722*1991Sheppo 		statsp->dring_data_acks	= ldckp->dring_data_acks.value.ul;
4723*1991Sheppo 	}
4724*1991Sheppo 
4725*1991Sheppo 	return (VGEN_SUCCESS);
4726*1991Sheppo }
4727*1991Sheppo 
4728*1991Sheppo /* handler for error messages received from the peer ldc end-point */
4729*1991Sheppo static void
4730*1991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4731*1991Sheppo {
4732*1991Sheppo 	_NOTE(ARGUNUSED(ldcp, tagp))
4733*1991Sheppo }
4734*1991Sheppo 
4735*1991Sheppo /* Check if the session id in the received message is valid */
4736*1991Sheppo static int
4737*1991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4738*1991Sheppo {
4739*1991Sheppo 	if (tagp->vio_sid != ldcp->peer_sid) {
4740*1991Sheppo 		void *vnetp = LDC_TO_VNET(ldcp);
4741*1991Sheppo 		DWARN((vnetp,
4742*1991Sheppo 		    "sid mismatch: expected(%x), rcvd(%x)\n",
4743*1991Sheppo 		    ldcp->peer_sid, tagp->vio_sid));
4744*1991Sheppo 		return (VGEN_FAILURE);
4745*1991Sheppo 	}
4746*1991Sheppo 	else
4747*1991Sheppo 		return (VGEN_SUCCESS);
4748*1991Sheppo }
4749*1991Sheppo 
4750*1991Sheppo /* convert mac address from string to uint64_t */
4751*1991Sheppo static uint64_t
4752*1991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr)
4753*1991Sheppo {
4754*1991Sheppo 	uint64_t val = 0;
4755*1991Sheppo 	int i;
4756*1991Sheppo 
4757*1991Sheppo #if 0
4758*1991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
4759*1991Sheppo #endif
4760*1991Sheppo 	for (i = 0; i < ETHERADDRL; i++) {
4761*1991Sheppo 		val <<= 8;
4762*1991Sheppo 		val |= macaddr[i];
4763*1991Sheppo 	}
4764*1991Sheppo 
4765*1991Sheppo #if 0
4766*1991Sheppo 	cmn_err(CE_CONT, "vgen_macaddr_strtoul: str(%x:%x:%x:%x:%x:%x)\n",
4767*1991Sheppo 		macaddr[0], macaddr[1], macaddr[2],
4768*1991Sheppo 		macaddr[3], macaddr[4], macaddr[5]);
4769*1991Sheppo 	cmn_err(CE_CONT, "vgen_macaddr_strtoul: val(0x%lx)\n", val);
4770*1991Sheppo #endif
4771*1991Sheppo 	return (val);
4772*1991Sheppo }
4773*1991Sheppo 
4774*1991Sheppo /* convert mac address from uint64_t to string */
4775*1991Sheppo static int
4776*1991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
4777*1991Sheppo {
4778*1991Sheppo 	int i;
4779*1991Sheppo 	uint64_t value;
4780*1991Sheppo 
4781*1991Sheppo 	value = val;
4782*1991Sheppo #if 0
4783*1991Sheppo 	for (i = 0; i < ETHERADDRL; i++) {
4784*1991Sheppo #endif
4785*1991Sheppo 	for (i = ETHERADDRL - 1; i >= 0; i--) {
4786*1991Sheppo 		macaddr[i] = value & 0xFF;
4787*1991Sheppo 		value >>= 8;
4788*1991Sheppo 	}
4789*1991Sheppo #if 0
4790*1991Sheppo 	cmn_err(CE_CONT, "vgen_macaddr_ultostr: val(0x%lx)\n", val);
4791*1991Sheppo 	cmn_err(CE_CONT, "vgen_macaddr_ultostr: str(%x:%x:%x:%x:%x:%x)\n",
4792*1991Sheppo 		macaddr[0], macaddr[1], macaddr[2],
4793*1991Sheppo 		macaddr[3], macaddr[4], macaddr[5]);
4794*1991Sheppo #endif
4795*1991Sheppo 	return (VGEN_SUCCESS);
4796*1991Sheppo }
4797*1991Sheppo 
4798*1991Sheppo static caddr_t
4799*1991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf)
4800*1991Sheppo {
4801*1991Sheppo 	(void) sprintf(ebuf,
4802*1991Sheppo 		"%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
4803*1991Sheppo 	return (ebuf);
4804*1991Sheppo }
4805*1991Sheppo 
4806*1991Sheppo /* Handshake watchdog timeout handler */
4807*1991Sheppo static void
4808*1991Sheppo vgen_hwatchdog(void *arg)
4809*1991Sheppo {
4810*1991Sheppo 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
4811*1991Sheppo 	void *vnetp = LDC_TO_VNET(ldcp);
4812*1991Sheppo 
4813*1991Sheppo 	DWARN((vnetp,
4814*1991Sheppo 	    "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
4815*1991Sheppo 	    ldcp->ldc_id, ldcp->hphase, ldcp->hstate));
4816*1991Sheppo 
4817*1991Sheppo 	mutex_enter(&ldcp->cblock);
4818*1991Sheppo 	ldcp->htid = 0;
4819*1991Sheppo 	vgen_handshake_retry(ldcp);
4820*1991Sheppo 	mutex_exit(&ldcp->cblock);
4821*1991Sheppo }
4822*1991Sheppo 
4823*1991Sheppo static void
4824*1991Sheppo vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint)
4825*1991Sheppo {
4826*1991Sheppo 	vgen_hparams_t *hp;
4827*1991Sheppo 	char ep[8];
4828*1991Sheppo 	uint8_t addr[6];
4829*1991Sheppo 	char	ea[6];
4830*1991Sheppo 
4831*1991Sheppo 	if (endpoint == VGEN_LOCAL) {
4832*1991Sheppo 		hp = &ldcp->local_hparams;
4833*1991Sheppo 		(void) sprintf(ep, "Local");
4834*1991Sheppo 	} else {
4835*1991Sheppo 		hp = &ldcp->peer_hparams;
4836*1991Sheppo 		(void) sprintf(ep, "Peer");
4837*1991Sheppo 	}
4838*1991Sheppo 	(void) vgen_macaddr_ultostr(hp->addr, addr);
4839*1991Sheppo 	cmn_err(CE_CONT, "attr_info: %s: \n", ep);
4840*1991Sheppo 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
4841*1991Sheppo 				vgen_print_ethaddr(addr, ea));
4842*1991Sheppo 	cmn_err(CE_CONT, "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
4843*1991Sheppo 		hp->addr_type, hp->xfer_mode, hp->ack_freq);
4844*1991Sheppo }
4845*1991Sheppo 
4846*1991Sheppo static void
4847*1991Sheppo vgen_print_hparams(vgen_hparams_t *hp)
4848*1991Sheppo {
4849*1991Sheppo 	uint8_t	addr[6];
4850*1991Sheppo 	char	ea[6];
4851*1991Sheppo 	ldc_mem_cookie_t *dc;
4852*1991Sheppo 
4853*1991Sheppo 	cmn_err(CE_CONT, "version_info:\n");
4854*1991Sheppo 	cmn_err(CE_CONT,
4855*1991Sheppo 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
4856*1991Sheppo 	    hp->ver_major, hp->ver_minor, hp->dev_class);
4857*1991Sheppo 
4858*1991Sheppo 	(void) vgen_macaddr_ultostr(hp->addr, addr);
4859*1991Sheppo 	cmn_err(CE_CONT, "attr_info:\n");
4860*1991Sheppo 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
4861*1991Sheppo 	    vgen_print_ethaddr(addr, ea));
4862*1991Sheppo 	cmn_err(CE_CONT,
4863*1991Sheppo 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
4864*1991Sheppo 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
4865*1991Sheppo 
4866*1991Sheppo 	dc = &hp->dring_cookie;
4867*1991Sheppo 	cmn_err(CE_CONT, "dring_info:\n");
4868*1991Sheppo 	cmn_err(CE_CONT,
4869*1991Sheppo 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
4870*1991Sheppo 	cmn_err(CE_CONT,
4871*1991Sheppo 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
4872*1991Sheppo 	    dc->addr, dc->size);
4873*1991Sheppo 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
4874*1991Sheppo }
4875*1991Sheppo 
4876*1991Sheppo static void
4877*1991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp)
4878*1991Sheppo {
4879*1991Sheppo 	vgen_hparams_t *hp;
4880*1991Sheppo 
4881*1991Sheppo 	cmn_err(CE_CONT, "Channel Information:\n");
4882*1991Sheppo 	cmn_err(CE_CONT,
4883*1991Sheppo 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
4884*1991Sheppo 	    ldcp->ldc_id, ldcp->ldc_status);
4885*1991Sheppo 	cmn_err(CE_CONT,
4886*1991Sheppo 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
4887*1991Sheppo 	    ldcp->local_sid, ldcp->peer_sid);
4888*1991Sheppo 	cmn_err(CE_CONT,
4889*1991Sheppo 	    "\thphase: 0x%x, hstate: 0x%x\n",
4890*1991Sheppo 	    ldcp->hphase, ldcp->hstate);
4891*1991Sheppo 
4892*1991Sheppo 	cmn_err(CE_CONT, "Local handshake params:\n");
4893*1991Sheppo 	hp = &ldcp->local_hparams;
4894*1991Sheppo 	vgen_print_hparams(hp);
4895*1991Sheppo 
4896*1991Sheppo 	cmn_err(CE_CONT, "Peer handshake params:\n");
4897*1991Sheppo 	hp = &ldcp->peer_hparams;
4898*1991Sheppo 	vgen_print_hparams(hp);
4899*1991Sheppo }
4900