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