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