xref: /titanic_52/usr/src/uts/sun4v/io/vnet_gen.c (revision 035c74aaf2aa9c8e7803b85ed58a292b0ccba299)
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 			    }
1799 			init_state;
1800 	uint32_t	ncookies = 0;
1801 	uint32_t	retries = 0;
1802 
1803 	init_state = ST_init;
1804 
1805 	LDC_LOCK(ldcp);
1806 
1807 	rv = ldc_open(ldcp->ldc_handle);
1808 	if (rv != 0) {
1809 		DWARN((vnetp,
1810 		    "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
1811 		    ldcp->ldc_id, rv));
1812 		goto ldcinit_failed;
1813 	}
1814 	init_state |= ST_ldc_open;
1815 
1816 	(void) ldc_status(ldcp->ldc_handle, &istatus);
1817 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
1818 		DWARN((vnetp,
1819 		    "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
1820 		    ldcp->ldc_id, istatus));
1821 		goto ldcinit_failed;
1822 	}
1823 	ldcp->ldc_status = istatus;
1824 
1825 	rv = vgen_init_tbufs(ldcp);
1826 	if (rv != 0) {
1827 		DWARN((vnetp,
1828 		    "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
1829 		    ldcp->ldc_id));
1830 		goto ldcinit_failed;
1831 	}
1832 	init_state |= ST_init_tbufs;
1833 
1834 	/* Bind descriptor ring to the channel */
1835 	rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
1836 	    LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies);
1837 	if (rv != 0) {
1838 		DWARN((vnetp, "vgen_ldcinit: id (%lx) "
1839 		    "ldc_mem_dring_bind failed rv(%x)\n", ldcp->ldc_id, rv));
1840 		goto ldcinit_failed;
1841 	}
1842 
1843 	ASSERT(ncookies == 1);
1844 	ldcp->num_txdcookies = ncookies;
1845 
1846 	init_state |= ST_dring_bind;
1847 
1848 	do {
1849 		rv = ldc_up(ldcp->ldc_handle);
1850 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
1851 			DBG2((vnetp,
1852 			    "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
1853 			    ldcp->ldc_id, rv));
1854 			drv_usecwait(VGEN_LDC_UP_DELAY);
1855 		}
1856 		if (retries++ >= vgen_ldcup_retries)
1857 			break;
1858 	} while (rv == EWOULDBLOCK);
1859 
1860 	(void) ldc_status(ldcp->ldc_handle, &istatus);
1861 	if (istatus != LDC_UP) {
1862 		DBG2((vnetp, "vgen_ldcinit: id(%lx) status(%d) is not UP\n",
1863 		    ldcp->ldc_id, istatus));
1864 	}
1865 	ldcp->ldc_status = istatus;
1866 
1867 	/* initialize transmit watchdog timeout */
1868 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
1869 	    drv_usectohz(vnet_ldcwd_interval * 1000));
1870 
1871 	ldcp->flags |= CHANNEL_STARTED;
1872 
1873 	LDC_UNLOCK(ldcp);
1874 	return (DDI_SUCCESS);
1875 
1876 ldcinit_failed:
1877 	if (init_state & ST_dring_bind) {
1878 		(void) ldc_mem_dring_unbind(ldcp->tx_dhandle);
1879 	}
1880 	if (init_state & ST_init_tbufs) {
1881 		vgen_uninit_tbufs(ldcp);
1882 	}
1883 	if (init_state & ST_ldc_open) {
1884 		(void) ldc_close(ldcp->ldc_handle);
1885 	}
1886 	LDC_UNLOCK(ldcp);
1887 	return (DDI_FAILURE);
1888 }
1889 
1890 /* stop transmit/receive on the channel */
1891 static void
1892 vgen_ldc_uninit(vgen_ldc_t *ldcp)
1893 {
1894 	void *vnetp = LDC_TO_VNET(ldcp);
1895 	int	rv;
1896 
1897 	DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id));
1898 	LDC_LOCK(ldcp);
1899 
1900 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
1901 		LDC_UNLOCK(ldcp);
1902 		DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED"
1903 		    " flag is not set\n", ldcp->ldc_id));
1904 		return;
1905 	}
1906 
1907 	/* disable further callbacks */
1908 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
1909 	if (rv != 0) {
1910 		DWARN((vnetp, "vgen_ldc_uninit: id (%lx) "
1911 		    "ldc_set_cb_mode failed\n", ldcp->ldc_id));
1912 	}
1913 
1914 	/* clear handshake done bit and wait for pending tx and cb to finish */
1915 	ldcp->hphase &= ~(VH_DONE);
1916 	LDC_UNLOCK(ldcp);
1917 	drv_usecwait(1000);
1918 	LDC_LOCK(ldcp);
1919 
1920 	vgen_reset_hphase(ldcp);
1921 
1922 	/* reset transmit watchdog timeout */
1923 	if (ldcp->wd_tid) {
1924 		(void) untimeout(ldcp->wd_tid);
1925 		ldcp->wd_tid = 0;
1926 	}
1927 
1928 	/* unbind tx descriptor ring from the channel */
1929 	rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
1930 	if (rv != 0) {
1931 		DWARN((vnetp, "vgen_ldcuninit: ldc_mem_dring_unbind "
1932 		    "failed id(%lx)\n", ldcp->ldc_id));
1933 	}
1934 
1935 	vgen_uninit_tbufs(ldcp);
1936 
1937 	rv = ldc_close(ldcp->ldc_handle);
1938 	if (rv != 0) {
1939 		DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n",
1940 		    ldcp->ldc_id));
1941 	}
1942 	ldcp->ldc_status = LDC_INIT;
1943 	ldcp->flags &= ~(CHANNEL_STARTED);
1944 
1945 	LDC_UNLOCK(ldcp);
1946 
1947 	DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id));
1948 }
1949 
1950 /* Initialize the transmit buffer ring for the channel */
1951 static int
1952 vgen_init_tbufs(vgen_ldc_t *ldcp)
1953 {
1954 	vgen_private_desc_t	*tbufp;
1955 	vnet_public_desc_t	*txdp;
1956 	vio_dring_entry_hdr_t		*hdrp;
1957 	int 			i;
1958 	int 			rv;
1959 	caddr_t			datap = NULL;
1960 	int			ci;
1961 	uint32_t		ncookies;
1962 
1963 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
1964 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
1965 
1966 	datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP);
1967 	ldcp->tx_datap = datap;
1968 
1969 	/*
1970 	 * for each private descriptor, allocate a ldc mem_handle which is
1971 	 * required to map the data during transmit, set the flags
1972 	 * to free (available for use by transmit routine).
1973 	 */
1974 
1975 	for (i = 0; i < ldcp->num_txds; i++) {
1976 
1977 		tbufp = &(ldcp->tbufp[i]);
1978 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
1979 			&(tbufp->memhandle));
1980 		if (rv) {
1981 			tbufp->memhandle = 0;
1982 			goto init_tbufs_failed;
1983 		}
1984 
1985 		/*
1986 		 * bind ldc memhandle to the corresponding transmit buffer.
1987 		 */
1988 		ci = ncookies = 0;
1989 		rv = ldc_mem_bind_handle(tbufp->memhandle,
1990 		    (caddr_t)datap, VGEN_DBLK_SZ, LDC_SHADOW_MAP,
1991 		    LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
1992 		if (rv != 0) {
1993 			goto init_tbufs_failed;
1994 		}
1995 
1996 		/*
1997 		 * successful in binding the handle to tx data buffer.
1998 		 * set datap in the private descr to this buffer.
1999 		 */
2000 		tbufp->datap = datap;
2001 
2002 		if ((ncookies == 0) ||
2003 			(ncookies > MAX_COOKIES)) {
2004 			goto init_tbufs_failed;
2005 		}
2006 
2007 		for (ci = 1; ci < ncookies; ci++) {
2008 			rv = ldc_mem_nextcookie(tbufp->memhandle,
2009 				&(tbufp->memcookie[ci]));
2010 			if (rv != 0) {
2011 				goto init_tbufs_failed;
2012 			}
2013 		}
2014 
2015 		tbufp->ncookies = ncookies;
2016 		datap += VGEN_DBLK_SZ;
2017 
2018 		tbufp->flags = VGEN_PRIV_DESC_FREE;
2019 		txdp = &(ldcp->txdp[i]);
2020 		hdrp = &txdp->hdr;
2021 		hdrp->dstate = VIO_DESC_FREE;
2022 		hdrp->ack = B_FALSE;
2023 		tbufp->descp = txdp;
2024 
2025 	}
2026 
2027 	/* reset tbuf walking pointers */
2028 	ldcp->next_tbufp = ldcp->tbufp;
2029 	ldcp->cur_tbufp = ldcp->tbufp;
2030 
2031 	/* initialize tx seqnum and index */
2032 	ldcp->next_txseq = VNET_ISS;
2033 	ldcp->next_txi = 0;
2034 
2035 	ldcp->resched_peer = B_TRUE;
2036 
2037 	return (DDI_SUCCESS);
2038 
2039 init_tbufs_failed:;
2040 	vgen_uninit_tbufs(ldcp);
2041 	return (DDI_FAILURE);
2042 }
2043 
2044 /* Uninitialize transmit buffer ring for the channel */
2045 static void
2046 vgen_uninit_tbufs(vgen_ldc_t *ldcp)
2047 {
2048 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
2049 	vnet_public_desc_t	*txdp;
2050 	vio_dring_entry_hdr_t		*hdrp;
2051 	int 			i;
2052 
2053 	/* for each tbuf (priv_desc), free ldc mem_handle */
2054 	for (i = 0; i < ldcp->num_txds; i++) {
2055 
2056 		tbufp = &(ldcp->tbufp[i]);
2057 		txdp = tbufp->descp;
2058 		hdrp = &txdp->hdr;
2059 
2060 		if (tbufp->datap) { /* if bound to a ldc memhandle */
2061 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
2062 			tbufp->datap = NULL;
2063 		}
2064 		tbufp->flags = VGEN_PRIV_DESC_FREE;
2065 		hdrp->dstate = VIO_DESC_FREE;
2066 		hdrp->ack = B_FALSE;
2067 		if (tbufp->memhandle) {
2068 			(void) ldc_mem_free_handle(tbufp->memhandle);
2069 			tbufp->memhandle = 0;
2070 		}
2071 		tbufp->descp = NULL;
2072 	}
2073 
2074 	if (ldcp->tx_datap) {
2075 		/* prealloc'd tx data buffer */
2076 		kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ);
2077 		ldcp->tx_datap = NULL;
2078 	}
2079 
2080 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
2081 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
2082 }
2083 
2084 /* clobber tx descriptor ring */
2085 static void
2086 vgen_clobber_tbufs(vgen_ldc_t *ldcp)
2087 {
2088 	vnet_public_desc_t	*txdp;
2089 	vgen_private_desc_t	*tbufp;
2090 	vio_dring_entry_hdr_t		*hdrp;
2091 	void *vnetp = LDC_TO_VNET(ldcp);
2092 	int i;
2093 #ifdef DEBUG
2094 	int ndone = 0;
2095 #endif
2096 
2097 	for (i = 0; i < ldcp->num_txds; i++) {
2098 
2099 		tbufp = &(ldcp->tbufp[i]);
2100 		txdp = tbufp->descp;
2101 		hdrp = &txdp->hdr;
2102 
2103 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
2104 			tbufp->flags = VGEN_PRIV_DESC_FREE;
2105 #ifdef DEBUG
2106 			if (hdrp->dstate == VIO_DESC_DONE)
2107 				ndone++;
2108 #endif
2109 			hdrp->dstate = VIO_DESC_FREE;
2110 			hdrp->ack = B_FALSE;
2111 		}
2112 	}
2113 	/* reset tbuf walking pointers */
2114 	ldcp->next_tbufp = ldcp->tbufp;
2115 	ldcp->cur_tbufp = ldcp->tbufp;
2116 
2117 	/* reset tx seqnum and index */
2118 	ldcp->next_txseq = VNET_ISS;
2119 	ldcp->next_txi = 0;
2120 
2121 	ldcp->resched_peer = B_TRUE;
2122 
2123 #ifdef DEBUG
2124 	DBG2((vnetp,
2125 	    "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
2126 	    ldcp->ldc_id, ndone));
2127 #endif
2128 }
2129 
2130 /* clobber receive descriptor ring */
2131 static void
2132 vgen_clobber_rxds(vgen_ldc_t *ldcp)
2133 {
2134 	ldcp->rx_dhandle = 0;
2135 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
2136 	ldcp->rxdp = NULL;
2137 	ldcp->next_rxi = 0;
2138 	ldcp->num_rxds = 0;
2139 	ldcp->next_rxseq = VNET_ISS;
2140 }
2141 
2142 /* initialize receive descriptor ring */
2143 static int
2144 vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
2145 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
2146 {
2147 	int rv;
2148 	ldc_mem_info_t minfo;
2149 
2150 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
2151 	    desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle));
2152 	if (rv != 0) {
2153 		return (DDI_FAILURE);
2154 	}
2155 
2156 	/*
2157 	 * sucessfully mapped, now try to
2158 	 * get info about the mapped dring
2159 	 */
2160 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
2161 	if (rv != 0) {
2162 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
2163 		return (DDI_FAILURE);
2164 	}
2165 
2166 	/*
2167 	 * save ring address, number of descriptors.
2168 	 */
2169 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
2170 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
2171 	ldcp->num_rxdcookies = ncookies;
2172 	ldcp->num_rxds = num_desc;
2173 	ldcp->next_rxi = 0;
2174 	ldcp->next_rxseq = VNET_ISS;
2175 
2176 	return (DDI_SUCCESS);
2177 }
2178 
2179 /* get channel statistics */
2180 static uint64_t
2181 vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
2182 {
2183 	vgen_stats_t *statsp;
2184 	uint64_t val;
2185 
2186 	val = 0;
2187 	statsp = ldcp->statsp;
2188 	switch (stat) {
2189 
2190 	case MAC_STAT_MULTIRCV:
2191 		val = statsp->multircv;
2192 		break;
2193 
2194 	case MAC_STAT_BRDCSTRCV:
2195 		val = statsp->brdcstrcv;
2196 		break;
2197 
2198 	case MAC_STAT_MULTIXMT:
2199 		val = statsp->multixmt;
2200 		break;
2201 
2202 	case MAC_STAT_BRDCSTXMT:
2203 		val = statsp->brdcstxmt;
2204 		break;
2205 
2206 	case MAC_STAT_NORCVBUF:
2207 		val = statsp->norcvbuf;
2208 		break;
2209 
2210 	case MAC_STAT_IERRORS:
2211 		val = statsp->ierrors;
2212 		break;
2213 
2214 	case MAC_STAT_NOXMTBUF:
2215 		val = statsp->noxmtbuf;
2216 		break;
2217 
2218 	case MAC_STAT_OERRORS:
2219 		val = statsp->oerrors;
2220 		break;
2221 
2222 	case MAC_STAT_COLLISIONS:
2223 		break;
2224 
2225 	case MAC_STAT_RBYTES:
2226 		val = statsp->rbytes;
2227 		break;
2228 
2229 	case MAC_STAT_IPACKETS:
2230 		val = statsp->ipackets;
2231 		break;
2232 
2233 	case MAC_STAT_OBYTES:
2234 		val = statsp->obytes;
2235 		break;
2236 
2237 	case MAC_STAT_OPACKETS:
2238 		val = statsp->opackets;
2239 		break;
2240 
2241 	/* stats not relevant to ldc, return 0 */
2242 	case MAC_STAT_IFSPEED:
2243 	case ETHER_STAT_ALIGN_ERRORS:
2244 	case ETHER_STAT_FCS_ERRORS:
2245 	case ETHER_STAT_FIRST_COLLISIONS:
2246 	case ETHER_STAT_MULTI_COLLISIONS:
2247 	case ETHER_STAT_DEFER_XMTS:
2248 	case ETHER_STAT_TX_LATE_COLLISIONS:
2249 	case ETHER_STAT_EX_COLLISIONS:
2250 	case ETHER_STAT_MACXMT_ERRORS:
2251 	case ETHER_STAT_CARRIER_ERRORS:
2252 	case ETHER_STAT_TOOLONG_ERRORS:
2253 	case ETHER_STAT_XCVR_ADDR:
2254 	case ETHER_STAT_XCVR_ID:
2255 	case ETHER_STAT_XCVR_INUSE:
2256 	case ETHER_STAT_CAP_1000FDX:
2257 	case ETHER_STAT_CAP_1000HDX:
2258 	case ETHER_STAT_CAP_100FDX:
2259 	case ETHER_STAT_CAP_100HDX:
2260 	case ETHER_STAT_CAP_10FDX:
2261 	case ETHER_STAT_CAP_10HDX:
2262 	case ETHER_STAT_CAP_ASMPAUSE:
2263 	case ETHER_STAT_CAP_PAUSE:
2264 	case ETHER_STAT_CAP_AUTONEG:
2265 	case ETHER_STAT_ADV_CAP_1000FDX:
2266 	case ETHER_STAT_ADV_CAP_1000HDX:
2267 	case ETHER_STAT_ADV_CAP_100FDX:
2268 	case ETHER_STAT_ADV_CAP_100HDX:
2269 	case ETHER_STAT_ADV_CAP_10FDX:
2270 	case ETHER_STAT_ADV_CAP_10HDX:
2271 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
2272 	case ETHER_STAT_ADV_CAP_PAUSE:
2273 	case ETHER_STAT_ADV_CAP_AUTONEG:
2274 	case ETHER_STAT_LP_CAP_1000FDX:
2275 	case ETHER_STAT_LP_CAP_1000HDX:
2276 	case ETHER_STAT_LP_CAP_100FDX:
2277 	case ETHER_STAT_LP_CAP_100HDX:
2278 	case ETHER_STAT_LP_CAP_10FDX:
2279 	case ETHER_STAT_LP_CAP_10HDX:
2280 	case ETHER_STAT_LP_CAP_ASMPAUSE:
2281 	case ETHER_STAT_LP_CAP_PAUSE:
2282 	case ETHER_STAT_LP_CAP_AUTONEG:
2283 	case ETHER_STAT_LINK_ASMPAUSE:
2284 	case ETHER_STAT_LINK_PAUSE:
2285 	case ETHER_STAT_LINK_AUTONEG:
2286 	case ETHER_STAT_LINK_DUPLEX:
2287 	default:
2288 		val = 0;
2289 		break;
2290 
2291 	}
2292 	return (val);
2293 }
2294 
2295 /* Interrupt handler for the channel */
2296 static uint_t
2297 vgen_ldc_cb(uint64_t event, caddr_t arg)
2298 {
2299 	_NOTE(ARGUNUSED(event))
2300 	vgen_ldc_t	*ldcp;
2301 	void 		*vnetp;
2302 	vgen_t		*vgenp;
2303 	size_t		msglen;
2304 	ldc_status_t 	istatus;
2305 	uint64_t	ldcmsg[7];
2306 	int 		rv;
2307 	vio_msg_tag_t	*tagp;
2308 	mblk_t		*mp = NULL;
2309 	mblk_t		*bp = NULL;
2310 	mblk_t		*bpt = NULL;
2311 	mblk_t		*headp = NULL;
2312 	mblk_t		*tailp = NULL;
2313 	vgen_stats_t	*statsp;
2314 
2315 	ldcp = (vgen_ldc_t *)arg;
2316 	vgenp = LDC_TO_VGEN(ldcp);
2317 	vnetp = LDC_TO_VNET(ldcp);
2318 	statsp = ldcp->statsp;
2319 
2320 	DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id));
2321 
2322 	mutex_enter(&ldcp->cblock);
2323 	statsp->callbacks++;
2324 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
2325 		DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
2326 		    ldcp->ldc_id, ldcp->ldc_status));
2327 		mutex_exit(&ldcp->cblock);
2328 		return (LDC_SUCCESS);
2329 	}
2330 
2331 	/* check ldc status change events first */
2332 	(void) ldc_status(ldcp->ldc_handle, &istatus);
2333 
2334 	if (istatus != ldcp->ldc_status) {
2335 		switch (istatus) {
2336 		case LDC_UP:
2337 			ldcp->ldc_status = istatus;
2338 			DBG1((vnetp,
2339 			    "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n",
2340 			    ldcp->ldc_id, ldcp->ldc_status));
2341 
2342 			if (ldcp->portp != vgenp->vsw_portp) {
2343 				/*
2344 				 * modify fdb entry to use this port as the
2345 				 * channel is up, instead of going through the
2346 				 * vsw-port (see comments in vgen_port_init())
2347 				 */
2348 				vnet_modify_fdb(vnetp,
2349 				    (uint8_t *)&ldcp->portp->macaddr,
2350 				    vgen_tx, ldcp->portp);
2351 			}
2352 			/* Initialize local session id */
2353 			ldcp->local_sid = ddi_get_lbolt();
2354 			/* clear peer session id */
2355 			ldcp->peer_sid = 0;
2356 			ldcp->hretries = 0;
2357 			/* Initiate Handshake process with peer ldc endpoint */
2358 			vgen_handshake_reset(ldcp);
2359 			vgen_handshake(vh_nextphase(ldcp));
2360 			break;
2361 
2362 		case LDC_OPEN:
2363 		case LDC_READY:
2364 			ldcp->ldc_status = istatus;
2365 			if ((ldcp->portp != vgenp->vsw_portp) &&
2366 				(vgenp->vsw_portp != NULL)) {
2367 				/*
2368 				 * modify fdb entry to use vsw-port  as the
2369 				 * channel is reset and we don't have a direct
2370 				 * link to the destination (see comments
2371 				 * in vgen_port_init()).
2372 				 */
2373 				vnet_modify_fdb(vnetp,
2374 				    (uint8_t *)&ldcp->portp->macaddr,
2375 				    vgen_tx, vgenp->vsw_portp);
2376 			}
2377 			/* clear sids */
2378 			ldcp->local_sid = 0;
2379 			ldcp->peer_sid = 0;
2380 			if (ldcp->hphase != VH_PHASE0) {
2381 				vgen_handshake_reset(ldcp);
2382 			}
2383 			DBG1((vnetp,
2384 			    "vgen_ldc_cb: id(%lx) status is (%d)\n",
2385 			    ldcp->ldc_id, ldcp->ldc_status));
2386 			break;
2387 
2388 		default:
2389 			DWARN((vnetp,
2390 			    "vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is"
2391 			    " *UNKNOWN*\n",
2392 			    ldcp->ldc_id, istatus, ldcp->ldc_status));
2393 			break;
2394 		}
2395 	}
2396 
2397 	if (istatus != LDC_UP) {
2398 		DBG1((vnetp, "vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n",
2399 			    ldcp->ldc_id, ldcp->ldc_status));
2400 		mutex_exit(&ldcp->cblock);
2401 		return (LDC_SUCCESS);
2402 	}
2403 
2404 	/* if ldc_status is UP, receive all packets */
2405 	do {
2406 		msglen = sizeof (ldcmsg);
2407 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen);
2408 
2409 		if (rv != 0) {
2410 			DWARN((vnetp,
2411 			    "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) "
2412 			    "len(%d)\n", ldcp->ldc_id, rv, msglen));
2413 			break;
2414 		}
2415 		if (msglen == 0) {
2416 			DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA",
2417 			ldcp->ldc_id));
2418 			break;
2419 		}
2420 		DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
2421 		    ldcp->ldc_id, msglen));
2422 
2423 		tagp = (vio_msg_tag_t *)ldcmsg;
2424 
2425 		if (ldcp->peer_sid) {
2426 			/*
2427 			 * check sid only after we have received peer's sid
2428 			 * in the version negotiate msg.
2429 			 */
2430 #ifdef DEBUG
2431 			if (vgen_hdbg & HDBG_BAD_SID) {
2432 				/* simulate bad sid condition */
2433 				tagp->vio_sid = 0;
2434 				vgen_hdbg &= ~(HDBG_BAD_SID);
2435 			}
2436 #endif
2437 			if (vgen_check_sid(ldcp, tagp) == VGEN_FAILURE) {
2438 				/*
2439 				 * If sid mismatch is detected,
2440 				 * reset the channel.
2441 				 */
2442 				ldcp->need_ldc_reset = B_TRUE;
2443 				vgen_handshake_reset(ldcp);
2444 				mutex_exit(&ldcp->cblock);
2445 				return (LDC_SUCCESS);
2446 			}
2447 		}
2448 
2449 		switch (tagp->vio_msgtype) {
2450 		case VIO_TYPE_CTRL:
2451 			vgen_handle_ctrlmsg(ldcp, tagp);
2452 			break;
2453 
2454 		case VIO_TYPE_DATA:
2455 			headp = tailp = NULL;
2456 			vgen_handle_datamsg(ldcp, tagp, &headp, &tailp);
2457 			/* build a chain of received packets */
2458 			if (headp != NULL) {
2459 				if (bp == NULL) {
2460 					bp = headp;
2461 					bpt = tailp;
2462 				} else {
2463 					bpt->b_next = headp;
2464 					bpt = tailp;
2465 				}
2466 			}
2467 			break;
2468 
2469 		case VIO_TYPE_ERR:
2470 			vgen_handle_errmsg(ldcp, tagp);
2471 			break;
2472 
2473 		default:
2474 			DWARN((vnetp,
2475 			    "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
2476 			    tagp->vio_msgtype));
2477 			break;
2478 		}
2479 
2480 	} while (msglen);
2481 
2482 	mutex_exit(&ldcp->cblock);
2483 	/* send up the received packets to MAC layer */
2484 	while (bp != NULL) {
2485 		mp = bp;
2486 		bp = bp->b_next;
2487 		mp->b_next = mp->b_prev = NULL;
2488 		DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
2489 		    ldcp->ldc_id, MBLKL(mp)));
2490 		vnet_rx(vgenp->vnetp, NULL, mp);
2491 	}
2492 	DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id));
2493 
2494 	return (LDC_SUCCESS);
2495 }
2496 
2497 /* vgen handshake functions */
2498 
2499 /* change the hphase for the channel to the next phase */
2500 static vgen_ldc_t *
2501 vh_nextphase(vgen_ldc_t *ldcp)
2502 {
2503 	if (ldcp->hphase == VH_PHASE3) {
2504 		ldcp->hphase = VH_DONE;
2505 	} else {
2506 		ldcp->hphase++;
2507 	}
2508 	return (ldcp);
2509 }
2510 
2511 /*
2512  * Check whether the given version is supported or not and
2513  * return VGEN_SUCCESS if supported.
2514  */
2515 static int
2516 vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major,
2517 uint16_t ver_minor)
2518 {
2519 	vgen_ver_t	*versions = ldcp->vgen_versions;
2520 	int		i = 0;
2521 
2522 	while (i < VGEN_NUM_VER) {
2523 		if ((versions[i].ver_major == 0) &&
2524 		    (versions[i].ver_minor == 0)) {
2525 			break;
2526 		}
2527 		if ((versions[i].ver_major == ver_major) &&
2528 			(versions[i].ver_minor == ver_minor)) {
2529 			return (VGEN_SUCCESS);
2530 		}
2531 		i++;
2532 	}
2533 	return (VGEN_FAILURE);
2534 }
2535 
2536 /*
2537  * Given a version, return VGEN_SUCCESS if a lower version is supported.
2538  */
2539 static int
2540 vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp)
2541 {
2542 	vgen_ver_t	*versions = ldcp->vgen_versions;
2543 	int		i = 0;
2544 
2545 	while (i < VGEN_NUM_VER) {
2546 		if ((versions[i].ver_major == 0) &&
2547 		    (versions[i].ver_minor == 0)) {
2548 			break;
2549 		}
2550 		/*
2551 		 * if we support a lower minor version within the same major
2552 		 * version, or if we support a lower major version,
2553 		 * update the verp parameter with this lower version and
2554 		 * return success.
2555 		 */
2556 		if (((versions[i].ver_major == verp->ver_major) &&
2557 			(versions[i].ver_minor < verp->ver_minor)) ||
2558 			(versions[i].ver_major < verp->ver_major)) {
2559 				verp->ver_major = versions[i].ver_major;
2560 				verp->ver_minor = versions[i].ver_minor;
2561 				return (VGEN_SUCCESS);
2562 		}
2563 		i++;
2564 	}
2565 
2566 	return (VGEN_FAILURE);
2567 }
2568 
2569 /*
2570  * wrapper routine to send the given message over ldc using ldc_write().
2571  */
2572 static int
2573 vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
2574     boolean_t caller_holds_lock)
2575 {
2576 	int	rv;
2577 	size_t	len;
2578 	void *vnetp = LDC_TO_VNET(ldcp);
2579 	uint32_t retries = 0;
2580 
2581 	len = msglen;
2582 	if ((len == 0) || (msg == NULL))
2583 		return (VGEN_FAILURE);
2584 
2585 	if (!caller_holds_lock) {
2586 		mutex_enter(&ldcp->txlock);
2587 	}
2588 
2589 	do {
2590 		len = msglen;
2591 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
2592 		if (retries++ >= vgen_ldcwr_retries)
2593 			break;
2594 	} while (rv == EWOULDBLOCK);
2595 
2596 	if (!caller_holds_lock) {
2597 		mutex_exit(&ldcp->txlock);
2598 	}
2599 
2600 	if ((rv != 0) || (len != msglen)) {
2601 		DWARN((vnetp,
2602 		    "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)"
2603 		    " msglen (%d)\n", ldcp->ldc_id, rv, msglen));
2604 		return (VGEN_FAILURE);
2605 	}
2606 	return (VGEN_SUCCESS);
2607 }
2608 
2609 /* send version negotiate message to the peer over ldc */
2610 static int
2611 vgen_send_version_negotiate(vgen_ldc_t *ldcp)
2612 {
2613 	vio_ver_msg_t	vermsg;
2614 	vio_msg_tag_t	*tagp = &vermsg.tag;
2615 	void		*vnetp = LDC_TO_VNET(ldcp);
2616 	int		rv;
2617 
2618 	bzero(&vermsg, sizeof (vermsg));
2619 
2620 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2621 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2622 	tagp->vio_subtype_env = VIO_VER_INFO;
2623 	tagp->vio_sid = ldcp->local_sid;
2624 
2625 	/* get version msg payload from ldcp->local */
2626 	vermsg.ver_major = ldcp->local_hparams.ver_major;
2627 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
2628 	vermsg.dev_class = ldcp->local_hparams.dev_class;
2629 
2630 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
2631 	if (rv != VGEN_SUCCESS) {
2632 		DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed"
2633 		    "id (%lx)\n", ldcp->ldc_id));
2634 		return (VGEN_FAILURE);
2635 	}
2636 
2637 	ldcp->hstate |= VER_INFO_SENT;
2638 	DBG2((vnetp,
2639 	    "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
2640 	    ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor));
2641 
2642 	return (VGEN_SUCCESS);
2643 }
2644 
2645 /* send attr info message to the peer over ldc */
2646 static int
2647 vgen_send_attr_info(vgen_ldc_t *ldcp)
2648 {
2649 	vnet_attr_msg_t	attrmsg;
2650 	vio_msg_tag_t	*tagp = &attrmsg.tag;
2651 	void		*vnetp = LDC_TO_VNET(ldcp);
2652 	int		rv;
2653 
2654 	bzero(&attrmsg, sizeof (attrmsg));
2655 
2656 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2657 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2658 	tagp->vio_subtype_env = VIO_ATTR_INFO;
2659 	tagp->vio_sid = ldcp->local_sid;
2660 
2661 	/* get attr msg payload from ldcp->local */
2662 	attrmsg.mtu = ldcp->local_hparams.mtu;
2663 	attrmsg.addr = ldcp->local_hparams.addr;
2664 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
2665 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
2666 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
2667 
2668 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
2669 	if (rv != VGEN_SUCCESS) {
2670 		DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed"
2671 		    "id (%lx)\n", ldcp->ldc_id));
2672 		return (VGEN_FAILURE);
2673 	}
2674 
2675 	ldcp->hstate |= ATTR_INFO_SENT;
2676 	DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
2677 	    ldcp->ldc_id));
2678 
2679 	return (VGEN_SUCCESS);
2680 }
2681 
2682 /* send descriptor ring register message to the peer over ldc */
2683 static int
2684 vgen_send_dring_reg(vgen_ldc_t *ldcp)
2685 {
2686 	vio_dring_reg_msg_t	msg;
2687 	vio_msg_tag_t		*tagp = &msg.tag;
2688 	void		*vnetp = LDC_TO_VNET(ldcp);
2689 	int		rv;
2690 
2691 	bzero(&msg, sizeof (msg));
2692 
2693 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2694 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2695 	tagp->vio_subtype_env = VIO_DRING_REG;
2696 	tagp->vio_sid = ldcp->local_sid;
2697 
2698 	/* get dring info msg payload from ldcp->local */
2699 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
2700 		sizeof (ldc_mem_cookie_t));
2701 	msg.ncookies = ldcp->local_hparams.num_dcookies;
2702 	msg.num_descriptors = ldcp->local_hparams.num_desc;
2703 	msg.descriptor_size = ldcp->local_hparams.desc_size;
2704 
2705 	/*
2706 	 * dring_ident is set to 0. After mapping the dring, peer sets this
2707 	 * value and sends it in the ack, which is saved in
2708 	 * vgen_handle_dring_reg().
2709 	 */
2710 	msg.dring_ident = 0;
2711 
2712 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
2713 	if (rv != VGEN_SUCCESS) {
2714 		DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed"
2715 		    "id (%lx)\n", ldcp->ldc_id));
2716 		return (VGEN_FAILURE);
2717 	}
2718 
2719 	ldcp->hstate |= DRING_INFO_SENT;
2720 	DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
2721 	    ldcp->ldc_id));
2722 
2723 	return (VGEN_SUCCESS);
2724 }
2725 
2726 static int
2727 vgen_send_rdx_info(vgen_ldc_t *ldcp)
2728 {
2729 	vio_rdx_msg_t	rdxmsg;
2730 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
2731 	void		*vnetp = LDC_TO_VNET(ldcp);
2732 	int		rv;
2733 
2734 	bzero(&rdxmsg, sizeof (rdxmsg));
2735 
2736 	tagp->vio_msgtype = VIO_TYPE_CTRL;
2737 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2738 	tagp->vio_subtype_env = VIO_RDX;
2739 	tagp->vio_sid = ldcp->local_sid;
2740 
2741 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
2742 	if (rv != VGEN_SUCCESS) {
2743 		DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed"
2744 		    "id (%lx)\n", ldcp->ldc_id));
2745 		return (VGEN_FAILURE);
2746 	}
2747 
2748 	ldcp->hstate |= RDX_INFO_SENT;
2749 	DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
2750 	    ldcp->ldc_id));
2751 
2752 	return (VGEN_SUCCESS);
2753 }
2754 
2755 /* send descriptor ring data message to the peer over ldc */
2756 static int
2757 vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
2758 {
2759 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
2760 	vio_msg_tag_t	*tagp = &msgp->tag;
2761 	void		*vnetp = LDC_TO_VNET(ldcp);
2762 	int		rv;
2763 
2764 	bzero(msgp, sizeof (*msgp));
2765 
2766 	tagp->vio_msgtype = VIO_TYPE_DATA;
2767 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
2768 	tagp->vio_subtype_env = VIO_DRING_DATA;
2769 	tagp->vio_sid = ldcp->local_sid;
2770 
2771 	msgp->seq_num = ldcp->next_txseq;
2772 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
2773 	msgp->start_idx = start;
2774 	msgp->end_idx = end;
2775 
2776 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
2777 	if (rv != VGEN_SUCCESS) {
2778 		DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed"
2779 		    "id (%lx)\n", ldcp->ldc_id));
2780 		return (VGEN_FAILURE);
2781 	}
2782 
2783 	ldcp->next_txseq++;
2784 	ldcp->statsp->dring_data_msgs++;
2785 
2786 	DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
2787 	    ldcp->ldc_id));
2788 
2789 	return (VGEN_SUCCESS);
2790 }
2791 
2792 /* send multicast addr info message to vsw */
2793 static int
2794 vgen_send_mcast_info(vgen_ldc_t *ldcp)
2795 {
2796 	vnet_mcast_msg_t	mcastmsg;
2797 	vnet_mcast_msg_t	*msgp;
2798 	vio_msg_tag_t		*tagp;
2799 	vgen_t			*vgenp;
2800 	void			*vnetp;
2801 	struct ether_addr	*mca;
2802 	int			rv;
2803 	int			i;
2804 	uint32_t		size;
2805 	uint32_t		mccount;
2806 	uint32_t		n;
2807 
2808 	msgp = &mcastmsg;
2809 	tagp = &msgp->tag;
2810 	vgenp = LDC_TO_VGEN(ldcp);
2811 	vnetp = LDC_TO_VNET(ldcp);
2812 
2813 	mccount = vgenp->mccount;
2814 	i = 0;
2815 
2816 	do {
2817 		tagp->vio_msgtype = VIO_TYPE_CTRL;
2818 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
2819 		tagp->vio_subtype_env = VNET_MCAST_INFO;
2820 		tagp->vio_sid = ldcp->local_sid;
2821 
2822 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
2823 		size = n * sizeof (struct ether_addr);
2824 
2825 		mca = &(vgenp->mctab[i]);
2826 		bcopy(mca, (msgp->mca), size);
2827 		msgp->set = B_TRUE;
2828 		msgp->count = n;
2829 
2830 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
2831 		    B_FALSE);
2832 		if (rv != VGEN_SUCCESS) {
2833 			DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err"
2834 			    "id (%lx)\n", ldcp->ldc_id));
2835 			return (VGEN_FAILURE);
2836 		}
2837 
2838 		mccount -= n;
2839 		i += n;
2840 
2841 	} while (mccount);
2842 
2843 	return (VGEN_SUCCESS);
2844 }
2845 
2846 /* Initiate Phase 2 of handshake */
2847 static int
2848 vgen_handshake_phase2(vgen_ldc_t *ldcp)
2849 {
2850 	int rv;
2851 #ifdef DEBUG
2852 	if (vgen_hdbg & HDBG_OUT_STATE) {
2853 		/* simulate out of state condition */
2854 		vgen_hdbg &= ~(HDBG_OUT_STATE);
2855 		rv = vgen_send_rdx_info(ldcp);
2856 		return (rv);
2857 	}
2858 	if (vgen_hdbg & HDBG_TIMEOUT) {
2859 		/* simulate timeout condition */
2860 		vgen_hdbg &= ~(HDBG_TIMEOUT);
2861 		return (VGEN_SUCCESS);
2862 	}
2863 #endif
2864 	if ((rv = vgen_send_attr_info(ldcp)) != VGEN_SUCCESS) {
2865 		return (rv);
2866 	}
2867 	if ((rv = vgen_send_dring_reg(ldcp)) != VGEN_SUCCESS) {
2868 		return (rv);
2869 	}
2870 
2871 	return (VGEN_SUCCESS);
2872 }
2873 
2874 /*
2875  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
2876  * This can happen after a channel comes up (status: LDC_UP) or
2877  * when handshake gets terminated due to various conditions.
2878  */
2879 static void
2880 vgen_reset_hphase(vgen_ldc_t *ldcp)
2881 {
2882 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
2883 	void	*vnetp = LDC_TO_VNET(ldcp);
2884 	ldc_status_t istatus;
2885 
2886 	DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id));
2887 	/* reset hstate and hphase */
2888 	ldcp->hstate = 0;
2889 	ldcp->hphase = VH_PHASE0;
2890 
2891 	/* reset handshake watchdog timeout */
2892 	if (ldcp->htid) {
2893 		(void) untimeout(ldcp->htid);
2894 		ldcp->htid = 0;
2895 	}
2896 
2897 	/*
2898 	 * Unmap drings, if dring_ready is set.
2899 	 */
2900 	if (ldcp->local_hparams.dring_ready) {
2901 		ldcp->local_hparams.dring_ready = B_FALSE;
2902 		/* do not unbind our dring */
2903 	}
2904 
2905 	if (ldcp->peer_hparams.dring_ready) {
2906 		ldcp->peer_hparams.dring_ready = B_FALSE;
2907 		/* Unmap peer's dring */
2908 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
2909 		vgen_clobber_rxds(ldcp);
2910 	}
2911 
2912 	vgen_clobber_tbufs(ldcp);
2913 
2914 	/*
2915 	 * clear local handshake params and initialize.
2916 	 */
2917 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
2918 
2919 	/* set version to the highest version supported */
2920 	ldcp->local_hparams.ver_major =
2921 			ldcp->vgen_versions[0].ver_major;
2922 	ldcp->local_hparams.ver_minor =
2923 			ldcp->vgen_versions[0].ver_minor;
2924 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
2925 
2926 	/* set attr_info params */
2927 	ldcp->local_hparams.mtu = ETHERMAX;
2928 	ldcp->local_hparams.addr =
2929 		vgen_macaddr_strtoul(vgenp->macaddr);
2930 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
2931 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE;
2932 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
2933 
2934 	/*
2935 	 * set dring_info params.
2936 	 * Note: dring is already created and bound.
2937 	 */
2938 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
2939 		sizeof (ldc_mem_cookie_t));
2940 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
2941 	ldcp->local_hparams.num_desc = ldcp->num_txds;
2942 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
2943 
2944 	/*
2945 	 * dring_ident is set to 0. After mapping the dring, peer sets this
2946 	 * value and sends it in the ack, which is saved in
2947 	 * vgen_handle_dring_reg().
2948 	 */
2949 	ldcp->local_hparams.dring_ident = 0;
2950 
2951 	/* clear peer_hparams */
2952 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
2953 
2954 	/* reset the channel if required */
2955 	if (ldcp->need_ldc_reset) {
2956 		DWARN((vnetp,
2957 		    "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
2958 		    ldcp->ldc_id));
2959 		ldcp->need_ldc_reset = B_FALSE;
2960 		(void) ldc_down(ldcp->ldc_handle);
2961 		(void) ldc_status(ldcp->ldc_handle, &istatus);
2962 		DBG2((vnetp,
2963 		    "vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n",
2964 		    ldcp->ldc_id, istatus));
2965 		ldcp->ldc_status = istatus;
2966 		/* clear sids */
2967 		ldcp->local_sid = 0;
2968 		ldcp->peer_sid = 0;
2969 		(void) ldc_up(ldcp->ldc_handle);
2970 	}
2971 }
2972 
2973 /* wrapper function for vgen_reset_hphase */
2974 static void
2975 vgen_handshake_reset(vgen_ldc_t *ldcp)
2976 {
2977 	ASSERT(MUTEX_HELD(&ldcp->cblock));
2978 	mutex_enter(&ldcp->txlock);
2979 	mutex_enter(&ldcp->tclock);
2980 
2981 	vgen_reset_hphase(ldcp);
2982 
2983 	mutex_exit(&ldcp->tclock);
2984 	mutex_exit(&ldcp->txlock);
2985 }
2986 
2987 /*
2988  * Initiate handshake with the peer by sending various messages
2989  * based on the handshake-phase that the channel is currently in.
2990  */
2991 static void
2992 vgen_handshake(vgen_ldc_t *ldcp)
2993 {
2994 	uint32_t hphase = ldcp->hphase;
2995 	void	*vnetp = LDC_TO_VNET(ldcp);
2996 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
2997 
2998 	switch (hphase) {
2999 
3000 	case VH_PHASE1:
3001 
3002 		/*
3003 		 * start timer, for entire handshake process, turn this timer
3004 		 * off if all phases of handshake complete successfully and
3005 		 * hphase goes to VH_DONE(below) or
3006 		 * vgen_reset_hphase() gets called or
3007 		 * channel is reset due to errors or
3008 		 * vgen_ldc_uninit() is invoked(vgen_stop).
3009 		 */
3010 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
3011 		    drv_usectohz(vgen_hwd_interval * 1000));
3012 
3013 		/* Phase 1 involves negotiating the version */
3014 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
3015 			vgen_handshake_reset(ldcp);
3016 		}
3017 		break;
3018 
3019 	case VH_PHASE2:
3020 		if (vgen_handshake_phase2(ldcp) != VGEN_SUCCESS) {
3021 			vgen_handshake_reset(ldcp);
3022 		}
3023 		break;
3024 
3025 	case VH_PHASE3:
3026 		if (vgen_send_rdx_info(ldcp) != VGEN_SUCCESS) {
3027 			vgen_handshake_reset(ldcp);
3028 		}
3029 		break;
3030 
3031 	case VH_DONE:
3032 		/* reset handshake watchdog timeout */
3033 		if (ldcp->htid) {
3034 			(void) untimeout(ldcp->htid);
3035 			ldcp->htid = 0;
3036 		}
3037 		ldcp->hretries = 0;
3038 #if 0
3039 		vgen_print_ldcinfo(ldcp);
3040 #endif
3041 		DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n",
3042 		    ldcp->ldc_id));
3043 
3044 		if (ldcp->need_mcast_sync) {
3045 			/* need to sync multicast table with vsw */
3046 
3047 			ldcp->need_mcast_sync = B_FALSE;
3048 			mutex_exit(&ldcp->cblock);
3049 
3050 			mutex_enter(&vgenp->lock);
3051 			(void) vgen_send_mcast_info(ldcp);
3052 			mutex_exit(&vgenp->lock);
3053 
3054 			mutex_enter(&ldcp->cblock);
3055 
3056 		}
3057 		break;
3058 
3059 	default:
3060 		break;
3061 	}
3062 }
3063 
3064 /*
3065  * Check if the current handshake phase has completed successfully and
3066  * return the status.
3067  */
3068 static int
3069 vgen_handshake_done(vgen_ldc_t *ldcp)
3070 {
3071 	uint32_t	hphase = ldcp->hphase;
3072 	int 		status = 0;
3073 	void		*vnetp = LDC_TO_VNET(ldcp);
3074 
3075 	switch (hphase) {
3076 
3077 	case VH_PHASE1:
3078 		/*
3079 		 * Phase1 is done, if version negotiation
3080 		 * completed successfully.
3081 		 */
3082 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
3083 			VER_NEGOTIATED);
3084 		break;
3085 
3086 	case VH_PHASE2:
3087 		/*
3088 		 * Phase 2 is done, if attr info and dring info
3089 		 * have been exchanged successfully.
3090 		 */
3091 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
3092 			    ATTR_INFO_EXCHANGED) &&
3093 			    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
3094 			    DRING_INFO_EXCHANGED));
3095 		break;
3096 
3097 	case VH_PHASE3:
3098 		/* Phase 3 is done, if rdx msg has been exchanged */
3099 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
3100 			RDX_EXCHANGED);
3101 		break;
3102 
3103 	default:
3104 		break;
3105 	}
3106 
3107 	if (status == 0) {
3108 		return (VGEN_FAILURE);
3109 	}
3110 	DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase));
3111 	return (VGEN_SUCCESS);
3112 }
3113 
3114 /* retry handshake on failure */
3115 static void
3116 vgen_handshake_retry(vgen_ldc_t *ldcp)
3117 {
3118 	/* reset handshake phase */
3119 	vgen_handshake_reset(ldcp);
3120 	if (vgen_max_hretries) {	/* handshake retry is specified */
3121 		if (ldcp->hretries++ < vgen_max_hretries)
3122 			vgen_handshake(vh_nextphase(ldcp));
3123 	}
3124 }
3125 
3126 /*
3127  * Handle a version info msg from the peer or an ACK/NACK from the peer
3128  * to a version info msg that we sent.
3129  */
3130 static void
3131 vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3132 {
3133 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
3134 	int		ack = 0;
3135 	int		failed = 0;
3136 	void		*vnetp = LDC_TO_VNET(ldcp);
3137 	int		idx;
3138 	vgen_ver_t	*versions = ldcp->vgen_versions;
3139 
3140 	DBG1((vnetp, "vgen_handle_version_negotiate: enter\n"));
3141 	switch (tagp->vio_subtype) {
3142 	case VIO_SUBTYPE_INFO:
3143 
3144 		/*  Cache sid of peer if this is the first time */
3145 		if (ldcp->peer_sid == 0) {
3146 			DBG2((vnetp,
3147 			    "vgen_handle_version_negotiate: id (%lx) Caching"
3148 			    " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid));
3149 			ldcp->peer_sid = tagp->vio_sid;
3150 		}
3151 
3152 		if (ldcp->hphase != VH_PHASE1) {
3153 			/*
3154 			 * If we are not already in VH_PHASE1, reset to
3155 			 * pre-handshake state, and initiate handshake
3156 			 * to the peer too.
3157 			 */
3158 			vgen_handshake_reset(ldcp);
3159 			vgen_handshake(vh_nextphase(ldcp));
3160 		}
3161 		ldcp->hstate |= VER_INFO_RCVD;
3162 
3163 		/* save peer's requested values */
3164 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
3165 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
3166 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
3167 
3168 		if ((vermsg->dev_class != VDEV_NETWORK) &&
3169 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
3170 			/* unsupported dev_class, send NACK */
3171 
3172 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3173 			tagp->vio_sid = ldcp->local_sid;
3174 			/* send reply msg back to peer */
3175 			(void) vgen_sendmsg(ldcp, (caddr_t)tagp,
3176 			    sizeof (*vermsg), B_FALSE);
3177 			DWARN((vnetp,
3178 			    "vgen_handle_version_negotiate: Version"
3179 			    " Negotiation Failed id (%lx)\n", ldcp->ldc_id));
3180 			vgen_handshake_reset(ldcp);
3181 			return;
3182 		}
3183 
3184 		DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD,"
3185 		    " id (%lx), ver(%d,%d)\n", ldcp->ldc_id,
3186 		    vermsg->ver_major,  vermsg->ver_minor));
3187 
3188 		idx = 0;
3189 
3190 		for (;;) {
3191 
3192 			if (vermsg->ver_major > versions[idx].ver_major) {
3193 
3194 				/* nack with next lower version */
3195 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
3196 				vermsg->ver_major = versions[idx].ver_major;
3197 				vermsg->ver_minor = versions[idx].ver_minor;
3198 				break;
3199 			}
3200 
3201 			if (vermsg->ver_major == versions[idx].ver_major) {
3202 
3203 				/* major version match - ACK version */
3204 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
3205 				ack = 1;
3206 
3207 				/*
3208 				 * lower minor version to the one this endpt
3209 				 * supports, if necessary
3210 				 */
3211 				if (vermsg->ver_minor >
3212 				    versions[idx].ver_minor) {
3213 					vermsg->ver_minor =
3214 						versions[idx].ver_minor;
3215 					ldcp->peer_hparams.ver_minor =
3216 						versions[idx].ver_minor;
3217 				}
3218 				break;
3219 			}
3220 
3221 			idx++;
3222 
3223 			if (idx == VGEN_NUM_VER) {
3224 
3225 				/* no version match - send NACK */
3226 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
3227 				vermsg->ver_major = 0;
3228 				vermsg->ver_minor = 0;
3229 				failed = 1;
3230 				break;
3231 			}
3232 
3233 		}
3234 
3235 		tagp->vio_sid = ldcp->local_sid;
3236 
3237 		/* send reply msg back to peer */
3238 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
3239 		    B_FALSE) != VGEN_SUCCESS) {
3240 			vgen_handshake_reset(ldcp);
3241 			return;
3242 		}
3243 
3244 		if (ack) {
3245 			ldcp->hstate |= VER_ACK_SENT;
3246 			DBG2((vnetp, "vgen_handle_version_negotiate:"
3247 			    " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
3248 			    ldcp->ldc_id, vermsg->ver_major,
3249 			    vermsg->ver_minor));
3250 		}
3251 		if (failed) {
3252 			DWARN((vnetp, "vgen_handle_version_negotiate:"
3253 			    " Version Negotiation Failed id (%lx)\n",
3254 			    ldcp->ldc_id));
3255 			vgen_handshake_reset(ldcp);
3256 			return;
3257 		}
3258 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3259 
3260 			/*  VER_ACK_SENT and VER_ACK_RCVD */
3261 
3262 			/* local and peer versions match? */
3263 			ASSERT((ldcp->local_hparams.ver_major ==
3264 				ldcp->peer_hparams.ver_major) &&
3265 				(ldcp->local_hparams.ver_minor ==
3266 				ldcp->peer_hparams.ver_minor));
3267 
3268 			/* move to the next phase */
3269 			vgen_handshake(vh_nextphase(ldcp));
3270 		}
3271 
3272 		break;
3273 
3274 	case VIO_SUBTYPE_ACK:
3275 
3276 		if (ldcp->hphase != VH_PHASE1) {
3277 			/*  This should not happen. */
3278 			DWARN((vnetp,
3279 			    "vgen_handle_version_negotiate:"
3280 			    " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
3281 			    ldcp->ldc_id, ldcp->hphase));
3282 			vgen_handshake_reset(ldcp);
3283 			return;
3284 		}
3285 
3286 		/* SUCCESS - we have agreed on a version */
3287 		ldcp->local_hparams.ver_major = vermsg->ver_major;
3288 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
3289 		ldcp->hstate |= VER_ACK_RCVD;
3290 
3291 		DBG2((vnetp, "vgen_handle_version_negotiate:"
3292 		    " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
3293 		    ldcp->ldc_id, vermsg->ver_major,  vermsg->ver_minor));
3294 
3295 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3296 
3297 			/*  VER_ACK_SENT and VER_ACK_RCVD */
3298 
3299 			/* local and peer versions match? */
3300 			ASSERT((ldcp->local_hparams.ver_major ==
3301 				ldcp->peer_hparams.ver_major) &&
3302 				(ldcp->local_hparams.ver_minor ==
3303 				ldcp->peer_hparams.ver_minor));
3304 
3305 			/* move to the next phase */
3306 			vgen_handshake(vh_nextphase(ldcp));
3307 		}
3308 		break;
3309 
3310 	case VIO_SUBTYPE_NACK:
3311 
3312 		if (ldcp->hphase != VH_PHASE1) {
3313 			/*  This should not happen.  */
3314 			DWARN((vnetp,
3315 			    "vgen_handle_version_negotiate:"
3316 			    " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
3317 			    ldcp->ldc_id, ldcp->hphase));
3318 			vgen_handshake_reset(ldcp);
3319 			return;
3320 		}
3321 
3322 		DBG2((vnetp, "vgen_handle_version_negotiate:"
3323 		    " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
3324 		    ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor));
3325 
3326 		/* check if version in NACK is zero */
3327 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
3328 			/*
3329 			 * Version Negotiation has failed.
3330 			 */
3331 			DWARN((vnetp, "vgen_handle_version_negotiate:"
3332 			    " Version Negotiation Failed id (%lx)\n",
3333 			    ldcp->ldc_id));
3334 			vgen_handshake_reset(ldcp);
3335 			return;
3336 		}
3337 
3338 		idx = 0;
3339 
3340 		for (;;) {
3341 
3342 			if (vermsg->ver_major > versions[idx].ver_major) {
3343 				/* select next lower version */
3344 
3345 				ldcp->local_hparams.ver_major =
3346 					versions[idx].ver_major;
3347 				ldcp->local_hparams.ver_minor =
3348 					versions[idx].ver_minor;
3349 				break;
3350 			}
3351 
3352 			if (vermsg->ver_major == versions[idx].ver_major) {
3353 				/* major version match */
3354 
3355 				ldcp->local_hparams.ver_major =
3356 					versions[idx].ver_major;
3357 
3358 				ldcp->local_hparams.ver_minor =
3359 					versions[idx].ver_minor;
3360 				break;
3361 			}
3362 
3363 			idx++;
3364 
3365 			if (idx == VGEN_NUM_VER) {
3366 				/*
3367 				 * no version match.
3368 				 * Version Negotiation has failed.
3369 				 */
3370 				DWARN((vnetp, "vgen_handle_version_negotiate:"
3371 				    " Version Negotiation Failed id (%lx)\n",
3372 				    ldcp->ldc_id));
3373 				vgen_handshake_reset(ldcp);
3374 				return;
3375 			}
3376 
3377 		}
3378 
3379 		if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) {
3380 			vgen_handshake_reset(ldcp);
3381 			return;
3382 		}
3383 
3384 		break;
3385 	}
3386 	DBG1((vnetp, "vgen_handle_version_negotiate: exit\n"));
3387 }
3388 
3389 /* Check if the attributes are supported */
3390 static int
3391 vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
3392 {
3393 	_NOTE(ARGUNUSED(ldcp))
3394 
3395 #if 0
3396 	uint64_t port_macaddr;
3397 	port_macaddr = vgen_macaddr_strtoul((uint8_t *)
3398 				&(ldcp->portp->macaddr));
3399 #endif
3400 	/*
3401 	 * currently, we support these attr values:
3402 	 * mtu of ethernet, addr_type of mac, xfer_mode of
3403 	 * ldc shared memory, ack_freq of 0 (data is acked if
3404 	 * the ack bit is set in the descriptor) and the address should
3405 	 * match the address in the port node.
3406 	 */
3407 	if ((msg->mtu != ETHERMAX) ||
3408 	    (msg->addr_type != ADDR_TYPE_MAC) ||
3409 	    (msg->xfer_mode != VIO_DRING_MODE) ||
3410 	    (msg->ack_freq > 64)) {
3411 #if 0
3412 	    (msg->addr != port_macaddr))
3413 cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
3414 	msg->addr, port_macaddr);
3415 #endif
3416 		return (VGEN_FAILURE);
3417 	}
3418 
3419 	return (VGEN_SUCCESS);
3420 }
3421 
3422 /*
3423  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
3424  * to an attr info msg that we sent.
3425  */
3426 static void
3427 vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3428 {
3429 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
3430 	void		*vnetp = LDC_TO_VNET(ldcp);
3431 	int		ack = 0;
3432 
3433 	DBG1((vnetp, "vgen_handle_attr_info: enter\n"));
3434 	if (ldcp->hphase != VH_PHASE2) {
3435 		DWARN((vnetp,
3436 		    "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)"
3437 		    " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3438 		    tagp->vio_subtype, ldcp->hphase));
3439 		vgen_handshake_reset(ldcp);
3440 		return;
3441 	}
3442 	switch (tagp->vio_subtype) {
3443 	case VIO_SUBTYPE_INFO:
3444 
3445 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
3446 		    ldcp->ldc_id));
3447 		ldcp->hstate |= ATTR_INFO_RCVD;
3448 
3449 		/* save peer's values */
3450 		ldcp->peer_hparams.mtu = attrmsg->mtu;
3451 		ldcp->peer_hparams.addr = attrmsg->addr;
3452 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
3453 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
3454 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
3455 
3456 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
3457 			/* unsupported attr, send NACK */
3458 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3459 		} else {
3460 			ack = 1;
3461 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
3462 		}
3463 		tagp->vio_sid = ldcp->local_sid;
3464 
3465 		/* send reply msg back to peer */
3466 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
3467 		    B_FALSE) != VGEN_SUCCESS) {
3468 			vgen_handshake_reset(ldcp);
3469 			return;
3470 		}
3471 
3472 		if (ack) {
3473 			ldcp->hstate |= ATTR_ACK_SENT;
3474 			DBG2((vnetp, "vgen_handle_attr_info:"
3475 			    " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id));
3476 		} else {
3477 			/* failed */
3478 			DWARN((vnetp, "vgen_handle_attr_info:"
3479 			    " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id));
3480 			vgen_handshake_reset(ldcp);
3481 			return;
3482 		}
3483 
3484 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3485 			vgen_handshake(vh_nextphase(ldcp));
3486 		}
3487 
3488 		break;
3489 
3490 	case VIO_SUBTYPE_ACK:
3491 
3492 		ldcp->hstate |= ATTR_ACK_RCVD;
3493 
3494 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
3495 		    ldcp->ldc_id));
3496 
3497 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3498 			vgen_handshake(vh_nextphase(ldcp));
3499 		}
3500 		break;
3501 
3502 	case VIO_SUBTYPE_NACK:
3503 
3504 		DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
3505 		    ldcp->ldc_id));
3506 		vgen_handshake_reset(ldcp);
3507 		break;
3508 	}
3509 	DBG1((vnetp, "vgen_handle_attr_info: exit\n"));
3510 }
3511 
3512 /* Check if the dring info msg is ok */
3513 static int
3514 vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
3515 {
3516 	/* check if msg contents are ok */
3517 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
3518 	    sizeof (vnet_public_desc_t))) {
3519 		return (VGEN_FAILURE);
3520 	}
3521 	return (VGEN_SUCCESS);
3522 }
3523 
3524 /*
3525  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
3526  * the peer to a dring register msg that we sent.
3527  */
3528 static void
3529 vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3530 {
3531 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
3532 	void *vnetp = LDC_TO_VNET(ldcp);
3533 	ldc_mem_cookie_t dcookie;
3534 	int ack = 0;
3535 	int rv = 0;
3536 
3537 	DBG1((vnetp, "vgen_handle_dring_reg: enter\n"));
3538 	if (ldcp->hphase < VH_PHASE2) {
3539 		/* dring_info can be rcvd in any of the phases after Phase1 */
3540 		DWARN((vnetp,
3541 		    "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)"
3542 		    " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3543 		    tagp->vio_subtype, ldcp->hphase));
3544 		vgen_handshake_reset(ldcp);
3545 		return;
3546 	}
3547 	switch (tagp->vio_subtype) {
3548 	case VIO_SUBTYPE_INFO:
3549 
3550 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
3551 		    ldcp->ldc_id));
3552 		ldcp->hstate |= DRING_INFO_RCVD;
3553 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
3554 
3555 		ASSERT(msg->ncookies == 1);
3556 
3557 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
3558 			/*
3559 			 * verified dring info msg to be ok,
3560 			 * now try to map the remote dring.
3561 			 */
3562 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
3563 			    msg->descriptor_size, &dcookie,
3564 			    msg->ncookies);
3565 			if (rv == DDI_SUCCESS) {
3566 				/* now we can ack the peer */
3567 				ack = 1;
3568 			}
3569 		}
3570 		if (ack == 0) {
3571 			/* failed, send NACK */
3572 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
3573 		} else {
3574 			if (!(ldcp->peer_hparams.dring_ready)) {
3575 
3576 				/* save peer's dring_info values */
3577 				bcopy(&dcookie,
3578 				    &(ldcp->peer_hparams.dring_cookie),
3579 				    sizeof (dcookie));
3580 				ldcp->peer_hparams.num_desc =
3581 						msg->num_descriptors;
3582 				ldcp->peer_hparams.desc_size =
3583 						msg->descriptor_size;
3584 				ldcp->peer_hparams.num_dcookies =
3585 						msg->ncookies;
3586 
3587 				/* set dring_ident for the peer */
3588 				ldcp->peer_hparams.dring_ident =
3589 							(uint64_t)ldcp->rxdp;
3590 				/* return the dring_ident in ack msg */
3591 				msg->dring_ident =
3592 							(uint64_t)ldcp->rxdp;
3593 
3594 				ldcp->peer_hparams.dring_ready = B_TRUE;
3595 			}
3596 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
3597 		}
3598 		tagp->vio_sid = ldcp->local_sid;
3599 		/* send reply msg back to peer */
3600 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
3601 		    B_FALSE) != VGEN_SUCCESS) {
3602 			vgen_handshake_reset(ldcp);
3603 			return;
3604 		}
3605 
3606 		if (ack) {
3607 			ldcp->hstate |= DRING_ACK_SENT;
3608 			DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT"
3609 			    " id (%lx)\n", ldcp->ldc_id));
3610 		} else {
3611 			DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT"
3612 			    " id (%lx)\n", ldcp->ldc_id));
3613 			vgen_handshake_reset(ldcp);
3614 			return;
3615 		}
3616 
3617 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3618 			vgen_handshake(vh_nextphase(ldcp));
3619 		}
3620 
3621 		break;
3622 
3623 	case VIO_SUBTYPE_ACK:
3624 
3625 		ldcp->hstate |= DRING_ACK_RCVD;
3626 
3627 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD"
3628 		    " id (%lx)\n", ldcp->ldc_id));
3629 
3630 		if (!(ldcp->local_hparams.dring_ready)) {
3631 			/* local dring is now ready */
3632 			ldcp->local_hparams.dring_ready = B_TRUE;
3633 
3634 			/* save dring_ident acked by peer */
3635 			ldcp->local_hparams.dring_ident =
3636 				msg->dring_ident;
3637 		}
3638 
3639 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3640 			vgen_handshake(vh_nextphase(ldcp));
3641 		}
3642 
3643 		break;
3644 
3645 	case VIO_SUBTYPE_NACK:
3646 
3647 		DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD"
3648 		    " id (%lx)\n", ldcp->ldc_id));
3649 		vgen_handshake_reset(ldcp);
3650 		break;
3651 	}
3652 	DBG1((vnetp, "vgen_handle_dring_reg: exit\n"));
3653 }
3654 
3655 /*
3656  * Handle a rdx info msg from the peer or an ACK/NACK
3657  * from the peer to a rdx info msg that we sent.
3658  */
3659 static void
3660 vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3661 {
3662 	void *vnetp = LDC_TO_VNET(ldcp);
3663 
3664 	DBG1((vnetp, "vgen_handle_rdx_info: enter\n"));
3665 	if (ldcp->hphase != VH_PHASE3) {
3666 		DWARN((vnetp,
3667 		    "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)"
3668 		    "  Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id,
3669 		    tagp->vio_subtype, ldcp->hphase));
3670 		vgen_handshake_reset(ldcp);
3671 		return;
3672 	}
3673 	switch (tagp->vio_subtype) {
3674 	case VIO_SUBTYPE_INFO:
3675 
3676 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
3677 		    ldcp->ldc_id));
3678 		ldcp->hstate |= RDX_INFO_RCVD;
3679 
3680 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
3681 		tagp->vio_sid = ldcp->local_sid;
3682 		/* send reply msg back to peer */
3683 		if (vgen_sendmsg(ldcp, (caddr_t)tagp,
3684 		    sizeof (vio_rdx_msg_t), B_FALSE) != VGEN_SUCCESS) {
3685 			vgen_handshake_reset(ldcp);
3686 			return;
3687 		}
3688 
3689 		ldcp->hstate |= RDX_ACK_SENT;
3690 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
3691 		    ldcp->ldc_id));
3692 
3693 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3694 			vgen_handshake(vh_nextphase(ldcp));
3695 		}
3696 
3697 		break;
3698 
3699 	case VIO_SUBTYPE_ACK:
3700 
3701 		ldcp->hstate |= RDX_ACK_RCVD;
3702 
3703 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
3704 		    ldcp->ldc_id));
3705 
3706 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
3707 			vgen_handshake(vh_nextphase(ldcp));
3708 		}
3709 		break;
3710 
3711 	case VIO_SUBTYPE_NACK:
3712 
3713 		DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
3714 		    ldcp->ldc_id));
3715 		vgen_handshake_reset(ldcp);
3716 		break;
3717 	}
3718 	DBG1((vnetp, "vgen_handle_rdx_info: exit\n"));
3719 }
3720 
3721 /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
3722 static void
3723 vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3724 {
3725 	void *vnetp = LDC_TO_VNET(ldcp);
3726 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3727 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
3728 	struct ether_addr *addrp;
3729 	int count;
3730 	int i;
3731 
3732 	DBG1((vnetp, "vgen_handle_mcast_info: enter\n"));
3733 	switch (tagp->vio_subtype) {
3734 
3735 	case VIO_SUBTYPE_INFO:
3736 
3737 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
3738 		DWARN((vnetp,
3739 		    "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
3740 		    ldcp->ldc_id));
3741 		break;
3742 
3743 	case VIO_SUBTYPE_ACK:
3744 
3745 		/* success adding/removing multicast addr */
3746 		DBG2((vnetp,
3747 		    "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
3748 		    ldcp->ldc_id));
3749 		break;
3750 
3751 	case VIO_SUBTYPE_NACK:
3752 
3753 		DWARN((vnetp,
3754 		    "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
3755 		    ldcp->ldc_id));
3756 		if (!(msgp->set)) {
3757 			/* multicast remove request failed */
3758 			break;
3759 		}
3760 
3761 		/* multicast add request failed */
3762 		for (count = 0; count < msgp->count; count++) {
3763 			addrp = &(msgp->mca[count]);
3764 
3765 			/* delete address from the table */
3766 			for (i = 0; i < vgenp->mccount; i++) {
3767 				if (ether_cmp(addrp,
3768 				    &(vgenp->mctab[i])) == 0) {
3769 					if (vgenp->mccount > 1) {
3770 						vgenp->mctab[i] =
3771 						vgenp->mctab[vgenp->mccount-1];
3772 					}
3773 					vgenp->mccount--;
3774 					break;
3775 				}
3776 			}
3777 		}
3778 		break;
3779 
3780 	}
3781 	DBG1((vnetp, "vgen_handle_mcast_info: exit\n"));
3782 }
3783 
3784 /* handler for control messages received from the peer ldc end-point */
3785 static void
3786 vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
3787 {
3788 	void *vnetp = LDC_TO_VNET(ldcp);
3789 
3790 	DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n"));
3791 	switch (tagp->vio_subtype_env) {
3792 
3793 	case VIO_VER_INFO:
3794 		vgen_handle_version_negotiate(ldcp, tagp);
3795 		break;
3796 
3797 	case VIO_ATTR_INFO:
3798 		vgen_handle_attr_info(ldcp, tagp);
3799 		break;
3800 
3801 	case VIO_DRING_REG:
3802 		vgen_handle_dring_reg(ldcp, tagp);
3803 		break;
3804 
3805 	case VIO_RDX:
3806 		vgen_handle_rdx_info(ldcp, tagp);
3807 		break;
3808 
3809 	case VNET_MCAST_INFO:
3810 		vgen_handle_mcast_info(ldcp, tagp);
3811 		break;
3812 
3813 	}
3814 	DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n"));
3815 }
3816 
3817 /* handler for data messages received from the peer ldc end-point */
3818 static void
3819 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3820 	mblk_t **headp, mblk_t **tailp)
3821 {
3822 	void *vnetp = LDC_TO_VNET(ldcp);
3823 
3824 	DBG1((vnetp, "vgen_handle_datamsg: enter\n"));
3825 
3826 	if (ldcp->hphase != VH_DONE)
3827 		return;
3828 	switch (tagp->vio_subtype_env) {
3829 	case VIO_DRING_DATA:
3830 		vgen_handle_dring_data(ldcp, tagp, headp, tailp);
3831 		break;
3832 	default:
3833 		break;
3834 	}
3835 
3836 	DBG1((vnetp, "vgen_handle_datamsg: exit\n"));
3837 }
3838 
3839 static void
3840 vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
3841     int32_t end, uint8_t pstate)
3842 {
3843 	vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp;
3844 	void *vnetp = LDC_TO_VNET(ldcp);
3845 
3846 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
3847 	tagp->vio_sid = ldcp->local_sid;
3848 	msgp->start_idx = start;
3849 	msgp->end_idx = end;
3850 	msgp->dring_process_state = pstate;
3851 	if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE)) {
3852 		DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg "
3853 		    "failed\n", (ldcp)->ldc_id));
3854 	}
3855 }
3856 
3857 static void
3858 vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
3859 	mblk_t **headp, mblk_t **tailp)
3860 {
3861 	vio_dring_msg_t *dringmsg;
3862 	vnet_public_desc_t *rxdp;
3863 	vnet_public_desc_t *txdp;
3864 	vio_dring_entry_hdr_t *hdrp;
3865 	vgen_stats_t *statsp;
3866 	struct ether_header *ehp;
3867 	mblk_t *mp = NULL;
3868 	mblk_t *bp = NULL;
3869 	mblk_t *bpt = NULL;
3870 	size_t nbytes;
3871 	size_t nread;
3872 	uint64_t off = 0;
3873 	uint32_t start;
3874 	int32_t end;
3875 	uint32_t datalen;
3876 	uint32_t ncookies;
3877 	uint32_t ack_start;
3878 	uint32_t ack_end;
3879 	uint32_t rxi;
3880 	uint32_t txi;
3881 	int rv;
3882 	boolean_t rxd_err = B_FALSE;
3883 	boolean_t set_ack_start = B_FALSE;
3884 	vgen_private_desc_t *tbufp;
3885 	uint32_t next_rxi;
3886 	boolean_t ready_txd = B_FALSE;
3887 	uint32_t retries = 0;
3888 #ifdef VGEN_HANDLE_LOST_PKTS
3889 	int n;
3890 #endif
3891 #ifdef VGEN_REXMIT
3892 	uint64_t seqnum;
3893 #endif
3894 	void *vnetp = LDC_TO_VNET(ldcp);
3895 
3896 	dringmsg = (vio_dring_msg_t *)tagp;
3897 	start = dringmsg->start_idx;
3898 	end = dringmsg->end_idx;
3899 	statsp = ldcp->statsp;
3900 
3901 	DBG1((vnetp, "vgen_handle_dring_data: enter\n"));
3902 	switch (tagp->vio_subtype) {
3903 
3904 	case VIO_SUBTYPE_INFO:
3905 		/*
3906 		 * received a data msg, which contains the start and end
3907 		 * indeces of the descriptors within the rx ring holding data,
3908 		 * the seq_num of data packet corresponding to the start index,
3909 		 * and the dring_ident.
3910 		 * We can now read the contents of each of these descriptors
3911 		 * and gather data from it.
3912 		 */
3913 		DBG2((vnetp,
3914 		    "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
3915 		    start, end));
3916 
3917 		/* validate rx start and end indeces */
3918 		if (!(CHECK_RXI(start, ldcp)) || ((end != -1) &&
3919 		    !(CHECK_RXI(end, ldcp)))) {
3920 			/* drop the message if invalid index */
3921 			break;
3922 		}
3923 
3924 		/* validate dring_ident */
3925 		if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
3926 			/* invalid dring_ident, drop the msg */
3927 			break;
3928 		}
3929 #ifdef DEBUG
3930 		if (vgen_trigger_rxlost) {
3931 			/* drop this msg to simulate lost pkts for debugging */
3932 			vgen_trigger_rxlost = 0;
3933 			break;
3934 		}
3935 #endif
3936 
3937 #ifdef	VGEN_HANDLE_LOST_PKTS
3938 
3939 		/* receive start index doesn't match expected index */
3940 		if (ldcp->next_rxi != start) {
3941 
3942 			DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
3943 			    "next_rxi(%d) != start(%d)\n",
3944 			    ldcp->ldc_id, ldcp->next_rxi, start));
3945 
3946 			/* calculate the number of pkts lost */
3947 			if (start >= ldcp->next_rxi) {
3948 				n = start - ldcp->next_rxi;
3949 			} else  {
3950 				n = ldcp->num_rxds - (ldcp->next_rxi - start);
3951 			}
3952 
3953 			/*
3954 			 * sequence number of dring data message
3955 			 * is less than the next sequence number that
3956 			 * is expected:
3957 			 *
3958 			 * drop the message and the corresponding packets.
3959 			 */
3960 			if (ldcp->next_rxseq > dringmsg->seq_num) {
3961 				DWARN((vnetp, "vgen_handle_dring_data: id(%lx) "
3962 				    "dropping pkts, expected rxseq(0x%lx) "
3963 				    "> recvd(0x%lx)\n",
3964 				    ldcp->ldc_id, ldcp->next_rxseq,
3965 				    dringmsg->seq_num));
3966 				/*
3967 				 * duplicate/multiple retransmissions from
3968 				 * sender?? drop this msg.
3969 				 */
3970 				break;
3971 			}
3972 
3973 			/*
3974 			 * sequence number of dring data message
3975 			 * is greater than the next expected sequence number
3976 			 *
3977 			 * send a NACK back to the peer to indicate lost
3978 			 * packets.
3979 			 */
3980 			if (dringmsg->seq_num > ldcp->next_rxseq) {
3981 				statsp->rx_lost_pkts += n;
3982 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
3983 				tagp->vio_sid = ldcp->local_sid;
3984 				/* indicate the range of lost descriptors */
3985 				dringmsg->start_idx = ldcp->next_rxi;
3986 				rxi = start;
3987 				DECR_RXI(rxi, ldcp);
3988 				dringmsg->end_idx = rxi;
3989 				/* dring ident is left unchanged */
3990 				if (vgen_sendmsg(ldcp, (caddr_t)tagp,
3991 				    sizeof (*dringmsg), B_FALSE)) {
3992 					DWARN((vnetp,
3993 					    "vgen_handle_dring_data: id(%lx) "
3994 					    "vgen_sendmsg failed, "
3995 					    "stype: NACK\n", ldcp->ldc_id));
3996 				}
3997 #ifdef VGEN_REXMIT
3998 				/*
3999 				 * stop further processing until peer
4000 				 * retransmits with the right index.
4001 				 * update next_rxseq expected.
4002 				 */
4003 				ldcp->next_rxseq += 1;
4004 				break;
4005 #else	/* VGEN_REXMIT */
4006 				/*
4007 				 * treat this range of descrs/pkts as dropped
4008 				 * and set the new expected values for next_rxi
4009 				 * and next_rxseq. continue(below) to process
4010 				 * from the new start index.
4011 				 */
4012 				ldcp->next_rxi = start;
4013 				ldcp->next_rxseq += 1;
4014 #endif	/* VGEN_REXMIT */
4015 
4016 			} else if (dringmsg->seq_num == ldcp->next_rxseq) {
4017 				/*
4018 				 * expected and received seqnums match, but
4019 				 * the descriptor indeces don't?
4020 				 *
4021 				 * restart handshake with peer.
4022 				 */
4023 				DWARN((vnetp,
4024 				    "vgen_handle_dring_data: id(%lx) "
4025 				    "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
4026 				    ldcp->ldc_id, ldcp->next_rxseq,
4027 				    dringmsg->seq_num));
4028 
4029 			}
4030 
4031 		} else {
4032 			/* expected and start dring indeces match */
4033 
4034 			if (dringmsg->seq_num != ldcp->next_rxseq) {
4035 
4036 				/* seqnums don't match */
4037 
4038 				DWARN((vnetp,
4039 				    "vgen_handle_dring_data: id(%lx) "
4040 				    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
4041 				    ldcp->ldc_id, ldcp->next_rxseq,
4042 				    dringmsg->seq_num));
4043 			}
4044 		}
4045 
4046 #endif	/* VGEN_HANDLE_LOST_PKTS */
4047 
4048 		/*
4049 		 * start processing the descriptors from the specified
4050 		 * start index, up to the index a descriptor is not ready
4051 		 * to be processed or we process the entire descriptor ring
4052 		 * and wrap around upto the start index.
4053 		 */
4054 
4055 		/* need to set the start index of descriptors to be ack'd */
4056 		set_ack_start = B_TRUE;
4057 
4058 		/* index upto which we have ack'd */
4059 		ack_end = start;
4060 		DECR_RXI(ack_end, ldcp);
4061 
4062 		next_rxi = rxi =  start;
4063 		do {
4064 
4065 vgen_recv_retry:	if (ldc_mem_dring_acquire(ldcp->rx_dhandle,
4066 			    rxi, rxi)) {
4067 				DWARN((vnetp, "vgen_handle_dring_data: "
4068 				    "id(%lx), ldc_mem_dring_acquire() failed\n",
4069 				    ldcp->ldc_id));
4070 				statsp->ierrors++;
4071 				break;
4072 			}
4073 
4074 			rxdp = &(ldcp->rxdp[rxi]);
4075 			hdrp = &rxdp->hdr;
4076 
4077 			if (hdrp->dstate != VIO_DESC_READY) {
4078 				/*
4079 				 * descriptor is not ready.
4080 				 * retry descriptor acquire, stop processing
4081 				 * after max # retries.
4082 				 */
4083 				if (retries == vgen_recv_retries)
4084 					break;
4085 				retries++;
4086 				drv_usecwait(vgen_recv_delay);
4087 				goto vgen_recv_retry;
4088 			}
4089 			retries = 0;
4090 
4091 			if (set_ack_start) {
4092 				/*
4093 				 * initialize the start index of the range
4094 				 * of descriptors to be ack'd.
4095 				 */
4096 				ack_start = rxi;
4097 				set_ack_start = B_FALSE;
4098 			}
4099 
4100 			datalen = rxdp->nbytes;
4101 			ncookies = rxdp->ncookies;
4102 			if ((datalen < ETHERMIN) ||
4103 			    (ncookies == 0) ||
4104 			    (ncookies > MAX_COOKIES)) {
4105 				rxd_err = B_TRUE;
4106 			} else {
4107 				/*
4108 				 * Try to allocate an mblk from the free pool
4109 				 * of recv mblks for the channel.
4110 				 * If this fails, use allocb().
4111 				 */
4112 				mp = vio_allocb(ldcp->rmp);
4113 				if (!mp) {
4114 					/*
4115 					 * The data buffer returned by
4116 					 * allocb(9F) is 8byte aligned. We
4117 					 * allocate extra 8 bytes to ensure
4118 					 * size is multiple of 8 bytes for
4119 					 * ldc_mem_copy().
4120 					 */
4121 					statsp->rx_vio_allocb_fail++;
4122 					mp = allocb(VNET_IPALIGN + datalen + 8,
4123 					    BPRI_MED);
4124 				}
4125 				nbytes = (VNET_IPALIGN + datalen + 7) & ~7;
4126 			}
4127 			if ((rxd_err) || (mp == NULL)) {
4128 				/*
4129 				 * rxd_err or allocb() failure,
4130 				 * drop this packet, get next.
4131 				 */
4132 				if (rxd_err) {
4133 					statsp->ierrors++;
4134 					rxd_err = B_FALSE;
4135 				} else {
4136 					statsp->rx_allocb_fail++;
4137 				}
4138 
4139 				/* set descriptor done bit */
4140 				hdrp->dstate = VIO_DESC_DONE;
4141 
4142 				(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4143 				    rxi, rxi);
4144 
4145 				if (hdrp->ack) {
4146 					/*
4147 					 * sender needs ack for this packet,
4148 					 * ack pkts upto this index.
4149 					 */
4150 					ack_end = rxi;
4151 
4152 					vgen_send_dring_ack(ldcp, tagp,
4153 					    ack_start, ack_end,
4154 					    VIO_DP_ACTIVE);
4155 
4156 					/* need to set new ack start index */
4157 					set_ack_start = B_TRUE;
4158 				}
4159 				goto vgen_next_rxi;
4160 			}
4161 
4162 			nread = nbytes;
4163 			rv = ldc_mem_copy(ldcp->ldc_handle,
4164 			    (caddr_t)mp->b_rptr, off, &nread,
4165 			    rxdp->memcookie, ncookies, LDC_COPY_IN);
4166 
4167 			/* set done bit irrespective of rv of ldc_mem_copy() */
4168 			hdrp->dstate = VIO_DESC_DONE;
4169 
4170 			(void) ldc_mem_dring_release(ldcp->rx_dhandle,
4171 			    rxi, rxi);
4172 
4173 			mp->b_rptr += VNET_IPALIGN;
4174 
4175 			if (hdrp->ack) {
4176 				/*
4177 				 * sender needs ack for this packet,
4178 				 * ack pkts upto this index.
4179 				 */
4180 				ack_end = rxi;
4181 
4182 				vgen_send_dring_ack(ldcp, tagp,
4183 				    ack_start, ack_end, VIO_DP_ACTIVE);
4184 
4185 				/* need to set new ack start index */
4186 				set_ack_start = B_TRUE;
4187 			}
4188 
4189 			/* if ldc_mem_copy() failed */
4190 			if (rv) {
4191 				DWARN((vnetp,
4192 				    "vgen_handle_dring_data: id(%lx) "
4193 				    "ldc_mem_copy failed\n", ldcp->ldc_id));
4194 				statsp->ierrors++;
4195 				freemsg(mp);
4196 				goto vgen_next_rxi;
4197 			}
4198 			if (nread != nbytes) {
4199 				DWARN((vnetp,
4200 				    "vgen_handle_dring_data: id(%lx) "
4201 				    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
4202 				    ldcp->ldc_id, nread, nbytes));
4203 				statsp->ierrors++;
4204 				freemsg(mp);
4205 				goto vgen_next_rxi;
4206 			}
4207 
4208 			/* point to the actual end of data */
4209 			mp->b_wptr = mp->b_rptr + datalen;
4210 
4211 			/* update stats */
4212 			statsp->ipackets++;
4213 			statsp->rbytes += datalen;
4214 			ehp = (struct ether_header *)mp->b_rptr;
4215 			if (IS_BROADCAST(ehp))
4216 				statsp->brdcstrcv++;
4217 			else if (IS_MULTICAST(ehp))
4218 				statsp->multircv++;
4219 
4220 			/* build a chain of received packets */
4221 			if (bp == NULL) {
4222 				/* first pkt */
4223 				bp = mp;
4224 				bpt = bp;
4225 				bpt->b_next = NULL;
4226 			} else {
4227 				mp->b_next = NULL;
4228 				bpt->b_next = mp;
4229 				bpt = mp;
4230 			}
4231 
4232 
4233 vgen_next_rxi:
4234 			/* update end index of range of descrs to be ack'd */
4235 			ack_end = rxi;
4236 
4237 			/* update the next index to be processed */
4238 			INCR_RXI(next_rxi, ldcp);
4239 			if (next_rxi == start) {
4240 				/*
4241 				 * processed the entire descriptor ring upto
4242 				 * the index at which we started.
4243 				 */
4244 				break;
4245 			}
4246 
4247 			rxi = next_rxi;
4248 
4249 		_NOTE(CONSTCOND)
4250 		} while (1);
4251 
4252 		/*
4253 		 * send an ack message to peer indicating that we have stopped
4254 		 * processing descriptors.
4255 		 */
4256 		if (set_ack_start) {
4257 			/*
4258 			 * We have ack'd upto some index and we have not
4259 			 * processed any descriptors beyond that index.
4260 			 * Use the last ack'd index as both the start and
4261 			 * end of range of descrs being ack'd.
4262 			 * Note: This results in acking the last index twice
4263 			 * and should be harmless.
4264 			 */
4265 			ack_start = ack_end;
4266 		}
4267 
4268 		vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
4269 		    VIO_DP_STOPPED);
4270 
4271 		/* save new recv index and expected seqnum of next dring msg */
4272 		ldcp->next_rxi = next_rxi;
4273 		ldcp->next_rxseq += 1;
4274 
4275 		break;
4276 
4277 	case VIO_SUBTYPE_ACK:
4278 		/*
4279 		 * received an ack corresponding to a specific descriptor for
4280 		 * which we had set the ACK bit in the descriptor (during
4281 		 * transmit). This enables us to reclaim descriptors.
4282 		 */
4283 
4284 		DBG2((vnetp,
4285 		    "vgen_handle_dring_data: ACK:  start(%d), end(%d)\n",
4286 		    start, end));
4287 
4288 		/* validate start and end indeces in the tx ack msg */
4289 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
4290 			/* drop the message if invalid index */
4291 			break;
4292 		}
4293 		/* validate dring_ident */
4294 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
4295 			/* invalid dring_ident, drop the msg */
4296 			break;
4297 		}
4298 		statsp->dring_data_acks++;
4299 
4300 		/* reclaim descriptors that are done */
4301 		vgen_reclaim(ldcp);
4302 
4303 		if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
4304 			/*
4305 			 * receiver continued processing descriptors after
4306 			 * sending us the ack.
4307 			 */
4308 			break;
4309 		}
4310 
4311 		statsp->dring_stopped_acks++;
4312 
4313 		/* receiver stopped processing descriptors */
4314 		mutex_enter(&ldcp->txlock);
4315 		mutex_enter(&ldcp->tclock);
4316 
4317 		/*
4318 		 * determine if there are any pending tx descriptors
4319 		 * ready to be processed by the receiver(peer) and if so,
4320 		 * send a message to the peer to restart receiving.
4321 		 */
4322 		ready_txd = B_FALSE;
4323 
4324 		/*
4325 		 * using the end index of the descriptor range for which
4326 		 * we received the ack, check if the next descriptor is
4327 		 * ready.
4328 		 */
4329 		txi = end;
4330 		INCR_TXI(txi, ldcp);
4331 		tbufp = &ldcp->tbufp[txi];
4332 		txdp = tbufp->descp;
4333 		hdrp = &txdp->hdr;
4334 		if (hdrp->dstate == VIO_DESC_READY) {
4335 			ready_txd = B_TRUE;
4336 		} else {
4337 			/*
4338 			 * descr next to the end of ack'd descr range is not
4339 			 * ready.
4340 			 * starting from the current reclaim index, check
4341 			 * if any descriptor is ready.
4342 			 */
4343 
4344 			txi = ldcp->cur_tbufp - ldcp->tbufp;
4345 			tbufp = &ldcp->tbufp[txi];
4346 
4347 			while (tbufp != ldcp->next_tbufp) {
4348 
4349 				txdp = tbufp->descp;
4350 				hdrp = &txdp->hdr;
4351 				if (hdrp->dstate == VIO_DESC_READY) {
4352 					break;
4353 				}
4354 
4355 				INCR_TXI(txi, ldcp);
4356 				tbufp = &ldcp->tbufp[txi];
4357 
4358 			}
4359 
4360 			if (tbufp != ldcp->next_tbufp)
4361 				ready_txd = B_TRUE;
4362 		}
4363 
4364 		if (ready_txd) {
4365 			/*
4366 			 * we have tx descriptor(s) ready to be
4367 			 * processed by the receiver.
4368 			 * send a message to the peer with the start index
4369 			 * of ready descriptors.
4370 			 */
4371 			rv = vgen_send_dring_data(ldcp, txi, -1);
4372 			if (rv != 0) {
4373 				ldcp->resched_peer = B_TRUE;
4374 			}
4375 		} else {
4376 			/*
4377 			 * no ready tx descriptors. set the flag to send a
4378 			 * message to peer when tx descriptors are ready in
4379 			 * transmit routine.
4380 			 */
4381 			ldcp->resched_peer = B_TRUE;
4382 		}
4383 
4384 		mutex_exit(&ldcp->tclock);
4385 		mutex_exit(&ldcp->txlock);
4386 
4387 		break;
4388 
4389 	case VIO_SUBTYPE_NACK:
4390 		/*
4391 		 * peer sent a NACK msg to indicate lost packets.
4392 		 * The start and end correspond to the range of descriptors
4393 		 * for which the peer didn't receive a dring data msg and so
4394 		 * didn't receive the corresponding data.
4395 		 */
4396 		DWARN((vnetp,
4397 		    "vgen_handle_dring_data: NACK:  start(%d), end(%d)\n",
4398 		    start, end));
4399 
4400 		/* validate start and end indeces in the tx nack msg */
4401 		if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
4402 			/* drop the message if invalid index */
4403 			break;
4404 		}
4405 		/* validate dring_ident */
4406 		if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
4407 			/* invalid dring_ident, drop the msg */
4408 			break;
4409 		}
4410 		mutex_enter(&ldcp->txlock);
4411 		mutex_enter(&ldcp->tclock);
4412 
4413 		if (ldcp->next_tbufp == ldcp->cur_tbufp) {
4414 			/* no busy descriptors, bogus nack ? */
4415 			mutex_exit(&ldcp->tclock);
4416 			mutex_exit(&ldcp->txlock);
4417 			break;
4418 		}
4419 
4420 #ifdef VGEN_REXMIT
4421 		/* send a new dring data msg including the lost descrs */
4422 		end = ldcp->next_tbufp - ldcp->tbufp;
4423 		DECR_TXI(end, ldcp);
4424 		rv = vgen_send_dring_data(ldcp, start, end);
4425 		if (rv != 0) {
4426 			/*
4427 			 * vgen_send_dring_data() error: drop all packets
4428 			 * in this descr range
4429 			 */
4430 			DWARN((vnetp,
4431 			    "vgen_handle_dring_data: "
4432 			    "vgen_send_dring_data failed :"
4433 			    "id(%lx) rv(%d)\n", ldcp->ldc_id, rv));
4434 			for (txi = start; txi <= end; ) {
4435 				tbufp = &(ldcp->tbufp[txi]);
4436 				txdp = tbufp->descp;
4437 				hdrp = &txdp->hdr;
4438 				tbufp->flags = VGEN_PRIV_DESC_FREE;
4439 				hdrp->dstate = VIO_DESC_FREE;
4440 				hdrp->ack = B_FALSE;
4441 				statsp->oerrors++;
4442 			}
4443 
4444 			/* update next pointer */
4445 			ldcp->next_tbufp = &(ldcp->tbufp[start]);
4446 			ldcp->next_txi = start;
4447 		}
4448 		DBG2((vnetp,
4449 		    "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
4450 		    start, end));
4451 #else	/* VGEN_REXMIT */
4452 		/* we just mark the descrs as done so they can be reclaimed */
4453 		for (txi = start; txi <= end; ) {
4454 			txdp = &(ldcp->txdp[txi]);
4455 			hdrp = &txdp->hdr;
4456 			if (hdrp->dstate == VIO_DESC_READY)
4457 				hdrp->dstate = VIO_DESC_DONE;
4458 			INCR_TXI(txi, ldcp);
4459 		}
4460 #endif	/* VGEN_REXMIT */
4461 		mutex_exit(&ldcp->tclock);
4462 		mutex_exit(&ldcp->txlock);
4463 
4464 		break;
4465 	}
4466 
4467 	DBG1((vnetp, "vgen_handle_dring_data: exit\n"));
4468 	*headp = bp;
4469 	*tailp = bpt;
4470 
4471 }
4472 
4473 static void
4474 vgen_reclaim(vgen_ldc_t *ldcp)
4475 {
4476 	mutex_enter(&ldcp->tclock);
4477 
4478 	vgen_reclaim_dring(ldcp);
4479 	ldcp->reclaim_lbolt = ddi_get_lbolt();
4480 
4481 	mutex_exit(&ldcp->tclock);
4482 }
4483 
4484 /*
4485  * transmit reclaim function. starting from the current reclaim index
4486  * look for descriptors marked DONE and reclaim the descriptor and the
4487  * corresponding buffers (tbuf).
4488  */
4489 static void
4490 vgen_reclaim_dring(vgen_ldc_t *ldcp)
4491 {
4492 	vnet_public_desc_t *txdp;
4493 	vgen_private_desc_t *tbufp;
4494 	vio_dring_entry_hdr_t	*hdrp;
4495 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
4496 
4497 #ifdef DEBUG
4498 	if (vgen_trigger_txtimeout)
4499 		return;
4500 #endif
4501 
4502 	tbufp = ldcp->cur_tbufp;
4503 	txdp = tbufp->descp;
4504 	hdrp = &txdp->hdr;
4505 
4506 	while ((hdrp->dstate == VIO_DESC_DONE) &&
4507 	    (tbufp != ldcp->next_tbufp)) {
4508 		tbufp->flags = VGEN_PRIV_DESC_FREE;
4509 		hdrp->dstate = VIO_DESC_FREE;
4510 		hdrp->ack = B_FALSE;
4511 
4512 		tbufp = NEXTTBUF(ldcp, tbufp);
4513 		txdp = tbufp->descp;
4514 		hdrp = &txdp->hdr;
4515 	}
4516 
4517 	ldcp->cur_tbufp = tbufp;
4518 
4519 	/*
4520 	 * Check if mac layer should be notified to restart transmissions
4521 	 */
4522 	if (ldcp->need_resched) {
4523 		ldcp->need_resched = B_FALSE;
4524 		vnet_tx_update(vgenp->vnetp);
4525 	}
4526 }
4527 
4528 /* return the number of pending transmits for the channel */
4529 static int
4530 vgen_num_txpending(vgen_ldc_t *ldcp)
4531 {
4532 	int n;
4533 
4534 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
4535 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
4536 	} else  {
4537 		/* cur_tbufp > next_tbufp */
4538 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
4539 	}
4540 
4541 	return (n);
4542 }
4543 
4544 /* determine if the transmit descriptor ring is full */
4545 static int
4546 vgen_tx_dring_full(vgen_ldc_t *ldcp)
4547 {
4548 	vgen_private_desc_t	*tbufp;
4549 	vgen_private_desc_t	*ntbufp;
4550 
4551 	tbufp = ldcp->next_tbufp;
4552 	ntbufp = NEXTTBUF(ldcp, tbufp);
4553 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
4554 		return (VGEN_SUCCESS);
4555 	}
4556 	return (VGEN_FAILURE);
4557 }
4558 
4559 /* determine if timeout condition has occured */
4560 static int
4561 vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
4562 {
4563 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
4564 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
4565 	    (vnet_ldcwd_txtimeout) &&
4566 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
4567 		return (VGEN_SUCCESS);
4568 	} else {
4569 		return (VGEN_FAILURE);
4570 	}
4571 }
4572 
4573 /* transmit watchdog timeout handler */
4574 static void
4575 vgen_ldc_watchdog(void *arg)
4576 {
4577 	vgen_ldc_t *ldcp;
4578 	vgen_t *vgenp;
4579 	void *vnetp;
4580 	int rv;
4581 
4582 	ldcp = (vgen_ldc_t *)arg;
4583 	vgenp = LDC_TO_VGEN(ldcp);
4584 	vnetp = LDC_TO_VNET(ldcp);
4585 
4586 	rv = vgen_ldc_txtimeout(ldcp);
4587 	if (rv == VGEN_SUCCESS) {
4588 		DWARN((vnetp,
4589 		    "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
4590 		    ldcp->ldc_id));
4591 #ifdef DEBUG
4592 		if (vgen_trigger_txtimeout) {
4593 			/* tx timeout triggered for debugging */
4594 			vgen_trigger_txtimeout = 0;
4595 		}
4596 #endif
4597 		mutex_enter(&ldcp->cblock);
4598 		vgen_handshake_retry(ldcp);
4599 		mutex_exit(&ldcp->cblock);
4600 		if (ldcp->need_resched) {
4601 			ldcp->need_resched = B_FALSE;
4602 			vnet_tx_update(vgenp->vnetp);
4603 		}
4604 	}
4605 
4606 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
4607 	    drv_usectohz(vnet_ldcwd_interval * 1000));
4608 }
4609 
4610 static int
4611 vgen_setup_kstats(vgen_ldc_t *ldcp)
4612 {
4613 	vgen_t *vgenp;
4614 	struct kstat *ksp;
4615 	vgen_stats_t *statsp;
4616 	vgen_kstats_t *ldckp;
4617 	int instance;
4618 	size_t size;
4619 	char name[MAXNAMELEN];
4620 
4621 	vgenp = LDC_TO_VGEN(ldcp);
4622 	instance = ddi_get_instance(vgenp->vnetdip);
4623 	(void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id);
4624 	statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP);
4625 	if (statsp == NULL) {
4626 		return (VGEN_FAILURE);
4627 	}
4628 	size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t);
4629 	ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED,
4630 		size, 0);
4631 	if (ksp == NULL) {
4632 		KMEM_FREE(statsp);
4633 		return (VGEN_FAILURE);
4634 	}
4635 
4636 	ldckp = (vgen_kstats_t *)ksp->ks_data;
4637 	kstat_named_init(&ldckp->ipackets,		"ipackets",
4638 		KSTAT_DATA_ULONG);
4639 	kstat_named_init(&ldckp->ipackets64,		"ipackets64",
4640 		KSTAT_DATA_ULONGLONG);
4641 	kstat_named_init(&ldckp->ierrors,		"ierrors",
4642 		KSTAT_DATA_ULONG);
4643 	kstat_named_init(&ldckp->opackets,		"opackets",
4644 		KSTAT_DATA_ULONG);
4645 	kstat_named_init(&ldckp->opackets64,		"opackets64",
4646 		KSTAT_DATA_ULONGLONG);
4647 	kstat_named_init(&ldckp->oerrors,		"oerrors",
4648 		KSTAT_DATA_ULONG);
4649 
4650 
4651 	/* MIB II kstat variables */
4652 	kstat_named_init(&ldckp->rbytes,		"rbytes",
4653 		KSTAT_DATA_ULONG);
4654 	kstat_named_init(&ldckp->rbytes64,		"rbytes64",
4655 		KSTAT_DATA_ULONGLONG);
4656 	kstat_named_init(&ldckp->obytes,		"obytes",
4657 		KSTAT_DATA_ULONG);
4658 	kstat_named_init(&ldckp->obytes64,		"obytes64",
4659 		KSTAT_DATA_ULONGLONG);
4660 	kstat_named_init(&ldckp->multircv,		"multircv",
4661 		KSTAT_DATA_ULONG);
4662 	kstat_named_init(&ldckp->multixmt,		"multixmt",
4663 		KSTAT_DATA_ULONG);
4664 	kstat_named_init(&ldckp->brdcstrcv,		"brdcstrcv",
4665 		KSTAT_DATA_ULONG);
4666 	kstat_named_init(&ldckp->brdcstxmt,		"brdcstxmt",
4667 		KSTAT_DATA_ULONG);
4668 	kstat_named_init(&ldckp->norcvbuf,		"norcvbuf",
4669 		KSTAT_DATA_ULONG);
4670 	kstat_named_init(&ldckp->noxmtbuf,		"noxmtbuf",
4671 		KSTAT_DATA_ULONG);
4672 
4673 	/* Tx stats */
4674 	kstat_named_init(&ldckp->tx_no_desc,		"tx_no_desc",
4675 		KSTAT_DATA_ULONG);
4676 
4677 	/* Rx stats */
4678 	kstat_named_init(&ldckp->rx_allocb_fail,	"rx_allocb_fail",
4679 		KSTAT_DATA_ULONG);
4680 	kstat_named_init(&ldckp->rx_vio_allocb_fail,	"rx_vio_allocb_fail",
4681 		KSTAT_DATA_ULONG);
4682 	kstat_named_init(&ldckp->rx_lost_pkts,		"rx_lost_pkts",
4683 		KSTAT_DATA_ULONG);
4684 
4685 	/* Interrupt stats */
4686 	kstat_named_init(&ldckp->callbacks,		"callbacks",
4687 		KSTAT_DATA_ULONG);
4688 	kstat_named_init(&ldckp->dring_data_acks,	"dring_data_acks",
4689 		KSTAT_DATA_ULONG);
4690 	kstat_named_init(&ldckp->dring_stopped_acks,	"dring_stopped_acks",
4691 		KSTAT_DATA_ULONG);
4692 	kstat_named_init(&ldckp->dring_data_msgs,	"dring_data_msgs",
4693 		KSTAT_DATA_ULONG);
4694 
4695 	ksp->ks_update = vgen_kstat_update;
4696 	ksp->ks_private = (void *)ldcp;
4697 	kstat_install(ksp);
4698 
4699 	ldcp->ksp = ksp;
4700 	ldcp->statsp = statsp;
4701 	return (VGEN_SUCCESS);
4702 }
4703 
4704 static void
4705 vgen_destroy_kstats(vgen_ldc_t *ldcp)
4706 {
4707 	if (ldcp->ksp)
4708 		kstat_delete(ldcp->ksp);
4709 	KMEM_FREE(ldcp->statsp);
4710 }
4711 
4712 static int
4713 vgen_kstat_update(kstat_t *ksp, int rw)
4714 {
4715 	vgen_ldc_t *ldcp;
4716 	vgen_stats_t *statsp;
4717 	vgen_kstats_t *ldckp;
4718 
4719 	ldcp = (vgen_ldc_t *)ksp->ks_private;
4720 	statsp = ldcp->statsp;
4721 	ldckp = (vgen_kstats_t *)ksp->ks_data;
4722 
4723 	if (rw == KSTAT_READ) {
4724 		ldckp->ipackets.value.ul	= (uint32_t)statsp->ipackets;
4725 		ldckp->ipackets64.value.ull	= statsp->ipackets;
4726 		ldckp->ierrors.value.ul		= statsp->ierrors;
4727 		ldckp->opackets.value.ul	= (uint32_t)statsp->opackets;
4728 		ldckp->opackets64.value.ull	= statsp->opackets;
4729 		ldckp->oerrors.value.ul		= statsp->oerrors;
4730 
4731 		/*
4732 		 * MIB II kstat variables
4733 		 */
4734 		ldckp->rbytes.value.ul		= (uint32_t)statsp->rbytes;
4735 		ldckp->rbytes64.value.ull	= statsp->rbytes;
4736 		ldckp->obytes.value.ul		= (uint32_t)statsp->obytes;
4737 		ldckp->obytes64.value.ull	= statsp->obytes;
4738 		ldckp->multircv.value.ul	= statsp->multircv;
4739 		ldckp->multixmt.value.ul	= statsp->multixmt;
4740 		ldckp->brdcstrcv.value.ul	= statsp->brdcstrcv;
4741 		ldckp->brdcstxmt.value.ul	= statsp->brdcstxmt;
4742 		ldckp->norcvbuf.value.ul	= statsp->norcvbuf;
4743 		ldckp->noxmtbuf.value.ul	= statsp->noxmtbuf;
4744 
4745 		ldckp->tx_no_desc.value.ul	= statsp->tx_no_desc;
4746 
4747 		ldckp->rx_allocb_fail.value.ul	= statsp->rx_allocb_fail;
4748 		ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail;
4749 		ldckp->rx_lost_pkts.value.ul	= statsp->rx_lost_pkts;
4750 
4751 		ldckp->callbacks.value.ul	= statsp->callbacks;
4752 		ldckp->dring_data_acks.value.ul	= statsp->dring_data_acks;
4753 		ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks;
4754 		ldckp->dring_data_msgs.value.ul	= statsp->dring_data_msgs;
4755 	} else {
4756 		statsp->ipackets	= ldckp->ipackets64.value.ull;
4757 		statsp->ierrors		= ldckp->ierrors.value.ul;
4758 		statsp->opackets	= ldckp->opackets64.value.ull;
4759 		statsp->oerrors		= ldckp->oerrors.value.ul;
4760 
4761 		/*
4762 		 * MIB II kstat variables
4763 		 */
4764 		statsp->rbytes		= ldckp->rbytes64.value.ull;
4765 		statsp->obytes		= ldckp->obytes64.value.ull;
4766 		statsp->multircv	= ldckp->multircv.value.ul;
4767 		statsp->multixmt	= ldckp->multixmt.value.ul;
4768 		statsp->brdcstrcv	= ldckp->brdcstrcv.value.ul;
4769 		statsp->brdcstxmt	= ldckp->brdcstxmt.value.ul;
4770 		statsp->norcvbuf	= ldckp->norcvbuf.value.ul;
4771 		statsp->noxmtbuf	= ldckp->noxmtbuf.value.ul;
4772 
4773 		statsp->tx_no_desc	= ldckp->tx_no_desc.value.ul;
4774 
4775 		statsp->rx_allocb_fail	= ldckp->rx_allocb_fail.value.ul;
4776 		statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul;
4777 		statsp->rx_lost_pkts	= ldckp->rx_lost_pkts.value.ul;
4778 
4779 		statsp->callbacks	= ldckp->callbacks.value.ul;
4780 		statsp->dring_data_acks	= ldckp->dring_data_acks.value.ul;
4781 		statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul;
4782 		statsp->dring_data_msgs	= ldckp->dring_data_msgs.value.ul;
4783 	}
4784 
4785 	return (VGEN_SUCCESS);
4786 }
4787 
4788 /* handler for error messages received from the peer ldc end-point */
4789 static void
4790 vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4791 {
4792 	_NOTE(ARGUNUSED(ldcp, tagp))
4793 }
4794 
4795 /* Check if the session id in the received message is valid */
4796 static int
4797 vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4798 {
4799 	if (tagp->vio_sid != ldcp->peer_sid) {
4800 		void *vnetp = LDC_TO_VNET(ldcp);
4801 		DWARN((vnetp,
4802 		    "sid mismatch: expected(%x), rcvd(%x)\n",
4803 		    ldcp->peer_sid, tagp->vio_sid));
4804 		return (VGEN_FAILURE);
4805 	}
4806 	else
4807 		return (VGEN_SUCCESS);
4808 }
4809 
4810 /* convert mac address from string to uint64_t */
4811 static uint64_t
4812 vgen_macaddr_strtoul(const uint8_t *macaddr)
4813 {
4814 	uint64_t val = 0;
4815 	int i;
4816 
4817 	for (i = 0; i < ETHERADDRL; i++) {
4818 		val <<= 8;
4819 		val |= macaddr[i];
4820 	}
4821 
4822 	return (val);
4823 }
4824 
4825 /* convert mac address from uint64_t to string */
4826 static int
4827 vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
4828 {
4829 	int i;
4830 	uint64_t value;
4831 
4832 	value = val;
4833 	for (i = ETHERADDRL - 1; i >= 0; i--) {
4834 		macaddr[i] = value & 0xFF;
4835 		value >>= 8;
4836 	}
4837 	return (VGEN_SUCCESS);
4838 }
4839 
4840 static caddr_t
4841 vgen_print_ethaddr(uint8_t *a, char *ebuf)
4842 {
4843 	(void) sprintf(ebuf,
4844 		"%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
4845 	return (ebuf);
4846 }
4847 
4848 /* Handshake watchdog timeout handler */
4849 static void
4850 vgen_hwatchdog(void *arg)
4851 {
4852 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
4853 	void *vnetp = LDC_TO_VNET(ldcp);
4854 
4855 	DWARN((vnetp,
4856 	    "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
4857 	    ldcp->ldc_id, ldcp->hphase, ldcp->hstate));
4858 
4859 	mutex_enter(&ldcp->cblock);
4860 	ldcp->htid = 0;
4861 	vgen_handshake_retry(ldcp);
4862 	mutex_exit(&ldcp->cblock);
4863 }
4864 
4865 static void
4866 vgen_print_hparams(vgen_hparams_t *hp)
4867 {
4868 	uint8_t	addr[6];
4869 	char	ea[6];
4870 	ldc_mem_cookie_t *dc;
4871 
4872 	cmn_err(CE_CONT, "version_info:\n");
4873 	cmn_err(CE_CONT,
4874 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
4875 	    hp->ver_major, hp->ver_minor, hp->dev_class);
4876 
4877 	(void) vgen_macaddr_ultostr(hp->addr, addr);
4878 	cmn_err(CE_CONT, "attr_info:\n");
4879 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
4880 	    vgen_print_ethaddr(addr, ea));
4881 	cmn_err(CE_CONT,
4882 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
4883 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
4884 
4885 	dc = &hp->dring_cookie;
4886 	cmn_err(CE_CONT, "dring_info:\n");
4887 	cmn_err(CE_CONT,
4888 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
4889 	cmn_err(CE_CONT,
4890 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
4891 	    dc->addr, dc->size);
4892 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
4893 }
4894 
4895 static void
4896 vgen_print_ldcinfo(vgen_ldc_t *ldcp)
4897 {
4898 	vgen_hparams_t *hp;
4899 
4900 	cmn_err(CE_CONT, "Channel Information:\n");
4901 	cmn_err(CE_CONT,
4902 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
4903 	    ldcp->ldc_id, ldcp->ldc_status);
4904 	cmn_err(CE_CONT,
4905 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
4906 	    ldcp->local_sid, ldcp->peer_sid);
4907 	cmn_err(CE_CONT,
4908 	    "\thphase: 0x%x, hstate: 0x%x\n",
4909 	    ldcp->hphase, ldcp->hstate);
4910 
4911 	cmn_err(CE_CONT, "Local handshake params:\n");
4912 	hp = &ldcp->local_hparams;
4913 	vgen_print_hparams(hp);
4914 
4915 	cmn_err(CE_CONT, "Peer handshake params:\n");
4916 	hp = &ldcp->peer_hparams;
4917 	vgen_print_hparams(hp);
4918 }
4919