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