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