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