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