xref: /titanic_50/usr/src/uts/sun4v/io/vsw.c (revision e07d9cb85217949d497b02d7211de8a197d2f2eb)
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 2007 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/debug.h>
32 #include <sys/time.h>
33 #include <sys/sysmacros.h>
34 #include <sys/systm.h>
35 #include <sys/user.h>
36 #include <sys/stropts.h>
37 #include <sys/stream.h>
38 #include <sys/strlog.h>
39 #include <sys/strsubr.h>
40 #include <sys/cmn_err.h>
41 #include <sys/cpu.h>
42 #include <sys/kmem.h>
43 #include <sys/conf.h>
44 #include <sys/ddi.h>
45 #include <sys/sunddi.h>
46 #include <sys/ksynch.h>
47 #include <sys/stat.h>
48 #include <sys/kstat.h>
49 #include <sys/vtrace.h>
50 #include <sys/strsun.h>
51 #include <sys/dlpi.h>
52 #include <sys/ethernet.h>
53 #include <net/if.h>
54 #include <sys/varargs.h>
55 #include <sys/machsystm.h>
56 #include <sys/modctl.h>
57 #include <sys/modhash.h>
58 #include <sys/mac.h>
59 #include <sys/mac_ether.h>
60 #include <sys/taskq.h>
61 #include <sys/note.h>
62 #include <sys/mach_descrip.h>
63 #include <sys/mac.h>
64 #include <sys/mdeg.h>
65 #include <sys/ldc.h>
66 #include <sys/vsw_fdb.h>
67 #include <sys/vsw.h>
68 #include <sys/vio_mailbox.h>
69 #include <sys/vnet_mailbox.h>
70 #include <sys/vnet_common.h>
71 #include <sys/vio_util.h>
72 #include <sys/sdt.h>
73 
74 /*
75  * Function prototypes.
76  */
77 static	int vsw_attach(dev_info_t *, ddi_attach_cmd_t);
78 static	int vsw_detach(dev_info_t *, ddi_detach_cmd_t);
79 static	int vsw_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
80 static	int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *);
81 static	int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *, int *);
82 static	int vsw_get_physaddr(vsw_t *);
83 static	int vsw_setup_switching(vsw_t *);
84 static	int vsw_setup_layer2(vsw_t *);
85 static	int vsw_setup_layer3(vsw_t *);
86 
87 /* MAC Ring table functions. */
88 static void vsw_mac_ring_tbl_init(vsw_t *vswp);
89 static void vsw_mac_ring_tbl_destroy(vsw_t *vswp);
90 static void vsw_queue_worker(vsw_mac_ring_t *rrp);
91 static void vsw_queue_stop(vsw_queue_t *vqp);
92 static vsw_queue_t *vsw_queue_create();
93 static void vsw_queue_destroy(vsw_queue_t *vqp);
94 
95 /* MAC layer routines */
96 static mac_resource_handle_t vsw_mac_ring_add_cb(void *arg,
97 		mac_resource_t *mrp);
98 static	int vsw_get_hw_maddr(vsw_t *);
99 static	int vsw_set_hw(vsw_t *, vsw_port_t *, int);
100 static	int vsw_set_hw_addr(vsw_t *, mac_multi_addr_t *);
101 static	int vsw_set_hw_promisc(vsw_t *, vsw_port_t *, int);
102 static	int vsw_unset_hw(vsw_t *, vsw_port_t *, int);
103 static	int vsw_unset_hw_addr(vsw_t *, int);
104 static	int vsw_unset_hw_promisc(vsw_t *, vsw_port_t *, int);
105 static void vsw_reconfig_hw(vsw_t *);
106 static int vsw_prog_if(vsw_t *);
107 static int vsw_prog_ports(vsw_t *);
108 static int vsw_mac_attach(vsw_t *vswp);
109 static void vsw_mac_detach(vsw_t *vswp);
110 
111 static void vsw_rx_queue_cb(void *, mac_resource_handle_t, mblk_t *);
112 static void vsw_rx_cb(void *, mac_resource_handle_t, mblk_t *);
113 static mblk_t *vsw_tx_msg(vsw_t *, mblk_t *);
114 static int vsw_mac_register(vsw_t *);
115 static int vsw_mac_unregister(vsw_t *);
116 static int vsw_m_stat(void *, uint_t, uint64_t *);
117 static void vsw_m_stop(void *arg);
118 static int vsw_m_start(void *arg);
119 static int vsw_m_unicst(void *arg, const uint8_t *);
120 static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *);
121 static int vsw_m_promisc(void *arg, boolean_t);
122 static mblk_t *vsw_m_tx(void *arg, mblk_t *);
123 
124 /* MDEG routines */
125 static	int vsw_mdeg_register(vsw_t *vswp);
126 static	void vsw_mdeg_unregister(vsw_t *vswp);
127 static	int vsw_mdeg_cb(void *cb_argp, mdeg_result_t *);
128 static	int vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *);
129 static	void vsw_get_initial_md_properties(vsw_t *vswp, md_t *, mde_cookie_t);
130 static	void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t);
131 
132 /* Port add/deletion routines */
133 static	int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node);
134 static	int vsw_port_attach(vsw_t *vswp, int p_instance,
135 	uint64_t *ldcids, int nids, struct ether_addr *macaddr);
136 static	int vsw_detach_ports(vsw_t *vswp);
137 static	int vsw_port_detach(vsw_t *vswp, int p_instance);
138 static	int vsw_port_delete(vsw_port_t *port);
139 static	int vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id);
140 static	int vsw_ldc_detach(vsw_port_t *port, uint64_t ldc_id);
141 static	int vsw_init_ldcs(vsw_port_t *port);
142 static	int vsw_uninit_ldcs(vsw_port_t *port);
143 static	int vsw_ldc_init(vsw_ldc_t *ldcp);
144 static	int vsw_ldc_uninit(vsw_ldc_t *ldcp);
145 static	int vsw_drain_ldcs(vsw_port_t *port);
146 static	int vsw_drain_port_taskq(vsw_port_t *port);
147 static	void vsw_marker_task(void *);
148 static	vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance);
149 static	int vsw_plist_del_node(vsw_t *, vsw_port_t *port);
150 
151 /* Interrupt routines */
152 static	uint_t vsw_ldc_cb(uint64_t cb, caddr_t arg);
153 
154 /* Handshake routines */
155 static	void vsw_ldc_reinit(vsw_ldc_t *);
156 static	void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
157 static	void vsw_conn_task(void *);
158 static	int vsw_check_flag(vsw_ldc_t *, int, uint64_t);
159 static	void vsw_next_milestone(vsw_ldc_t *);
160 static	int vsw_supported_version(vio_ver_msg_t *);
161 
162 /* Data processing routines */
163 static void vsw_process_pkt(void *);
164 static void vsw_dispatch_ctrl_task(vsw_ldc_t *, void *, vio_msg_tag_t);
165 static void vsw_process_ctrl_pkt(void *);
166 static void vsw_process_ctrl_ver_pkt(vsw_ldc_t *, void *);
167 static void vsw_process_ctrl_attr_pkt(vsw_ldc_t *, void *);
168 static void vsw_process_ctrl_mcst_pkt(vsw_ldc_t *, void *);
169 static void vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *, void *);
170 static void vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *, void *);
171 static void vsw_process_ctrl_rdx_pkt(vsw_ldc_t *, void *);
172 static void vsw_process_data_pkt(vsw_ldc_t *, void *, vio_msg_tag_t);
173 static void vsw_process_data_dring_pkt(vsw_ldc_t *, void *);
174 static void vsw_process_data_raw_pkt(vsw_ldc_t *, void *);
175 static void vsw_process_data_ibnd_pkt(vsw_ldc_t *, void *);
176 static void vsw_process_err_pkt(vsw_ldc_t *, void *, vio_msg_tag_t);
177 
178 /* Switching/data transmit routines */
179 static	void vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller,
180 	    vsw_port_t *port, mac_resource_handle_t);
181 static	void vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller,
182 	    vsw_port_t *port, mac_resource_handle_t);
183 static	int vsw_forward_all(vsw_t *vswp, mblk_t *mp, int caller,
184 	    vsw_port_t *port);
185 static	int vsw_forward_grp(vsw_t *vswp, mblk_t *mp, int caller,
186 	    vsw_port_t *port);
187 static	int vsw_portsend(vsw_port_t *, mblk_t *);
188 static	int vsw_dringsend(vsw_ldc_t *, mblk_t *);
189 static	int vsw_descrsend(vsw_ldc_t *, mblk_t *);
190 
191 /* Packet creation routines */
192 static void vsw_send_ver(void *);
193 static void vsw_send_attr(vsw_ldc_t *);
194 static vio_dring_reg_msg_t *vsw_create_dring_info_pkt(vsw_ldc_t *);
195 static void vsw_send_dring_info(vsw_ldc_t *);
196 static void vsw_send_rdx(vsw_ldc_t *);
197 
198 static int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t);
199 
200 /* Forwarding database (FDB) routines */
201 static	int vsw_add_fdb(vsw_t *vswp, vsw_port_t *port);
202 static	int vsw_del_fdb(vsw_t *vswp, vsw_port_t *port);
203 static	vsw_port_t *vsw_lookup_fdb(vsw_t *vswp, struct ether_header *);
204 static	int vsw_add_rem_mcst(vnet_mcast_msg_t *, vsw_port_t *);
205 static	int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *);
206 static	int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *);
207 static	void vsw_del_addr(uint8_t, void *, uint64_t);
208 static	void vsw_del_mcst_port(vsw_port_t *);
209 static	void vsw_del_mcst_vsw(vsw_t *);
210 
211 /* Dring routines */
212 static dring_info_t *vsw_create_dring(vsw_ldc_t *);
213 static void vsw_create_privring(vsw_ldc_t *);
214 static int vsw_setup_ring(vsw_ldc_t *ldcp, dring_info_t *dp);
215 static int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **,
216     int *);
217 static dring_info_t *vsw_ident2dring(lane_t *, uint64_t);
218 
219 static void vsw_set_lane_attr(vsw_t *, lane_t *);
220 static int vsw_check_attr(vnet_attr_msg_t *, vsw_port_t *);
221 static int vsw_dring_match(dring_info_t *dp, vio_dring_reg_msg_t *msg);
222 static int vsw_mem_cookie_match(ldc_mem_cookie_t *, ldc_mem_cookie_t *);
223 static int vsw_check_dring_info(vio_dring_reg_msg_t *);
224 
225 /* Misc support routines */
226 static	caddr_t vsw_print_ethaddr(uint8_t *addr, char *ebuf);
227 static void vsw_free_lane_resources(vsw_ldc_t *, uint64_t);
228 static int vsw_free_ring(dring_info_t *);
229 
230 /* Debugging routines */
231 static void dump_flags(uint64_t);
232 static void display_state(void);
233 static void display_lane(lane_t *);
234 static void display_ring(dring_info_t *);
235 
236 int	vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */
237 int	vsw_wretries = 100;		/* # of write attempts */
238 int	vsw_chain_len = 150;		/* max # of mblks in msg chain */
239 int	vsw_desc_delay = 0;		/* delay in us */
240 int	vsw_read_attempts = 5;		/* # of reads of descriptor */
241 
242 uint32_t	vsw_mblk_size = VSW_MBLK_SIZE;
243 uint32_t	vsw_num_mblks = VSW_NUM_MBLKS;
244 
245 static	mac_callbacks_t	vsw_m_callbacks = {
246 	0,
247 	vsw_m_stat,
248 	vsw_m_start,
249 	vsw_m_stop,
250 	vsw_m_promisc,
251 	vsw_m_multicst,
252 	vsw_m_unicst,
253 	vsw_m_tx,
254 	NULL,
255 	NULL,
256 	NULL
257 };
258 
259 static	struct	cb_ops	vsw_cb_ops = {
260 	nulldev,			/* cb_open */
261 	nulldev,			/* cb_close */
262 	nodev,				/* cb_strategy */
263 	nodev,				/* cb_print */
264 	nodev,				/* cb_dump */
265 	nodev,				/* cb_read */
266 	nodev,				/* cb_write */
267 	nodev,				/* cb_ioctl */
268 	nodev,				/* cb_devmap */
269 	nodev,				/* cb_mmap */
270 	nodev,				/* cb_segmap */
271 	nochpoll,			/* cb_chpoll */
272 	ddi_prop_op,			/* cb_prop_op */
273 	NULL,				/* cb_stream */
274 	D_MP,				/* cb_flag */
275 	CB_REV,				/* rev */
276 	nodev,				/* int (*cb_aread)() */
277 	nodev				/* int (*cb_awrite)() */
278 };
279 
280 static	struct	dev_ops	vsw_ops = {
281 	DEVO_REV,		/* devo_rev */
282 	0,			/* devo_refcnt */
283 	vsw_getinfo,		/* devo_getinfo */
284 	nulldev,		/* devo_identify */
285 	nulldev,		/* devo_probe */
286 	vsw_attach,		/* devo_attach */
287 	vsw_detach,		/* devo_detach */
288 	nodev,			/* devo_reset */
289 	&vsw_cb_ops,		/* devo_cb_ops */
290 	(struct bus_ops *)NULL,	/* devo_bus_ops */
291 	ddi_power		/* devo_power */
292 };
293 
294 extern	struct	mod_ops	mod_driverops;
295 static struct modldrv vswmodldrv = {
296 	&mod_driverops,
297 	"sun4v Virtual Switch %I%",
298 	&vsw_ops,
299 };
300 
301 #define	LDC_ENTER_LOCK(ldcp)	\
302 				mutex_enter(&((ldcp)->ldc_cblock));\
303 				mutex_enter(&((ldcp)->ldc_txlock));
304 #define	LDC_EXIT_LOCK(ldcp)	\
305 				mutex_exit(&((ldcp)->ldc_txlock));\
306 				mutex_exit(&((ldcp)->ldc_cblock));
307 
308 /* Driver soft state ptr  */
309 static void	*vsw_state;
310 
311 /*
312  * Linked list of "vsw_t" structures - one per instance.
313  */
314 vsw_t		*vsw_head = NULL;
315 krwlock_t	vsw_rw;
316 
317 /*
318  * Property names
319  */
320 static char vdev_propname[] = "virtual-device";
321 static char vsw_propname[] = "virtual-network-switch";
322 static char physdev_propname[] = "vsw-phys-dev";
323 static char smode_propname[] = "vsw-switch-mode";
324 static char macaddr_propname[] = "local-mac-address";
325 static char remaddr_propname[] = "remote-mac-address";
326 static char ldcids_propname[] = "ldc-ids";
327 static char chan_propname[] = "channel-endpoint";
328 static char id_propname[] = "id";
329 static char reg_propname[] = "reg";
330 
331 /* supported versions */
332 static	ver_sup_t	vsw_versions[] = { {1, 0} };
333 
334 /*
335  * Matching criteria passed to the MDEG to register interest
336  * in changes to 'virtual-device-port' nodes identified by their
337  * 'id' property.
338  */
339 static md_prop_match_t vport_prop_match[] = {
340 	{ MDET_PROP_VAL,    "id"   },
341 	{ MDET_LIST_END,    NULL    }
342 };
343 
344 static mdeg_node_match_t vport_match = { "virtual-device-port",
345 						vport_prop_match };
346 
347 /*
348  * Matching criteria passed to the MDEG to register interest
349  * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified
350  * by their 'name' and 'cfg-handle' properties.
351  */
352 static md_prop_match_t vdev_prop_match[] = {
353 	{ MDET_PROP_STR,    "name"   },
354 	{ MDET_PROP_VAL,    "cfg-handle" },
355 	{ MDET_LIST_END,    NULL    }
356 };
357 
358 static mdeg_node_match_t vdev_match = { "virtual-device",
359 						vdev_prop_match };
360 
361 
362 /*
363  * Specification of an MD node passed to the MDEG to filter any
364  * 'vport' nodes that do not belong to the specified node. This
365  * template is copied for each vsw instance and filled in with
366  * the appropriate 'cfg-handle' value before being passed to the MDEG.
367  */
368 static mdeg_prop_spec_t vsw_prop_template[] = {
369 	{ MDET_PROP_STR,    "name",		vsw_propname },
370 	{ MDET_PROP_VAL,    "cfg-handle",	NULL	},
371 	{ MDET_LIST_END,    NULL,		NULL	}
372 };
373 
374 #define	VSW_SET_MDEG_PROP_INST(specp, val)	(specp)[1].ps_val = (val);
375 
376 /*
377  * From /etc/system enable/disable thread per ring. This is a mode
378  * selection that is done a vsw driver attach time.
379  */
380 boolean_t vsw_multi_ring_enable = B_FALSE;
381 int vsw_mac_rx_rings = VSW_MAC_RX_RINGS;
382 
383 /*
384  * Print debug messages - set to 0x1f to enable all msgs
385  * or 0x0 to turn all off.
386  */
387 int vswdbg = 0x0;
388 
389 /*
390  * debug levels:
391  * 0x01:	Function entry/exit tracing
392  * 0x02:	Internal function messages
393  * 0x04:	Verbose internal messages
394  * 0x08:	Warning messages
395  * 0x10:	Error messages
396  */
397 
398 static void
399 vswdebug(vsw_t *vswp, const char *fmt, ...)
400 {
401 	char buf[512];
402 	va_list ap;
403 
404 	va_start(ap, fmt);
405 	(void) vsprintf(buf, fmt, ap);
406 	va_end(ap);
407 
408 	if (vswp == NULL)
409 		cmn_err(CE_CONT, "%s\n", buf);
410 	else
411 		cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf);
412 }
413 
414 /*
415  * For the moment the state dump routines have their own
416  * private flag.
417  */
418 #define	DUMP_STATE	0
419 
420 #if DUMP_STATE
421 
422 #define	DUMP_TAG(tag) \
423 {			\
424 	D1(NULL, "DUMP_TAG: type 0x%llx", (tag).vio_msgtype); \
425 	D1(NULL, "DUMP_TAG: stype 0x%llx", (tag).vio_subtype);	\
426 	D1(NULL, "DUMP_TAG: senv 0x%llx", (tag).vio_subtype_env);	\
427 }
428 
429 #define	DUMP_TAG_PTR(tag) \
430 {			\
431 	D1(NULL, "DUMP_TAG: type 0x%llx", (tag)->vio_msgtype); \
432 	D1(NULL, "DUMP_TAG: stype 0x%llx", (tag)->vio_subtype);	\
433 	D1(NULL, "DUMP_TAG: senv 0x%llx", (tag)->vio_subtype_env);	\
434 }
435 
436 #define	DUMP_FLAGS(flags) dump_flags(flags);
437 #define	DISPLAY_STATE()	display_state()
438 
439 #else
440 
441 #define	DUMP_TAG(tag)
442 #define	DUMP_TAG_PTR(tag)
443 #define	DUMP_FLAGS(state)
444 #define	DISPLAY_STATE()
445 
446 #endif	/* DUMP_STATE */
447 
448 #ifdef DEBUG
449 
450 #define	D1		\
451 if (vswdbg & 0x01)	\
452 	vswdebug
453 
454 #define	D2		\
455 if (vswdbg & 0x02)	\
456 	vswdebug
457 
458 #define	D3		\
459 if (vswdbg & 0x04)	\
460 	vswdebug
461 
462 #define	DWARN		\
463 if (vswdbg & 0x08)	\
464 	vswdebug
465 
466 #define	DERR		\
467 if (vswdbg & 0x10)	\
468 	vswdebug
469 
470 #else
471 
472 #define	DERR		if (0)	vswdebug
473 #define	DWARN		if (0)	vswdebug
474 #define	D1		if (0)	vswdebug
475 #define	D2		if (0)	vswdebug
476 #define	D3		if (0)	vswdebug
477 
478 #endif	/* DEBUG */
479 
480 static struct modlinkage modlinkage = {
481 	MODREV_1,
482 	&vswmodldrv,
483 	NULL
484 };
485 
486 int
487 _init(void)
488 {
489 	int status;
490 
491 	rw_init(&vsw_rw, NULL, RW_DRIVER, NULL);
492 
493 	status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1);
494 	if (status != 0) {
495 		return (status);
496 	}
497 
498 	mac_init_ops(&vsw_ops, "vsw");
499 	status = mod_install(&modlinkage);
500 	if (status != 0) {
501 		ddi_soft_state_fini(&vsw_state);
502 	}
503 	return (status);
504 }
505 
506 int
507 _fini(void)
508 {
509 	int status;
510 
511 	status = mod_remove(&modlinkage);
512 	if (status != 0)
513 		return (status);
514 	mac_fini_ops(&vsw_ops);
515 	ddi_soft_state_fini(&vsw_state);
516 
517 	rw_destroy(&vsw_rw);
518 
519 	return (status);
520 }
521 
522 int
523 _info(struct modinfo *modinfop)
524 {
525 	return (mod_info(&modlinkage, modinfop));
526 }
527 
528 static int
529 vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
530 {
531 	vsw_t		*vswp;
532 	int		instance;
533 	char		hashname[MAXNAMELEN];
534 	char		qname[TASKQ_NAMELEN];
535 	enum		{ PROG_init = 0x00,
536 				PROG_if_lock = 0x01,
537 				PROG_fdb = 0x02,
538 				PROG_mfdb = 0x04,
539 				PROG_report_dev = 0x08,
540 				PROG_plist = 0x10,
541 				PROG_taskq = 0x20}
542 			progress;
543 
544 	progress = PROG_init;
545 
546 	switch (cmd) {
547 	case DDI_ATTACH:
548 		break;
549 	case DDI_RESUME:
550 		/* nothing to do for this non-device */
551 		return (DDI_SUCCESS);
552 	case DDI_PM_RESUME:
553 	default:
554 		return (DDI_FAILURE);
555 	}
556 
557 	instance = ddi_get_instance(dip);
558 	if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) {
559 		DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance);
560 		return (DDI_FAILURE);
561 	}
562 	vswp = ddi_get_soft_state(vsw_state, instance);
563 
564 	if (vswp == NULL) {
565 		DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance);
566 		goto vsw_attach_fail;
567 	}
568 
569 	vswp->dip = dip;
570 	vswp->instance = instance;
571 	ddi_set_driver_private(dip, (caddr_t)vswp);
572 
573 	mutex_init(&vswp->hw_lock, NULL, MUTEX_DRIVER, NULL);
574 	mutex_init(&vswp->mac_lock, NULL, MUTEX_DRIVER, NULL);
575 	rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL);
576 	progress |= PROG_if_lock;
577 
578 	/* setup the unicast forwarding database  */
579 	(void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d",
580 							vswp->instance);
581 	D2(vswp, "creating unicast hash table (%s)...", hashname);
582 	vswp->fdb = mod_hash_create_ptrhash(hashname, VSW_NCHAINS,
583 		mod_hash_null_valdtor, sizeof (void *));
584 
585 	progress |= PROG_fdb;
586 
587 	/* setup the multicast fowarding database */
588 	(void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d",
589 							vswp->instance);
590 	D2(vswp, "creating multicast hash table %s)...", hashname);
591 	rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL);
592 	vswp->mfdb = mod_hash_create_ptrhash(hashname, VSW_NCHAINS,
593 			mod_hash_null_valdtor, sizeof (void *));
594 
595 	progress |= PROG_mfdb;
596 
597 	/*
598 	 * create lock protecting list of multicast addresses
599 	 * which could come via m_multicst() entry point when plumbed.
600 	 */
601 	mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL);
602 	vswp->mcap = NULL;
603 
604 	ddi_report_dev(vswp->dip);
605 
606 	progress |= PROG_report_dev;
607 
608 	WRITE_ENTER(&vsw_rw);
609 	vswp->next = vsw_head;
610 	vsw_head = vswp;
611 	RW_EXIT(&vsw_rw);
612 
613 	/* setup the port list */
614 	rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL);
615 	vswp->plist.head = NULL;
616 
617 	progress |= PROG_plist;
618 
619 	/*
620 	 * Create the taskq which will process all the VIO
621 	 * control messages.
622 	 */
623 	(void) snprintf(qname, TASKQ_NAMELEN, "vsw_taskq%d", vswp->instance);
624 	if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1,
625 					TASKQ_DEFAULTPRI, 0)) == NULL) {
626 		cmn_err(CE_WARN, "!vsw%d: Unable to create task queue",
627 			vswp->instance);
628 		goto vsw_attach_fail;
629 	}
630 
631 	progress |= PROG_taskq;
632 
633 	/* prevent auto-detaching */
634 	if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip,
635 				DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) {
636 		cmn_err(CE_NOTE, "!Unable to set \"%s\" property for "
637 			"instance %u", DDI_NO_AUTODETACH, instance);
638 	}
639 
640 	/*
641 	 * Now we have everything setup, register an interest in
642 	 * specific MD nodes.
643 	 *
644 	 * The callback is invoked in 2 cases, firstly if upon mdeg
645 	 * registration there are existing nodes which match our specified
646 	 * criteria, and secondly if the MD is changed (and again, there
647 	 * are nodes which we are interested in present within it. Note
648 	 * that our callback will be invoked even if our specified nodes
649 	 * have not actually changed).
650 	 *
651 	 * Until the callback is invoked we cannot switch any pkts as
652 	 * we don't know basic information such as what mode we are
653 	 * operating in. However we expect the callback to be invoked
654 	 * immediately upon registration as this driver should only
655 	 * be attaching if there are vsw nodes in the MD.
656 	 */
657 	if (vsw_mdeg_register(vswp))
658 		goto vsw_attach_fail;
659 
660 	return (DDI_SUCCESS);
661 
662 vsw_attach_fail:
663 	DERR(NULL, "vsw_attach: failed");
664 
665 	if (progress & PROG_taskq)
666 		ddi_taskq_destroy(vswp->taskq_p);
667 
668 	if (progress & PROG_plist)
669 		rw_destroy(&vswp->plist.lockrw);
670 
671 	if (progress & PROG_report_dev) {
672 		ddi_remove_minor_node(dip, NULL);
673 		mutex_destroy(&vswp->mca_lock);
674 	}
675 
676 	if (progress & PROG_mfdb) {
677 		mod_hash_destroy_hash(vswp->mfdb);
678 		vswp->mfdb = NULL;
679 		rw_destroy(&vswp->mfdbrw);
680 	}
681 
682 	if (progress & PROG_fdb) {
683 		mod_hash_destroy_hash(vswp->fdb);
684 		vswp->fdb = NULL;
685 	}
686 
687 	if (progress & PROG_if_lock) {
688 		rw_destroy(&vswp->if_lockrw);
689 		mutex_destroy(&vswp->mac_lock);
690 		mutex_destroy(&vswp->hw_lock);
691 	}
692 
693 	ddi_soft_state_free(vsw_state, instance);
694 	return (DDI_FAILURE);
695 }
696 
697 static int
698 vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
699 {
700 	vio_mblk_pool_t		*poolp, *npoolp;
701 	vsw_t			**vswpp, *vswp;
702 	int 			instance;
703 
704 	instance = ddi_get_instance(dip);
705 	vswp = ddi_get_soft_state(vsw_state, instance);
706 
707 	if (vswp == NULL) {
708 		return (DDI_FAILURE);
709 	}
710 
711 	switch (cmd) {
712 	case DDI_DETACH:
713 		break;
714 	case DDI_SUSPEND:
715 	case DDI_PM_SUSPEND:
716 	default:
717 		return (DDI_FAILURE);
718 	}
719 
720 	D2(vswp, "detaching instance %d", instance);
721 
722 	if (vswp->if_state & VSW_IF_REG) {
723 		if (vsw_mac_unregister(vswp) != 0) {
724 			cmn_err(CE_WARN, "!vsw%d: Unable to detach from "
725 				"MAC layer", vswp->instance);
726 			return (DDI_FAILURE);
727 		}
728 	}
729 
730 	vsw_mdeg_unregister(vswp);
731 
732 	/* remove mac layer callback */
733 	mutex_enter(&vswp->mac_lock);
734 	if ((vswp->mh != NULL) && (vswp->mrh != NULL)) {
735 		mac_rx_remove(vswp->mh, vswp->mrh);
736 		vswp->mrh = NULL;
737 	}
738 	mutex_exit(&vswp->mac_lock);
739 
740 	if (vsw_detach_ports(vswp) != 0) {
741 		cmn_err(CE_WARN, "!vsw%d: Unable to detach ports",
742 							vswp->instance);
743 		return (DDI_FAILURE);
744 	}
745 
746 	rw_destroy(&vswp->if_lockrw);
747 
748 	mutex_destroy(&vswp->hw_lock);
749 
750 	/*
751 	 * Now that the ports have been deleted, stop and close
752 	 * the physical device.
753 	 */
754 	mutex_enter(&vswp->mac_lock);
755 	if (vswp->mh != NULL) {
756 		if (vswp->mstarted)
757 			mac_stop(vswp->mh);
758 		if (vswp->mresources)
759 			mac_resource_set(vswp->mh, NULL, NULL);
760 		mac_close(vswp->mh);
761 
762 		vswp->mh = NULL;
763 		vswp->txinfo = NULL;
764 	}
765 	mutex_exit(&vswp->mac_lock);
766 	mutex_destroy(&vswp->mac_lock);
767 
768 	/*
769 	 * Destroy any free pools that may still exist.
770 	 */
771 	poolp = vswp->rxh;
772 	while (poolp != NULL) {
773 		npoolp = vswp->rxh = poolp->nextp;
774 		if (vio_destroy_mblks(poolp) != 0) {
775 			vswp->rxh = poolp;
776 			return (DDI_FAILURE);
777 		}
778 		poolp = npoolp;
779 	}
780 
781 	/*
782 	 * Remove this instance from any entries it may be on in
783 	 * the hash table by using the list of addresses maintained
784 	 * in the vsw_t structure.
785 	 */
786 	vsw_del_mcst_vsw(vswp);
787 
788 	vswp->mcap = NULL;
789 	mutex_destroy(&vswp->mca_lock);
790 
791 	/*
792 	 * By now any pending tasks have finished and the underlying
793 	 * ldc's have been destroyed, so its safe to delete the control
794 	 * message taskq.
795 	 */
796 	if (vswp->taskq_p != NULL)
797 		ddi_taskq_destroy(vswp->taskq_p);
798 
799 	/*
800 	 * At this stage all the data pointers in the hash table
801 	 * should be NULL, as all the ports have been removed and will
802 	 * have deleted themselves from the port lists which the data
803 	 * pointers point to. Hence we can destroy the table using the
804 	 * default destructors.
805 	 */
806 	D2(vswp, "vsw_detach: destroying hash tables..");
807 	mod_hash_destroy_hash(vswp->fdb);
808 	vswp->fdb = NULL;
809 
810 	WRITE_ENTER(&vswp->mfdbrw);
811 	mod_hash_destroy_hash(vswp->mfdb);
812 	vswp->mfdb = NULL;
813 	RW_EXIT(&vswp->mfdbrw);
814 	rw_destroy(&vswp->mfdbrw);
815 
816 	ddi_remove_minor_node(dip, NULL);
817 
818 	rw_destroy(&vswp->plist.lockrw);
819 	WRITE_ENTER(&vsw_rw);
820 	for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) {
821 		if (*vswpp == vswp) {
822 			*vswpp = vswp->next;
823 			break;
824 		}
825 	}
826 	RW_EXIT(&vsw_rw);
827 	ddi_soft_state_free(vsw_state, instance);
828 
829 	return (DDI_SUCCESS);
830 }
831 
832 static int
833 vsw_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
834 {
835 	_NOTE(ARGUNUSED(dip))
836 
837 	vsw_t	*vswp = NULL;
838 	dev_t	dev = (dev_t)arg;
839 	int	instance;
840 
841 	instance = getminor(dev);
842 
843 	switch (infocmd) {
844 	case DDI_INFO_DEVT2DEVINFO:
845 		if ((vswp = ddi_get_soft_state(vsw_state, instance)) == NULL) {
846 			*result = NULL;
847 			return (DDI_FAILURE);
848 		}
849 		*result = vswp->dip;
850 		return (DDI_SUCCESS);
851 
852 	case DDI_INFO_DEVT2INSTANCE:
853 		*result = (void *)(uintptr_t)instance;
854 		return (DDI_SUCCESS);
855 
856 	default:
857 		*result = NULL;
858 		return (DDI_FAILURE);
859 	}
860 }
861 
862 /*
863  * Get the value of the "vsw-phys-dev" property in the specified
864  * node. This property is the name of the physical device that
865  * the virtual switch will use to talk to the outside world.
866  *
867  * Note it is valid for this property to be NULL (but the property
868  * itself must exist). Callers of this routine should verify that
869  * the value returned is what they expected (i.e. either NULL or non NULL).
870  *
871  * On success returns value of the property in region pointed to by
872  * the 'name' argument, and with return value of 0. Otherwise returns 1.
873  */
874 static int
875 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name)
876 {
877 	int	len = 0;
878 	char	*physname = NULL;
879 	char	*dev;
880 
881 	if (md_get_prop_data(mdp, node, physdev_propname,
882 				(uint8_t **)(&physname), &len) != 0) {
883 		cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical "
884 				"device(s) from MD", vswp->instance);
885 		return (1);
886 	} else if ((strlen(physname) + 1) > LIFNAMSIZ) {
887 		cmn_err(CE_WARN, "!vsw%d: %s is too long a device name",
888 			vswp->instance, physname);
889 		return (1);
890 	} else {
891 		(void) strncpy(name, physname, strlen(physname) + 1);
892 		D2(vswp, "%s: using first device specified (%s)",
893 			__func__, physname);
894 	}
895 
896 #ifdef DEBUG
897 	/*
898 	 * As a temporary measure to aid testing we check to see if there
899 	 * is a vsw.conf file present. If there is we use the value of the
900 	 * vsw_physname property in the file as the name of the physical
901 	 * device, overriding the value from the MD.
902 	 *
903 	 * There may be multiple devices listed, but for the moment
904 	 * we just use the first one.
905 	 */
906 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0,
907 		"vsw_physname", &dev) == DDI_PROP_SUCCESS) {
908 		if ((strlen(dev) + 1) > LIFNAMSIZ) {
909 			cmn_err(CE_WARN, "vsw%d: %s is too long a device name",
910 				vswp->instance, dev);
911 			ddi_prop_free(dev);
912 			return (1);
913 		} else {
914 			cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from "
915 				"config file", vswp->instance, dev);
916 
917 			(void) strncpy(name, dev, strlen(dev) + 1);
918 		}
919 
920 		ddi_prop_free(dev);
921 	}
922 #endif
923 
924 	return (0);
925 }
926 
927 /*
928  * Read the 'vsw-switch-mode' property from the specified MD node.
929  *
930  * Returns 0 on success and the number of modes found in 'found',
931  * otherwise returns 1.
932  */
933 static int
934 vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node,
935 						uint8_t *modes, int *found)
936 {
937 	int		len = 0;
938 	int		smode_num = 0;
939 	char		*smode = NULL;
940 	char		*curr_mode = NULL;
941 
942 	D1(vswp, "%s: enter", __func__);
943 
944 	/*
945 	 * Get the switch-mode property. The modes are listed in
946 	 * decreasing order of preference, i.e. prefered mode is
947 	 * first item in list.
948 	 */
949 	len = 0;
950 	smode_num = 0;
951 	if (md_get_prop_data(mdp, node, smode_propname,
952 				(uint8_t **)(&smode), &len) != 0) {
953 		/*
954 		 * Unable to get switch-mode property from MD, nothing
955 		 * more we can do.
956 		 */
957 		cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property"
958 			" from the MD", vswp->instance);
959 		*found = 0;
960 		return (1);
961 	}
962 
963 	curr_mode = smode;
964 	/*
965 	 * Modes of operation:
966 	 * 'switched'	 - layer 2 switching, underlying HW in
967 	 *			programmed mode.
968 	 * 'promiscuous' - layer 2 switching, underlying HW in
969 	 *			promiscuous mode.
970 	 * 'routed'	 - layer 3 (i.e. IP) routing, underlying HW
971 	 *			in non-promiscuous mode.
972 	 */
973 	while ((curr_mode < (smode + len)) && (smode_num < NUM_SMODES)) {
974 		D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode);
975 		if (strcmp(curr_mode, "switched") == 0) {
976 			modes[smode_num++] = VSW_LAYER2;
977 		} else if (strcmp(curr_mode, "promiscuous") == 0) {
978 			modes[smode_num++] = VSW_LAYER2_PROMISC;
979 		} else if (strcmp(curr_mode, "routed") == 0) {
980 			modes[smode_num++] = VSW_LAYER3;
981 		} else {
982 			cmn_err(CE_WARN, "!vsw%d: Unknown switch mode %s, "
983 				"setting to default switched mode",
984 				vswp->instance, curr_mode);
985 			modes[smode_num++] = VSW_LAYER2;
986 		}
987 		curr_mode += strlen(curr_mode) + 1;
988 	}
989 	*found = smode_num;
990 
991 	D2(vswp, "%s: %d modes found", __func__, smode_num);
992 
993 	D1(vswp, "%s: exit", __func__);
994 
995 	return (0);
996 }
997 
998 /*
999  * Get the mac address of the physical device.
1000  *
1001  * Returns 0 on success, 1 on failure.
1002  */
1003 static int
1004 vsw_get_physaddr(vsw_t *vswp)
1005 {
1006 	mac_handle_t	mh;
1007 	char		drv[LIFNAMSIZ];
1008 	uint_t		ddi_instance;
1009 
1010 	D1(vswp, "%s: enter", __func__);
1011 
1012 	if (ddi_parse(vswp->physname, drv, &ddi_instance) != DDI_SUCCESS)
1013 		return (1);
1014 
1015 	if (mac_open(vswp->physname, ddi_instance, &mh) != 0) {
1016 		cmn_err(CE_WARN, "!vsw%d: mac_open %s failed",
1017 				vswp->instance, vswp->physname);
1018 		return (1);
1019 	}
1020 
1021 	READ_ENTER(&vswp->if_lockrw);
1022 	mac_unicst_get(mh, vswp->if_addr.ether_addr_octet);
1023 	RW_EXIT(&vswp->if_lockrw);
1024 
1025 	mac_close(mh);
1026 
1027 	vswp->mdprops |= VSW_DEV_MACADDR;
1028 
1029 	D1(vswp, "%s: exit", __func__);
1030 
1031 	return (0);
1032 }
1033 
1034 /*
1035  * Check to see if the card supports the setting of multiple unicst
1036  * addresses.
1037  *
1038  * Returns 0 if card supports the programming of multiple unicast addresses,
1039  * otherwise returns 1.
1040  */
1041 static int
1042 vsw_get_hw_maddr(vsw_t *vswp)
1043 {
1044 	D1(vswp, "%s: enter", __func__);
1045 
1046 	mutex_enter(&vswp->mac_lock);
1047 	if (vswp->mh == NULL) {
1048 		mutex_exit(&vswp->mac_lock);
1049 		return (1);
1050 	}
1051 
1052 	if (!mac_capab_get(vswp->mh, MAC_CAPAB_MULTIADDRESS, &vswp->maddr)) {
1053 		cmn_err(CE_WARN, "!vsw%d: device (%s) does not support "
1054 			"setting multiple unicast addresses", vswp->instance,
1055 			vswp->physname);
1056 		mutex_exit(&vswp->mac_lock);
1057 		return (1);
1058 	}
1059 	mutex_exit(&vswp->mac_lock);
1060 
1061 	D2(vswp, "%s: %d addrs : %d free", __func__,
1062 		vswp->maddr.maddr_naddr, vswp->maddr.maddr_naddrfree);
1063 
1064 	D1(vswp, "%s: exit", __func__);
1065 
1066 	return (0);
1067 }
1068 
1069 /*
1070  * Setup the required switching mode.
1071  *
1072  * Returns 0 on success, 1 on failure.
1073  */
1074 static int
1075 vsw_setup_switching(vsw_t *vswp)
1076 {
1077 	int	i, rv = 1;
1078 
1079 	D1(vswp, "%s: enter", __func__);
1080 
1081 	/* select best switching mode */
1082 	for (i = 0; i < vswp->smode_num; i++) {
1083 		vswp->smode_idx = i;
1084 		switch (vswp->smode[i]) {
1085 		case VSW_LAYER2:
1086 		case VSW_LAYER2_PROMISC:
1087 			rv = vsw_setup_layer2(vswp);
1088 			break;
1089 
1090 		case VSW_LAYER3:
1091 			rv = vsw_setup_layer3(vswp);
1092 			break;
1093 
1094 		default:
1095 			DERR(vswp, "unknown switch mode");
1096 			rv = 1;
1097 			break;
1098 		}
1099 
1100 		if (rv == 0)
1101 			break;
1102 	}
1103 
1104 	if (rv == 1) {
1105 		cmn_err(CE_WARN, "!vsw%d: Unable to setup specified "
1106 			"switching mode", vswp->instance);
1107 		return (rv);
1108 	}
1109 
1110 	D2(vswp, "%s: Operating in mode %d", __func__,
1111 					vswp->smode[vswp->smode_idx]);
1112 
1113 	D1(vswp, "%s: exit", __func__);
1114 
1115 	return (0);
1116 }
1117 
1118 /*
1119  * Setup for layer 2 switching.
1120  *
1121  * Returns 0 on success, 1 on failure.
1122  */
1123 static int
1124 vsw_setup_layer2(vsw_t *vswp)
1125 {
1126 	D1(vswp, "%s: enter", __func__);
1127 
1128 	vswp->vsw_switch_frame = vsw_switch_l2_frame;
1129 
1130 	/*
1131 	 * Attempt to link into the MAC layer so we can get
1132 	 * and send packets out over the physical adapter.
1133 	 */
1134 	if (vswp->mdprops & VSW_MD_PHYSNAME) {
1135 		if (vsw_mac_attach(vswp) != 0) {
1136 			/*
1137 			 * Registration with the MAC layer has failed,
1138 			 * so return 1 so that can fall back to next
1139 			 * prefered switching method.
1140 			 */
1141 			cmn_err(CE_WARN, "!vsw%d: Unable to join as MAC layer "
1142 				"client", vswp->instance);
1143 			return (1);
1144 		}
1145 
1146 		if (vswp->smode[vswp->smode_idx] == VSW_LAYER2) {
1147 			/*
1148 			 * Verify that underlying device can support multiple
1149 			 * unicast mac addresses.
1150 			 */
1151 			if (vsw_get_hw_maddr(vswp) != 0) {
1152 				cmn_err(CE_WARN, "!vsw%d: Unable to setup "
1153 					"layer2 switching", vswp->instance);
1154 				vsw_mac_detach(vswp);
1155 				return (1);
1156 			}
1157 		}
1158 
1159 	} else {
1160 		/*
1161 		 * No physical device name found in MD which is
1162 		 * required for layer 2.
1163 		 */
1164 		cmn_err(CE_WARN, "!vsw%d: no physical device name specified",
1165 			vswp->instance);
1166 		return (1);
1167 	}
1168 
1169 	D1(vswp, "%s: exit", __func__);
1170 
1171 	return (0);
1172 }
1173 
1174 static int
1175 vsw_setup_layer3(vsw_t *vswp)
1176 {
1177 	D1(vswp, "%s: enter", __func__);
1178 
1179 	D2(vswp, "%s: operating in layer 3 mode", __func__);
1180 	vswp->vsw_switch_frame = vsw_switch_l3_frame;
1181 
1182 	D1(vswp, "%s: exit", __func__);
1183 
1184 	return (0);
1185 }
1186 
1187 /*
1188  * Link into the MAC layer to gain access to the services provided by
1189  * the underlying physical device driver (which should also have
1190  * registered with the MAC layer).
1191  *
1192  * Only when in layer 2 mode.
1193  */
1194 static int
1195 vsw_mac_attach(vsw_t *vswp)
1196 {
1197 	char	drv[LIFNAMSIZ];
1198 	uint_t	ddi_instance;
1199 
1200 	D1(vswp, "%s: enter", __func__);
1201 
1202 	ASSERT(vswp->mh == NULL);
1203 	ASSERT(vswp->mrh == NULL);
1204 	ASSERT(vswp->mstarted == B_FALSE);
1205 	ASSERT(vswp->mresources == B_FALSE);
1206 
1207 	ASSERT(vswp->mdprops & VSW_MD_PHYSNAME);
1208 
1209 	mutex_enter(&vswp->mac_lock);
1210 	if (ddi_parse(vswp->physname, drv, &ddi_instance) != DDI_SUCCESS) {
1211 		cmn_err(CE_WARN, "!vsw%d: invalid device name: %s",
1212 			vswp->instance, vswp->physname);
1213 		goto mac_fail_exit;
1214 	}
1215 
1216 	if ((mac_open(vswp->physname, ddi_instance, &vswp->mh)) != 0) {
1217 		cmn_err(CE_WARN, "!vsw%d: mac_open %s failed",
1218 			vswp->instance, vswp->physname);
1219 		goto mac_fail_exit;
1220 	}
1221 
1222 	ASSERT(vswp->mh != NULL);
1223 
1224 	D2(vswp, "vsw_mac_attach: using device %s", vswp->physname);
1225 
1226 	if (vsw_multi_ring_enable) {
1227 		/*
1228 		 * Initialize the ring table.
1229 		 */
1230 		vsw_mac_ring_tbl_init(vswp);
1231 
1232 		/*
1233 		 * Register our rx callback function.
1234 		 */
1235 		vswp->mrh = mac_rx_add(vswp->mh,
1236 			vsw_rx_queue_cb, (void *)vswp);
1237 		ASSERT(vswp->mrh != NULL);
1238 
1239 		/*
1240 		 * Register our mac resource callback.
1241 		 */
1242 		mac_resource_set(vswp->mh, vsw_mac_ring_add_cb, (void *)vswp);
1243 		vswp->mresources = B_TRUE;
1244 
1245 		/*
1246 		 * Get the ring resources available to us from
1247 		 * the mac below us.
1248 		 */
1249 		mac_resources(vswp->mh);
1250 	} else {
1251 		/*
1252 		 * Just register our rx callback function
1253 		 */
1254 		vswp->mrh = mac_rx_add(vswp->mh, vsw_rx_cb, (void *)vswp);
1255 		ASSERT(vswp->mrh != NULL);
1256 	}
1257 
1258 	/* Get the MAC tx fn */
1259 	vswp->txinfo = mac_tx_get(vswp->mh);
1260 
1261 	/* start the interface */
1262 	if (mac_start(vswp->mh) != 0) {
1263 		cmn_err(CE_WARN, "!vsw%d: Could not start mac interface",
1264 			vswp->instance);
1265 		goto mac_fail_exit;
1266 	}
1267 
1268 	mutex_exit(&vswp->mac_lock);
1269 
1270 	vswp->mstarted = B_TRUE;
1271 
1272 	D1(vswp, "%s: exit", __func__);
1273 	return (0);
1274 
1275 mac_fail_exit:
1276 	mutex_exit(&vswp->mac_lock);
1277 	vsw_mac_detach(vswp);
1278 
1279 	D1(vswp, "%s: exit", __func__);
1280 	return (1);
1281 }
1282 
1283 static void
1284 vsw_mac_detach(vsw_t *vswp)
1285 {
1286 	D1(vswp, "vsw_mac_detach: enter");
1287 
1288 	ASSERT(vswp != NULL);
1289 
1290 	if (vsw_multi_ring_enable) {
1291 		vsw_mac_ring_tbl_destroy(vswp);
1292 	}
1293 
1294 	mutex_enter(&vswp->mac_lock);
1295 
1296 	if (vswp->mh != NULL) {
1297 		if (vswp->mstarted)
1298 			mac_stop(vswp->mh);
1299 		if (vswp->mrh != NULL)
1300 			mac_rx_remove(vswp->mh, vswp->mrh);
1301 		if (vswp->mresources)
1302 			mac_resource_set(vswp->mh, NULL, NULL);
1303 		mac_close(vswp->mh);
1304 	}
1305 
1306 	vswp->mrh = NULL;
1307 	vswp->mh = NULL;
1308 	vswp->txinfo = NULL;
1309 	vswp->mstarted = B_FALSE;
1310 
1311 	mutex_exit(&vswp->mac_lock);
1312 
1313 	D1(vswp, "vsw_mac_detach: exit");
1314 }
1315 
1316 /*
1317  * Depending on the mode specified, the capabilites and capacity
1318  * of the underlying device setup the physical device.
1319  *
1320  * If in layer 3 mode, then do nothing.
1321  *
1322  * If in layer 2 programmed mode attempt to program the unicast address
1323  * associated with the port into the physical device. If this is not
1324  * possible due to resource exhaustion or simply because the device does
1325  * not support multiple unicast addresses then if required fallback onto
1326  * putting the card into promisc mode.
1327  *
1328  * If in promisc mode then simply set the card into promisc mode.
1329  *
1330  * Returns 0 success, 1 on failure.
1331  */
1332 static int
1333 vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type)
1334 {
1335 	mac_multi_addr_t	mac_addr;
1336 	int			err;
1337 
1338 	D1(vswp, "%s: enter", __func__);
1339 
1340 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1341 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
1342 
1343 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER3)
1344 		return (0);
1345 
1346 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC) {
1347 		return (vsw_set_hw_promisc(vswp, port, type));
1348 	}
1349 
1350 	/*
1351 	 * Attempt to program the unicast address into the HW.
1352 	 */
1353 	mac_addr.mma_addrlen = ETHERADDRL;
1354 	if (type == VSW_VNETPORT) {
1355 		ASSERT(port != NULL);
1356 		ether_copy(&port->p_macaddr, &mac_addr.mma_addr);
1357 	} else {
1358 		READ_ENTER(&vswp->if_lockrw);
1359 		/*
1360 		 * Don't program if the interface is not UP. This
1361 		 * is possible if the address has just been changed
1362 		 * in the MD node, but the interface has not yet been
1363 		 * plumbed.
1364 		 */
1365 		if (!(vswp->if_state & VSW_IF_UP)) {
1366 			RW_EXIT(&vswp->if_lockrw);
1367 			return (0);
1368 		}
1369 		ether_copy(&vswp->if_addr, &mac_addr.mma_addr);
1370 		RW_EXIT(&vswp->if_lockrw);
1371 	}
1372 
1373 	err = vsw_set_hw_addr(vswp, &mac_addr);
1374 	if (err != 0) {
1375 		/*
1376 		 * Mark that attempt should be made to re-config sometime
1377 		 * in future if a port is deleted.
1378 		 */
1379 		vswp->recfg_reqd = B_TRUE;
1380 
1381 		/*
1382 		 * Only 1 mode specified, nothing more to do.
1383 		 */
1384 		if (vswp->smode_num == 1)
1385 			return (err);
1386 
1387 		/*
1388 		 * If promiscuous was next mode specified try to
1389 		 * set the card into that mode.
1390 		 */
1391 		if ((vswp->smode_idx <= (vswp->smode_num - 2)) &&
1392 			(vswp->smode[vswp->smode_idx + 1]
1393 					== VSW_LAYER2_PROMISC)) {
1394 			vswp->smode_idx += 1;
1395 			return (vsw_set_hw_promisc(vswp, port, type));
1396 		}
1397 		return (err);
1398 	}
1399 
1400 	if (type == VSW_VNETPORT) {
1401 		port->addr_slot = mac_addr.mma_slot;
1402 		port->addr_set = VSW_ADDR_HW;
1403 	} else {
1404 		vswp->addr_slot = mac_addr.mma_slot;
1405 		vswp->addr_set = VSW_ADDR_HW;
1406 	}
1407 
1408 	D2(vswp, "programmed addr %x:%x:%x:%x:%x:%x into slot %d "
1409 		"of device %s",
1410 		mac_addr.mma_addr[0], mac_addr.mma_addr[1],
1411 		mac_addr.mma_addr[2], mac_addr.mma_addr[3],
1412 		mac_addr.mma_addr[4], mac_addr.mma_addr[5],
1413 		mac_addr.mma_slot, vswp->physname);
1414 
1415 	D1(vswp, "%s: exit", __func__);
1416 
1417 	return (0);
1418 }
1419 
1420 /*
1421  * If in layer 3 mode do nothing.
1422  *
1423  * If in layer 2 switched mode remove the address from the physical
1424  * device.
1425  *
1426  * If in layer 2 promiscuous mode disable promisc mode.
1427  *
1428  * Returns 0 on success.
1429  */
1430 static int
1431 vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type)
1432 {
1433 	mac_addr_slot_t	slot;
1434 	int		rv;
1435 
1436 	D1(vswp, "%s: enter", __func__);
1437 
1438 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1439 
1440 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER3)
1441 		return (0);
1442 
1443 	switch (type) {
1444 	case VSW_VNETPORT:
1445 		ASSERT(port != NULL);
1446 
1447 		if (port->addr_set == VSW_ADDR_PROMISC) {
1448 			return (vsw_unset_hw_promisc(vswp, port, type));
1449 
1450 		} else if (port->addr_set == VSW_ADDR_HW) {
1451 			slot = port->addr_slot;
1452 			if ((rv = vsw_unset_hw_addr(vswp, slot)) == 0)
1453 				port->addr_set = VSW_ADDR_UNSET;
1454 		}
1455 
1456 		break;
1457 
1458 	case VSW_LOCALDEV:
1459 		if (vswp->addr_set == VSW_ADDR_PROMISC) {
1460 			return (vsw_unset_hw_promisc(vswp, NULL, type));
1461 
1462 		} else if (vswp->addr_set == VSW_ADDR_HW) {
1463 			slot = vswp->addr_slot;
1464 			if ((rv = vsw_unset_hw_addr(vswp, slot)) == 0)
1465 				vswp->addr_set = VSW_ADDR_UNSET;
1466 		}
1467 
1468 		break;
1469 
1470 	default:
1471 		/* should never happen */
1472 		DERR(vswp, "%s: unknown type %d", __func__, type);
1473 		ASSERT(0);
1474 		return (1);
1475 	}
1476 
1477 	D1(vswp, "%s: exit", __func__);
1478 	return (rv);
1479 }
1480 
1481 /*
1482  * Attempt to program a unicast address into HW.
1483  *
1484  * Returns 0 on sucess, 1 on failure.
1485  */
1486 static int
1487 vsw_set_hw_addr(vsw_t *vswp, mac_multi_addr_t *mac)
1488 {
1489 	void	*mah;
1490 	int	rv;
1491 
1492 	D1(vswp, "%s: enter", __func__);
1493 
1494 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1495 
1496 	if (vswp->maddr.maddr_handle == NULL)
1497 		return (1);
1498 
1499 	mah = vswp->maddr.maddr_handle;
1500 
1501 	rv = vswp->maddr.maddr_add(mah, mac);
1502 
1503 	if (rv == 0)
1504 		return (0);
1505 
1506 	/*
1507 	 * Its okay for the add to fail because we have exhausted
1508 	 * all the resouces in the hardware device. Any other error
1509 	 * we want to flag.
1510 	 */
1511 	if (rv != ENOSPC) {
1512 		cmn_err(CE_WARN, "!vsw%d: error programming "
1513 			"address %x:%x:%x:%x:%x:%x into HW "
1514 			"err (%d)", vswp->instance,
1515 			mac->mma_addr[0], mac->mma_addr[1],
1516 			mac->mma_addr[2], mac->mma_addr[3],
1517 			mac->mma_addr[4], mac->mma_addr[5], rv);
1518 	}
1519 	D1(vswp, "%s: exit", __func__);
1520 	return (1);
1521 }
1522 
1523 /*
1524  * Remove a unicast mac address which has previously been programmed
1525  * into HW.
1526  *
1527  * Returns 0 on sucess, 1 on failure.
1528  */
1529 static int
1530 vsw_unset_hw_addr(vsw_t *vswp, int slot)
1531 {
1532 	void	*mah;
1533 	int	rv;
1534 
1535 	D1(vswp, "%s: enter", __func__);
1536 
1537 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1538 	ASSERT(slot >= 0);
1539 
1540 	if (vswp->maddr.maddr_handle == NULL)
1541 		return (1);
1542 
1543 	mah = vswp->maddr.maddr_handle;
1544 
1545 	rv = vswp->maddr.maddr_remove(mah, slot);
1546 	if (rv != 0) {
1547 		cmn_err(CE_WARN, "!vsw%d: unable to remove address "
1548 			"from slot %d in device %s (err %d)",
1549 			vswp->instance, slot, vswp->physname, rv);
1550 		return (1);
1551 	}
1552 
1553 	D2(vswp, "removed addr from slot %d in device %s",
1554 		slot, vswp->physname);
1555 
1556 	D1(vswp, "%s: exit", __func__);
1557 	return (0);
1558 }
1559 
1560 /*
1561  * Set network card into promisc mode.
1562  *
1563  * Returns 0 on success, 1 on failure.
1564  */
1565 static int
1566 vsw_set_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
1567 {
1568 	D1(vswp, "%s: enter", __func__);
1569 
1570 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1571 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
1572 
1573 	mutex_enter(&vswp->mac_lock);
1574 	if (vswp->mh == NULL) {
1575 		mutex_exit(&vswp->mac_lock);
1576 		return (1);
1577 	}
1578 
1579 	if (vswp->promisc_cnt++ == 0) {
1580 		if (mac_promisc_set(vswp->mh, B_TRUE, MAC_DEVPROMISC) != 0) {
1581 			vswp->promisc_cnt--;
1582 			mutex_exit(&vswp->mac_lock);
1583 			return (1);
1584 		}
1585 		cmn_err(CE_NOTE, "!vsw%d: switching device %s into "
1586 			"promiscuous mode", vswp->instance, vswp->physname);
1587 	}
1588 	mutex_exit(&vswp->mac_lock);
1589 
1590 	if (type == VSW_VNETPORT) {
1591 		ASSERT(port != NULL);
1592 		port->addr_set = VSW_ADDR_PROMISC;
1593 	} else {
1594 		vswp->addr_set = VSW_ADDR_PROMISC;
1595 	}
1596 
1597 	D1(vswp, "%s: exit", __func__);
1598 
1599 	return (0);
1600 }
1601 
1602 /*
1603  * Turn off promiscuous mode on network card.
1604  *
1605  * Returns 0 on success, 1 on failure.
1606  */
1607 static int
1608 vsw_unset_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
1609 {
1610 	vsw_port_list_t 	*plist = &vswp->plist;
1611 
1612 	D2(vswp, "%s: enter", __func__);
1613 
1614 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1615 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
1616 
1617 	mutex_enter(&vswp->mac_lock);
1618 	if (vswp->mh == NULL) {
1619 		mutex_exit(&vswp->mac_lock);
1620 		return (1);
1621 	}
1622 
1623 	if (--vswp->promisc_cnt == 0) {
1624 		if (mac_promisc_set(vswp->mh, B_FALSE, MAC_DEVPROMISC) != 0) {
1625 			vswp->promisc_cnt++;
1626 			mutex_exit(&vswp->mac_lock);
1627 			return (1);
1628 		}
1629 
1630 		/*
1631 		 * We are exiting promisc mode either because we were
1632 		 * only in promisc mode because we had failed over from
1633 		 * switched mode due to HW resource issues, or the user
1634 		 * wanted the card in promisc mode for all the ports and
1635 		 * the last port is now being deleted. Tweak the message
1636 		 * accordingly.
1637 		 */
1638 		if (plist->num_ports != 0) {
1639 			cmn_err(CE_NOTE, "!vsw%d: switching device %s back to "
1640 				"programmed mode", vswp->instance,
1641 				vswp->physname);
1642 		} else {
1643 			cmn_err(CE_NOTE, "!vsw%d: switching device %s out of "
1644 				"promiscuous mode", vswp->instance,
1645 				vswp->physname);
1646 		}
1647 	}
1648 	mutex_exit(&vswp->mac_lock);
1649 
1650 	if (type == VSW_VNETPORT) {
1651 		ASSERT(port != NULL);
1652 		ASSERT(port->addr_set == VSW_ADDR_PROMISC);
1653 		port->addr_set = VSW_ADDR_UNSET;
1654 	} else {
1655 		ASSERT(vswp->addr_set == VSW_ADDR_PROMISC);
1656 		vswp->addr_set = VSW_ADDR_UNSET;
1657 	}
1658 
1659 	D1(vswp, "%s: exit", __func__);
1660 	return (0);
1661 }
1662 
1663 /*
1664  * Determine whether or not we are operating in our prefered
1665  * mode and if not whether the physical resources now allow us
1666  * to operate in it.
1667  *
1668  * If a port is being removed should only be invoked after port has been
1669  * removed from the port list.
1670  */
1671 static void
1672 vsw_reconfig_hw(vsw_t *vswp)
1673 {
1674 	int			s_idx;
1675 
1676 	D1(vswp, "%s: enter", __func__);
1677 
1678 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1679 
1680 	if (vswp->maddr.maddr_handle == NULL) {
1681 		return;
1682 	}
1683 
1684 	/*
1685 	 * If we are in layer 2 (i.e. switched) or would like to be
1686 	 * in layer 2 then check if any ports or the vswitch itself
1687 	 * need to be programmed into the HW.
1688 	 *
1689 	 * This can happen in two cases - switched was specified as
1690 	 * the prefered mode of operation but we exhausted the HW
1691 	 * resources and so failed over to the next specifed mode,
1692 	 * or switched was the only mode specified so after HW
1693 	 * resources were exhausted there was nothing more we
1694 	 * could do.
1695 	 */
1696 	if (vswp->smode_idx > 0)
1697 		s_idx = vswp->smode_idx - 1;
1698 	else
1699 		s_idx = vswp->smode_idx;
1700 
1701 	if (vswp->smode[s_idx] != VSW_LAYER2) {
1702 		return;
1703 	}
1704 
1705 	D2(vswp, "%s: attempting reconfig..", __func__);
1706 
1707 	/*
1708 	 * First, attempt to set the vswitch mac address into HW,
1709 	 * if required.
1710 	 */
1711 	if (vsw_prog_if(vswp)) {
1712 		return;
1713 	}
1714 
1715 	/*
1716 	 * Next, attempt to set any ports which have not yet been
1717 	 * programmed into HW.
1718 	 */
1719 	if (vsw_prog_ports(vswp)) {
1720 		return;
1721 	}
1722 
1723 	/*
1724 	 * By now we know that have programmed all desired ports etc
1725 	 * into HW, so safe to mark reconfiguration as complete.
1726 	 */
1727 	vswp->recfg_reqd = B_FALSE;
1728 
1729 	vswp->smode_idx = s_idx;
1730 
1731 	D1(vswp, "%s: exit", __func__);
1732 }
1733 
1734 /*
1735  * Check to see if vsw itself is plumbed, and if so whether or not
1736  * its mac address should be written into HW.
1737  *
1738  * Returns 0 if could set address, or didn't have to set it.
1739  * Returns 1 if failed to set address.
1740  */
1741 static int
1742 vsw_prog_if(vsw_t *vswp)
1743 {
1744 	mac_multi_addr_t	addr;
1745 
1746 	D1(vswp, "%s: enter", __func__);
1747 
1748 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1749 
1750 	READ_ENTER(&vswp->if_lockrw);
1751 	if ((vswp->if_state & VSW_IF_UP) &&
1752 		(vswp->addr_set != VSW_ADDR_HW)) {
1753 
1754 		addr.mma_addrlen = ETHERADDRL;
1755 		ether_copy(&vswp->if_addr, &addr.mma_addr);
1756 
1757 		if (vsw_set_hw_addr(vswp, &addr) != 0) {
1758 			RW_EXIT(&vswp->if_lockrw);
1759 			return (1);
1760 		}
1761 
1762 		vswp->addr_slot = addr.mma_slot;
1763 
1764 		/*
1765 		 * If previously when plumbed had had to place
1766 		 * interface into promisc mode, now reverse that.
1767 		 *
1768 		 * Note that interface will only actually be set into
1769 		 * non-promisc mode when last port/interface has been
1770 		 * programmed into HW.
1771 		 */
1772 		if (vswp->addr_set == VSW_ADDR_PROMISC)
1773 			(void) vsw_unset_hw_promisc(vswp, NULL, VSW_LOCALDEV);
1774 
1775 		vswp->addr_set = VSW_ADDR_HW;
1776 	}
1777 	RW_EXIT(&vswp->if_lockrw);
1778 
1779 	D1(vswp, "%s: exit", __func__);
1780 	return (0);
1781 }
1782 
1783 /*
1784  * Scan the port list for any ports which have not yet been set
1785  * into HW. For those found attempt to program their mac addresses
1786  * into the physical device.
1787  *
1788  * Returns 0 if able to program all required ports (can be 0) into HW.
1789  * Returns 1 if failed to set at least one mac address.
1790  */
1791 static int
1792 vsw_prog_ports(vsw_t *vswp)
1793 {
1794 	mac_multi_addr_t	addr;
1795 	vsw_port_list_t		*plist = &vswp->plist;
1796 	vsw_port_t		*tp;
1797 	int			rv = 0;
1798 
1799 	D1(vswp, "%s: enter", __func__);
1800 
1801 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
1802 
1803 	READ_ENTER(&plist->lockrw);
1804 	for (tp = plist->head; tp != NULL; tp = tp->p_next) {
1805 		if (tp->addr_set != VSW_ADDR_HW) {
1806 			addr.mma_addrlen = ETHERADDRL;
1807 			ether_copy(&tp->p_macaddr, &addr.mma_addr);
1808 
1809 			if (vsw_set_hw_addr(vswp, &addr) != 0) {
1810 				rv = 1;
1811 				break;
1812 			}
1813 
1814 			tp->addr_slot = addr.mma_slot;
1815 
1816 			/*
1817 			 * If when this port had first attached we had
1818 			 * had to place the interface into promisc mode,
1819 			 * then now reverse that.
1820 			 *
1821 			 * Note that the interface will not actually
1822 			 * change to non-promisc mode until all ports
1823 			 * have been programmed.
1824 			 */
1825 			if (tp->addr_set == VSW_ADDR_PROMISC)
1826 				(void) vsw_unset_hw_promisc(vswp,
1827 						tp, VSW_VNETPORT);
1828 
1829 			tp->addr_set = VSW_ADDR_HW;
1830 		}
1831 	}
1832 	RW_EXIT(&plist->lockrw);
1833 
1834 	D1(vswp, "%s: exit", __func__);
1835 	return (rv);
1836 }
1837 
1838 static void
1839 vsw_mac_ring_tbl_entry_init(vsw_t *vswp, vsw_mac_ring_t *ringp)
1840 {
1841 	ringp->ring_state = VSW_MAC_RING_FREE;
1842 	ringp->ring_arg = NULL;
1843 	ringp->ring_blank = NULL;
1844 	ringp->ring_vqp = NULL;
1845 	ringp->ring_vswp = vswp;
1846 }
1847 
1848 static void
1849 vsw_mac_ring_tbl_init(vsw_t *vswp)
1850 {
1851 	int		i;
1852 
1853 	mutex_init(&vswp->mac_ring_lock, NULL, MUTEX_DRIVER, NULL);
1854 
1855 	vswp->mac_ring_tbl_sz = vsw_mac_rx_rings;
1856 	vswp->mac_ring_tbl  =
1857 		kmem_alloc(vsw_mac_rx_rings * sizeof (vsw_mac_ring_t),
1858 		KM_SLEEP);
1859 
1860 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++)
1861 		vsw_mac_ring_tbl_entry_init(vswp, &vswp->mac_ring_tbl[i]);
1862 }
1863 
1864 static void
1865 vsw_mac_ring_tbl_destroy(vsw_t *vswp)
1866 {
1867 	int		i;
1868 	vsw_mac_ring_t	*ringp;
1869 
1870 	mutex_enter(&vswp->mac_ring_lock);
1871 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
1872 		ringp = &vswp->mac_ring_tbl[i];
1873 
1874 		if (ringp->ring_state != VSW_MAC_RING_FREE) {
1875 			/*
1876 			 * Destroy the queue.
1877 			 */
1878 			vsw_queue_stop(ringp->ring_vqp);
1879 			vsw_queue_destroy(ringp->ring_vqp);
1880 
1881 			/*
1882 			 * Re-initialize the structure.
1883 			 */
1884 			vsw_mac_ring_tbl_entry_init(vswp, ringp);
1885 		}
1886 	}
1887 	mutex_exit(&vswp->mac_ring_lock);
1888 
1889 	mutex_destroy(&vswp->mac_ring_lock);
1890 	kmem_free(vswp->mac_ring_tbl,
1891 		vswp->mac_ring_tbl_sz * sizeof (vsw_mac_ring_t));
1892 	vswp->mac_ring_tbl_sz = 0;
1893 }
1894 
1895 /*
1896  * Handle resource add callbacks from the driver below.
1897  */
1898 static mac_resource_handle_t
1899 vsw_mac_ring_add_cb(void *arg, mac_resource_t *mrp)
1900 {
1901 	vsw_t		*vswp = (vsw_t *)arg;
1902 	mac_rx_fifo_t	*mrfp = (mac_rx_fifo_t *)mrp;
1903 	vsw_mac_ring_t	*ringp;
1904 	vsw_queue_t	*vqp;
1905 	int		i;
1906 
1907 	ASSERT(vswp != NULL);
1908 	ASSERT(mrp != NULL);
1909 	ASSERT(vswp->mac_ring_tbl != NULL);
1910 
1911 	D1(vswp, "%s: enter", __func__);
1912 
1913 	/*
1914 	 * Check to make sure we have the correct resource type.
1915 	 */
1916 	if (mrp->mr_type != MAC_RX_FIFO)
1917 		return (NULL);
1918 
1919 	/*
1920 	 * Find a open entry in the ring table.
1921 	 */
1922 	mutex_enter(&vswp->mac_ring_lock);
1923 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
1924 		ringp = &vswp->mac_ring_tbl[i];
1925 
1926 		/*
1927 		 * Check for an empty slot, if found, then setup queue
1928 		 * and thread.
1929 		 */
1930 		if (ringp->ring_state == VSW_MAC_RING_FREE) {
1931 			/*
1932 			 * Create the queue for this ring.
1933 			 */
1934 			vqp = vsw_queue_create();
1935 
1936 			/*
1937 			 * Initialize the ring data structure.
1938 			 */
1939 			ringp->ring_vqp = vqp;
1940 			ringp->ring_arg = mrfp->mrf_arg;
1941 			ringp->ring_blank = mrfp->mrf_blank;
1942 			ringp->ring_state = VSW_MAC_RING_INUSE;
1943 
1944 			/*
1945 			 * Create the worker thread.
1946 			 */
1947 			vqp->vq_worker = thread_create(NULL, 0,
1948 				vsw_queue_worker, ringp, 0, &p0,
1949 				TS_RUN, minclsyspri);
1950 			if (vqp->vq_worker == NULL) {
1951 				vsw_queue_destroy(vqp);
1952 				vsw_mac_ring_tbl_entry_init(vswp, ringp);
1953 				ringp = NULL;
1954 			}
1955 
1956 			if (ringp != NULL) {
1957 				/*
1958 				 * Make sure thread get's running state for
1959 				 * this ring.
1960 				 */
1961 				mutex_enter(&vqp->vq_lock);
1962 				while ((vqp->vq_state != VSW_QUEUE_RUNNING) &&
1963 					(vqp->vq_state != VSW_QUEUE_DRAINED)) {
1964 					cv_wait(&vqp->vq_cv, &vqp->vq_lock);
1965 				}
1966 
1967 				/*
1968 				 * If the thread is not running, cleanup.
1969 				 */
1970 				if (vqp->vq_state == VSW_QUEUE_DRAINED) {
1971 					vsw_queue_destroy(vqp);
1972 					vsw_mac_ring_tbl_entry_init(vswp,
1973 						ringp);
1974 					ringp = NULL;
1975 				}
1976 				mutex_exit(&vqp->vq_lock);
1977 			}
1978 
1979 			mutex_exit(&vswp->mac_ring_lock);
1980 			D1(vswp, "%s: exit", __func__);
1981 			return ((mac_resource_handle_t)ringp);
1982 		}
1983 	}
1984 	mutex_exit(&vswp->mac_ring_lock);
1985 
1986 	/*
1987 	 * No slots in the ring table available.
1988 	 */
1989 	D1(vswp, "%s: exit", __func__);
1990 	return (NULL);
1991 }
1992 
1993 static void
1994 vsw_queue_stop(vsw_queue_t *vqp)
1995 {
1996 	mutex_enter(&vqp->vq_lock);
1997 
1998 	if (vqp->vq_state == VSW_QUEUE_RUNNING) {
1999 		vqp->vq_state = VSW_QUEUE_STOP;
2000 		cv_signal(&vqp->vq_cv);
2001 
2002 		while (vqp->vq_state != VSW_QUEUE_DRAINED)
2003 			cv_wait(&vqp->vq_cv, &vqp->vq_lock);
2004 	}
2005 
2006 	vqp->vq_state = VSW_QUEUE_STOPPED;
2007 
2008 	mutex_exit(&vqp->vq_lock);
2009 }
2010 
2011 static vsw_queue_t *
2012 vsw_queue_create()
2013 {
2014 	vsw_queue_t *vqp;
2015 
2016 	vqp = kmem_zalloc(sizeof (vsw_queue_t), KM_SLEEP);
2017 
2018 	mutex_init(&vqp->vq_lock, NULL, MUTEX_DRIVER, NULL);
2019 	cv_init(&vqp->vq_cv, NULL, CV_DRIVER, NULL);
2020 	vqp->vq_first = NULL;
2021 	vqp->vq_last = NULL;
2022 	vqp->vq_state = VSW_QUEUE_STOPPED;
2023 
2024 	return (vqp);
2025 }
2026 
2027 static void
2028 vsw_queue_destroy(vsw_queue_t *vqp)
2029 {
2030 	cv_destroy(&vqp->vq_cv);
2031 	mutex_destroy(&vqp->vq_lock);
2032 	kmem_free(vqp, sizeof (vsw_queue_t));
2033 }
2034 
2035 static void
2036 vsw_queue_worker(vsw_mac_ring_t *rrp)
2037 {
2038 	mblk_t		*mp;
2039 	vsw_queue_t	*vqp = rrp->ring_vqp;
2040 	vsw_t		*vswp = rrp->ring_vswp;
2041 
2042 	mutex_enter(&vqp->vq_lock);
2043 
2044 	ASSERT(vqp->vq_state == VSW_QUEUE_STOPPED);
2045 
2046 	/*
2047 	 * Set the state to running, since the thread is now active.
2048 	 */
2049 	vqp->vq_state = VSW_QUEUE_RUNNING;
2050 	cv_signal(&vqp->vq_cv);
2051 
2052 	while (vqp->vq_state == VSW_QUEUE_RUNNING) {
2053 		/*
2054 		 * Wait for work to do or the state has changed
2055 		 * to not running.
2056 		 */
2057 		while ((vqp->vq_state == VSW_QUEUE_RUNNING) &&
2058 				(vqp->vq_first == NULL)) {
2059 			cv_wait(&vqp->vq_cv, &vqp->vq_lock);
2060 		}
2061 
2062 		/*
2063 		 * Process packets that we received from the interface.
2064 		 */
2065 		if (vqp->vq_first != NULL) {
2066 			mp = vqp->vq_first;
2067 
2068 			vqp->vq_first = NULL;
2069 			vqp->vq_last = NULL;
2070 
2071 			mutex_exit(&vqp->vq_lock);
2072 
2073 			/* switch the chain of packets received */
2074 			vswp->vsw_switch_frame(vswp, mp,
2075 						VSW_PHYSDEV, NULL, NULL);
2076 
2077 			mutex_enter(&vqp->vq_lock);
2078 		}
2079 	}
2080 
2081 	/*
2082 	 * We are drained and signal we are done.
2083 	 */
2084 	vqp->vq_state = VSW_QUEUE_DRAINED;
2085 	cv_signal(&vqp->vq_cv);
2086 
2087 	/*
2088 	 * Exit lock and drain the remaining packets.
2089 	 */
2090 	mutex_exit(&vqp->vq_lock);
2091 
2092 	/*
2093 	 * Exit the thread
2094 	 */
2095 	thread_exit();
2096 }
2097 
2098 /*
2099  * static void
2100  * vsw_rx_queue_cb() - Receive callback routine when
2101  *	vsw_multi_ring_enable is non-zero.  Queue the packets
2102  *	to a packet queue for a worker thread to process.
2103  */
2104 static void
2105 vsw_rx_queue_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
2106 {
2107 	vsw_mac_ring_t	*ringp = (vsw_mac_ring_t *)mrh;
2108 	vsw_t		*vswp = (vsw_t *)arg;
2109 	vsw_queue_t	*vqp;
2110 	mblk_t		*bp, *last;
2111 
2112 	ASSERT(mrh != NULL);
2113 	ASSERT(vswp != NULL);
2114 	ASSERT(mp != NULL);
2115 
2116 	D1(vswp, "%s: enter", __func__);
2117 
2118 	/*
2119 	 * Find the last element in the mblk chain.
2120 	 */
2121 	bp = mp;
2122 	do {
2123 		last = bp;
2124 		bp = bp->b_next;
2125 	} while (bp != NULL);
2126 
2127 	/* Get the queue for the packets */
2128 	vqp = ringp->ring_vqp;
2129 
2130 	/*
2131 	 * Grab the lock such we can queue the packets.
2132 	 */
2133 	mutex_enter(&vqp->vq_lock);
2134 
2135 	if (vqp->vq_state != VSW_QUEUE_RUNNING) {
2136 		freemsg(mp);
2137 		mutex_exit(&vqp->vq_lock);
2138 		goto vsw_rx_queue_cb_exit;
2139 	}
2140 
2141 	/*
2142 	 * Add the mblk chain to the queue.  If there
2143 	 * is some mblks in the queue, then add the new
2144 	 * chain to the end.
2145 	 */
2146 	if (vqp->vq_first == NULL)
2147 		vqp->vq_first = mp;
2148 	else
2149 		vqp->vq_last->b_next = mp;
2150 
2151 	vqp->vq_last = last;
2152 
2153 	/*
2154 	 * Signal the worker thread that there is work to
2155 	 * do.
2156 	 */
2157 	cv_signal(&vqp->vq_cv);
2158 
2159 	/*
2160 	 * Let go of the lock and exit.
2161 	 */
2162 	mutex_exit(&vqp->vq_lock);
2163 
2164 vsw_rx_queue_cb_exit:
2165 	D1(vswp, "%s: exit", __func__);
2166 }
2167 
2168 /*
2169  * receive callback routine. Invoked by MAC layer when there
2170  * are pkts being passed up from physical device.
2171  *
2172  * PERF: It may be more efficient when the card is in promisc
2173  * mode to check the dest address of the pkts here (against
2174  * the FDB) rather than checking later. Needs to be investigated.
2175  */
2176 static void
2177 vsw_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
2178 {
2179 	_NOTE(ARGUNUSED(mrh))
2180 
2181 	vsw_t		*vswp = (vsw_t *)arg;
2182 
2183 	ASSERT(vswp != NULL);
2184 
2185 	D1(vswp, "vsw_rx_cb: enter");
2186 
2187 	/* switch the chain of packets received */
2188 	vswp->vsw_switch_frame(vswp, mp, VSW_PHYSDEV, NULL, NULL);
2189 
2190 	D1(vswp, "vsw_rx_cb: exit");
2191 }
2192 
2193 /*
2194  * Send a message out over the physical device via the MAC layer.
2195  *
2196  * Returns any mblks that it was unable to transmit.
2197  */
2198 static mblk_t *
2199 vsw_tx_msg(vsw_t *vswp, mblk_t *mp)
2200 {
2201 	const mac_txinfo_t	*mtp;
2202 	mblk_t			*nextp;
2203 
2204 	mutex_enter(&vswp->mac_lock);
2205 	if (vswp->mh == NULL) {
2206 		DERR(vswp, "vsw_tx_msg: dropping pkts: no tx routine avail");
2207 		mutex_exit(&vswp->mac_lock);
2208 		return (mp);
2209 	} else {
2210 		for (;;) {
2211 			nextp = mp->b_next;
2212 			mp->b_next = NULL;
2213 
2214 			mtp = vswp->txinfo;
2215 
2216 			if ((mp = mtp->mt_fn(mtp->mt_arg, mp)) != NULL) {
2217 				mp->b_next = nextp;
2218 				break;
2219 			}
2220 
2221 			if ((mp = nextp) == NULL)
2222 				break;
2223 		}
2224 	}
2225 	mutex_exit(&vswp->mac_lock);
2226 
2227 	return (mp);
2228 }
2229 
2230 /*
2231  * Register with the MAC layer as a network device, so we
2232  * can be plumbed if necessary.
2233  */
2234 static int
2235 vsw_mac_register(vsw_t *vswp)
2236 {
2237 	mac_register_t	*macp;
2238 	int		rv;
2239 
2240 	D1(vswp, "%s: enter", __func__);
2241 
2242 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2243 		return (EINVAL);
2244 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2245 	macp->m_driver = vswp;
2246 	macp->m_dip = vswp->dip;
2247 	macp->m_src_addr = (uint8_t *)&vswp->if_addr;
2248 	macp->m_callbacks = &vsw_m_callbacks;
2249 	macp->m_min_sdu = 0;
2250 	macp->m_max_sdu = ETHERMTU;
2251 	rv = mac_register(macp, &vswp->if_mh);
2252 	mac_free(macp);
2253 	if (rv == 0)
2254 		vswp->if_state |= VSW_IF_REG;
2255 
2256 	D1(vswp, "%s: exit", __func__);
2257 
2258 	return (rv);
2259 }
2260 
2261 static int
2262 vsw_mac_unregister(vsw_t *vswp)
2263 {
2264 	int		rv = 0;
2265 
2266 	D1(vswp, "%s: enter", __func__);
2267 
2268 	WRITE_ENTER(&vswp->if_lockrw);
2269 
2270 	if (vswp->if_state & VSW_IF_REG) {
2271 		rv = mac_unregister(vswp->if_mh);
2272 		if (rv != 0) {
2273 			DWARN(vswp, "%s: unable to unregister from MAC "
2274 				"framework", __func__);
2275 
2276 			RW_EXIT(&vswp->if_lockrw);
2277 			D1(vswp, "%s: fail exit", __func__);
2278 			return (rv);
2279 		}
2280 
2281 		/* mark i/f as down and unregistered */
2282 		vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG);
2283 	}
2284 	RW_EXIT(&vswp->if_lockrw);
2285 
2286 	D1(vswp, "%s: exit", __func__);
2287 
2288 	return (rv);
2289 }
2290 
2291 static int
2292 vsw_m_stat(void *arg, uint_t stat, uint64_t *val)
2293 {
2294 	vsw_t			*vswp = (vsw_t *)arg;
2295 
2296 	D1(vswp, "%s: enter", __func__);
2297 
2298 	mutex_enter(&vswp->mac_lock);
2299 	if (vswp->mh == NULL) {
2300 		mutex_exit(&vswp->mac_lock);
2301 		return (EINVAL);
2302 	}
2303 
2304 	/* return stats from underlying device */
2305 	*val = mac_stat_get(vswp->mh, stat);
2306 
2307 	mutex_exit(&vswp->mac_lock);
2308 
2309 	return (0);
2310 }
2311 
2312 static void
2313 vsw_m_stop(void *arg)
2314 {
2315 	vsw_t		*vswp = (vsw_t *)arg;
2316 
2317 	D1(vswp, "%s: enter", __func__);
2318 
2319 	WRITE_ENTER(&vswp->if_lockrw);
2320 	vswp->if_state &= ~VSW_IF_UP;
2321 	RW_EXIT(&vswp->if_lockrw);
2322 
2323 	mutex_enter(&vswp->hw_lock);
2324 
2325 	(void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
2326 
2327 	if (vswp->recfg_reqd)
2328 		vsw_reconfig_hw(vswp);
2329 
2330 	mutex_exit(&vswp->hw_lock);
2331 
2332 	D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state);
2333 }
2334 
2335 static int
2336 vsw_m_start(void *arg)
2337 {
2338 	vsw_t		*vswp = (vsw_t *)arg;
2339 
2340 	D1(vswp, "%s: enter", __func__);
2341 
2342 	WRITE_ENTER(&vswp->if_lockrw);
2343 	vswp->if_state |= VSW_IF_UP;
2344 	RW_EXIT(&vswp->if_lockrw);
2345 
2346 	mutex_enter(&vswp->hw_lock);
2347 	(void) vsw_set_hw(vswp, NULL, VSW_LOCALDEV);
2348 	mutex_exit(&vswp->hw_lock);
2349 
2350 	D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state);
2351 	return (0);
2352 }
2353 
2354 /*
2355  * Change the local interface address.
2356  *
2357  * Note: we don't support this entry point. The local
2358  * mac address of the switch can only be changed via its
2359  * MD node properties.
2360  */
2361 static int
2362 vsw_m_unicst(void *arg, const uint8_t *macaddr)
2363 {
2364 	_NOTE(ARGUNUSED(arg, macaddr))
2365 
2366 	return (DDI_FAILURE);
2367 }
2368 
2369 static int
2370 vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
2371 {
2372 	vsw_t		*vswp = (vsw_t *)arg;
2373 	mcst_addr_t	*mcst_p = NULL;
2374 	uint64_t	addr = 0x0;
2375 	int		i, ret = 0;
2376 
2377 	D1(vswp, "%s: enter", __func__);
2378 
2379 	/*
2380 	 * Convert address into form that can be used
2381 	 * as hash table key.
2382 	 */
2383 	for (i = 0; i < ETHERADDRL; i++) {
2384 		addr = (addr << 8) | mca[i];
2385 	}
2386 
2387 	D2(vswp, "%s: addr = 0x%llx", __func__, addr);
2388 
2389 	if (add) {
2390 		D2(vswp, "%s: adding multicast", __func__);
2391 		if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) {
2392 			/*
2393 			 * Update the list of multicast addresses
2394 			 * contained within the vsw_t structure to
2395 			 * include this new one.
2396 			 */
2397 			mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP);
2398 			if (mcst_p == NULL) {
2399 				DERR(vswp, "%s unable to alloc mem", __func__);
2400 				return (1);
2401 			}
2402 			mcst_p->addr = addr;
2403 
2404 			mutex_enter(&vswp->mca_lock);
2405 			mcst_p->nextp = vswp->mcap;
2406 			vswp->mcap = mcst_p;
2407 			mutex_exit(&vswp->mca_lock);
2408 
2409 			/*
2410 			 * Call into the underlying driver to program the
2411 			 * address into HW.
2412 			 */
2413 			mutex_enter(&vswp->mac_lock);
2414 			if (vswp->mh != NULL) {
2415 				ret = mac_multicst_add(vswp->mh, mca);
2416 				if (ret != 0) {
2417 					cmn_err(CE_WARN, "!vsw%d: unable to "
2418 						"add multicast address",
2419 						vswp->instance);
2420 					mutex_exit(&vswp->mac_lock);
2421 					goto vsw_remove_addr;
2422 				}
2423 			}
2424 			mutex_exit(&vswp->mac_lock);
2425 		} else {
2426 			cmn_err(CE_WARN, "!vsw%d: unable to add multicast "
2427 				"address", vswp->instance);
2428 		}
2429 		return (ret);
2430 	}
2431 
2432 vsw_remove_addr:
2433 
2434 	D2(vswp, "%s: removing multicast", __func__);
2435 	/*
2436 	 * Remove the address from the hash table..
2437 	 */
2438 	if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) {
2439 
2440 		/*
2441 		 * ..and then from the list maintained in the
2442 		 * vsw_t structure.
2443 		 */
2444 		vsw_del_addr(VSW_LOCALDEV, vswp, addr);
2445 
2446 		mutex_enter(&vswp->mac_lock);
2447 		if (vswp->mh != NULL)
2448 			(void) mac_multicst_remove(vswp->mh, mca);
2449 		mutex_exit(&vswp->mac_lock);
2450 	}
2451 
2452 	D1(vswp, "%s: exit", __func__);
2453 
2454 	return (0);
2455 }
2456 
2457 static int
2458 vsw_m_promisc(void *arg, boolean_t on)
2459 {
2460 	vsw_t		*vswp = (vsw_t *)arg;
2461 
2462 	D1(vswp, "%s: enter", __func__);
2463 
2464 	WRITE_ENTER(&vswp->if_lockrw);
2465 	if (on)
2466 		vswp->if_state |= VSW_IF_PROMISC;
2467 	else
2468 		vswp->if_state &= ~VSW_IF_PROMISC;
2469 	RW_EXIT(&vswp->if_lockrw);
2470 
2471 	D1(vswp, "%s: exit", __func__);
2472 
2473 	return (0);
2474 }
2475 
2476 static mblk_t *
2477 vsw_m_tx(void *arg, mblk_t *mp)
2478 {
2479 	vsw_t		*vswp = (vsw_t *)arg;
2480 
2481 	D1(vswp, "%s: enter", __func__);
2482 
2483 	vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL);
2484 
2485 	D1(vswp, "%s: exit", __func__);
2486 
2487 	return (NULL);
2488 }
2489 
2490 /*
2491  * Register for machine description (MD) updates.
2492  *
2493  * Returns 0 on success, 1 on failure.
2494  */
2495 static int
2496 vsw_mdeg_register(vsw_t *vswp)
2497 {
2498 	mdeg_prop_spec_t	*pspecp;
2499 	mdeg_node_spec_t	*inst_specp;
2500 	mdeg_handle_t		mdeg_hdl, mdeg_port_hdl;
2501 	size_t			templatesz;
2502 	int			inst, rv;
2503 
2504 	D1(vswp, "%s: enter", __func__);
2505 
2506 	/*
2507 	 * In each 'virtual-device' node in the MD there is a
2508 	 * 'cfg-handle' property which is the MD's concept of
2509 	 * an instance number (this may be completely different from
2510 	 * the device drivers instance #). OBP reads that value and
2511 	 * stores it in the 'reg' property of the appropriate node in
2512 	 * the device tree. So we use the 'reg' value when registering
2513 	 * with the mdeg framework, to ensure we get events for the
2514 	 * correct nodes.
2515 	 */
2516 	inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip,
2517 		DDI_PROP_DONTPASS, reg_propname, -1);
2518 	if (inst == -1) {
2519 		cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from "
2520 			"OBP device tree", vswp->instance, reg_propname);
2521 		return (1);
2522 	}
2523 
2524 	D2(vswp, "%s: instance %d registering with mdeg", __func__, inst);
2525 
2526 	/*
2527 	 * Allocate and initialize a per-instance copy
2528 	 * of the global property spec array that will
2529 	 * uniquely identify this vsw instance.
2530 	 */
2531 	templatesz = sizeof (vsw_prop_template);
2532 	pspecp = kmem_zalloc(templatesz, KM_SLEEP);
2533 
2534 	bcopy(vsw_prop_template, pspecp, templatesz);
2535 
2536 	VSW_SET_MDEG_PROP_INST(pspecp, inst);
2537 
2538 	/* initialize the complete prop spec structure */
2539 	inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP);
2540 	inst_specp->namep = "virtual-device";
2541 	inst_specp->specp = pspecp;
2542 
2543 	/*
2544 	 * Register an interest in 'virtual-device' nodes with a
2545 	 * 'name' property of 'virtual-network-switch'
2546 	 */
2547 	rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb,
2548 	    (void *)vswp, &mdeg_hdl);
2549 	if (rv != MDEG_SUCCESS) {
2550 		DERR(vswp, "%s: mdeg_register failed (%d) for vsw node",
2551 			__func__, rv);
2552 		goto mdeg_reg_fail;
2553 	}
2554 
2555 	/*
2556 	 * Register an interest in 'vsw-port' nodes.
2557 	 */
2558 	rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb,
2559 	    (void *)vswp, &mdeg_port_hdl);
2560 	if (rv != MDEG_SUCCESS) {
2561 		DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv);
2562 		(void) mdeg_unregister(mdeg_hdl);
2563 		goto mdeg_reg_fail;
2564 	}
2565 
2566 	/* save off data that will be needed later */
2567 	vswp->inst_spec = inst_specp;
2568 	vswp->mdeg_hdl = mdeg_hdl;
2569 	vswp->mdeg_port_hdl = mdeg_port_hdl;
2570 
2571 	D1(vswp, "%s: exit", __func__);
2572 	return (0);
2573 
2574 mdeg_reg_fail:
2575 	cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks",
2576 				vswp->instance);
2577 	kmem_free(pspecp, templatesz);
2578 	kmem_free(inst_specp, sizeof (mdeg_node_spec_t));
2579 
2580 	vswp->mdeg_hdl = NULL;
2581 	vswp->mdeg_port_hdl = NULL;
2582 
2583 	return (1);
2584 }
2585 
2586 static void
2587 vsw_mdeg_unregister(vsw_t *vswp)
2588 {
2589 	D1(vswp, "vsw_mdeg_unregister: enter");
2590 
2591 	if (vswp->mdeg_hdl != NULL)
2592 		(void) mdeg_unregister(vswp->mdeg_hdl);
2593 
2594 	if (vswp->mdeg_port_hdl != NULL)
2595 		(void) mdeg_unregister(vswp->mdeg_port_hdl);
2596 
2597 	if (vswp->inst_spec != NULL) {
2598 		if (vswp->inst_spec->specp != NULL) {
2599 			(void) kmem_free(vswp->inst_spec->specp,
2600 				sizeof (vsw_prop_template));
2601 			vswp->inst_spec->specp = NULL;
2602 		}
2603 
2604 		(void) kmem_free(vswp->inst_spec,
2605 			sizeof (mdeg_node_spec_t));
2606 		vswp->inst_spec = NULL;
2607 	}
2608 
2609 	D1(vswp, "vsw_mdeg_unregister: exit");
2610 }
2611 
2612 /*
2613  * Mdeg callback invoked for the vsw node itself.
2614  */
2615 static int
2616 vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
2617 {
2618 	vsw_t		*vswp;
2619 	int		idx;
2620 	md_t		*mdp;
2621 	mde_cookie_t	node;
2622 	uint64_t	inst;
2623 	char		*node_name = NULL;
2624 
2625 	if (resp == NULL)
2626 		return (MDEG_FAILURE);
2627 
2628 	vswp = (vsw_t *)cb_argp;
2629 
2630 	D1(vswp, "%s: added %d : removed %d : curr matched %d"
2631 		" : prev matched %d", __func__, resp->added.nelem,
2632 		resp->removed.nelem, resp->match_curr.nelem,
2633 		resp->match_prev.nelem);
2634 
2635 	/*
2636 	 * Expect 'added' to be non-zero if virtual-network-switch
2637 	 * nodes exist in the MD when the driver attaches.
2638 	 */
2639 	for (idx = 0; idx < resp->added.nelem; idx++) {
2640 		mdp = resp->added.mdp;
2641 		node = resp->added.mdep[idx];
2642 
2643 		if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
2644 			DERR(vswp, "%s: unable to get node name for "
2645 				"node(%d) 0x%lx", __func__, idx, node);
2646 			continue;
2647 		}
2648 
2649 		if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
2650 			DERR(vswp, "%s: prop(cfg-handle) not found port(%d)",
2651 				__func__, idx);
2652 			continue;
2653 		}
2654 
2655 		D2(vswp, "%s: added node(%d) 0x%lx with name %s "
2656 			"and inst %d", __func__, idx, node, node_name, inst);
2657 
2658 		vsw_get_initial_md_properties(vswp, mdp, node);
2659 	}
2660 
2661 	/*
2662 	 * A non-zero 'match' value indicates that the MD has been
2663 	 * updated and that a virtual-network-switch node is present
2664 	 * which may or may not have been updated. It is up to the clients
2665 	 * to examine their own nodes and determine if they have changed.
2666 	 */
2667 	for (idx = 0; idx < resp->match_curr.nelem; idx++) {
2668 		mdp = resp->match_curr.mdp;
2669 		node = resp->match_curr.mdep[idx];
2670 
2671 		if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
2672 			DERR(vswp, "%s: unable to get node name for "
2673 				"node(%d) 0x%lx", __func__, idx, node);
2674 			continue;
2675 		}
2676 
2677 		if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
2678 			DERR(vswp, "%s: prop(cfg-handle) not found port(%d)",
2679 				__func__, idx);
2680 			continue;
2681 		}
2682 
2683 		D2(vswp, "%s: changed node(%d) 0x%lx with name %s "
2684 			"and inst %d", __func__, idx, node, node_name, inst);
2685 
2686 		vsw_update_md_prop(vswp, mdp, node);
2687 	}
2688 
2689 	return (MDEG_SUCCESS);
2690 }
2691 
2692 /*
2693  * Mdeg callback invoked for changes to the vsw-port nodes
2694  * under the vsw node.
2695  */
2696 static int
2697 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
2698 {
2699 	vsw_t		*vswp;
2700 	int		idx;
2701 	md_t		*mdp;
2702 	mde_cookie_t	node;
2703 	uint64_t	inst;
2704 
2705 	if ((resp == NULL) || (cb_argp == NULL))
2706 		return (MDEG_FAILURE);
2707 
2708 	vswp = (vsw_t *)cb_argp;
2709 
2710 	D2(vswp, "%s: added %d : removed %d : curr matched %d"
2711 		" : prev matched %d", __func__, resp->added.nelem,
2712 		resp->removed.nelem, resp->match_curr.nelem,
2713 		resp->match_prev.nelem);
2714 
2715 	/* process added ports */
2716 	for (idx = 0; idx < resp->added.nelem; idx++) {
2717 		mdp = resp->added.mdp;
2718 		node = resp->added.mdep[idx];
2719 
2720 		D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node);
2721 
2722 		if (vsw_port_add(vswp, mdp, &node) != 0) {
2723 			cmn_err(CE_WARN, "!vsw%d: Unable to add new port "
2724 				"(0x%lx)", vswp->instance, node);
2725 		}
2726 	}
2727 
2728 	/* process removed ports */
2729 	for (idx = 0; idx < resp->removed.nelem; idx++) {
2730 		mdp = resp->removed.mdp;
2731 		node = resp->removed.mdep[idx];
2732 
2733 		if (md_get_prop_val(mdp, node, id_propname, &inst)) {
2734 			DERR(vswp, "%s: prop(%s) not found in port(%d)",
2735 				__func__, id_propname, idx);
2736 			continue;
2737 		}
2738 
2739 		D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node);
2740 
2741 		if (vsw_port_detach(vswp, inst) != 0) {
2742 			cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld",
2743 				vswp->instance, inst);
2744 		}
2745 	}
2746 
2747 	/*
2748 	 * Currently no support for updating already active ports.
2749 	 * So, ignore the match_curr and match_priv arrays for now.
2750 	 */
2751 
2752 	D1(vswp, "%s: exit", __func__);
2753 
2754 	return (MDEG_SUCCESS);
2755 }
2756 
2757 /*
2758  * Read the initial start-of-day values from the specified MD node.
2759  */
2760 static void
2761 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node)
2762 {
2763 	int		i;
2764 	uint64_t 	macaddr = 0;
2765 
2766 	D1(vswp, "%s: enter", __func__);
2767 
2768 	if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) == 0) {
2769 		/*
2770 		 * Note it is valid for the physname property to
2771 		 * be NULL so check actual name length to determine
2772 		 * if we have a actual device name.
2773 		 */
2774 		if (strlen(vswp->physname) > 0)
2775 			vswp->mdprops |= VSW_MD_PHYSNAME;
2776 	} else {
2777 		cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical "
2778 			"device from MD", vswp->instance);
2779 		return;
2780 	}
2781 
2782 	/* mac address for vswitch device itself */
2783 	if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) {
2784 		cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD",
2785 			vswp->instance);
2786 
2787 		/*
2788 		 * Fallback to using the mac address of the physical
2789 		 * device.
2790 		 */
2791 		if (vsw_get_physaddr(vswp) == 0) {
2792 			cmn_err(CE_NOTE, "!vsw%d: Using MAC address from "
2793 				"physical device (%s)", vswp->instance,
2794 				vswp->physname);
2795 		} else {
2796 			cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address"
2797 				"from device %s", vswp->instance,
2798 				vswp->physname);
2799 		}
2800 	} else {
2801 		WRITE_ENTER(&vswp->if_lockrw);
2802 		for (i = ETHERADDRL - 1; i >= 0; i--) {
2803 			vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF;
2804 			macaddr >>= 8;
2805 		}
2806 		RW_EXIT(&vswp->if_lockrw);
2807 		vswp->mdprops |= VSW_MD_MACADDR;
2808 	}
2809 
2810 	if (vsw_get_md_smodes(vswp, mdp, node,
2811 				vswp->smode, &vswp->smode_num)) {
2812 		cmn_err(CE_WARN, "vsw%d: Unable to read %s property from "
2813 			"MD, defaulting to programmed mode", vswp->instance,
2814 			smode_propname);
2815 
2816 		for (i = 0; i < NUM_SMODES; i++)
2817 			vswp->smode[i] = VSW_LAYER2;
2818 
2819 		vswp->smode_num = NUM_SMODES;
2820 	} else {
2821 		ASSERT(vswp->smode_num != 0);
2822 		vswp->mdprops |= VSW_MD_SMODE;
2823 	}
2824 
2825 	/*
2826 	 * Unable to setup any switching mode, nothing more
2827 	 * we can do.
2828 	 */
2829 	if (vsw_setup_switching(vswp))
2830 		return;
2831 
2832 	WRITE_ENTER(&vswp->if_lockrw);
2833 	vswp->if_state &= ~VSW_IF_UP;
2834 	RW_EXIT(&vswp->if_lockrw);
2835 	if (vswp->mdprops & (VSW_MD_MACADDR | VSW_DEV_MACADDR)) {
2836 		if (vsw_mac_register(vswp) != 0) {
2837 			/*
2838 			 * Treat this as a non-fatal error as we may be
2839 			 * able to operate in some other mode.
2840 			 */
2841 			cmn_err(CE_WARN, "vsw%d: Unable to register as "
2842 				"provider with MAC layer", vswp->instance);
2843 		}
2844 	}
2845 
2846 	D1(vswp, "%s: exit", __func__);
2847 }
2848 
2849 /*
2850  * Check to see if the relevant properties in the specified node have
2851  * changed, and if so take the appropriate action.
2852  *
2853  * If any of the properties are missing or invalid we don't take
2854  * any action, as this function should only be invoked when modifications
2855  * have been made to what we assume is a working configuration, which
2856  * we leave active.
2857  *
2858  * Note it is legal for this routine to be invoked even if none of the
2859  * properties in the port node within the MD have actually changed.
2860  */
2861 static void
2862 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node)
2863 {
2864 	char		physname[LIFNAMSIZ];
2865 	char		drv[LIFNAMSIZ];
2866 	uint_t		ddi_instance;
2867 	uint8_t		new_smode[NUM_SMODES];
2868 	int		i, smode_num = 0;
2869 	uint64_t 	macaddr = 0;
2870 	vsw_port_list_t *plist = &vswp->plist;
2871 	vsw_port_t	*port = NULL;
2872 	enum		{MD_init = 0x1,
2873 				MD_physname = 0x2,
2874 				MD_macaddr = 0x4,
2875 				MD_smode = 0x8} updated;
2876 
2877 	updated = MD_init;
2878 
2879 	D1(vswp, "%s: enter", __func__);
2880 
2881 	/*
2882 	 * Check if name of physical device in MD has changed.
2883 	 */
2884 	if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) {
2885 		/*
2886 		 * Do basic sanity check on new device name/instance,
2887 		 * if its non NULL. It is valid for the device name to
2888 		 * have changed from a non NULL to a NULL value, i.e.
2889 		 * the vsw is being changed to 'routed' mode.
2890 		 */
2891 		if ((strlen(physname) != 0) &&
2892 			(ddi_parse(physname, drv,
2893 				&ddi_instance) != DDI_SUCCESS)) {
2894 			cmn_err(CE_WARN, "!vsw%d: new device name %s is not"
2895 				" a valid device name/instance",
2896 				vswp->instance, physname);
2897 			goto fail_reconf;
2898 		}
2899 
2900 		if (strcmp(physname, vswp->physname)) {
2901 			D2(vswp, "%s: device name changed from %s to %s",
2902 					__func__, vswp->physname, physname);
2903 
2904 			updated |= MD_physname;
2905 		} else {
2906 			D2(vswp, "%s: device name unchanged at %s",
2907 					__func__, vswp->physname);
2908 		}
2909 	} else {
2910 		cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical "
2911 			"device from updated MD.", vswp->instance);
2912 		goto fail_reconf;
2913 	}
2914 
2915 	/*
2916 	 * Check if MAC address has changed.
2917 	 */
2918 	if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) {
2919 		cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD",
2920 			vswp->instance);
2921 		goto fail_reconf;
2922 	} else {
2923 		READ_ENTER(&vswp->if_lockrw);
2924 		for (i = ETHERADDRL - 1; i >= 0; i--) {
2925 			if (vswp->if_addr.ether_addr_octet[i]
2926 							!= (macaddr & 0xFF)) {
2927 				D2(vswp, "%s: octet[%d] 0x%x != 0x%x",
2928 					__func__, i,
2929 					vswp->if_addr.ether_addr_octet[i],
2930 					(macaddr & 0xFF));
2931 				updated |= MD_macaddr;
2932 				break;
2933 			}
2934 			macaddr >>= 8;
2935 		}
2936 		RW_EXIT(&vswp->if_lockrw);
2937 	}
2938 
2939 	/*
2940 	 * Check if switching modes have changed.
2941 	 */
2942 	if (vsw_get_md_smodes(vswp, mdp, node,
2943 				new_smode, &smode_num)) {
2944 		cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD",
2945 					vswp->instance, smode_propname);
2946 		goto fail_reconf;
2947 	} else {
2948 		ASSERT(smode_num != 0);
2949 		if (smode_num != vswp->smode_num) {
2950 			D2(vswp, "%s: number of modes changed from %d to %d",
2951 				__func__, vswp->smode_num, smode_num);
2952 		}
2953 
2954 		for (i = 0; i < smode_num; i++) {
2955 			if (new_smode[i] != vswp->smode[i]) {
2956 				D2(vswp, "%s: mode changed from %d to %d",
2957 					__func__, vswp->smode[i], new_smode[i]);
2958 				updated |= MD_smode;
2959 				break;
2960 			}
2961 		}
2962 	}
2963 
2964 	/*
2965 	 * Now make any changes which are needed...
2966 	 */
2967 
2968 	if (updated & (MD_physname | MD_smode)) {
2969 		/*
2970 		 * Disconnect all ports from the current card
2971 		 */
2972 		WRITE_ENTER(&plist->lockrw);
2973 		for (port = plist->head; port != NULL; port = port->p_next) {
2974 			/* Remove address if was programmed into HW. */
2975 			mutex_enter(&vswp->hw_lock);
2976 			if (vsw_unset_hw(vswp, port, VSW_VNETPORT)) {
2977 				mutex_exit(&vswp->hw_lock);
2978 				RW_EXIT(&plist->lockrw);
2979 				goto fail_update;
2980 			}
2981 			mutex_exit(&vswp->hw_lock);
2982 		}
2983 		RW_EXIT(&plist->lockrw);
2984 
2985 		/*
2986 		 * Stop, detach the old device..
2987 		 */
2988 		vsw_mac_detach(vswp);
2989 
2990 		/*
2991 		 * Update phys name.
2992 		 */
2993 		if (updated & MD_physname) {
2994 			cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s",
2995 				vswp->instance, vswp->physname, physname);
2996 			(void) strncpy(vswp->physname,
2997 					physname, strlen(physname) + 1);
2998 
2999 			if (strlen(vswp->physname) > 0)
3000 				vswp->mdprops |= VSW_MD_PHYSNAME;
3001 		}
3002 
3003 		/*
3004 		 * Update array with the new switch mode values.
3005 		 */
3006 		if (updated & MD_smode) {
3007 			for (i = 0; i < smode_num; i++)
3008 				vswp->smode[i] = new_smode[i];
3009 
3010 			vswp->smode_num = smode_num;
3011 			vswp->smode_idx = 0;
3012 		}
3013 
3014 		/*
3015 		 * ..and attach, start the new device.
3016 		 */
3017 		if (vsw_setup_switching(vswp))
3018 			goto fail_update;
3019 
3020 		/*
3021 		 * Connect ports to new card.
3022 		 */
3023 		WRITE_ENTER(&plist->lockrw);
3024 		for (port = plist->head; port != NULL; port = port->p_next) {
3025 			mutex_enter(&vswp->hw_lock);
3026 			if (vsw_set_hw(vswp, port, VSW_VNETPORT)) {
3027 				mutex_exit(&vswp->hw_lock);
3028 				RW_EXIT(&plist->lockrw);
3029 				goto fail_update;
3030 			}
3031 			mutex_exit(&vswp->hw_lock);
3032 		}
3033 		RW_EXIT(&plist->lockrw);
3034 	}
3035 
3036 	if (updated & MD_macaddr) {
3037 		cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx",
3038 				vswp->instance, macaddr);
3039 
3040 		WRITE_ENTER(&vswp->if_lockrw);
3041 		for (i = ETHERADDRL - 1; i >= 0; i--) {
3042 			vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF;
3043 			macaddr >>= 8;
3044 		}
3045 		RW_EXIT(&vswp->if_lockrw);
3046 
3047 		/*
3048 		 * Remove old address from HW (if programmed) and set
3049 		 * new address.
3050 		 */
3051 		mutex_enter(&vswp->hw_lock);
3052 		(void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
3053 		(void) vsw_set_hw(vswp, NULL, VSW_LOCALDEV);
3054 		mutex_exit(&vswp->hw_lock);
3055 
3056 		/*
3057 		 * Notify the MAC layer of the changed address.
3058 		 */
3059 		mac_unicst_update(vswp->if_mh, (uint8_t *)&vswp->if_addr);
3060 	}
3061 
3062 	return;
3063 
3064 fail_reconf:
3065 	cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance);
3066 	return;
3067 
3068 fail_update:
3069 	cmn_err(CE_WARN, "!vsw%d: update of configuration failed",
3070 			vswp->instance);
3071 }
3072 
3073 /*
3074  * Add a new port to the system.
3075  *
3076  * Returns 0 on success, 1 on failure.
3077  */
3078 int
3079 vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node)
3080 {
3081 	uint64_t		ldc_id;
3082 	uint8_t			*addrp;
3083 	int			i, addrsz;
3084 	int			num_nodes = 0, nchan = 0;
3085 	int			listsz = 0;
3086 	mde_cookie_t		*listp = NULL;
3087 	struct ether_addr	ea;
3088 	uint64_t		macaddr;
3089 	uint64_t		inst = 0;
3090 	vsw_port_t		*port;
3091 
3092 	if (md_get_prop_val(mdp, *node, id_propname, &inst)) {
3093 		DWARN(vswp, "%s: prop(%s) not found", __func__,
3094 			id_propname);
3095 		return (1);
3096 	}
3097 
3098 	/*
3099 	 * Find the channel endpoint node(s) (which should be under this
3100 	 * port node) which contain the channel id(s).
3101 	 */
3102 	if ((num_nodes = md_node_count(mdp)) <= 0) {
3103 		DERR(vswp, "%s: invalid number of nodes found (%d)",
3104 			__func__, num_nodes);
3105 		return (1);
3106 	}
3107 
3108 	D2(vswp, "%s: %d nodes found", __func__, num_nodes);
3109 
3110 	/* allocate enough space for node list */
3111 	listsz = num_nodes * sizeof (mde_cookie_t);
3112 	listp = kmem_zalloc(listsz, KM_SLEEP);
3113 
3114 	nchan = md_scan_dag(mdp, *node,
3115 		md_find_name(mdp, chan_propname),
3116 		md_find_name(mdp, "fwd"), listp);
3117 
3118 	if (nchan <= 0) {
3119 		DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname);
3120 		kmem_free(listp, listsz);
3121 		return (1);
3122 	}
3123 
3124 	D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname);
3125 
3126 	/* use property from first node found */
3127 	if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) {
3128 		DWARN(vswp, "%s: prop(%s) not found\n", __func__,
3129 			id_propname);
3130 		kmem_free(listp, listsz);
3131 		return (1);
3132 	}
3133 
3134 	/* don't need list any more */
3135 	kmem_free(listp, listsz);
3136 
3137 	D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id);
3138 
3139 	/* read mac-address property */
3140 	if (md_get_prop_data(mdp, *node, remaddr_propname,
3141 					&addrp, &addrsz)) {
3142 		DWARN(vswp, "%s: prop(%s) not found",
3143 				__func__, remaddr_propname);
3144 		return (1);
3145 	}
3146 
3147 	if (addrsz < ETHERADDRL) {
3148 		DWARN(vswp, "%s: invalid address size", __func__);
3149 		return (1);
3150 	}
3151 
3152 	macaddr = *((uint64_t *)addrp);
3153 	D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr);
3154 
3155 	for (i = ETHERADDRL - 1; i >= 0; i--) {
3156 		ea.ether_addr_octet[i] = macaddr & 0xFF;
3157 		macaddr >>= 8;
3158 	}
3159 
3160 	if (vsw_port_attach(vswp, (int)inst, &ldc_id, 1, &ea) != 0) {
3161 		DERR(vswp, "%s: failed to attach port", __func__);
3162 		return (1);
3163 	}
3164 
3165 	port = vsw_lookup_port(vswp, (int)inst);
3166 
3167 	/* just successfuly created the port, so it should exist */
3168 	ASSERT(port != NULL);
3169 
3170 	return (0);
3171 }
3172 
3173 /*
3174  * Attach the specified port.
3175  *
3176  * Returns 0 on success, 1 on failure.
3177  */
3178 static int
3179 vsw_port_attach(vsw_t *vswp, int p_instance, uint64_t *ldcids, int nids,
3180 struct ether_addr *macaddr)
3181 {
3182 	vsw_port_list_t		*plist = &vswp->plist;
3183 	vsw_port_t		*port, **prev_port;
3184 	int			i;
3185 
3186 	D1(vswp, "%s: enter : port %d", __func__, p_instance);
3187 
3188 	/* port already exists? */
3189 	READ_ENTER(&plist->lockrw);
3190 	for (port = plist->head; port != NULL; port = port->p_next) {
3191 		if (port->p_instance == p_instance) {
3192 			DWARN(vswp, "%s: port instance %d already attached",
3193 				__func__, p_instance);
3194 			RW_EXIT(&plist->lockrw);
3195 			return (1);
3196 		}
3197 	}
3198 	RW_EXIT(&plist->lockrw);
3199 
3200 	port = kmem_zalloc(sizeof (vsw_port_t), KM_SLEEP);
3201 	port->p_vswp = vswp;
3202 	port->p_instance = p_instance;
3203 	port->p_ldclist.num_ldcs = 0;
3204 	port->p_ldclist.head = NULL;
3205 	port->addr_set = VSW_ADDR_UNSET;
3206 
3207 	rw_init(&port->p_ldclist.lockrw, NULL, RW_DRIVER, NULL);
3208 
3209 	mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL);
3210 	mutex_init(&port->mca_lock, NULL, MUTEX_DRIVER, NULL);
3211 
3212 	mutex_init(&port->ref_lock, NULL, MUTEX_DRIVER, NULL);
3213 	cv_init(&port->ref_cv, NULL, CV_DRIVER, NULL);
3214 
3215 	mutex_init(&port->state_lock, NULL, MUTEX_DRIVER, NULL);
3216 	cv_init(&port->state_cv, NULL, CV_DRIVER, NULL);
3217 	port->state = VSW_PORT_INIT;
3218 
3219 	if (nids > VSW_PORT_MAX_LDCS) {
3220 		D2(vswp, "%s: using first of %d ldc ids",
3221 			__func__, nids);
3222 		nids = VSW_PORT_MAX_LDCS;
3223 	}
3224 
3225 	D2(vswp, "%s: %d nids", __func__, nids);
3226 	for (i = 0; i < nids; i++) {
3227 		D2(vswp, "%s: ldcid (%llx)", __func__, (uint64_t)ldcids[i]);
3228 		if (vsw_ldc_attach(port, (uint64_t)ldcids[i]) != 0) {
3229 			DERR(vswp, "%s: ldc_attach failed", __func__);
3230 
3231 			rw_destroy(&port->p_ldclist.lockrw);
3232 
3233 			cv_destroy(&port->ref_cv);
3234 			mutex_destroy(&port->ref_lock);
3235 
3236 			cv_destroy(&port->state_cv);
3237 			mutex_destroy(&port->state_lock);
3238 
3239 			mutex_destroy(&port->tx_lock);
3240 			mutex_destroy(&port->mca_lock);
3241 			kmem_free(port, sizeof (vsw_port_t));
3242 			return (1);
3243 		}
3244 	}
3245 
3246 	ether_copy(macaddr, &port->p_macaddr);
3247 
3248 	WRITE_ENTER(&plist->lockrw);
3249 
3250 	/* create the fdb entry for this port/mac address */
3251 	(void) vsw_add_fdb(vswp, port);
3252 
3253 	mutex_enter(&vswp->hw_lock);
3254 	(void) vsw_set_hw(vswp, port, VSW_VNETPORT);
3255 	mutex_exit(&vswp->hw_lock);
3256 
3257 	/* link it into the list of ports for this vsw instance */
3258 	prev_port = (vsw_port_t **)(&plist->head);
3259 	port->p_next = *prev_port;
3260 	*prev_port = port;
3261 	plist->num_ports++;
3262 	RW_EXIT(&plist->lockrw);
3263 
3264 	/*
3265 	 * Initialise the port and any ldc's under it.
3266 	 */
3267 	(void) vsw_init_ldcs(port);
3268 
3269 	D1(vswp, "%s: exit", __func__);
3270 	return (0);
3271 }
3272 
3273 /*
3274  * Detach the specified port.
3275  *
3276  * Returns 0 on success, 1 on failure.
3277  */
3278 static int
3279 vsw_port_detach(vsw_t *vswp, int p_instance)
3280 {
3281 	vsw_port_t	*port = NULL;
3282 	vsw_port_list_t	*plist = &vswp->plist;
3283 
3284 	D1(vswp, "%s: enter: port id %d", __func__, p_instance);
3285 
3286 	WRITE_ENTER(&plist->lockrw);
3287 
3288 	if ((port = vsw_lookup_port(vswp, p_instance)) == NULL) {
3289 		RW_EXIT(&plist->lockrw);
3290 		return (1);
3291 	}
3292 
3293 	if (vsw_plist_del_node(vswp, port)) {
3294 		RW_EXIT(&plist->lockrw);
3295 		return (1);
3296 	}
3297 
3298 	/* Remove the fdb entry for this port/mac address */
3299 	(void) vsw_del_fdb(vswp, port);
3300 
3301 	/* Remove any multicast addresses.. */
3302 	vsw_del_mcst_port(port);
3303 
3304 	/*
3305 	 * No longer need to hold writer lock on port list now
3306 	 * that we have unlinked the target port from the list.
3307 	 */
3308 	RW_EXIT(&plist->lockrw);
3309 
3310 	/* Remove address if was programmed into HW. */
3311 	mutex_enter(&vswp->hw_lock);
3312 	(void) vsw_unset_hw(vswp, port, VSW_VNETPORT);
3313 	if (vswp->recfg_reqd)
3314 		vsw_reconfig_hw(vswp);
3315 	mutex_exit(&vswp->hw_lock);
3316 
3317 	if (vsw_port_delete(port)) {
3318 		return (1);
3319 	}
3320 
3321 	D1(vswp, "%s: exit: p_instance(%d)", __func__, p_instance);
3322 	return (0);
3323 }
3324 
3325 /*
3326  * Detach all active ports.
3327  *
3328  * Returns 0 on success, 1 on failure.
3329  */
3330 static int
3331 vsw_detach_ports(vsw_t *vswp)
3332 {
3333 	vsw_port_list_t 	*plist = &vswp->plist;
3334 	vsw_port_t		*port = NULL;
3335 
3336 	D1(vswp, "%s: enter", __func__);
3337 
3338 	WRITE_ENTER(&plist->lockrw);
3339 
3340 	while ((port = plist->head) != NULL) {
3341 		if (vsw_plist_del_node(vswp, port)) {
3342 			DERR(vswp, "%s: Error deleting port %d"
3343 				" from port list", __func__,
3344 				port->p_instance);
3345 			RW_EXIT(&plist->lockrw);
3346 			return (1);
3347 		}
3348 
3349 		/* Remove address if was programmed into HW. */
3350 		mutex_enter(&vswp->hw_lock);
3351 		(void) vsw_unset_hw(vswp, port, VSW_VNETPORT);
3352 		mutex_exit(&vswp->hw_lock);
3353 
3354 		/* Remove the fdb entry for this port/mac address */
3355 		(void) vsw_del_fdb(vswp, port);
3356 
3357 		/* Remove any multicast addresses.. */
3358 		vsw_del_mcst_port(port);
3359 
3360 		/*
3361 		 * No longer need to hold the lock on the port list
3362 		 * now that we have unlinked the target port from the
3363 		 * list.
3364 		 */
3365 		RW_EXIT(&plist->lockrw);
3366 		if (vsw_port_delete(port)) {
3367 			DERR(vswp, "%s: Error deleting port %d",
3368 				__func__, port->p_instance);
3369 			return (1);
3370 		}
3371 		WRITE_ENTER(&plist->lockrw);
3372 	}
3373 	RW_EXIT(&plist->lockrw);
3374 
3375 	D1(vswp, "%s: exit", __func__);
3376 
3377 	return (0);
3378 }
3379 
3380 /*
3381  * Delete the specified port.
3382  *
3383  * Returns 0 on success, 1 on failure.
3384  */
3385 static int
3386 vsw_port_delete(vsw_port_t *port)
3387 {
3388 	vsw_ldc_list_t 		*ldcl;
3389 	vsw_t			*vswp = port->p_vswp;
3390 
3391 	D1(vswp, "%s: enter : port id %d", __func__, port->p_instance);
3392 
3393 	(void) vsw_uninit_ldcs(port);
3394 
3395 	/*
3396 	 * Wait for any pending ctrl msg tasks which reference this
3397 	 * port to finish.
3398 	 */
3399 	if (vsw_drain_port_taskq(port))
3400 		return (1);
3401 
3402 	/*
3403 	 * Wait for port reference count to hit zero.
3404 	 */
3405 	mutex_enter(&port->ref_lock);
3406 	while (port->ref_cnt != 0)
3407 		cv_wait(&port->ref_cv, &port->ref_lock);
3408 	mutex_exit(&port->ref_lock);
3409 
3410 	/*
3411 	 * Wait for any active callbacks to finish
3412 	 */
3413 	if (vsw_drain_ldcs(port))
3414 		return (1);
3415 
3416 	ldcl = &port->p_ldclist;
3417 	WRITE_ENTER(&ldcl->lockrw);
3418 	while (ldcl->num_ldcs > 0) {
3419 		if (vsw_ldc_detach(port, ldcl->head->ldc_id) != 0) {;
3420 			cmn_err(CE_WARN, "!vsw%d: unable to detach ldc %ld",
3421 					vswp->instance, ldcl->head->ldc_id);
3422 			RW_EXIT(&ldcl->lockrw);
3423 			return (1);
3424 		}
3425 	}
3426 	RW_EXIT(&ldcl->lockrw);
3427 
3428 	rw_destroy(&port->p_ldclist.lockrw);
3429 
3430 	mutex_destroy(&port->mca_lock);
3431 	mutex_destroy(&port->tx_lock);
3432 	cv_destroy(&port->ref_cv);
3433 	mutex_destroy(&port->ref_lock);
3434 
3435 	cv_destroy(&port->state_cv);
3436 	mutex_destroy(&port->state_lock);
3437 
3438 	kmem_free(port, sizeof (vsw_port_t));
3439 
3440 	D1(vswp, "%s: exit", __func__);
3441 
3442 	return (0);
3443 }
3444 
3445 /*
3446  * Attach a logical domain channel (ldc) under a specified port.
3447  *
3448  * Returns 0 on success, 1 on failure.
3449  */
3450 static int
3451 vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id)
3452 {
3453 	vsw_t 		*vswp = port->p_vswp;
3454 	vsw_ldc_list_t *ldcl = &port->p_ldclist;
3455 	vsw_ldc_t 	*ldcp = NULL;
3456 	ldc_attr_t 	attr;
3457 	ldc_status_t	istatus;
3458 	int 		status = DDI_FAILURE;
3459 	int		rv;
3460 	enum		{ PROG_init = 0x0, PROG_mblks = 0x1,
3461 				PROG_callback = 0x2}
3462 			progress;
3463 
3464 	progress = PROG_init;
3465 
3466 	D1(vswp, "%s: enter", __func__);
3467 
3468 	ldcp = kmem_zalloc(sizeof (vsw_ldc_t), KM_NOSLEEP);
3469 	if (ldcp == NULL) {
3470 		DERR(vswp, "%s: kmem_zalloc failed", __func__);
3471 		return (1);
3472 	}
3473 	ldcp->ldc_id = ldc_id;
3474 
3475 	/* allocate pool of receive mblks */
3476 	rv = vio_create_mblks(vsw_num_mblks, vsw_mblk_size, &(ldcp->rxh));
3477 	if (rv) {
3478 		DWARN(vswp, "%s: unable to create free mblk pool for"
3479 			" channel %ld (rv %d)", __func__, ldc_id, rv);
3480 		kmem_free(ldcp, sizeof (vsw_ldc_t));
3481 		return (1);
3482 	}
3483 
3484 	progress |= PROG_mblks;
3485 
3486 	mutex_init(&ldcp->ldc_txlock, NULL, MUTEX_DRIVER, NULL);
3487 	mutex_init(&ldcp->ldc_cblock, NULL, MUTEX_DRIVER, NULL);
3488 	mutex_init(&ldcp->drain_cv_lock, NULL, MUTEX_DRIVER, NULL);
3489 	cv_init(&ldcp->drain_cv, NULL, CV_DRIVER, NULL);
3490 	rw_init(&ldcp->lane_in.dlistrw, NULL, RW_DRIVER, NULL);
3491 	rw_init(&ldcp->lane_out.dlistrw, NULL, RW_DRIVER, NULL);
3492 
3493 	/* required for handshake with peer */
3494 	ldcp->local_session = (uint64_t)ddi_get_lbolt();
3495 	ldcp->peer_session = 0;
3496 	ldcp->session_status = 0;
3497 
3498 	mutex_init(&ldcp->hss_lock, NULL, MUTEX_DRIVER, NULL);
3499 	ldcp->hss_id = 1;	/* Initial handshake session id */
3500 
3501 	/* only set for outbound lane, inbound set by peer */
3502 	mutex_init(&ldcp->lane_in.seq_lock, NULL, MUTEX_DRIVER, NULL);
3503 	mutex_init(&ldcp->lane_out.seq_lock, NULL, MUTEX_DRIVER, NULL);
3504 	vsw_set_lane_attr(vswp, &ldcp->lane_out);
3505 
3506 	attr.devclass = LDC_DEV_NT_SVC;
3507 	attr.instance = ddi_get_instance(vswp->dip);
3508 	attr.mode = LDC_MODE_UNRELIABLE;
3509 	attr.mtu = VSW_LDC_MTU;
3510 	status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
3511 	if (status != 0) {
3512 		DERR(vswp, "%s(%lld): ldc_init failed, rv (%d)",
3513 		    __func__, ldc_id, status);
3514 		goto ldc_attach_fail;
3515 	}
3516 
3517 	status = ldc_reg_callback(ldcp->ldc_handle, vsw_ldc_cb, (caddr_t)ldcp);
3518 	if (status != 0) {
3519 		DERR(vswp, "%s(%lld): ldc_reg_callback failed, rv (%d)",
3520 		    __func__, ldc_id, status);
3521 		(void) ldc_fini(ldcp->ldc_handle);
3522 		goto ldc_attach_fail;
3523 	}
3524 
3525 	progress |= PROG_callback;
3526 
3527 	mutex_init(&ldcp->status_lock, NULL, MUTEX_DRIVER, NULL);
3528 
3529 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3530 		DERR(vswp, "%s: ldc_status failed", __func__);
3531 		mutex_destroy(&ldcp->status_lock);
3532 		goto ldc_attach_fail;
3533 	}
3534 
3535 	ldcp->ldc_status = istatus;
3536 	ldcp->ldc_port = port;
3537 	ldcp->ldc_vswp = vswp;
3538 
3539 	/* link it into the list of channels for this port */
3540 	WRITE_ENTER(&ldcl->lockrw);
3541 	ldcp->ldc_next = ldcl->head;
3542 	ldcl->head = ldcp;
3543 	ldcl->num_ldcs++;
3544 	RW_EXIT(&ldcl->lockrw);
3545 
3546 	D1(vswp, "%s: exit", __func__);
3547 	return (0);
3548 
3549 ldc_attach_fail:
3550 	mutex_destroy(&ldcp->ldc_txlock);
3551 	mutex_destroy(&ldcp->ldc_cblock);
3552 
3553 	cv_destroy(&ldcp->drain_cv);
3554 
3555 	rw_destroy(&ldcp->lane_in.dlistrw);
3556 	rw_destroy(&ldcp->lane_out.dlistrw);
3557 
3558 	if (progress & PROG_callback) {
3559 		(void) ldc_unreg_callback(ldcp->ldc_handle);
3560 	}
3561 
3562 	if ((progress & PROG_mblks) && (ldcp->rxh != NULL)) {
3563 		if (vio_destroy_mblks(ldcp->rxh) != 0) {
3564 			/*
3565 			 * Something odd has happened, as the destroy
3566 			 * will only fail if some mblks have been allocated
3567 			 * from the pool already (which shouldn't happen)
3568 			 * and have not been returned.
3569 			 *
3570 			 * Add the pool pointer to a list maintained in
3571 			 * the device instance. Another attempt will be made
3572 			 * to free the pool when the device itself detaches.
3573 			 */
3574 			cmn_err(CE_WARN, "!vsw%d: Creation of ldc channel %ld "
3575 				"failed and cannot destroy associated mblk "
3576 				"pool", vswp->instance, ldc_id);
3577 			ldcp->rxh->nextp =  vswp->rxh;
3578 			vswp->rxh = ldcp->rxh;
3579 		}
3580 	}
3581 	mutex_destroy(&ldcp->drain_cv_lock);
3582 	mutex_destroy(&ldcp->hss_lock);
3583 
3584 	mutex_destroy(&ldcp->lane_in.seq_lock);
3585 	mutex_destroy(&ldcp->lane_out.seq_lock);
3586 	kmem_free(ldcp, sizeof (vsw_ldc_t));
3587 
3588 	return (1);
3589 }
3590 
3591 /*
3592  * Detach a logical domain channel (ldc) belonging to a
3593  * particular port.
3594  *
3595  * Returns 0 on success, 1 on failure.
3596  */
3597 static int
3598 vsw_ldc_detach(vsw_port_t *port, uint64_t ldc_id)
3599 {
3600 	vsw_t 		*vswp = port->p_vswp;
3601 	vsw_ldc_t 	*ldcp, *prev_ldcp;
3602 	vsw_ldc_list_t	*ldcl = &port->p_ldclist;
3603 	int 		rv;
3604 
3605 	prev_ldcp = ldcl->head;
3606 	for (; (ldcp = prev_ldcp) != NULL; prev_ldcp = ldcp->ldc_next) {
3607 		if (ldcp->ldc_id == ldc_id) {
3608 			break;
3609 		}
3610 	}
3611 
3612 	/* specified ldc id not found */
3613 	if (ldcp == NULL) {
3614 		DERR(vswp, "%s: ldcp = NULL", __func__);
3615 		return (1);
3616 	}
3617 
3618 	D2(vswp, "%s: detaching channel %lld", __func__, ldcp->ldc_id);
3619 
3620 	/*
3621 	 * Before we can close the channel we must release any mapped
3622 	 * resources (e.g. drings).
3623 	 */
3624 	vsw_free_lane_resources(ldcp, INBOUND);
3625 	vsw_free_lane_resources(ldcp, OUTBOUND);
3626 
3627 	/*
3628 	 * If the close fails we are in serious trouble, as won't
3629 	 * be able to delete the parent port.
3630 	 */
3631 	if ((rv = ldc_close(ldcp->ldc_handle)) != 0) {
3632 		DERR(vswp, "%s: error %d closing channel %lld",
3633 			__func__, rv, ldcp->ldc_id);
3634 		return (1);
3635 	}
3636 
3637 	(void) ldc_fini(ldcp->ldc_handle);
3638 
3639 	ldcp->ldc_status = LDC_INIT;
3640 	ldcp->ldc_handle = NULL;
3641 	ldcp->ldc_vswp = NULL;
3642 
3643 	if (ldcp->rxh != NULL) {
3644 		if (vio_destroy_mblks(ldcp->rxh)) {
3645 			/*
3646 			 * Mostly likely some mblks are still in use and
3647 			 * have not been returned to the pool. Add the pool
3648 			 * to the list maintained in the device instance.
3649 			 * Another attempt will be made to destroy the pool
3650 			 * when the device detaches.
3651 			 */
3652 			ldcp->rxh->nextp =  vswp->rxh;
3653 			vswp->rxh = ldcp->rxh;
3654 		}
3655 	}
3656 
3657 	/* unlink it from the list */
3658 	prev_ldcp = ldcp->ldc_next;
3659 	ldcl->num_ldcs--;
3660 
3661 	mutex_destroy(&ldcp->ldc_txlock);
3662 	mutex_destroy(&ldcp->ldc_cblock);
3663 	cv_destroy(&ldcp->drain_cv);
3664 	mutex_destroy(&ldcp->drain_cv_lock);
3665 	mutex_destroy(&ldcp->hss_lock);
3666 	mutex_destroy(&ldcp->lane_in.seq_lock);
3667 	mutex_destroy(&ldcp->lane_out.seq_lock);
3668 	mutex_destroy(&ldcp->status_lock);
3669 	rw_destroy(&ldcp->lane_in.dlistrw);
3670 	rw_destroy(&ldcp->lane_out.dlistrw);
3671 
3672 	kmem_free(ldcp, sizeof (vsw_ldc_t));
3673 
3674 	return (0);
3675 }
3676 
3677 /*
3678  * Open and attempt to bring up the channel. Note that channel
3679  * can only be brought up if peer has also opened channel.
3680  *
3681  * Returns 0 if can open and bring up channel, otherwise
3682  * returns 1.
3683  */
3684 static int
3685 vsw_ldc_init(vsw_ldc_t *ldcp)
3686 {
3687 	vsw_t 		*vswp = ldcp->ldc_vswp;
3688 	ldc_status_t	istatus = 0;
3689 	int		rv;
3690 
3691 	D1(vswp, "%s: enter", __func__);
3692 
3693 	LDC_ENTER_LOCK(ldcp);
3694 
3695 	/* don't start at 0 in case clients don't like that */
3696 	ldcp->next_ident = 1;
3697 
3698 	rv = ldc_open(ldcp->ldc_handle);
3699 	if (rv != 0) {
3700 		DERR(vswp, "%s: ldc_open failed: id(%lld) rv(%d)",
3701 		    __func__, ldcp->ldc_id, rv);
3702 		LDC_EXIT_LOCK(ldcp);
3703 		return (1);
3704 	}
3705 
3706 	if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
3707 		DERR(vswp, "%s: unable to get status", __func__);
3708 		LDC_EXIT_LOCK(ldcp);
3709 		return (1);
3710 
3711 	} else if (istatus != LDC_OPEN && istatus != LDC_READY) {
3712 		DERR(vswp, "%s: id (%lld) status(%d) is not OPEN/READY",
3713 		    __func__, ldcp->ldc_id, istatus);
3714 		LDC_EXIT_LOCK(ldcp);
3715 		return (1);
3716 	}
3717 
3718 	mutex_enter(&ldcp->status_lock);
3719 	ldcp->ldc_status = istatus;
3720 	mutex_exit(&ldcp->status_lock);
3721 
3722 	rv = ldc_up(ldcp->ldc_handle);
3723 	if (rv != 0) {
3724 		/*
3725 		 * Not a fatal error for ldc_up() to fail, as peer
3726 		 * end point may simply not be ready yet.
3727 		 */
3728 		D2(vswp, "%s: ldc_up err id(%lld) rv(%d)", __func__,
3729 			ldcp->ldc_id, rv);
3730 		LDC_EXIT_LOCK(ldcp);
3731 		return (1);
3732 	}
3733 
3734 	/*
3735 	 * ldc_up() call is non-blocking so need to explicitly
3736 	 * check channel status to see if in fact the channel
3737 	 * is UP.
3738 	 */
3739 	mutex_enter(&ldcp->status_lock);
3740 	if (ldc_status(ldcp->ldc_handle, &ldcp->ldc_status) != 0) {
3741 		DERR(vswp, "%s: unable to get status", __func__);
3742 		mutex_exit(&ldcp->status_lock);
3743 		LDC_EXIT_LOCK(ldcp);
3744 		return (1);
3745 
3746 	}
3747 
3748 	if (ldcp->ldc_status == LDC_UP) {
3749 		D2(vswp, "%s: channel %ld now UP (%ld)", __func__,
3750 			ldcp->ldc_id, istatus);
3751 		mutex_exit(&ldcp->status_lock);
3752 		LDC_EXIT_LOCK(ldcp);
3753 
3754 		vsw_process_conn_evt(ldcp, VSW_CONN_UP);
3755 		return (0);
3756 	}
3757 
3758 	mutex_exit(&ldcp->status_lock);
3759 	LDC_EXIT_LOCK(ldcp);
3760 
3761 	D1(vswp, "%s: exit", __func__);
3762 	return (0);
3763 }
3764 
3765 /* disable callbacks on the channel */
3766 static int
3767 vsw_ldc_uninit(vsw_ldc_t *ldcp)
3768 {
3769 	vsw_t	*vswp = ldcp->ldc_vswp;
3770 	int	rv;
3771 
3772 	D1(vswp, "vsw_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id);
3773 
3774 	LDC_ENTER_LOCK(ldcp);
3775 
3776 	rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
3777 	if (rv != 0) {
3778 		DERR(vswp, "vsw_ldc_uninit(%lld): error disabling "
3779 			"interrupts (rv = %d)\n", ldcp->ldc_id, rv);
3780 		LDC_EXIT_LOCK(ldcp);
3781 		return (1);
3782 	}
3783 
3784 	mutex_enter(&ldcp->status_lock);
3785 	ldcp->ldc_status = LDC_INIT;
3786 	mutex_exit(&ldcp->status_lock);
3787 
3788 	LDC_EXIT_LOCK(ldcp);
3789 
3790 	D1(vswp, "vsw_ldc_uninit: exit: id(%lx)", ldcp->ldc_id);
3791 
3792 	return (0);
3793 }
3794 
3795 static int
3796 vsw_init_ldcs(vsw_port_t *port)
3797 {
3798 	vsw_ldc_list_t	*ldcl = &port->p_ldclist;
3799 	vsw_ldc_t	*ldcp;
3800 
3801 	READ_ENTER(&ldcl->lockrw);
3802 	ldcp =  ldcl->head;
3803 	for (; ldcp  != NULL; ldcp = ldcp->ldc_next) {
3804 		(void) vsw_ldc_init(ldcp);
3805 	}
3806 	RW_EXIT(&ldcl->lockrw);
3807 
3808 	return (0);
3809 }
3810 
3811 static int
3812 vsw_uninit_ldcs(vsw_port_t *port)
3813 {
3814 	vsw_ldc_list_t	*ldcl = &port->p_ldclist;
3815 	vsw_ldc_t	*ldcp;
3816 
3817 	D1(NULL, "vsw_uninit_ldcs: enter\n");
3818 
3819 	READ_ENTER(&ldcl->lockrw);
3820 	ldcp =  ldcl->head;
3821 	for (; ldcp  != NULL; ldcp = ldcp->ldc_next) {
3822 		(void) vsw_ldc_uninit(ldcp);
3823 	}
3824 	RW_EXIT(&ldcl->lockrw);
3825 
3826 	D1(NULL, "vsw_uninit_ldcs: exit\n");
3827 
3828 	return (0);
3829 }
3830 
3831 /*
3832  * Wait until the callback(s) associated with the ldcs under the specified
3833  * port have completed.
3834  *
3835  * Prior to this function being invoked each channel under this port
3836  * should have been quiesced via ldc_set_cb_mode(DISABLE).
3837  *
3838  * A short explaination of what we are doing below..
3839  *
3840  * The simplest approach would be to have a reference counter in
3841  * the ldc structure which is increment/decremented by the callbacks as
3842  * they use the channel. The drain function could then simply disable any
3843  * further callbacks and do a cv_wait for the ref to hit zero. Unfortunately
3844  * there is a tiny window here - before the callback is able to get the lock
3845  * on the channel it is interrupted and this function gets to execute. It
3846  * sees that the ref count is zero and believes its free to delete the
3847  * associated data structures.
3848  *
3849  * We get around this by taking advantage of the fact that before the ldc
3850  * framework invokes a callback it sets a flag to indicate that there is a
3851  * callback active (or about to become active). If when we attempt to
3852  * unregister a callback when this active flag is set then the unregister
3853  * will fail with EWOULDBLOCK.
3854  *
3855  * If the unregister fails we do a cv_timedwait. We will either be signaled
3856  * by the callback as it is exiting (note we have to wait a short period to
3857  * allow the callback to return fully to the ldc framework and it to clear
3858  * the active flag), or by the timer expiring. In either case we again attempt
3859  * the unregister. We repeat this until we can succesfully unregister the
3860  * callback.
3861  *
3862  * The reason we use a cv_timedwait rather than a simple cv_wait is to catch
3863  * the case where the callback has finished but the ldc framework has not yet
3864  * cleared the active flag. In this case we would never get a cv_signal.
3865  */
3866 static int
3867 vsw_drain_ldcs(vsw_port_t *port)
3868 {
3869 	vsw_ldc_list_t	*ldcl = &port->p_ldclist;
3870 	vsw_ldc_t	*ldcp;
3871 	vsw_t		*vswp = port->p_vswp;
3872 
3873 	D1(vswp, "%s: enter", __func__);
3874 
3875 	READ_ENTER(&ldcl->lockrw);
3876 
3877 	ldcp = ldcl->head;
3878 
3879 	for (; ldcp  != NULL; ldcp = ldcp->ldc_next) {
3880 		/*
3881 		 * If we can unregister the channel callback then we
3882 		 * know that there is no callback either running or
3883 		 * scheduled to run for this channel so move on to next
3884 		 * channel in the list.
3885 		 */
3886 		mutex_enter(&ldcp->drain_cv_lock);
3887 
3888 		/* prompt active callbacks to quit */
3889 		ldcp->drain_state = VSW_LDC_DRAINING;
3890 
3891 		if ((ldc_unreg_callback(ldcp->ldc_handle)) == 0) {
3892 			D2(vswp, "%s: unreg callback for chan %ld", __func__,
3893 				ldcp->ldc_id);
3894 			mutex_exit(&ldcp->drain_cv_lock);
3895 			continue;
3896 		} else {
3897 			/*
3898 			 * If we end up here we know that either 1) a callback
3899 			 * is currently executing, 2) is about to start (i.e.
3900 			 * the ldc framework has set the active flag but
3901 			 * has not actually invoked the callback yet, or 3)
3902 			 * has finished and has returned to the ldc framework
3903 			 * but the ldc framework has not yet cleared the
3904 			 * active bit.
3905 			 *
3906 			 * Wait for it to finish.
3907 			 */
3908 			while (ldc_unreg_callback(ldcp->ldc_handle)
3909 								== EWOULDBLOCK)
3910 				(void) cv_timedwait(&ldcp->drain_cv,
3911 					&ldcp->drain_cv_lock, lbolt + hz);
3912 
3913 			mutex_exit(&ldcp->drain_cv_lock);
3914 			D2(vswp, "%s: unreg callback for chan %ld after "
3915 				"timeout", __func__, ldcp->ldc_id);
3916 		}
3917 	}
3918 	RW_EXIT(&ldcl->lockrw);
3919 
3920 	D1(vswp, "%s: exit", __func__);
3921 	return (0);
3922 }
3923 
3924 /*
3925  * Wait until all tasks which reference this port have completed.
3926  *
3927  * Prior to this function being invoked each channel under this port
3928  * should have been quiesced via ldc_set_cb_mode(DISABLE).
3929  */
3930 static int
3931 vsw_drain_port_taskq(vsw_port_t *port)
3932 {
3933 	vsw_t		*vswp = port->p_vswp;
3934 
3935 	D1(vswp, "%s: enter", __func__);
3936 
3937 	/*
3938 	 * Mark the port as in the process of being detached, and
3939 	 * dispatch a marker task to the queue so we know when all
3940 	 * relevant tasks have completed.
3941 	 */
3942 	mutex_enter(&port->state_lock);
3943 	port->state = VSW_PORT_DETACHING;
3944 
3945 	if ((vswp->taskq_p == NULL) ||
3946 		(ddi_taskq_dispatch(vswp->taskq_p, vsw_marker_task,
3947 			port, DDI_NOSLEEP) != DDI_SUCCESS)) {
3948 		DERR(vswp, "%s: unable to dispatch marker task",
3949 			__func__);
3950 		mutex_exit(&port->state_lock);
3951 		return (1);
3952 	}
3953 
3954 	/*
3955 	 * Wait for the marker task to finish.
3956 	 */
3957 	while (port->state != VSW_PORT_DETACHABLE)
3958 		cv_wait(&port->state_cv, &port->state_lock);
3959 
3960 	mutex_exit(&port->state_lock);
3961 
3962 	D1(vswp, "%s: exit", __func__);
3963 
3964 	return (0);
3965 }
3966 
3967 static void
3968 vsw_marker_task(void *arg)
3969 {
3970 	vsw_port_t	*port = arg;
3971 	vsw_t		*vswp = port->p_vswp;
3972 
3973 	D1(vswp, "%s: enter", __func__);
3974 
3975 	mutex_enter(&port->state_lock);
3976 
3977 	/*
3978 	 * No further tasks should be dispatched which reference
3979 	 * this port so ok to mark it as safe to detach.
3980 	 */
3981 	port->state = VSW_PORT_DETACHABLE;
3982 
3983 	cv_signal(&port->state_cv);
3984 
3985 	mutex_exit(&port->state_lock);
3986 
3987 	D1(vswp, "%s: exit", __func__);
3988 }
3989 
3990 static vsw_port_t *
3991 vsw_lookup_port(vsw_t *vswp, int p_instance)
3992 {
3993 	vsw_port_list_t *plist = &vswp->plist;
3994 	vsw_port_t	*port;
3995 
3996 	for (port = plist->head; port != NULL; port = port->p_next) {
3997 		if (port->p_instance == p_instance) {
3998 			D2(vswp, "vsw_lookup_port: found p_instance\n");
3999 			return (port);
4000 		}
4001 	}
4002 
4003 	return (NULL);
4004 }
4005 
4006 /*
4007  * Search for and remove the specified port from the port
4008  * list. Returns 0 if able to locate and remove port, otherwise
4009  * returns 1.
4010  */
4011 static int
4012 vsw_plist_del_node(vsw_t *vswp, vsw_port_t *port)
4013 {
4014 	vsw_port_list_t *plist = &vswp->plist;
4015 	vsw_port_t	*curr_p, *prev_p;
4016 
4017 	if (plist->head == NULL)
4018 		return (1);
4019 
4020 	curr_p = prev_p = plist->head;
4021 
4022 	while (curr_p != NULL) {
4023 		if (curr_p == port) {
4024 			if (prev_p == curr_p) {
4025 				plist->head = curr_p->p_next;
4026 			} else {
4027 				prev_p->p_next = curr_p->p_next;
4028 			}
4029 			plist->num_ports--;
4030 			break;
4031 		} else {
4032 			prev_p = curr_p;
4033 			curr_p = curr_p->p_next;
4034 		}
4035 	}
4036 	return (0);
4037 }
4038 
4039 /*
4040  * Interrupt handler for ldc messages.
4041  */
4042 static uint_t
4043 vsw_ldc_cb(uint64_t event, caddr_t arg)
4044 {
4045 	vsw_ldc_t	*ldcp = (vsw_ldc_t  *)arg;
4046 	vsw_t 		*vswp = ldcp->ldc_vswp;
4047 
4048 	D1(vswp, "%s: enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
4049 
4050 	mutex_enter(&ldcp->ldc_cblock);
4051 
4052 	mutex_enter(&ldcp->status_lock);
4053 	if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
4054 		mutex_exit(&ldcp->status_lock);
4055 		mutex_exit(&ldcp->ldc_cblock);
4056 		return (LDC_SUCCESS);
4057 	}
4058 	mutex_exit(&ldcp->status_lock);
4059 
4060 	if (event & LDC_EVT_UP) {
4061 		/*
4062 		 * Channel has come up.
4063 		 */
4064 		D2(vswp, "%s: id(%ld) event(%llx) UP: status(%ld)",
4065 			__func__, ldcp->ldc_id, event, ldcp->ldc_status);
4066 
4067 		vsw_process_conn_evt(ldcp, VSW_CONN_UP);
4068 
4069 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
4070 	}
4071 
4072 	if (event & LDC_EVT_READ) {
4073 		/*
4074 		 * Data available for reading.
4075 		 */
4076 		D2(vswp, "%s: id(ld) event(%llx) data READ",
4077 				__func__, ldcp->ldc_id, event);
4078 
4079 		vsw_process_pkt(ldcp);
4080 
4081 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
4082 
4083 		goto vsw_cb_exit;
4084 	}
4085 
4086 	if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) {
4087 		D2(vswp, "%s: id(%ld) event (%lx) DOWN/RESET: status(%ld)",
4088 			__func__, ldcp->ldc_id, event, ldcp->ldc_status);
4089 
4090 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
4091 	}
4092 
4093 	/*
4094 	 * Catch either LDC_EVT_WRITE which we don't support or any
4095 	 * unknown event.
4096 	 */
4097 	if (event & ~(LDC_EVT_UP | LDC_EVT_RESET
4098 					| LDC_EVT_DOWN | LDC_EVT_READ)) {
4099 
4100 		DERR(vswp, "%s: id(%ld) Unexpected event=(%llx) status(%ld)",
4101 			__func__, ldcp->ldc_id, event, ldcp->ldc_status);
4102 	}
4103 
4104 vsw_cb_exit:
4105 	mutex_exit(&ldcp->ldc_cblock);
4106 
4107 	/*
4108 	 * Let the drain function know we are finishing if it
4109 	 * is waiting.
4110 	 */
4111 	mutex_enter(&ldcp->drain_cv_lock);
4112 	if (ldcp->drain_state == VSW_LDC_DRAINING)
4113 		cv_signal(&ldcp->drain_cv);
4114 	mutex_exit(&ldcp->drain_cv_lock);
4115 
4116 	return (LDC_SUCCESS);
4117 }
4118 
4119 /*
4120  * Reinitialise data structures associated with the channel.
4121  */
4122 static void
4123 vsw_ldc_reinit(vsw_ldc_t *ldcp)
4124 {
4125 	vsw_t		*vswp = ldcp->ldc_vswp;
4126 	vsw_port_t	*port;
4127 	vsw_ldc_list_t	*ldcl;
4128 
4129 	D1(vswp, "%s: enter", __func__);
4130 
4131 	port = ldcp->ldc_port;
4132 	ldcl = &port->p_ldclist;
4133 
4134 	READ_ENTER(&ldcl->lockrw);
4135 
4136 	D2(vswp, "%s: in 0x%llx : out 0x%llx", __func__,
4137 		ldcp->lane_in.lstate, ldcp->lane_out.lstate);
4138 
4139 	vsw_free_lane_resources(ldcp, INBOUND);
4140 	vsw_free_lane_resources(ldcp, OUTBOUND);
4141 	RW_EXIT(&ldcl->lockrw);
4142 
4143 	ldcp->lane_in.lstate = 0;
4144 	ldcp->lane_out.lstate = 0;
4145 
4146 	/*
4147 	 * Remove parent port from any multicast groups
4148 	 * it may have registered with. Client must resend
4149 	 * multicast add command after handshake completes.
4150 	 */
4151 	(void) vsw_del_fdb(vswp, port);
4152 
4153 	vsw_del_mcst_port(port);
4154 
4155 	ldcp->peer_session = 0;
4156 	ldcp->session_status = 0;
4157 	ldcp->hcnt = 0;
4158 	ldcp->hphase = VSW_MILESTONE0;
4159 
4160 	D1(vswp, "%s: exit", __func__);
4161 }
4162 
4163 /*
4164  * Process a connection event.
4165  *
4166  * Note - care must be taken to ensure that this function is
4167  * not called with the dlistrw lock held.
4168  */
4169 static void
4170 vsw_process_conn_evt(vsw_ldc_t *ldcp, uint16_t evt)
4171 {
4172 	vsw_t		*vswp = ldcp->ldc_vswp;
4173 	vsw_conn_evt_t	*conn = NULL;
4174 
4175 	D1(vswp, "%s: enter", __func__);
4176 
4177 	/*
4178 	 * Check if either a reset or restart event is pending
4179 	 * or in progress. If so just return.
4180 	 *
4181 	 * A VSW_CONN_RESET event originates either with a LDC_RESET_EVT
4182 	 * being received by the callback handler, or a ECONNRESET error
4183 	 * code being returned from a ldc_read() or ldc_write() call.
4184 	 *
4185 	 * A VSW_CONN_RESTART event occurs when some error checking code
4186 	 * decides that there is a problem with data from the channel,
4187 	 * and that the handshake should be restarted.
4188 	 */
4189 	if (((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) &&
4190 			(ldstub((uint8_t *)&ldcp->reset_active)))
4191 		return;
4192 
4193 	/*
4194 	 * If it is an LDC_UP event we first check the recorded
4195 	 * state of the channel. If this is UP then we know that
4196 	 * the channel moving to the UP state has already been dealt
4197 	 * with and don't need to dispatch a  new task.
4198 	 *
4199 	 * The reason for this check is that when we do a ldc_up(),
4200 	 * depending on the state of the peer, we may or may not get
4201 	 * a LDC_UP event. As we can't depend on getting a LDC_UP evt
4202 	 * every time we do ldc_up() we explicitly check the channel
4203 	 * status to see has it come up (ldc_up() is asynch and will
4204 	 * complete at some undefined time), and take the appropriate
4205 	 * action.
4206 	 *
4207 	 * The flip side of this is that we may get a LDC_UP event
4208 	 * when we have already seen that the channel is up and have
4209 	 * dealt with that.
4210 	 */
4211 	mutex_enter(&ldcp->status_lock);
4212 	if (evt == VSW_CONN_UP) {
4213 		if ((ldcp->ldc_status == LDC_UP) ||
4214 					(ldcp->reset_active != 0)) {
4215 			mutex_exit(&ldcp->status_lock);
4216 			return;
4217 		}
4218 	}
4219 	mutex_exit(&ldcp->status_lock);
4220 
4221 	/*
4222 	 * The transaction group id allows us to identify and discard
4223 	 * any tasks which are still pending on the taskq and refer
4224 	 * to the handshake session we are about to restart or reset.
4225 	 * These stale messages no longer have any real meaning.
4226 	 */
4227 	mutex_enter(&ldcp->hss_lock);
4228 	ldcp->hss_id++;
4229 	mutex_exit(&ldcp->hss_lock);
4230 
4231 	ASSERT(vswp->taskq_p != NULL);
4232 
4233 	if ((conn = kmem_zalloc(sizeof (vsw_conn_evt_t), KM_NOSLEEP)) == NULL) {
4234 		cmn_err(CE_WARN, "!vsw%d: unable to allocate memory for"
4235 			" connection event", vswp->instance);
4236 		goto err_exit;
4237 	}
4238 
4239 	conn->evt = evt;
4240 	conn->ldcp = ldcp;
4241 
4242 	if (ddi_taskq_dispatch(vswp->taskq_p, vsw_conn_task, conn,
4243 		DDI_NOSLEEP) != DDI_SUCCESS) {
4244 		cmn_err(CE_WARN, "!vsw%d: Can't dispatch connection task",
4245 			vswp->instance);
4246 
4247 		kmem_free(conn, sizeof (vsw_conn_evt_t));
4248 		goto err_exit;
4249 	}
4250 
4251 	D1(vswp, "%s: exit", __func__);
4252 	return;
4253 
4254 err_exit:
4255 	/*
4256 	 * Have mostly likely failed due to memory shortage. Clear the flag so
4257 	 * that future requests will at least be attempted and will hopefully
4258 	 * succeed.
4259 	 */
4260 	if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
4261 		ldcp->reset_active = 0;
4262 }
4263 
4264 /*
4265  * Deal with events relating to a connection. Invoked from a taskq.
4266  */
4267 static void
4268 vsw_conn_task(void *arg)
4269 {
4270 	vsw_conn_evt_t	*conn = (vsw_conn_evt_t *)arg;
4271 	vsw_ldc_t	*ldcp = NULL;
4272 	vsw_t		*vswp = NULL;
4273 	uint16_t	evt;
4274 	ldc_status_t	curr_status;
4275 
4276 	ldcp = conn->ldcp;
4277 	evt = conn->evt;
4278 	vswp = ldcp->ldc_vswp;
4279 
4280 	D1(vswp, "%s: enter", __func__);
4281 
4282 	/* can safely free now have copied out data */
4283 	kmem_free(conn, sizeof (vsw_conn_evt_t));
4284 
4285 	mutex_enter(&ldcp->status_lock);
4286 	if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
4287 		cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
4288 			"channel %ld", vswp->instance, ldcp->ldc_id);
4289 		mutex_exit(&ldcp->status_lock);
4290 		return;
4291 	}
4292 
4293 	/*
4294 	 * If we wish to restart the handshake on this channel, then if
4295 	 * the channel is UP we bring it DOWN to flush the underlying
4296 	 * ldc queue.
4297 	 */
4298 	if ((evt == VSW_CONN_RESTART) && (curr_status == LDC_UP))
4299 		(void) ldc_down(ldcp->ldc_handle);
4300 
4301 	/*
4302 	 * re-init all the associated data structures.
4303 	 */
4304 	vsw_ldc_reinit(ldcp);
4305 
4306 	/*
4307 	 * Bring the channel back up (note it does no harm to
4308 	 * do this even if the channel is already UP, Just
4309 	 * becomes effectively a no-op).
4310 	 */
4311 	(void) ldc_up(ldcp->ldc_handle);
4312 
4313 	/*
4314 	 * Check if channel is now UP. This will only happen if
4315 	 * peer has also done a ldc_up().
4316 	 */
4317 	if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
4318 		cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
4319 			"channel %ld", vswp->instance, ldcp->ldc_id);
4320 		mutex_exit(&ldcp->status_lock);
4321 		return;
4322 	}
4323 
4324 	ldcp->ldc_status = curr_status;
4325 
4326 	/* channel UP so restart handshake by sending version info */
4327 	if (curr_status == LDC_UP) {
4328 		if (ldcp->hcnt++ > vsw_num_handshakes) {
4329 			cmn_err(CE_WARN, "!vsw%d: exceeded number of permitted"
4330 				" handshake attempts (%d) on channel %ld",
4331 				vswp->instance, ldcp->hcnt, ldcp->ldc_id);
4332 			mutex_exit(&ldcp->status_lock);
4333 			return;
4334 		}
4335 
4336 		if (ddi_taskq_dispatch(vswp->taskq_p, vsw_send_ver, ldcp,
4337 			DDI_NOSLEEP) != DDI_SUCCESS) {
4338 			cmn_err(CE_WARN, "!vsw%d: Can't dispatch version task",
4339 				vswp->instance);
4340 
4341 			/*
4342 			 * Don't count as valid restart attempt if couldn't
4343 			 * send version msg.
4344 			 */
4345 			if (ldcp->hcnt > 0)
4346 				ldcp->hcnt--;
4347 		}
4348 	}
4349 
4350 	/*
4351 	 * Mark that the process is complete by clearing the flag.
4352 	 *
4353 	 * Note is it possible that the taskq dispatch above may have failed,
4354 	 * most likely due to memory shortage. We still clear the flag so
4355 	 * future attempts will at least be attempted and will hopefully
4356 	 * succeed.
4357 	 */
4358 	if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
4359 		ldcp->reset_active = 0;
4360 
4361 	mutex_exit(&ldcp->status_lock);
4362 
4363 	D1(vswp, "%s: exit", __func__);
4364 }
4365 
4366 /*
4367  * returns 0 if legal for event signified by flag to have
4368  * occured at the time it did. Otherwise returns 1.
4369  */
4370 int
4371 vsw_check_flag(vsw_ldc_t *ldcp, int dir, uint64_t flag)
4372 {
4373 	vsw_t		*vswp = ldcp->ldc_vswp;
4374 	uint64_t	state;
4375 	uint64_t	phase;
4376 
4377 	if (dir == INBOUND)
4378 		state = ldcp->lane_in.lstate;
4379 	else
4380 		state = ldcp->lane_out.lstate;
4381 
4382 	phase = ldcp->hphase;
4383 
4384 	switch (flag) {
4385 	case VSW_VER_INFO_RECV:
4386 		if (phase > VSW_MILESTONE0) {
4387 			DERR(vswp, "vsw_check_flag (%d): VER_INFO_RECV"
4388 				" when in state %d\n", ldcp->ldc_id, phase);
4389 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4390 			return (1);
4391 		}
4392 		break;
4393 
4394 	case VSW_VER_ACK_RECV:
4395 	case VSW_VER_NACK_RECV:
4396 		if (!(state & VSW_VER_INFO_SENT)) {
4397 			DERR(vswp, "vsw_check_flag (%d): spurious VER_ACK"
4398 				" or VER_NACK when in state %d\n",
4399 				ldcp->ldc_id, phase);
4400 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4401 			return (1);
4402 		} else
4403 			state &= ~VSW_VER_INFO_SENT;
4404 		break;
4405 
4406 	case VSW_ATTR_INFO_RECV:
4407 		if ((phase < VSW_MILESTONE1) || (phase >= VSW_MILESTONE2)) {
4408 			DERR(vswp, "vsw_check_flag (%d): ATTR_INFO_RECV"
4409 				" when in state %d\n", ldcp->ldc_id, phase);
4410 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4411 			return (1);
4412 		}
4413 		break;
4414 
4415 	case VSW_ATTR_ACK_RECV:
4416 	case VSW_ATTR_NACK_RECV:
4417 		if (!(state & VSW_ATTR_INFO_SENT)) {
4418 			DERR(vswp, "vsw_check_flag (%d): spurious ATTR_ACK"
4419 				" or ATTR_NACK when in state %d\n",
4420 				ldcp->ldc_id, phase);
4421 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4422 			return (1);
4423 		} else
4424 			state &= ~VSW_ATTR_INFO_SENT;
4425 		break;
4426 
4427 	case VSW_DRING_INFO_RECV:
4428 		if (phase < VSW_MILESTONE1) {
4429 			DERR(vswp, "vsw_check_flag (%d): DRING_INFO_RECV"
4430 				" when in state %d\n", ldcp->ldc_id, phase);
4431 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4432 			return (1);
4433 		}
4434 		break;
4435 
4436 	case VSW_DRING_ACK_RECV:
4437 	case VSW_DRING_NACK_RECV:
4438 		if (!(state & VSW_DRING_INFO_SENT)) {
4439 			DERR(vswp, "vsw_check_flag (%d): spurious DRING_ACK"
4440 				" or DRING_NACK when in state %d\n",
4441 				ldcp->ldc_id, phase);
4442 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4443 			return (1);
4444 		} else
4445 			state &= ~VSW_DRING_INFO_SENT;
4446 		break;
4447 
4448 	case VSW_RDX_INFO_RECV:
4449 		if (phase < VSW_MILESTONE3) {
4450 			DERR(vswp, "vsw_check_flag (%d): RDX_INFO_RECV"
4451 				" when in state %d\n", ldcp->ldc_id, phase);
4452 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4453 			return (1);
4454 		}
4455 		break;
4456 
4457 	case VSW_RDX_ACK_RECV:
4458 	case VSW_RDX_NACK_RECV:
4459 		if (!(state & VSW_RDX_INFO_SENT)) {
4460 			DERR(vswp, "vsw_check_flag (%d): spurious RDX_ACK"
4461 				" or RDX_NACK when in state %d\n",
4462 				ldcp->ldc_id, phase);
4463 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4464 			return (1);
4465 		} else
4466 			state &= ~VSW_RDX_INFO_SENT;
4467 		break;
4468 
4469 	case VSW_MCST_INFO_RECV:
4470 		if (phase < VSW_MILESTONE3) {
4471 			DERR(vswp, "vsw_check_flag (%d): VSW_MCST_INFO_RECV"
4472 				" when in state %d\n", ldcp->ldc_id, phase);
4473 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4474 			return (1);
4475 		}
4476 		break;
4477 
4478 	default:
4479 		DERR(vswp, "vsw_check_flag (%lld): unknown flag (%llx)",
4480 				ldcp->ldc_id, flag);
4481 		return (1);
4482 	}
4483 
4484 	if (dir == INBOUND)
4485 		ldcp->lane_in.lstate = state;
4486 	else
4487 		ldcp->lane_out.lstate = state;
4488 
4489 	D1(vswp, "vsw_check_flag (chan %lld): exit", ldcp->ldc_id);
4490 
4491 	return (0);
4492 }
4493 
4494 void
4495 vsw_next_milestone(vsw_ldc_t *ldcp)
4496 {
4497 	vsw_t		*vswp = ldcp->ldc_vswp;
4498 
4499 	D1(vswp, "%s (chan %lld): enter (phase %ld)", __func__,
4500 		ldcp->ldc_id, ldcp->hphase);
4501 
4502 	DUMP_FLAGS(ldcp->lane_in.lstate);
4503 	DUMP_FLAGS(ldcp->lane_out.lstate);
4504 
4505 	switch (ldcp->hphase) {
4506 
4507 	case VSW_MILESTONE0:
4508 		/*
4509 		 * If we haven't started to handshake with our peer,
4510 		 * start to do so now.
4511 		 */
4512 		if (ldcp->lane_out.lstate == 0) {
4513 			D2(vswp, "%s: (chan %lld) starting handshake "
4514 				"with peer", __func__, ldcp->ldc_id);
4515 			vsw_process_conn_evt(ldcp, VSW_CONN_UP);
4516 		}
4517 
4518 		/*
4519 		 * Only way to pass this milestone is to have successfully
4520 		 * negotiated version info.
4521 		 */
4522 		if ((ldcp->lane_in.lstate & VSW_VER_ACK_SENT) &&
4523 			(ldcp->lane_out.lstate & VSW_VER_ACK_RECV)) {
4524 
4525 			D2(vswp, "%s: (chan %lld) leaving milestone 0",
4526 				__func__, ldcp->ldc_id);
4527 
4528 			/*
4529 			 * Next milestone is passed when attribute
4530 			 * information has been successfully exchanged.
4531 			 */
4532 			ldcp->hphase = VSW_MILESTONE1;
4533 			vsw_send_attr(ldcp);
4534 
4535 		}
4536 		break;
4537 
4538 	case VSW_MILESTONE1:
4539 		/*
4540 		 * Only way to pass this milestone is to have successfully
4541 		 * negotiated attribute information.
4542 		 */
4543 		if (ldcp->lane_in.lstate & VSW_ATTR_ACK_SENT) {
4544 
4545 			ldcp->hphase = VSW_MILESTONE2;
4546 
4547 			/*
4548 			 * If the peer device has said it wishes to
4549 			 * use descriptor rings then we send it our ring
4550 			 * info, otherwise we just set up a private ring
4551 			 * which we use an internal buffer
4552 			 */
4553 			if (ldcp->lane_in.xfer_mode == VIO_DRING_MODE)
4554 				vsw_send_dring_info(ldcp);
4555 		}
4556 		break;
4557 
4558 	case VSW_MILESTONE2:
4559 		/*
4560 		 * If peer has indicated in its attribute message that
4561 		 * it wishes to use descriptor rings then the only way
4562 		 * to pass this milestone is for us to have received
4563 		 * valid dring info.
4564 		 *
4565 		 * If peer is not using descriptor rings then just fall
4566 		 * through.
4567 		 */
4568 		if ((ldcp->lane_in.xfer_mode == VIO_DRING_MODE) &&
4569 			(!(ldcp->lane_in.lstate & VSW_DRING_ACK_SENT)))
4570 			break;
4571 
4572 		D2(vswp, "%s: (chan %lld) leaving milestone 2",
4573 				__func__, ldcp->ldc_id);
4574 
4575 		ldcp->hphase = VSW_MILESTONE3;
4576 		vsw_send_rdx(ldcp);
4577 		break;
4578 
4579 	case VSW_MILESTONE3:
4580 		/*
4581 		 * Pass this milestone when all paramaters have been
4582 		 * successfully exchanged and RDX sent in both directions.
4583 		 *
4584 		 * Mark outbound lane as available to transmit data.
4585 		 */
4586 		if ((ldcp->lane_out.lstate & VSW_RDX_ACK_SENT) &&
4587 			(ldcp->lane_in.lstate & VSW_RDX_ACK_RECV)) {
4588 
4589 			D2(vswp, "%s: (chan %lld) leaving milestone 3",
4590 				__func__, ldcp->ldc_id);
4591 			D2(vswp, "%s: ** handshake complete (0x%llx : "
4592 				"0x%llx) **", __func__, ldcp->lane_in.lstate,
4593 				ldcp->lane_out.lstate);
4594 			ldcp->lane_out.lstate |= VSW_LANE_ACTIVE;
4595 			ldcp->hphase = VSW_MILESTONE4;
4596 			ldcp->hcnt = 0;
4597 			DISPLAY_STATE();
4598 		} else {
4599 			D2(vswp, "%s: still in milestone 3 (0x%llx :"
4600 				" 0x%llx", __func__, ldcp->lane_in.lstate,
4601 				ldcp->lane_out.lstate);
4602 		}
4603 		break;
4604 
4605 	case VSW_MILESTONE4:
4606 		D2(vswp, "%s: (chan %lld) in milestone 4", __func__,
4607 							ldcp->ldc_id);
4608 		break;
4609 
4610 	default:
4611 		DERR(vswp, "%s: (chan %lld) Unknown Phase %x", __func__,
4612 			ldcp->ldc_id, ldcp->hphase);
4613 	}
4614 
4615 	D1(vswp, "%s (chan %lld): exit (phase %ld)", __func__, ldcp->ldc_id,
4616 		ldcp->hphase);
4617 }
4618 
4619 /*
4620  * Check if major version is supported.
4621  *
4622  * Returns 0 if finds supported major number, and if necessary
4623  * adjusts the minor field.
4624  *
4625  * Returns 1 if can't match major number exactly. Sets mjor/minor
4626  * to next lowest support values, or to zero if no other values possible.
4627  */
4628 static int
4629 vsw_supported_version(vio_ver_msg_t *vp)
4630 {
4631 	int	i;
4632 
4633 	D1(NULL, "vsw_supported_version: enter");
4634 
4635 	for (i = 0; i < VSW_NUM_VER; i++) {
4636 		if (vsw_versions[i].ver_major == vp->ver_major) {
4637 			/*
4638 			 * Matching or lower major version found. Update
4639 			 * minor number if necessary.
4640 			 */
4641 			if (vp->ver_minor > vsw_versions[i].ver_minor) {
4642 				D2(NULL, "%s: adjusting minor value"
4643 					" from %d to %d", __func__,
4644 					vp->ver_minor,
4645 					vsw_versions[i].ver_minor);
4646 				vp->ver_minor = vsw_versions[i].ver_minor;
4647 			}
4648 
4649 			return (0);
4650 		}
4651 
4652 		if (vsw_versions[i].ver_major < vp->ver_major) {
4653 			if (vp->ver_minor > vsw_versions[i].ver_minor) {
4654 				D2(NULL, "%s: adjusting minor value"
4655 					" from %d to %d", __func__,
4656 					vp->ver_minor,
4657 					vsw_versions[i].ver_minor);
4658 				vp->ver_minor = vsw_versions[i].ver_minor;
4659 			}
4660 			return (1);
4661 		}
4662 	}
4663 
4664 	/* No match was possible, zero out fields */
4665 	vp->ver_major = 0;
4666 	vp->ver_minor = 0;
4667 
4668 	D1(NULL, "vsw_supported_version: exit");
4669 
4670 	return (1);
4671 }
4672 
4673 /*
4674  * Main routine for processing messages received over LDC.
4675  */
4676 static void
4677 vsw_process_pkt(void *arg)
4678 {
4679 	vsw_ldc_t	*ldcp = (vsw_ldc_t  *)arg;
4680 	vsw_t 		*vswp = ldcp->ldc_vswp;
4681 	size_t		msglen;
4682 	vio_msg_tag_t	tag;
4683 	def_msg_t	dmsg;
4684 	int 		rv = 0;
4685 
4686 
4687 	D1(vswp, "%s enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
4688 
4689 	/*
4690 	 * If channel is up read messages until channel is empty.
4691 	 */
4692 	do {
4693 		msglen = sizeof (dmsg);
4694 		rv = ldc_read(ldcp->ldc_handle, (caddr_t)&dmsg, &msglen);
4695 
4696 		if (rv != 0) {
4697 			DERR(vswp, "%s :ldc_read err id(%lld) rv(%d) "
4698 				"len(%d)\n", __func__, ldcp->ldc_id,
4699 							rv, msglen);
4700 		}
4701 
4702 		/* channel has been reset */
4703 		if (rv == ECONNRESET) {
4704 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
4705 			break;
4706 		}
4707 
4708 		if (msglen == 0) {
4709 			D2(vswp, "%s: ldc_read id(%lld) NODATA", __func__,
4710 			ldcp->ldc_id);
4711 			break;
4712 		}
4713 
4714 		D2(vswp, "%s: ldc_read id(%lld): msglen(%d)", __func__,
4715 		    ldcp->ldc_id, msglen);
4716 
4717 		/*
4718 		 * Figure out what sort of packet we have gotten by
4719 		 * examining the msg tag, and then switch it appropriately.
4720 		 */
4721 		bcopy(&dmsg, &tag, sizeof (vio_msg_tag_t));
4722 
4723 		switch (tag.vio_msgtype) {
4724 		case VIO_TYPE_CTRL:
4725 			vsw_dispatch_ctrl_task(ldcp, &dmsg, tag);
4726 			break;
4727 		case VIO_TYPE_DATA:
4728 			vsw_process_data_pkt(ldcp, &dmsg, tag);
4729 			break;
4730 		case VIO_TYPE_ERR:
4731 			vsw_process_err_pkt(ldcp, &dmsg, tag);
4732 			break;
4733 		default:
4734 			DERR(vswp, "%s: Unknown tag(%lx) ", __func__,
4735 				"id(%lx)\n", tag.vio_msgtype, ldcp->ldc_id);
4736 			break;
4737 		}
4738 	} while (msglen);
4739 
4740 	D1(vswp, "%s exit: ldcid (%lld)\n", __func__, ldcp->ldc_id);
4741 }
4742 
4743 /*
4744  * Dispatch a task to process a VIO control message.
4745  */
4746 static void
4747 vsw_dispatch_ctrl_task(vsw_ldc_t *ldcp, void *cpkt, vio_msg_tag_t tag)
4748 {
4749 	vsw_ctrl_task_t		*ctaskp = NULL;
4750 	vsw_port_t		*port = ldcp->ldc_port;
4751 	vsw_t			*vswp = port->p_vswp;
4752 
4753 	D1(vswp, "%s: enter", __func__);
4754 
4755 	/*
4756 	 * We need to handle RDX ACK messages in-band as once they
4757 	 * are exchanged it is possible that we will get an
4758 	 * immediate (legitimate) data packet.
4759 	 */
4760 	if ((tag.vio_subtype_env == VIO_RDX) &&
4761 		(tag.vio_subtype == VIO_SUBTYPE_ACK)) {
4762 
4763 		if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_ACK_RECV))
4764 			return;
4765 
4766 		ldcp->lane_in.lstate |= VSW_RDX_ACK_RECV;
4767 		D2(vswp, "%s (%ld) handling RDX_ACK in place "
4768 			"(ostate 0x%llx : hphase %d)", __func__,
4769 			ldcp->ldc_id, ldcp->lane_in.lstate, ldcp->hphase);
4770 		vsw_next_milestone(ldcp);
4771 		return;
4772 	}
4773 
4774 	ctaskp = kmem_alloc(sizeof (vsw_ctrl_task_t), KM_NOSLEEP);
4775 
4776 	if (ctaskp == NULL) {
4777 		DERR(vswp, "%s: unable to alloc space for ctrl"
4778 			" msg", __func__);
4779 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4780 		return;
4781 	}
4782 
4783 	ctaskp->ldcp = ldcp;
4784 	bcopy((def_msg_t *)cpkt, &ctaskp->pktp, sizeof (def_msg_t));
4785 	mutex_enter(&ldcp->hss_lock);
4786 	ctaskp->hss_id = ldcp->hss_id;
4787 	mutex_exit(&ldcp->hss_lock);
4788 
4789 	/*
4790 	 * Dispatch task to processing taskq if port is not in
4791 	 * the process of being detached.
4792 	 */
4793 	mutex_enter(&port->state_lock);
4794 	if (port->state == VSW_PORT_INIT) {
4795 		if ((vswp->taskq_p == NULL) ||
4796 			(ddi_taskq_dispatch(vswp->taskq_p,
4797 			vsw_process_ctrl_pkt, ctaskp, DDI_NOSLEEP)
4798 							!= DDI_SUCCESS)) {
4799 			DERR(vswp, "%s: unable to dispatch task to taskq",
4800 				__func__);
4801 			kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
4802 			mutex_exit(&port->state_lock);
4803 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4804 			return;
4805 		}
4806 	} else {
4807 		DWARN(vswp, "%s: port %d detaching, not dispatching "
4808 			"task", __func__, port->p_instance);
4809 	}
4810 
4811 	mutex_exit(&port->state_lock);
4812 
4813 	D2(vswp, "%s: dispatched task to taskq for chan %d", __func__,
4814 			ldcp->ldc_id);
4815 	D1(vswp, "%s: exit", __func__);
4816 }
4817 
4818 /*
4819  * Process a VIO ctrl message. Invoked from taskq.
4820  */
4821 static void
4822 vsw_process_ctrl_pkt(void *arg)
4823 {
4824 	vsw_ctrl_task_t	*ctaskp = (vsw_ctrl_task_t *)arg;
4825 	vsw_ldc_t	*ldcp = ctaskp->ldcp;
4826 	vsw_t 		*vswp = ldcp->ldc_vswp;
4827 	vio_msg_tag_t	tag;
4828 	uint16_t	env;
4829 
4830 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
4831 
4832 	bcopy(&ctaskp->pktp, &tag, sizeof (vio_msg_tag_t));
4833 	env = tag.vio_subtype_env;
4834 
4835 	/* stale pkt check */
4836 	mutex_enter(&ldcp->hss_lock);
4837 	if (ctaskp->hss_id < ldcp->hss_id) {
4838 		DWARN(vswp, "%s: discarding stale packet belonging to"
4839 			" earlier (%ld) handshake session", __func__,
4840 			ctaskp->hss_id);
4841 		mutex_exit(&ldcp->hss_lock);
4842 		return;
4843 	}
4844 	mutex_exit(&ldcp->hss_lock);
4845 
4846 	/* session id check */
4847 	if (ldcp->session_status & VSW_PEER_SESSION) {
4848 		if (ldcp->peer_session != tag.vio_sid) {
4849 			DERR(vswp, "%s (chan %d): invalid session id (%llx)",
4850 				__func__, ldcp->ldc_id, tag.vio_sid);
4851 			kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
4852 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
4853 			return;
4854 		}
4855 	}
4856 
4857 	/*
4858 	 * Switch on vio_subtype envelope, then let lower routines
4859 	 * decide if its an INFO, ACK or NACK packet.
4860 	 */
4861 	switch (env) {
4862 	case VIO_VER_INFO:
4863 		vsw_process_ctrl_ver_pkt(ldcp, &ctaskp->pktp);
4864 		break;
4865 	case VIO_DRING_REG:
4866 		vsw_process_ctrl_dring_reg_pkt(ldcp, &ctaskp->pktp);
4867 		break;
4868 	case VIO_DRING_UNREG:
4869 		vsw_process_ctrl_dring_unreg_pkt(ldcp, &ctaskp->pktp);
4870 		break;
4871 	case VIO_ATTR_INFO:
4872 		vsw_process_ctrl_attr_pkt(ldcp, &ctaskp->pktp);
4873 		break;
4874 	case VNET_MCAST_INFO:
4875 		vsw_process_ctrl_mcst_pkt(ldcp, &ctaskp->pktp);
4876 		break;
4877 	case VIO_RDX:
4878 		vsw_process_ctrl_rdx_pkt(ldcp, &ctaskp->pktp);
4879 		break;
4880 	default:
4881 		DERR(vswp, "%s : unknown vio_subtype_env (%x)\n",
4882 							__func__, env);
4883 	}
4884 
4885 	kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
4886 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
4887 }
4888 
4889 /*
4890  * Version negotiation. We can end up here either because our peer
4891  * has responded to a handshake message we have sent it, or our peer
4892  * has initiated a handshake with us. If its the former then can only
4893  * be ACK or NACK, if its the later can only be INFO.
4894  *
4895  * If its an ACK we move to the next stage of the handshake, namely
4896  * attribute exchange. If its a NACK we see if we can specify another
4897  * version, if we can't we stop.
4898  *
4899  * If it is an INFO we reset all params associated with communication
4900  * in that direction over this channel (remember connection is
4901  * essentially 2 independent simplex channels).
4902  */
4903 void
4904 vsw_process_ctrl_ver_pkt(vsw_ldc_t *ldcp, void *pkt)
4905 {
4906 	vio_ver_msg_t	*ver_pkt;
4907 	vsw_t 		*vswp = ldcp->ldc_vswp;
4908 
4909 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
4910 
4911 	/*
4912 	 * We know this is a ctrl/version packet so
4913 	 * cast it into the correct structure.
4914 	 */
4915 	ver_pkt = (vio_ver_msg_t *)pkt;
4916 
4917 	switch (ver_pkt->tag.vio_subtype) {
4918 	case VIO_SUBTYPE_INFO:
4919 		D2(vswp, "vsw_process_ctrl_ver_pkt: VIO_SUBTYPE_INFO\n");
4920 
4921 		/*
4922 		 * Record the session id, which we will use from now
4923 		 * until we see another VER_INFO msg. Even then the
4924 		 * session id in most cases will be unchanged, execpt
4925 		 * if channel was reset.
4926 		 */
4927 		if ((ldcp->session_status & VSW_PEER_SESSION) &&
4928 			(ldcp->peer_session != ver_pkt->tag.vio_sid)) {
4929 			DERR(vswp, "%s: updating session id for chan %lld "
4930 				"from %llx to %llx", __func__, ldcp->ldc_id,
4931 				ldcp->peer_session, ver_pkt->tag.vio_sid);
4932 		}
4933 
4934 		ldcp->peer_session = ver_pkt->tag.vio_sid;
4935 		ldcp->session_status |= VSW_PEER_SESSION;
4936 
4937 		/* Legal message at this time ? */
4938 		if (vsw_check_flag(ldcp, INBOUND, VSW_VER_INFO_RECV))
4939 			return;
4940 
4941 		/*
4942 		 * First check the device class. Currently only expect
4943 		 * to be talking to a network device. In the future may
4944 		 * also talk to another switch.
4945 		 */
4946 		if (ver_pkt->dev_class != VDEV_NETWORK) {
4947 			DERR(vswp, "%s: illegal device class %d", __func__,
4948 				ver_pkt->dev_class);
4949 
4950 			ver_pkt->tag.vio_sid = ldcp->local_session;
4951 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
4952 
4953 			DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
4954 
4955 			(void) vsw_send_msg(ldcp, (void *)ver_pkt,
4956 					sizeof (vio_ver_msg_t), B_TRUE);
4957 
4958 			ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
4959 			vsw_next_milestone(ldcp);
4960 			return;
4961 		} else {
4962 			ldcp->dev_class = ver_pkt->dev_class;
4963 		}
4964 
4965 		/*
4966 		 * Now check the version.
4967 		 */
4968 		if (vsw_supported_version(ver_pkt) == 0) {
4969 			/*
4970 			 * Support this major version and possibly
4971 			 * adjusted minor version.
4972 			 */
4973 
4974 			D2(vswp, "%s: accepted ver %d:%d", __func__,
4975 				ver_pkt->ver_major, ver_pkt->ver_minor);
4976 
4977 			/* Store accepted values */
4978 			ldcp->lane_in.ver_major = ver_pkt->ver_major;
4979 			ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
4980 
4981 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
4982 
4983 			ldcp->lane_in.lstate |= VSW_VER_ACK_SENT;
4984 		} else {
4985 			/*
4986 			 * NACK back with the next lower major/minor
4987 			 * pairing we support (if don't suuport any more
4988 			 * versions then they will be set to zero.
4989 			 */
4990 
4991 			D2(vswp, "%s: replying with ver %d:%d", __func__,
4992 				ver_pkt->ver_major, ver_pkt->ver_minor);
4993 
4994 			/* Store updated values */
4995 			ldcp->lane_in.ver_major = ver_pkt->ver_major;
4996 			ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
4997 
4998 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
4999 
5000 			ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
5001 		}
5002 
5003 		DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
5004 		ver_pkt->tag.vio_sid = ldcp->local_session;
5005 		(void) vsw_send_msg(ldcp, (void *)ver_pkt,
5006 			sizeof (vio_ver_msg_t), B_TRUE);
5007 
5008 		vsw_next_milestone(ldcp);
5009 		break;
5010 
5011 	case VIO_SUBTYPE_ACK:
5012 		D2(vswp, "%s: VIO_SUBTYPE_ACK\n", __func__);
5013 
5014 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_ACK_RECV))
5015 			return;
5016 
5017 		/* Store updated values */
5018 		ldcp->lane_in.ver_major = ver_pkt->ver_major;
5019 		ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
5020 
5021 
5022 		ldcp->lane_out.lstate |= VSW_VER_ACK_RECV;
5023 		vsw_next_milestone(ldcp);
5024 
5025 		break;
5026 
5027 	case VIO_SUBTYPE_NACK:
5028 		D2(vswp, "%s: VIO_SUBTYPE_NACK\n", __func__);
5029 
5030 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_NACK_RECV))
5031 			return;
5032 
5033 		/*
5034 		 * If our peer sent us a NACK with the ver fields set to
5035 		 * zero then there is nothing more we can do. Otherwise see
5036 		 * if we support either the version suggested, or a lesser
5037 		 * one.
5038 		 */
5039 		if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
5040 			DERR(vswp, "%s: peer unable to negotiate any "
5041 				"further.", __func__);
5042 			ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
5043 			vsw_next_milestone(ldcp);
5044 			return;
5045 		}
5046 
5047 		/*
5048 		 * Check to see if we support this major version or
5049 		 * a lower one. If we don't then maj/min will be set
5050 		 * to zero.
5051 		 */
5052 		(void) vsw_supported_version(ver_pkt);
5053 		if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
5054 			/* Nothing more we can do */
5055 			DERR(vswp, "%s: version negotiation failed.\n",
5056 								__func__);
5057 			ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
5058 			vsw_next_milestone(ldcp);
5059 		} else {
5060 			/* found a supported major version */
5061 			ldcp->lane_out.ver_major = ver_pkt->ver_major;
5062 			ldcp->lane_out.ver_minor = ver_pkt->ver_minor;
5063 
5064 			D2(vswp, "%s: resending with updated values (%x, %x)",
5065 				__func__, ver_pkt->ver_major,
5066 				ver_pkt->ver_minor);
5067 
5068 			ldcp->lane_out.lstate |= VSW_VER_INFO_SENT;
5069 			ver_pkt->tag.vio_sid = ldcp->local_session;
5070 			ver_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
5071 
5072 			DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
5073 
5074 			(void) vsw_send_msg(ldcp, (void *)ver_pkt,
5075 				sizeof (vio_ver_msg_t), B_TRUE);
5076 
5077 			vsw_next_milestone(ldcp);
5078 
5079 		}
5080 		break;
5081 
5082 	default:
5083 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
5084 			ver_pkt->tag.vio_subtype);
5085 	}
5086 
5087 	D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id);
5088 }
5089 
5090 /*
5091  * Process an attribute packet. We can end up here either because our peer
5092  * has ACK/NACK'ed back to an earlier ATTR msg we had sent it, or our
5093  * peer has sent us an attribute INFO message
5094  *
5095  * If its an ACK we then move to the next stage of the handshake which
5096  * is to send our descriptor ring info to our peer. If its a NACK then
5097  * there is nothing more we can (currently) do.
5098  *
5099  * If we get a valid/acceptable INFO packet (and we have already negotiated
5100  * a version) we ACK back and set channel state to ATTR_RECV, otherwise we
5101  * NACK back and reset channel state to INACTIV.
5102  *
5103  * FUTURE: in time we will probably negotiate over attributes, but for
5104  * the moment unacceptable attributes are regarded as a fatal error.
5105  *
5106  */
5107 void
5108 vsw_process_ctrl_attr_pkt(vsw_ldc_t *ldcp, void *pkt)
5109 {
5110 	vnet_attr_msg_t		*attr_pkt;
5111 	vsw_t			*vswp = ldcp->ldc_vswp;
5112 	vsw_port_t		*port = ldcp->ldc_port;
5113 	uint64_t		macaddr = 0;
5114 	int			i;
5115 
5116 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
5117 
5118 	/*
5119 	 * We know this is a ctrl/attr packet so
5120 	 * cast it into the correct structure.
5121 	 */
5122 	attr_pkt = (vnet_attr_msg_t *)pkt;
5123 
5124 	switch (attr_pkt->tag.vio_subtype) {
5125 	case VIO_SUBTYPE_INFO:
5126 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
5127 
5128 		if (vsw_check_flag(ldcp, INBOUND, VSW_ATTR_INFO_RECV))
5129 			return;
5130 
5131 		/*
5132 		 * If the attributes are unacceptable then we NACK back.
5133 		 */
5134 		if (vsw_check_attr(attr_pkt, ldcp->ldc_port)) {
5135 
5136 			DERR(vswp, "%s (chan %d): invalid attributes",
5137 				__func__, ldcp->ldc_id);
5138 
5139 			vsw_free_lane_resources(ldcp, INBOUND);
5140 
5141 			attr_pkt->tag.vio_sid = ldcp->local_session;
5142 			attr_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
5143 
5144 			DUMP_TAG_PTR((vio_msg_tag_t *)attr_pkt);
5145 			ldcp->lane_in.lstate |= VSW_ATTR_NACK_SENT;
5146 			(void) vsw_send_msg(ldcp, (void *)attr_pkt,
5147 				sizeof (vnet_attr_msg_t), B_TRUE);
5148 
5149 			vsw_next_milestone(ldcp);
5150 			return;
5151 		}
5152 
5153 		/*
5154 		 * Otherwise store attributes for this lane and update
5155 		 * lane state.
5156 		 */
5157 		ldcp->lane_in.mtu = attr_pkt->mtu;
5158 		ldcp->lane_in.addr = attr_pkt->addr;
5159 		ldcp->lane_in.addr_type = attr_pkt->addr_type;
5160 		ldcp->lane_in.xfer_mode = attr_pkt->xfer_mode;
5161 		ldcp->lane_in.ack_freq = attr_pkt->ack_freq;
5162 
5163 		macaddr = ldcp->lane_in.addr;
5164 		for (i = ETHERADDRL - 1; i >= 0; i--) {
5165 			port->p_macaddr.ether_addr_octet[i] = macaddr & 0xFF;
5166 			macaddr >>= 8;
5167 		}
5168 
5169 		/* create the fdb entry for this port/mac address */
5170 		(void) vsw_add_fdb(vswp, port);
5171 
5172 		/* setup device specifc xmit routines */
5173 		mutex_enter(&port->tx_lock);
5174 		if (ldcp->lane_in.xfer_mode == VIO_DRING_MODE) {
5175 			D2(vswp, "%s: mode = VIO_DRING_MODE", __func__);
5176 			port->transmit = vsw_dringsend;
5177 		} else if (ldcp->lane_in.xfer_mode == VIO_DESC_MODE) {
5178 			D2(vswp, "%s: mode = VIO_DESC_MODE", __func__);
5179 			vsw_create_privring(ldcp);
5180 			port->transmit = vsw_descrsend;
5181 		}
5182 		mutex_exit(&port->tx_lock);
5183 
5184 		attr_pkt->tag.vio_sid = ldcp->local_session;
5185 		attr_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
5186 
5187 		DUMP_TAG_PTR((vio_msg_tag_t *)attr_pkt);
5188 
5189 		ldcp->lane_in.lstate |= VSW_ATTR_ACK_SENT;
5190 
5191 		(void) vsw_send_msg(ldcp, (void *)attr_pkt,
5192 				sizeof (vnet_attr_msg_t), B_TRUE);
5193 
5194 		vsw_next_milestone(ldcp);
5195 		break;
5196 
5197 	case VIO_SUBTYPE_ACK:
5198 		D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
5199 
5200 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_ACK_RECV))
5201 			return;
5202 
5203 		ldcp->lane_out.lstate |= VSW_ATTR_ACK_RECV;
5204 		vsw_next_milestone(ldcp);
5205 		break;
5206 
5207 	case VIO_SUBTYPE_NACK:
5208 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
5209 
5210 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_NACK_RECV))
5211 			return;
5212 
5213 		ldcp->lane_out.lstate |= VSW_ATTR_NACK_RECV;
5214 		vsw_next_milestone(ldcp);
5215 		break;
5216 
5217 	default:
5218 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
5219 			attr_pkt->tag.vio_subtype);
5220 	}
5221 
5222 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
5223 }
5224 
5225 /*
5226  * Process a dring info packet. We can end up here either because our peer
5227  * has ACK/NACK'ed back to an earlier DRING msg we had sent it, or our
5228  * peer has sent us a dring INFO message.
5229  *
5230  * If we get a valid/acceptable INFO packet (and we have already negotiated
5231  * a version) we ACK back and update the lane state, otherwise we NACK back.
5232  *
5233  * FUTURE: nothing to stop client from sending us info on multiple dring's
5234  * but for the moment we will just use the first one we are given.
5235  *
5236  */
5237 void
5238 vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *ldcp, void *pkt)
5239 {
5240 	vio_dring_reg_msg_t	*dring_pkt;
5241 	vsw_t			*vswp = ldcp->ldc_vswp;
5242 	ldc_mem_info_t		minfo;
5243 	dring_info_t		*dp, *dbp;
5244 	int			dring_found = 0;
5245 
5246 	/*
5247 	 * We know this is a ctrl/dring packet so
5248 	 * cast it into the correct structure.
5249 	 */
5250 	dring_pkt = (vio_dring_reg_msg_t *)pkt;
5251 
5252 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
5253 
5254 	switch (dring_pkt->tag.vio_subtype) {
5255 	case VIO_SUBTYPE_INFO:
5256 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
5257 
5258 		if (vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV))
5259 			return;
5260 
5261 		/*
5262 		 * If the dring params are unacceptable then we NACK back.
5263 		 */
5264 		if (vsw_check_dring_info(dring_pkt)) {
5265 
5266 			DERR(vswp, "%s (%lld): invalid dring info",
5267 				__func__, ldcp->ldc_id);
5268 
5269 			vsw_free_lane_resources(ldcp, INBOUND);
5270 
5271 			dring_pkt->tag.vio_sid = ldcp->local_session;
5272 			dring_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
5273 
5274 			DUMP_TAG_PTR((vio_msg_tag_t *)dring_pkt);
5275 
5276 			ldcp->lane_in.lstate |= VSW_DRING_NACK_SENT;
5277 
5278 			(void) vsw_send_msg(ldcp, (void *)dring_pkt,
5279 				sizeof (vio_dring_reg_msg_t), B_TRUE);
5280 
5281 			vsw_next_milestone(ldcp);
5282 			return;
5283 		}
5284 
5285 		/*
5286 		 * Otherwise, attempt to map in the dring using the
5287 		 * cookie. If that succeeds we send back a unique dring
5288 		 * identifier that the sending side will use in future
5289 		 * to refer to this descriptor ring.
5290 		 */
5291 		dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
5292 
5293 		dp->num_descriptors = dring_pkt->num_descriptors;
5294 		dp->descriptor_size = dring_pkt->descriptor_size;
5295 		dp->options = dring_pkt->options;
5296 		dp->ncookies = dring_pkt->ncookies;
5297 
5298 		/*
5299 		 * Note: should only get one cookie. Enforced in
5300 		 * the ldc layer.
5301 		 */
5302 		bcopy(&dring_pkt->cookie[0], &dp->cookie[0],
5303 			sizeof (ldc_mem_cookie_t));
5304 
5305 		D2(vswp, "%s: num_desc %ld : desc_size %ld", __func__,
5306 			dp->num_descriptors, dp->descriptor_size);
5307 		D2(vswp, "%s: options 0x%lx: ncookies %ld", __func__,
5308 			dp->options, dp->ncookies);
5309 
5310 		if ((ldc_mem_dring_map(ldcp->ldc_handle, &dp->cookie[0],
5311 			dp->ncookies, dp->num_descriptors,
5312 			dp->descriptor_size, LDC_SHADOW_MAP,
5313 			&(dp->handle))) != 0) {
5314 
5315 			DERR(vswp, "%s: dring_map failed\n", __func__);
5316 
5317 			kmem_free(dp, sizeof (dring_info_t));
5318 			vsw_free_lane_resources(ldcp, INBOUND);
5319 
5320 			dring_pkt->tag.vio_sid = ldcp->local_session;
5321 			dring_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
5322 
5323 			DUMP_TAG_PTR((vio_msg_tag_t *)dring_pkt);
5324 
5325 			ldcp->lane_in.lstate |= VSW_DRING_NACK_SENT;
5326 			(void) vsw_send_msg(ldcp, (void *)dring_pkt,
5327 				sizeof (vio_dring_reg_msg_t), B_TRUE);
5328 
5329 			vsw_next_milestone(ldcp);
5330 			return;
5331 		}
5332 
5333 		if ((ldc_mem_dring_info(dp->handle, &minfo)) != 0) {
5334 
5335 			DERR(vswp, "%s: dring_addr failed\n", __func__);
5336 
5337 			kmem_free(dp, sizeof (dring_info_t));
5338 			vsw_free_lane_resources(ldcp, INBOUND);
5339 
5340 			dring_pkt->tag.vio_sid = ldcp->local_session;
5341 			dring_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
5342 
5343 			DUMP_TAG_PTR((vio_msg_tag_t *)dring_pkt);
5344 
5345 			ldcp->lane_in.lstate |= VSW_DRING_NACK_SENT;
5346 			(void) vsw_send_msg(ldcp, (void *)dring_pkt,
5347 				sizeof (vio_dring_reg_msg_t), B_TRUE);
5348 
5349 			vsw_next_milestone(ldcp);
5350 			return;
5351 		} else {
5352 			/* store the address of the pub part of ring */
5353 			dp->pub_addr = minfo.vaddr;
5354 		}
5355 
5356 		/* no private section as we are importing */
5357 		dp->priv_addr = NULL;
5358 
5359 		/*
5360 		 * Using simple mono increasing int for ident at
5361 		 * the moment.
5362 		 */
5363 		dp->ident = ldcp->next_ident;
5364 		ldcp->next_ident++;
5365 
5366 		dp->end_idx = 0;
5367 		dp->next = NULL;
5368 
5369 		/*
5370 		 * Link it onto the end of the list of drings
5371 		 * for this lane.
5372 		 */
5373 		if (ldcp->lane_in.dringp == NULL) {
5374 			D2(vswp, "%s: adding first INBOUND dring", __func__);
5375 			ldcp->lane_in.dringp = dp;
5376 		} else {
5377 			dbp = ldcp->lane_in.dringp;
5378 
5379 			while (dbp->next != NULL)
5380 				dbp = dbp->next;
5381 
5382 			dbp->next = dp;
5383 		}
5384 
5385 		/* acknowledge it */
5386 		dring_pkt->tag.vio_sid = ldcp->local_session;
5387 		dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
5388 		dring_pkt->dring_ident = dp->ident;
5389 
5390 		(void) vsw_send_msg(ldcp, (void *)dring_pkt,
5391 			sizeof (vio_dring_reg_msg_t), B_TRUE);
5392 
5393 		ldcp->lane_in.lstate |= VSW_DRING_ACK_SENT;
5394 		vsw_next_milestone(ldcp);
5395 		break;
5396 
5397 	case VIO_SUBTYPE_ACK:
5398 		D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
5399 
5400 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_ACK_RECV))
5401 			return;
5402 
5403 		/*
5404 		 * Peer is acknowledging our dring info and will have
5405 		 * sent us a dring identifier which we will use to
5406 		 * refer to this ring w.r.t. our peer.
5407 		 */
5408 		dp = ldcp->lane_out.dringp;
5409 		if (dp != NULL) {
5410 			/*
5411 			 * Find the ring this ident should be associated
5412 			 * with.
5413 			 */
5414 			if (vsw_dring_match(dp, dring_pkt)) {
5415 				dring_found = 1;
5416 
5417 			} else while (dp != NULL) {
5418 				if (vsw_dring_match(dp, dring_pkt)) {
5419 					dring_found = 1;
5420 					break;
5421 				}
5422 				dp = dp->next;
5423 			}
5424 
5425 			if (dring_found == 0) {
5426 				DERR(NULL, "%s: unrecognised ring cookie",
5427 					__func__);
5428 				vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5429 				return;
5430 			}
5431 
5432 		} else {
5433 			DERR(vswp, "%s: DRING ACK received but no drings "
5434 				"allocated", __func__);
5435 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5436 			return;
5437 		}
5438 
5439 		/* store ident */
5440 		dp->ident = dring_pkt->dring_ident;
5441 		ldcp->lane_out.lstate |= VSW_DRING_ACK_RECV;
5442 		vsw_next_milestone(ldcp);
5443 		break;
5444 
5445 	case VIO_SUBTYPE_NACK:
5446 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
5447 
5448 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_NACK_RECV))
5449 			return;
5450 
5451 		ldcp->lane_out.lstate |= VSW_DRING_NACK_RECV;
5452 		vsw_next_milestone(ldcp);
5453 		break;
5454 
5455 	default:
5456 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
5457 			dring_pkt->tag.vio_subtype);
5458 	}
5459 
5460 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
5461 }
5462 
5463 /*
5464  * Process a request from peer to unregister a dring.
5465  *
5466  * For the moment we just restart the handshake if our
5467  * peer endpoint attempts to unregister a dring.
5468  */
5469 void
5470 vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *ldcp, void *pkt)
5471 {
5472 	vsw_t			*vswp = ldcp->ldc_vswp;
5473 	vio_dring_unreg_msg_t	*dring_pkt;
5474 
5475 	/*
5476 	 * We know this is a ctrl/dring packet so
5477 	 * cast it into the correct structure.
5478 	 */
5479 	dring_pkt = (vio_dring_unreg_msg_t *)pkt;
5480 
5481 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
5482 
5483 	switch (dring_pkt->tag.vio_subtype) {
5484 	case VIO_SUBTYPE_INFO:
5485 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
5486 
5487 		DWARN(vswp, "%s: restarting handshake..", __func__);
5488 		break;
5489 
5490 	case VIO_SUBTYPE_ACK:
5491 		D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
5492 
5493 		DWARN(vswp, "%s: restarting handshake..", __func__);
5494 		break;
5495 
5496 	case VIO_SUBTYPE_NACK:
5497 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
5498 
5499 		DWARN(vswp, "%s: restarting handshake..", __func__);
5500 		break;
5501 
5502 	default:
5503 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
5504 			dring_pkt->tag.vio_subtype);
5505 	}
5506 
5507 	vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5508 
5509 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
5510 }
5511 
5512 #define	SND_MCST_NACK(ldcp, pkt) \
5513 	pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \
5514 	pkt->tag.vio_sid = ldcp->local_session; \
5515 	(void) vsw_send_msg(ldcp, (void *)pkt, \
5516 			sizeof (vnet_mcast_msg_t), B_TRUE);
5517 
5518 /*
5519  * Process a multicast request from a vnet.
5520  *
5521  * Vnet's specify a multicast address that they are interested in. This
5522  * address is used as a key into the hash table which forms the multicast
5523  * forwarding database (mFDB).
5524  *
5525  * The table keys are the multicast addresses, while the table entries
5526  * are pointers to lists of ports which wish to receive packets for the
5527  * specified multicast address.
5528  *
5529  * When a multicast packet is being switched we use the address as a key
5530  * into the hash table, and then walk the appropriate port list forwarding
5531  * the pkt to each port in turn.
5532  *
5533  * If a vnet is no longer interested in a particular multicast grouping
5534  * we simply find the correct location in the hash table and then delete
5535  * the relevant port from the port list.
5536  *
5537  * To deal with the case whereby a port is being deleted without first
5538  * removing itself from the lists in the hash table, we maintain a list
5539  * of multicast addresses the port has registered an interest in, within
5540  * the port structure itself. We then simply walk that list of addresses
5541  * using them as keys into the hash table and remove the port from the
5542  * appropriate lists.
5543  */
5544 static void
5545 vsw_process_ctrl_mcst_pkt(vsw_ldc_t *ldcp, void *pkt)
5546 {
5547 	vnet_mcast_msg_t	*mcst_pkt;
5548 	vsw_port_t		*port = ldcp->ldc_port;
5549 	vsw_t			*vswp = ldcp->ldc_vswp;
5550 	int			i;
5551 
5552 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
5553 
5554 	/*
5555 	 * We know this is a ctrl/mcast packet so
5556 	 * cast it into the correct structure.
5557 	 */
5558 	mcst_pkt = (vnet_mcast_msg_t *)pkt;
5559 
5560 	switch (mcst_pkt->tag.vio_subtype) {
5561 	case VIO_SUBTYPE_INFO:
5562 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
5563 
5564 		/*
5565 		 * Check if in correct state to receive a multicast
5566 		 * message (i.e. handshake complete). If not reset
5567 		 * the handshake.
5568 		 */
5569 		if (vsw_check_flag(ldcp, INBOUND, VSW_MCST_INFO_RECV))
5570 			return;
5571 
5572 		/*
5573 		 * Before attempting to add or remove address check
5574 		 * that they are valid multicast addresses.
5575 		 * If not, then NACK back.
5576 		 */
5577 		for (i = 0; i < mcst_pkt->count; i++) {
5578 			if ((mcst_pkt->mca[i].ether_addr_octet[0] & 01) != 1) {
5579 				DERR(vswp, "%s: invalid multicast address",
5580 								__func__);
5581 				SND_MCST_NACK(ldcp, mcst_pkt);
5582 				return;
5583 			}
5584 		}
5585 
5586 		/*
5587 		 * Now add/remove the addresses. If this fails we
5588 		 * NACK back.
5589 		 */
5590 		if (vsw_add_rem_mcst(mcst_pkt, port) != 0) {
5591 			SND_MCST_NACK(ldcp, mcst_pkt);
5592 			return;
5593 		}
5594 
5595 		mcst_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
5596 		mcst_pkt->tag.vio_sid = ldcp->local_session;
5597 
5598 		DUMP_TAG_PTR((vio_msg_tag_t *)mcst_pkt);
5599 
5600 		(void) vsw_send_msg(ldcp, (void *)mcst_pkt,
5601 				sizeof (vnet_mcast_msg_t), B_TRUE);
5602 		break;
5603 
5604 	case VIO_SUBTYPE_ACK:
5605 		DWARN(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
5606 
5607 		/*
5608 		 * We shouldn't ever get a multicast ACK message as
5609 		 * at the moment we never request multicast addresses
5610 		 * to be set on some other device. This may change in
5611 		 * the future if we have cascading switches.
5612 		 */
5613 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_ACK_RECV))
5614 			return;
5615 
5616 				/* Do nothing */
5617 		break;
5618 
5619 	case VIO_SUBTYPE_NACK:
5620 		DWARN(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
5621 
5622 		/*
5623 		 * We shouldn't get a multicast NACK packet for the
5624 		 * same reasons as we shouldn't get a ACK packet.
5625 		 */
5626 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_NACK_RECV))
5627 			return;
5628 
5629 				/* Do nothing */
5630 		break;
5631 
5632 	default:
5633 		DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
5634 			mcst_pkt->tag.vio_subtype);
5635 	}
5636 
5637 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
5638 }
5639 
5640 static void
5641 vsw_process_ctrl_rdx_pkt(vsw_ldc_t *ldcp, void *pkt)
5642 {
5643 	vio_rdx_msg_t	*rdx_pkt;
5644 	vsw_t		*vswp = ldcp->ldc_vswp;
5645 
5646 	/*
5647 	 * We know this is a ctrl/rdx packet so
5648 	 * cast it into the correct structure.
5649 	 */
5650 	rdx_pkt = (vio_rdx_msg_t *)pkt;
5651 
5652 	D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
5653 
5654 	switch (rdx_pkt->tag.vio_subtype) {
5655 	case VIO_SUBTYPE_INFO:
5656 		D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
5657 
5658 		if (vsw_check_flag(ldcp, OUTBOUND, VSW_RDX_INFO_RECV))
5659 			return;
5660 
5661 		rdx_pkt->tag.vio_sid = ldcp->local_session;
5662 		rdx_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
5663 
5664 		DUMP_TAG_PTR((vio_msg_tag_t *)rdx_pkt);
5665 
5666 		ldcp->lane_out.lstate |= VSW_RDX_ACK_SENT;
5667 
5668 		(void) vsw_send_msg(ldcp, (void *)rdx_pkt,
5669 			sizeof (vio_rdx_msg_t), B_TRUE);
5670 
5671 		vsw_next_milestone(ldcp);
5672 		break;
5673 
5674 	case VIO_SUBTYPE_ACK:
5675 		/*
5676 		 * Should be handled in-band by callback handler.
5677 		 */
5678 		DERR(vswp, "%s: Unexpected VIO_SUBTYPE_ACK", __func__);
5679 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5680 		break;
5681 
5682 	case VIO_SUBTYPE_NACK:
5683 		D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
5684 
5685 		if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_NACK_RECV))
5686 			return;
5687 
5688 		ldcp->lane_in.lstate |= VSW_RDX_NACK_RECV;
5689 		vsw_next_milestone(ldcp);
5690 		break;
5691 
5692 	default:
5693 		DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
5694 			rdx_pkt->tag.vio_subtype);
5695 	}
5696 
5697 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
5698 }
5699 
5700 static void
5701 vsw_process_data_pkt(vsw_ldc_t *ldcp, void *dpkt, vio_msg_tag_t tag)
5702 {
5703 	uint16_t	env = tag.vio_subtype_env;
5704 	vsw_t		*vswp = ldcp->ldc_vswp;
5705 
5706 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
5707 
5708 	/* session id check */
5709 	if (ldcp->session_status & VSW_PEER_SESSION) {
5710 		if (ldcp->peer_session != tag.vio_sid) {
5711 			DERR(vswp, "%s (chan %d): invalid session id (%llx)",
5712 				__func__, ldcp->ldc_id, tag.vio_sid);
5713 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5714 			return;
5715 		}
5716 	}
5717 
5718 	/*
5719 	 * It is an error for us to be getting data packets
5720 	 * before the handshake has completed.
5721 	 */
5722 	if (ldcp->hphase != VSW_MILESTONE4) {
5723 		DERR(vswp, "%s: got data packet before handshake complete "
5724 			"hphase %d (%x: %x)", __func__, ldcp->hphase,
5725 			ldcp->lane_in.lstate, ldcp->lane_out.lstate);
5726 		DUMP_FLAGS(ldcp->lane_in.lstate);
5727 		DUMP_FLAGS(ldcp->lane_out.lstate);
5728 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
5729 		return;
5730 	}
5731 
5732 	/*
5733 	 * Switch on vio_subtype envelope, then let lower routines
5734 	 * decide if its an INFO, ACK or NACK packet.
5735 	 */
5736 	if (env == VIO_DRING_DATA) {
5737 		vsw_process_data_dring_pkt(ldcp, dpkt);
5738 	} else if (env == VIO_PKT_DATA) {
5739 		vsw_process_data_raw_pkt(ldcp, dpkt);
5740 	} else if (env == VIO_DESC_DATA) {
5741 		vsw_process_data_ibnd_pkt(ldcp, dpkt);
5742 	} else {
5743 		DERR(vswp, "%s : unknown vio_subtype_env (%x)\n",
5744 							__func__, env);
5745 	}
5746 
5747 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
5748 }
5749 
5750 #define	SND_DRING_NACK(ldcp, pkt) \
5751 	pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \
5752 	pkt->tag.vio_sid = ldcp->local_session; \
5753 	(void) vsw_send_msg(ldcp, (void *)pkt, \
5754 			sizeof (vio_dring_msg_t), B_TRUE);
5755 
5756 static void
5757 vsw_process_data_dring_pkt(vsw_ldc_t *ldcp, void *dpkt)
5758 {
5759 	vio_dring_msg_t		*dring_pkt;
5760 	vnet_public_desc_t	*pub_addr = NULL;
5761 	vsw_private_desc_t	*priv_addr = NULL;
5762 	dring_info_t		*dp = NULL;
5763 	vsw_t			*vswp = ldcp->ldc_vswp;
5764 	mblk_t			*mp = NULL;
5765 	mblk_t			*bp = NULL;
5766 	mblk_t			*bpt = NULL;
5767 	size_t			nbytes = 0;
5768 	size_t			off = 0;
5769 	uint64_t		ncookies = 0;
5770 	uint64_t		chain = 0;
5771 	uint64_t		j, len;
5772 	uint32_t		pos, start, datalen;
5773 	uint32_t		range_start, range_end;
5774 	int32_t			end, num, cnt = 0;
5775 	int			i, rv, msg_rv = 0;
5776 	boolean_t		ack_needed = B_FALSE;
5777 	boolean_t		prev_desc_ack = B_FALSE;
5778 	int			read_attempts = 0;
5779 
5780 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
5781 
5782 	/*
5783 	 * We know this is a data/dring packet so
5784 	 * cast it into the correct structure.
5785 	 */
5786 	dring_pkt = (vio_dring_msg_t *)dpkt;
5787 
5788 	/*
5789 	 * Switch on the vio_subtype. If its INFO then we need to
5790 	 * process the data. If its an ACK we need to make sure
5791 	 * it makes sense (i.e did we send an earlier data/info),
5792 	 * and if its a NACK then we maybe attempt a retry.
5793 	 */
5794 	switch (dring_pkt->tag.vio_subtype) {
5795 	case VIO_SUBTYPE_INFO:
5796 		D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id);
5797 
5798 		READ_ENTER(&ldcp->lane_in.dlistrw);
5799 		if ((dp = vsw_ident2dring(&ldcp->lane_in,
5800 				dring_pkt->dring_ident)) == NULL) {
5801 			RW_EXIT(&ldcp->lane_in.dlistrw);
5802 
5803 			DERR(vswp, "%s(%lld): unable to find dring from "
5804 				"ident 0x%llx", __func__, ldcp->ldc_id,
5805 				dring_pkt->dring_ident);
5806 
5807 			SND_DRING_NACK(ldcp, dring_pkt);
5808 			return;
5809 		}
5810 
5811 		start = pos = dring_pkt->start_idx;
5812 		end = dring_pkt->end_idx;
5813 		len = dp->num_descriptors;
5814 
5815 		range_start = range_end = pos;
5816 
5817 		D2(vswp, "%s(%lld): start index %ld : end %ld\n",
5818 			__func__, ldcp->ldc_id, start, end);
5819 
5820 		if (end == -1) {
5821 			num = -1;
5822 		} else if (end >= 0) {
5823 			num = end >= pos ?
5824 				end - pos + 1: (len - pos + 1) + end;
5825 
5826 			/* basic sanity check */
5827 			if (end > len) {
5828 				RW_EXIT(&ldcp->lane_in.dlistrw);
5829 				DERR(vswp, "%s(%lld): endpoint %lld outside "
5830 					"ring length %lld", __func__,
5831 					ldcp->ldc_id, end, len);
5832 
5833 				SND_DRING_NACK(ldcp, dring_pkt);
5834 				return;
5835 			}
5836 		} else {
5837 			RW_EXIT(&ldcp->lane_in.dlistrw);
5838 			DERR(vswp, "%s(%lld): invalid endpoint %lld",
5839 				__func__, ldcp->ldc_id, end);
5840 			SND_DRING_NACK(ldcp, dring_pkt);
5841 			return;
5842 		}
5843 
5844 		while (cnt != num) {
5845 vsw_recheck_desc:
5846 			if ((rv = ldc_mem_dring_acquire(dp->handle,
5847 							pos, pos)) != 0) {
5848 				RW_EXIT(&ldcp->lane_in.dlistrw);
5849 				DERR(vswp, "%s(%lld): unable to acquire "
5850 					"descriptor at pos %d: err %d",
5851 					__func__, pos, ldcp->ldc_id, rv);
5852 				SND_DRING_NACK(ldcp, dring_pkt);
5853 				return;
5854 			}
5855 
5856 			pub_addr = (vnet_public_desc_t *)dp->pub_addr + pos;
5857 
5858 			/*
5859 			 * When given a bounded range of descriptors
5860 			 * to process, its an error to hit a descriptor
5861 			 * which is not ready. In the non-bounded case
5862 			 * (end_idx == -1) this simply indicates we have
5863 			 * reached the end of the current active range.
5864 			 */
5865 			if (pub_addr->hdr.dstate != VIO_DESC_READY) {
5866 				/* unbound - no error */
5867 				if (end == -1) {
5868 					if (read_attempts == vsw_read_attempts)
5869 						break;
5870 
5871 					delay(drv_usectohz(vsw_desc_delay));
5872 					read_attempts++;
5873 					goto vsw_recheck_desc;
5874 				}
5875 
5876 				/* bounded - error - so NACK back */
5877 				RW_EXIT(&ldcp->lane_in.dlistrw);
5878 				DERR(vswp, "%s(%lld): descriptor not READY "
5879 					"(%d)", __func__, ldcp->ldc_id,
5880 					pub_addr->hdr.dstate);
5881 				SND_DRING_NACK(ldcp, dring_pkt);
5882 				return;
5883 			}
5884 
5885 			DTRACE_PROBE1(read_attempts, int, read_attempts);
5886 
5887 			range_end = pos;
5888 
5889 			/*
5890 			 * If we ACK'd the previous descriptor then now
5891 			 * record the new range start position for later
5892 			 * ACK's.
5893 			 */
5894 			if (prev_desc_ack) {
5895 				range_start = pos;
5896 
5897 				D2(vswp, "%s(%lld): updating range start "
5898 					"to be %d", __func__, ldcp->ldc_id,
5899 					range_start);
5900 
5901 				prev_desc_ack = B_FALSE;
5902 			}
5903 
5904 			/*
5905 			 * Data is padded to align on 8 byte boundary,
5906 			 * datalen is actual data length, i.e. minus that
5907 			 * padding.
5908 			 */
5909 			datalen = pub_addr->nbytes;
5910 
5911 			/*
5912 			 * Does peer wish us to ACK when we have finished
5913 			 * with this descriptor ?
5914 			 */
5915 			if (pub_addr->hdr.ack)
5916 				ack_needed = B_TRUE;
5917 
5918 			D2(vswp, "%s(%lld): processing desc %lld at pos"
5919 				" 0x%llx : dstate 0x%lx : datalen 0x%lx",
5920 				__func__, ldcp->ldc_id, pos, pub_addr,
5921 				pub_addr->hdr.dstate, datalen);
5922 
5923 			/*
5924 			 * Mark that we are starting to process descriptor.
5925 			 */
5926 			pub_addr->hdr.dstate = VIO_DESC_ACCEPTED;
5927 
5928 			mp = vio_allocb(ldcp->rxh);
5929 			if (mp == NULL) {
5930 				/*
5931 				 * No free receive buffers available, so
5932 				 * fallback onto allocb(9F). Make sure that
5933 				 * we get a data buffer which is a multiple
5934 				 * of 8 as this is required by ldc_mem_copy.
5935 				 */
5936 				DTRACE_PROBE(allocb);
5937 				mp = allocb(datalen + VNET_IPALIGN + 8,
5938 								BPRI_MED);
5939 			}
5940 
5941 			/*
5942 			 * Ensure that we ask ldc for an aligned
5943 			 * number of bytes.
5944 			 */
5945 			nbytes = datalen + VNET_IPALIGN;
5946 			if (nbytes & 0x7) {
5947 				off = 8 - (nbytes & 0x7);
5948 				nbytes += off;
5949 			}
5950 
5951 			ncookies = pub_addr->ncookies;
5952 			rv = ldc_mem_copy(ldcp->ldc_handle,
5953 				(caddr_t)mp->b_rptr, 0, &nbytes,
5954 				pub_addr->memcookie, ncookies,
5955 				LDC_COPY_IN);
5956 
5957 			if (rv != 0) {
5958 				DERR(vswp, "%s(%d): unable to copy in "
5959 					"data from %d cookies in desc %d"
5960 					" (rv %d)", __func__, ldcp->ldc_id,
5961 					ncookies, pos, rv);
5962 				freemsg(mp);
5963 
5964 				pub_addr->hdr.dstate = VIO_DESC_DONE;
5965 				(void) ldc_mem_dring_release(dp->handle,
5966 								pos, pos);
5967 				break;
5968 			} else {
5969 				D2(vswp, "%s(%d): copied in %ld bytes"
5970 					" using %d cookies", __func__,
5971 					ldcp->ldc_id, nbytes, ncookies);
5972 			}
5973 
5974 			/* adjust the read pointer to skip over the padding */
5975 			mp->b_rptr += VNET_IPALIGN;
5976 
5977 			/* point to the actual end of data */
5978 			mp->b_wptr = mp->b_rptr + datalen;
5979 
5980 			/* build a chain of received packets */
5981 			if (bp == NULL) {
5982 				/* first pkt */
5983 				bp = mp;
5984 				bp->b_next = bp->b_prev = NULL;
5985 				bpt = bp;
5986 				chain = 1;
5987 			} else {
5988 				mp->b_next = NULL;
5989 				mp->b_prev = bpt;
5990 				bpt->b_next = mp;
5991 				bpt = mp;
5992 				chain++;
5993 			}
5994 
5995 			/* mark we are finished with this descriptor */
5996 			pub_addr->hdr.dstate = VIO_DESC_DONE;
5997 
5998 			(void) ldc_mem_dring_release(dp->handle, pos, pos);
5999 
6000 			/*
6001 			 * Send an ACK back to peer if requested.
6002 			 */
6003 			if (ack_needed) {
6004 				ack_needed = B_FALSE;
6005 
6006 				dring_pkt->start_idx = range_start;
6007 				dring_pkt->end_idx = range_end;
6008 
6009 				DERR(vswp, "%s(%lld): processed %d %d, ACK"
6010 					" requested", __func__, ldcp->ldc_id,
6011 					dring_pkt->start_idx,
6012 					dring_pkt->end_idx);
6013 
6014 				dring_pkt->dring_process_state = VIO_DP_ACTIVE;
6015 				dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
6016 				dring_pkt->tag.vio_sid = ldcp->local_session;
6017 				msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt,
6018 						sizeof (vio_dring_msg_t),
6019 						B_FALSE);
6020 
6021 				/*
6022 				 * Check if ACK was successfully sent. If not
6023 				 * we break and deal with that below.
6024 				 */
6025 				if (msg_rv != 0)
6026 					break;
6027 
6028 				prev_desc_ack = B_TRUE;
6029 				range_start = pos;
6030 			}
6031 
6032 			/* next descriptor */
6033 			pos = (pos + 1) % len;
6034 			cnt++;
6035 
6036 			/*
6037 			 * Break out of loop here and stop processing to
6038 			 * allow some other network device (or disk) to
6039 			 * get access to the cpu.
6040 			 */
6041 			if (chain > vsw_chain_len) {
6042 				D3(vswp, "%s(%lld): switching chain of %d "
6043 					"msgs", __func__, ldcp->ldc_id, chain);
6044 				break;
6045 			}
6046 		}
6047 		RW_EXIT(&ldcp->lane_in.dlistrw);
6048 
6049 		/*
6050 		 * If when we attempted to send the ACK we found that the
6051 		 * channel had been reset then now handle this. We deal with
6052 		 * it here as we cannot reset the channel while holding the
6053 		 * dlistrw lock, and we don't want to acquire/release it
6054 		 * continuously in the above loop, as a channel reset should
6055 		 * be a rare event.
6056 		 */
6057 		if (msg_rv == ECONNRESET) {
6058 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
6059 			break;
6060 		}
6061 
6062 		/* send the chain of packets to be switched */
6063 		if (bp != NULL) {
6064 			D3(vswp, "%s(%lld): switching chain of %d msgs",
6065 					__func__, ldcp->ldc_id, chain);
6066 			vswp->vsw_switch_frame(vswp, bp, VSW_VNETPORT,
6067 							ldcp->ldc_port, NULL);
6068 		}
6069 
6070 		DTRACE_PROBE1(msg_cnt, int, cnt);
6071 
6072 		/*
6073 		 * We are now finished so ACK back with the state
6074 		 * set to STOPPING so our peer knows we are finished
6075 		 */
6076 		dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
6077 		dring_pkt->tag.vio_sid = ldcp->local_session;
6078 
6079 		dring_pkt->dring_process_state = VIO_DP_STOPPED;
6080 
6081 		DTRACE_PROBE(stop_process_sent);
6082 
6083 		/*
6084 		 * We have not processed any more descriptors beyond
6085 		 * the last one we ACK'd.
6086 		 */
6087 		if (prev_desc_ack)
6088 			range_start = range_end;
6089 
6090 		dring_pkt->start_idx = range_start;
6091 		dring_pkt->end_idx = range_end;
6092 
6093 		D2(vswp, "%s(%lld) processed : %d : %d, now stopping",
6094 			__func__, ldcp->ldc_id, dring_pkt->start_idx,
6095 			dring_pkt->end_idx);
6096 
6097 		(void) vsw_send_msg(ldcp, (void *)dring_pkt,
6098 				sizeof (vio_dring_msg_t), B_TRUE);
6099 		break;
6100 
6101 	case VIO_SUBTYPE_ACK:
6102 		D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id);
6103 		/*
6104 		 * Verify that the relevant descriptors are all
6105 		 * marked as DONE
6106 		 */
6107 		READ_ENTER(&ldcp->lane_out.dlistrw);
6108 		if ((dp = vsw_ident2dring(&ldcp->lane_out,
6109 			dring_pkt->dring_ident)) == NULL) {
6110 			RW_EXIT(&ldcp->lane_out.dlistrw);
6111 			DERR(vswp, "%s: unknown ident in ACK", __func__);
6112 			return;
6113 		}
6114 
6115 		pub_addr = (vnet_public_desc_t *)dp->pub_addr;
6116 		priv_addr = (vsw_private_desc_t *)dp->priv_addr;
6117 
6118 		start = end = 0;
6119 		start = dring_pkt->start_idx;
6120 		end = dring_pkt->end_idx;
6121 		len = dp->num_descriptors;
6122 
6123 		j = num = 0;
6124 		/* calculate # descriptors taking into a/c wrap around */
6125 		num = end >= start ? end - start + 1: (len - start + 1) + end;
6126 
6127 		D2(vswp, "%s(%lld): start index %ld : end %ld : num %ld\n",
6128 			__func__, ldcp->ldc_id, start, end, num);
6129 
6130 		mutex_enter(&dp->dlock);
6131 		dp->last_ack_recv = end;
6132 		mutex_exit(&dp->dlock);
6133 
6134 		for (i = start; j < num; i = (i + 1) % len, j++) {
6135 			pub_addr = (vnet_public_desc_t *)dp->pub_addr + i;
6136 			priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
6137 
6138 			/*
6139 			 * If the last descriptor in a range has the ACK
6140 			 * bit set then we will get two messages from our
6141 			 * peer relating to it. The normal ACK msg and then
6142 			 * a subsequent STOP msg. The first message will have
6143 			 * resulted in the descriptor being reclaimed and
6144 			 * its state set to FREE so when we encounter a non
6145 			 * DONE descriptor we need to check to see if its
6146 			 * because we have just reclaimed it.
6147 			 */
6148 			mutex_enter(&priv_addr->dstate_lock);
6149 			if (pub_addr->hdr.dstate == VIO_DESC_DONE) {
6150 				/* clear all the fields */
6151 				bzero(priv_addr->datap, priv_addr->datalen);
6152 				priv_addr->datalen = 0;
6153 
6154 				pub_addr->hdr.dstate = VIO_DESC_FREE;
6155 				pub_addr->hdr.ack = 0;
6156 
6157 				priv_addr->dstate = VIO_DESC_FREE;
6158 				mutex_exit(&priv_addr->dstate_lock);
6159 
6160 				D3(vswp, "clearing descp %d : pub state "
6161 					"0x%llx : priv state 0x%llx", i,
6162 					pub_addr->hdr.dstate,
6163 					priv_addr->dstate);
6164 
6165 			} else {
6166 				mutex_exit(&priv_addr->dstate_lock);
6167 
6168 				if (dring_pkt->dring_process_state !=
6169 							VIO_DP_STOPPED) {
6170 					DERR(vswp, "%s: descriptor %lld at pos "
6171 						" 0x%llx not DONE (0x%lx)\n",
6172 						__func__, i, pub_addr,
6173 						pub_addr->hdr.dstate);
6174 					RW_EXIT(&ldcp->lane_out.dlistrw);
6175 					return;
6176 				}
6177 			}
6178 		}
6179 
6180 		/*
6181 		 * If our peer is stopping processing descriptors then
6182 		 * we check to make sure it has processed all the descriptors
6183 		 * we have updated. If not then we send it a new message
6184 		 * to prompt it to restart.
6185 		 */
6186 		if (dring_pkt->dring_process_state == VIO_DP_STOPPED) {
6187 			DTRACE_PROBE(stop_process_recv);
6188 			D2(vswp, "%s(%lld): got stopping msg : %d : %d",
6189 				__func__, ldcp->ldc_id, dring_pkt->start_idx,
6190 				dring_pkt->end_idx);
6191 
6192 			/*
6193 			 * Check next descriptor in public section of ring.
6194 			 * If its marked as READY then we need to prompt our
6195 			 * peer to start processing the ring again.
6196 			 */
6197 			i = (end + 1) % len;
6198 			pub_addr = (vnet_public_desc_t *)dp->pub_addr + i;
6199 			priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
6200 
6201 			/*
6202 			 * Hold the restart lock across all of this to
6203 			 * make sure that its not possible for us to
6204 			 * decide that a msg needs to be sent in the future
6205 			 * but the sending code having already checked is
6206 			 * about to exit.
6207 			 */
6208 			mutex_enter(&dp->restart_lock);
6209 			mutex_enter(&priv_addr->dstate_lock);
6210 			if (pub_addr->hdr.dstate == VIO_DESC_READY) {
6211 
6212 				mutex_exit(&priv_addr->dstate_lock);
6213 
6214 				dring_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
6215 				dring_pkt->tag.vio_sid = ldcp->local_session;
6216 
6217 				mutex_enter(&ldcp->lane_out.seq_lock);
6218 				dring_pkt->seq_num = ldcp->lane_out.seq_num++;
6219 				mutex_exit(&ldcp->lane_out.seq_lock);
6220 
6221 				dring_pkt->start_idx = (end + 1) % len;
6222 				dring_pkt->end_idx = -1;
6223 
6224 				D2(vswp, "%s(%lld) : sending restart msg:"
6225 					" %d : %d", __func__, ldcp->ldc_id,
6226 					dring_pkt->start_idx,
6227 					dring_pkt->end_idx);
6228 
6229 				msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt,
6230 					sizeof (vio_dring_msg_t), B_FALSE);
6231 
6232 			} else {
6233 				mutex_exit(&priv_addr->dstate_lock);
6234 				dp->restart_reqd = B_TRUE;
6235 			}
6236 			mutex_exit(&dp->restart_lock);
6237 		}
6238 		RW_EXIT(&ldcp->lane_out.dlistrw);
6239 
6240 		/* only do channel reset after dropping dlistrw lock */
6241 		if (msg_rv == ECONNRESET)
6242 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
6243 
6244 		break;
6245 
6246 	case VIO_SUBTYPE_NACK:
6247 		DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK",
6248 						__func__, ldcp->ldc_id);
6249 		/*
6250 		 * Something is badly wrong if we are getting NACK's
6251 		 * for our data pkts. So reset the channel.
6252 		 */
6253 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
6254 
6255 		break;
6256 
6257 	default:
6258 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
6259 			ldcp->ldc_id, dring_pkt->tag.vio_subtype);
6260 	}
6261 
6262 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
6263 }
6264 
6265 /*
6266  * VIO_PKT_DATA (a.k.a raw data mode )
6267  *
6268  * Note - currently not supported. Do nothing.
6269  */
6270 static void
6271 vsw_process_data_raw_pkt(vsw_ldc_t *ldcp, void *dpkt)
6272 {
6273 	_NOTE(ARGUNUSED(dpkt))
6274 
6275 	D1(NULL, "%s (%lld): enter\n", __func__, ldcp->ldc_id);
6276 
6277 	DERR(NULL, "%s (%lld): currently  not supported",
6278 						__func__, ldcp->ldc_id);
6279 
6280 	D1(NULL, "%s (%lld): exit\n", __func__, ldcp->ldc_id);
6281 }
6282 
6283 /*
6284  * Process an in-band descriptor message (most likely from
6285  * OBP).
6286  */
6287 static void
6288 vsw_process_data_ibnd_pkt(vsw_ldc_t *ldcp, void *pkt)
6289 {
6290 	vnet_ibnd_desc_t	*ibnd_desc;
6291 	dring_info_t		*dp = NULL;
6292 	vsw_private_desc_t	*priv_addr = NULL;
6293 	vsw_t			*vswp = ldcp->ldc_vswp;
6294 	mblk_t			*mp = NULL;
6295 	mblk_t			*nmp;
6296 	size_t			nbytes = 0;
6297 	size_t			off = 0;
6298 	uint64_t		idx = 0;
6299 	uint32_t		num = 1, len, datalen = 0;
6300 	uint64_t		ncookies = 0;
6301 	int			i, rv;
6302 	int			j = 0;
6303 
6304 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
6305 
6306 	ibnd_desc = (vnet_ibnd_desc_t *)pkt;
6307 
6308 	switch (ibnd_desc->hdr.tag.vio_subtype) {
6309 	case VIO_SUBTYPE_INFO:
6310 		D1(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
6311 
6312 		if (vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV))
6313 			return;
6314 
6315 		/*
6316 		 * Data is padded to align on a 8 byte boundary,
6317 		 * nbytes is actual data length, i.e. minus that
6318 		 * padding.
6319 		 */
6320 		datalen = ibnd_desc->nbytes;
6321 
6322 		D2(vswp, "%s(%lld): processing inband desc : "
6323 			": datalen 0x%lx", __func__, ldcp->ldc_id, datalen);
6324 
6325 		ncookies = ibnd_desc->ncookies;
6326 
6327 		/*
6328 		 * allocb(9F) returns an aligned data block. We
6329 		 * need to ensure that we ask ldc for an aligned
6330 		 * number of bytes also.
6331 		 */
6332 		nbytes = datalen;
6333 		if (nbytes & 0x7) {
6334 			off = 8 - (nbytes & 0x7);
6335 			nbytes += off;
6336 		}
6337 
6338 		mp = allocb(datalen, BPRI_MED);
6339 		if (mp == NULL) {
6340 			DERR(vswp, "%s(%lld): allocb failed",
6341 					__func__, ldcp->ldc_id);
6342 			return;
6343 		}
6344 
6345 		rv = ldc_mem_copy(ldcp->ldc_handle, (caddr_t)mp->b_rptr,
6346 			0, &nbytes, ibnd_desc->memcookie, (uint64_t)ncookies,
6347 			LDC_COPY_IN);
6348 
6349 		if (rv != 0) {
6350 			DERR(vswp, "%s(%d): unable to copy in data from "
6351 				"%d cookie(s)", __func__,
6352 				ldcp->ldc_id, ncookies);
6353 			freemsg(mp);
6354 			return;
6355 		}
6356 
6357 		D2(vswp, "%s(%d): copied in %ld bytes using %d "
6358 			"cookies", __func__, ldcp->ldc_id, nbytes,
6359 			ncookies);
6360 
6361 		/*
6362 		 * Upper layer is expecting the IP header in the packet to
6363 		 * be 4-bytes aligned, but the OBP is sending packets that
6364 		 * are not aligned.  So, copy the data to another message
6365 		 * such that the alignment requirement is met.
6366 		 */
6367 		nmp = allocb(datalen + VNET_IPALIGN, BPRI_MED);
6368 		if (nmp == NULL) {
6369 			DERR(vswp, "%s(%lld): allocb failed",
6370 				__func__, ldcp->ldc_id);
6371 			freemsg(mp);
6372 			return;
6373 		}
6374 		nmp->b_rptr += VNET_IPALIGN;
6375 		bcopy(mp->b_rptr, nmp->b_rptr, datalen);
6376 		freemsg(mp);
6377 
6378 		/* point to the actual end of data */
6379 		nmp->b_wptr = nmp->b_rptr + datalen;
6380 
6381 		/*
6382 		 * We ACK back every in-band descriptor message we process
6383 		 */
6384 		ibnd_desc->hdr.tag.vio_subtype = VIO_SUBTYPE_ACK;
6385 		ibnd_desc->hdr.tag.vio_sid = ldcp->local_session;
6386 		(void) vsw_send_msg(ldcp, (void *)ibnd_desc,
6387 				sizeof (vnet_ibnd_desc_t), B_TRUE);
6388 
6389 		/* send the packet to be switched */
6390 		vswp->vsw_switch_frame(vswp, nmp, VSW_VNETPORT,
6391 					ldcp->ldc_port, NULL);
6392 
6393 		break;
6394 
6395 	case VIO_SUBTYPE_ACK:
6396 		D1(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
6397 
6398 		/* Verify the ACK is valid */
6399 		idx = ibnd_desc->hdr.desc_handle;
6400 
6401 		if (idx >= VSW_RING_NUM_EL) {
6402 			cmn_err(CE_WARN, "!vsw%d: corrupted ACK received "
6403 				"(idx %ld)", vswp->instance, idx);
6404 			return;
6405 		}
6406 
6407 		if ((dp = ldcp->lane_out.dringp) == NULL) {
6408 			DERR(vswp, "%s: no dring found", __func__);
6409 			return;
6410 		}
6411 
6412 		len = dp->num_descriptors;
6413 		/*
6414 		 * If the descriptor we are being ACK'ed for is not the
6415 		 * one we expected, then pkts were lost somwhere, either
6416 		 * when we tried to send a msg, or a previous ACK msg from
6417 		 * our peer. In either case we now reclaim the descriptors
6418 		 * in the range from the last ACK we received up to the
6419 		 * current ACK.
6420 		 */
6421 		if (idx != dp->last_ack_recv) {
6422 			DWARN(vswp, "%s: dropped pkts detected, (%ld, %ld)",
6423 				__func__, dp->last_ack_recv, idx);
6424 			num = idx >= dp->last_ack_recv ?
6425 				idx - dp->last_ack_recv + 1:
6426 				(len - dp->last_ack_recv + 1) + idx;
6427 		}
6428 
6429 		/*
6430 		 * When we sent the in-band message to our peer we
6431 		 * marked the copy in our private ring as READY. We now
6432 		 * check that the descriptor we are being ACK'ed for is in
6433 		 * fact READY, i.e. it is one we have shared with our peer.
6434 		 *
6435 		 * If its not we flag an error, but still reset the descr
6436 		 * back to FREE.
6437 		 */
6438 		for (i = dp->last_ack_recv; j < num; i = (i + 1) % len, j++) {
6439 			priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
6440 			mutex_enter(&priv_addr->dstate_lock);
6441 			if (priv_addr->dstate != VIO_DESC_READY) {
6442 				DERR(vswp, "%s: (%ld) desc at index %ld not "
6443 					"READY (0x%lx)", __func__,
6444 					ldcp->ldc_id, idx, priv_addr->dstate);
6445 				DERR(vswp, "%s: bound %d: ncookies %ld : "
6446 					"datalen %ld", __func__,
6447 					priv_addr->bound, priv_addr->ncookies,
6448 					priv_addr->datalen);
6449 			}
6450 			D2(vswp, "%s: (%lld) freeing descp at %lld", __func__,
6451 				ldcp->ldc_id, idx);
6452 			/* release resources associated with sent msg */
6453 			bzero(priv_addr->datap, priv_addr->datalen);
6454 			priv_addr->datalen = 0;
6455 			priv_addr->dstate = VIO_DESC_FREE;
6456 			mutex_exit(&priv_addr->dstate_lock);
6457 		}
6458 		/* update to next expected value */
6459 		dp->last_ack_recv = (idx + 1) % dp->num_descriptors;
6460 
6461 		break;
6462 
6463 	case VIO_SUBTYPE_NACK:
6464 		DERR(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
6465 
6466 		/*
6467 		 * We should only get a NACK if our peer doesn't like
6468 		 * something about a message we have sent it. If this
6469 		 * happens we just release the resources associated with
6470 		 * the message. (We are relying on higher layers to decide
6471 		 * whether or not to resend.
6472 		 */
6473 
6474 		/* limit check */
6475 		idx = ibnd_desc->hdr.desc_handle;
6476 
6477 		if (idx >= VSW_RING_NUM_EL) {
6478 			DERR(vswp, "%s: corrupted NACK received (idx %lld)",
6479 				__func__, idx);
6480 			return;
6481 		}
6482 
6483 		if ((dp = ldcp->lane_out.dringp) == NULL) {
6484 			DERR(vswp, "%s: no dring found", __func__);
6485 			return;
6486 		}
6487 
6488 		priv_addr = (vsw_private_desc_t *)dp->priv_addr;
6489 
6490 		/* move to correct location in ring */
6491 		priv_addr += idx;
6492 
6493 		/* release resources associated with sent msg */
6494 		mutex_enter(&priv_addr->dstate_lock);
6495 		bzero(priv_addr->datap, priv_addr->datalen);
6496 		priv_addr->datalen = 0;
6497 		priv_addr->dstate = VIO_DESC_FREE;
6498 		mutex_exit(&priv_addr->dstate_lock);
6499 
6500 		break;
6501 
6502 	default:
6503 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
6504 			ldcp->ldc_id, ibnd_desc->hdr.tag.vio_subtype);
6505 	}
6506 
6507 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
6508 }
6509 
6510 static void
6511 vsw_process_err_pkt(vsw_ldc_t *ldcp, void *epkt, vio_msg_tag_t tag)
6512 {
6513 	_NOTE(ARGUNUSED(epkt))
6514 
6515 	vsw_t		*vswp = ldcp->ldc_vswp;
6516 	uint16_t	env = tag.vio_subtype_env;
6517 
6518 	D1(vswp, "%s (%lld): enter\n", __func__, ldcp->ldc_id);
6519 
6520 	/*
6521 	 * Error vio_subtypes have yet to be defined. So for
6522 	 * the moment we can't do anything.
6523 	 */
6524 	D2(vswp, "%s: (%x) vio_subtype env", __func__, env);
6525 
6526 	D1(vswp, "%s (%lld): exit\n", __func__, ldcp->ldc_id);
6527 }
6528 
6529 /*
6530  * Switch the given ethernet frame when operating in layer 2 mode.
6531  *
6532  * vswp: pointer to the vsw instance
6533  * mp: pointer to chain of ethernet frame(s) to be switched
6534  * caller: identifies the source of this frame as:
6535  * 		1. VSW_VNETPORT - a vsw port (connected to a vnet).
6536  *		2. VSW_PHYSDEV - the physical ethernet device
6537  *		3. VSW_LOCALDEV - vsw configured as a virtual interface
6538  * arg: argument provided by the caller.
6539  *		1. for VNETPORT - pointer to the corresponding vsw_port_t.
6540  *		2. for PHYSDEV - NULL
6541  *		3. for LOCALDEV - pointer to to this vsw_t(self)
6542  */
6543 void
6544 vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller,
6545 			vsw_port_t *arg, mac_resource_handle_t mrh)
6546 {
6547 	struct ether_header	*ehp;
6548 	vsw_port_t		*port = NULL;
6549 	mblk_t			*bp, *ret_m;
6550 	mblk_t			*nmp = NULL;
6551 	vsw_port_list_t		*plist = &vswp->plist;
6552 
6553 	D1(vswp, "%s: enter (caller %d)", __func__, caller);
6554 
6555 	/*
6556 	 * PERF: rather than breaking up the chain here, scan it
6557 	 * to find all mblks heading to same destination and then
6558 	 * pass that sub-chain to the lower transmit functions.
6559 	 */
6560 
6561 	/* process the chain of packets */
6562 	bp = mp;
6563 	while (bp) {
6564 		mp = bp;
6565 		bp = bp->b_next;
6566 		mp->b_next = mp->b_prev = NULL;
6567 		ehp = (struct ether_header *)mp->b_rptr;
6568 
6569 		D2(vswp, "%s: mblk data buffer %lld : actual data size %lld",
6570 			__func__, MBLKSIZE(mp), MBLKL(mp));
6571 
6572 		READ_ENTER(&vswp->if_lockrw);
6573 		if (ether_cmp(&ehp->ether_dhost, &vswp->if_addr) == 0) {
6574 			/*
6575 			 * If destination is VSW_LOCALDEV (vsw as an eth
6576 			 * interface) and if the device is up & running,
6577 			 * send the packet up the stack on this host.
6578 			 * If the virtual interface is down, drop the packet.
6579 			 */
6580 			if (caller != VSW_LOCALDEV) {
6581 				if (vswp->if_state & VSW_IF_UP) {
6582 					RW_EXIT(&vswp->if_lockrw);
6583 					mac_rx(vswp->if_mh, mrh, mp);
6584 				} else {
6585 					RW_EXIT(&vswp->if_lockrw);
6586 					/* Interface down, drop pkt */
6587 					freemsg(mp);
6588 				}
6589 			} else {
6590 				RW_EXIT(&vswp->if_lockrw);
6591 				freemsg(mp);
6592 			}
6593 			continue;
6594 		}
6595 		RW_EXIT(&vswp->if_lockrw);
6596 
6597 		READ_ENTER(&plist->lockrw);
6598 		port = vsw_lookup_fdb(vswp, ehp);
6599 		if (port) {
6600 			/*
6601 			 * Mark the port as in-use.
6602 			 */
6603 			mutex_enter(&port->ref_lock);
6604 			port->ref_cnt++;
6605 			mutex_exit(&port->ref_lock);
6606 			RW_EXIT(&plist->lockrw);
6607 
6608 			/*
6609 			 * If plumbed and in promisc mode then copy msg
6610 			 * and send up the stack.
6611 			 */
6612 			READ_ENTER(&vswp->if_lockrw);
6613 			if (VSW_U_P(vswp->if_state)) {
6614 				RW_EXIT(&vswp->if_lockrw);
6615 				nmp = copymsg(mp);
6616 				if (nmp)
6617 					mac_rx(vswp->if_mh, mrh, nmp);
6618 			} else {
6619 				RW_EXIT(&vswp->if_lockrw);
6620 			}
6621 
6622 			/*
6623 			 * If the destination is in FDB, the packet
6624 			 * should be forwarded to the correponding
6625 			 * vsw_port (connected to a vnet device -
6626 			 * VSW_VNETPORT)
6627 			 */
6628 			(void) vsw_portsend(port, mp);
6629 
6630 			/*
6631 			 * Decrement use count in port and check if
6632 			 * should wake delete thread.
6633 			 */
6634 			mutex_enter(&port->ref_lock);
6635 			port->ref_cnt--;
6636 			if (port->ref_cnt == 0)
6637 				cv_signal(&port->ref_cv);
6638 			mutex_exit(&port->ref_lock);
6639 		} else {
6640 			RW_EXIT(&plist->lockrw);
6641 			/*
6642 			 * Destination not in FDB.
6643 			 *
6644 			 * If the destination is broadcast or
6645 			 * multicast forward the packet to all
6646 			 * (VNETPORTs, PHYSDEV, LOCALDEV),
6647 			 * except the caller.
6648 			 */
6649 			if (IS_BROADCAST(ehp)) {
6650 				D3(vswp, "%s: BROADCAST pkt", __func__);
6651 				(void) vsw_forward_all(vswp, mp,
6652 								caller, arg);
6653 			} else if (IS_MULTICAST(ehp)) {
6654 				D3(vswp, "%s: MULTICAST pkt", __func__);
6655 				(void) vsw_forward_grp(vswp, mp,
6656 							caller, arg);
6657 			} else {
6658 				/*
6659 				 * If the destination is unicast, and came
6660 				 * from either a logical network device or
6661 				 * the switch itself when it is plumbed, then
6662 				 * send it out on the physical device and also
6663 				 * up the stack if the logical interface is
6664 				 * in promiscious mode.
6665 				 *
6666 				 * NOTE:  The assumption here is that if we
6667 				 * cannot find the destination in our fdb, its
6668 				 * a unicast address, and came from either a
6669 				 * vnet or down the stack (when plumbed) it
6670 				 * must be destinded for an ethernet device
6671 				 * outside our ldoms.
6672 				 */
6673 				if (caller == VSW_VNETPORT) {
6674 					READ_ENTER(&vswp->if_lockrw);
6675 					if (VSW_U_P(vswp->if_state)) {
6676 						RW_EXIT(&vswp->if_lockrw);
6677 						nmp = copymsg(mp);
6678 						if (nmp)
6679 							mac_rx(vswp->if_mh,
6680 								mrh, nmp);
6681 					} else {
6682 						RW_EXIT(&vswp->if_lockrw);
6683 					}
6684 					if ((ret_m = vsw_tx_msg(vswp, mp))
6685 								!= NULL) {
6686 						DERR(vswp, "%s: drop mblks to "
6687 							"phys dev", __func__);
6688 						freemsg(ret_m);
6689 					}
6690 
6691 				} else if (caller == VSW_PHYSDEV) {
6692 					/*
6693 					 * Pkt seen because card in promisc
6694 					 * mode. Send up stack if plumbed in
6695 					 * promisc mode, else drop it.
6696 					 */
6697 					READ_ENTER(&vswp->if_lockrw);
6698 					if (VSW_U_P(vswp->if_state)) {
6699 						RW_EXIT(&vswp->if_lockrw);
6700 						mac_rx(vswp->if_mh, mrh, mp);
6701 					} else {
6702 						RW_EXIT(&vswp->if_lockrw);
6703 						freemsg(mp);
6704 					}
6705 
6706 				} else if (caller == VSW_LOCALDEV) {
6707 					/*
6708 					 * Pkt came down the stack, send out
6709 					 * over physical device.
6710 					 */
6711 					if ((ret_m = vsw_tx_msg(vswp, mp))
6712 								!= NULL) {
6713 						DERR(vswp, "%s: drop mblks to "
6714 							"phys dev", __func__);
6715 						freemsg(ret_m);
6716 					}
6717 				}
6718 			}
6719 		}
6720 	}
6721 	D1(vswp, "%s: exit\n", __func__);
6722 }
6723 
6724 /*
6725  * Switch ethernet frame when in layer 3 mode (i.e. using IP
6726  * layer to do the routing).
6727  *
6728  * There is a large amount of overlap between this function and
6729  * vsw_switch_l2_frame. At some stage we need to revisit and refactor
6730  * both these functions.
6731  */
6732 void
6733 vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller,
6734 			vsw_port_t *arg, mac_resource_handle_t mrh)
6735 {
6736 	struct ether_header	*ehp;
6737 	vsw_port_t		*port = NULL;
6738 	mblk_t			*bp = NULL;
6739 	vsw_port_list_t		*plist = &vswp->plist;
6740 
6741 	D1(vswp, "%s: enter (caller %d)", __func__, caller);
6742 
6743 	/*
6744 	 * In layer 3 mode should only ever be switching packets
6745 	 * between IP layer and vnet devices. So make sure thats
6746 	 * who is invoking us.
6747 	 */
6748 	if ((caller != VSW_LOCALDEV) && (caller != VSW_VNETPORT)) {
6749 		DERR(vswp, "%s: unexpected caller (%d)", __func__, caller);
6750 		freemsgchain(mp);
6751 		return;
6752 	}
6753 
6754 	/* process the chain of packets */
6755 	bp = mp;
6756 	while (bp) {
6757 		mp = bp;
6758 		bp = bp->b_next;
6759 		mp->b_next = mp->b_prev = NULL;
6760 		ehp = (struct ether_header *)mp->b_rptr;
6761 
6762 		D2(vswp, "%s: mblk data buffer %lld : actual data size %lld",
6763 			__func__, MBLKSIZE(mp), MBLKL(mp));
6764 
6765 		READ_ENTER(&plist->lockrw);
6766 		port = vsw_lookup_fdb(vswp, ehp);
6767 		if (port) {
6768 			/*
6769 			 * Mark port as in-use.
6770 			 */
6771 			mutex_enter(&port->ref_lock);
6772 			port->ref_cnt++;
6773 			mutex_exit(&port->ref_lock);
6774 			RW_EXIT(&plist->lockrw);
6775 
6776 			D2(vswp, "%s: sending to target port", __func__);
6777 			(void) vsw_portsend(port, mp);
6778 
6779 			/*
6780 			 * Finished with port so decrement ref count and
6781 			 * check if should wake delete thread.
6782 			 */
6783 			mutex_enter(&port->ref_lock);
6784 			port->ref_cnt--;
6785 			if (port->ref_cnt == 0)
6786 				cv_signal(&port->ref_cv);
6787 			mutex_exit(&port->ref_lock);
6788 		} else {
6789 			RW_EXIT(&plist->lockrw);
6790 			/*
6791 			 * Destination not in FDB
6792 			 *
6793 			 * If the destination is broadcast or
6794 			 * multicast forward the packet to all
6795 			 * (VNETPORTs, PHYSDEV, LOCALDEV),
6796 			 * except the caller.
6797 			 */
6798 			if (IS_BROADCAST(ehp)) {
6799 				D2(vswp, "%s: BROADCAST pkt", __func__);
6800 				(void) vsw_forward_all(vswp, mp,
6801 								caller, arg);
6802 			} else if (IS_MULTICAST(ehp)) {
6803 				D2(vswp, "%s: MULTICAST pkt", __func__);
6804 				(void) vsw_forward_grp(vswp, mp,
6805 							caller, arg);
6806 			} else {
6807 				/*
6808 				 * Unicast pkt from vnet that we don't have
6809 				 * an FDB entry for, so must be destinded for
6810 				 * the outside world. Attempt to send up to the
6811 				 * IP layer to allow it to deal with it.
6812 				 */
6813 				if (caller == VSW_VNETPORT) {
6814 					READ_ENTER(&vswp->if_lockrw);
6815 					if (vswp->if_state & VSW_IF_UP) {
6816 						RW_EXIT(&vswp->if_lockrw);
6817 						D2(vswp, "%s: sending up",
6818 							__func__);
6819 						mac_rx(vswp->if_mh, mrh, mp);
6820 					} else {
6821 						RW_EXIT(&vswp->if_lockrw);
6822 						/* Interface down, drop pkt */
6823 						D2(vswp, "%s I/F down",
6824 								__func__);
6825 						freemsg(mp);
6826 					}
6827 				}
6828 			}
6829 		}
6830 	}
6831 
6832 	D1(vswp, "%s: exit", __func__);
6833 }
6834 
6835 /*
6836  * Forward the ethernet frame to all ports (VNETPORTs, PHYSDEV, LOCALDEV),
6837  * except the caller (port on which frame arrived).
6838  */
6839 static int
6840 vsw_forward_all(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg)
6841 {
6842 	vsw_port_list_t	*plist = &vswp->plist;
6843 	vsw_port_t	*portp;
6844 	mblk_t		*nmp = NULL;
6845 	mblk_t		*ret_m = NULL;
6846 	int		skip_port = 0;
6847 
6848 	D1(vswp, "vsw_forward_all: enter\n");
6849 
6850 	/*
6851 	 * Broadcast message from inside ldoms so send to outside
6852 	 * world if in either of layer 2 modes.
6853 	 */
6854 	if (((vswp->smode[vswp->smode_idx] == VSW_LAYER2) ||
6855 		(vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC)) &&
6856 		((caller == VSW_LOCALDEV) || (caller == VSW_VNETPORT))) {
6857 
6858 		nmp = dupmsg(mp);
6859 		if (nmp) {
6860 			if ((ret_m = vsw_tx_msg(vswp, nmp)) != NULL) {
6861 				DERR(vswp, "%s: dropping pkt(s) "
6862 				"consisting of %ld bytes of data for"
6863 				" physical device", __func__, MBLKL(ret_m));
6864 			freemsg(ret_m);
6865 			}
6866 		}
6867 	}
6868 
6869 	if (caller == VSW_VNETPORT)
6870 		skip_port = 1;
6871 
6872 	/*
6873 	 * Broadcast message from other vnet (layer 2 or 3) or outside
6874 	 * world (layer 2 only), send up stack if plumbed.
6875 	 */
6876 	if ((caller == VSW_PHYSDEV) || (caller == VSW_VNETPORT)) {
6877 		READ_ENTER(&vswp->if_lockrw);
6878 		if (vswp->if_state & VSW_IF_UP) {
6879 			RW_EXIT(&vswp->if_lockrw);
6880 			nmp = copymsg(mp);
6881 			if (nmp)
6882 				mac_rx(vswp->if_mh, NULL, nmp);
6883 		} else {
6884 			RW_EXIT(&vswp->if_lockrw);
6885 		}
6886 	}
6887 
6888 	/* send it to all VNETPORTs */
6889 	READ_ENTER(&plist->lockrw);
6890 	for (portp = plist->head; portp != NULL; portp = portp->p_next) {
6891 		D2(vswp, "vsw_forward_all: port %d", portp->p_instance);
6892 		/*
6893 		 * Caution ! - don't reorder these two checks as arg
6894 		 * will be NULL if the caller is PHYSDEV. skip_port is
6895 		 * only set if caller is VNETPORT.
6896 		 */
6897 		if ((skip_port) && (portp == arg))
6898 			continue;
6899 		else {
6900 			nmp = dupmsg(mp);
6901 			if (nmp) {
6902 				(void) vsw_portsend(portp, nmp);
6903 			} else {
6904 				DERR(vswp, "vsw_forward_all: nmp NULL");
6905 			}
6906 		}
6907 	}
6908 	RW_EXIT(&plist->lockrw);
6909 
6910 	freemsg(mp);
6911 
6912 	D1(vswp, "vsw_forward_all: exit\n");
6913 	return (0);
6914 }
6915 
6916 /*
6917  * Forward pkts to any devices or interfaces which have registered
6918  * an interest in them (i.e. multicast groups).
6919  */
6920 static int
6921 vsw_forward_grp(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg)
6922 {
6923 	struct ether_header	*ehp = (struct ether_header *)mp->b_rptr;
6924 	mfdb_ent_t		*entp = NULL;
6925 	mfdb_ent_t		*tpp = NULL;
6926 	vsw_port_t 		*port;
6927 	uint64_t		key = 0;
6928 	mblk_t			*nmp = NULL;
6929 	mblk_t			*ret_m = NULL;
6930 	boolean_t		check_if = B_TRUE;
6931 
6932 	/*
6933 	 * Convert address to hash table key
6934 	 */
6935 	KEY_HASH(key, ehp->ether_dhost);
6936 
6937 	D1(vswp, "%s: key 0x%llx", __func__, key);
6938 
6939 	/*
6940 	 * If pkt came from either a vnet or down the stack (if we are
6941 	 * plumbed) and we are in layer 2 mode, then we send the pkt out
6942 	 * over the physical adapter, and then check to see if any other
6943 	 * vnets are interested in it.
6944 	 */
6945 	if (((vswp->smode[vswp->smode_idx] == VSW_LAYER2) ||
6946 		(vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC)) &&
6947 		((caller == VSW_VNETPORT) || (caller == VSW_LOCALDEV))) {
6948 		nmp = dupmsg(mp);
6949 		if (nmp) {
6950 			if ((ret_m = vsw_tx_msg(vswp, nmp)) != NULL) {
6951 				DERR(vswp, "%s: dropping pkt(s) "
6952 					"consisting of %ld bytes of "
6953 					"data for physical device",
6954 					__func__, MBLKL(ret_m));
6955 				freemsg(ret_m);
6956 			}
6957 		}
6958 	}
6959 
6960 	READ_ENTER(&vswp->mfdbrw);
6961 	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)key,
6962 				(mod_hash_val_t *)&entp) != 0) {
6963 		D3(vswp, "%s: no table entry found for addr 0x%llx",
6964 								__func__, key);
6965 	} else {
6966 		/*
6967 		 * Send to list of devices associated with this address...
6968 		 */
6969 		for (tpp = entp; tpp != NULL; tpp = tpp->nextp) {
6970 
6971 			/* dont send to ourselves */
6972 			if ((caller == VSW_VNETPORT) &&
6973 				(tpp->d_addr == (void *)arg)) {
6974 				port = (vsw_port_t *)tpp->d_addr;
6975 				D3(vswp, "%s: not sending to ourselves"
6976 					" : port %d", __func__,
6977 					port->p_instance);
6978 				continue;
6979 
6980 			} else if ((caller == VSW_LOCALDEV) &&
6981 				(tpp->d_type == VSW_LOCALDEV)) {
6982 				D3(vswp, "%s: not sending back up stack",
6983 					__func__);
6984 				continue;
6985 			}
6986 
6987 			if (tpp->d_type == VSW_VNETPORT) {
6988 				port = (vsw_port_t *)tpp->d_addr;
6989 				D3(vswp, "%s: sending to port %ld for "
6990 					" addr 0x%llx", __func__,
6991 					port->p_instance, key);
6992 
6993 				nmp = dupmsg(mp);
6994 				if (nmp)
6995 					(void) vsw_portsend(port, nmp);
6996 			} else {
6997 				if (vswp->if_state & VSW_IF_UP) {
6998 					nmp = copymsg(mp);
6999 					if (nmp)
7000 						mac_rx(vswp->if_mh, NULL, nmp);
7001 					check_if = B_FALSE;
7002 					D3(vswp, "%s: sending up stack"
7003 						" for addr 0x%llx", __func__,
7004 						key);
7005 				}
7006 			}
7007 		}
7008 	}
7009 
7010 	RW_EXIT(&vswp->mfdbrw);
7011 
7012 	/*
7013 	 * If the pkt came from either a vnet or from physical device,
7014 	 * and if we havent already sent the pkt up the stack then we
7015 	 * check now if we can/should (i.e. the interface is plumbed
7016 	 * and in promisc mode).
7017 	 */
7018 	if ((check_if) &&
7019 		((caller == VSW_VNETPORT) || (caller == VSW_PHYSDEV))) {
7020 		READ_ENTER(&vswp->if_lockrw);
7021 		if (VSW_U_P(vswp->if_state)) {
7022 			RW_EXIT(&vswp->if_lockrw);
7023 			D3(vswp, "%s: (caller %d) finally sending up stack"
7024 				" for addr 0x%llx", __func__, caller, key);
7025 			nmp = copymsg(mp);
7026 			if (nmp)
7027 				mac_rx(vswp->if_mh, NULL, nmp);
7028 		} else {
7029 			RW_EXIT(&vswp->if_lockrw);
7030 		}
7031 	}
7032 
7033 	freemsg(mp);
7034 
7035 	D1(vswp, "%s: exit", __func__);
7036 
7037 	return (0);
7038 }
7039 
7040 /* transmit the packet over the given port */
7041 static int
7042 vsw_portsend(vsw_port_t *port, mblk_t *mp)
7043 {
7044 	vsw_ldc_list_t 	*ldcl = &port->p_ldclist;
7045 	vsw_ldc_t 	*ldcp;
7046 	int		status = 0;
7047 
7048 
7049 	READ_ENTER(&ldcl->lockrw);
7050 	/*
7051 	 * Note for now, we have a single channel.
7052 	 */
7053 	ldcp = ldcl->head;
7054 	if (ldcp == NULL) {
7055 		DERR(port->p_vswp, "vsw_portsend: no ldc: dropping packet\n");
7056 		freemsg(mp);
7057 		RW_EXIT(&ldcl->lockrw);
7058 		return (1);
7059 	}
7060 
7061 	/*
7062 	 * Send the message out using the appropriate
7063 	 * transmit function which will free mblock when it
7064 	 * is finished with it.
7065 	 */
7066 	mutex_enter(&port->tx_lock);
7067 	if (port->transmit != NULL)
7068 		status = (*port->transmit)(ldcp, mp);
7069 	else {
7070 		freemsg(mp);
7071 	}
7072 	mutex_exit(&port->tx_lock);
7073 
7074 	RW_EXIT(&ldcl->lockrw);
7075 
7076 	return (status);
7077 }
7078 
7079 /*
7080  * Send packet out via descriptor ring to a logical device.
7081  */
7082 static int
7083 vsw_dringsend(vsw_ldc_t *ldcp, mblk_t *mp)
7084 {
7085 	vio_dring_msg_t		dring_pkt;
7086 	dring_info_t		*dp = NULL;
7087 	vsw_private_desc_t	*priv_desc = NULL;
7088 	vnet_public_desc_t	*pub = NULL;
7089 	vsw_t			*vswp = ldcp->ldc_vswp;
7090 	mblk_t			*bp;
7091 	size_t			n, size;
7092 	caddr_t			bufp;
7093 	int			idx;
7094 	int			status = LDC_TX_SUCCESS;
7095 
7096 	D1(vswp, "%s(%lld): enter\n", __func__, ldcp->ldc_id);
7097 
7098 	/* TODO: make test a macro */
7099 	if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
7100 		(ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
7101 		DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
7102 			"packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
7103 			ldcp->lane_out.lstate);
7104 		freemsg(mp);
7105 		return (LDC_TX_FAILURE);
7106 	}
7107 
7108 	/*
7109 	 * Note - using first ring only, this may change
7110 	 * in the future.
7111 	 */
7112 	READ_ENTER(&ldcp->lane_out.dlistrw);
7113 	if ((dp = ldcp->lane_out.dringp) == NULL) {
7114 		RW_EXIT(&ldcp->lane_out.dlistrw);
7115 		DERR(vswp, "%s(%lld): no dring for outbound lane on"
7116 			" channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id);
7117 		freemsg(mp);
7118 		return (LDC_TX_FAILURE);
7119 	}
7120 
7121 	size = msgsize(mp);
7122 	if (size > (size_t)ETHERMAX) {
7123 		RW_EXIT(&ldcp->lane_out.dlistrw);
7124 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
7125 		    ldcp->ldc_id, size);
7126 		freemsg(mp);
7127 		return (LDC_TX_FAILURE);
7128 	}
7129 
7130 	/*
7131 	 * Find a free descriptor
7132 	 *
7133 	 * Note: for the moment we are assuming that we will only
7134 	 * have one dring going from the switch to each of its
7135 	 * peers. This may change in the future.
7136 	 */
7137 	if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) {
7138 		D2(vswp, "%s(%lld): no descriptor available for ring "
7139 			"at 0x%llx", __func__, ldcp->ldc_id, dp);
7140 
7141 		/* nothing more we can do */
7142 		status = LDC_TX_NORESOURCES;
7143 		goto vsw_dringsend_free_exit;
7144 	} else {
7145 		D2(vswp, "%s(%lld): free private descriptor found at pos "
7146 			"%ld addr 0x%llx\n", __func__, ldcp->ldc_id, idx,
7147 			priv_desc);
7148 	}
7149 
7150 	/* copy data into the descriptor */
7151 	bufp = priv_desc->datap;
7152 	bufp += VNET_IPALIGN;
7153 	for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) {
7154 		n = MBLKL(bp);
7155 		bcopy(bp->b_rptr, bufp, n);
7156 		bufp += n;
7157 	}
7158 
7159 	priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size;
7160 
7161 	pub = priv_desc->descp;
7162 	pub->nbytes = priv_desc->datalen;
7163 
7164 	mutex_enter(&priv_desc->dstate_lock);
7165 	pub->hdr.dstate = VIO_DESC_READY;
7166 	mutex_exit(&priv_desc->dstate_lock);
7167 
7168 	/*
7169 	 * Determine whether or not we need to send a message to our
7170 	 * peer prompting them to read our newly updated descriptor(s).
7171 	 */
7172 	mutex_enter(&dp->restart_lock);
7173 	if (dp->restart_reqd) {
7174 		dp->restart_reqd = B_FALSE;
7175 		mutex_exit(&dp->restart_lock);
7176 
7177 		/*
7178 		 * Send a vio_dring_msg to peer to prompt them to read
7179 		 * the updated descriptor ring.
7180 		 */
7181 		dring_pkt.tag.vio_msgtype = VIO_TYPE_DATA;
7182 		dring_pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
7183 		dring_pkt.tag.vio_subtype_env = VIO_DRING_DATA;
7184 		dring_pkt.tag.vio_sid = ldcp->local_session;
7185 
7186 		/* Note - for now using first ring */
7187 		dring_pkt.dring_ident = dp->ident;
7188 
7189 		mutex_enter(&ldcp->lane_out.seq_lock);
7190 		dring_pkt.seq_num = ldcp->lane_out.seq_num++;
7191 		mutex_exit(&ldcp->lane_out.seq_lock);
7192 
7193 		/*
7194 		 * If last_ack_recv is -1 then we know we've not
7195 		 * received any ack's yet, so this must be the first
7196 		 * msg sent, so set the start to the begining of the ring.
7197 		 */
7198 		mutex_enter(&dp->dlock);
7199 		if (dp->last_ack_recv == -1) {
7200 			dring_pkt.start_idx = 0;
7201 		} else {
7202 			dring_pkt.start_idx = (dp->last_ack_recv + 1) %
7203 						dp->num_descriptors;
7204 		}
7205 		dring_pkt.end_idx = -1;
7206 		mutex_exit(&dp->dlock);
7207 
7208 		D3(vswp, "%s(%lld): dring 0x%llx : ident 0x%llx\n", __func__,
7209 			ldcp->ldc_id, dp, dring_pkt.dring_ident);
7210 		D3(vswp, "%s(%lld): start %lld : end %lld : seq %lld\n",
7211 			__func__, ldcp->ldc_id, dring_pkt.start_idx,
7212 			dring_pkt.end_idx, dring_pkt.seq_num);
7213 
7214 		RW_EXIT(&ldcp->lane_out.dlistrw);
7215 
7216 		(void) vsw_send_msg(ldcp, (void *)&dring_pkt,
7217 					sizeof (vio_dring_msg_t), B_TRUE);
7218 
7219 		/* free the message block */
7220 		freemsg(mp);
7221 		return (status);
7222 
7223 	} else {
7224 		mutex_exit(&dp->restart_lock);
7225 		D2(vswp, "%s(%lld): updating descp %d", __func__,
7226 			ldcp->ldc_id, idx);
7227 	}
7228 
7229 vsw_dringsend_free_exit:
7230 
7231 	RW_EXIT(&ldcp->lane_out.dlistrw);
7232 
7233 	/* free the message block */
7234 	freemsg(mp);
7235 
7236 	D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id);
7237 	return (status);
7238 }
7239 
7240 /*
7241  * Send an in-band descriptor message over ldc.
7242  */
7243 static int
7244 vsw_descrsend(vsw_ldc_t *ldcp, mblk_t *mp)
7245 {
7246 	vsw_t			*vswp = ldcp->ldc_vswp;
7247 	vnet_ibnd_desc_t	ibnd_msg;
7248 	vsw_private_desc_t	*priv_desc = NULL;
7249 	dring_info_t		*dp = NULL;
7250 	size_t			n, size = 0;
7251 	caddr_t			bufp;
7252 	mblk_t			*bp;
7253 	int			idx, i;
7254 	int			status = LDC_TX_SUCCESS;
7255 	static int		warn_msg = 1;
7256 
7257 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
7258 
7259 	ASSERT(mp != NULL);
7260 
7261 	if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
7262 		(ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
7263 		DERR(vswp, "%s(%lld) status(%d) state (0x%llx), dropping pkt",
7264 			__func__, ldcp->ldc_id, ldcp->ldc_status,
7265 			ldcp->lane_out.lstate);
7266 		freemsg(mp);
7267 		return (LDC_TX_FAILURE);
7268 	}
7269 
7270 	/*
7271 	 * only expect single dring to exist, which we use
7272 	 * as an internal buffer, rather than a transfer channel.
7273 	 */
7274 	READ_ENTER(&ldcp->lane_out.dlistrw);
7275 	if ((dp = ldcp->lane_out.dringp) == NULL) {
7276 		DERR(vswp, "%s(%lld): no dring for outbound lane",
7277 			__func__, ldcp->ldc_id);
7278 		DERR(vswp, "%s(%lld) status(%d) state (0x%llx)",
7279 			__func__, ldcp->ldc_id, ldcp->ldc_status,
7280 			ldcp->lane_out.lstate);
7281 		RW_EXIT(&ldcp->lane_out.dlistrw);
7282 		freemsg(mp);
7283 		return (LDC_TX_FAILURE);
7284 	}
7285 
7286 	size = msgsize(mp);
7287 	if (size > (size_t)ETHERMAX) {
7288 		RW_EXIT(&ldcp->lane_out.dlistrw);
7289 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
7290 		    ldcp->ldc_id, size);
7291 		freemsg(mp);
7292 		return (LDC_TX_FAILURE);
7293 	}
7294 
7295 	/*
7296 	 * Find a free descriptor in our buffer ring
7297 	 */
7298 	if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) {
7299 		RW_EXIT(&ldcp->lane_out.dlistrw);
7300 		if (warn_msg) {
7301 			DERR(vswp, "%s(%lld): no descriptor available for ring "
7302 			"at 0x%llx", __func__, ldcp->ldc_id, dp);
7303 			warn_msg = 0;
7304 		}
7305 
7306 		/* nothing more we can do */
7307 		status = LDC_TX_NORESOURCES;
7308 		goto vsw_descrsend_free_exit;
7309 	} else {
7310 		D2(vswp, "%s(%lld): free private descriptor found at pos "
7311 			"%ld addr 0x%x\n", __func__, ldcp->ldc_id, idx,
7312 			priv_desc);
7313 		warn_msg = 1;
7314 	}
7315 
7316 	/* copy data into the descriptor */
7317 	bufp = priv_desc->datap;
7318 	for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) {
7319 		n = MBLKL(bp);
7320 		bcopy(bp->b_rptr, bufp, n);
7321 		bufp += n;
7322 	}
7323 
7324 	priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size;
7325 
7326 	/* create and send the in-band descp msg */
7327 	ibnd_msg.hdr.tag.vio_msgtype = VIO_TYPE_DATA;
7328 	ibnd_msg.hdr.tag.vio_subtype = VIO_SUBTYPE_INFO;
7329 	ibnd_msg.hdr.tag.vio_subtype_env = VIO_DESC_DATA;
7330 	ibnd_msg.hdr.tag.vio_sid = ldcp->local_session;
7331 
7332 	mutex_enter(&ldcp->lane_out.seq_lock);
7333 	ibnd_msg.hdr.seq_num = ldcp->lane_out.seq_num++;
7334 	mutex_exit(&ldcp->lane_out.seq_lock);
7335 
7336 	/*
7337 	 * Copy the mem cookies describing the data from the
7338 	 * private region of the descriptor ring into the inband
7339 	 * descriptor.
7340 	 */
7341 	for (i = 0; i < priv_desc->ncookies; i++) {
7342 		bcopy(&priv_desc->memcookie[i], &ibnd_msg.memcookie[i],
7343 			sizeof (ldc_mem_cookie_t));
7344 	}
7345 
7346 	ibnd_msg.hdr.desc_handle = idx;
7347 	ibnd_msg.ncookies = priv_desc->ncookies;
7348 	ibnd_msg.nbytes = size;
7349 
7350 	RW_EXIT(&ldcp->lane_out.dlistrw);
7351 
7352 	(void) vsw_send_msg(ldcp, (void *)&ibnd_msg,
7353 			sizeof (vnet_ibnd_desc_t), B_TRUE);
7354 
7355 vsw_descrsend_free_exit:
7356 
7357 	/* free the allocated message blocks */
7358 	freemsg(mp);
7359 
7360 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
7361 	return (status);
7362 }
7363 
7364 static void
7365 vsw_send_ver(void *arg)
7366 {
7367 	vsw_ldc_t	*ldcp = (vsw_ldc_t *)arg;
7368 	vsw_t		*vswp = ldcp->ldc_vswp;
7369 	lane_t		*lp = &ldcp->lane_out;
7370 	vio_ver_msg_t	ver_msg;
7371 
7372 	D1(vswp, "%s enter", __func__);
7373 
7374 	ver_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
7375 	ver_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
7376 	ver_msg.tag.vio_subtype_env = VIO_VER_INFO;
7377 	ver_msg.tag.vio_sid = ldcp->local_session;
7378 
7379 	ver_msg.ver_major = vsw_versions[0].ver_major;
7380 	ver_msg.ver_minor = vsw_versions[0].ver_minor;
7381 	ver_msg.dev_class = VDEV_NETWORK_SWITCH;
7382 
7383 	lp->lstate |= VSW_VER_INFO_SENT;
7384 	lp->ver_major = ver_msg.ver_major;
7385 	lp->ver_minor = ver_msg.ver_minor;
7386 
7387 	DUMP_TAG(ver_msg.tag);
7388 
7389 	(void) vsw_send_msg(ldcp, &ver_msg, sizeof (vio_ver_msg_t), B_TRUE);
7390 
7391 	D1(vswp, "%s (%d): exit", __func__, ldcp->ldc_id);
7392 }
7393 
7394 static void
7395 vsw_send_attr(vsw_ldc_t *ldcp)
7396 {
7397 	vsw_t			*vswp = ldcp->ldc_vswp;
7398 	lane_t			*lp = &ldcp->lane_out;
7399 	vnet_attr_msg_t		attr_msg;
7400 
7401 	D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
7402 
7403 	/*
7404 	 * Subtype is set to INFO by default
7405 	 */
7406 	attr_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
7407 	attr_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
7408 	attr_msg.tag.vio_subtype_env = VIO_ATTR_INFO;
7409 	attr_msg.tag.vio_sid = ldcp->local_session;
7410 
7411 	/* payload copied from default settings for lane */
7412 	attr_msg.mtu = lp->mtu;
7413 	attr_msg.addr_type = lp->addr_type;
7414 	attr_msg.xfer_mode = lp->xfer_mode;
7415 	attr_msg.ack_freq = lp->xfer_mode;
7416 
7417 	READ_ENTER(&vswp->if_lockrw);
7418 	bcopy(&(vswp->if_addr), &(attr_msg.addr), ETHERADDRL);
7419 	RW_EXIT(&vswp->if_lockrw);
7420 
7421 	ldcp->lane_out.lstate |= VSW_ATTR_INFO_SENT;
7422 
7423 	DUMP_TAG(attr_msg.tag);
7424 
7425 	(void) vsw_send_msg(ldcp, &attr_msg, sizeof (vnet_attr_msg_t), B_TRUE);
7426 
7427 	D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
7428 }
7429 
7430 /*
7431  * Create dring info msg (which also results in the creation of
7432  * a dring).
7433  */
7434 static vio_dring_reg_msg_t *
7435 vsw_create_dring_info_pkt(vsw_ldc_t *ldcp)
7436 {
7437 	vio_dring_reg_msg_t	*mp;
7438 	dring_info_t		*dp;
7439 	vsw_t			*vswp = ldcp->ldc_vswp;
7440 
7441 	D1(vswp, "vsw_create_dring_info_pkt enter\n");
7442 
7443 	/*
7444 	 * If we can't create a dring, obviously no point sending
7445 	 * a message.
7446 	 */
7447 	if ((dp = vsw_create_dring(ldcp)) == NULL)
7448 		return (NULL);
7449 
7450 	mp = kmem_zalloc(sizeof (vio_dring_reg_msg_t), KM_SLEEP);
7451 
7452 	mp->tag.vio_msgtype = VIO_TYPE_CTRL;
7453 	mp->tag.vio_subtype = VIO_SUBTYPE_INFO;
7454 	mp->tag.vio_subtype_env = VIO_DRING_REG;
7455 	mp->tag.vio_sid = ldcp->local_session;
7456 
7457 	/* payload */
7458 	mp->num_descriptors = dp->num_descriptors;
7459 	mp->descriptor_size = dp->descriptor_size;
7460 	mp->options = dp->options;
7461 	mp->ncookies = dp->ncookies;
7462 	bcopy(&dp->cookie[0], &mp->cookie[0], sizeof (ldc_mem_cookie_t));
7463 
7464 	mp->dring_ident = 0;
7465 
7466 	D1(vswp, "vsw_create_dring_info_pkt exit\n");
7467 
7468 	return (mp);
7469 }
7470 
7471 static void
7472 vsw_send_dring_info(vsw_ldc_t *ldcp)
7473 {
7474 	vio_dring_reg_msg_t	*dring_msg;
7475 	vsw_t			*vswp = ldcp->ldc_vswp;
7476 
7477 	D1(vswp, "%s: (%ld) enter", __func__, ldcp->ldc_id);
7478 
7479 	dring_msg = vsw_create_dring_info_pkt(ldcp);
7480 	if (dring_msg == NULL) {
7481 		cmn_err(CE_WARN, "!vsw%d: %s: error creating msg",
7482 			vswp->instance, __func__);
7483 		return;
7484 	}
7485 
7486 	ldcp->lane_out.lstate |= VSW_DRING_INFO_SENT;
7487 
7488 	DUMP_TAG_PTR((vio_msg_tag_t *)dring_msg);
7489 
7490 	(void) vsw_send_msg(ldcp, dring_msg,
7491 		sizeof (vio_dring_reg_msg_t), B_TRUE);
7492 
7493 	kmem_free(dring_msg, sizeof (vio_dring_reg_msg_t));
7494 
7495 	D1(vswp, "%s: (%ld) exit", __func__, ldcp->ldc_id);
7496 }
7497 
7498 static void
7499 vsw_send_rdx(vsw_ldc_t *ldcp)
7500 {
7501 	vsw_t		*vswp = ldcp->ldc_vswp;
7502 	vio_rdx_msg_t	rdx_msg;
7503 
7504 	D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
7505 
7506 	rdx_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
7507 	rdx_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
7508 	rdx_msg.tag.vio_subtype_env = VIO_RDX;
7509 	rdx_msg.tag.vio_sid = ldcp->local_session;
7510 
7511 	ldcp->lane_in.lstate |= VSW_RDX_INFO_SENT;
7512 
7513 	DUMP_TAG(rdx_msg.tag);
7514 
7515 	(void) vsw_send_msg(ldcp, &rdx_msg, sizeof (vio_rdx_msg_t), B_TRUE);
7516 
7517 	D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
7518 }
7519 
7520 /*
7521  * Generic routine to send message out over ldc channel.
7522  *
7523  * It is possible that when we attempt to write over the ldc channel
7524  * that we get notified that it has been reset. Depending on the value
7525  * of the handle_reset flag we either handle that event here or simply
7526  * notify the caller that the channel was reset.
7527  */
7528 static int
7529 vsw_send_msg(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset)
7530 {
7531 	int		rv;
7532 	size_t		msglen = size;
7533 	vio_msg_tag_t	*tag = (vio_msg_tag_t *)msgp;
7534 	vsw_t		*vswp = ldcp->ldc_vswp;
7535 
7536 	D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes",
7537 			ldcp->ldc_id, size);
7538 
7539 	D2(vswp, "send_msg: type 0x%llx", tag->vio_msgtype);
7540 	D2(vswp, "send_msg: stype 0x%llx", tag->vio_subtype);
7541 	D2(vswp, "send_msg: senv 0x%llx", tag->vio_subtype_env);
7542 
7543 	mutex_enter(&ldcp->ldc_txlock);
7544 	do {
7545 		msglen = size;
7546 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen);
7547 	} while (rv == EWOULDBLOCK && --vsw_wretries > 0);
7548 
7549 	if ((rv != 0) || (msglen != size)) {
7550 		DERR(vswp, "vsw_send_msg:ldc_write failed: chan(%lld) "
7551 			"rv(%d) size (%d) msglen(%d)\n", ldcp->ldc_id,
7552 			rv, size, msglen);
7553 	}
7554 	mutex_exit(&ldcp->ldc_txlock);
7555 
7556 	/*
7557 	 * If channel has been reset we either handle it here or
7558 	 * simply report back that it has been reset and let caller
7559 	 * decide what to do.
7560 	 */
7561 	if (rv == ECONNRESET) {
7562 		DWARN(vswp, "%s (%lld) channel reset",
7563 					__func__, ldcp->ldc_id);
7564 
7565 		/*
7566 		 * N.B - must never be holding the dlistrw lock when
7567 		 * we do a reset of the channel.
7568 		 */
7569 		if (handle_reset) {
7570 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
7571 		}
7572 	}
7573 
7574 	return (rv);
7575 }
7576 
7577 /*
7578  * Add an entry into FDB, for the given mac address and port_id.
7579  * Returns 0 on success, 1 on failure.
7580  *
7581  * Lock protecting FDB must be held by calling process.
7582  */
7583 static int
7584 vsw_add_fdb(vsw_t *vswp, vsw_port_t *port)
7585 {
7586 	uint64_t	addr = 0;
7587 
7588 	D1(vswp, "%s: enter", __func__);
7589 
7590 	KEY_HASH(addr, port->p_macaddr);
7591 
7592 	D2(vswp, "%s: key = 0x%llx", __func__, addr);
7593 
7594 	/*
7595 	 * Note: duplicate keys will be rejected by mod_hash.
7596 	 */
7597 	if (mod_hash_insert(vswp->fdb, (mod_hash_key_t)addr,
7598 				(mod_hash_val_t)port) != 0) {
7599 		DERR(vswp, "%s: unable to add entry into fdb.", __func__);
7600 		return (1);
7601 	}
7602 
7603 	D1(vswp, "%s: exit", __func__);
7604 	return (0);
7605 }
7606 
7607 /*
7608  * Remove an entry from FDB.
7609  * Returns 0 on success, 1 on failure.
7610  */
7611 static int
7612 vsw_del_fdb(vsw_t *vswp, vsw_port_t *port)
7613 {
7614 	uint64_t	addr = 0;
7615 
7616 	D1(vswp, "%s: enter", __func__);
7617 
7618 	KEY_HASH(addr, port->p_macaddr);
7619 
7620 	D2(vswp, "%s: key = 0x%llx", __func__, addr);
7621 
7622 	(void) mod_hash_destroy(vswp->fdb, (mod_hash_val_t)addr);
7623 
7624 	D1(vswp, "%s: enter", __func__);
7625 
7626 	return (0);
7627 }
7628 
7629 /*
7630  * Search fdb for a given mac address.
7631  * Returns pointer to the entry if found, else returns NULL.
7632  */
7633 static vsw_port_t *
7634 vsw_lookup_fdb(vsw_t *vswp, struct ether_header *ehp)
7635 {
7636 	uint64_t	key = 0;
7637 	vsw_port_t	*port = NULL;
7638 
7639 	D1(vswp, "%s: enter", __func__);
7640 
7641 	KEY_HASH(key, ehp->ether_dhost);
7642 
7643 	D2(vswp, "%s: key = 0x%llx", __func__, key);
7644 
7645 	if (mod_hash_find(vswp->fdb, (mod_hash_key_t)key,
7646 				(mod_hash_val_t *)&port) != 0) {
7647 		D2(vswp, "%s: no port found", __func__);
7648 		return (NULL);
7649 	}
7650 
7651 	D1(vswp, "%s: exit", __func__);
7652 
7653 	return (port);
7654 }
7655 
7656 /*
7657  * Add or remove multicast address(es).
7658  *
7659  * Returns 0 on success, 1 on failure.
7660  */
7661 static int
7662 vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port)
7663 {
7664 	mcst_addr_t		*mcst_p = NULL;
7665 	vsw_t			*vswp = port->p_vswp;
7666 	uint64_t		addr = 0x0;
7667 	int			i;
7668 
7669 	D1(vswp, "%s: enter", __func__);
7670 
7671 	D2(vswp, "%s: %d addresses", __func__, mcst_pkt->count);
7672 
7673 	mutex_enter(&vswp->mac_lock);
7674 	if (vswp->mh == NULL) {
7675 		mutex_exit(&vswp->mac_lock);
7676 		return (1);
7677 	}
7678 	mutex_exit(&vswp->mac_lock);
7679 
7680 	for (i = 0; i < mcst_pkt->count; i++) {
7681 		/*
7682 		 * Convert address into form that can be used
7683 		 * as hash table key.
7684 		 */
7685 		KEY_HASH(addr, mcst_pkt->mca[i]);
7686 
7687 		/*
7688 		 * Add or delete the specified address/port combination.
7689 		 */
7690 		if (mcst_pkt->set == 0x1) {
7691 			D3(vswp, "%s: adding multicast address 0x%llx for "
7692 				"port %ld", __func__, addr, port->p_instance);
7693 			if (vsw_add_mcst(vswp, VSW_VNETPORT, addr, port) == 0) {
7694 				/*
7695 				 * Update the list of multicast
7696 				 * addresses contained within the
7697 				 * port structure to include this new
7698 				 * one.
7699 				 */
7700 				mcst_p = kmem_alloc(sizeof (mcst_addr_t),
7701 								KM_NOSLEEP);
7702 				if (mcst_p == NULL) {
7703 					DERR(vswp, "%s: unable to alloc mem",
7704 						__func__);
7705 					return (1);
7706 				}
7707 
7708 				mcst_p->nextp = NULL;
7709 				mcst_p->addr = addr;
7710 
7711 				mutex_enter(&port->mca_lock);
7712 				mcst_p->nextp = port->mcap;
7713 				port->mcap = mcst_p;
7714 				mutex_exit(&port->mca_lock);
7715 
7716 				/*
7717 				 * Program the address into HW. If the addr
7718 				 * has already been programmed then the MAC
7719 				 * just increments a ref counter (which is
7720 				 * used when the address is being deleted)
7721 				 */
7722 				mutex_enter(&vswp->mac_lock);
7723 				if ((vswp->mh == NULL) ||
7724 					mac_multicst_add(vswp->mh,
7725 						(uchar_t *)&mcst_pkt->mca[i])) {
7726 					mutex_exit(&vswp->mac_lock);
7727 					cmn_err(CE_WARN, "!vsw%d: unable to "
7728 						"add multicast address",
7729 						vswp->instance);
7730 					(void) vsw_del_mcst(vswp, VSW_VNETPORT,
7731 						addr, port);
7732 					vsw_del_addr(VSW_VNETPORT, port, addr);
7733 					return (1);
7734 				}
7735 				mutex_exit(&vswp->mac_lock);
7736 
7737 			} else {
7738 				DERR(vswp, "%s: error adding multicast "
7739 					"address 0x%llx for port %ld",
7740 					__func__, addr, port->p_instance);
7741 				return (1);
7742 			}
7743 		} else {
7744 			/*
7745 			 * Delete an entry from the multicast hash
7746 			 * table and update the address list
7747 			 * appropriately.
7748 			 */
7749 			if (vsw_del_mcst(vswp, VSW_VNETPORT, addr, port) == 0) {
7750 				D3(vswp, "%s: deleting multicast address "
7751 					"0x%llx for port %ld", __func__, addr,
7752 					port->p_instance);
7753 
7754 				vsw_del_addr(VSW_VNETPORT, port, addr);
7755 
7756 				/*
7757 				 * Remove the address from HW. The address
7758 				 * will actually only be removed once the ref
7759 				 * count within the MAC layer has dropped to
7760 				 * zero. I.e. we can safely call this fn even
7761 				 * if other ports are interested in this
7762 				 * address.
7763 				 */
7764 				mutex_enter(&vswp->mac_lock);
7765 				if ((vswp->mh == NULL) ||
7766 					mac_multicst_remove(vswp->mh,
7767 						(uchar_t *)&mcst_pkt->mca[i])) {
7768 					mutex_exit(&vswp->mac_lock);
7769 					cmn_err(CE_WARN, "!vsw%d: unable to "
7770 						"remove multicast address",
7771 						vswp->instance);
7772 					return (1);
7773 				}
7774 				mutex_exit(&vswp->mac_lock);
7775 
7776 			} else {
7777 				DERR(vswp, "%s: error deleting multicast "
7778 					"addr 0x%llx for port %ld",
7779 					__func__, addr, port->p_instance);
7780 				return (1);
7781 			}
7782 		}
7783 	}
7784 	D1(vswp, "%s: exit", __func__);
7785 	return (0);
7786 }
7787 
7788 /*
7789  * Add a new multicast entry.
7790  *
7791  * Search hash table based on address. If match found then
7792  * update associated val (which is chain of ports), otherwise
7793  * create new key/val (addr/port) pair and insert into table.
7794  */
7795 static int
7796 vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
7797 {
7798 	int		dup = 0;
7799 	int		rv = 0;
7800 	mfdb_ent_t	*ment = NULL;
7801 	mfdb_ent_t	*tmp_ent = NULL;
7802 	mfdb_ent_t	*new_ent = NULL;
7803 	void		*tgt = NULL;
7804 
7805 	if (devtype == VSW_VNETPORT) {
7806 		/*
7807 		 * Being invoked from a vnet.
7808 		 */
7809 		ASSERT(arg != NULL);
7810 		tgt = arg;
7811 		D2(NULL, "%s: port %d : address 0x%llx", __func__,
7812 			((vsw_port_t *)arg)->p_instance, addr);
7813 	} else {
7814 		/*
7815 		 * We are being invoked via the m_multicst mac entry
7816 		 * point.
7817 		 */
7818 		D2(NULL, "%s: address 0x%llx", __func__, addr);
7819 		tgt = (void *)vswp;
7820 	}
7821 
7822 	WRITE_ENTER(&vswp->mfdbrw);
7823 	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
7824 				(mod_hash_val_t *)&ment) != 0) {
7825 
7826 		/* address not currently in table */
7827 		ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
7828 		ment->d_addr = (void *)tgt;
7829 		ment->d_type = devtype;
7830 		ment->nextp = NULL;
7831 
7832 		if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr,
7833 			(mod_hash_val_t)ment) != 0) {
7834 			DERR(vswp, "%s: hash table insertion failed", __func__);
7835 			kmem_free(ment, sizeof (mfdb_ent_t));
7836 			rv = 1;
7837 		} else {
7838 			D2(vswp, "%s: added initial entry for 0x%llx to "
7839 				"table", __func__, addr);
7840 		}
7841 	} else {
7842 		/*
7843 		 * Address in table. Check to see if specified port
7844 		 * is already associated with the address. If not add
7845 		 * it now.
7846 		 */
7847 		tmp_ent = ment;
7848 		while (tmp_ent != NULL) {
7849 			if (tmp_ent->d_addr == (void *)tgt) {
7850 				if (devtype == VSW_VNETPORT) {
7851 					DERR(vswp, "%s: duplicate port entry "
7852 						"found for portid %ld and key "
7853 						"0x%llx", __func__,
7854 						((vsw_port_t *)arg)->p_instance,
7855 						addr);
7856 				} else {
7857 					DERR(vswp, "%s: duplicate entry found"
7858 						"for key 0x%llx",
7859 						__func__, addr);
7860 				}
7861 				rv = 1;
7862 				dup = 1;
7863 				break;
7864 			}
7865 			tmp_ent = tmp_ent->nextp;
7866 		}
7867 
7868 		/*
7869 		 * Port not on list so add it to end now.
7870 		 */
7871 		if (0 == dup) {
7872 			D2(vswp, "%s: added entry for 0x%llx to table",
7873 				__func__, addr);
7874 			new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
7875 			new_ent->d_addr = (void *)tgt;
7876 			new_ent->d_type = devtype;
7877 			new_ent->nextp = NULL;
7878 
7879 			tmp_ent = ment;
7880 			while (tmp_ent->nextp != NULL)
7881 				tmp_ent = tmp_ent->nextp;
7882 
7883 			tmp_ent->nextp = new_ent;
7884 		}
7885 	}
7886 
7887 	RW_EXIT(&vswp->mfdbrw);
7888 	return (rv);
7889 }
7890 
7891 /*
7892  * Remove a multicast entry from the hashtable.
7893  *
7894  * Search hash table based on address. If match found, scan
7895  * list of ports associated with address. If specified port
7896  * found remove it from list.
7897  */
7898 static int
7899 vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
7900 {
7901 	mfdb_ent_t	*ment = NULL;
7902 	mfdb_ent_t	*curr_p, *prev_p;
7903 	void		*tgt = NULL;
7904 
7905 	D1(vswp, "%s: enter", __func__);
7906 
7907 	if (devtype == VSW_VNETPORT) {
7908 		tgt = (vsw_port_t *)arg;
7909 		D2(vswp, "%s: removing port %d from mFDB for address"
7910 			" 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance,
7911 			addr);
7912 	} else {
7913 		D2(vswp, "%s: removing entry", __func__);
7914 		tgt = (void *)vswp;
7915 	}
7916 
7917 	WRITE_ENTER(&vswp->mfdbrw);
7918 	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
7919 				(mod_hash_val_t *)&ment) != 0) {
7920 		D2(vswp, "%s: address 0x%llx not in table", __func__, addr);
7921 		RW_EXIT(&vswp->mfdbrw);
7922 		return (1);
7923 	}
7924 
7925 	prev_p = curr_p = ment;
7926 
7927 	while (curr_p != NULL) {
7928 		if (curr_p->d_addr == (void *)tgt) {
7929 			if (devtype == VSW_VNETPORT) {
7930 				D2(vswp, "%s: port %d found", __func__,
7931 					((vsw_port_t *)tgt)->p_instance);
7932 			} else {
7933 				D2(vswp, "%s: instance found", __func__);
7934 			}
7935 
7936 			if (prev_p == curr_p) {
7937 				/*
7938 				 * head of list, if no other element is in
7939 				 * list then destroy this entry, otherwise
7940 				 * just replace it with updated value.
7941 				 */
7942 				ment = curr_p->nextp;
7943 				kmem_free(curr_p, sizeof (mfdb_ent_t));
7944 				if (ment == NULL) {
7945 					(void) mod_hash_destroy(vswp->mfdb,
7946 							(mod_hash_val_t)addr);
7947 				} else {
7948 					(void) mod_hash_replace(vswp->mfdb,
7949 							(mod_hash_key_t)addr,
7950 							(mod_hash_val_t)ment);
7951 				}
7952 			} else {
7953 				/*
7954 				 * Not head of list, no need to do
7955 				 * replacement, just adjust list pointers.
7956 				 */
7957 				prev_p->nextp = curr_p->nextp;
7958 				kmem_free(curr_p, sizeof (mfdb_ent_t));
7959 			}
7960 			break;
7961 		}
7962 
7963 		prev_p = curr_p;
7964 		curr_p = curr_p->nextp;
7965 	}
7966 
7967 	RW_EXIT(&vswp->mfdbrw);
7968 
7969 	D1(vswp, "%s: exit", __func__);
7970 
7971 	return (0);
7972 }
7973 
7974 /*
7975  * Port is being deleted, but has registered an interest in one
7976  * or more multicast groups. Using the list of addresses maintained
7977  * within the port structure find the appropriate entry in the hash
7978  * table and remove this port from the list of interested ports.
7979  */
7980 static void
7981 vsw_del_mcst_port(vsw_port_t *port)
7982 {
7983 	mcst_addr_t	*mcst_p = NULL;
7984 	vsw_t		*vswp = port->p_vswp;
7985 
7986 	D1(vswp, "%s: enter", __func__);
7987 
7988 	mutex_enter(&port->mca_lock);
7989 	while (port->mcap != NULL) {
7990 		(void) vsw_del_mcst(vswp, VSW_VNETPORT,
7991 					port->mcap->addr, port);
7992 
7993 		mcst_p = port->mcap->nextp;
7994 		kmem_free(port->mcap, sizeof (mcst_addr_t));
7995 		port->mcap = mcst_p;
7996 	}
7997 	mutex_exit(&port->mca_lock);
7998 
7999 	D1(vswp, "%s: exit", __func__);
8000 }
8001 
8002 /*
8003  * This vsw instance is detaching, but has registered an interest in one
8004  * or more multicast groups. Using the list of addresses maintained
8005  * within the vsw structure find the appropriate entry in the hash
8006  * table and remove this instance from the list of interested ports.
8007  */
8008 static void
8009 vsw_del_mcst_vsw(vsw_t *vswp)
8010 {
8011 	mcst_addr_t	*next_p = NULL;
8012 
8013 	D1(vswp, "%s: enter", __func__);
8014 
8015 	mutex_enter(&vswp->mca_lock);
8016 
8017 	while (vswp->mcap != NULL) {
8018 		DERR(vswp, "%s: deleting addr 0x%llx",
8019 			__func__, vswp->mcap->addr);
8020 		(void) vsw_del_mcst(vswp, VSW_LOCALDEV,
8021 				vswp->mcap->addr, NULL);
8022 
8023 		next_p = vswp->mcap->nextp;
8024 		kmem_free(vswp->mcap, sizeof (mcst_addr_t));
8025 		vswp->mcap = next_p;
8026 	}
8027 
8028 	vswp->mcap = NULL;
8029 	mutex_exit(&vswp->mca_lock);
8030 
8031 	D1(vswp, "%s: exit", __func__);
8032 }
8033 
8034 
8035 /*
8036  * Remove the specified address from the list of address maintained
8037  * in this port node.
8038  */
8039 static void
8040 vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr)
8041 {
8042 	vsw_t		*vswp = NULL;
8043 	vsw_port_t	*port = NULL;
8044 	mcst_addr_t	*prev_p = NULL;
8045 	mcst_addr_t	*curr_p = NULL;
8046 
8047 	D1(NULL, "%s: enter : devtype %d : addr 0x%llx",
8048 		__func__, devtype, addr);
8049 
8050 	if (devtype == VSW_VNETPORT) {
8051 		port = (vsw_port_t *)arg;
8052 		mutex_enter(&port->mca_lock);
8053 		prev_p = curr_p = port->mcap;
8054 	} else {
8055 		vswp = (vsw_t *)arg;
8056 		mutex_enter(&vswp->mca_lock);
8057 		prev_p = curr_p = vswp->mcap;
8058 	}
8059 
8060 	while (curr_p != NULL) {
8061 		if (curr_p->addr == addr) {
8062 			D2(NULL, "%s: address found", __func__);
8063 			/* match found */
8064 			if (prev_p == curr_p) {
8065 				/* list head */
8066 				if (devtype == VSW_VNETPORT)
8067 					port->mcap = curr_p->nextp;
8068 				else
8069 					vswp->mcap = curr_p->nextp;
8070 			} else {
8071 				prev_p->nextp = curr_p->nextp;
8072 			}
8073 			kmem_free(curr_p, sizeof (mcst_addr_t));
8074 			break;
8075 		} else {
8076 			prev_p = curr_p;
8077 			curr_p = curr_p->nextp;
8078 		}
8079 	}
8080 
8081 	if (devtype == VSW_VNETPORT)
8082 		mutex_exit(&port->mca_lock);
8083 	else
8084 		mutex_exit(&vswp->mca_lock);
8085 
8086 	D1(NULL, "%s: exit", __func__);
8087 }
8088 
8089 /*
8090  * Creates a descriptor ring (dring) and links it into the
8091  * link of outbound drings for this channel.
8092  *
8093  * Returns NULL if creation failed.
8094  */
8095 static dring_info_t *
8096 vsw_create_dring(vsw_ldc_t *ldcp)
8097 {
8098 	vsw_private_desc_t	*priv_addr = NULL;
8099 	vsw_t			*vswp = ldcp->ldc_vswp;
8100 	ldc_mem_info_t		minfo;
8101 	dring_info_t		*dp, *tp;
8102 	int			i;
8103 
8104 	dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
8105 
8106 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
8107 
8108 	/* create public section of ring */
8109 	if ((ldc_mem_dring_create(VSW_RING_NUM_EL,
8110 			VSW_PUB_SIZE, &dp->handle)) != 0) {
8111 
8112 		DERR(vswp, "vsw_create_dring(%lld): ldc dring create "
8113 			"failed", ldcp->ldc_id);
8114 		goto create_fail_exit;
8115 	}
8116 
8117 	ASSERT(dp->handle != NULL);
8118 
8119 	/*
8120 	 * Get the base address of the public section of the ring.
8121 	 */
8122 	if ((ldc_mem_dring_info(dp->handle, &minfo)) != 0) {
8123 		DERR(vswp, "vsw_create_dring(%lld): dring info failed\n",
8124 			ldcp->ldc_id);
8125 		goto dring_fail_exit;
8126 	} else {
8127 		ASSERT(minfo.vaddr != 0);
8128 		dp->pub_addr = minfo.vaddr;
8129 	}
8130 
8131 	dp->num_descriptors = VSW_RING_NUM_EL;
8132 	dp->descriptor_size = VSW_PUB_SIZE;
8133 	dp->options = VIO_TX_DRING;
8134 	dp->ncookies = 1;	/* guaranteed by ldc */
8135 
8136 	/*
8137 	 * create private portion of ring
8138 	 */
8139 	dp->priv_addr = (vsw_private_desc_t *)kmem_zalloc(
8140 		(sizeof (vsw_private_desc_t) * VSW_RING_NUM_EL), KM_SLEEP);
8141 
8142 	if (vsw_setup_ring(ldcp, dp)) {
8143 		DERR(vswp, "%s: unable to setup ring", __func__);
8144 		goto dring_fail_exit;
8145 	}
8146 
8147 	/* haven't used any descriptors yet */
8148 	dp->end_idx = 0;
8149 	dp->last_ack_recv = -1;
8150 
8151 	/* bind dring to the channel */
8152 	if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->handle,
8153 		LDC_SHADOW_MAP, LDC_MEM_RW,
8154 		&dp->cookie[0], &dp->ncookies)) != 0) {
8155 		DERR(vswp, "vsw_create_dring: unable to bind to channel "
8156 			"%lld", ldcp->ldc_id);
8157 		goto dring_fail_exit;
8158 	}
8159 
8160 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
8161 	dp->restart_reqd = B_TRUE;
8162 
8163 	/*
8164 	 * Only ever create rings for outgoing lane. Link it onto
8165 	 * end of list.
8166 	 */
8167 	WRITE_ENTER(&ldcp->lane_out.dlistrw);
8168 	if (ldcp->lane_out.dringp == NULL) {
8169 		D2(vswp, "vsw_create_dring: adding first outbound ring");
8170 		ldcp->lane_out.dringp = dp;
8171 	} else {
8172 		tp = ldcp->lane_out.dringp;
8173 		while (tp->next != NULL)
8174 			tp = tp->next;
8175 
8176 		tp->next = dp;
8177 	}
8178 	RW_EXIT(&ldcp->lane_out.dlistrw);
8179 
8180 	return (dp);
8181 
8182 dring_fail_exit:
8183 	(void) ldc_mem_dring_destroy(dp->handle);
8184 
8185 create_fail_exit:
8186 	if (dp->priv_addr != NULL) {
8187 		priv_addr = dp->priv_addr;
8188 		for (i = 0; i < VSW_RING_NUM_EL; i++) {
8189 			if (priv_addr->memhandle != NULL)
8190 				(void) ldc_mem_free_handle(
8191 						priv_addr->memhandle);
8192 			priv_addr++;
8193 		}
8194 		kmem_free(dp->priv_addr,
8195 			(sizeof (vsw_private_desc_t) * VSW_RING_NUM_EL));
8196 	}
8197 	mutex_destroy(&dp->dlock);
8198 
8199 	kmem_free(dp, sizeof (dring_info_t));
8200 	return (NULL);
8201 }
8202 
8203 /*
8204  * Create a ring consisting of just a private portion and link
8205  * it into the list of rings for the outbound lane.
8206  *
8207  * These type of rings are used primarily for temporary data
8208  * storage (i.e. as data buffers).
8209  */
8210 void
8211 vsw_create_privring(vsw_ldc_t *ldcp)
8212 {
8213 	dring_info_t		*dp, *tp;
8214 	vsw_t			*vswp = ldcp->ldc_vswp;
8215 
8216 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
8217 
8218 	dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
8219 
8220 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
8221 
8222 	/* no public section */
8223 	dp->pub_addr = NULL;
8224 
8225 	dp->priv_addr = kmem_zalloc((sizeof (vsw_private_desc_t) *
8226 					VSW_RING_NUM_EL), KM_SLEEP);
8227 
8228 	dp->num_descriptors = VSW_RING_NUM_EL;
8229 
8230 	if (vsw_setup_ring(ldcp, dp)) {
8231 		DERR(vswp, "%s: setup of ring failed", __func__);
8232 		kmem_free(dp->priv_addr,
8233 			(sizeof (vsw_private_desc_t) * VSW_RING_NUM_EL));
8234 		mutex_destroy(&dp->dlock);
8235 		kmem_free(dp, sizeof (dring_info_t));
8236 		return;
8237 	}
8238 
8239 	/* haven't used any descriptors yet */
8240 	dp->end_idx = 0;
8241 
8242 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
8243 	dp->restart_reqd = B_TRUE;
8244 
8245 	/*
8246 	 * Only ever create rings for outgoing lane. Link it onto
8247 	 * end of list.
8248 	 */
8249 	WRITE_ENTER(&ldcp->lane_out.dlistrw);
8250 	if (ldcp->lane_out.dringp == NULL) {
8251 		D2(vswp, "%s: adding first outbound privring", __func__);
8252 		ldcp->lane_out.dringp = dp;
8253 	} else {
8254 		tp = ldcp->lane_out.dringp;
8255 		while (tp->next != NULL)
8256 			tp = tp->next;
8257 
8258 		tp->next = dp;
8259 	}
8260 	RW_EXIT(&ldcp->lane_out.dlistrw);
8261 
8262 	D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
8263 }
8264 
8265 /*
8266  * Setup the descriptors in the dring. Returns 0 on success, 1 on
8267  * failure.
8268  */
8269 int
8270 vsw_setup_ring(vsw_ldc_t *ldcp, dring_info_t *dp)
8271 {
8272 	vnet_public_desc_t	*pub_addr = NULL;
8273 	vsw_private_desc_t	*priv_addr = NULL;
8274 	vsw_t			*vswp = ldcp->ldc_vswp;
8275 	uint64_t		*tmpp;
8276 	uint64_t		offset = 0;
8277 	uint32_t		ncookies = 0;
8278 	static char		*name = "vsw_setup_ring";
8279 	int			i, j, nc, rv;
8280 
8281 	priv_addr = dp->priv_addr;
8282 	pub_addr = dp->pub_addr;
8283 
8284 	/* public section may be null but private should never be */
8285 	ASSERT(priv_addr != NULL);
8286 
8287 	/*
8288 	 * Allocate the region of memory which will be used to hold
8289 	 * the data the descriptors will refer to.
8290 	 */
8291 	dp->data_sz = (VSW_RING_NUM_EL * VSW_RING_EL_DATA_SZ);
8292 	dp->data_addr = kmem_alloc(dp->data_sz, KM_SLEEP);
8293 
8294 	D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name,
8295 		dp->data_sz, dp->data_addr);
8296 
8297 	tmpp = (uint64_t *)dp->data_addr;
8298 	offset = VSW_RING_EL_DATA_SZ / sizeof (tmpp);
8299 
8300 	/*
8301 	 * Initialise some of the private and public (if they exist)
8302 	 * descriptor fields.
8303 	 */
8304 	for (i = 0; i < VSW_RING_NUM_EL; i++) {
8305 		mutex_init(&priv_addr->dstate_lock, NULL, MUTEX_DRIVER, NULL);
8306 
8307 		if ((ldc_mem_alloc_handle(ldcp->ldc_handle,
8308 			&priv_addr->memhandle)) != 0) {
8309 			DERR(vswp, "%s: alloc mem handle failed", name);
8310 			goto setup_ring_cleanup;
8311 		}
8312 
8313 		priv_addr->datap = (void *)tmpp;
8314 
8315 		rv = ldc_mem_bind_handle(priv_addr->memhandle,
8316 			(caddr_t)priv_addr->datap, VSW_RING_EL_DATA_SZ,
8317 			LDC_SHADOW_MAP, LDC_MEM_R|LDC_MEM_W,
8318 			&(priv_addr->memcookie[0]), &ncookies);
8319 		if (rv != 0) {
8320 			DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed "
8321 				"(rv %d)", name, ldcp->ldc_id, rv);
8322 			goto setup_ring_cleanup;
8323 		}
8324 		priv_addr->bound = 1;
8325 
8326 		D2(vswp, "%s: %d: memcookie 0 : addr 0x%llx : size 0x%llx",
8327 			name, i, priv_addr->memcookie[0].addr,
8328 			priv_addr->memcookie[0].size);
8329 
8330 		if (ncookies >= (uint32_t)(VSW_MAX_COOKIES + 1)) {
8331 			DERR(vswp, "%s(%lld) ldc_mem_bind_handle returned "
8332 				"invalid num of cookies (%d) for size 0x%llx",
8333 				name, ldcp->ldc_id, ncookies,
8334 				VSW_RING_EL_DATA_SZ);
8335 
8336 			goto setup_ring_cleanup;
8337 		} else {
8338 			for (j = 1; j < ncookies; j++) {
8339 				rv = ldc_mem_nextcookie(priv_addr->memhandle,
8340 					&(priv_addr->memcookie[j]));
8341 				if (rv != 0) {
8342 					DERR(vswp, "%s: ldc_mem_nextcookie "
8343 						"failed rv (%d)", name, rv);
8344 					goto setup_ring_cleanup;
8345 				}
8346 				D3(vswp, "%s: memcookie %d : addr 0x%llx : "
8347 					"size 0x%llx", name, j,
8348 					priv_addr->memcookie[j].addr,
8349 					priv_addr->memcookie[j].size);
8350 			}
8351 
8352 		}
8353 		priv_addr->ncookies = ncookies;
8354 		priv_addr->dstate = VIO_DESC_FREE;
8355 
8356 		if (pub_addr != NULL) {
8357 
8358 			/* link pub and private sides */
8359 			priv_addr->descp = pub_addr;
8360 
8361 			pub_addr->ncookies = priv_addr->ncookies;
8362 
8363 			for (nc = 0; nc < pub_addr->ncookies; nc++) {
8364 				bcopy(&priv_addr->memcookie[nc],
8365 					&pub_addr->memcookie[nc],
8366 					sizeof (ldc_mem_cookie_t));
8367 			}
8368 
8369 			pub_addr->hdr.dstate = VIO_DESC_FREE;
8370 			pub_addr++;
8371 		}
8372 
8373 		/*
8374 		 * move to next element in the dring and the next
8375 		 * position in the data buffer.
8376 		 */
8377 		priv_addr++;
8378 		tmpp += offset;
8379 	}
8380 
8381 	return (0);
8382 
8383 setup_ring_cleanup:
8384 	priv_addr = dp->priv_addr;
8385 
8386 	for (j = 0; j < i; j++) {
8387 		(void) ldc_mem_unbind_handle(priv_addr->memhandle);
8388 		(void) ldc_mem_free_handle(priv_addr->memhandle);
8389 
8390 		mutex_destroy(&priv_addr->dstate_lock);
8391 
8392 		priv_addr++;
8393 	}
8394 	kmem_free(dp->data_addr, dp->data_sz);
8395 
8396 	return (1);
8397 }
8398 
8399 /*
8400  * Searches the private section of a ring for a free descriptor,
8401  * starting at the location of the last free descriptor found
8402  * previously.
8403  *
8404  * Returns 0 if free descriptor is available, and updates state
8405  * of private descriptor to VIO_DESC_READY,  otherwise returns 1.
8406  *
8407  * FUTURE: might need to return contiguous range of descriptors
8408  * as dring info msg assumes all will be contiguous.
8409  */
8410 static int
8411 vsw_dring_find_free_desc(dring_info_t *dringp,
8412 		vsw_private_desc_t **priv_p, int *idx)
8413 {
8414 	vsw_private_desc_t	*addr = NULL;
8415 	int			num = VSW_RING_NUM_EL;
8416 	int			ret = 1;
8417 
8418 	D1(NULL, "%s enter\n", __func__);
8419 
8420 	ASSERT(dringp->priv_addr != NULL);
8421 
8422 	D2(NULL, "%s: searching ring, dringp 0x%llx : start pos %lld",
8423 			__func__, dringp, dringp->end_idx);
8424 
8425 	addr = (vsw_private_desc_t *)dringp->priv_addr + dringp->end_idx;
8426 
8427 	mutex_enter(&addr->dstate_lock);
8428 	if (addr->dstate == VIO_DESC_FREE) {
8429 		addr->dstate = VIO_DESC_READY;
8430 		*priv_p = addr;
8431 		*idx = dringp->end_idx;
8432 		dringp->end_idx = (dringp->end_idx + 1) % num;
8433 		ret = 0;
8434 
8435 	}
8436 	mutex_exit(&addr->dstate_lock);
8437 
8438 	/* ring full */
8439 	if (ret == 1) {
8440 		D2(NULL, "%s: no desp free: started at %d", __func__,
8441 			dringp->end_idx);
8442 	}
8443 
8444 	D1(NULL, "%s: exit\n", __func__);
8445 
8446 	return (ret);
8447 }
8448 
8449 /*
8450  * Map from a dring identifier to the ring itself. Returns
8451  * pointer to ring or NULL if no match found.
8452  *
8453  * Should be called with dlistrw rwlock held as reader.
8454  */
8455 static dring_info_t *
8456 vsw_ident2dring(lane_t *lane, uint64_t ident)
8457 {
8458 	dring_info_t	*dp = NULL;
8459 
8460 	if ((dp = lane->dringp) == NULL) {
8461 		return (NULL);
8462 	} else {
8463 		if (dp->ident == ident)
8464 			return (dp);
8465 
8466 		while (dp != NULL) {
8467 			if (dp->ident == ident)
8468 				break;
8469 			dp = dp->next;
8470 		}
8471 	}
8472 
8473 	return (dp);
8474 }
8475 
8476 /*
8477  * Set the default lane attributes. These are copied into
8478  * the attr msg we send to our peer. If they are not acceptable
8479  * then (currently) the handshake ends.
8480  */
8481 static void
8482 vsw_set_lane_attr(vsw_t *vswp, lane_t *lp)
8483 {
8484 	bzero(lp, sizeof (lane_t));
8485 
8486 	READ_ENTER(&vswp->if_lockrw);
8487 	ether_copy(&(vswp->if_addr), &(lp->addr));
8488 	RW_EXIT(&vswp->if_lockrw);
8489 
8490 	lp->mtu = VSW_MTU;
8491 	lp->addr_type = ADDR_TYPE_MAC;
8492 	lp->xfer_mode = VIO_DRING_MODE;
8493 	lp->ack_freq = 0;	/* for shared mode */
8494 
8495 	mutex_enter(&lp->seq_lock);
8496 	lp->seq_num = VNET_ISS;
8497 	mutex_exit(&lp->seq_lock);
8498 }
8499 
8500 /*
8501  * Verify that the attributes are acceptable.
8502  *
8503  * FUTURE: If some attributes are not acceptable, change them
8504  * our desired values.
8505  */
8506 static int
8507 vsw_check_attr(vnet_attr_msg_t *pkt, vsw_port_t *port)
8508 {
8509 	int	ret = 0;
8510 
8511 	D1(NULL, "vsw_check_attr enter\n");
8512 
8513 	/*
8514 	 * Note we currently only support in-band descriptors
8515 	 * and descriptor rings, not packet based transfer (VIO_PKT_MODE)
8516 	 */
8517 	if ((pkt->xfer_mode != VIO_DESC_MODE) &&
8518 			(pkt->xfer_mode != VIO_DRING_MODE)) {
8519 		D2(NULL, "vsw_check_attr: unknown mode %x\n",
8520 			pkt->xfer_mode);
8521 		ret = 1;
8522 	}
8523 
8524 	/* Only support MAC addresses at moment. */
8525 	if ((pkt->addr_type != ADDR_TYPE_MAC) || (pkt->addr == 0)) {
8526 		D2(NULL, "vsw_check_attr: invalid addr_type %x, "
8527 			"or address 0x%llx\n", pkt->addr_type,
8528 			pkt->addr);
8529 		ret = 1;
8530 	}
8531 
8532 	/*
8533 	 * MAC address supplied by device should match that stored
8534 	 * in the vsw-port OBP node. Need to decide what to do if they
8535 	 * don't match, for the moment just warn but don't fail.
8536 	 */
8537 	if (bcmp(&pkt->addr, &port->p_macaddr, ETHERADDRL) != 0) {
8538 		DERR(NULL, "vsw_check_attr: device supplied address "
8539 			"0x%llx doesn't match node address 0x%llx\n",
8540 			pkt->addr, port->p_macaddr);
8541 	}
8542 
8543 	/*
8544 	 * Ack freq only makes sense in pkt mode, in shared
8545 	 * mode the ring descriptors say whether or not to
8546 	 * send back an ACK.
8547 	 */
8548 	if ((pkt->xfer_mode == VIO_DRING_MODE) &&
8549 				(pkt->ack_freq > 0)) {
8550 		D2(NULL, "vsw_check_attr: non zero ack freq "
8551 			" in SHM mode\n");
8552 		ret = 1;
8553 	}
8554 
8555 	/*
8556 	 * Note: for the moment we only support ETHER
8557 	 * frames. This may change in the future.
8558 	 */
8559 	if ((pkt->mtu > VSW_MTU) || (pkt->mtu <= 0)) {
8560 		D2(NULL, "vsw_check_attr: invalid MTU (0x%llx)\n",
8561 			pkt->mtu);
8562 		ret = 1;
8563 	}
8564 
8565 	D1(NULL, "vsw_check_attr exit\n");
8566 
8567 	return (ret);
8568 }
8569 
8570 /*
8571  * Returns 1 if there is a problem, 0 otherwise.
8572  */
8573 static int
8574 vsw_check_dring_info(vio_dring_reg_msg_t *pkt)
8575 {
8576 	_NOTE(ARGUNUSED(pkt))
8577 
8578 	int	ret = 0;
8579 
8580 	D1(NULL, "vsw_check_dring_info enter\n");
8581 
8582 	if ((pkt->num_descriptors == 0) ||
8583 		(pkt->descriptor_size == 0) ||
8584 		(pkt->ncookies != 1)) {
8585 		DERR(NULL, "vsw_check_dring_info: invalid dring msg");
8586 		ret = 1;
8587 	}
8588 
8589 	D1(NULL, "vsw_check_dring_info exit\n");
8590 
8591 	return (ret);
8592 }
8593 
8594 /*
8595  * Returns 1 if two memory cookies match. Otherwise returns 0.
8596  */
8597 static int
8598 vsw_mem_cookie_match(ldc_mem_cookie_t *m1, ldc_mem_cookie_t *m2)
8599 {
8600 	if ((m1->addr != m2->addr) ||
8601 		(m2->size != m2->size)) {
8602 		return (0);
8603 	} else {
8604 		return (1);
8605 	}
8606 }
8607 
8608 /*
8609  * Returns 1 if ring described in reg message matches that
8610  * described by dring_info structure. Otherwise returns 0.
8611  */
8612 static int
8613 vsw_dring_match(dring_info_t *dp, vio_dring_reg_msg_t *msg)
8614 {
8615 	if ((msg->descriptor_size != dp->descriptor_size) ||
8616 		(msg->num_descriptors != dp->num_descriptors) ||
8617 		(msg->ncookies != dp->ncookies) ||
8618 		!(vsw_mem_cookie_match(&msg->cookie[0], &dp->cookie[0]))) {
8619 		return (0);
8620 	} else {
8621 		return (1);
8622 	}
8623 
8624 }
8625 
8626 static caddr_t
8627 vsw_print_ethaddr(uint8_t *a, char *ebuf)
8628 {
8629 	(void) sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
8630 	    a[0], a[1], a[2], a[3], a[4], a[5]);
8631 	return (ebuf);
8632 }
8633 
8634 /*
8635  * Reset and free all the resources associated with
8636  * the channel.
8637  */
8638 static void
8639 vsw_free_lane_resources(vsw_ldc_t *ldcp, uint64_t dir)
8640 {
8641 	dring_info_t		*dp, *dpp;
8642 	lane_t			*lp = NULL;
8643 	int			rv = 0;
8644 
8645 	ASSERT(ldcp != NULL);
8646 
8647 	D1(ldcp->ldc_vswp, "%s (%lld): enter", __func__, ldcp->ldc_id);
8648 
8649 	if (dir == INBOUND) {
8650 		D2(ldcp->ldc_vswp, "%s: freeing INBOUND lane"
8651 			" of channel %lld", __func__, ldcp->ldc_id);
8652 		lp = &ldcp->lane_in;
8653 	} else {
8654 		D2(ldcp->ldc_vswp, "%s: freeing OUTBOUND lane"
8655 			" of channel %lld", __func__, ldcp->ldc_id);
8656 		lp = &ldcp->lane_out;
8657 	}
8658 
8659 	lp->lstate = VSW_LANE_INACTIV;
8660 	mutex_enter(&lp->seq_lock);
8661 	lp->seq_num = VNET_ISS;
8662 	mutex_exit(&lp->seq_lock);
8663 	if (lp->dringp) {
8664 		if (dir == INBOUND) {
8665 			WRITE_ENTER(&lp->dlistrw);
8666 			dp = lp->dringp;
8667 			while (dp != NULL) {
8668 				dpp = dp->next;
8669 				if (dp->handle != NULL)
8670 					(void) ldc_mem_dring_unmap(dp->handle);
8671 				kmem_free(dp, sizeof (dring_info_t));
8672 				dp = dpp;
8673 			}
8674 			RW_EXIT(&lp->dlistrw);
8675 		} else {
8676 			/*
8677 			 * unbind, destroy exported dring, free dring struct
8678 			 */
8679 			WRITE_ENTER(&lp->dlistrw);
8680 			dp = lp->dringp;
8681 			rv = vsw_free_ring(dp);
8682 			RW_EXIT(&lp->dlistrw);
8683 		}
8684 		if (rv == 0) {
8685 			lp->dringp = NULL;
8686 		}
8687 	}
8688 
8689 	D1(ldcp->ldc_vswp, "%s (%lld): exit", __func__, ldcp->ldc_id);
8690 }
8691 
8692 /*
8693  * Free ring and all associated resources.
8694  *
8695  * Should be called with dlistrw rwlock held as writer.
8696  */
8697 static int
8698 vsw_free_ring(dring_info_t *dp)
8699 {
8700 	vsw_private_desc_t	*paddr = NULL;
8701 	dring_info_t		*dpp;
8702 	int			i, rv = 1;
8703 
8704 	while (dp != NULL) {
8705 		mutex_enter(&dp->dlock);
8706 		dpp = dp->next;
8707 		if (dp->priv_addr != NULL) {
8708 			/*
8709 			 * First unbind and free the memory handles
8710 			 * stored in each descriptor within the ring.
8711 			 */
8712 			for (i = 0; i < VSW_RING_NUM_EL; i++) {
8713 				paddr = (vsw_private_desc_t *)
8714 						dp->priv_addr + i;
8715 				if (paddr->memhandle != NULL) {
8716 					if (paddr->bound == 1) {
8717 						rv = ldc_mem_unbind_handle(
8718 							paddr->memhandle);
8719 
8720 						if (rv != 0) {
8721 							DERR(NULL, "error "
8722 							"unbinding handle for "
8723 							"ring 0x%llx at pos %d",
8724 							dp, i);
8725 							mutex_exit(&dp->dlock);
8726 							return (rv);
8727 						}
8728 						paddr->bound = 0;
8729 					}
8730 
8731 					rv = ldc_mem_free_handle(
8732 							paddr->memhandle);
8733 					if (rv != 0) {
8734 						DERR(NULL, "error freeing "
8735 							"handle for ring "
8736 							"0x%llx at pos %d",
8737 							dp, i);
8738 						mutex_exit(&dp->dlock);
8739 						return (rv);
8740 					}
8741 					paddr->memhandle = NULL;
8742 				}
8743 				mutex_destroy(&paddr->dstate_lock);
8744 			}
8745 			kmem_free(dp->priv_addr, (sizeof (vsw_private_desc_t)
8746 					* VSW_RING_NUM_EL));
8747 		}
8748 
8749 		/*
8750 		 * Now unbind and destroy the ring itself.
8751 		 */
8752 		if (dp->handle != NULL) {
8753 			(void) ldc_mem_dring_unbind(dp->handle);
8754 			(void) ldc_mem_dring_destroy(dp->handle);
8755 		}
8756 
8757 		if (dp->data_addr != NULL) {
8758 			kmem_free(dp->data_addr, dp->data_sz);
8759 		}
8760 
8761 		mutex_exit(&dp->dlock);
8762 		mutex_destroy(&dp->dlock);
8763 		mutex_destroy(&dp->restart_lock);
8764 		kmem_free(dp, sizeof (dring_info_t));
8765 
8766 		dp = dpp;
8767 	}
8768 	return (0);
8769 }
8770 
8771 /*
8772  * Debugging routines
8773  */
8774 static void
8775 display_state(void)
8776 {
8777 	vsw_t		*vswp;
8778 	vsw_port_list_t	*plist;
8779 	vsw_port_t 	*port;
8780 	vsw_ldc_list_t	*ldcl;
8781 	vsw_ldc_t 	*ldcp;
8782 
8783 	cmn_err(CE_NOTE, "***** system state *****");
8784 
8785 	for (vswp = vsw_head; vswp; vswp = vswp->next) {
8786 		plist = &vswp->plist;
8787 		READ_ENTER(&plist->lockrw);
8788 		cmn_err(CE_CONT, "vsw instance %d has %d ports attached\n",
8789 			vswp->instance, plist->num_ports);
8790 
8791 		for (port = plist->head; port != NULL; port = port->p_next) {
8792 			ldcl = &port->p_ldclist;
8793 			cmn_err(CE_CONT, "port %d : %d ldcs attached\n",
8794 				port->p_instance, ldcl->num_ldcs);
8795 			READ_ENTER(&ldcl->lockrw);
8796 			ldcp = ldcl->head;
8797 			for (; ldcp != NULL; ldcp = ldcp->ldc_next) {
8798 				cmn_err(CE_CONT, "chan %lu : dev %d : "
8799 					"status %d : phase %u\n",
8800 					ldcp->ldc_id, ldcp->dev_class,
8801 					ldcp->ldc_status, ldcp->hphase);
8802 				cmn_err(CE_CONT, "chan %lu : lsession %lu : "
8803 					"psession %lu\n",
8804 					ldcp->ldc_id,
8805 					ldcp->local_session,
8806 					ldcp->peer_session);
8807 
8808 				cmn_err(CE_CONT, "Inbound lane:\n");
8809 				display_lane(&ldcp->lane_in);
8810 				cmn_err(CE_CONT, "Outbound lane:\n");
8811 				display_lane(&ldcp->lane_out);
8812 			}
8813 			RW_EXIT(&ldcl->lockrw);
8814 		}
8815 		RW_EXIT(&plist->lockrw);
8816 	}
8817 	cmn_err(CE_NOTE, "***** system state *****");
8818 }
8819 
8820 static void
8821 display_lane(lane_t *lp)
8822 {
8823 	dring_info_t	*drp;
8824 
8825 	cmn_err(CE_CONT, "ver 0x%x:0x%x : state %lx : mtu 0x%lx\n",
8826 		lp->ver_major, lp->ver_minor, lp->lstate, lp->mtu);
8827 	cmn_err(CE_CONT, "addr_type %d : addr 0x%lx : xmode %d\n",
8828 		lp->addr_type, lp->addr, lp->xfer_mode);
8829 	cmn_err(CE_CONT, "dringp 0x%lx\n", (uint64_t)lp->dringp);
8830 
8831 	cmn_err(CE_CONT, "Dring info:\n");
8832 	for (drp = lp->dringp; drp != NULL; drp = drp->next) {
8833 		cmn_err(CE_CONT, "\tnum_desc %u : dsize %u\n",
8834 			drp->num_descriptors, drp->descriptor_size);
8835 		cmn_err(CE_CONT, "\thandle 0x%lx\n", drp->handle);
8836 		cmn_err(CE_CONT, "\tpub_addr 0x%lx : priv_addr 0x%lx\n",
8837 			(uint64_t)drp->pub_addr, (uint64_t)drp->priv_addr);
8838 		cmn_err(CE_CONT, "\tident 0x%lx : end_idx %lu\n",
8839 			drp->ident, drp->end_idx);
8840 		display_ring(drp);
8841 	}
8842 }
8843 
8844 static void
8845 display_ring(dring_info_t *dringp)
8846 {
8847 	uint64_t		i;
8848 	uint64_t		priv_count = 0;
8849 	uint64_t		pub_count = 0;
8850 	vnet_public_desc_t	*pub_addr = NULL;
8851 	vsw_private_desc_t	*priv_addr = NULL;
8852 
8853 	for (i = 0; i < VSW_RING_NUM_EL; i++) {
8854 		if (dringp->pub_addr != NULL) {
8855 			pub_addr = (vnet_public_desc_t *)dringp->pub_addr + i;
8856 
8857 			if (pub_addr->hdr.dstate == VIO_DESC_FREE)
8858 				pub_count++;
8859 		}
8860 
8861 		if (dringp->priv_addr != NULL) {
8862 			priv_addr =
8863 				(vsw_private_desc_t *)dringp->priv_addr + i;
8864 
8865 			if (priv_addr->dstate == VIO_DESC_FREE)
8866 				priv_count++;
8867 		}
8868 	}
8869 	cmn_err(CE_CONT, "\t%lu elements: %lu priv free: %lu pub free\n",
8870 			i, priv_count, pub_count);
8871 }
8872 
8873 static void
8874 dump_flags(uint64_t state)
8875 {
8876 	int	i;
8877 
8878 	typedef struct flag_name {
8879 		int	flag_val;
8880 		char	*flag_name;
8881 	} flag_name_t;
8882 
8883 	flag_name_t	flags[] = {
8884 		VSW_VER_INFO_SENT, "VSW_VER_INFO_SENT",
8885 		VSW_VER_INFO_RECV, "VSW_VER_INFO_RECV",
8886 		VSW_VER_ACK_RECV, "VSW_VER_ACK_RECV",
8887 		VSW_VER_ACK_SENT, "VSW_VER_ACK_SENT",
8888 		VSW_VER_NACK_RECV, "VSW_VER_NACK_RECV",
8889 		VSW_VER_NACK_SENT, "VSW_VER_NACK_SENT",
8890 		VSW_ATTR_INFO_SENT, "VSW_ATTR_INFO_SENT",
8891 		VSW_ATTR_INFO_RECV, "VSW_ATTR_INFO_RECV",
8892 		VSW_ATTR_ACK_SENT, "VSW_ATTR_ACK_SENT",
8893 		VSW_ATTR_ACK_RECV, "VSW_ATTR_ACK_RECV",
8894 		VSW_ATTR_NACK_SENT, "VSW_ATTR_NACK_SENT",
8895 		VSW_ATTR_NACK_RECV, "VSW_ATTR_NACK_RECV",
8896 		VSW_DRING_INFO_SENT, "VSW_DRING_INFO_SENT",
8897 		VSW_DRING_INFO_RECV, "VSW_DRING_INFO_RECV",
8898 		VSW_DRING_ACK_SENT, "VSW_DRING_ACK_SENT",
8899 		VSW_DRING_ACK_RECV, "VSW_DRING_ACK_RECV",
8900 		VSW_DRING_NACK_SENT, "VSW_DRING_NACK_SENT",
8901 		VSW_DRING_NACK_RECV, "VSW_DRING_NACK_RECV",
8902 		VSW_RDX_INFO_SENT, "VSW_RDX_INFO_SENT",
8903 		VSW_RDX_INFO_RECV, "VSW_RDX_INFO_RECV",
8904 		VSW_RDX_ACK_SENT, "VSW_RDX_ACK_SENT",
8905 		VSW_RDX_ACK_RECV, "VSW_RDX_ACK_RECV",
8906 		VSW_RDX_NACK_SENT, "VSW_RDX_NACK_SENT",
8907 		VSW_RDX_NACK_RECV, "VSW_RDX_NACK_RECV",
8908 		VSW_MCST_INFO_SENT, "VSW_MCST_INFO_SENT",
8909 		VSW_MCST_INFO_RECV, "VSW_MCST_INFO_RECV",
8910 		VSW_MCST_ACK_SENT, "VSW_MCST_ACK_SENT",
8911 		VSW_MCST_ACK_RECV, "VSW_MCST_ACK_RECV",
8912 		VSW_MCST_NACK_SENT, "VSW_MCST_NACK_SENT",
8913 		VSW_MCST_NACK_RECV, "VSW_MCST_NACK_RECV",
8914 		VSW_LANE_ACTIVE, "VSW_LANE_ACTIVE"};
8915 
8916 	DERR(NULL, "DUMP_FLAGS: %llx\n", state);
8917 	for (i = 0; i < sizeof (flags)/sizeof (flag_name_t); i++) {
8918 		if (state & flags[i].flag_val)
8919 			DERR(NULL, "DUMP_FLAGS %s", flags[i].flag_name);
8920 	}
8921 }
8922