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