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