xref: /titanic_44/usr/src/uts/sun4v/io/vnet_gen.c (revision cf170fc06cee7b670cc5ccf1fe83dce33fb2592b)
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 2008 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/strsubr.h>
34 #include <sys/kmem.h>
35 #include <sys/conf.h>
36 #include <sys/devops.h>
37 #include <sys/ksynch.h>
38 #include <sys/stat.h>
39 #include <sys/modctl.h>
40 #include <sys/debug.h>
41 #include <sys/ethernet.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/strsun.h>
45 #include <sys/note.h>
46 #include <sys/mac.h>
47 #include <sys/mac_ether.h>
48 #include <sys/ldc.h>
49 #include <sys/mach_descrip.h>
50 #include <sys/mdeg.h>
51 #include <net/if.h>
52 #include <sys/vnet.h>
53 #include <sys/vio_mailbox.h>
54 #include <sys/vio_common.h>
55 #include <sys/vnet_common.h>
56 #include <sys/vnet_mailbox.h>
57 #include <sys/vio_util.h>
58 #include <sys/vnet_gen.h>
59 #include <sys/atomic.h>
60 #include <sys/callb.h>
61 #include <sys/sdt.h>
62 #include <sys/intr.h>
63 #include <sys/pattr.h>
64 #include <sys/vlan.h>
65 
66 /*
67  * Implementation of the mac functionality for vnet using the
68  * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
69  */
70 
71 /*
72  * Function prototypes.
73  */
74 /* vgen proxy entry points */
75 int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
76     const uint8_t *macaddr, void **vgenhdl);
77 int vgen_uninit(void *arg);
78 int vgen_dds_tx(void *arg, void *dmsg);
79 static int vgen_start(void *arg);
80 static void vgen_stop(void *arg);
81 static mblk_t *vgen_tx(void *arg, mblk_t *mp);
82 static int vgen_multicst(void *arg, boolean_t add,
83 	const uint8_t *mca);
84 static int vgen_promisc(void *arg, boolean_t on);
85 static int vgen_unicst(void *arg, const uint8_t *mca);
86 static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
87 static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp);
88 
89 /* vgen internal functions */
90 static int vgen_read_mdprops(vgen_t *vgenp);
91 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
92 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp,
93 	mde_cookie_t node);
94 static void vgen_detach_ports(vgen_t *vgenp);
95 static void vgen_port_detach(vgen_port_t *portp);
96 static void vgen_port_list_insert(vgen_port_t *portp);
97 static void vgen_port_list_remove(vgen_port_t *portp);
98 static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
99 	int port_num);
100 static int vgen_mdeg_reg(vgen_t *vgenp);
101 static void vgen_mdeg_unreg(vgen_t *vgenp);
102 static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
103 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
104 static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
105 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
106 	mde_cookie_t mdex);
107 static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
108 static int vgen_port_attach(vgen_port_t *portp);
109 static void vgen_port_detach_mdeg(vgen_port_t *portp);
110 static void vgen_port_detach_mdeg(vgen_port_t *portp);
111 static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
112 	mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
113 static uint64_t	vgen_port_stat(vgen_port_t *portp, uint_t stat);
114 
115 static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
116 static void vgen_ldc_detach(vgen_ldc_t *ldcp);
117 static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp);
118 static void vgen_free_tx_ring(vgen_ldc_t *ldcp);
119 static void vgen_init_ports(vgen_t *vgenp);
120 static void vgen_port_init(vgen_port_t *portp);
121 static void vgen_uninit_ports(vgen_t *vgenp);
122 static void vgen_port_uninit(vgen_port_t *portp);
123 static void vgen_init_ldcs(vgen_port_t *portp);
124 static void vgen_uninit_ldcs(vgen_port_t *portp);
125 static int vgen_ldc_init(vgen_ldc_t *ldcp);
126 static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
127 static int vgen_init_tbufs(vgen_ldc_t *ldcp);
128 static void vgen_uninit_tbufs(vgen_ldc_t *ldcp);
129 static void vgen_clobber_tbufs(vgen_ldc_t *ldcp);
130 static void vgen_clobber_rxds(vgen_ldc_t *ldcp);
131 static uint64_t	vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
132 static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
133 static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
134 static int vgen_ldcsend(void *arg, mblk_t *mp);
135 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp);
136 static int vgen_ldcsend_dring(void *arg, mblk_t *mp);
137 static void vgen_reclaim(vgen_ldc_t *ldcp);
138 static void vgen_reclaim_dring(vgen_ldc_t *ldcp);
139 static int vgen_num_txpending(vgen_ldc_t *ldcp);
140 static int vgen_tx_dring_full(vgen_ldc_t *ldcp);
141 static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp);
142 static void vgen_ldc_watchdog(void *arg);
143 
144 /* vgen handshake functions */
145 static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
146 static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
147 	boolean_t caller_holds_lock);
148 static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
149 static int vgen_send_attr_info(vgen_ldc_t *ldcp);
150 static int vgen_send_dring_reg(vgen_ldc_t *ldcp);
151 static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
152 static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
153 static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
154 static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
155 static void vgen_handshake_reset(vgen_ldc_t *ldcp);
156 static void vgen_reset_hphase(vgen_ldc_t *ldcp);
157 static void vgen_handshake(vgen_ldc_t *ldcp);
158 static int vgen_handshake_done(vgen_ldc_t *ldcp);
159 static void vgen_handshake_retry(vgen_ldc_t *ldcp);
160 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
161 	vio_msg_tag_t *tagp);
162 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
163 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
164 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
165 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
166 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
167 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen);
168 static void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
169 static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
170 static int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
171 static int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
172 static int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
173 static int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
174 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
175 	uint32_t start, int32_t end, uint8_t pstate);
176 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
177 	uint32_t msglen);
178 static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
179 static void vgen_handle_evt_up(vgen_ldc_t *ldcp);
180 static void vgen_handle_evt_reset(vgen_ldc_t *ldcp);
181 static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
182 static int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
183 static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf);
184 static void vgen_hwatchdog(void *arg);
185 static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint);
186 static void vgen_print_hparams(vgen_hparams_t *hp);
187 static void vgen_print_ldcinfo(vgen_ldc_t *ldcp);
188 static void vgen_stop_rcv_thread(vgen_ldc_t *ldcp);
189 static void vgen_ldc_rcv_worker(void *arg);
190 static void vgen_handle_evt_read(vgen_ldc_t *ldcp);
191 static void vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp);
192 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp);
193 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp);
194 
195 /* VLAN routines */
196 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp,
197 	mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp,
198 	uint16_t *nvidsp, uint16_t *default_idp);
199 static void vgen_vlan_create_hash(vgen_port_t *portp);
200 static void vgen_vlan_destroy_hash(vgen_port_t *portp);
201 static void vgen_vlan_add_ids(vgen_port_t *portp);
202 static void vgen_vlan_remove_ids(vgen_port_t *portp);
203 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
204 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp,
205 	uint16_t *vidp);
206 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp,
207 	boolean_t is_tagged, uint16_t vid);
208 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp);
209 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp);
210 static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
211 
212 /* externs */
213 extern void vnet_dds_rx(void *arg, void *dmsg);
214 
215 /*
216  * The handshake process consists of 5 phases defined below, with VH_PHASE0
217  * being the pre-handshake phase and VH_DONE is the phase to indicate
218  * successful completion of all phases.
219  * Each phase may have one to several handshake states which are required
220  * to complete successfully to move to the next phase.
221  * Refer to the functions vgen_handshake() and vgen_handshake_done() for
222  * more details.
223  */
224 /* handshake phases */
225 enum {	VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 };
226 
227 /* handshake states */
228 enum {
229 
230 	VER_INFO_SENT	=	0x1,
231 	VER_ACK_RCVD	=	0x2,
232 	VER_INFO_RCVD	=	0x4,
233 	VER_ACK_SENT	=	0x8,
234 	VER_NEGOTIATED	=	(VER_ACK_RCVD | VER_ACK_SENT),
235 
236 	ATTR_INFO_SENT	=	0x10,
237 	ATTR_ACK_RCVD	=	0x20,
238 	ATTR_INFO_RCVD	=	0x40,
239 	ATTR_ACK_SENT	=	0x80,
240 	ATTR_INFO_EXCHANGED	=	(ATTR_ACK_RCVD | ATTR_ACK_SENT),
241 
242 	DRING_INFO_SENT	=	0x100,
243 	DRING_ACK_RCVD	=	0x200,
244 	DRING_INFO_RCVD	=	0x400,
245 	DRING_ACK_SENT	=	0x800,
246 	DRING_INFO_EXCHANGED	=	(DRING_ACK_RCVD | DRING_ACK_SENT),
247 
248 	RDX_INFO_SENT	=	0x1000,
249 	RDX_ACK_RCVD	=	0x2000,
250 	RDX_INFO_RCVD	=	0x4000,
251 	RDX_ACK_SENT	=	0x8000,
252 	RDX_EXCHANGED	=	(RDX_ACK_RCVD | RDX_ACK_SENT)
253 
254 };
255 
256 #define	VGEN_PRI_ETH_DEFINED(vgenp)	((vgenp)->pri_num_types != 0)
257 
258 #define	LDC_LOCK(ldcp)	\
259 				mutex_enter(&((ldcp)->cblock));\
260 				mutex_enter(&((ldcp)->rxlock));\
261 				mutex_enter(&((ldcp)->wrlock));\
262 				mutex_enter(&((ldcp)->txlock));\
263 				mutex_enter(&((ldcp)->tclock));
264 #define	LDC_UNLOCK(ldcp)	\
265 				mutex_exit(&((ldcp)->tclock));\
266 				mutex_exit(&((ldcp)->txlock));\
267 				mutex_exit(&((ldcp)->wrlock));\
268 				mutex_exit(&((ldcp)->rxlock));\
269 				mutex_exit(&((ldcp)->cblock));
270 
271 #define	VGEN_VER_EQ(ldcp, major, minor)	\
272 	((ldcp)->local_hparams.ver_major == (major) &&	\
273 	    (ldcp)->local_hparams.ver_minor == (minor))
274 
275 #define	VGEN_VER_LT(ldcp, major, minor)	\
276 	(((ldcp)->local_hparams.ver_major < (major)) ||	\
277 	    ((ldcp)->local_hparams.ver_major == (major) &&	\
278 	    (ldcp)->local_hparams.ver_minor < (minor)))
279 
280 #define	VGEN_VER_GTEQ(ldcp, major, minor)	\
281 	(((ldcp)->local_hparams.ver_major > (major)) ||	\
282 	    ((ldcp)->local_hparams.ver_major == (major) &&	\
283 	    (ldcp)->local_hparams.ver_minor >= (minor)))
284 
285 static struct ether_addr etherbroadcastaddr = {
286 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
287 };
288 /*
289  * MIB II broadcast/multicast packets
290  */
291 #define	IS_BROADCAST(ehp) \
292 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
293 #define	IS_MULTICAST(ehp) \
294 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
295 
296 /*
297  * Property names
298  */
299 static char macaddr_propname[] = "mac-address";
300 static char rmacaddr_propname[] = "remote-mac-address";
301 static char channel_propname[] = "channel-endpoint";
302 static char reg_propname[] = "reg";
303 static char port_propname[] = "port";
304 static char swport_propname[] = "switch-port";
305 static char id_propname[] = "id";
306 static char vdev_propname[] = "virtual-device";
307 static char vnet_propname[] = "network";
308 static char pri_types_propname[] = "priority-ether-types";
309 static char vgen_pvid_propname[] = "port-vlan-id";
310 static char vgen_vid_propname[] = "vlan-id";
311 static char vgen_dvid_propname[] = "default-vlan-id";
312 static char port_pvid_propname[] = "remote-port-vlan-id";
313 static char port_vid_propname[] = "remote-vlan-id";
314 
315 /* versions supported - in decreasing order */
316 static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 3} };
317 
318 /* Tunables */
319 uint32_t vgen_hwd_interval = 5;		/* handshake watchdog freq in sec */
320 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */
321 uint32_t vgen_ldcwr_retries = 10;	/* max # of ldc_write() retries */
322 uint32_t vgen_ldcup_retries = 5;	/* max # of ldc_up() retries */
323 uint32_t vgen_recv_delay = 1;		/* delay when rx descr not ready */
324 uint32_t vgen_recv_retries = 10;	/* retry when rx descr not ready */
325 uint32_t vgen_tx_retries = 0x4;		/* retry when tx descr not available */
326 uint32_t vgen_tx_delay = 0x30;		/* delay when tx descr not available */
327 
328 int vgen_rcv_thread_enabled = 1;	/* Enable Recieve thread */
329 
330 /*
331  * max # of packets accumulated prior to sending them up. It is best
332  * to keep this at 60% of the number of recieve buffers.
333  */
334 uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6);
335 
336 /*
337  * Tunables for each receive buffer size and number of buffers for
338  * each buffer size.
339  */
340 uint32_t vgen_rbufsz1 = VGEN_DBLK_SZ_128;
341 uint32_t vgen_rbufsz2 = VGEN_DBLK_SZ_256;
342 uint32_t vgen_rbufsz3 = VGEN_DBLK_SZ_2048;
343 
344 uint32_t vgen_nrbufs1 = VGEN_NRBUFS;
345 uint32_t vgen_nrbufs2 = VGEN_NRBUFS;
346 uint32_t vgen_nrbufs3 = VGEN_NRBUFS;
347 
348 /*
349  * In the absence of "priority-ether-types" property in MD, the following
350  * internal tunable can be set to specify a single priority ethertype.
351  */
352 uint64_t vgen_pri_eth_type = 0;
353 
354 /*
355  * Number of transmit priority buffers that are preallocated per device.
356  * This number is chosen to be a small value to throttle transmission
357  * of priority packets. Note: Must be a power of 2 for vio_create_mblks().
358  */
359 uint32_t vgen_pri_tx_nmblks = 64;
360 
361 uint32_t	vgen_vlan_nchains = 4;	/* # of chains in vlan id hash table */
362 
363 #ifdef DEBUG
364 /* flags to simulate error conditions for debugging */
365 int vgen_trigger_txtimeout = 0;
366 int vgen_trigger_rxlost = 0;
367 #endif
368 
369 /*
370  * Matching criteria passed to the MDEG to register interest
371  * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified
372  * by their 'name' and 'cfg-handle' properties.
373  */
374 static md_prop_match_t vdev_prop_match[] = {
375 	{ MDET_PROP_STR,    "name"   },
376 	{ MDET_PROP_VAL,    "cfg-handle" },
377 	{ MDET_LIST_END,    NULL    }
378 };
379 
380 static mdeg_node_match_t vdev_match = { "virtual-device",
381 						vdev_prop_match };
382 
383 /* MD update matching structure */
384 static md_prop_match_t	vport_prop_match[] = {
385 	{ MDET_PROP_VAL,	"id" },
386 	{ MDET_LIST_END,	NULL }
387 };
388 
389 static mdeg_node_match_t vport_match = { "virtual-device-port",
390 					vport_prop_match };
391 
392 /* template for matching a particular vnet instance */
393 static mdeg_prop_spec_t vgen_prop_template[] = {
394 	{ MDET_PROP_STR,	"name",		"network" },
395 	{ MDET_PROP_VAL,	"cfg-handle",	NULL },
396 	{ MDET_LIST_END,	NULL,		NULL }
397 };
398 
399 #define	VGEN_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val)
400 
401 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
402 
403 static mac_callbacks_t vgen_m_callbacks = {
404 	0,
405 	vgen_stat,
406 	vgen_start,
407 	vgen_stop,
408 	vgen_promisc,
409 	vgen_multicst,
410 	vgen_unicst,
411 	vgen_tx,
412 	NULL,
413 	NULL,
414 	NULL
415 };
416 
417 /* externs */
418 extern pri_t	maxclsyspri;
419 extern proc_t	p0;
420 extern uint32_t vnet_ntxds;
421 extern uint32_t vnet_ldcwd_interval;
422 extern uint32_t vnet_ldcwd_txtimeout;
423 extern uint32_t vnet_ldc_mtu;
424 extern uint32_t vnet_nrbufs;
425 extern uint32_t	vnet_ethermtu;
426 extern uint16_t	vnet_default_vlan_id;
427 
428 #ifdef DEBUG
429 
430 extern int vnet_dbglevel;
431 static void debug_printf(const char *fname, vgen_t *vgenp,
432 	vgen_ldc_t *ldcp, const char *fmt, ...);
433 
434 /* -1 for all LDCs info, or ldc_id for a specific LDC info */
435 int vgendbg_ldcid = -1;
436 
437 /* simulate handshake error conditions for debug */
438 uint32_t vgen_hdbg;
439 #define	HDBG_VERSION	0x1
440 #define	HDBG_TIMEOUT	0x2
441 #define	HDBG_BAD_SID	0x4
442 #define	HDBG_OUT_STATE	0x8
443 
444 #endif
445 
446 /*
447  * vgen_init() is called by an instance of vnet driver to initialize the
448  * corresponding generic proxy transport layer. The arguments passed by vnet
449  * are - an opaque pointer to the vnet instance, pointers to dev_info_t and
450  * the mac address of the vnet device, and a pointer to vgen_t is passed
451  * back as a handle to vnet.
452  */
453 int
454 vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
455     const uint8_t *macaddr, void **vgenhdl)
456 {
457 	vgen_t *vgenp;
458 	int instance;
459 	int rv;
460 
461 	if ((vnetp == NULL) || (vnetdip == NULL))
462 		return (DDI_FAILURE);
463 
464 	instance = ddi_get_instance(vnetdip);
465 
466 	DBG1(NULL, NULL, "vnet(%d): enter\n", instance);
467 
468 	vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
469 
470 	vgenp->vnetp = vnetp;
471 	vgenp->instance = instance;
472 	vgenp->regprop = regprop;
473 	vgenp->vnetdip = vnetdip;
474 	bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
475 
476 	/* allocate multicast table */
477 	vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
478 	    sizeof (struct ether_addr), KM_SLEEP);
479 	vgenp->mccount = 0;
480 	vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
481 	vgenp->max_frame_size = vnet_ethermtu + sizeof (struct ether_header)
482 	    + VLAN_TAGSZ;
483 
484 	mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
485 	rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL);
486 
487 	rv = vgen_read_mdprops(vgenp);
488 	if (rv != 0) {
489 		goto vgen_init_fail;
490 	}
491 
492 	/* register with MD event generator */
493 	rv = vgen_mdeg_reg(vgenp);
494 	if (rv != DDI_SUCCESS) {
495 		goto vgen_init_fail;
496 	}
497 
498 	*vgenhdl = (void *)vgenp;
499 
500 	DBG1(NULL, NULL, "vnet(%d): exit\n", instance);
501 	return (DDI_SUCCESS);
502 
503 vgen_init_fail:
504 	rw_destroy(&vgenp->vgenports.rwlock);
505 	mutex_destroy(&vgenp->lock);
506 	kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
507 	    sizeof (struct ether_addr));
508 	if (VGEN_PRI_ETH_DEFINED(vgenp)) {
509 		kmem_free(vgenp->pri_types,
510 		    sizeof (uint16_t) * vgenp->pri_num_types);
511 		(void) vio_destroy_mblks(vgenp->pri_tx_vmp);
512 	}
513 	KMEM_FREE(vgenp);
514 	return (DDI_FAILURE);
515 }
516 
517 /*
518  * Called by vnet to undo the initializations done by vgen_init().
519  * The handle provided by generic transport during vgen_init() is the argument.
520  */
521 int
522 vgen_uninit(void *arg)
523 {
524 	vgen_t		*vgenp = (vgen_t *)arg;
525 	vio_mblk_pool_t	*rp;
526 	vio_mblk_pool_t	*nrp;
527 
528 	if (vgenp == NULL) {
529 		return (DDI_FAILURE);
530 	}
531 
532 	DBG1(vgenp, NULL, "enter\n");
533 
534 	/* unregister with MD event generator */
535 	vgen_mdeg_unreg(vgenp);
536 
537 	mutex_enter(&vgenp->lock);
538 
539 	/* detach all ports from the device */
540 	vgen_detach_ports(vgenp);
541 
542 	/*
543 	 * free any pending rx mblk pools,
544 	 * that couldn't be freed previously during channel detach.
545 	 */
546 	rp = vgenp->rmp;
547 	while (rp != NULL) {
548 		nrp = vgenp->rmp = rp->nextp;
549 		if (vio_destroy_mblks(rp)) {
550 			vgenp->rmp = rp;
551 			mutex_exit(&vgenp->lock);
552 			return (DDI_FAILURE);
553 		}
554 		rp = nrp;
555 	}
556 
557 	/* free multicast table */
558 	kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
559 
560 	/* free pri_types table */
561 	if (VGEN_PRI_ETH_DEFINED(vgenp)) {
562 		kmem_free(vgenp->pri_types,
563 		    sizeof (uint16_t) * vgenp->pri_num_types);
564 		(void) vio_destroy_mblks(vgenp->pri_tx_vmp);
565 	}
566 
567 	mutex_exit(&vgenp->lock);
568 
569 	rw_destroy(&vgenp->vgenports.rwlock);
570 	mutex_destroy(&vgenp->lock);
571 
572 	KMEM_FREE(vgenp);
573 
574 	DBG1(vgenp, NULL, "exit\n");
575 
576 	return (DDI_SUCCESS);
577 }
578 
579 /* enable transmit/receive for the device */
580 int
581 vgen_start(void *arg)
582 {
583 	vgen_port_t	*portp = (vgen_port_t *)arg;
584 	vgen_t		*vgenp = portp->vgenp;
585 
586 	DBG1(vgenp, NULL, "enter\n");
587 	mutex_enter(&portp->lock);
588 	vgen_port_init(portp);
589 	portp->flags |= VGEN_STARTED;
590 	mutex_exit(&portp->lock);
591 	DBG1(vgenp, NULL, "exit\n");
592 
593 	return (DDI_SUCCESS);
594 }
595 
596 /* stop transmit/receive */
597 void
598 vgen_stop(void *arg)
599 {
600 	vgen_port_t	*portp = (vgen_port_t *)arg;
601 	vgen_t		*vgenp = portp->vgenp;
602 
603 	DBG1(vgenp, NULL, "enter\n");
604 
605 	mutex_enter(&portp->lock);
606 	vgen_port_uninit(portp);
607 	portp->flags &= ~(VGEN_STARTED);
608 	mutex_exit(&portp->lock);
609 	DBG1(vgenp, NULL, "exit\n");
610 
611 }
612 
613 /* vgen transmit function */
614 static mblk_t *
615 vgen_tx(void *arg, mblk_t *mp)
616 {
617 	int i;
618 	vgen_port_t *portp;
619 	int status = VGEN_FAILURE;
620 
621 	portp = (vgen_port_t *)arg;
622 	/*
623 	 * Retry so that we avoid reporting a failure
624 	 * to the upper layer. Returning a failure may cause the
625 	 * upper layer to go into single threaded mode there by
626 	 * causing performance degradation, especially for a large
627 	 * number of connections.
628 	 */
629 	for (i = 0; i < vgen_tx_retries; ) {
630 		status = vgen_portsend(portp, mp);
631 		if (status == VGEN_SUCCESS) {
632 			break;
633 		}
634 		if (++i < vgen_tx_retries)
635 			delay(drv_usectohz(vgen_tx_delay));
636 	}
637 	if (status != VGEN_SUCCESS) {
638 		/* failure */
639 		return (mp);
640 	}
641 	/* success */
642 	return (NULL);
643 }
644 
645 /*
646  * This function provides any necessary tagging/untagging of the frames
647  * that are being transmitted over the port. It first verifies the vlan
648  * membership of the destination(port) and drops the packet if the
649  * destination doesn't belong to the given vlan.
650  *
651  * Arguments:
652  *   portp:     port over which the frames should be transmitted
653  *   mp:        frame to be transmitted
654  *   is_tagged:
655  *              B_TRUE: indicates frame header contains the vlan tag already.
656  *              B_FALSE: indicates frame is untagged.
657  *   vid:       vlan in which the frame should be transmitted.
658  *
659  * Returns:
660  *              Sucess: frame(mblk_t *) after doing the necessary tag/untag.
661  *              Failure: NULL
662  */
663 static mblk_t *
664 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged,
665 	uint16_t vid)
666 {
667 	vgen_t				*vgenp;
668 	boolean_t			dst_tagged;
669 	int				rv;
670 
671 	vgenp = portp->vgenp;
672 
673 	/*
674 	 * If the packet is going to a vnet:
675 	 *   Check if the destination vnet is in the same vlan.
676 	 *   Check the frame header if tag or untag is needed.
677 	 *
678 	 * We do not check the above conditions if the packet is going to vsw:
679 	 *   vsw must be present implicitly in all the vlans that a vnet device
680 	 *   is configured into; even if vsw itself is not assigned to those
681 	 *   vlans as an interface. For instance, the packet might be destined
682 	 *   to another vnet(indirectly through vsw) or to an external host
683 	 *   which is in the same vlan as this vnet and vsw itself may not be
684 	 *   present in that vlan. Similarly packets going to vsw must be
685 	 *   always tagged(unless in the default-vlan) if not already tagged,
686 	 *   as we do not know the final destination. This is needed because
687 	 *   vsw must always invoke its switching function only after tagging
688 	 *   the packet; otherwise after switching function determines the
689 	 *   destination we cannot figure out if the destination belongs to the
690 	 *   the same vlan that the frame originated from and if it needs tag/
691 	 *   untag. Note that vsw will tag the packet itself when it receives
692 	 *   it over the channel from a client if needed. However, that is
693 	 *   needed only in the case of vlan unaware clients such as obp or
694 	 *   earlier versions of vnet.
695 	 *
696 	 */
697 	if (portp != vgenp->vsw_portp) {
698 		/*
699 		 * Packet going to a vnet. Check if the destination vnet is in
700 		 * the same vlan. Then check the frame header if tag/untag is
701 		 * needed.
702 		 */
703 		rv = vgen_vlan_lookup(portp->vlan_hashp, vid);
704 		if (rv == B_FALSE) {
705 			/* drop the packet */
706 			freemsg(mp);
707 			return (NULL);
708 		}
709 
710 		/* is the destination tagged or untagged in this vlan? */
711 		(vid == portp->pvid) ? (dst_tagged = B_FALSE) :
712 		    (dst_tagged = B_TRUE);
713 
714 		if (is_tagged == dst_tagged) {
715 			/* no tagging/untagging needed */
716 			return (mp);
717 		}
718 
719 		if (is_tagged == B_TRUE) {
720 			/* frame is tagged; destination needs untagged */
721 			mp = vnet_vlan_remove_tag(mp);
722 			return (mp);
723 		}
724 
725 		/* (is_tagged == B_FALSE): fallthru to tag tx packet: */
726 	}
727 
728 	/*
729 	 * Packet going to a vnet needs tagging.
730 	 * OR
731 	 * If the packet is going to vsw, then it must be tagged in all cases:
732 	 * unknown unicast, broadcast/multicast or to vsw interface.
733 	 */
734 
735 	if (is_tagged == B_FALSE) {
736 		mp = vnet_vlan_insert_tag(mp, vid);
737 	}
738 
739 	return (mp);
740 }
741 
742 /* transmit packets over the given port */
743 static int
744 vgen_portsend(vgen_port_t *portp, mblk_t *mp)
745 {
746 	vgen_ldclist_t		*ldclp;
747 	vgen_ldc_t		*ldcp;
748 	int			status;
749 	int			rv = VGEN_SUCCESS;
750 	vgen_t			*vgenp = portp->vgenp;
751 	vnet_t			*vnetp = vgenp->vnetp;
752 	boolean_t		is_tagged;
753 	boolean_t		dec_refcnt = B_FALSE;
754 	uint16_t		vlan_id;
755 	struct ether_header	*ehp;
756 
757 	if (portp->use_vsw_port) {
758 		(void) atomic_inc_32(&vgenp->vsw_port_refcnt);
759 		portp = portp->vgenp->vsw_portp;
760 		dec_refcnt = B_TRUE;
761 	}
762 	if (portp == NULL) {
763 		return (VGEN_FAILURE);
764 	}
765 
766 	/*
767 	 * Determine the vlan id that the frame belongs to.
768 	 */
769 	ehp = (struct ether_header *)mp->b_rptr;
770 	is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id);
771 
772 	if (vlan_id == vnetp->default_vlan_id) {
773 
774 		/* Frames in default vlan must be untagged */
775 		ASSERT(is_tagged == B_FALSE);
776 
777 		/*
778 		 * If the destination is a vnet-port verify it belongs to the
779 		 * default vlan; otherwise drop the packet. We do not need
780 		 * this check for vsw-port, as it should implicitly belong to
781 		 * this vlan; see comments in vgen_vlan_frame_fixtag().
782 		 */
783 		if (portp != vgenp->vsw_portp &&
784 		    portp->pvid != vnetp->default_vlan_id) {
785 			freemsg(mp);
786 			goto portsend_ret;
787 		}
788 
789 	} else {	/* frame not in default-vlan */
790 
791 		mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id);
792 		if (mp == NULL) {
793 			goto portsend_ret;
794 		}
795 
796 	}
797 
798 	ldclp = &portp->ldclist;
799 	READ_ENTER(&ldclp->rwlock);
800 	/*
801 	 * NOTE: for now, we will assume we have a single channel.
802 	 */
803 	if (ldclp->headp == NULL) {
804 		RW_EXIT(&ldclp->rwlock);
805 		rv = VGEN_FAILURE;
806 		goto portsend_ret;
807 	}
808 	ldcp = ldclp->headp;
809 
810 	status = ldcp->tx(ldcp, mp);
811 
812 	RW_EXIT(&ldclp->rwlock);
813 
814 	if (status != VGEN_TX_SUCCESS) {
815 		rv = VGEN_FAILURE;
816 	}
817 
818 portsend_ret:
819 	if (dec_refcnt == B_TRUE) {
820 		(void) atomic_dec_32(&vgenp->vsw_port_refcnt);
821 	}
822 	return (rv);
823 }
824 
825 /*
826  * Wrapper function to transmit normal and/or priority frames over the channel.
827  */
828 static int
829 vgen_ldcsend(void *arg, mblk_t *mp)
830 {
831 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg;
832 	int			status;
833 	struct ether_header	*ehp;
834 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
835 	uint32_t		num_types;
836 	uint16_t		*types;
837 	int			i;
838 
839 	ASSERT(VGEN_PRI_ETH_DEFINED(vgenp));
840 
841 	num_types = vgenp->pri_num_types;
842 	types = vgenp->pri_types;
843 	ehp = (struct ether_header *)mp->b_rptr;
844 
845 	for (i = 0; i < num_types; i++) {
846 
847 		if (ehp->ether_type == types[i]) {
848 			/* priority frame, use pri tx function */
849 			vgen_ldcsend_pkt(ldcp, mp);
850 			return (VGEN_SUCCESS);
851 		}
852 
853 	}
854 
855 	status  = vgen_ldcsend_dring(ldcp, mp);
856 
857 	return (status);
858 }
859 
860 /*
861  * This functions handles ldc channel reset while in the context
862  * of transmit routines: vgen_ldcsend_pkt() or vgen_ldcsend_dring().
863  */
864 static void
865 vgen_ldcsend_process_reset(vgen_ldc_t *ldcp)
866 {
867 	ldc_status_t	istatus;
868 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
869 
870 	if (mutex_tryenter(&ldcp->cblock)) {
871 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
872 			DWARN(vgenp, ldcp, "ldc_status() error\n");
873 		} else {
874 			ldcp->ldc_status = istatus;
875 		}
876 		if (ldcp->ldc_status != LDC_UP) {
877 			vgen_handle_evt_reset(ldcp);
878 		}
879 		mutex_exit(&ldcp->cblock);
880 	}
881 }
882 
883 /*
884  * This function transmits the frame in the payload of a raw data
885  * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
886  * send special frames with high priorities, without going through
887  * the normal data path which uses descriptor ring mechanism.
888  */
889 static void
890 vgen_ldcsend_pkt(void *arg, mblk_t *mp)
891 {
892 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg;
893 	vio_raw_data_msg_t	*pkt;
894 	mblk_t			*bp;
895 	mblk_t			*nmp = NULL;
896 	caddr_t			dst;
897 	uint32_t		mblksz;
898 	uint32_t		size;
899 	uint32_t		nbytes;
900 	int			rv;
901 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
902 	vgen_stats_t		*statsp = &ldcp->stats;
903 
904 	/* drop the packet if ldc is not up or handshake is not done */
905 	if (ldcp->ldc_status != LDC_UP) {
906 		(void) atomic_inc_32(&statsp->tx_pri_fail);
907 		DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
908 		    ldcp->ldc_status);
909 		goto send_pkt_exit;
910 	}
911 
912 	if (ldcp->hphase != VH_DONE) {
913 		(void) atomic_inc_32(&statsp->tx_pri_fail);
914 		DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
915 		    ldcp->hphase);
916 		goto send_pkt_exit;
917 	}
918 
919 	size = msgsize(mp);
920 
921 	/* frame size bigger than available payload len of raw data msg ? */
922 	if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
923 		(void) atomic_inc_32(&statsp->tx_pri_fail);
924 		DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
925 		goto send_pkt_exit;
926 	}
927 
928 	if (size < ETHERMIN)
929 		size = ETHERMIN;
930 
931 	/* alloc space for a raw data message */
932 	nmp = vio_allocb(vgenp->pri_tx_vmp);
933 	if (nmp == NULL) {
934 		(void) atomic_inc_32(&statsp->tx_pri_fail);
935 		DWARN(vgenp, ldcp, "vio_allocb failed\n");
936 		goto send_pkt_exit;
937 	}
938 	pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
939 
940 	/* copy frame into the payload of raw data message */
941 	dst = (caddr_t)pkt->data;
942 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
943 		mblksz = MBLKL(bp);
944 		bcopy(bp->b_rptr, dst, mblksz);
945 		dst += mblksz;
946 	}
947 
948 	/* setup the raw data msg */
949 	pkt->tag.vio_msgtype = VIO_TYPE_DATA;
950 	pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
951 	pkt->tag.vio_subtype_env = VIO_PKT_DATA;
952 	pkt->tag.vio_sid = ldcp->local_sid;
953 	nbytes = VIO_PKT_DATA_HDRSIZE + size;
954 
955 	/* send the msg over ldc */
956 	rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE);
957 	if (rv != VGEN_SUCCESS) {
958 		(void) atomic_inc_32(&statsp->tx_pri_fail);
959 		DWARN(vgenp, ldcp, "Error sending priority frame\n");
960 		if (rv == ECONNRESET) {
961 			vgen_ldcsend_process_reset(ldcp);
962 		}
963 		goto send_pkt_exit;
964 	}
965 
966 	/* update stats */
967 	(void) atomic_inc_64(&statsp->tx_pri_packets);
968 	(void) atomic_add_64(&statsp->tx_pri_bytes, size);
969 
970 send_pkt_exit:
971 	if (nmp != NULL)
972 		freemsg(nmp);
973 	freemsg(mp);
974 }
975 
976 /*
977  * This function transmits normal (non-priority) data frames over
978  * the channel. It queues the frame into the transmit descriptor ring
979  * and sends a VIO_DRING_DATA message if needed, to wake up the
980  * peer to (re)start processing.
981  */
982 static int
983 vgen_ldcsend_dring(void *arg, mblk_t *mp)
984 {
985 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg;
986 	vgen_private_desc_t	*tbufp;
987 	vgen_private_desc_t	*rtbufp;
988 	vnet_public_desc_t	*rtxdp;
989 	vgen_private_desc_t	*ntbufp;
990 	vnet_public_desc_t	*txdp;
991 	vio_dring_entry_hdr_t	*hdrp;
992 	vgen_stats_t		*statsp;
993 	struct ether_header	*ehp;
994 	boolean_t		is_bcast = B_FALSE;
995 	boolean_t		is_mcast = B_FALSE;
996 	size_t			mblksz;
997 	caddr_t			dst;
998 	mblk_t			*bp;
999 	size_t			size;
1000 	int			rv = 0;
1001 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
1002 	vgen_hparams_t		*lp = &ldcp->local_hparams;
1003 
1004 	statsp = &ldcp->stats;
1005 	size = msgsize(mp);
1006 
1007 	DBG1(vgenp, ldcp, "enter\n");
1008 
1009 	if (ldcp->ldc_status != LDC_UP) {
1010 		DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
1011 		    ldcp->ldc_status);
1012 		/* retry ldc_up() if needed */
1013 		if (ldcp->flags & CHANNEL_STARTED)
1014 			(void) ldc_up(ldcp->ldc_handle);
1015 		goto send_dring_exit;
1016 	}
1017 
1018 	/* drop the packet if ldc is not up or handshake is not done */
1019 	if (ldcp->hphase != VH_DONE) {
1020 		DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
1021 		    ldcp->hphase);
1022 		goto send_dring_exit;
1023 	}
1024 
1025 	if (size > (size_t)lp->mtu) {
1026 		DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
1027 		goto send_dring_exit;
1028 	}
1029 	if (size < ETHERMIN)
1030 		size = ETHERMIN;
1031 
1032 	ehp = (struct ether_header *)mp->b_rptr;
1033 	is_bcast = IS_BROADCAST(ehp);
1034 	is_mcast = IS_MULTICAST(ehp);
1035 
1036 	mutex_enter(&ldcp->txlock);
1037 	/*
1038 	 * allocate a descriptor
1039 	 */
1040 	tbufp = ldcp->next_tbufp;
1041 	ntbufp = NEXTTBUF(ldcp, tbufp);
1042 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
1043 
1044 		mutex_enter(&ldcp->tclock);
1045 		/* Try reclaiming now */
1046 		vgen_reclaim_dring(ldcp);
1047 		ldcp->reclaim_lbolt = ddi_get_lbolt();
1048 
1049 		if (ntbufp == ldcp->cur_tbufp) {
1050 			/* Now we are really out of tbuf/txds */
1051 			ldcp->need_resched = B_TRUE;
1052 			mutex_exit(&ldcp->tclock);
1053 
1054 			statsp->tx_no_desc++;
1055 			mutex_exit(&ldcp->txlock);
1056 
1057 			return (VGEN_TX_NORESOURCES);
1058 		}
1059 		mutex_exit(&ldcp->tclock);
1060 	}
1061 	/* update next available tbuf in the ring and update tx index */
1062 	ldcp->next_tbufp = ntbufp;
1063 	INCR_TXI(ldcp->next_txi, ldcp);
1064 
1065 	/* Mark the buffer busy before releasing the lock */
1066 	tbufp->flags = VGEN_PRIV_DESC_BUSY;
1067 	mutex_exit(&ldcp->txlock);
1068 
1069 	/* copy data into pre-allocated transmit buffer */
1070 	dst = tbufp->datap + VNET_IPALIGN;
1071 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
1072 		mblksz = MBLKL(bp);
1073 		bcopy(bp->b_rptr, dst, mblksz);
1074 		dst += mblksz;
1075 	}
1076 
1077 	tbufp->datalen = size;
1078 
1079 	/* initialize the corresponding public descriptor (txd) */
1080 	txdp = tbufp->descp;
1081 	hdrp = &txdp->hdr;
1082 	txdp->nbytes = size;
1083 	txdp->ncookies = tbufp->ncookies;
1084 	bcopy((tbufp->memcookie), (txdp->memcookie),
1085 	    tbufp->ncookies * sizeof (ldc_mem_cookie_t));
1086 
1087 	mutex_enter(&ldcp->wrlock);
1088 	/*
1089 	 * If the flags not set to BUSY, it implies that the clobber
1090 	 * was done while we were copying the data. In such case,
1091 	 * discard the packet and return.
1092 	 */
1093 	if (tbufp->flags != VGEN_PRIV_DESC_BUSY) {
1094 		statsp->oerrors++;
1095 		mutex_exit(&ldcp->wrlock);
1096 		goto send_dring_exit;
1097 	}
1098 	hdrp->dstate = VIO_DESC_READY;
1099 
1100 	/* update stats */
1101 	statsp->opackets++;
1102 	statsp->obytes += size;
1103 	if (is_bcast)
1104 		statsp->brdcstxmt++;
1105 	else if (is_mcast)
1106 		statsp->multixmt++;
1107 
1108 	/* send dring datamsg to the peer */
1109 	if (ldcp->resched_peer) {
1110 
1111 		rtbufp = &ldcp->tbufp[ldcp->resched_peer_txi];
1112 		rtxdp = rtbufp->descp;
1113 
1114 		if (rtxdp->hdr.dstate == VIO_DESC_READY) {
1115 
1116 			rv = vgen_send_dring_data(ldcp,
1117 			    (uint32_t)ldcp->resched_peer_txi, -1);
1118 			if (rv != 0) {
1119 				/* error: drop the packet */
1120 				DWARN(vgenp, ldcp, "vgen_send_dring_data "
1121 				    "failed: rv(%d) len(%d)\n",
1122 				    ldcp->ldc_id, rv, size);
1123 				statsp->oerrors++;
1124 			} else {
1125 				ldcp->resched_peer = B_FALSE;
1126 			}
1127 
1128 		}
1129 
1130 	}
1131 
1132 	mutex_exit(&ldcp->wrlock);
1133 
1134 send_dring_exit:
1135 	if (rv == ECONNRESET) {
1136 		vgen_ldcsend_process_reset(ldcp);
1137 	}
1138 	freemsg(mp);
1139 	DBG1(vgenp, ldcp, "exit\n");
1140 	return (VGEN_TX_SUCCESS);
1141 }
1142 
1143 /* enable/disable a multicast address */
1144 int
1145 vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
1146 {
1147 	vgen_t			*vgenp;
1148 	vnet_mcast_msg_t	mcastmsg;
1149 	vio_msg_tag_t		*tagp;
1150 	vgen_port_t		*portp;
1151 	vgen_portlist_t		*plistp;
1152 	vgen_ldc_t		*ldcp;
1153 	vgen_ldclist_t		*ldclp;
1154 	struct ether_addr	*addrp;
1155 	int			rv = DDI_FAILURE;
1156 	uint32_t		i;
1157 
1158 	portp = (vgen_port_t *)arg;
1159 	vgenp = portp->vgenp;
1160 
1161 	if (portp != vgenp->vsw_portp) {
1162 		return (DDI_SUCCESS);
1163 	}
1164 
1165 	addrp = (struct ether_addr *)mca;
1166 	tagp = &mcastmsg.tag;
1167 	bzero(&mcastmsg, sizeof (mcastmsg));
1168 
1169 	mutex_enter(&vgenp->lock);
1170 
1171 	plistp = &(vgenp->vgenports);
1172 
1173 	READ_ENTER(&plistp->rwlock);
1174 
1175 	portp = vgenp->vsw_portp;
1176 	if (portp == NULL) {
1177 		RW_EXIT(&plistp->rwlock);
1178 		mutex_exit(&vgenp->lock);
1179 		return (rv);
1180 	}
1181 	ldclp = &portp->ldclist;
1182 
1183 	READ_ENTER(&ldclp->rwlock);
1184 
1185 	ldcp = ldclp->headp;
1186 	if (ldcp == NULL)
1187 		goto vgen_mcast_exit;
1188 
1189 	mutex_enter(&ldcp->cblock);
1190 
1191 	if (ldcp->hphase == VH_DONE) {
1192 		/*
1193 		 * If handshake is done, send a msg to vsw to add/remove
1194 		 * the multicast address. Otherwise, we just update this
1195 		 * mcast address in our table and the table will be sync'd
1196 		 * with vsw when handshake completes.
1197 		 */
1198 		tagp->vio_msgtype = VIO_TYPE_CTRL;
1199 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
1200 		tagp->vio_subtype_env = VNET_MCAST_INFO;
1201 		tagp->vio_sid = ldcp->local_sid;
1202 		bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
1203 		mcastmsg.set = add;
1204 		mcastmsg.count = 1;
1205 		if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
1206 		    B_FALSE) != VGEN_SUCCESS) {
1207 			DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
1208 			mutex_exit(&ldcp->cblock);
1209 			goto vgen_mcast_exit;
1210 		}
1211 	}
1212 
1213 	mutex_exit(&ldcp->cblock);
1214 
1215 	if (add) {
1216 
1217 		/* expand multicast table if necessary */
1218 		if (vgenp->mccount >= vgenp->mcsize) {
1219 			struct ether_addr	*newtab;
1220 			uint32_t		newsize;
1221 
1222 
1223 			newsize = vgenp->mcsize * 2;
1224 
1225 			newtab = kmem_zalloc(newsize *
1226 			    sizeof (struct ether_addr), KM_NOSLEEP);
1227 			if (newtab == NULL)
1228 				goto vgen_mcast_exit;
1229 			bcopy(vgenp->mctab, newtab, vgenp->mcsize *
1230 			    sizeof (struct ether_addr));
1231 			kmem_free(vgenp->mctab,
1232 			    vgenp->mcsize * sizeof (struct ether_addr));
1233 
1234 			vgenp->mctab = newtab;
1235 			vgenp->mcsize = newsize;
1236 		}
1237 
1238 		/* add address to the table */
1239 		vgenp->mctab[vgenp->mccount++] = *addrp;
1240 
1241 	} else {
1242 
1243 		/* delete address from the table */
1244 		for (i = 0; i < vgenp->mccount; i++) {
1245 			if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
1246 
1247 				/*
1248 				 * If there's more than one address in this
1249 				 * table, delete the unwanted one by moving
1250 				 * the last one in the list over top of it;
1251 				 * otherwise, just remove it.
1252 				 */
1253 				if (vgenp->mccount > 1) {
1254 					vgenp->mctab[i] =
1255 					    vgenp->mctab[vgenp->mccount-1];
1256 				}
1257 				vgenp->mccount--;
1258 				break;
1259 			}
1260 		}
1261 	}
1262 
1263 	rv = DDI_SUCCESS;
1264 
1265 vgen_mcast_exit:
1266 	RW_EXIT(&ldclp->rwlock);
1267 	RW_EXIT(&plistp->rwlock);
1268 
1269 	mutex_exit(&vgenp->lock);
1270 	return (rv);
1271 }
1272 
1273 /* set or clear promiscuous mode on the device */
1274 static int
1275 vgen_promisc(void *arg, boolean_t on)
1276 {
1277 	_NOTE(ARGUNUSED(arg, on))
1278 	return (DDI_SUCCESS);
1279 }
1280 
1281 /* set the unicast mac address of the device */
1282 static int
1283 vgen_unicst(void *arg, const uint8_t *mca)
1284 {
1285 	_NOTE(ARGUNUSED(arg, mca))
1286 	return (DDI_SUCCESS);
1287 }
1288 
1289 /* get device statistics */
1290 int
1291 vgen_stat(void *arg, uint_t stat, uint64_t *val)
1292 {
1293 	vgen_port_t	*portp = (vgen_port_t *)arg;
1294 
1295 	*val = vgen_port_stat(portp, stat);
1296 
1297 	return (0);
1298 }
1299 
1300 static void
1301 vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1302 {
1303 	 _NOTE(ARGUNUSED(arg, wq, mp))
1304 }
1305 
1306 /* vgen internal functions */
1307 /* detach all ports from the device */
1308 static void
1309 vgen_detach_ports(vgen_t *vgenp)
1310 {
1311 	vgen_port_t	*portp;
1312 	vgen_portlist_t	*plistp;
1313 
1314 	plistp = &(vgenp->vgenports);
1315 	WRITE_ENTER(&plistp->rwlock);
1316 
1317 	while ((portp = plistp->headp) != NULL) {
1318 		vgen_port_detach(portp);
1319 	}
1320 
1321 	RW_EXIT(&plistp->rwlock);
1322 }
1323 
1324 /*
1325  * detach the given port.
1326  */
1327 static void
1328 vgen_port_detach(vgen_port_t *portp)
1329 {
1330 	vgen_t		*vgenp;
1331 	vgen_ldclist_t	*ldclp;
1332 	int		port_num;
1333 
1334 	vgenp = portp->vgenp;
1335 	port_num = portp->port_num;
1336 
1337 	DBG1(vgenp, NULL, "port(%d):enter\n", port_num);
1338 
1339 	/*
1340 	 * If this port is connected to the vswitch, then
1341 	 * potentially there could be ports that may be using
1342 	 * this port to transmit packets. To address this do
1343 	 * the following:
1344 	 *	- First set vgenp->vsw_portp to NULL, so that
1345 	 *	  its not used after that.
1346 	 *	- Then wait for the refcnt to go down to 0.
1347 	 *	- Now we can safely detach this port.
1348 	 */
1349 	if (vgenp->vsw_portp == portp) {
1350 		vgenp->vsw_portp = NULL;
1351 		while (vgenp->vsw_port_refcnt > 0) {
1352 			delay(drv_usectohz(vgen_tx_delay));
1353 		}
1354 		(void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
1355 	}
1356 
1357 	if (portp->vhp != NULL) {
1358 		vio_net_resource_unreg(portp->vhp);
1359 		portp->vhp = NULL;
1360 	}
1361 
1362 	vgen_vlan_destroy_hash(portp);
1363 
1364 	/* remove it from port list */
1365 	vgen_port_list_remove(portp);
1366 
1367 	/* detach channels from this port */
1368 	ldclp = &portp->ldclist;
1369 	WRITE_ENTER(&ldclp->rwlock);
1370 	while (ldclp->headp) {
1371 		vgen_ldc_detach(ldclp->headp);
1372 	}
1373 	RW_EXIT(&ldclp->rwlock);
1374 	rw_destroy(&ldclp->rwlock);
1375 
1376 	if (portp->num_ldcs != 0) {
1377 		kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t));
1378 		portp->num_ldcs = 0;
1379 	}
1380 
1381 	mutex_destroy(&portp->lock);
1382 	KMEM_FREE(portp);
1383 
1384 	DBG1(vgenp, NULL, "port(%d):exit\n", port_num);
1385 }
1386 
1387 /* add a port to port list */
1388 static void
1389 vgen_port_list_insert(vgen_port_t *portp)
1390 {
1391 	vgen_portlist_t *plistp;
1392 	vgen_t *vgenp;
1393 
1394 	vgenp = portp->vgenp;
1395 	plistp = &(vgenp->vgenports);
1396 
1397 	if (plistp->headp == NULL) {
1398 		plistp->headp = portp;
1399 	} else {
1400 		plistp->tailp->nextp = portp;
1401 	}
1402 	plistp->tailp = portp;
1403 	portp->nextp = NULL;
1404 }
1405 
1406 /* remove a port from port list */
1407 static void
1408 vgen_port_list_remove(vgen_port_t *portp)
1409 {
1410 	vgen_port_t *prevp;
1411 	vgen_port_t *nextp;
1412 	vgen_portlist_t *plistp;
1413 	vgen_t *vgenp;
1414 
1415 	vgenp = portp->vgenp;
1416 
1417 	plistp = &(vgenp->vgenports);
1418 
1419 	if (plistp->headp == NULL)
1420 		return;
1421 
1422 	if (portp == plistp->headp) {
1423 		plistp->headp = portp->nextp;
1424 		if (portp == plistp->tailp)
1425 			plistp->tailp = plistp->headp;
1426 	} else {
1427 		for (prevp = plistp->headp;
1428 		    ((nextp = prevp->nextp) != NULL) && (nextp != portp);
1429 		    prevp = nextp)
1430 			;
1431 		if (nextp == portp) {
1432 			prevp->nextp = portp->nextp;
1433 		}
1434 		if (portp == plistp->tailp)
1435 			plistp->tailp = prevp;
1436 	}
1437 }
1438 
1439 /* lookup a port in the list based on port_num */
1440 static vgen_port_t *
1441 vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
1442 {
1443 	vgen_port_t *portp = NULL;
1444 
1445 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1446 		if (portp->port_num == port_num) {
1447 			break;
1448 		}
1449 	}
1450 
1451 	return (portp);
1452 }
1453 
1454 /* enable ports for transmit/receive */
1455 static void
1456 vgen_init_ports(vgen_t *vgenp)
1457 {
1458 	vgen_port_t	*portp;
1459 	vgen_portlist_t	*plistp;
1460 
1461 	plistp = &(vgenp->vgenports);
1462 	READ_ENTER(&plistp->rwlock);
1463 
1464 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1465 		vgen_port_init(portp);
1466 	}
1467 
1468 	RW_EXIT(&plistp->rwlock);
1469 }
1470 
1471 static void
1472 vgen_port_init(vgen_port_t *portp)
1473 {
1474 	/* Add the port to the specified vlans */
1475 	vgen_vlan_add_ids(portp);
1476 
1477 	/* Bring up the channels of this port */
1478 	vgen_init_ldcs(portp);
1479 }
1480 
1481 /* disable transmit/receive on ports */
1482 static void
1483 vgen_uninit_ports(vgen_t *vgenp)
1484 {
1485 	vgen_port_t	*portp;
1486 	vgen_portlist_t	*plistp;
1487 
1488 	plistp = &(vgenp->vgenports);
1489 	READ_ENTER(&plistp->rwlock);
1490 
1491 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
1492 		vgen_port_uninit(portp);
1493 	}
1494 
1495 	RW_EXIT(&plistp->rwlock);
1496 }
1497 
1498 static void
1499 vgen_port_uninit(vgen_port_t *portp)
1500 {
1501 	vgen_uninit_ldcs(portp);
1502 
1503 	/* remove the port from vlans it has been assigned to */
1504 	vgen_vlan_remove_ids(portp);
1505 }
1506 
1507 /*
1508  * Scan the machine description for this instance of vnet
1509  * and read its properties. Called only from vgen_init().
1510  * Returns: 0 on success, 1 on failure.
1511  */
1512 static int
1513 vgen_read_mdprops(vgen_t *vgenp)
1514 {
1515 	vnet_t		*vnetp = vgenp->vnetp;
1516 	md_t		*mdp = NULL;
1517 	mde_cookie_t	rootnode;
1518 	mde_cookie_t	*listp = NULL;
1519 	uint64_t	cfgh;
1520 	char		*name;
1521 	int		rv = 1;
1522 	int		num_nodes = 0;
1523 	int		num_devs = 0;
1524 	int		listsz = 0;
1525 	int		i;
1526 
1527 	if ((mdp = md_get_handle()) == NULL) {
1528 		return (rv);
1529 	}
1530 
1531 	num_nodes = md_node_count(mdp);
1532 	ASSERT(num_nodes > 0);
1533 
1534 	listsz = num_nodes * sizeof (mde_cookie_t);
1535 	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
1536 
1537 	rootnode = md_root_node(mdp);
1538 
1539 	/* search for all "virtual_device" nodes */
1540 	num_devs = md_scan_dag(mdp, rootnode,
1541 	    md_find_name(mdp, vdev_propname),
1542 	    md_find_name(mdp, "fwd"), listp);
1543 	if (num_devs <= 0) {
1544 		goto vgen_readmd_exit;
1545 	}
1546 
1547 	/*
1548 	 * Now loop through the list of virtual-devices looking for
1549 	 * devices with name "network" and for each such device compare
1550 	 * its instance with what we have from the 'reg' property to
1551 	 * find the right node in MD and then read all its properties.
1552 	 */
1553 	for (i = 0; i < num_devs; i++) {
1554 
1555 		if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) {
1556 			goto vgen_readmd_exit;
1557 		}
1558 
1559 		/* is this a "network" device? */
1560 		if (strcmp(name, vnet_propname) != 0)
1561 			continue;
1562 
1563 		if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) {
1564 			goto vgen_readmd_exit;
1565 		}
1566 
1567 		/* is this the required instance of vnet? */
1568 		if (vgenp->regprop != cfgh)
1569 			continue;
1570 
1571 		/* now read all properties of this vnet instance */
1572 		vgen_read_pri_eth_types(vgenp, mdp, listp[i]);
1573 
1574 		/* read vlan id properties of this vnet instance */
1575 		vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i],
1576 		    &vnetp->pvid, &vnetp->vids, &vnetp->nvids,
1577 		    &vnetp->default_vlan_id);
1578 
1579 		rv = 0;
1580 		break;
1581 	}
1582 
1583 vgen_readmd_exit:
1584 
1585 	kmem_free(listp, listsz);
1586 	(void) md_fini_handle(mdp);
1587 	return (rv);
1588 }
1589 
1590 /*
1591  * Read vlan id properties of the given MD node.
1592  * Arguments:
1593  *   arg:          device argument(vnet device or a port)
1594  *   type:         type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port)
1595  *   mdp:          machine description
1596  *   node:         md node cookie
1597  *
1598  * Returns:
1599  *   pvidp:        port-vlan-id of the node
1600  *   vidspp:       list of vlan-ids of the node
1601  *   nvidsp:       # of vlan-ids in the list
1602  *   default_idp:  default-vlan-id of the node(if node is vnet device)
1603  */
1604 static void
1605 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node,
1606 	uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp,
1607 	uint16_t *default_idp)
1608 {
1609 	vgen_t		*vgenp;
1610 	vnet_t		*vnetp;
1611 	vgen_port_t	*portp;
1612 	char		*pvid_propname;
1613 	char		*vid_propname;
1614 	uint_t		nvids;
1615 	uint32_t	vids_size;
1616 	int		rv;
1617 	int		i;
1618 	uint64_t	*data;
1619 	uint64_t	val;
1620 	int		size;
1621 	int		inst;
1622 
1623 	if (type == VGEN_LOCAL) {
1624 
1625 		vgenp = (vgen_t *)arg;
1626 		vnetp = vgenp->vnetp;
1627 		pvid_propname = vgen_pvid_propname;
1628 		vid_propname = vgen_vid_propname;
1629 		inst = vnetp->instance;
1630 
1631 	} else if (type == VGEN_PEER) {
1632 
1633 		portp = (vgen_port_t *)arg;
1634 		vgenp = portp->vgenp;
1635 		vnetp = vgenp->vnetp;
1636 		pvid_propname = port_pvid_propname;
1637 		vid_propname = port_vid_propname;
1638 		inst = portp->port_num;
1639 
1640 	} else {
1641 		return;
1642 	}
1643 
1644 	if (type == VGEN_LOCAL && default_idp != NULL) {
1645 		rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val);
1646 		if (rv != 0) {
1647 			DWARN(vgenp, NULL, "prop(%s) not found",
1648 			    vgen_dvid_propname);
1649 
1650 			*default_idp = vnet_default_vlan_id;
1651 		} else {
1652 			*default_idp = val & 0xFFF;
1653 			DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname,
1654 			    inst, *default_idp);
1655 		}
1656 	}
1657 
1658 	rv = md_get_prop_val(mdp, node, pvid_propname, &val);
1659 	if (rv != 0) {
1660 		DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname);
1661 		*pvidp = vnet_default_vlan_id;
1662 	} else {
1663 
1664 		*pvidp = val & 0xFFF;
1665 		DBG2(vgenp, NULL, "%s(%d): (%d)\n",
1666 		    pvid_propname, inst, *pvidp);
1667 	}
1668 
1669 	rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data,
1670 	    &size);
1671 	if (rv != 0) {
1672 		DBG2(vgenp, NULL, "prop(%s) not found", vid_propname);
1673 		size = 0;
1674 	} else {
1675 		size /= sizeof (uint64_t);
1676 	}
1677 	nvids = size;
1678 
1679 	if (nvids != 0) {
1680 		DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst);
1681 		vids_size = sizeof (uint16_t) * nvids;
1682 		*vidspp = kmem_zalloc(vids_size, KM_SLEEP);
1683 		for (i = 0; i < nvids; i++) {
1684 			(*vidspp)[i] = data[i] & 0xFFFF;
1685 			DBG2(vgenp, NULL, " %d ", (*vidspp)[i]);
1686 		}
1687 		DBG2(vgenp, NULL, "\n");
1688 	}
1689 
1690 	*nvidsp = nvids;
1691 }
1692 
1693 /*
1694  * Create a vlan id hash table for the given port.
1695  */
1696 static void
1697 vgen_vlan_create_hash(vgen_port_t *portp)
1698 {
1699 	char		hashname[MAXNAMELEN];
1700 
1701 	(void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
1702 	    portp->port_num);
1703 
1704 	portp->vlan_nchains = vgen_vlan_nchains;
1705 	portp->vlan_hashp = mod_hash_create_idhash(hashname,
1706 	    portp->vlan_nchains, mod_hash_null_valdtor);
1707 }
1708 
1709 /*
1710  * Destroy the vlan id hash table in the given port.
1711  */
1712 static void
1713 vgen_vlan_destroy_hash(vgen_port_t *portp)
1714 {
1715 	if (portp->vlan_hashp != NULL) {
1716 		mod_hash_destroy_hash(portp->vlan_hashp);
1717 		portp->vlan_hashp = NULL;
1718 		portp->vlan_nchains = 0;
1719 	}
1720 }
1721 
1722 /*
1723  * Add a port to the vlans specified in its port properites.
1724  */
1725 static void
1726 vgen_vlan_add_ids(vgen_port_t *portp)
1727 {
1728 	int		rv;
1729 	int		i;
1730 
1731 	rv = mod_hash_insert(portp->vlan_hashp,
1732 	    (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
1733 	    (mod_hash_val_t)B_TRUE);
1734 	ASSERT(rv == 0);
1735 
1736 	for (i = 0; i < portp->nvids; i++) {
1737 		rv = mod_hash_insert(portp->vlan_hashp,
1738 		    (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
1739 		    (mod_hash_val_t)B_TRUE);
1740 		ASSERT(rv == 0);
1741 	}
1742 }
1743 
1744 /*
1745  * Remove a port from the vlans it has been assigned to.
1746  */
1747 static void
1748 vgen_vlan_remove_ids(vgen_port_t *portp)
1749 {
1750 	int		rv;
1751 	int		i;
1752 	mod_hash_val_t	vp;
1753 
1754 	rv = mod_hash_remove(portp->vlan_hashp,
1755 	    (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
1756 	    (mod_hash_val_t *)&vp);
1757 	ASSERT(rv == 0);
1758 
1759 	for (i = 0; i < portp->nvids; i++) {
1760 		rv = mod_hash_remove(portp->vlan_hashp,
1761 		    (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
1762 		    (mod_hash_val_t *)&vp);
1763 		ASSERT(rv == 0);
1764 	}
1765 }
1766 
1767 /*
1768  * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame,
1769  * then the vlan-id is available in the tag; otherwise, its vlan id is
1770  * implicitly obtained from the port-vlan-id of the vnet device.
1771  * The vlan id determined is returned in vidp.
1772  * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
1773  */
1774 static boolean_t
1775 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp)
1776 {
1777 	struct ether_vlan_header	*evhp;
1778 
1779 	/* If it's a tagged frame, get the vlan id from vlan header */
1780 	if (ehp->ether_type == ETHERTYPE_VLAN) {
1781 
1782 		evhp = (struct ether_vlan_header *)ehp;
1783 		*vidp = VLAN_ID(ntohs(evhp->ether_tci));
1784 		return (B_TRUE);
1785 	}
1786 
1787 	/* Untagged frame, vlan-id is the pvid of vnet device */
1788 	*vidp = vnetp->pvid;
1789 	return (B_FALSE);
1790 }
1791 
1792 /*
1793  * Find the given vlan id in the hash table.
1794  * Return: B_TRUE if the id is found; B_FALSE if not found.
1795  */
1796 static boolean_t
1797 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
1798 {
1799 	int		rv;
1800 	mod_hash_val_t	vp;
1801 
1802 	rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
1803 
1804 	if (rv != 0)
1805 		return (B_FALSE);
1806 
1807 	return (B_TRUE);
1808 }
1809 
1810 /*
1811  * This function reads "priority-ether-types" property from md. This property
1812  * is used to enable support for priority frames. Applications which need
1813  * guaranteed and timely delivery of certain high priority frames to/from
1814  * a vnet or vsw within ldoms, should configure this property by providing
1815  * the ether type(s) for which the priority facility is needed.
1816  * Normal data frames are delivered over a ldc channel using the descriptor
1817  * ring mechanism which is constrained by factors such as descriptor ring size,
1818  * the rate at which the ring is processed at the peer ldc end point, etc.
1819  * The priority mechanism provides an Out-Of-Band path to send/receive frames
1820  * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the
1821  * descriptor ring path and enables a more reliable and timely delivery of
1822  * frames to the peer.
1823  */
1824 static void
1825 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node)
1826 {
1827 	int		rv;
1828 	uint16_t	*types;
1829 	uint64_t	*data;
1830 	int		size;
1831 	int		i;
1832 	size_t		mblk_sz;
1833 
1834 	rv = md_get_prop_data(mdp, node, pri_types_propname,
1835 	    (uint8_t **)&data, &size);
1836 	if (rv != 0) {
1837 		/*
1838 		 * Property may not exist if we are running pre-ldoms1.1 f/w.
1839 		 * Check if 'vgen_pri_eth_type' has been set in that case.
1840 		 */
1841 		if (vgen_pri_eth_type != 0) {
1842 			size = sizeof (vgen_pri_eth_type);
1843 			data = &vgen_pri_eth_type;
1844 		} else {
1845 			DBG2(vgenp, NULL,
1846 			    "prop(%s) not found", pri_types_propname);
1847 			size = 0;
1848 		}
1849 	}
1850 
1851 	if (size == 0) {
1852 		vgenp->pri_num_types = 0;
1853 		return;
1854 	}
1855 
1856 	/*
1857 	 * we have some priority-ether-types defined;
1858 	 * allocate a table of these types and also
1859 	 * allocate a pool of mblks to transmit these
1860 	 * priority packets.
1861 	 */
1862 	size /= sizeof (uint64_t);
1863 	vgenp->pri_num_types = size;
1864 	vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP);
1865 	for (i = 0, types = vgenp->pri_types; i < size; i++) {
1866 		types[i] = data[i] & 0xFFFF;
1867 	}
1868 	mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7;
1869 	(void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz,
1870 	    &vgenp->pri_tx_vmp);
1871 }
1872 
1873 /* register with MD event generator */
1874 static int
1875 vgen_mdeg_reg(vgen_t *vgenp)
1876 {
1877 	mdeg_prop_spec_t	*pspecp;
1878 	mdeg_node_spec_t	*parentp;
1879 	uint_t			templatesz;
1880 	int			rv;
1881 	mdeg_handle_t		dev_hdl = NULL;
1882 	mdeg_handle_t		port_hdl = NULL;
1883 
1884 	templatesz = sizeof (vgen_prop_template);
1885 	pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
1886 	if (pspecp == NULL) {
1887 		return (DDI_FAILURE);
1888 	}
1889 	parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
1890 	if (parentp == NULL) {
1891 		kmem_free(pspecp, templatesz);
1892 		return (DDI_FAILURE);
1893 	}
1894 
1895 	bcopy(vgen_prop_template, pspecp, templatesz);
1896 
1897 	/*
1898 	 * NOTE: The instance here refers to the value of "reg" property and
1899 	 * not the dev_info instance (ddi_get_instance()) of vnet.
1900 	 */
1901 	VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop);
1902 
1903 	parentp->namep = "virtual-device";
1904 	parentp->specp = pspecp;
1905 
1906 	/* save parentp in vgen_t */
1907 	vgenp->mdeg_parentp = parentp;
1908 
1909 	/*
1910 	 * Register an interest in 'virtual-device' nodes with a
1911 	 * 'name' property of 'network'
1912 	 */
1913 	rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl);
1914 	if (rv != MDEG_SUCCESS) {
1915 		DERR(vgenp, NULL, "mdeg_register failed\n");
1916 		goto mdeg_reg_fail;
1917 	}
1918 
1919 	/* Register an interest in 'port' nodes */
1920 	rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp,
1921 	    &port_hdl);
1922 	if (rv != MDEG_SUCCESS) {
1923 		DERR(vgenp, NULL, "mdeg_register failed\n");
1924 		goto mdeg_reg_fail;
1925 	}
1926 
1927 	/* save mdeg handle in vgen_t */
1928 	vgenp->mdeg_dev_hdl = dev_hdl;
1929 	vgenp->mdeg_port_hdl = port_hdl;
1930 
1931 	return (DDI_SUCCESS);
1932 
1933 mdeg_reg_fail:
1934 	if (dev_hdl != NULL) {
1935 		(void) mdeg_unregister(dev_hdl);
1936 	}
1937 	KMEM_FREE(parentp);
1938 	kmem_free(pspecp, templatesz);
1939 	vgenp->mdeg_parentp = NULL;
1940 	return (DDI_FAILURE);
1941 }
1942 
1943 /* unregister with MD event generator */
1944 static void
1945 vgen_mdeg_unreg(vgen_t *vgenp)
1946 {
1947 	(void) mdeg_unregister(vgenp->mdeg_dev_hdl);
1948 	(void) mdeg_unregister(vgenp->mdeg_port_hdl);
1949 	kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template));
1950 	KMEM_FREE(vgenp->mdeg_parentp);
1951 	vgenp->mdeg_parentp = NULL;
1952 	vgenp->mdeg_dev_hdl = NULL;
1953 	vgenp->mdeg_port_hdl = NULL;
1954 }
1955 
1956 /* mdeg callback function for the port node */
1957 static int
1958 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp)
1959 {
1960 	int idx;
1961 	int vsw_idx = -1;
1962 	uint64_t val;
1963 	vgen_t *vgenp;
1964 
1965 	if ((resp == NULL) || (cb_argp == NULL)) {
1966 		return (MDEG_FAILURE);
1967 	}
1968 
1969 	vgenp = (vgen_t *)cb_argp;
1970 	DBG1(vgenp, NULL, "enter\n");
1971 
1972 	mutex_enter(&vgenp->lock);
1973 
1974 	DBG1(vgenp, NULL, "ports: removed(%x), "
1975 	"added(%x), updated(%x)\n", resp->removed.nelem,
1976 	    resp->added.nelem, resp->match_curr.nelem);
1977 
1978 	for (idx = 0; idx < resp->removed.nelem; idx++) {
1979 		(void) vgen_remove_port(vgenp, resp->removed.mdp,
1980 		    resp->removed.mdep[idx]);
1981 	}
1982 
1983 	if (vgenp->vsw_portp == NULL) {
1984 		/*
1985 		 * find vsw_port and add it first, because other ports need
1986 		 * this when adding fdb entry (see vgen_port_init()).
1987 		 */
1988 		for (idx = 0; idx < resp->added.nelem; idx++) {
1989 			if (!(md_get_prop_val(resp->added.mdp,
1990 			    resp->added.mdep[idx], swport_propname, &val))) {
1991 				if (val == 0) {
1992 					/*
1993 					 * This port is connected to the
1994 					 * vsw on service domain.
1995 					 */
1996 					vsw_idx = idx;
1997 					if (vgen_add_port(vgenp,
1998 					    resp->added.mdp,
1999 					    resp->added.mdep[idx]) !=
2000 					    DDI_SUCCESS) {
2001 						cmn_err(CE_NOTE, "vnet%d Could "
2002 						    "not initialize virtual "
2003 						    "switch port.",
2004 						    vgenp->instance);
2005 						mutex_exit(&vgenp->lock);
2006 						return (MDEG_FAILURE);
2007 					}
2008 					break;
2009 				}
2010 			}
2011 		}
2012 		if (vsw_idx == -1) {
2013 			DWARN(vgenp, NULL, "can't find vsw_port\n");
2014 			mutex_exit(&vgenp->lock);
2015 			return (MDEG_FAILURE);
2016 		}
2017 	}
2018 
2019 	for (idx = 0; idx < resp->added.nelem; idx++) {
2020 		if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
2021 			continue;
2022 
2023 		/* If this port can't be added just skip it. */
2024 		(void) vgen_add_port(vgenp, resp->added.mdp,
2025 		    resp->added.mdep[idx]);
2026 	}
2027 
2028 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
2029 		(void) vgen_update_port(vgenp, resp->match_curr.mdp,
2030 		    resp->match_curr.mdep[idx],
2031 		    resp->match_prev.mdp,
2032 		    resp->match_prev.mdep[idx]);
2033 	}
2034 
2035 	mutex_exit(&vgenp->lock);
2036 	DBG1(vgenp, NULL, "exit\n");
2037 	return (MDEG_SUCCESS);
2038 }
2039 
2040 /* mdeg callback function for the vnet node */
2041 static int
2042 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
2043 {
2044 	vgen_t		*vgenp;
2045 	vnet_t		*vnetp;
2046 	md_t		*mdp;
2047 	mde_cookie_t	node;
2048 	uint64_t	inst;
2049 	char		*node_name = NULL;
2050 
2051 	if ((resp == NULL) || (cb_argp == NULL)) {
2052 		return (MDEG_FAILURE);
2053 	}
2054 
2055 	vgenp = (vgen_t *)cb_argp;
2056 	vnetp = vgenp->vnetp;
2057 
2058 	DBG1(vgenp, NULL, "%s: added %d : removed %d : curr matched %d"
2059 	    " : prev matched %d", resp->added.nelem, resp->removed.nelem,
2060 	    resp->match_curr.nelem, resp->match_prev.nelem);
2061 
2062 	mutex_enter(&vgenp->lock);
2063 
2064 	/*
2065 	 * We get an initial callback for this node as 'added' after
2066 	 * registering with mdeg. Note that we would have already gathered
2067 	 * information about this vnet node by walking MD earlier during attach
2068 	 * (in vgen_read_mdprops()). So, there is a window where the properties
2069 	 * of this node might have changed when we get this initial 'added'
2070 	 * callback. We handle this as if an update occured and invoke the same
2071 	 * function which handles updates to the properties of this vnet-node
2072 	 * if any. A non-zero 'match' value indicates that the MD has been
2073 	 * updated and that a 'network' node is present which may or may not
2074 	 * have been updated. It is up to the clients to examine their own
2075 	 * nodes and determine if they have changed.
2076 	 */
2077 	if (resp->added.nelem != 0) {
2078 
2079 		if (resp->added.nelem != 1) {
2080 			cmn_err(CE_NOTE, "!vnet%d: number of nodes added "
2081 			    "invalid: %d\n", vnetp->instance,
2082 			    resp->added.nelem);
2083 			goto vgen_mdeg_cb_err;
2084 		}
2085 
2086 		mdp = resp->added.mdp;
2087 		node = resp->added.mdep[0];
2088 
2089 	} else if (resp->match_curr.nelem != 0) {
2090 
2091 		if (resp->match_curr.nelem != 1) {
2092 			cmn_err(CE_NOTE, "!vnet%d: number of nodes updated "
2093 			    "invalid: %d\n", vnetp->instance,
2094 			    resp->match_curr.nelem);
2095 			goto vgen_mdeg_cb_err;
2096 		}
2097 
2098 		mdp = resp->match_curr.mdp;
2099 		node = resp->match_curr.mdep[0];
2100 
2101 	} else {
2102 		goto vgen_mdeg_cb_err;
2103 	}
2104 
2105 	/* Validate name and instance */
2106 	if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
2107 		DERR(vgenp, NULL, "unable to get node name\n");
2108 		goto vgen_mdeg_cb_err;
2109 	}
2110 
2111 	/* is this a virtual-network device? */
2112 	if (strcmp(node_name, vnet_propname) != 0) {
2113 		DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name);
2114 		goto vgen_mdeg_cb_err;
2115 	}
2116 
2117 	if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
2118 		DERR(vgenp, NULL, "prop(cfg-handle) not found\n");
2119 		goto vgen_mdeg_cb_err;
2120 	}
2121 
2122 	/* is this the right instance of vnet? */
2123 	if (inst != vgenp->regprop) {
2124 		DERR(vgenp, NULL,  "Invalid cfg-handle: %lx\n", inst);
2125 		goto vgen_mdeg_cb_err;
2126 	}
2127 
2128 	vgen_update_md_prop(vgenp, mdp, node);
2129 
2130 	mutex_exit(&vgenp->lock);
2131 	return (MDEG_SUCCESS);
2132 
2133 vgen_mdeg_cb_err:
2134 	mutex_exit(&vgenp->lock);
2135 	return (MDEG_FAILURE);
2136 }
2137 
2138 /*
2139  * Check to see if the relevant properties in the specified node have
2140  * changed, and if so take the appropriate action.
2141  */
2142 static void
2143 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
2144 {
2145 	uint16_t	pvid;
2146 	uint16_t	*vids;
2147 	uint16_t	nvids;
2148 	vnet_t		*vnetp = vgenp->vnetp;
2149 	boolean_t	updated_vlans = B_FALSE;
2150 
2151 	/* Read the vlan ids */
2152 	vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids,
2153 	    &nvids, NULL);
2154 
2155 	/* Determine if there are any vlan id updates */
2156 	if ((pvid != vnetp->pvid) ||		/* pvid changed? */
2157 	    (nvids != vnetp->nvids) ||		/* # of vids changed? */
2158 	    ((nvids != 0) && (vnetp->nvids != 0) &&	/* vids changed? */
2159 	    bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) {
2160 		updated_vlans = B_TRUE;
2161 	}
2162 
2163 	if (updated_vlans == B_FALSE) {
2164 		if (nvids != 0) {
2165 			kmem_free(vids, sizeof (uint16_t) * nvids);
2166 		}
2167 		return;
2168 	}
2169 
2170 	/* save the new vlan ids */
2171 	vnetp->pvid = pvid;
2172 	if (vnetp->nvids != 0) {
2173 		kmem_free(vnetp->vids, sizeof (uint16_t) * vnetp->nvids);
2174 		vnetp->nvids = 0;
2175 	}
2176 	if (nvids != 0) {
2177 		vnetp->nvids = nvids;
2178 		vnetp->vids = vids;
2179 	}
2180 
2181 	/* reset vlan-unaware peers (ver < 1.3) and restart handshake */
2182 	vgen_reset_vlan_unaware_ports(vgenp);
2183 }
2184 
2185 /* add a new port to the device */
2186 static int
2187 vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
2188 {
2189 	vgen_port_t	*portp;
2190 	int		rv;
2191 
2192 	portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP);
2193 
2194 	rv = vgen_port_read_props(portp, vgenp, mdp, mdex);
2195 	if (rv != DDI_SUCCESS) {
2196 		KMEM_FREE(portp);
2197 		return (DDI_FAILURE);
2198 	}
2199 
2200 	rv = vgen_port_attach(portp);
2201 	if (rv != DDI_SUCCESS) {
2202 		return (DDI_FAILURE);
2203 	}
2204 
2205 	return (DDI_SUCCESS);
2206 }
2207 
2208 /* read properties of the port from its md node */
2209 static int
2210 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
2211 	mde_cookie_t mdex)
2212 {
2213 	uint64_t		port_num;
2214 	uint64_t		*ldc_ids;
2215 	uint64_t		macaddr;
2216 	uint64_t		val;
2217 	int			num_ldcs;
2218 	int			i;
2219 	int			addrsz;
2220 	int			num_nodes = 0;
2221 	int			listsz = 0;
2222 	mde_cookie_t		*listp = NULL;
2223 	uint8_t			*addrp;
2224 	struct ether_addr	ea;
2225 
2226 	/* read "id" property to get the port number */
2227 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
2228 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2229 		return (DDI_FAILURE);
2230 	}
2231 
2232 	/*
2233 	 * Find the channel endpoint node(s) under this port node.
2234 	 */
2235 	if ((num_nodes = md_node_count(mdp)) <= 0) {
2236 		DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
2237 		    num_nodes);
2238 		return (DDI_FAILURE);
2239 	}
2240 
2241 	/* allocate space for node list */
2242 	listsz = num_nodes * sizeof (mde_cookie_t);
2243 	listp = kmem_zalloc(listsz, KM_NOSLEEP);
2244 	if (listp == NULL)
2245 		return (DDI_FAILURE);
2246 
2247 	num_ldcs = md_scan_dag(mdp, mdex,
2248 	    md_find_name(mdp, channel_propname),
2249 	    md_find_name(mdp, "fwd"), listp);
2250 
2251 	if (num_ldcs <= 0) {
2252 		DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
2253 		kmem_free(listp, listsz);
2254 		return (DDI_FAILURE);
2255 	}
2256 
2257 	DBG2(vgenp, NULL, "num_ldcs %d", num_ldcs);
2258 
2259 	ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
2260 	if (ldc_ids == NULL) {
2261 		kmem_free(listp, listsz);
2262 		return (DDI_FAILURE);
2263 	}
2264 
2265 	for (i = 0; i < num_ldcs; i++) {
2266 		/* read channel ids */
2267 		if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
2268 			DWARN(vgenp, NULL, "prop(%s) not found\n",
2269 			    id_propname);
2270 			kmem_free(listp, listsz);
2271 			kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
2272 			return (DDI_FAILURE);
2273 		}
2274 		DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]);
2275 	}
2276 
2277 	kmem_free(listp, listsz);
2278 
2279 	if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
2280 	    &addrsz)) {
2281 		DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
2282 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
2283 		return (DDI_FAILURE);
2284 	}
2285 
2286 	if (addrsz < ETHERADDRL) {
2287 		DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
2288 		kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
2289 		return (DDI_FAILURE);
2290 	}
2291 
2292 	macaddr = *((uint64_t *)addrp);
2293 
2294 	DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
2295 
2296 	for (i = ETHERADDRL - 1; i >= 0; i--) {
2297 		ea.ether_addr_octet[i] = macaddr & 0xFF;
2298 		macaddr >>= 8;
2299 	}
2300 
2301 	if (vgenp->vsw_portp == NULL) {
2302 		if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
2303 			if (val == 0) {
2304 				(void) atomic_swap_32(
2305 				    &vgenp->vsw_port_refcnt, 0);
2306 				/* This port is connected to the vsw */
2307 				vgenp->vsw_portp = portp;
2308 			}
2309 		}
2310 	}
2311 
2312 	/* now update all properties into the port */
2313 	portp->vgenp = vgenp;
2314 	portp->port_num = port_num;
2315 	ether_copy(&ea, &portp->macaddr);
2316 	portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP);
2317 	bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs);
2318 	portp->num_ldcs = num_ldcs;
2319 
2320 	/* read vlan id properties of this port node */
2321 	vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid,
2322 	    &portp->vids, &portp->nvids, NULL);
2323 
2324 	kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
2325 
2326 	return (DDI_SUCCESS);
2327 }
2328 
2329 /* remove a port from the device */
2330 static int
2331 vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
2332 {
2333 	uint64_t	port_num;
2334 	vgen_port_t	*portp;
2335 	vgen_portlist_t	*plistp;
2336 
2337 	/* read "id" property to get the port number */
2338 	if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
2339 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2340 		return (DDI_FAILURE);
2341 	}
2342 
2343 	plistp = &(vgenp->vgenports);
2344 
2345 	WRITE_ENTER(&plistp->rwlock);
2346 	portp = vgen_port_lookup(plistp, (int)port_num);
2347 	if (portp == NULL) {
2348 		DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
2349 		RW_EXIT(&plistp->rwlock);
2350 		return (DDI_FAILURE);
2351 	}
2352 
2353 	vgen_port_detach_mdeg(portp);
2354 	RW_EXIT(&plistp->rwlock);
2355 
2356 	return (DDI_SUCCESS);
2357 }
2358 
2359 /* attach a port to the device based on mdeg data */
2360 static int
2361 vgen_port_attach(vgen_port_t *portp)
2362 {
2363 	int			i;
2364 	vgen_portlist_t		*plistp;
2365 	vgen_t			*vgenp;
2366 	uint64_t		*ldcids;
2367 	uint32_t		num_ldcs;
2368 	mac_register_t		*macp;
2369 	vio_net_res_type_t	type;
2370 	int			rv;
2371 
2372 	ASSERT(portp != NULL);
2373 
2374 	vgenp = portp->vgenp;
2375 	ldcids = portp->ldc_ids;
2376 	num_ldcs = portp->num_ldcs;
2377 
2378 	DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num);
2379 
2380 	mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL);
2381 	rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL);
2382 	portp->ldclist.headp = NULL;
2383 
2384 	for (i = 0; i < num_ldcs; i++) {
2385 		DBG2(vgenp, NULL, "ldcid (%lx)\n", ldcids[i]);
2386 		if (vgen_ldc_attach(portp, ldcids[i]) == DDI_FAILURE) {
2387 			vgen_port_detach(portp);
2388 			return (DDI_FAILURE);
2389 		}
2390 	}
2391 
2392 	/* create vlan id hash table */
2393 	vgen_vlan_create_hash(portp);
2394 
2395 	if (portp == vgenp->vsw_portp) {
2396 		/* This port is connected to the switch port */
2397 		vgenp->vsw_portp = portp;
2398 		(void) atomic_swap_32(&portp->use_vsw_port, B_FALSE);
2399 		type = VIO_NET_RES_LDC_SERVICE;
2400 	} else {
2401 		(void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
2402 		type = VIO_NET_RES_LDC_GUEST;
2403 	}
2404 
2405 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
2406 		vgen_port_detach(portp);
2407 		return (DDI_FAILURE);
2408 	}
2409 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2410 	macp->m_driver = portp;
2411 	macp->m_dip = vgenp->vnetdip;
2412 	macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
2413 	macp->m_callbacks = &vgen_m_callbacks;
2414 	macp->m_min_sdu = 0;
2415 	macp->m_max_sdu = ETHERMTU;
2416 
2417 	mutex_enter(&portp->lock);
2418 	rv = vio_net_resource_reg(macp, type, vgenp->macaddr,
2419 	    portp->macaddr, &portp->vhp, &portp->vcb);
2420 	mutex_exit(&portp->lock);
2421 	mac_free(macp);
2422 
2423 	if (rv == 0) {
2424 		/* link it into the list of ports */
2425 		plistp = &(vgenp->vgenports);
2426 		WRITE_ENTER(&plistp->rwlock);
2427 		vgen_port_list_insert(portp);
2428 		RW_EXIT(&plistp->rwlock);
2429 	} else {
2430 		DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p",
2431 		    portp);
2432 		vgen_port_detach(portp);
2433 	}
2434 
2435 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
2436 	return (DDI_SUCCESS);
2437 }
2438 
2439 /* detach a port from the device based on mdeg data */
2440 static void
2441 vgen_port_detach_mdeg(vgen_port_t *portp)
2442 {
2443 	vgen_t *vgenp = portp->vgenp;
2444 
2445 	DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
2446 
2447 	mutex_enter(&portp->lock);
2448 
2449 	/* stop the port if needed */
2450 	if (portp->flags & VGEN_STARTED) {
2451 		vgen_port_uninit(portp);
2452 	}
2453 
2454 	mutex_exit(&portp->lock);
2455 	vgen_port_detach(portp);
2456 
2457 	DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
2458 }
2459 
2460 static int
2461 vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
2462 	md_t *prev_mdp, mde_cookie_t prev_mdex)
2463 {
2464 	uint64_t	cport_num;
2465 	uint64_t	pport_num;
2466 	vgen_portlist_t	*plistp;
2467 	vgen_port_t	*portp;
2468 	boolean_t	updated_vlans = B_FALSE;
2469 	uint16_t	pvid;
2470 	uint16_t	*vids;
2471 	uint16_t	nvids;
2472 
2473 	/*
2474 	 * For now, we get port updates only if vlan ids changed.
2475 	 * We read the port num and do some sanity check.
2476 	 */
2477 	if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) {
2478 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2479 		return (DDI_FAILURE);
2480 	}
2481 
2482 	if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) {
2483 		DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
2484 		return (DDI_FAILURE);
2485 	}
2486 	if (cport_num != pport_num)
2487 		return (DDI_FAILURE);
2488 
2489 	plistp = &(vgenp->vgenports);
2490 
2491 	READ_ENTER(&plistp->rwlock);
2492 
2493 	portp = vgen_port_lookup(plistp, (int)cport_num);
2494 	if (portp == NULL) {
2495 		DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num);
2496 		RW_EXIT(&plistp->rwlock);
2497 		return (DDI_FAILURE);
2498 	}
2499 
2500 	/* Read the vlan ids */
2501 	vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids,
2502 	    &nvids, NULL);
2503 
2504 	/* Determine if there are any vlan id updates */
2505 	if ((pvid != portp->pvid) ||		/* pvid changed? */
2506 	    (nvids != portp->nvids) ||		/* # of vids changed? */
2507 	    ((nvids != 0) && (portp->nvids != 0) &&	/* vids changed? */
2508 	    bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) {
2509 		updated_vlans = B_TRUE;
2510 	}
2511 
2512 	if (updated_vlans == B_FALSE) {
2513 		RW_EXIT(&plistp->rwlock);
2514 		return (DDI_FAILURE);
2515 	}
2516 
2517 	/* remove the port from vlans it has been assigned to */
2518 	vgen_vlan_remove_ids(portp);
2519 
2520 	/* save the new vlan ids */
2521 	portp->pvid = pvid;
2522 	if (portp->nvids != 0) {
2523 		kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids);
2524 		portp->nvids = 0;
2525 	}
2526 	if (nvids != 0) {
2527 		portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP);
2528 		bcopy(vids, portp->vids, sizeof (uint16_t) * nvids);
2529 		portp->nvids = nvids;
2530 		kmem_free(vids, sizeof (uint16_t) * nvids);
2531 	}
2532 
2533 	/* add port to the new vlans */
2534 	vgen_vlan_add_ids(portp);
2535 
2536 	/* reset the port if it is vlan unaware (ver < 1.3) */
2537 	vgen_vlan_unaware_port_reset(portp);
2538 
2539 	RW_EXIT(&plistp->rwlock);
2540 
2541 	return (DDI_SUCCESS);
2542 }
2543 
2544 static uint64_t
2545 vgen_port_stat(vgen_port_t *portp, uint_t stat)
2546 {
2547 	vgen_ldclist_t	*ldclp;
2548 	vgen_ldc_t *ldcp;
2549 	uint64_t	val;
2550 
2551 	val = 0;
2552 	ldclp = &portp->ldclist;
2553 
2554 	READ_ENTER(&ldclp->rwlock);
2555 	for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) {
2556 		val += vgen_ldc_stat(ldcp, stat);
2557 	}
2558 	RW_EXIT(&ldclp->rwlock);
2559 
2560 	return (val);
2561 }
2562 
2563 /* attach the channel corresponding to the given ldc_id to the port */
2564 static int
2565 vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
2566 {
2567 	vgen_t 		*vgenp;
2568 	vgen_ldclist_t	*ldclp;
2569 	vgen_ldc_t 	*ldcp, **prev_ldcp;
2570 	ldc_attr_t 	attr;
2571 	int 		status;
2572 	ldc_status_t	istatus;
2573 	char		kname[MAXNAMELEN];
2574 	int		instance;
2575 	enum	{AST_init = 0x0, AST_ldc_alloc = 0x1,
2576 		AST_mutex_init = 0x2, AST_ldc_init = 0x4,
2577 		AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10,
2578 		AST_create_rxmblks = 0x20,
2579 		AST_create_rcv_thread = 0x40} attach_state;
2580 
2581 	attach_state = AST_init;
2582 	vgenp = portp->vgenp;
2583 	ldclp = &portp->ldclist;
2584 
2585 	ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
2586 	if (ldcp == NULL) {
2587 		goto ldc_attach_failed;
2588 	}
2589 	ldcp->ldc_id = ldc_id;
2590 	ldcp->portp = portp;
2591 
2592 	attach_state |= AST_ldc_alloc;
2593 
2594 	mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
2595 	mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
2596 	mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
2597 	mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
2598 	mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
2599 
2600 	attach_state |= AST_mutex_init;
2601 
2602 	attr.devclass = LDC_DEV_NT;
2603 	attr.instance = vgenp->instance;
2604 	attr.mode = LDC_MODE_UNRELIABLE;
2605 	attr.mtu = vnet_ldc_mtu;
2606 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
2607 	if (status != 0) {
2608 		DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
2609 		goto ldc_attach_failed;
2610 	}
2611 	attach_state |= AST_ldc_init;
2612 
2613 	if (vgen_rcv_thread_enabled) {
2614 		ldcp->rcv_thr_flags = 0;
2615 
2616 		mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL);
2617 		cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL);
2618 		ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
2619 		    vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
2620 
2621 		attach_state |= AST_create_rcv_thread;
2622 		if (ldcp->rcv_thread == NULL) {
2623 			DWARN(vgenp, ldcp, "Failed to create worker thread");
2624 			goto ldc_attach_failed;
2625 		}
2626 	}
2627 
2628 	status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
2629 	if (status != 0) {
2630 		DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
2631 		    status);
2632 		goto ldc_attach_failed;
2633 	}
2634 	/*
2635 	 * allocate a message for ldc_read()s, big enough to hold ctrl and
2636 	 * data msgs, including raw data msgs used to recv priority frames.
2637 	 */
2638 	ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size;
2639 	ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
2640 	attach_state |= AST_ldc_reg_cb;
2641 
2642 	(void) ldc_status(ldcp->ldc_handle, &istatus);
2643 	ASSERT(istatus == LDC_INIT);
2644 	ldcp->ldc_status = istatus;
2645 
2646 	/* allocate transmit resources */
2647 	status = vgen_alloc_tx_ring(ldcp);
2648 	if (status != 0) {
2649 		goto ldc_attach_failed;
2650 	}
2651 	attach_state |= AST_alloc_tx_ring;
2652 
2653 	/* allocate receive resources */
2654 	status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS,
2655 	    vgen_rbufsz1, vgen_rbufsz2, vgen_rbufsz3,
2656 	    vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3);
2657 	if (status != 0) {
2658 		goto ldc_attach_failed;
2659 	}
2660 	attach_state |= AST_create_rxmblks;
2661 
2662 	/* Setup kstats for the channel */
2663 	instance = vgenp->instance;
2664 	(void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id);
2665 	ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats);
2666 	if (ldcp->ksp == NULL) {
2667 		goto ldc_attach_failed;
2668 	}
2669 
2670 	/* initialize vgen_versions supported */
2671 	bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
2672 	vgen_reset_vnet_proto_ops(ldcp);
2673 
2674 	/* link it into the list of channels for this port */
2675 	WRITE_ENTER(&ldclp->rwlock);
2676 	prev_ldcp = (vgen_ldc_t **)(&ldclp->headp);
2677 	ldcp->nextp = *prev_ldcp;
2678 	*prev_ldcp = ldcp;
2679 	RW_EXIT(&ldclp->rwlock);
2680 
2681 	ldcp->flags |= CHANNEL_ATTACHED;
2682 	return (DDI_SUCCESS);
2683 
2684 ldc_attach_failed:
2685 	if (attach_state & AST_ldc_reg_cb) {
2686 		(void) ldc_unreg_callback(ldcp->ldc_handle);
2687 		kmem_free(ldcp->ldcmsg, ldcp->msglen);
2688 	}
2689 	if (attach_state & AST_create_rcv_thread) {
2690 		if (ldcp->rcv_thread != NULL) {
2691 			vgen_stop_rcv_thread(ldcp);
2692 		}
2693 		mutex_destroy(&ldcp->rcv_thr_lock);
2694 		cv_destroy(&ldcp->rcv_thr_cv);
2695 	}
2696 	if (attach_state & AST_create_rxmblks) {
2697 		vio_mblk_pool_t *fvmp = NULL;
2698 
2699 		vio_destroy_multipools(&ldcp->vmp, &fvmp);
2700 		ASSERT(fvmp == NULL);
2701 	}
2702 	if (attach_state & AST_alloc_tx_ring) {
2703 		vgen_free_tx_ring(ldcp);
2704 	}
2705 	if (attach_state & AST_ldc_init) {
2706 		(void) ldc_fini(ldcp->ldc_handle);
2707 	}
2708 	if (attach_state & AST_mutex_init) {
2709 		mutex_destroy(&ldcp->tclock);
2710 		mutex_destroy(&ldcp->txlock);
2711 		mutex_destroy(&ldcp->cblock);
2712 		mutex_destroy(&ldcp->wrlock);
2713 		mutex_destroy(&ldcp->rxlock);
2714 	}
2715 	if (attach_state & AST_ldc_alloc) {
2716 		KMEM_FREE(ldcp);
2717 	}
2718 	return (DDI_FAILURE);
2719 }
2720 
2721 /* detach a channel from the port */
2722 static void
2723 vgen_ldc_detach(vgen_ldc_t *ldcp)
2724 {
2725 	vgen_port_t	*portp;
2726 	vgen_t 		*vgenp;
2727 	vgen_ldc_t 	*pldcp;
2728 	vgen_ldc_t	**prev_ldcp;
2729 	vgen_ldclist_t	*ldclp;
2730 
2731 	portp = ldcp->portp;
2732 	vgenp = portp->vgenp;
2733 	ldclp = &portp->ldclist;
2734 
2735 	prev_ldcp =  (vgen_ldc_t **)&ldclp->headp;
2736 	for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) {
2737 		if (pldcp == ldcp) {
2738 			break;
2739 		}
2740 	}
2741 
2742 	if (pldcp == NULL) {
2743 		/* invalid ldcp? */
2744 		return;
2745 	}
2746 
2747 	if (ldcp->ldc_status != LDC_INIT) {
2748 		DWARN(vgenp, ldcp, "ldc_status is not INIT\n");
2749 	}
2750 
2751 	if (ldcp->flags & CHANNEL_ATTACHED) {
2752 		ldcp->flags &= ~(CHANNEL_ATTACHED);
2753 
2754 		(void) ldc_unreg_callback(ldcp->ldc_handle);
2755 		if (ldcp->rcv_thread != NULL) {
2756 			/* First stop the receive thread */
2757 			vgen_stop_rcv_thread(ldcp);
2758 			mutex_destroy(&ldcp->rcv_thr_lock);
2759 			cv_destroy(&ldcp->rcv_thr_cv);
2760 		}
2761 		kmem_free(ldcp->ldcmsg, ldcp->msglen);
2762 
2763 		vgen_destroy_kstats(ldcp->ksp);
2764 		ldcp->ksp = NULL;
2765 
2766 		/*
2767 		 * if we cannot reclaim all mblks, put this
2768 		 * on the list of pools(vgenp->rmp) to be reclaimed when the
2769 		 * device gets detached (see vgen_uninit()).
2770 		 */
2771 		vio_destroy_multipools(&ldcp->vmp, &vgenp->rmp);
2772 
2773 		/* free transmit resources */
2774 		vgen_free_tx_ring(ldcp);
2775 
2776 		(void) ldc_fini(ldcp->ldc_handle);
2777 		mutex_destroy(&ldcp->tclock);
2778 		mutex_destroy(&ldcp->txlock);
2779 		mutex_destroy(&ldcp->cblock);
2780 		mutex_destroy(&ldcp->wrlock);
2781 		mutex_destroy(&ldcp->rxlock);
2782 
2783 		/* unlink it from the list */
2784 		*prev_ldcp = ldcp->nextp;
2785 		KMEM_FREE(ldcp);
2786 	}
2787 }
2788 
2789 /*
2790  * This function allocates transmit resources for the channel.
2791  * The resources consist of a transmit descriptor ring and an associated
2792  * transmit buffer ring.
2793  */
2794 static int
2795 vgen_alloc_tx_ring(vgen_ldc_t *ldcp)
2796 {
2797 	void *tbufp;
2798 	ldc_mem_info_t minfo;
2799 	uint32_t txdsize;
2800 	uint32_t tbufsize;
2801 	int status;
2802 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
2803 
2804 	ldcp->num_txds = vnet_ntxds;
2805 	txdsize = sizeof (vnet_public_desc_t);
2806 	tbufsize = sizeof (vgen_private_desc_t);
2807 
2808 	/* allocate transmit buffer ring */
2809 	tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP);
2810 	if (tbufp == NULL) {
2811 		return (DDI_FAILURE);
2812 	}
2813 
2814 	/* create transmit descriptor ring */
2815 	status = ldc_mem_dring_create(ldcp->num_txds, txdsize,
2816 	    &ldcp->tx_dhandle);
2817 	if (status) {
2818 		DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n");
2819 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
2820 		return (DDI_FAILURE);
2821 	}
2822 
2823 	/* get the addr of descripror ring */
2824 	status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo);
2825 	if (status) {
2826 		DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n");
2827 		kmem_free(tbufp, ldcp->num_txds * tbufsize);
2828 		(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
2829 		ldcp->tbufp = NULL;
2830 		return (DDI_FAILURE);
2831 	}
2832 	ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr);
2833 	ldcp->tbufp = tbufp;
2834 
2835 	ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]);
2836 	ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]);
2837 
2838 	return (DDI_SUCCESS);
2839 }
2840 
2841 /* Free transmit resources for the channel */
2842 static void
2843 vgen_free_tx_ring(vgen_ldc_t *ldcp)
2844 {
2845 	int tbufsize = sizeof (vgen_private_desc_t);
2846 
2847 	/* free transmit descriptor ring */
2848 	(void) ldc_mem_dring_destroy(ldcp->tx_dhandle);
2849 
2850 	/* free transmit buffer ring */
2851 	kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize);
2852 	ldcp->txdp = ldcp->txdendp = NULL;
2853 	ldcp->tbufp = ldcp->tbufendp = NULL;
2854 }
2855 
2856 /* enable transmit/receive on the channels for the port */
2857 static void
2858 vgen_init_ldcs(vgen_port_t *portp)
2859 {
2860 	vgen_ldclist_t	*ldclp = &portp->ldclist;
2861 	vgen_ldc_t	*ldcp;
2862 
2863 	READ_ENTER(&ldclp->rwlock);
2864 	ldcp =  ldclp->headp;
2865 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
2866 		(void) vgen_ldc_init(ldcp);
2867 	}
2868 	RW_EXIT(&ldclp->rwlock);
2869 }
2870 
2871 /* stop transmit/receive on the channels for the port */
2872 static void
2873 vgen_uninit_ldcs(vgen_port_t *portp)
2874 {
2875 	vgen_ldclist_t	*ldclp = &portp->ldclist;
2876 	vgen_ldc_t	*ldcp;
2877 
2878 	READ_ENTER(&ldclp->rwlock);
2879 	ldcp =  ldclp->headp;
2880 	for (; ldcp  != NULL; ldcp = ldcp->nextp) {
2881 		vgen_ldc_uninit(ldcp);
2882 	}
2883 	RW_EXIT(&ldclp->rwlock);
2884 }
2885 
2886 /* enable transmit/receive on the channel */
2887 static int
2888 vgen_ldc_init(vgen_ldc_t *ldcp)
2889 {
2890 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
2891 	ldc_status_t	istatus;
2892 	int		rv;
2893 	uint32_t	retries = 0;
2894 	enum	{ ST_init = 0x0, ST_ldc_open = 0x1,
2895 		ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state;
2896 	init_state = ST_init;
2897 
2898 	DBG1(vgenp, ldcp, "enter\n");
2899 	LDC_LOCK(ldcp);
2900 
2901 	rv = ldc_open(ldcp->ldc_handle);
2902 	if (rv != 0) {
2903 		DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
2904 		goto ldcinit_failed;
2905 	}
2906 	init_state |= ST_ldc_open;
2907 
2908 	(void) ldc_status(ldcp->ldc_handle, &istatus);
2909 	if (istatus != LDC_OPEN && istatus != LDC_READY) {
2910 		DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
2911 		goto ldcinit_failed;
2912 	}
2913 	ldcp->ldc_status = istatus;
2914 
2915 	rv = vgen_init_tbufs(ldcp);
2916 	if (rv != 0) {
2917 		DWARN(vgenp, ldcp, "vgen_init_tbufs() failed\n");
2918 		goto ldcinit_failed;
2919 	}
2920 	init_state |= ST_init_tbufs;
2921 
2922 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
2923 	if (rv != 0) {
2924 		DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
2925 		goto ldcinit_failed;
2926 	}
2927 
2928 	init_state |= ST_cb_enable;
2929 
2930 	do {
2931 		rv = ldc_up(ldcp->ldc_handle);
2932 		if ((rv != 0) && (rv == EWOULDBLOCK)) {
2933 			DBG2(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
2934 			drv_usecwait(VGEN_LDC_UP_DELAY);
2935 		}
2936 		if (retries++ >= vgen_ldcup_retries)
2937 			break;
2938 	} while (rv == EWOULDBLOCK);
2939 
2940 	(void) ldc_status(ldcp->ldc_handle, &istatus);
2941 	if (istatus == LDC_UP) {
2942 		DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus);
2943 	}
2944 
2945 	ldcp->ldc_status = istatus;
2946 
2947 	/* initialize transmit watchdog timeout */
2948 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
2949 	    drv_usectohz(vnet_ldcwd_interval * 1000));
2950 
2951 	ldcp->hphase = -1;
2952 	ldcp->flags |= CHANNEL_STARTED;
2953 
2954 	/* if channel is already UP - start handshake */
2955 	if (istatus == LDC_UP) {
2956 		vgen_t *vgenp = LDC_TO_VGEN(ldcp);
2957 		if (ldcp->portp != vgenp->vsw_portp) {
2958 			/*
2959 			 * As the channel is up, use this port from now on.
2960 			 */
2961 			(void) atomic_swap_32(
2962 			    &ldcp->portp->use_vsw_port, B_FALSE);
2963 		}
2964 
2965 		/* Initialize local session id */
2966 		ldcp->local_sid = ddi_get_lbolt();
2967 
2968 		/* clear peer session id */
2969 		ldcp->peer_sid = 0;
2970 		ldcp->hretries = 0;
2971 
2972 		/* Initiate Handshake process with peer ldc endpoint */
2973 		vgen_reset_hphase(ldcp);
2974 
2975 		mutex_exit(&ldcp->tclock);
2976 		mutex_exit(&ldcp->txlock);
2977 		mutex_exit(&ldcp->wrlock);
2978 		mutex_exit(&ldcp->rxlock);
2979 		vgen_handshake(vh_nextphase(ldcp));
2980 		mutex_exit(&ldcp->cblock);
2981 	} else {
2982 		LDC_UNLOCK(ldcp);
2983 	}
2984 
2985 	return (DDI_SUCCESS);
2986 
2987 ldcinit_failed:
2988 	if (init_state & ST_cb_enable) {
2989 		(void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
2990 	}
2991 	if (init_state & ST_init_tbufs) {
2992 		vgen_uninit_tbufs(ldcp);
2993 	}
2994 	if (init_state & ST_ldc_open) {
2995 		(void) ldc_close(ldcp->ldc_handle);
2996 	}
2997 	LDC_UNLOCK(ldcp);
2998 	DBG1(vgenp, ldcp, "exit\n");
2999 	return (DDI_FAILURE);
3000 }
3001 
3002 /* stop transmit/receive on the channel */
3003 static void
3004 vgen_ldc_uninit(vgen_ldc_t *ldcp)
3005 {
3006 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3007 	int	rv;
3008 
3009 	DBG1(vgenp, ldcp, "enter\n");
3010 	LDC_LOCK(ldcp);
3011 
3012 	if ((ldcp->flags & CHANNEL_STARTED) == 0) {
3013 		LDC_UNLOCK(ldcp);
3014 		DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
3015 		return;
3016 	}
3017 
3018 	/* disable further callbacks */
3019 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
3020 	if (rv != 0) {
3021 		DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n");
3022 	}
3023 
3024 	if (vgenp->vsw_portp == ldcp->portp) {
3025 		vio_net_report_err_t rep_err =
3026 		    ldcp->portp->vcb.vio_net_report_err;
3027 		rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN);
3028 	}
3029 
3030 	/*
3031 	 * clear handshake done bit and wait for pending tx and cb to finish.
3032 	 * release locks before untimeout(9F) is invoked to cancel timeouts.
3033 	 */
3034 	ldcp->hphase &= ~(VH_DONE);
3035 	LDC_UNLOCK(ldcp);
3036 
3037 	/* cancel handshake watchdog timeout */
3038 	if (ldcp->htid) {
3039 		(void) untimeout(ldcp->htid);
3040 		ldcp->htid = 0;
3041 	}
3042 
3043 	/* cancel transmit watchdog timeout */
3044 	if (ldcp->wd_tid) {
3045 		(void) untimeout(ldcp->wd_tid);
3046 		ldcp->wd_tid = 0;
3047 	}
3048 
3049 	drv_usecwait(1000);
3050 
3051 	/* acquire locks again; any pending transmits and callbacks are done */
3052 	LDC_LOCK(ldcp);
3053 
3054 	vgen_reset_hphase(ldcp);
3055 
3056 	vgen_uninit_tbufs(ldcp);
3057 
3058 	rv = ldc_close(ldcp->ldc_handle);
3059 	if (rv != 0) {
3060 		DWARN(vgenp, ldcp, "ldc_close err\n");
3061 	}
3062 	ldcp->ldc_status = LDC_INIT;
3063 	ldcp->flags &= ~(CHANNEL_STARTED);
3064 
3065 	LDC_UNLOCK(ldcp);
3066 
3067 	DBG1(vgenp, ldcp, "exit\n");
3068 }
3069 
3070 /* Initialize the transmit buffer ring for the channel */
3071 static int
3072 vgen_init_tbufs(vgen_ldc_t *ldcp)
3073 {
3074 	vgen_private_desc_t	*tbufp;
3075 	vnet_public_desc_t	*txdp;
3076 	vio_dring_entry_hdr_t		*hdrp;
3077 	int 			i;
3078 	int 			rv;
3079 	caddr_t			datap = NULL;
3080 	int			ci;
3081 	uint32_t		ncookies;
3082 	size_t			data_sz;
3083 	vgen_t			*vgenp;
3084 
3085 	vgenp = LDC_TO_VGEN(ldcp);
3086 
3087 	bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds));
3088 	bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds));
3089 
3090 	data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN;
3091 	data_sz = VNET_ROUNDUP_2K(data_sz);
3092 	ldcp->tx_data_sz = data_sz * ldcp->num_txds;
3093 	datap = kmem_zalloc(ldcp->tx_data_sz, KM_SLEEP);
3094 	ldcp->tx_datap = datap;
3095 
3096 	/*
3097 	 * for each private descriptor, allocate a ldc mem_handle which is
3098 	 * required to map the data during transmit, set the flags
3099 	 * to free (available for use by transmit routine).
3100 	 */
3101 
3102 	for (i = 0; i < ldcp->num_txds; i++) {
3103 
3104 		tbufp = &(ldcp->tbufp[i]);
3105 		rv = ldc_mem_alloc_handle(ldcp->ldc_handle,
3106 		    &(tbufp->memhandle));
3107 		if (rv) {
3108 			tbufp->memhandle = 0;
3109 			goto init_tbufs_failed;
3110 		}
3111 
3112 		/*
3113 		 * bind ldc memhandle to the corresponding transmit buffer.
3114 		 */
3115 		ci = ncookies = 0;
3116 		rv = ldc_mem_bind_handle(tbufp->memhandle,
3117 		    (caddr_t)datap, data_sz, LDC_SHADOW_MAP,
3118 		    LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies);
3119 		if (rv != 0) {
3120 			goto init_tbufs_failed;
3121 		}
3122 
3123 		/*
3124 		 * successful in binding the handle to tx data buffer.
3125 		 * set datap in the private descr to this buffer.
3126 		 */
3127 		tbufp->datap = datap;
3128 
3129 		if ((ncookies == 0) ||
3130 		    (ncookies > MAX_COOKIES)) {
3131 			goto init_tbufs_failed;
3132 		}
3133 
3134 		for (ci = 1; ci < ncookies; ci++) {
3135 			rv = ldc_mem_nextcookie(tbufp->memhandle,
3136 			    &(tbufp->memcookie[ci]));
3137 			if (rv != 0) {
3138 				goto init_tbufs_failed;
3139 			}
3140 		}
3141 
3142 		tbufp->ncookies = ncookies;
3143 		datap += data_sz;
3144 
3145 		tbufp->flags = VGEN_PRIV_DESC_FREE;
3146 		txdp = &(ldcp->txdp[i]);
3147 		hdrp = &txdp->hdr;
3148 		hdrp->dstate = VIO_DESC_FREE;
3149 		hdrp->ack = B_FALSE;
3150 		tbufp->descp = txdp;
3151 
3152 	}
3153 
3154 	/* reset tbuf walking pointers */
3155 	ldcp->next_tbufp = ldcp->tbufp;
3156 	ldcp->cur_tbufp = ldcp->tbufp;
3157 
3158 	/* initialize tx seqnum and index */
3159 	ldcp->next_txseq = VNET_ISS;
3160 	ldcp->next_txi = 0;
3161 
3162 	ldcp->resched_peer = B_TRUE;
3163 	ldcp->resched_peer_txi = 0;
3164 
3165 	return (DDI_SUCCESS);
3166 
3167 init_tbufs_failed:;
3168 	vgen_uninit_tbufs(ldcp);
3169 	return (DDI_FAILURE);
3170 }
3171 
3172 /* Uninitialize transmit buffer ring for the channel */
3173 static void
3174 vgen_uninit_tbufs(vgen_ldc_t *ldcp)
3175 {
3176 	vgen_private_desc_t	*tbufp = ldcp->tbufp;
3177 	int 			i;
3178 
3179 	/* for each tbuf (priv_desc), free ldc mem_handle */
3180 	for (i = 0; i < ldcp->num_txds; i++) {
3181 
3182 		tbufp = &(ldcp->tbufp[i]);
3183 
3184 		if (tbufp->datap) { /* if bound to a ldc memhandle */
3185 			(void) ldc_mem_unbind_handle(tbufp->memhandle);
3186 			tbufp->datap = NULL;
3187 		}
3188 		if (tbufp->memhandle) {
3189 			(void) ldc_mem_free_handle(tbufp->memhandle);
3190 			tbufp->memhandle = 0;
3191 		}
3192 	}
3193 
3194 	if (ldcp->tx_datap) {
3195 		/* prealloc'd tx data buffer */
3196 		kmem_free(ldcp->tx_datap, ldcp->tx_data_sz);
3197 		ldcp->tx_datap = NULL;
3198 		ldcp->tx_data_sz = 0;
3199 	}
3200 
3201 	bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds));
3202 	bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds));
3203 }
3204 
3205 /* clobber tx descriptor ring */
3206 static void
3207 vgen_clobber_tbufs(vgen_ldc_t *ldcp)
3208 {
3209 	vnet_public_desc_t	*txdp;
3210 	vgen_private_desc_t	*tbufp;
3211 	vio_dring_entry_hdr_t	*hdrp;
3212 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
3213 	int i;
3214 #ifdef DEBUG
3215 	int ndone = 0;
3216 #endif
3217 
3218 	for (i = 0; i < ldcp->num_txds; i++) {
3219 
3220 		tbufp = &(ldcp->tbufp[i]);
3221 		txdp = tbufp->descp;
3222 		hdrp = &txdp->hdr;
3223 
3224 		if (tbufp->flags & VGEN_PRIV_DESC_BUSY) {
3225 			tbufp->flags = VGEN_PRIV_DESC_FREE;
3226 #ifdef DEBUG
3227 			if (hdrp->dstate == VIO_DESC_DONE)
3228 				ndone++;
3229 #endif
3230 			hdrp->dstate = VIO_DESC_FREE;
3231 			hdrp->ack = B_FALSE;
3232 		}
3233 	}
3234 	/* reset tbuf walking pointers */
3235 	ldcp->next_tbufp = ldcp->tbufp;
3236 	ldcp->cur_tbufp = ldcp->tbufp;
3237 
3238 	/* reset tx seqnum and index */
3239 	ldcp->next_txseq = VNET_ISS;
3240 	ldcp->next_txi = 0;
3241 
3242 	ldcp->resched_peer = B_TRUE;
3243 	ldcp->resched_peer_txi = 0;
3244 
3245 	DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone);
3246 }
3247 
3248 /* clobber receive descriptor ring */
3249 static void
3250 vgen_clobber_rxds(vgen_ldc_t *ldcp)
3251 {
3252 	ldcp->rx_dhandle = 0;
3253 	bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie));
3254 	ldcp->rxdp = NULL;
3255 	ldcp->next_rxi = 0;
3256 	ldcp->num_rxds = 0;
3257 	ldcp->next_rxseq = VNET_ISS;
3258 }
3259 
3260 /* initialize receive descriptor ring */
3261 static int
3262 vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size,
3263 	ldc_mem_cookie_t *dcookie, uint32_t ncookies)
3264 {
3265 	int rv;
3266 	ldc_mem_info_t minfo;
3267 
3268 	rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc,
3269 	    desc_size, LDC_DIRECT_MAP, &(ldcp->rx_dhandle));
3270 	if (rv != 0) {
3271 		return (DDI_FAILURE);
3272 	}
3273 
3274 	/*
3275 	 * sucessfully mapped, now try to
3276 	 * get info about the mapped dring
3277 	 */
3278 	rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo);
3279 	if (rv != 0) {
3280 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
3281 		return (DDI_FAILURE);
3282 	}
3283 
3284 	/*
3285 	 * save ring address, number of descriptors.
3286 	 */
3287 	ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr);
3288 	bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie));
3289 	ldcp->num_rxdcookies = ncookies;
3290 	ldcp->num_rxds = num_desc;
3291 	ldcp->next_rxi = 0;
3292 	ldcp->next_rxseq = VNET_ISS;
3293 	ldcp->dring_mtype = minfo.mtype;
3294 
3295 	return (DDI_SUCCESS);
3296 }
3297 
3298 /* get channel statistics */
3299 static uint64_t
3300 vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
3301 {
3302 	vgen_stats_t *statsp;
3303 	uint64_t val;
3304 
3305 	val = 0;
3306 	statsp = &ldcp->stats;
3307 	switch (stat) {
3308 
3309 	case MAC_STAT_MULTIRCV:
3310 		val = statsp->multircv;
3311 		break;
3312 
3313 	case MAC_STAT_BRDCSTRCV:
3314 		val = statsp->brdcstrcv;
3315 		break;
3316 
3317 	case MAC_STAT_MULTIXMT:
3318 		val = statsp->multixmt;
3319 		break;
3320 
3321 	case MAC_STAT_BRDCSTXMT:
3322 		val = statsp->brdcstxmt;
3323 		break;
3324 
3325 	case MAC_STAT_NORCVBUF:
3326 		val = statsp->norcvbuf;
3327 		break;
3328 
3329 	case MAC_STAT_IERRORS:
3330 		val = statsp->ierrors;
3331 		break;
3332 
3333 	case MAC_STAT_NOXMTBUF:
3334 		val = statsp->noxmtbuf;
3335 		break;
3336 
3337 	case MAC_STAT_OERRORS:
3338 		val = statsp->oerrors;
3339 		break;
3340 
3341 	case MAC_STAT_COLLISIONS:
3342 		break;
3343 
3344 	case MAC_STAT_RBYTES:
3345 		val = statsp->rbytes;
3346 		break;
3347 
3348 	case MAC_STAT_IPACKETS:
3349 		val = statsp->ipackets;
3350 		break;
3351 
3352 	case MAC_STAT_OBYTES:
3353 		val = statsp->obytes;
3354 		break;
3355 
3356 	case MAC_STAT_OPACKETS:
3357 		val = statsp->opackets;
3358 		break;
3359 
3360 	/* stats not relevant to ldc, return 0 */
3361 	case MAC_STAT_IFSPEED:
3362 	case ETHER_STAT_ALIGN_ERRORS:
3363 	case ETHER_STAT_FCS_ERRORS:
3364 	case ETHER_STAT_FIRST_COLLISIONS:
3365 	case ETHER_STAT_MULTI_COLLISIONS:
3366 	case ETHER_STAT_DEFER_XMTS:
3367 	case ETHER_STAT_TX_LATE_COLLISIONS:
3368 	case ETHER_STAT_EX_COLLISIONS:
3369 	case ETHER_STAT_MACXMT_ERRORS:
3370 	case ETHER_STAT_CARRIER_ERRORS:
3371 	case ETHER_STAT_TOOLONG_ERRORS:
3372 	case ETHER_STAT_XCVR_ADDR:
3373 	case ETHER_STAT_XCVR_ID:
3374 	case ETHER_STAT_XCVR_INUSE:
3375 	case ETHER_STAT_CAP_1000FDX:
3376 	case ETHER_STAT_CAP_1000HDX:
3377 	case ETHER_STAT_CAP_100FDX:
3378 	case ETHER_STAT_CAP_100HDX:
3379 	case ETHER_STAT_CAP_10FDX:
3380 	case ETHER_STAT_CAP_10HDX:
3381 	case ETHER_STAT_CAP_ASMPAUSE:
3382 	case ETHER_STAT_CAP_PAUSE:
3383 	case ETHER_STAT_CAP_AUTONEG:
3384 	case ETHER_STAT_ADV_CAP_1000FDX:
3385 	case ETHER_STAT_ADV_CAP_1000HDX:
3386 	case ETHER_STAT_ADV_CAP_100FDX:
3387 	case ETHER_STAT_ADV_CAP_100HDX:
3388 	case ETHER_STAT_ADV_CAP_10FDX:
3389 	case ETHER_STAT_ADV_CAP_10HDX:
3390 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
3391 	case ETHER_STAT_ADV_CAP_PAUSE:
3392 	case ETHER_STAT_ADV_CAP_AUTONEG:
3393 	case ETHER_STAT_LP_CAP_1000FDX:
3394 	case ETHER_STAT_LP_CAP_1000HDX:
3395 	case ETHER_STAT_LP_CAP_100FDX:
3396 	case ETHER_STAT_LP_CAP_100HDX:
3397 	case ETHER_STAT_LP_CAP_10FDX:
3398 	case ETHER_STAT_LP_CAP_10HDX:
3399 	case ETHER_STAT_LP_CAP_ASMPAUSE:
3400 	case ETHER_STAT_LP_CAP_PAUSE:
3401 	case ETHER_STAT_LP_CAP_AUTONEG:
3402 	case ETHER_STAT_LINK_ASMPAUSE:
3403 	case ETHER_STAT_LINK_PAUSE:
3404 	case ETHER_STAT_LINK_AUTONEG:
3405 	case ETHER_STAT_LINK_DUPLEX:
3406 	default:
3407 		val = 0;
3408 		break;
3409 
3410 	}
3411 	return (val);
3412 }
3413 
3414 /*
3415  * LDC channel is UP, start handshake process with peer.
3416  */
3417 static void
3418 vgen_handle_evt_up(vgen_ldc_t *ldcp)
3419 {
3420 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
3421 
3422 	DBG1(vgenp, ldcp, "enter\n");
3423 
3424 	ASSERT(MUTEX_HELD(&ldcp->cblock));
3425 
3426 	if (ldcp->portp != vgenp->vsw_portp) {
3427 		/*
3428 		 * As the channel is up, use this port from now on.
3429 		 */
3430 		(void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE);
3431 	}
3432 
3433 	/* Initialize local session id */
3434 	ldcp->local_sid = ddi_get_lbolt();
3435 
3436 	/* clear peer session id */
3437 	ldcp->peer_sid = 0;
3438 	ldcp->hretries = 0;
3439 
3440 	if (ldcp->hphase != VH_PHASE0) {
3441 		vgen_handshake_reset(ldcp);
3442 	}
3443 
3444 	/* Initiate Handshake process with peer ldc endpoint */
3445 	vgen_handshake(vh_nextphase(ldcp));
3446 
3447 	DBG1(vgenp, ldcp, "exit\n");
3448 }
3449 
3450 /*
3451  * LDC channel is Reset, terminate connection with peer and try to
3452  * bring the channel up again.
3453  */
3454 static void
3455 vgen_handle_evt_reset(vgen_ldc_t *ldcp)
3456 {
3457 	ldc_status_t istatus;
3458 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
3459 	int	rv;
3460 
3461 	DBG1(vgenp, ldcp, "enter\n");
3462 
3463 	ASSERT(MUTEX_HELD(&ldcp->cblock));
3464 
3465 	if ((ldcp->portp != vgenp->vsw_portp) &&
3466 	    (vgenp->vsw_portp != NULL)) {
3467 		/*
3468 		 * As the channel is down, use the switch port until
3469 		 * the channel becomes ready to be used.
3470 		 */
3471 		(void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_TRUE);
3472 	}
3473 
3474 	if (vgenp->vsw_portp == ldcp->portp) {
3475 		vio_net_report_err_t rep_err =
3476 		    ldcp->portp->vcb.vio_net_report_err;
3477 
3478 		/* Post a reset message */
3479 		rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN);
3480 	}
3481 
3482 	if (ldcp->hphase != VH_PHASE0) {
3483 		vgen_handshake_reset(ldcp);
3484 	}
3485 
3486 	/* try to bring the channel up */
3487 	rv = ldc_up(ldcp->ldc_handle);
3488 	if (rv != 0) {
3489 		DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
3490 	}
3491 
3492 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3493 		DWARN(vgenp, ldcp, "ldc_status err\n");
3494 	} else {
3495 		ldcp->ldc_status = istatus;
3496 	}
3497 
3498 	/* if channel is already UP - restart handshake */
3499 	if (ldcp->ldc_status == LDC_UP) {
3500 		vgen_handle_evt_up(ldcp);
3501 	}
3502 
3503 	DBG1(vgenp, ldcp, "exit\n");
3504 }
3505 
3506 /* Interrupt handler for the channel */
3507 static uint_t
3508 vgen_ldc_cb(uint64_t event, caddr_t arg)
3509 {
3510 	_NOTE(ARGUNUSED(event))
3511 	vgen_ldc_t	*ldcp;
3512 	vgen_t		*vgenp;
3513 	ldc_status_t 	istatus;
3514 	vgen_stats_t	*statsp;
3515 
3516 	ldcp = (vgen_ldc_t *)arg;
3517 	vgenp = LDC_TO_VGEN(ldcp);
3518 	statsp = &ldcp->stats;
3519 
3520 	DBG1(vgenp, ldcp, "enter\n");
3521 
3522 	mutex_enter(&ldcp->cblock);
3523 	statsp->callbacks++;
3524 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
3525 		DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n",
3526 		    ldcp->ldc_status);
3527 		mutex_exit(&ldcp->cblock);
3528 		return (LDC_SUCCESS);
3529 	}
3530 
3531 	/*
3532 	 * NOTE: not using switch() as event could be triggered by
3533 	 * a state change and a read request. Also the ordering	of the
3534 	 * check for the event types is deliberate.
3535 	 */
3536 	if (event & LDC_EVT_UP) {
3537 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3538 			DWARN(vgenp, ldcp, "ldc_status err\n");
3539 			/* status couldn't be determined */
3540 			mutex_exit(&ldcp->cblock);
3541 			return (LDC_FAILURE);
3542 		}
3543 		ldcp->ldc_status = istatus;
3544 		if (ldcp->ldc_status != LDC_UP) {
3545 			DWARN(vgenp, ldcp, "LDC_EVT_UP received "
3546 			    " but ldc status is not UP(0x%x)\n",
3547 			    ldcp->ldc_status);
3548 			/* spurious interrupt, return success */
3549 			mutex_exit(&ldcp->cblock);
3550 			return (LDC_SUCCESS);
3551 		}
3552 		DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n",
3553 		    event, ldcp->ldc_status);
3554 
3555 		vgen_handle_evt_up(ldcp);
3556 
3557 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
3558 	}
3559 
3560 	/* Handle RESET/DOWN before READ event */
3561 	if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
3562 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3563 			DWARN(vgenp, ldcp, "ldc_status error\n");
3564 			/* status couldn't be determined */
3565 			mutex_exit(&ldcp->cblock);
3566 			return (LDC_FAILURE);
3567 		}
3568 		ldcp->ldc_status = istatus;
3569 		DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
3570 		    event, ldcp->ldc_status);
3571 
3572 		vgen_handle_evt_reset(ldcp);
3573 
3574 		/*
3575 		 * As the channel is down/reset, ignore READ event
3576 		 * but print a debug warning message.
3577 		 */
3578 		if (event & LDC_EVT_READ) {
3579 			DWARN(vgenp, ldcp,
3580 			    "LDC_EVT_READ set along with RESET/DOWN\n");
3581 			event &= ~LDC_EVT_READ;
3582 		}
3583 	}
3584 
3585 	if (event & LDC_EVT_READ) {
3586 		DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n",
3587 		    event, ldcp->ldc_status);
3588 
3589 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
3590 
3591 		if (ldcp->rcv_thread != NULL) {
3592 			/*
3593 			 * If the receive thread is enabled, then
3594 			 * wakeup the receive thread to process the
3595 			 * LDC messages.
3596 			 */
3597 			mutex_exit(&ldcp->cblock);
3598 			mutex_enter(&ldcp->rcv_thr_lock);
3599 			if (!(ldcp->rcv_thr_flags & VGEN_WTHR_DATARCVD)) {
3600 				ldcp->rcv_thr_flags |= VGEN_WTHR_DATARCVD;
3601 				cv_signal(&ldcp->rcv_thr_cv);
3602 			}
3603 			mutex_exit(&ldcp->rcv_thr_lock);
3604 			mutex_enter(&ldcp->cblock);
3605 		} else  {
3606 			vgen_handle_evt_read(ldcp);
3607 		}
3608 	}
3609 	mutex_exit(&ldcp->cblock);
3610 
3611 	if (ldcp->cancel_htid) {
3612 		/*
3613 		 * Cancel handshake timer.
3614 		 * untimeout(9F) will not return until the pending callback is
3615 		 * cancelled or has run. No problems will result from calling
3616 		 * untimeout if the handler has already completed.
3617 		 * If the timeout handler did run, then it would just
3618 		 * return as cancel_htid is set.
3619 		 */
3620 		(void) untimeout(ldcp->cancel_htid);
3621 		ldcp->cancel_htid = 0;
3622 	}
3623 	DBG1(vgenp, ldcp, "exit\n");
3624 
3625 	return (LDC_SUCCESS);
3626 }
3627 
3628 static void
3629 vgen_handle_evt_read(vgen_ldc_t *ldcp)
3630 {
3631 	int		rv;
3632 	uint64_t	*ldcmsg;
3633 	size_t		msglen;
3634 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
3635 	vio_msg_tag_t	*tagp;
3636 	ldc_status_t 	istatus;
3637 	boolean_t 	has_data;
3638 
3639 	DBG1(vgenp, ldcp, "enter\n");
3640 
3641 	ldcmsg = ldcp->ldcmsg;
3642 	/*
3643 	 * If the receive thread is enabled, then the cblock
3644 	 * need to be acquired here. If not, the vgen_ldc_cb()
3645 	 * calls this function with cblock held already.
3646 	 */
3647 	if (ldcp->rcv_thread != NULL) {
3648 		mutex_enter(&ldcp->cblock);
3649 	} else {
3650 		ASSERT(MUTEX_HELD(&ldcp->cblock));
3651 	}
3652 
3653 vgen_evt_read:
3654 	do {
3655 		msglen = ldcp->msglen;
3656 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
3657 
3658 		if (rv != 0) {
3659 			DWARN(vgenp, ldcp, "err rv(%d) len(%d)\n",
3660 			    rv, msglen);
3661 			if (rv == ECONNRESET)
3662 				goto vgen_evtread_error;
3663 			break;
3664 		}
3665 		if (msglen == 0) {
3666 			DBG2(vgenp, ldcp, "ldc_read NODATA");
3667 			break;
3668 		}
3669 		DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen);
3670 
3671 		tagp = (vio_msg_tag_t *)ldcmsg;
3672 
3673 		if (ldcp->peer_sid) {
3674 			/*
3675 			 * check sid only after we have received peer's sid
3676 			 * in the version negotiate msg.
3677 			 */
3678 #ifdef DEBUG
3679 			if (vgen_hdbg & HDBG_BAD_SID) {
3680 				/* simulate bad sid condition */
3681 				tagp->vio_sid = 0;
3682 				vgen_hdbg &= ~(HDBG_BAD_SID);
3683 			}
3684 #endif
3685 			rv = vgen_check_sid(ldcp, tagp);
3686 			if (rv != VGEN_SUCCESS) {
3687 				/*
3688 				 * If sid mismatch is detected,
3689 				 * reset the channel.
3690 				 */
3691 				ldcp->need_ldc_reset = B_TRUE;
3692 				goto vgen_evtread_error;
3693 			}
3694 		}
3695 
3696 		switch (tagp->vio_msgtype) {
3697 		case VIO_TYPE_CTRL:
3698 			rv = vgen_handle_ctrlmsg(ldcp, tagp);
3699 			break;
3700 
3701 		case VIO_TYPE_DATA:
3702 			rv = vgen_handle_datamsg(ldcp, tagp, msglen);
3703 			break;
3704 
3705 		case VIO_TYPE_ERR:
3706 			vgen_handle_errmsg(ldcp, tagp);
3707 			break;
3708 
3709 		default:
3710 			DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n",
3711 			    tagp->vio_msgtype);
3712 			break;
3713 		}
3714 
3715 		/*
3716 		 * If an error is encountered, stop processing and
3717 		 * handle the error.
3718 		 */
3719 		if (rv != 0) {
3720 			goto vgen_evtread_error;
3721 		}
3722 
3723 	} while (msglen);
3724 
3725 	/* check once more before exiting */
3726 	rv = ldc_chkq(ldcp->ldc_handle, &has_data);
3727 	if ((rv == 0) && (has_data == B_TRUE)) {
3728 		DTRACE_PROBE(vgen_chkq);
3729 		goto vgen_evt_read;
3730 	}
3731 
3732 vgen_evtread_error:
3733 	if (rv == ECONNRESET) {
3734 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3735 			DWARN(vgenp, ldcp, "ldc_status err\n");
3736 		} else {
3737 			ldcp->ldc_status = istatus;
3738 		}
3739 		vgen_handle_evt_reset(ldcp);
3740 	} else if (rv) {
3741 		vgen_handshake_retry(ldcp);
3742 	}
3743 
3744 	/*
3745 	 * If the receive thread is not enabled, then cancel the
3746 	 * handshake timeout here.
3747 	 */
3748 	if (ldcp->rcv_thread != NULL) {
3749 		mutex_exit(&ldcp->cblock);
3750 		if (ldcp->cancel_htid) {
3751 			/*
3752 			 * Cancel handshake timer. untimeout(9F) will
3753 			 * not return until the pending callback is cancelled
3754 			 * or has run. No problems will result from calling
3755 			 * untimeout if the handler has already completed.
3756 			 * If the timeout handler did run, then it would just
3757 			 * return as cancel_htid is set.
3758 			 */
3759 			(void) untimeout(ldcp->cancel_htid);
3760 			ldcp->cancel_htid = 0;
3761 		}
3762 	}
3763 
3764 	DBG1(vgenp, ldcp, "exit\n");
3765 }
3766 
3767 /* vgen handshake functions */
3768 
3769 /* change the hphase for the channel to the next phase */
3770 static vgen_ldc_t *
3771 vh_nextphase(vgen_ldc_t *ldcp)
3772 {
3773 	if (ldcp->hphase == VH_PHASE3) {
3774 		ldcp->hphase = VH_DONE;
3775 	} else {
3776 		ldcp->hphase++;
3777 	}
3778 	return (ldcp);
3779 }
3780 
3781 /*
3782  * wrapper routine to send the given message over ldc using ldc_write().
3783  */
3784 static int
3785 vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen,
3786     boolean_t caller_holds_lock)
3787 {
3788 	int			rv;
3789 	size_t			len;
3790 	uint32_t		retries = 0;
3791 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
3792 	vio_msg_tag_t		*tagp = (vio_msg_tag_t *)msg;
3793 	vio_dring_msg_t		*dmsg;
3794 	vio_raw_data_msg_t	*rmsg;
3795 	boolean_t		data_msg = B_FALSE;
3796 
3797 	len = msglen;
3798 	if ((len == 0) || (msg == NULL))
3799 		return (VGEN_FAILURE);
3800 
3801 	if (!caller_holds_lock) {
3802 		mutex_enter(&ldcp->wrlock);
3803 	}
3804 
3805 	if (tagp->vio_subtype == VIO_SUBTYPE_INFO) {
3806 		if (tagp->vio_subtype_env == VIO_DRING_DATA) {
3807 			dmsg = (vio_dring_msg_t *)tagp;
3808 			dmsg->seq_num = ldcp->next_txseq;
3809 			data_msg = B_TRUE;
3810 		} else if (tagp->vio_subtype_env == VIO_PKT_DATA) {
3811 			rmsg = (vio_raw_data_msg_t *)tagp;
3812 			rmsg->seq_num = ldcp->next_txseq;
3813 			data_msg = B_TRUE;
3814 		}
3815 	}
3816 
3817 	do {
3818 		len = msglen;
3819 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
3820 		if (retries++ >= vgen_ldcwr_retries)
3821 			break;
3822 	} while (rv == EWOULDBLOCK);
3823 
3824 	if (rv == 0 && data_msg == B_TRUE) {
3825 		ldcp->next_txseq++;
3826 	}
3827 
3828 	if (!caller_holds_lock) {
3829 		mutex_exit(&ldcp->wrlock);
3830 	}
3831 
3832 	if (rv != 0) {
3833 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d)\n",
3834 		    rv, msglen);
3835 		return (rv);
3836 	}
3837 
3838 	if (len != msglen) {
3839 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n",
3840 		    rv, msglen);
3841 		return (VGEN_FAILURE);
3842 	}
3843 
3844 	return (VGEN_SUCCESS);
3845 }
3846 
3847 /* send version negotiate message to the peer over ldc */
3848 static int
3849 vgen_send_version_negotiate(vgen_ldc_t *ldcp)
3850 {
3851 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
3852 	vio_ver_msg_t	vermsg;
3853 	vio_msg_tag_t	*tagp = &vermsg.tag;
3854 	int		rv;
3855 
3856 	bzero(&vermsg, sizeof (vermsg));
3857 
3858 	tagp->vio_msgtype = VIO_TYPE_CTRL;
3859 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
3860 	tagp->vio_subtype_env = VIO_VER_INFO;
3861 	tagp->vio_sid = ldcp->local_sid;
3862 
3863 	/* get version msg payload from ldcp->local */
3864 	vermsg.ver_major = ldcp->local_hparams.ver_major;
3865 	vermsg.ver_minor = ldcp->local_hparams.ver_minor;
3866 	vermsg.dev_class = ldcp->local_hparams.dev_class;
3867 
3868 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
3869 	if (rv != VGEN_SUCCESS) {
3870 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
3871 		return (rv);
3872 	}
3873 
3874 	ldcp->hstate |= VER_INFO_SENT;
3875 	DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n",
3876 	    vermsg.ver_major, vermsg.ver_minor);
3877 
3878 	return (VGEN_SUCCESS);
3879 }
3880 
3881 /* send attr info message to the peer over ldc */
3882 static int
3883 vgen_send_attr_info(vgen_ldc_t *ldcp)
3884 {
3885 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
3886 	vnet_attr_msg_t	attrmsg;
3887 	vio_msg_tag_t	*tagp = &attrmsg.tag;
3888 	int		rv;
3889 
3890 	bzero(&attrmsg, sizeof (attrmsg));
3891 
3892 	tagp->vio_msgtype = VIO_TYPE_CTRL;
3893 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
3894 	tagp->vio_subtype_env = VIO_ATTR_INFO;
3895 	tagp->vio_sid = ldcp->local_sid;
3896 
3897 	/* get attr msg payload from ldcp->local */
3898 	attrmsg.mtu = ldcp->local_hparams.mtu;
3899 	attrmsg.addr = ldcp->local_hparams.addr;
3900 	attrmsg.addr_type = ldcp->local_hparams.addr_type;
3901 	attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
3902 	attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
3903 
3904 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
3905 	if (rv != VGEN_SUCCESS) {
3906 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
3907 		return (rv);
3908 	}
3909 
3910 	ldcp->hstate |= ATTR_INFO_SENT;
3911 	DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n");
3912 
3913 	return (VGEN_SUCCESS);
3914 }
3915 
3916 /* send descriptor ring register message to the peer over ldc */
3917 static int
3918 vgen_send_dring_reg(vgen_ldc_t *ldcp)
3919 {
3920 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
3921 	vio_dring_reg_msg_t	msg;
3922 	vio_msg_tag_t		*tagp = &msg.tag;
3923 	int		rv;
3924 
3925 	bzero(&msg, sizeof (msg));
3926 
3927 	tagp->vio_msgtype = VIO_TYPE_CTRL;
3928 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
3929 	tagp->vio_subtype_env = VIO_DRING_REG;
3930 	tagp->vio_sid = ldcp->local_sid;
3931 
3932 	/* get dring info msg payload from ldcp->local */
3933 	bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie),
3934 	    sizeof (ldc_mem_cookie_t));
3935 	msg.ncookies = ldcp->local_hparams.num_dcookies;
3936 	msg.num_descriptors = ldcp->local_hparams.num_desc;
3937 	msg.descriptor_size = ldcp->local_hparams.desc_size;
3938 
3939 	/*
3940 	 * dring_ident is set to 0. After mapping the dring, peer sets this
3941 	 * value and sends it in the ack, which is saved in
3942 	 * vgen_handle_dring_reg().
3943 	 */
3944 	msg.dring_ident = 0;
3945 
3946 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE);
3947 	if (rv != VGEN_SUCCESS) {
3948 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
3949 		return (rv);
3950 	}
3951 
3952 	ldcp->hstate |= DRING_INFO_SENT;
3953 	DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
3954 
3955 	return (VGEN_SUCCESS);
3956 }
3957 
3958 static int
3959 vgen_send_rdx_info(vgen_ldc_t *ldcp)
3960 {
3961 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
3962 	vio_rdx_msg_t	rdxmsg;
3963 	vio_msg_tag_t	*tagp = &rdxmsg.tag;
3964 	int		rv;
3965 
3966 	bzero(&rdxmsg, sizeof (rdxmsg));
3967 
3968 	tagp->vio_msgtype = VIO_TYPE_CTRL;
3969 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
3970 	tagp->vio_subtype_env = VIO_RDX;
3971 	tagp->vio_sid = ldcp->local_sid;
3972 
3973 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
3974 	if (rv != VGEN_SUCCESS) {
3975 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
3976 		return (rv);
3977 	}
3978 
3979 	ldcp->hstate |= RDX_INFO_SENT;
3980 	DBG2(vgenp, ldcp, "RDX_INFO_SENT\n");
3981 
3982 	return (VGEN_SUCCESS);
3983 }
3984 
3985 /* send descriptor ring data message to the peer over ldc */
3986 static int
3987 vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
3988 {
3989 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
3990 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
3991 	vio_msg_tag_t	*tagp = &msgp->tag;
3992 	vgen_stats_t	*statsp = &ldcp->stats;
3993 	int		rv;
3994 
3995 	bzero(msgp, sizeof (*msgp));
3996 
3997 	tagp->vio_msgtype = VIO_TYPE_DATA;
3998 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
3999 	tagp->vio_subtype_env = VIO_DRING_DATA;
4000 	tagp->vio_sid = ldcp->local_sid;
4001 
4002 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
4003 	msgp->start_idx = start;
4004 	msgp->end_idx = end;
4005 
4006 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE);
4007 	if (rv != VGEN_SUCCESS) {
4008 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
4009 		return (rv);
4010 	}
4011 
4012 	statsp->dring_data_msgs++;
4013 
4014 	DBG2(vgenp, ldcp, "DRING_DATA_SENT \n");
4015 
4016 	return (VGEN_SUCCESS);
4017 }
4018 
4019 /* send multicast addr info message to vsw */
4020 static int
4021 vgen_send_mcast_info(vgen_ldc_t *ldcp)
4022 {
4023 	vnet_mcast_msg_t	mcastmsg;
4024 	vnet_mcast_msg_t	*msgp;
4025 	vio_msg_tag_t		*tagp;
4026 	vgen_t			*vgenp;
4027 	struct ether_addr	*mca;
4028 	int			rv;
4029 	int			i;
4030 	uint32_t		size;
4031 	uint32_t		mccount;
4032 	uint32_t		n;
4033 
4034 	msgp = &mcastmsg;
4035 	tagp = &msgp->tag;
4036 	vgenp = LDC_TO_VGEN(ldcp);
4037 
4038 	mccount = vgenp->mccount;
4039 	i = 0;
4040 
4041 	do {
4042 		tagp->vio_msgtype = VIO_TYPE_CTRL;
4043 		tagp->vio_subtype = VIO_SUBTYPE_INFO;
4044 		tagp->vio_subtype_env = VNET_MCAST_INFO;
4045 		tagp->vio_sid = ldcp->local_sid;
4046 
4047 		n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
4048 		size = n * sizeof (struct ether_addr);
4049 
4050 		mca = &(vgenp->mctab[i]);
4051 		bcopy(mca, (msgp->mca), size);
4052 		msgp->set = B_TRUE;
4053 		msgp->count = n;
4054 
4055 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
4056 		    B_FALSE);
4057 		if (rv != VGEN_SUCCESS) {
4058 			DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv);
4059 			return (rv);
4060 		}
4061 
4062 		mccount -= n;
4063 		i += n;
4064 
4065 	} while (mccount);
4066 
4067 	return (VGEN_SUCCESS);
4068 }
4069 
4070 /* Initiate Phase 2 of handshake */
4071 static int
4072 vgen_handshake_phase2(vgen_ldc_t *ldcp)
4073 {
4074 	int rv;
4075 	uint32_t ncookies = 0;
4076 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
4077 
4078 #ifdef DEBUG
4079 	if (vgen_hdbg & HDBG_OUT_STATE) {
4080 		/* simulate out of state condition */
4081 		vgen_hdbg &= ~(HDBG_OUT_STATE);
4082 		rv = vgen_send_rdx_info(ldcp);
4083 		return (rv);
4084 	}
4085 	if (vgen_hdbg & HDBG_TIMEOUT) {
4086 		/* simulate timeout condition */
4087 		vgen_hdbg &= ~(HDBG_TIMEOUT);
4088 		return (VGEN_SUCCESS);
4089 	}
4090 #endif
4091 	rv = vgen_send_attr_info(ldcp);
4092 	if (rv != VGEN_SUCCESS) {
4093 		return (rv);
4094 	}
4095 
4096 	/* Bind descriptor ring to the channel */
4097 	if (ldcp->num_txdcookies == 0) {
4098 		rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle,
4099 		    LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW,
4100 		    &ldcp->tx_dcookie, &ncookies);
4101 		if (rv != 0) {
4102 			DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed "
4103 			    "rv(%x)\n", rv);
4104 			return (rv);
4105 		}
4106 		ASSERT(ncookies == 1);
4107 		ldcp->num_txdcookies = ncookies;
4108 	}
4109 
4110 	/* update local dring_info params */
4111 	bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie),
4112 	    sizeof (ldc_mem_cookie_t));
4113 	ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies;
4114 	ldcp->local_hparams.num_desc = ldcp->num_txds;
4115 	ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
4116 
4117 	rv = vgen_send_dring_reg(ldcp);
4118 	if (rv != VGEN_SUCCESS) {
4119 		return (rv);
4120 	}
4121 
4122 	return (VGEN_SUCCESS);
4123 }
4124 
4125 /*
4126  * Set vnet-protocol-version dependent functions based on version.
4127  */
4128 static void
4129 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp)
4130 {
4131 	vgen_hparams_t	*lp = &ldcp->local_hparams;
4132 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
4133 
4134 	if (VGEN_VER_GTEQ(ldcp, 1, 3)) {
4135 
4136 		/*
4137 		 * If the version negotiated with peer is >= 1.3,
4138 		 * set the mtu in our attributes to max_frame_size.
4139 		 */
4140 		lp->mtu = vgenp->max_frame_size;
4141 	} else {
4142 		vgen_port_t	*portp = ldcp->portp;
4143 		vnet_t		*vnetp = vgenp->vnetp;
4144 		/*
4145 		 * Pre-1.3 peers expect max frame size of ETHERMAX.
4146 		 * We can negotiate that size with those peers provided the
4147 		 * following conditions are true:
4148 		 * - Our max_frame_size is greater only by VLAN_TAGSZ (4).
4149 		 * - Only pvid is defined for our peer and there are no vids.
4150 		 * - pvids are equal.
4151 		 * If the above conditions are true, then we can send/recv only
4152 		 * untagged frames of max size ETHERMAX.
4153 		 */
4154 		if ((vgenp->max_frame_size == ETHERMAX + VLAN_TAGSZ) &&
4155 		    portp->nvids == 0 && portp->pvid == vnetp->pvid) {
4156 			lp->mtu = ETHERMAX;
4157 		}
4158 	}
4159 
4160 	if (VGEN_VER_GTEQ(ldcp, 1, 2)) {
4161 		/* Versions >= 1.2 */
4162 
4163 		if (VGEN_PRI_ETH_DEFINED(vgenp)) {
4164 			/*
4165 			 * enable priority routines and pkt mode only if
4166 			 * at least one pri-eth-type is specified in MD.
4167 			 */
4168 
4169 			ldcp->tx = vgen_ldcsend;
4170 			ldcp->rx_pktdata = vgen_handle_pkt_data;
4171 
4172 			/* set xfer mode for vgen_send_attr_info() */
4173 			lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
4174 
4175 		} else {
4176 			/* no priority eth types defined in MD */
4177 
4178 			ldcp->tx = vgen_ldcsend_dring;
4179 			ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
4180 
4181 			/* set xfer mode for vgen_send_attr_info() */
4182 			lp->xfer_mode = VIO_DRING_MODE_V1_2;
4183 
4184 		}
4185 	} else {
4186 		/* Versions prior to 1.2  */
4187 
4188 		vgen_reset_vnet_proto_ops(ldcp);
4189 	}
4190 }
4191 
4192 /*
4193  * Reset vnet-protocol-version dependent functions to pre-v1.2.
4194  */
4195 static void
4196 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp)
4197 {
4198 	vgen_hparams_t	*lp = &ldcp->local_hparams;
4199 
4200 	ldcp->tx = vgen_ldcsend_dring;
4201 	ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
4202 
4203 	/* set xfer mode for vgen_send_attr_info() */
4204 	lp->xfer_mode = VIO_DRING_MODE_V1_0;
4205 }
4206 
4207 static void
4208 vgen_vlan_unaware_port_reset(vgen_port_t *portp)
4209 {
4210 	vgen_ldclist_t	*ldclp;
4211 	vgen_ldc_t	*ldcp;
4212 	vgen_t		*vgenp = portp->vgenp;
4213 	vnet_t		*vnetp = vgenp->vnetp;
4214 
4215 	ldclp = &portp->ldclist;
4216 
4217 	READ_ENTER(&ldclp->rwlock);
4218 
4219 	/*
4220 	 * NOTE: for now, we will assume we have a single channel.
4221 	 */
4222 	if (ldclp->headp == NULL) {
4223 		RW_EXIT(&ldclp->rwlock);
4224 		return;
4225 	}
4226 	ldcp = ldclp->headp;
4227 
4228 	mutex_enter(&ldcp->cblock);
4229 
4230 	/*
4231 	 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
4232 	 * the connection. See comments in vgen_set_vnet_proto_ops().
4233 	 */
4234 	if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) &&
4235 	    (portp->nvids != 0 || portp->pvid != vnetp->pvid)) {
4236 		ldcp->need_ldc_reset = B_TRUE;
4237 		vgen_handshake_retry(ldcp);
4238 	}
4239 
4240 	mutex_exit(&ldcp->cblock);
4241 
4242 	RW_EXIT(&ldclp->rwlock);
4243 }
4244 
4245 static void
4246 vgen_reset_vlan_unaware_ports(vgen_t *vgenp)
4247 {
4248 	vgen_port_t	*portp;
4249 	vgen_portlist_t	*plistp;
4250 
4251 	plistp = &(vgenp->vgenports);
4252 	READ_ENTER(&plistp->rwlock);
4253 
4254 	for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
4255 
4256 		vgen_vlan_unaware_port_reset(portp);
4257 
4258 	}
4259 
4260 	RW_EXIT(&plistp->rwlock);
4261 }
4262 
4263 /*
4264  * This function resets the handshake phase to VH_PHASE0(pre-handshake phase).
4265  * This can happen after a channel comes up (status: LDC_UP) or
4266  * when handshake gets terminated due to various conditions.
4267  */
4268 static void
4269 vgen_reset_hphase(vgen_ldc_t *ldcp)
4270 {
4271 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
4272 	ldc_status_t istatus;
4273 	int rv;
4274 
4275 	DBG1(vgenp, ldcp, "enter\n");
4276 	/* reset hstate and hphase */
4277 	ldcp->hstate = 0;
4278 	ldcp->hphase = VH_PHASE0;
4279 
4280 	vgen_reset_vnet_proto_ops(ldcp);
4281 
4282 	/*
4283 	 * Save the id of pending handshake timer in cancel_htid.
4284 	 * This will be checked in vgen_ldc_cb() and the handshake timer will
4285 	 * be cancelled after releasing cblock.
4286 	 */
4287 	if (ldcp->htid) {
4288 		ldcp->cancel_htid = ldcp->htid;
4289 		ldcp->htid = 0;
4290 	}
4291 
4292 	if (ldcp->local_hparams.dring_ready) {
4293 		ldcp->local_hparams.dring_ready = B_FALSE;
4294 	}
4295 
4296 	/* Unbind tx descriptor ring from the channel */
4297 	if (ldcp->num_txdcookies) {
4298 		rv = ldc_mem_dring_unbind(ldcp->tx_dhandle);
4299 		if (rv != 0) {
4300 			DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n");
4301 		}
4302 		ldcp->num_txdcookies = 0;
4303 	}
4304 
4305 	if (ldcp->peer_hparams.dring_ready) {
4306 		ldcp->peer_hparams.dring_ready = B_FALSE;
4307 		/* Unmap peer's dring */
4308 		(void) ldc_mem_dring_unmap(ldcp->rx_dhandle);
4309 		vgen_clobber_rxds(ldcp);
4310 	}
4311 
4312 	vgen_clobber_tbufs(ldcp);
4313 
4314 	/*
4315 	 * clear local handshake params and initialize.
4316 	 */
4317 	bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
4318 
4319 	/* set version to the highest version supported */
4320 	ldcp->local_hparams.ver_major =
4321 	    ldcp->vgen_versions[0].ver_major;
4322 	ldcp->local_hparams.ver_minor =
4323 	    ldcp->vgen_versions[0].ver_minor;
4324 	ldcp->local_hparams.dev_class = VDEV_NETWORK;
4325 
4326 	/* set attr_info params */
4327 	ldcp->local_hparams.mtu = vgenp->max_frame_size;
4328 	ldcp->local_hparams.addr =
4329 	    vnet_macaddr_strtoul(vgenp->macaddr);
4330 	ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
4331 	ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0;
4332 	ldcp->local_hparams.ack_freq = 0;	/* don't need acks */
4333 
4334 	/*
4335 	 * Note: dring is created, but not bound yet.
4336 	 * local dring_info params will be updated when we bind the dring in
4337 	 * vgen_handshake_phase2().
4338 	 * dring_ident is set to 0. After mapping the dring, peer sets this
4339 	 * value and sends it in the ack, which is saved in
4340 	 * vgen_handle_dring_reg().
4341 	 */
4342 	ldcp->local_hparams.dring_ident = 0;
4343 
4344 	/* clear peer_hparams */
4345 	bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
4346 
4347 	/* reset the channel if required */
4348 	if (ldcp->need_ldc_reset) {
4349 		DWARN(vgenp, ldcp, "Doing Channel Reset...\n");
4350 		ldcp->need_ldc_reset = B_FALSE;
4351 		(void) ldc_down(ldcp->ldc_handle);
4352 		(void) ldc_status(ldcp->ldc_handle, &istatus);
4353 		DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus);
4354 		ldcp->ldc_status = istatus;
4355 
4356 		/* clear sids */
4357 		ldcp->local_sid = 0;
4358 		ldcp->peer_sid = 0;
4359 
4360 		/* try to bring the channel up */
4361 		rv = ldc_up(ldcp->ldc_handle);
4362 		if (rv != 0) {
4363 			DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
4364 		}
4365 
4366 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
4367 			DWARN(vgenp, ldcp, "ldc_status err\n");
4368 		} else {
4369 			ldcp->ldc_status = istatus;
4370 		}
4371 	}
4372 }
4373 
4374 /* wrapper function for vgen_reset_hphase */
4375 static void
4376 vgen_handshake_reset(vgen_ldc_t *ldcp)
4377 {
4378 	ASSERT(MUTEX_HELD(&ldcp->cblock));
4379 	mutex_enter(&ldcp->rxlock);
4380 	mutex_enter(&ldcp->wrlock);
4381 	mutex_enter(&ldcp->txlock);
4382 	mutex_enter(&ldcp->tclock);
4383 
4384 	vgen_reset_hphase(ldcp);
4385 
4386 	mutex_exit(&ldcp->tclock);
4387 	mutex_exit(&ldcp->txlock);
4388 	mutex_exit(&ldcp->wrlock);
4389 	mutex_exit(&ldcp->rxlock);
4390 }
4391 
4392 /*
4393  * Initiate handshake with the peer by sending various messages
4394  * based on the handshake-phase that the channel is currently in.
4395  */
4396 static void
4397 vgen_handshake(vgen_ldc_t *ldcp)
4398 {
4399 	uint32_t hphase = ldcp->hphase;
4400 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
4401 	ldc_status_t	istatus;
4402 	int	rv = 0;
4403 
4404 	switch (hphase) {
4405 
4406 	case VH_PHASE1:
4407 
4408 		/*
4409 		 * start timer, for entire handshake process, turn this timer
4410 		 * off if all phases of handshake complete successfully and
4411 		 * hphase goes to VH_DONE(below) or
4412 		 * vgen_reset_hphase() gets called or
4413 		 * channel is reset due to errors or
4414 		 * vgen_ldc_uninit() is invoked(vgen_stop).
4415 		 */
4416 		ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
4417 		    drv_usectohz(vgen_hwd_interval * MICROSEC));
4418 
4419 		/* Phase 1 involves negotiating the version */
4420 		rv = vgen_send_version_negotiate(ldcp);
4421 		break;
4422 
4423 	case VH_PHASE2:
4424 		rv = vgen_handshake_phase2(ldcp);
4425 		break;
4426 
4427 	case VH_PHASE3:
4428 		rv = vgen_send_rdx_info(ldcp);
4429 		break;
4430 
4431 	case VH_DONE:
4432 		/*
4433 		 * Save the id of pending handshake timer in cancel_htid.
4434 		 * This will be checked in vgen_ldc_cb() and the handshake
4435 		 * timer will be cancelled after releasing cblock.
4436 		 */
4437 		if (ldcp->htid) {
4438 			ldcp->cancel_htid = ldcp->htid;
4439 			ldcp->htid = 0;
4440 		}
4441 		ldcp->hretries = 0;
4442 		DBG1(vgenp, ldcp, "Handshake Done\n");
4443 
4444 		if (ldcp->portp == vgenp->vsw_portp) {
4445 			/*
4446 			 * If this channel(port) is connected to vsw,
4447 			 * need to sync multicast table with vsw.
4448 			 */
4449 			mutex_exit(&ldcp->cblock);
4450 
4451 			mutex_enter(&vgenp->lock);
4452 			rv = vgen_send_mcast_info(ldcp);
4453 			mutex_exit(&vgenp->lock);
4454 
4455 			mutex_enter(&ldcp->cblock);
4456 			if (rv != VGEN_SUCCESS)
4457 				break;
4458 		}
4459 
4460 		/*
4461 		 * Check if mac layer should be notified to restart
4462 		 * transmissions. This can happen if the channel got
4463 		 * reset and vgen_clobber_tbufs() is called, while
4464 		 * need_resched is set.
4465 		 */
4466 		mutex_enter(&ldcp->tclock);
4467 		if (ldcp->need_resched) {
4468 			vio_net_tx_update_t vtx_update =
4469 			    ldcp->portp->vcb.vio_net_tx_update;
4470 
4471 			ldcp->need_resched = B_FALSE;
4472 			vtx_update(ldcp->portp->vhp);
4473 		}
4474 		mutex_exit(&ldcp->tclock);
4475 
4476 		break;
4477 
4478 	default:
4479 		break;
4480 	}
4481 
4482 	if (rv == ECONNRESET) {
4483 		if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
4484 			DWARN(vgenp, ldcp, "ldc_status err\n");
4485 		} else {
4486 			ldcp->ldc_status = istatus;
4487 		}
4488 		vgen_handle_evt_reset(ldcp);
4489 	} else if (rv) {
4490 		vgen_handshake_reset(ldcp);
4491 	}
4492 }
4493 
4494 /*
4495  * Check if the current handshake phase has completed successfully and
4496  * return the status.
4497  */
4498 static int
4499 vgen_handshake_done(vgen_ldc_t *ldcp)
4500 {
4501 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
4502 	uint32_t	hphase = ldcp->hphase;
4503 	int 		status = 0;
4504 
4505 	switch (hphase) {
4506 
4507 	case VH_PHASE1:
4508 		/*
4509 		 * Phase1 is done, if version negotiation
4510 		 * completed successfully.
4511 		 */
4512 		status = ((ldcp->hstate & VER_NEGOTIATED) ==
4513 		    VER_NEGOTIATED);
4514 		break;
4515 
4516 	case VH_PHASE2:
4517 		/*
4518 		 * Phase 2 is done, if attr info and dring info
4519 		 * have been exchanged successfully.
4520 		 */
4521 		status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
4522 		    ATTR_INFO_EXCHANGED) &&
4523 		    ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
4524 		    DRING_INFO_EXCHANGED));
4525 		break;
4526 
4527 	case VH_PHASE3:
4528 		/* Phase 3 is done, if rdx msg has been exchanged */
4529 		status = ((ldcp->hstate & RDX_EXCHANGED) ==
4530 		    RDX_EXCHANGED);
4531 		break;
4532 
4533 	default:
4534 		break;
4535 	}
4536 
4537 	if (status == 0) {
4538 		return (VGEN_FAILURE);
4539 	}
4540 	DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase);
4541 	return (VGEN_SUCCESS);
4542 }
4543 
4544 /* retry handshake on failure */
4545 static void
4546 vgen_handshake_retry(vgen_ldc_t *ldcp)
4547 {
4548 	/* reset handshake phase */
4549 	vgen_handshake_reset(ldcp);
4550 
4551 	/* handshake retry is specified and the channel is UP */
4552 	if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) {
4553 		if (ldcp->hretries++ < vgen_max_hretries) {
4554 			ldcp->local_sid = ddi_get_lbolt();
4555 			vgen_handshake(vh_nextphase(ldcp));
4556 		}
4557 	}
4558 }
4559 
4560 /*
4561  * Handle a version info msg from the peer or an ACK/NACK from the peer
4562  * to a version info msg that we sent.
4563  */
4564 static int
4565 vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4566 {
4567 	vgen_t		*vgenp;
4568 	vio_ver_msg_t	*vermsg = (vio_ver_msg_t *)tagp;
4569 	int		ack = 0;
4570 	int		failed = 0;
4571 	int		idx;
4572 	vgen_ver_t	*versions = ldcp->vgen_versions;
4573 	int		rv = 0;
4574 
4575 	vgenp = LDC_TO_VGEN(ldcp);
4576 	DBG1(vgenp, ldcp, "enter\n");
4577 	switch (tagp->vio_subtype) {
4578 	case VIO_SUBTYPE_INFO:
4579 
4580 		/*  Cache sid of peer if this is the first time */
4581 		if (ldcp->peer_sid == 0) {
4582 			DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n",
4583 			    tagp->vio_sid);
4584 			ldcp->peer_sid = tagp->vio_sid;
4585 		}
4586 
4587 		if (ldcp->hphase != VH_PHASE1) {
4588 			/*
4589 			 * If we are not already in VH_PHASE1, reset to
4590 			 * pre-handshake state, and initiate handshake
4591 			 * to the peer too.
4592 			 */
4593 			vgen_handshake_reset(ldcp);
4594 			vgen_handshake(vh_nextphase(ldcp));
4595 		}
4596 		ldcp->hstate |= VER_INFO_RCVD;
4597 
4598 		/* save peer's requested values */
4599 		ldcp->peer_hparams.ver_major = vermsg->ver_major;
4600 		ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
4601 		ldcp->peer_hparams.dev_class = vermsg->dev_class;
4602 
4603 		if ((vermsg->dev_class != VDEV_NETWORK) &&
4604 		    (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
4605 			/* unsupported dev_class, send NACK */
4606 
4607 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
4608 
4609 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
4610 			tagp->vio_sid = ldcp->local_sid;
4611 			/* send reply msg back to peer */
4612 			rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
4613 			    sizeof (*vermsg), B_FALSE);
4614 			if (rv != VGEN_SUCCESS) {
4615 				return (rv);
4616 			}
4617 			return (VGEN_FAILURE);
4618 		}
4619 
4620 		DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n",
4621 		    vermsg->ver_major,  vermsg->ver_minor);
4622 
4623 		idx = 0;
4624 
4625 		for (;;) {
4626 
4627 			if (vermsg->ver_major > versions[idx].ver_major) {
4628 
4629 				/* nack with next lower version */
4630 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
4631 				vermsg->ver_major = versions[idx].ver_major;
4632 				vermsg->ver_minor = versions[idx].ver_minor;
4633 				break;
4634 			}
4635 
4636 			if (vermsg->ver_major == versions[idx].ver_major) {
4637 
4638 				/* major version match - ACK version */
4639 				tagp->vio_subtype = VIO_SUBTYPE_ACK;
4640 				ack = 1;
4641 
4642 				/*
4643 				 * lower minor version to the one this endpt
4644 				 * supports, if necessary
4645 				 */
4646 				if (vermsg->ver_minor >
4647 				    versions[idx].ver_minor) {
4648 					vermsg->ver_minor =
4649 					    versions[idx].ver_minor;
4650 					ldcp->peer_hparams.ver_minor =
4651 					    versions[idx].ver_minor;
4652 				}
4653 				break;
4654 			}
4655 
4656 			idx++;
4657 
4658 			if (idx == VGEN_NUM_VER) {
4659 
4660 				/* no version match - send NACK */
4661 				tagp->vio_subtype = VIO_SUBTYPE_NACK;
4662 				vermsg->ver_major = 0;
4663 				vermsg->ver_minor = 0;
4664 				failed = 1;
4665 				break;
4666 			}
4667 
4668 		}
4669 
4670 		tagp->vio_sid = ldcp->local_sid;
4671 
4672 		/* send reply msg back to peer */
4673 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
4674 		    B_FALSE);
4675 		if (rv != VGEN_SUCCESS) {
4676 			return (rv);
4677 		}
4678 
4679 		if (ack) {
4680 			ldcp->hstate |= VER_ACK_SENT;
4681 			DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n",
4682 			    vermsg->ver_major, vermsg->ver_minor);
4683 		}
4684 		if (failed) {
4685 			DWARN(vgenp, ldcp, "Negotiation Failed\n");
4686 			return (VGEN_FAILURE);
4687 		}
4688 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
4689 
4690 			/*  VER_ACK_SENT and VER_ACK_RCVD */
4691 
4692 			/* local and peer versions match? */
4693 			ASSERT((ldcp->local_hparams.ver_major ==
4694 			    ldcp->peer_hparams.ver_major) &&
4695 			    (ldcp->local_hparams.ver_minor ==
4696 			    ldcp->peer_hparams.ver_minor));
4697 
4698 			vgen_set_vnet_proto_ops(ldcp);
4699 
4700 			/* move to the next phase */
4701 			vgen_handshake(vh_nextphase(ldcp));
4702 		}
4703 
4704 		break;
4705 
4706 	case VIO_SUBTYPE_ACK:
4707 
4708 		if (ldcp->hphase != VH_PHASE1) {
4709 			/*  This should not happen. */
4710 			DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
4711 			return (VGEN_FAILURE);
4712 		}
4713 
4714 		/* SUCCESS - we have agreed on a version */
4715 		ldcp->local_hparams.ver_major = vermsg->ver_major;
4716 		ldcp->local_hparams.ver_minor = vermsg->ver_minor;
4717 		ldcp->hstate |= VER_ACK_RCVD;
4718 
4719 		DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n",
4720 		    vermsg->ver_major,  vermsg->ver_minor);
4721 
4722 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
4723 
4724 			/*  VER_ACK_SENT and VER_ACK_RCVD */
4725 
4726 			/* local and peer versions match? */
4727 			ASSERT((ldcp->local_hparams.ver_major ==
4728 			    ldcp->peer_hparams.ver_major) &&
4729 			    (ldcp->local_hparams.ver_minor ==
4730 			    ldcp->peer_hparams.ver_minor));
4731 
4732 			vgen_set_vnet_proto_ops(ldcp);
4733 
4734 			/* move to the next phase */
4735 			vgen_handshake(vh_nextphase(ldcp));
4736 		}
4737 		break;
4738 
4739 	case VIO_SUBTYPE_NACK:
4740 
4741 		if (ldcp->hphase != VH_PHASE1) {
4742 			/*  This should not happen.  */
4743 			DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid "
4744 			"Phase(%u)\n", ldcp->hphase);
4745 			return (VGEN_FAILURE);
4746 		}
4747 
4748 		DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n",
4749 		    vermsg->ver_major, vermsg->ver_minor);
4750 
4751 		/* check if version in NACK is zero */
4752 		if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
4753 			/*
4754 			 * Version Negotiation has failed.
4755 			 */
4756 			DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
4757 			return (VGEN_FAILURE);
4758 		}
4759 
4760 		idx = 0;
4761 
4762 		for (;;) {
4763 
4764 			if (vermsg->ver_major > versions[idx].ver_major) {
4765 				/* select next lower version */
4766 
4767 				ldcp->local_hparams.ver_major =
4768 				    versions[idx].ver_major;
4769 				ldcp->local_hparams.ver_minor =
4770 				    versions[idx].ver_minor;
4771 				break;
4772 			}
4773 
4774 			if (vermsg->ver_major == versions[idx].ver_major) {
4775 				/* major version match */
4776 
4777 				ldcp->local_hparams.ver_major =
4778 				    versions[idx].ver_major;
4779 
4780 				ldcp->local_hparams.ver_minor =
4781 				    versions[idx].ver_minor;
4782 				break;
4783 			}
4784 
4785 			idx++;
4786 
4787 			if (idx == VGEN_NUM_VER) {
4788 				/*
4789 				 * no version match.
4790 				 * Version Negotiation has failed.
4791 				 */
4792 				DWARN(vgenp, ldcp,
4793 				    "Version Negotiation Failed\n");
4794 				return (VGEN_FAILURE);
4795 			}
4796 
4797 		}
4798 
4799 		rv = vgen_send_version_negotiate(ldcp);
4800 		if (rv != VGEN_SUCCESS) {
4801 			return (rv);
4802 		}
4803 
4804 		break;
4805 	}
4806 
4807 	DBG1(vgenp, ldcp, "exit\n");
4808 	return (VGEN_SUCCESS);
4809 }
4810 
4811 /* Check if the attributes are supported */
4812 static int
4813 vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
4814 {
4815 	vgen_hparams_t	*lp = &ldcp->local_hparams;
4816 
4817 	if ((msg->mtu != lp->mtu) ||
4818 	    (msg->addr_type != ADDR_TYPE_MAC) ||
4819 	    (msg->ack_freq > 64) ||
4820 	    (msg->xfer_mode != lp->xfer_mode)) {
4821 		return (VGEN_FAILURE);
4822 	}
4823 
4824 	return (VGEN_SUCCESS);
4825 }
4826 
4827 /*
4828  * Handle an attribute info msg from the peer or an ACK/NACK from the peer
4829  * to an attr info msg that we sent.
4830  */
4831 static int
4832 vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4833 {
4834 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
4835 	vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp;
4836 	int		ack = 0;
4837 	int		rv = 0;
4838 
4839 	DBG1(vgenp, ldcp, "enter\n");
4840 	if (ldcp->hphase != VH_PHASE2) {
4841 		DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d),"
4842 		" Invalid Phase(%u)\n",
4843 		    tagp->vio_subtype, ldcp->hphase);
4844 		return (VGEN_FAILURE);
4845 	}
4846 	switch (tagp->vio_subtype) {
4847 	case VIO_SUBTYPE_INFO:
4848 
4849 		DBG2(vgenp, ldcp, "ATTR_INFO_RCVD \n");
4850 		ldcp->hstate |= ATTR_INFO_RCVD;
4851 
4852 		/* save peer's values */
4853 		ldcp->peer_hparams.mtu = attrmsg->mtu;
4854 		ldcp->peer_hparams.addr = attrmsg->addr;
4855 		ldcp->peer_hparams.addr_type = attrmsg->addr_type;
4856 		ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode;
4857 		ldcp->peer_hparams.ack_freq = attrmsg->ack_freq;
4858 
4859 		if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) {
4860 			/* unsupported attr, send NACK */
4861 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
4862 		} else {
4863 			ack = 1;
4864 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
4865 		}
4866 		tagp->vio_sid = ldcp->local_sid;
4867 
4868 		/* send reply msg back to peer */
4869 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg),
4870 		    B_FALSE);
4871 		if (rv != VGEN_SUCCESS) {
4872 			return (rv);
4873 		}
4874 
4875 		if (ack) {
4876 			ldcp->hstate |= ATTR_ACK_SENT;
4877 			DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n");
4878 		} else {
4879 			/* failed */
4880 			DWARN(vgenp, ldcp, "ATTR_NACK_SENT \n");
4881 			return (VGEN_FAILURE);
4882 		}
4883 
4884 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
4885 			vgen_handshake(vh_nextphase(ldcp));
4886 		}
4887 
4888 		break;
4889 
4890 	case VIO_SUBTYPE_ACK:
4891 
4892 		ldcp->hstate |= ATTR_ACK_RCVD;
4893 
4894 		DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n");
4895 
4896 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
4897 			vgen_handshake(vh_nextphase(ldcp));
4898 		}
4899 		break;
4900 
4901 	case VIO_SUBTYPE_NACK:
4902 
4903 		DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n");
4904 		return (VGEN_FAILURE);
4905 	}
4906 	DBG1(vgenp, ldcp, "exit\n");
4907 	return (VGEN_SUCCESS);
4908 }
4909 
4910 /* Check if the dring info msg is ok */
4911 static int
4912 vgen_check_dring_reg(vio_dring_reg_msg_t *msg)
4913 {
4914 	/* check if msg contents are ok */
4915 	if ((msg->num_descriptors < 128) || (msg->descriptor_size <
4916 	    sizeof (vnet_public_desc_t))) {
4917 		return (VGEN_FAILURE);
4918 	}
4919 	return (VGEN_SUCCESS);
4920 }
4921 
4922 /*
4923  * Handle a descriptor ring register msg from the peer or an ACK/NACK from
4924  * the peer to a dring register msg that we sent.
4925  */
4926 static int
4927 vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
4928 {
4929 	vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp;
4930 	ldc_mem_cookie_t dcookie;
4931 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
4932 	int ack = 0;
4933 	int rv = 0;
4934 
4935 	DBG1(vgenp, ldcp, "enter\n");
4936 	if (ldcp->hphase < VH_PHASE2) {
4937 		/* dring_info can be rcvd in any of the phases after Phase1 */
4938 		DWARN(vgenp, ldcp,
4939 		    "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n",
4940 		    tagp->vio_subtype, ldcp->hphase);
4941 		return (VGEN_FAILURE);
4942 	}
4943 	switch (tagp->vio_subtype) {
4944 	case VIO_SUBTYPE_INFO:
4945 
4946 		DBG2(vgenp, ldcp, "DRING_INFO_RCVD \n");
4947 		ldcp->hstate |= DRING_INFO_RCVD;
4948 		bcopy((msg->cookie), &dcookie, sizeof (dcookie));
4949 
4950 		ASSERT(msg->ncookies == 1);
4951 
4952 		if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) {
4953 			/*
4954 			 * verified dring info msg to be ok,
4955 			 * now try to map the remote dring.
4956 			 */
4957 			rv = vgen_init_rxds(ldcp, msg->num_descriptors,
4958 			    msg->descriptor_size, &dcookie,
4959 			    msg->ncookies);
4960 			if (rv == DDI_SUCCESS) {
4961 				/* now we can ack the peer */
4962 				ack = 1;
4963 			}
4964 		}
4965 		if (ack == 0) {
4966 			/* failed, send NACK */
4967 			tagp->vio_subtype = VIO_SUBTYPE_NACK;
4968 		} else {
4969 			if (!(ldcp->peer_hparams.dring_ready)) {
4970 
4971 				/* save peer's dring_info values */
4972 				bcopy(&dcookie,
4973 				    &(ldcp->peer_hparams.dring_cookie),
4974 				    sizeof (dcookie));
4975 				ldcp->peer_hparams.num_desc =
4976 				    msg->num_descriptors;
4977 				ldcp->peer_hparams.desc_size =
4978 				    msg->descriptor_size;
4979 				ldcp->peer_hparams.num_dcookies =
4980 				    msg->ncookies;
4981 
4982 				/* set dring_ident for the peer */
4983 				ldcp->peer_hparams.dring_ident =
4984 				    (uint64_t)ldcp->rxdp;
4985 				/* return the dring_ident in ack msg */
4986 				msg->dring_ident =
4987 				    (uint64_t)ldcp->rxdp;
4988 
4989 				ldcp->peer_hparams.dring_ready = B_TRUE;
4990 			}
4991 			tagp->vio_subtype = VIO_SUBTYPE_ACK;
4992 		}
4993 		tagp->vio_sid = ldcp->local_sid;
4994 		/* send reply msg back to peer */
4995 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
4996 		    B_FALSE);
4997 		if (rv != VGEN_SUCCESS) {
4998 			return (rv);
4999 		}
5000 
5001 		if (ack) {
5002 			ldcp->hstate |= DRING_ACK_SENT;
5003 			DBG2(vgenp, ldcp, "DRING_ACK_SENT");
5004 		} else {
5005 			DWARN(vgenp, ldcp, "DRING_NACK_SENT");
5006 			return (VGEN_FAILURE);
5007 		}
5008 
5009 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
5010 			vgen_handshake(vh_nextphase(ldcp));
5011 		}
5012 
5013 		break;
5014 
5015 	case VIO_SUBTYPE_ACK:
5016 
5017 		ldcp->hstate |= DRING_ACK_RCVD;
5018 
5019 		DBG2(vgenp, ldcp, "DRING_ACK_RCVD");
5020 
5021 		if (!(ldcp->local_hparams.dring_ready)) {
5022 			/* local dring is now ready */
5023 			ldcp->local_hparams.dring_ready = B_TRUE;
5024 
5025 			/* save dring_ident acked by peer */
5026 			ldcp->local_hparams.dring_ident =
5027 			    msg->dring_ident;
5028 		}
5029 
5030 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
5031 			vgen_handshake(vh_nextphase(ldcp));
5032 		}
5033 
5034 		break;
5035 
5036 	case VIO_SUBTYPE_NACK:
5037 
5038 		DBG2(vgenp, ldcp, "DRING_NACK_RCVD");
5039 		return (VGEN_FAILURE);
5040 	}
5041 	DBG1(vgenp, ldcp, "exit\n");
5042 	return (VGEN_SUCCESS);
5043 }
5044 
5045 /*
5046  * Handle a rdx info msg from the peer or an ACK/NACK
5047  * from the peer to a rdx info msg that we sent.
5048  */
5049 static int
5050 vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5051 {
5052 	int rv = 0;
5053 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
5054 
5055 	DBG1(vgenp, ldcp, "enter\n");
5056 	if (ldcp->hphase != VH_PHASE3) {
5057 		DWARN(vgenp, ldcp,
5058 		    "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n",
5059 		    tagp->vio_subtype, ldcp->hphase);
5060 		return (VGEN_FAILURE);
5061 	}
5062 	switch (tagp->vio_subtype) {
5063 	case VIO_SUBTYPE_INFO:
5064 
5065 		DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n");
5066 		ldcp->hstate |= RDX_INFO_RCVD;
5067 
5068 		tagp->vio_subtype = VIO_SUBTYPE_ACK;
5069 		tagp->vio_sid = ldcp->local_sid;
5070 		/* send reply msg back to peer */
5071 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
5072 		    B_FALSE);
5073 		if (rv != VGEN_SUCCESS) {
5074 			return (rv);
5075 		}
5076 
5077 		ldcp->hstate |= RDX_ACK_SENT;
5078 		DBG2(vgenp, ldcp, "RDX_ACK_SENT \n");
5079 
5080 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
5081 			vgen_handshake(vh_nextphase(ldcp));
5082 		}
5083 
5084 		break;
5085 
5086 	case VIO_SUBTYPE_ACK:
5087 
5088 		ldcp->hstate |= RDX_ACK_RCVD;
5089 
5090 		DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n");
5091 
5092 		if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
5093 			vgen_handshake(vh_nextphase(ldcp));
5094 		}
5095 		break;
5096 
5097 	case VIO_SUBTYPE_NACK:
5098 
5099 		DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n");
5100 		return (VGEN_FAILURE);
5101 	}
5102 	DBG1(vgenp, ldcp, "exit\n");
5103 	return (VGEN_SUCCESS);
5104 }
5105 
5106 /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
5107 static int
5108 vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5109 {
5110 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5111 	vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
5112 	struct ether_addr *addrp;
5113 	int count;
5114 	int i;
5115 
5116 	DBG1(vgenp, ldcp, "enter\n");
5117 	switch (tagp->vio_subtype) {
5118 
5119 	case VIO_SUBTYPE_INFO:
5120 
5121 		/* vnet shouldn't recv set mcast msg, only vsw handles it */
5122 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n");
5123 		break;
5124 
5125 	case VIO_SUBTYPE_ACK:
5126 
5127 		/* success adding/removing multicast addr */
5128 		DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n");
5129 		break;
5130 
5131 	case VIO_SUBTYPE_NACK:
5132 
5133 		DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n");
5134 		if (!(msgp->set)) {
5135 			/* multicast remove request failed */
5136 			break;
5137 		}
5138 
5139 		/* multicast add request failed */
5140 		for (count = 0; count < msgp->count; count++) {
5141 			addrp = &(msgp->mca[count]);
5142 
5143 			/* delete address from the table */
5144 			for (i = 0; i < vgenp->mccount; i++) {
5145 				if (ether_cmp(addrp,
5146 				    &(vgenp->mctab[i])) == 0) {
5147 					if (vgenp->mccount > 1) {
5148 						int t = vgenp->mccount - 1;
5149 						vgenp->mctab[i] =
5150 						    vgenp->mctab[t];
5151 					}
5152 					vgenp->mccount--;
5153 					break;
5154 				}
5155 			}
5156 		}
5157 		break;
5158 
5159 	}
5160 	DBG1(vgenp, ldcp, "exit\n");
5161 
5162 	return (VGEN_SUCCESS);
5163 }
5164 
5165 /* handler for control messages received from the peer ldc end-point */
5166 static int
5167 vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5168 {
5169 	int rv = 0;
5170 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5171 
5172 	DBG1(vgenp, ldcp, "enter\n");
5173 	switch (tagp->vio_subtype_env) {
5174 
5175 	case VIO_VER_INFO:
5176 		rv = vgen_handle_version_negotiate(ldcp, tagp);
5177 		break;
5178 
5179 	case VIO_ATTR_INFO:
5180 		rv = vgen_handle_attr_info(ldcp, tagp);
5181 		break;
5182 
5183 	case VIO_DRING_REG:
5184 		rv = vgen_handle_dring_reg(ldcp, tagp);
5185 		break;
5186 
5187 	case VIO_RDX:
5188 		rv = vgen_handle_rdx_info(ldcp, tagp);
5189 		break;
5190 
5191 	case VNET_MCAST_INFO:
5192 		rv = vgen_handle_mcast_info(ldcp, tagp);
5193 		break;
5194 
5195 	case VIO_DDS_INFO:
5196 		rv = vgen_dds_rx(ldcp, tagp);
5197 		break;
5198 	}
5199 
5200 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5201 	return (rv);
5202 }
5203 
5204 /* handler for data messages received from the peer ldc end-point */
5205 static int
5206 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen)
5207 {
5208 	int rv = 0;
5209 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5210 
5211 	DBG1(vgenp, ldcp, "enter\n");
5212 
5213 	if (ldcp->hphase != VH_DONE)
5214 		return (rv);
5215 
5216 	if (tagp->vio_subtype == VIO_SUBTYPE_INFO) {
5217 		rv = vgen_check_datamsg_seq(ldcp, tagp);
5218 		if (rv != 0) {
5219 			return (rv);
5220 		}
5221 	}
5222 
5223 	switch (tagp->vio_subtype_env) {
5224 	case VIO_DRING_DATA:
5225 		rv = vgen_handle_dring_data(ldcp, tagp);
5226 		break;
5227 
5228 	case VIO_PKT_DATA:
5229 		ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen);
5230 		break;
5231 	default:
5232 		break;
5233 	}
5234 
5235 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5236 	return (rv);
5237 }
5238 
5239 /*
5240  * dummy pkt data handler function for vnet protocol version 1.0
5241  */
5242 static void
5243 vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
5244 {
5245 	_NOTE(ARGUNUSED(arg1, arg2, msglen))
5246 }
5247 
5248 /*
5249  * This function handles raw pkt data messages received over the channel.
5250  * Currently, only priority-eth-type frames are received through this mechanism.
5251  * In this case, the frame(data) is present within the message itself which
5252  * is copied into an mblk before sending it up the stack.
5253  */
5254 static void
5255 vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen)
5256 {
5257 	vgen_ldc_t		*ldcp = (vgen_ldc_t *)arg1;
5258 	vio_raw_data_msg_t	*pkt	= (vio_raw_data_msg_t *)arg2;
5259 	uint32_t		size;
5260 	mblk_t			*mp;
5261 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
5262 	vgen_stats_t		*statsp = &ldcp->stats;
5263 	vgen_hparams_t		*lp = &ldcp->local_hparams;
5264 	vio_net_rx_cb_t		vrx_cb;
5265 
5266 	ASSERT(MUTEX_HELD(&ldcp->cblock));
5267 
5268 	mutex_exit(&ldcp->cblock);
5269 
5270 	size = msglen - VIO_PKT_DATA_HDRSIZE;
5271 	if (size < ETHERMIN || size > lp->mtu) {
5272 		(void) atomic_inc_32(&statsp->rx_pri_fail);
5273 		goto exit;
5274 	}
5275 
5276 	mp = vio_multipool_allocb(&ldcp->vmp, size);
5277 	if (mp == NULL) {
5278 		mp = allocb(size, BPRI_MED);
5279 		if (mp == NULL) {
5280 			(void) atomic_inc_32(&statsp->rx_pri_fail);
5281 			DWARN(vgenp, ldcp, "allocb failure, "
5282 			    "unable to process priority frame\n");
5283 			goto exit;
5284 		}
5285 	}
5286 
5287 	/* copy the frame from the payload of raw data msg into the mblk */
5288 	bcopy(pkt->data, mp->b_rptr, size);
5289 	mp->b_wptr = mp->b_rptr + size;
5290 
5291 	/* update stats */
5292 	(void) atomic_inc_64(&statsp->rx_pri_packets);
5293 	(void) atomic_add_64(&statsp->rx_pri_bytes, size);
5294 
5295 	/* send up; call vrx_cb() as cblock is already released */
5296 	vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
5297 	vrx_cb(ldcp->portp->vhp, mp);
5298 
5299 exit:
5300 	mutex_enter(&ldcp->cblock);
5301 }
5302 
5303 static int
5304 vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
5305     int32_t end, uint8_t pstate)
5306 {
5307 	int rv = 0;
5308 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5309 	vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp;
5310 
5311 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
5312 	tagp->vio_sid = ldcp->local_sid;
5313 	msgp->start_idx = start;
5314 	msgp->end_idx = end;
5315 	msgp->dring_process_state = pstate;
5316 	rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE);
5317 	if (rv != VGEN_SUCCESS) {
5318 		DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
5319 	}
5320 	return (rv);
5321 }
5322 
5323 static int
5324 vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5325 {
5326 	int rv = 0;
5327 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5328 
5329 
5330 	DBG1(vgenp, ldcp, "enter\n");
5331 	switch (tagp->vio_subtype) {
5332 
5333 	case VIO_SUBTYPE_INFO:
5334 		/*
5335 		 * To reduce the locking contention, release the
5336 		 * cblock here and re-acquire it once we are done
5337 		 * receiving packets.
5338 		 */
5339 		mutex_exit(&ldcp->cblock);
5340 		mutex_enter(&ldcp->rxlock);
5341 		rv = vgen_handle_dring_data_info(ldcp, tagp);
5342 		mutex_exit(&ldcp->rxlock);
5343 		mutex_enter(&ldcp->cblock);
5344 		break;
5345 
5346 	case VIO_SUBTYPE_ACK:
5347 		rv = vgen_handle_dring_data_ack(ldcp, tagp);
5348 		break;
5349 
5350 	case VIO_SUBTYPE_NACK:
5351 		rv = vgen_handle_dring_data_nack(ldcp, tagp);
5352 		break;
5353 	}
5354 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5355 	return (rv);
5356 }
5357 
5358 static int
5359 vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5360 {
5361 	uint32_t start;
5362 	int32_t end;
5363 	int rv = 0;
5364 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
5365 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5366 #ifdef VGEN_HANDLE_LOST_PKTS
5367 	vgen_stats_t *statsp = &ldcp->stats;
5368 	uint32_t rxi;
5369 	int n;
5370 #endif
5371 
5372 	DBG1(vgenp, ldcp, "enter\n");
5373 
5374 	start = dringmsg->start_idx;
5375 	end = dringmsg->end_idx;
5376 	/*
5377 	 * received a data msg, which contains the start and end
5378 	 * indices of the descriptors within the rx ring holding data,
5379 	 * the seq_num of data packet corresponding to the start index,
5380 	 * and the dring_ident.
5381 	 * We can now read the contents of each of these descriptors
5382 	 * and gather data from it.
5383 	 */
5384 	DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n",
5385 	    start, end);
5386 
5387 	/* validate rx start and end indeces */
5388 	if (!(CHECK_RXI(start, ldcp)) || ((end != -1) &&
5389 	    !(CHECK_RXI(end, ldcp)))) {
5390 		DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n",
5391 		    start, end);
5392 		/* drop the message if invalid index */
5393 		return (rv);
5394 	}
5395 
5396 	/* validate dring_ident */
5397 	if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
5398 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
5399 		    dringmsg->dring_ident);
5400 		/* invalid dring_ident, drop the msg */
5401 		return (rv);
5402 	}
5403 #ifdef DEBUG
5404 	if (vgen_trigger_rxlost) {
5405 		/* drop this msg to simulate lost pkts for debugging */
5406 		vgen_trigger_rxlost = 0;
5407 		return (rv);
5408 	}
5409 #endif
5410 
5411 #ifdef	VGEN_HANDLE_LOST_PKTS
5412 
5413 	/* receive start index doesn't match expected index */
5414 	if (ldcp->next_rxi != start) {
5415 		DWARN(vgenp, ldcp, "next_rxi(%d) != start(%d)\n",
5416 		    ldcp->next_rxi, start);
5417 
5418 		/* calculate the number of pkts lost */
5419 		if (start >= ldcp->next_rxi) {
5420 			n = start - ldcp->next_rxi;
5421 		} else  {
5422 			n = ldcp->num_rxds - (ldcp->next_rxi - start);
5423 		}
5424 
5425 		statsp->rx_lost_pkts += n;
5426 		tagp->vio_subtype = VIO_SUBTYPE_NACK;
5427 		tagp->vio_sid = ldcp->local_sid;
5428 		/* indicate the range of lost descriptors */
5429 		dringmsg->start_idx = ldcp->next_rxi;
5430 		rxi = start;
5431 		DECR_RXI(rxi, ldcp);
5432 		dringmsg->end_idx = rxi;
5433 		/* dring ident is left unchanged */
5434 		rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
5435 		    sizeof (*dringmsg), B_FALSE);
5436 		if (rv != VGEN_SUCCESS) {
5437 			DWARN(vgenp, ldcp,
5438 			    "vgen_sendmsg failed, stype:NACK\n");
5439 			return (rv);
5440 		}
5441 		/*
5442 		 * treat this range of descrs/pkts as dropped
5443 		 * and set the new expected value of next_rxi
5444 		 * and continue(below) to process from the new
5445 		 * start index.
5446 		 */
5447 		ldcp->next_rxi = start;
5448 	}
5449 
5450 #endif	/* VGEN_HANDLE_LOST_PKTS */
5451 
5452 	/* Now receive messages */
5453 	rv = vgen_process_dring_data(ldcp, tagp);
5454 
5455 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5456 	return (rv);
5457 }
5458 
5459 static int
5460 vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5461 {
5462 	boolean_t set_ack_start = B_FALSE;
5463 	uint32_t start;
5464 	uint32_t ack_end;
5465 	uint32_t next_rxi;
5466 	uint32_t rxi;
5467 	int count = 0;
5468 	int rv = 0;
5469 	uint32_t retries = 0;
5470 	vgen_stats_t *statsp;
5471 	vnet_public_desc_t rxd;
5472 	vio_dring_entry_hdr_t *hdrp;
5473 	mblk_t *bp = NULL;
5474 	mblk_t *bpt = NULL;
5475 	uint32_t ack_start;
5476 	boolean_t rxd_err = B_FALSE;
5477 	mblk_t *mp = NULL;
5478 	size_t nbytes;
5479 	boolean_t ack_needed = B_FALSE;
5480 	size_t nread;
5481 	uint64_t off = 0;
5482 	struct ether_header *ehp;
5483 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
5484 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5485 
5486 	DBG1(vgenp, ldcp, "enter\n");
5487 
5488 	statsp = &ldcp->stats;
5489 	start = dringmsg->start_idx;
5490 
5491 	/*
5492 	 * start processing the descriptors from the specified
5493 	 * start index, up to the index a descriptor is not ready
5494 	 * to be processed or we process the entire descriptor ring
5495 	 * and wrap around upto the start index.
5496 	 */
5497 
5498 	/* need to set the start index of descriptors to be ack'd */
5499 	set_ack_start = B_TRUE;
5500 
5501 	/* index upto which we have ack'd */
5502 	ack_end = start;
5503 	DECR_RXI(ack_end, ldcp);
5504 
5505 	next_rxi = rxi =  start;
5506 	do {
5507 vgen_recv_retry:
5508 		rv = vnet_dring_entry_copy(&(ldcp->rxdp[rxi]), &rxd,
5509 		    ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi);
5510 		if (rv != 0) {
5511 			DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed"
5512 			    " rv(%d)\n", rv);
5513 			statsp->ierrors++;
5514 			return (rv);
5515 		}
5516 
5517 		hdrp = &rxd.hdr;
5518 
5519 		if (hdrp->dstate != VIO_DESC_READY) {
5520 			/*
5521 			 * Before waiting and retry here, send up
5522 			 * the packets that are received already
5523 			 */
5524 			if (bp != NULL) {
5525 				DTRACE_PROBE1(vgen_rcv_msgs, int, count);
5526 				vgen_rx(ldcp, bp);
5527 				count = 0;
5528 				bp = bpt = NULL;
5529 			}
5530 			/*
5531 			 * descriptor is not ready.
5532 			 * retry descriptor acquire, stop processing
5533 			 * after max # retries.
5534 			 */
5535 			if (retries == vgen_recv_retries)
5536 				break;
5537 			retries++;
5538 			drv_usecwait(vgen_recv_delay);
5539 			goto vgen_recv_retry;
5540 		}
5541 		retries = 0;
5542 
5543 		if (set_ack_start) {
5544 			/*
5545 			 * initialize the start index of the range
5546 			 * of descriptors to be ack'd.
5547 			 */
5548 			ack_start = rxi;
5549 			set_ack_start = B_FALSE;
5550 		}
5551 
5552 		if ((rxd.nbytes < ETHERMIN) ||
5553 		    (rxd.ncookies == 0) ||
5554 		    (rxd.ncookies > MAX_COOKIES)) {
5555 			rxd_err = B_TRUE;
5556 		} else {
5557 			/*
5558 			 * Try to allocate an mblk from the free pool
5559 			 * of recv mblks for the channel.
5560 			 * If this fails, use allocb().
5561 			 */
5562 			nbytes = (VNET_IPALIGN + rxd.nbytes + 7) & ~7;
5563 			mp = vio_multipool_allocb(&ldcp->vmp, nbytes);
5564 			if (!mp) {
5565 				/*
5566 				 * The data buffer returned by
5567 				 * allocb(9F) is 8byte aligned. We
5568 				 * allocate extra 8 bytes to ensure
5569 				 * size is multiple of 8 bytes for
5570 				 * ldc_mem_copy().
5571 				 */
5572 				statsp->rx_vio_allocb_fail++;
5573 				mp = allocb(VNET_IPALIGN + rxd.nbytes + 8,
5574 				    BPRI_MED);
5575 			}
5576 		}
5577 		if ((rxd_err) || (mp == NULL)) {
5578 			/*
5579 			 * rxd_err or allocb() failure,
5580 			 * drop this packet, get next.
5581 			 */
5582 			if (rxd_err) {
5583 				statsp->ierrors++;
5584 				rxd_err = B_FALSE;
5585 			} else {
5586 				statsp->rx_allocb_fail++;
5587 			}
5588 
5589 			ack_needed = hdrp->ack;
5590 
5591 			/* set descriptor done bit */
5592 			rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]),
5593 			    ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi,
5594 			    VIO_DESC_DONE);
5595 			if (rv != 0) {
5596 				DWARN(vgenp, ldcp,
5597 				    "vnet_dring_entry_set_dstate err rv(%d)\n",
5598 				    rv);
5599 				return (rv);
5600 			}
5601 
5602 			if (ack_needed) {
5603 				ack_needed = B_FALSE;
5604 				/*
5605 				 * sender needs ack for this packet,
5606 				 * ack pkts upto this index.
5607 				 */
5608 				ack_end = rxi;
5609 
5610 				rv = vgen_send_dring_ack(ldcp, tagp,
5611 				    ack_start, ack_end,
5612 				    VIO_DP_ACTIVE);
5613 				if (rv != VGEN_SUCCESS) {
5614 					goto error_ret;
5615 				}
5616 
5617 				/* need to set new ack start index */
5618 				set_ack_start = B_TRUE;
5619 			}
5620 			goto vgen_next_rxi;
5621 		}
5622 
5623 		nread = nbytes;
5624 		rv = ldc_mem_copy(ldcp->ldc_handle,
5625 		    (caddr_t)mp->b_rptr, off, &nread,
5626 		    rxd.memcookie, rxd.ncookies, LDC_COPY_IN);
5627 
5628 		/* if ldc_mem_copy() failed */
5629 		if (rv) {
5630 			DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv);
5631 			statsp->ierrors++;
5632 			freemsg(mp);
5633 			goto error_ret;
5634 		}
5635 
5636 		ack_needed = hdrp->ack;
5637 
5638 		rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]),
5639 		    ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi,
5640 		    VIO_DESC_DONE);
5641 		if (rv != 0) {
5642 			DWARN(vgenp, ldcp,
5643 			    "vnet_dring_entry_set_dstate err rv(%d)\n", rv);
5644 			goto error_ret;
5645 		}
5646 
5647 		mp->b_rptr += VNET_IPALIGN;
5648 
5649 		if (ack_needed) {
5650 			ack_needed = B_FALSE;
5651 			/*
5652 			 * sender needs ack for this packet,
5653 			 * ack pkts upto this index.
5654 			 */
5655 			ack_end = rxi;
5656 
5657 			rv = vgen_send_dring_ack(ldcp, tagp,
5658 			    ack_start, ack_end, VIO_DP_ACTIVE);
5659 			if (rv != VGEN_SUCCESS) {
5660 				goto error_ret;
5661 			}
5662 
5663 			/* need to set new ack start index */
5664 			set_ack_start = B_TRUE;
5665 		}
5666 
5667 		if (nread != nbytes) {
5668 			DWARN(vgenp, ldcp,
5669 			    "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
5670 			    nread, nbytes);
5671 			statsp->ierrors++;
5672 			freemsg(mp);
5673 			goto vgen_next_rxi;
5674 		}
5675 
5676 		/* point to the actual end of data */
5677 		mp->b_wptr = mp->b_rptr + rxd.nbytes;
5678 
5679 		/* update stats */
5680 		statsp->ipackets++;
5681 		statsp->rbytes += rxd.nbytes;
5682 		ehp = (struct ether_header *)mp->b_rptr;
5683 		if (IS_BROADCAST(ehp))
5684 			statsp->brdcstrcv++;
5685 		else if (IS_MULTICAST(ehp))
5686 			statsp->multircv++;
5687 
5688 		/* build a chain of received packets */
5689 		if (bp == NULL) {
5690 			/* first pkt */
5691 			bp = mp;
5692 			bpt = bp;
5693 			bpt->b_next = NULL;
5694 		} else {
5695 			mp->b_next = NULL;
5696 			bpt->b_next = mp;
5697 			bpt = mp;
5698 		}
5699 
5700 		if (count++ > vgen_chain_len) {
5701 			DTRACE_PROBE1(vgen_rcv_msgs, int, count);
5702 			vgen_rx(ldcp, bp);
5703 			count = 0;
5704 			bp = bpt = NULL;
5705 		}
5706 
5707 vgen_next_rxi:
5708 		/* update end index of range of descrs to be ack'd */
5709 		ack_end = rxi;
5710 
5711 		/* update the next index to be processed */
5712 		INCR_RXI(next_rxi, ldcp);
5713 		if (next_rxi == start) {
5714 			/*
5715 			 * processed the entire descriptor ring upto
5716 			 * the index at which we started.
5717 			 */
5718 			break;
5719 		}
5720 
5721 		rxi = next_rxi;
5722 
5723 	_NOTE(CONSTCOND)
5724 	} while (1);
5725 
5726 	/*
5727 	 * send an ack message to peer indicating that we have stopped
5728 	 * processing descriptors.
5729 	 */
5730 	if (set_ack_start) {
5731 		/*
5732 		 * We have ack'd upto some index and we have not
5733 		 * processed any descriptors beyond that index.
5734 		 * Use the last ack'd index as both the start and
5735 		 * end of range of descrs being ack'd.
5736 		 * Note: This results in acking the last index twice
5737 		 * and should be harmless.
5738 		 */
5739 		ack_start = ack_end;
5740 	}
5741 
5742 	rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end,
5743 	    VIO_DP_STOPPED);
5744 	if (rv != VGEN_SUCCESS) {
5745 		goto error_ret;
5746 	}
5747 
5748 	/* save new recv index of next dring msg */
5749 	ldcp->next_rxi = next_rxi;
5750 
5751 error_ret:
5752 	/* send up packets received so far */
5753 	if (bp != NULL) {
5754 		DTRACE_PROBE1(vgen_rcv_msgs, int, count);
5755 		vgen_rx(ldcp, bp);
5756 		bp = bpt = NULL;
5757 	}
5758 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5759 	return (rv);
5760 
5761 }
5762 
5763 static int
5764 vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5765 {
5766 	int rv = 0;
5767 	uint32_t start;
5768 	int32_t end;
5769 	uint32_t txi;
5770 	boolean_t ready_txd = B_FALSE;
5771 	vgen_stats_t *statsp;
5772 	vgen_private_desc_t *tbufp;
5773 	vnet_public_desc_t *txdp;
5774 	vio_dring_entry_hdr_t *hdrp;
5775 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5776 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
5777 
5778 	DBG1(vgenp, ldcp, "enter\n");
5779 	start = dringmsg->start_idx;
5780 	end = dringmsg->end_idx;
5781 	statsp = &ldcp->stats;
5782 
5783 	/*
5784 	 * received an ack corresponding to a specific descriptor for
5785 	 * which we had set the ACK bit in the descriptor (during
5786 	 * transmit). This enables us to reclaim descriptors.
5787 	 */
5788 
5789 	DBG2(vgenp, ldcp, "ACK:  start(%d), end(%d)\n", start, end);
5790 
5791 	/* validate start and end indeces in the tx ack msg */
5792 	if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
5793 		/* drop the message if invalid index */
5794 		DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n",
5795 		    start, end);
5796 		return (rv);
5797 	}
5798 	/* validate dring_ident */
5799 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
5800 		/* invalid dring_ident, drop the msg */
5801 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
5802 		    dringmsg->dring_ident);
5803 		return (rv);
5804 	}
5805 	statsp->dring_data_acks++;
5806 
5807 	/* reclaim descriptors that are done */
5808 	vgen_reclaim(ldcp);
5809 
5810 	if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
5811 		/*
5812 		 * receiver continued processing descriptors after
5813 		 * sending us the ack.
5814 		 */
5815 		return (rv);
5816 	}
5817 
5818 	statsp->dring_stopped_acks++;
5819 
5820 	/* receiver stopped processing descriptors */
5821 	mutex_enter(&ldcp->wrlock);
5822 	mutex_enter(&ldcp->tclock);
5823 
5824 	/*
5825 	 * determine if there are any pending tx descriptors
5826 	 * ready to be processed by the receiver(peer) and if so,
5827 	 * send a message to the peer to restart receiving.
5828 	 */
5829 	ready_txd = B_FALSE;
5830 
5831 	/*
5832 	 * using the end index of the descriptor range for which
5833 	 * we received the ack, check if the next descriptor is
5834 	 * ready.
5835 	 */
5836 	txi = end;
5837 	INCR_TXI(txi, ldcp);
5838 	tbufp = &ldcp->tbufp[txi];
5839 	txdp = tbufp->descp;
5840 	hdrp = &txdp->hdr;
5841 	if (hdrp->dstate == VIO_DESC_READY) {
5842 		ready_txd = B_TRUE;
5843 	} else {
5844 		/*
5845 		 * descr next to the end of ack'd descr range is not
5846 		 * ready.
5847 		 * starting from the current reclaim index, check
5848 		 * if any descriptor is ready.
5849 		 */
5850 
5851 		txi = ldcp->cur_tbufp - ldcp->tbufp;
5852 		tbufp = &ldcp->tbufp[txi];
5853 
5854 		txdp = tbufp->descp;
5855 		hdrp = &txdp->hdr;
5856 		if (hdrp->dstate == VIO_DESC_READY) {
5857 			ready_txd = B_TRUE;
5858 		}
5859 
5860 	}
5861 
5862 	if (ready_txd) {
5863 		/*
5864 		 * we have tx descriptor(s) ready to be
5865 		 * processed by the receiver.
5866 		 * send a message to the peer with the start index
5867 		 * of ready descriptors.
5868 		 */
5869 		rv = vgen_send_dring_data(ldcp, txi, -1);
5870 		if (rv != VGEN_SUCCESS) {
5871 			ldcp->resched_peer = B_TRUE;
5872 			ldcp->resched_peer_txi = txi;
5873 			mutex_exit(&ldcp->tclock);
5874 			mutex_exit(&ldcp->wrlock);
5875 			return (rv);
5876 		}
5877 	} else {
5878 		/*
5879 		 * no ready tx descriptors. set the flag to send a
5880 		 * message to peer when tx descriptors are ready in
5881 		 * transmit routine.
5882 		 */
5883 		ldcp->resched_peer = B_TRUE;
5884 		ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp;
5885 	}
5886 
5887 	mutex_exit(&ldcp->tclock);
5888 	mutex_exit(&ldcp->wrlock);
5889 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5890 	return (rv);
5891 }
5892 
5893 static int
5894 vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
5895 {
5896 	int rv = 0;
5897 	uint32_t start;
5898 	int32_t end;
5899 	uint32_t txi;
5900 	vnet_public_desc_t *txdp;
5901 	vio_dring_entry_hdr_t *hdrp;
5902 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5903 	vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp;
5904 
5905 	DBG1(vgenp, ldcp, "enter\n");
5906 	start = dringmsg->start_idx;
5907 	end = dringmsg->end_idx;
5908 
5909 	/*
5910 	 * peer sent a NACK msg to indicate lost packets.
5911 	 * The start and end correspond to the range of descriptors
5912 	 * for which the peer didn't receive a dring data msg and so
5913 	 * didn't receive the corresponding data.
5914 	 */
5915 	DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end);
5916 
5917 	/* validate start and end indeces in the tx nack msg */
5918 	if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) {
5919 		/* drop the message if invalid index */
5920 		DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n",
5921 		    start, end);
5922 		return (rv);
5923 	}
5924 	/* validate dring_ident */
5925 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
5926 		/* invalid dring_ident, drop the msg */
5927 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
5928 		    dringmsg->dring_ident);
5929 		return (rv);
5930 	}
5931 	mutex_enter(&ldcp->txlock);
5932 	mutex_enter(&ldcp->tclock);
5933 
5934 	if (ldcp->next_tbufp == ldcp->cur_tbufp) {
5935 		/* no busy descriptors, bogus nack ? */
5936 		mutex_exit(&ldcp->tclock);
5937 		mutex_exit(&ldcp->txlock);
5938 		return (rv);
5939 	}
5940 
5941 	/* we just mark the descrs as done so they can be reclaimed */
5942 	for (txi = start; txi <= end; ) {
5943 		txdp = &(ldcp->txdp[txi]);
5944 		hdrp = &txdp->hdr;
5945 		if (hdrp->dstate == VIO_DESC_READY)
5946 			hdrp->dstate = VIO_DESC_DONE;
5947 		INCR_TXI(txi, ldcp);
5948 	}
5949 	mutex_exit(&ldcp->tclock);
5950 	mutex_exit(&ldcp->txlock);
5951 	DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
5952 	return (rv);
5953 }
5954 
5955 static void
5956 vgen_reclaim(vgen_ldc_t *ldcp)
5957 {
5958 	mutex_enter(&ldcp->tclock);
5959 
5960 	vgen_reclaim_dring(ldcp);
5961 	ldcp->reclaim_lbolt = ddi_get_lbolt();
5962 
5963 	mutex_exit(&ldcp->tclock);
5964 }
5965 
5966 /*
5967  * transmit reclaim function. starting from the current reclaim index
5968  * look for descriptors marked DONE and reclaim the descriptor and the
5969  * corresponding buffers (tbuf).
5970  */
5971 static void
5972 vgen_reclaim_dring(vgen_ldc_t *ldcp)
5973 {
5974 	int count = 0;
5975 	vnet_public_desc_t *txdp;
5976 	vgen_private_desc_t *tbufp;
5977 	vio_dring_entry_hdr_t	*hdrp;
5978 
5979 #ifdef DEBUG
5980 	if (vgen_trigger_txtimeout)
5981 		return;
5982 #endif
5983 
5984 	tbufp = ldcp->cur_tbufp;
5985 	txdp = tbufp->descp;
5986 	hdrp = &txdp->hdr;
5987 
5988 	while ((hdrp->dstate == VIO_DESC_DONE) &&
5989 	    (tbufp != ldcp->next_tbufp)) {
5990 		tbufp->flags = VGEN_PRIV_DESC_FREE;
5991 		hdrp->dstate = VIO_DESC_FREE;
5992 		hdrp->ack = B_FALSE;
5993 
5994 		tbufp = NEXTTBUF(ldcp, tbufp);
5995 		txdp = tbufp->descp;
5996 		hdrp = &txdp->hdr;
5997 		count++;
5998 	}
5999 
6000 	ldcp->cur_tbufp = tbufp;
6001 
6002 	/*
6003 	 * Check if mac layer should be notified to restart transmissions
6004 	 */
6005 	if ((ldcp->need_resched) && (count > 0)) {
6006 		vio_net_tx_update_t vtx_update =
6007 		    ldcp->portp->vcb.vio_net_tx_update;
6008 
6009 		ldcp->need_resched = B_FALSE;
6010 		vtx_update(ldcp->portp->vhp);
6011 	}
6012 }
6013 
6014 /* return the number of pending transmits for the channel */
6015 static int
6016 vgen_num_txpending(vgen_ldc_t *ldcp)
6017 {
6018 	int n;
6019 
6020 	if (ldcp->next_tbufp >= ldcp->cur_tbufp) {
6021 		n = ldcp->next_tbufp - ldcp->cur_tbufp;
6022 	} else  {
6023 		/* cur_tbufp > next_tbufp */
6024 		n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp);
6025 	}
6026 
6027 	return (n);
6028 }
6029 
6030 /* determine if the transmit descriptor ring is full */
6031 static int
6032 vgen_tx_dring_full(vgen_ldc_t *ldcp)
6033 {
6034 	vgen_private_desc_t	*tbufp;
6035 	vgen_private_desc_t	*ntbufp;
6036 
6037 	tbufp = ldcp->next_tbufp;
6038 	ntbufp = NEXTTBUF(ldcp, tbufp);
6039 	if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */
6040 		return (VGEN_SUCCESS);
6041 	}
6042 	return (VGEN_FAILURE);
6043 }
6044 
6045 /* determine if timeout condition has occured */
6046 static int
6047 vgen_ldc_txtimeout(vgen_ldc_t *ldcp)
6048 {
6049 	if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) >
6050 	    drv_usectohz(vnet_ldcwd_txtimeout * 1000)) &&
6051 	    (vnet_ldcwd_txtimeout) &&
6052 	    (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) {
6053 		return (VGEN_SUCCESS);
6054 	} else {
6055 		return (VGEN_FAILURE);
6056 	}
6057 }
6058 
6059 /* transmit watchdog timeout handler */
6060 static void
6061 vgen_ldc_watchdog(void *arg)
6062 {
6063 	vgen_ldc_t *ldcp;
6064 	vgen_t *vgenp;
6065 	int rv;
6066 
6067 	ldcp = (vgen_ldc_t *)arg;
6068 	vgenp = LDC_TO_VGEN(ldcp);
6069 
6070 	rv = vgen_ldc_txtimeout(ldcp);
6071 	if (rv == VGEN_SUCCESS) {
6072 		DWARN(vgenp, ldcp, "transmit timeout\n");
6073 #ifdef DEBUG
6074 		if (vgen_trigger_txtimeout) {
6075 			/* tx timeout triggered for debugging */
6076 			vgen_trigger_txtimeout = 0;
6077 		}
6078 #endif
6079 		mutex_enter(&ldcp->cblock);
6080 		ldcp->need_ldc_reset = B_TRUE;
6081 		vgen_handshake_retry(ldcp);
6082 		mutex_exit(&ldcp->cblock);
6083 		if (ldcp->need_resched) {
6084 			vio_net_tx_update_t vtx_update =
6085 			    ldcp->portp->vcb.vio_net_tx_update;
6086 
6087 			ldcp->need_resched = B_FALSE;
6088 			vtx_update(ldcp->portp->vhp);
6089 		}
6090 	}
6091 
6092 	ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp,
6093 	    drv_usectohz(vnet_ldcwd_interval * 1000));
6094 }
6095 
6096 /* handler for error messages received from the peer ldc end-point */
6097 static void
6098 vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
6099 {
6100 	_NOTE(ARGUNUSED(ldcp, tagp))
6101 }
6102 
6103 static int
6104 vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
6105 {
6106 	vio_raw_data_msg_t	*rmsg;
6107 	vio_dring_msg_t		*dmsg;
6108 	uint64_t		seq_num;
6109 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
6110 
6111 	if (tagp->vio_subtype_env == VIO_DRING_DATA) {
6112 		dmsg = (vio_dring_msg_t *)tagp;
6113 		seq_num = dmsg->seq_num;
6114 	} else if (tagp->vio_subtype_env == VIO_PKT_DATA) {
6115 		rmsg = (vio_raw_data_msg_t *)tagp;
6116 		seq_num = rmsg->seq_num;
6117 	} else {
6118 		return (EINVAL);
6119 	}
6120 
6121 	if (seq_num != ldcp->next_rxseq) {
6122 
6123 		/* seqnums don't match */
6124 		DWARN(vgenp, ldcp,
6125 		    "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
6126 		    ldcp->next_rxseq, seq_num);
6127 
6128 		ldcp->need_ldc_reset = B_TRUE;
6129 		return (EINVAL);
6130 
6131 	}
6132 
6133 	ldcp->next_rxseq++;
6134 
6135 	return (0);
6136 }
6137 
6138 /* Check if the session id in the received message is valid */
6139 static int
6140 vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
6141 {
6142 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6143 
6144 	if (tagp->vio_sid != ldcp->peer_sid) {
6145 		DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
6146 		    ldcp->peer_sid, tagp->vio_sid);
6147 		return (VGEN_FAILURE);
6148 	}
6149 	else
6150 		return (VGEN_SUCCESS);
6151 }
6152 
6153 static caddr_t
6154 vgen_print_ethaddr(uint8_t *a, char *ebuf)
6155 {
6156 	(void) sprintf(ebuf,
6157 	    "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
6158 	return (ebuf);
6159 }
6160 
6161 /* Handshake watchdog timeout handler */
6162 static void
6163 vgen_hwatchdog(void *arg)
6164 {
6165 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
6166 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6167 
6168 	DWARN(vgenp, ldcp,
6169 	    "handshake timeout ldc(%lx) phase(%x) state(%x)\n",
6170 	    ldcp->hphase, ldcp->hstate);
6171 
6172 	mutex_enter(&ldcp->cblock);
6173 	if (ldcp->cancel_htid) {
6174 		ldcp->cancel_htid = 0;
6175 		mutex_exit(&ldcp->cblock);
6176 		return;
6177 	}
6178 	ldcp->htid = 0;
6179 	ldcp->need_ldc_reset = B_TRUE;
6180 	vgen_handshake_retry(ldcp);
6181 	mutex_exit(&ldcp->cblock);
6182 }
6183 
6184 static void
6185 vgen_print_hparams(vgen_hparams_t *hp)
6186 {
6187 	uint8_t	addr[6];
6188 	char	ea[6];
6189 	ldc_mem_cookie_t *dc;
6190 
6191 	cmn_err(CE_CONT, "version_info:\n");
6192 	cmn_err(CE_CONT,
6193 	    "\tver_major: %d, ver_minor: %d, dev_class: %d\n",
6194 	    hp->ver_major, hp->ver_minor, hp->dev_class);
6195 
6196 	vnet_macaddr_ultostr(hp->addr, addr);
6197 	cmn_err(CE_CONT, "attr_info:\n");
6198 	cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu,
6199 	    vgen_print_ethaddr(addr, ea));
6200 	cmn_err(CE_CONT,
6201 	    "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
6202 	    hp->addr_type, hp->xfer_mode, hp->ack_freq);
6203 
6204 	dc = &hp->dring_cookie;
6205 	cmn_err(CE_CONT, "dring_info:\n");
6206 	cmn_err(CE_CONT,
6207 	    "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size);
6208 	cmn_err(CE_CONT,
6209 	    "\tldc_addr: 0x%lx, ldc_size: %ld\n",
6210 	    dc->addr, dc->size);
6211 	cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident);
6212 }
6213 
6214 static void
6215 vgen_print_ldcinfo(vgen_ldc_t *ldcp)
6216 {
6217 	vgen_hparams_t *hp;
6218 
6219 	cmn_err(CE_CONT, "Channel Information:\n");
6220 	cmn_err(CE_CONT,
6221 	    "\tldc_id: 0x%lx, ldc_status: 0x%x\n",
6222 	    ldcp->ldc_id, ldcp->ldc_status);
6223 	cmn_err(CE_CONT,
6224 	    "\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
6225 	    ldcp->local_sid, ldcp->peer_sid);
6226 	cmn_err(CE_CONT,
6227 	    "\thphase: 0x%x, hstate: 0x%x\n",
6228 	    ldcp->hphase, ldcp->hstate);
6229 
6230 	cmn_err(CE_CONT, "Local handshake params:\n");
6231 	hp = &ldcp->local_hparams;
6232 	vgen_print_hparams(hp);
6233 
6234 	cmn_err(CE_CONT, "Peer handshake params:\n");
6235 	hp = &ldcp->peer_hparams;
6236 	vgen_print_hparams(hp);
6237 }
6238 
6239 /*
6240  * Send received packets up the stack.
6241  */
6242 static void
6243 vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp)
6244 {
6245 	vio_net_rx_cb_t vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
6246 
6247 	if (ldcp->rcv_thread != NULL) {
6248 		ASSERT(MUTEX_HELD(&ldcp->rxlock));
6249 		mutex_exit(&ldcp->rxlock);
6250 	} else {
6251 		ASSERT(MUTEX_HELD(&ldcp->cblock));
6252 		mutex_exit(&ldcp->cblock);
6253 	}
6254 
6255 	vrx_cb(ldcp->portp->vhp, bp);
6256 
6257 	if (ldcp->rcv_thread != NULL) {
6258 		mutex_enter(&ldcp->rxlock);
6259 	} else {
6260 		mutex_enter(&ldcp->cblock);
6261 	}
6262 }
6263 
6264 /*
6265  * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data.
6266  * This thread is woken up by the LDC interrupt handler to process
6267  * LDC packets and receive data.
6268  */
6269 static void
6270 vgen_ldc_rcv_worker(void *arg)
6271 {
6272 	callb_cpr_t	cprinfo;
6273 	vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
6274 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6275 
6276 	DBG1(vgenp, ldcp, "enter\n");
6277 	CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr,
6278 	    "vnet_rcv_thread");
6279 	mutex_enter(&ldcp->rcv_thr_lock);
6280 	ldcp->rcv_thr_flags |= VGEN_WTHR_RUNNING;
6281 	while (!(ldcp->rcv_thr_flags & VGEN_WTHR_STOP)) {
6282 
6283 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
6284 		/*
6285 		 * Wait until the data is received or a stop
6286 		 * request is received.
6287 		 */
6288 		while (!(ldcp->rcv_thr_flags &
6289 		    (VGEN_WTHR_DATARCVD | VGEN_WTHR_STOP))) {
6290 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
6291 		}
6292 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock)
6293 
6294 		/*
6295 		 * First process the stop request.
6296 		 */
6297 		if (ldcp->rcv_thr_flags & VGEN_WTHR_STOP) {
6298 			DBG2(vgenp, ldcp, "stopped\n");
6299 			break;
6300 		}
6301 		ldcp->rcv_thr_flags &= ~VGEN_WTHR_DATARCVD;
6302 		mutex_exit(&ldcp->rcv_thr_lock);
6303 		DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n");
6304 		vgen_handle_evt_read(ldcp);
6305 		mutex_enter(&ldcp->rcv_thr_lock);
6306 	}
6307 
6308 	/*
6309 	 * Update the run status and wakeup the thread that
6310 	 * has sent the stop request.
6311 	 */
6312 	ldcp->rcv_thr_flags &= ~VGEN_WTHR_RUNNING;
6313 	cv_signal(&ldcp->rcv_thr_cv);
6314 	CALLB_CPR_EXIT(&cprinfo);
6315 	thread_exit();
6316 	DBG1(vgenp, ldcp, "exit\n");
6317 }
6318 
6319 /* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */
6320 static void
6321 vgen_stop_rcv_thread(vgen_ldc_t *ldcp)
6322 {
6323 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6324 
6325 	DBG1(vgenp, ldcp, "enter\n");
6326 	/*
6327 	 * Send a stop request by setting the stop flag and
6328 	 * wait until the receive thread stops.
6329 	 */
6330 	mutex_enter(&ldcp->rcv_thr_lock);
6331 	if (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) {
6332 		ldcp->rcv_thr_flags |= VGEN_WTHR_STOP;
6333 		cv_signal(&ldcp->rcv_thr_cv);
6334 		DBG2(vgenp, ldcp, "waiting...");
6335 		while (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) {
6336 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
6337 		}
6338 	}
6339 	mutex_exit(&ldcp->rcv_thr_lock);
6340 	ldcp->rcv_thread = NULL;
6341 	DBG1(vgenp, ldcp, "exit\n");
6342 }
6343 
6344 /*
6345  * vgen_dds_rx -- post DDS messages to vnet.
6346  */
6347 static int
6348 vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
6349 {
6350 	vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp;
6351 	vgen_t *vgenp = LDC_TO_VGEN(ldcp);
6352 
6353 	if (dmsg->dds_class != DDS_VNET_NIU) {
6354 		DWARN(vgenp, ldcp, "Unknown DDS class, dropping");
6355 		return (EBADMSG);
6356 	}
6357 	vnet_dds_rx(vgenp->vnetp, dmsg);
6358 	return (0);
6359 }
6360 
6361 /*
6362  * vgen_dds_tx -- an interface called by vnet to send DDS messages.
6363  */
6364 int
6365 vgen_dds_tx(void *arg, void *msg)
6366 {
6367 	vgen_t *vgenp = arg;
6368 	vio_dds_msg_t *dmsg = msg;
6369 	vgen_portlist_t *plistp = &vgenp->vgenports;
6370 	vgen_ldc_t *ldcp;
6371 	vgen_ldclist_t *ldclp;
6372 	int rv = EIO;
6373 
6374 
6375 	READ_ENTER(&plistp->rwlock);
6376 	ldclp = &(vgenp->vsw_portp->ldclist);
6377 	READ_ENTER(&ldclp->rwlock);
6378 	ldcp = ldclp->headp;
6379 	if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) {
6380 		goto vgen_dsend_exit;
6381 	}
6382 
6383 	dmsg->tag.vio_sid = ldcp->local_sid;
6384 	rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE);
6385 	if (rv != VGEN_SUCCESS) {
6386 		rv = EIO;
6387 	} else {
6388 		rv = 0;
6389 	}
6390 
6391 vgen_dsend_exit:
6392 	RW_EXIT(&ldclp->rwlock);
6393 	RW_EXIT(&plistp->rwlock);
6394 	return (rv);
6395 
6396 }
6397 
6398 #if DEBUG
6399 
6400 /*
6401  * Print debug messages - set to 0xf to enable all msgs
6402  */
6403 static void
6404 debug_printf(const char *fname, vgen_t *vgenp,
6405     vgen_ldc_t *ldcp, const char *fmt, ...)
6406 {
6407 	char    buf[256];
6408 	char    *bufp = buf;
6409 	va_list ap;
6410 
6411 	if ((vgenp != NULL) && (vgenp->vnetp != NULL)) {
6412 		(void) sprintf(bufp, "vnet%d:",
6413 		    ((vnet_t *)(vgenp->vnetp))->instance);
6414 		bufp += strlen(bufp);
6415 	}
6416 	if (ldcp != NULL) {
6417 		(void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id);
6418 		bufp += strlen(bufp);
6419 	}
6420 	(void) sprintf(bufp, "%s: ", fname);
6421 	bufp += strlen(bufp);
6422 
6423 	va_start(ap, fmt);
6424 	(void) vsprintf(bufp, fmt, ap);
6425 	va_end(ap);
6426 
6427 	if ((ldcp == NULL) ||(vgendbg_ldcid == -1) ||
6428 	    (vgendbg_ldcid == ldcp->ldc_id)) {
6429 		cmn_err(CE_CONT, "%s\n", buf);
6430 	}
6431 }
6432 #endif
6433