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