1*b494511aSVenki Rajagopalan /*
2*b494511aSVenki Rajagopalan  * CDDL HEADER START
3*b494511aSVenki Rajagopalan  *
4*b494511aSVenki Rajagopalan  * The contents of this file are subject to the terms of the
5*b494511aSVenki Rajagopalan  * Common Development and Distribution License (the "License").
6*b494511aSVenki Rajagopalan  * You may not use this file except in compliance with the License.
7*b494511aSVenki Rajagopalan  *
8*b494511aSVenki Rajagopalan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*b494511aSVenki Rajagopalan  * or http://www.opensolaris.org/os/licensing.
10*b494511aSVenki Rajagopalan  * See the License for the specific language governing permissions
11*b494511aSVenki Rajagopalan  * and limitations under the License.
12*b494511aSVenki Rajagopalan  *
13*b494511aSVenki Rajagopalan  * When distributing Covered Code, include this CDDL HEADER in each
14*b494511aSVenki Rajagopalan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*b494511aSVenki Rajagopalan  * If applicable, add the following below this CDDL HEADER, with the
16*b494511aSVenki Rajagopalan  * fields enclosed by brackets "[]" replaced with your own identifying
17*b494511aSVenki Rajagopalan  * information: Portions Copyright [yyyy] [name of copyright owner]
18*b494511aSVenki Rajagopalan  *
19*b494511aSVenki Rajagopalan  * CDDL HEADER END
20*b494511aSVenki Rajagopalan  */
21*b494511aSVenki Rajagopalan 
22*b494511aSVenki Rajagopalan /*
23*b494511aSVenki Rajagopalan  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*b494511aSVenki Rajagopalan  */
25*b494511aSVenki Rajagopalan 
26*b494511aSVenki Rajagopalan #include <sys/types.h>
27*b494511aSVenki Rajagopalan #include <sys/kmem.h>
28*b494511aSVenki Rajagopalan #include <sys/conf.h>
29*b494511aSVenki Rajagopalan #include <sys/ddi.h>
30*b494511aSVenki Rajagopalan #include <sys/sunddi.h>
31*b494511aSVenki Rajagopalan #include <sys/ksynch.h>
32*b494511aSVenki Rajagopalan 
33*b494511aSVenki Rajagopalan #include <sys/ib/clients/eoib/eib_impl.h>
34*b494511aSVenki Rajagopalan 
35*b494511aSVenki Rajagopalan /*
36*b494511aSVenki Rajagopalan  * Declarations private to this file
37*b494511aSVenki Rajagopalan  */
38*b494511aSVenki Rajagopalan static int eib_vnic_get_instance(eib_t *, int *);
39*b494511aSVenki Rajagopalan static void eib_vnic_ret_instance(eib_t *, int);
40*b494511aSVenki Rajagopalan static void eib_vnic_modify_enter(eib_t *, uint_t);
41*b494511aSVenki Rajagopalan static void eib_vnic_modify_exit(eib_t *, uint_t);
42*b494511aSVenki Rajagopalan static int eib_vnic_create_common(eib_t *, eib_vnic_t *, int *);
43*b494511aSVenki Rajagopalan static int eib_vnic_set_partition(eib_t *, eib_vnic_t *, int *);
44*b494511aSVenki Rajagopalan static void eib_vnic_make_vhub_mgid(uint8_t *, uint8_t, uint8_t *, uint8_t,
45*b494511aSVenki Rajagopalan     uint8_t, uint32_t, ib_gid_t *);
46*b494511aSVenki Rajagopalan static int eib_vnic_attach_ctl_mcgs(eib_t *, eib_vnic_t *, int *);
47*b494511aSVenki Rajagopalan static int eib_vnic_attach_vhub_table(eib_t *, eib_vnic_t *);
48*b494511aSVenki Rajagopalan static int eib_vnic_attach_vhub_update(eib_t *, eib_vnic_t *);
49*b494511aSVenki Rajagopalan static void eib_vnic_start_keepalives(eib_t *, eib_vnic_t *);
50*b494511aSVenki Rajagopalan static int eib_vnic_lookup_dest(eib_vnic_t *, uint8_t *, uint16_t,
51*b494511aSVenki Rajagopalan     eib_vhub_map_t *, ibt_mcg_info_t *, int *);
52*b494511aSVenki Rajagopalan static void eib_vnic_leave_all_data_mcgs(eib_t *, eib_vnic_t *);
53*b494511aSVenki Rajagopalan static void eib_vnic_rejoin_data_mcgs(eib_t *, eib_vnic_t *);
54*b494511aSVenki Rajagopalan static void eib_vnic_reattach_ctl_mcgs(eib_t *, eib_vnic_t *);
55*b494511aSVenki Rajagopalan static void eib_rb_vnic_create_common(eib_t *, eib_vnic_t *, uint_t);
56*b494511aSVenki Rajagopalan static void eib_rb_vnic_attach_ctl_mcgs(eib_t *, eib_vnic_t *);
57*b494511aSVenki Rajagopalan static void eib_rb_vnic_attach_vhub_table(eib_t *, eib_vnic_t *);
58*b494511aSVenki Rajagopalan static void eib_rb_vnic_attach_vhub_update(eib_t *, eib_vnic_t *);
59*b494511aSVenki Rajagopalan static void eib_rb_vnic_start_keepalives(eib_t *, eib_vnic_t *);
60*b494511aSVenki Rajagopalan static void eib_rb_vnic_join_data_mcg(eib_t *, eib_vnic_t *, uint8_t *);
61*b494511aSVenki Rajagopalan 
62*b494511aSVenki Rajagopalan /*
63*b494511aSVenki Rajagopalan  * Definitions private to this file
64*b494511aSVenki Rajagopalan  */
65*b494511aSVenki Rajagopalan #define	EIB_VNIC_STRUCT_ALLOCD		0x0001
66*b494511aSVenki Rajagopalan #define	EIB_VNIC_GOT_INSTANCE		0x0002
67*b494511aSVenki Rajagopalan #define	EIB_VNIC_CREATE_COMMON_DONE	0x0004
68*b494511aSVenki Rajagopalan #define	EIB_VNIC_CTLQP_CREATED		0x0008
69*b494511aSVenki Rajagopalan #define	EIB_VNIC_DATAQP_CREATED		0x0010
70*b494511aSVenki Rajagopalan #define	EIB_VNIC_LOGIN_DONE		0x0020
71*b494511aSVenki Rajagopalan #define	EIB_VNIC_PARTITION_SET		0x0040
72*b494511aSVenki Rajagopalan #define	EIB_VNIC_RX_POSTED_TO_CTLQP	0x0080
73*b494511aSVenki Rajagopalan #define	EIB_VNIC_RX_POSTED_TO_DATAQP	0x0100
74*b494511aSVenki Rajagopalan #define	EIB_VNIC_ATTACHED_TO_CTL_MCGS	0x0200
75*b494511aSVenki Rajagopalan #define	EIB_VNIC_GOT_VHUB_TABLE		0x0400
76*b494511aSVenki Rajagopalan #define	EIB_VNIC_KEEPALIVES_STARTED	0x0800
77*b494511aSVenki Rajagopalan #define	EIB_VNIC_BROADCAST_JOINED	0x1000
78*b494511aSVenki Rajagopalan 
79*b494511aSVenki Rajagopalan /*
80*b494511aSVenki Rajagopalan  * Destination type
81*b494511aSVenki Rajagopalan  */
82*b494511aSVenki Rajagopalan #define	EIB_TX_UNICAST			1
83*b494511aSVenki Rajagopalan #define	EIB_TX_MULTICAST		2
84*b494511aSVenki Rajagopalan #define	EIB_TX_BROADCAST		3
85*b494511aSVenki Rajagopalan 
86*b494511aSVenki Rajagopalan int
eib_vnic_create(eib_t * ss,uint8_t * macaddr,uint16_t vlan,eib_vnic_t ** vnicp,int * err)87*b494511aSVenki Rajagopalan eib_vnic_create(eib_t *ss, uint8_t *macaddr, uint16_t vlan, eib_vnic_t **vnicp,
88*b494511aSVenki Rajagopalan     int *err)
89*b494511aSVenki Rajagopalan {
90*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic = NULL;
91*b494511aSVenki Rajagopalan 	boolean_t failed_vnic = B_FALSE;
92*b494511aSVenki Rajagopalan 	uint_t progress = 0;
93*b494511aSVenki Rajagopalan 
94*b494511aSVenki Rajagopalan 	eib_vnic_modify_enter(ss, EIB_VN_BEING_CREATED);
95*b494511aSVenki Rajagopalan 
96*b494511aSVenki Rajagopalan 	/*
97*b494511aSVenki Rajagopalan 	 * When a previously created vnic is being resurrected due to a
98*b494511aSVenki Rajagopalan 	 * gateway reboot, there's a race possible where a creation request
99*b494511aSVenki Rajagopalan 	 * for the existing vnic could get filed with the vnic creator
100*b494511aSVenki Rajagopalan 	 * thread. So, before we go ahead with the creation of this vnic,
101*b494511aSVenki Rajagopalan 	 * make sure we already don't have the vnic.
102*b494511aSVenki Rajagopalan 	 */
103*b494511aSVenki Rajagopalan 	if (macaddr) {
104*b494511aSVenki Rajagopalan 		if (eib_data_lookup_vnic(ss, macaddr, vlan, vnicp,
105*b494511aSVenki Rajagopalan 		    &failed_vnic) == EIB_E_SUCCESS) {
106*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_create: "
107*b494511aSVenki Rajagopalan 			    "vnic for mac=%x:%x:%x:%x:%x:%x, vlan=0x%x "
108*b494511aSVenki Rajagopalan 			    "already there, no duplicate creation", macaddr[0],
109*b494511aSVenki Rajagopalan 			    macaddr[1], macaddr[2], macaddr[3], macaddr[4],
110*b494511aSVenki Rajagopalan 			    macaddr[5], vlan);
111*b494511aSVenki Rajagopalan 
112*b494511aSVenki Rajagopalan 			eib_vnic_modify_exit(ss, EIB_VN_BEING_CREATED);
113*b494511aSVenki Rajagopalan 			return (EIB_E_SUCCESS);
114*b494511aSVenki Rajagopalan 		} else if (failed_vnic) {
115*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_create: "
116*b494511aSVenki Rajagopalan 			    "vnic for mac=%x:%x:%x:%x:%x:%x, vlan=0x%x "
117*b494511aSVenki Rajagopalan 			    "failed earlier, shouldn't be here at all",
118*b494511aSVenki Rajagopalan 			    macaddr[0], macaddr[1], macaddr[2], macaddr[3],
119*b494511aSVenki Rajagopalan 			    macaddr[4], macaddr[5], vlan);
120*b494511aSVenki Rajagopalan 
121*b494511aSVenki Rajagopalan 			*err = EEXIST;
122*b494511aSVenki Rajagopalan 
123*b494511aSVenki Rajagopalan 			eib_vnic_modify_exit(ss, EIB_VN_BEING_CREATED);
124*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
125*b494511aSVenki Rajagopalan 		}
126*b494511aSVenki Rajagopalan 	}
127*b494511aSVenki Rajagopalan 
128*b494511aSVenki Rajagopalan 	/*
129*b494511aSVenki Rajagopalan 	 * Allocate a vnic structure for this instance
130*b494511aSVenki Rajagopalan 	 */
131*b494511aSVenki Rajagopalan 	vnic = kmem_zalloc(sizeof (eib_vnic_t), KM_SLEEP);
132*b494511aSVenki Rajagopalan 	vnic->vn_ss = ss;
133*b494511aSVenki Rajagopalan 	vnic->vn_instance = -1;
134*b494511aSVenki Rajagopalan 	mutex_init(&vnic->vn_lock, NULL, MUTEX_DRIVER, NULL);
135*b494511aSVenki Rajagopalan 	cv_init(&vnic->vn_cv, NULL, CV_DEFAULT, NULL);
136*b494511aSVenki Rajagopalan 
137*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_STRUCT_ALLOCD;
138*b494511aSVenki Rajagopalan 
139*b494511aSVenki Rajagopalan 	/*
140*b494511aSVenki Rajagopalan 	 * Get a vnic instance
141*b494511aSVenki Rajagopalan 	 */
142*b494511aSVenki Rajagopalan 	if (eib_vnic_get_instance(ss, &vnic->vn_instance) != EIB_E_SUCCESS) {
143*b494511aSVenki Rajagopalan 		*err = EMFILE;
144*b494511aSVenki Rajagopalan 		goto vnic_create_fail;
145*b494511aSVenki Rajagopalan 	}
146*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_GOT_INSTANCE;
147*b494511aSVenki Rajagopalan 
148*b494511aSVenki Rajagopalan 	/*
149*b494511aSVenki Rajagopalan 	 * Initialize vnic's basic parameters.  Note that we set the 15-bit
150*b494511aSVenki Rajagopalan 	 * vnic id to send to gw during a login to be a 2-tuple of
151*b494511aSVenki Rajagopalan 	 * {devi_instance#, eoib_vnic_instance#}.
152*b494511aSVenki Rajagopalan 	 */
153*b494511aSVenki Rajagopalan 	vnic->vn_vlan = vlan;
154*b494511aSVenki Rajagopalan 	if (macaddr) {
155*b494511aSVenki Rajagopalan 		bcopy(macaddr, vnic->vn_macaddr, sizeof (vnic->vn_macaddr));
156*b494511aSVenki Rajagopalan 	}
157*b494511aSVenki Rajagopalan 	vnic->vn_id = (uint16_t)EIB_VNIC_ID(ss->ei_instance, vnic->vn_instance);
158*b494511aSVenki Rajagopalan 
159*b494511aSVenki Rajagopalan 	/*
160*b494511aSVenki Rajagopalan 	 * Start up this vnic instance
161*b494511aSVenki Rajagopalan 	 */
162*b494511aSVenki Rajagopalan 	if (eib_vnic_create_common(ss, vnic, err) != EIB_E_SUCCESS)
163*b494511aSVenki Rajagopalan 		goto vnic_create_fail;
164*b494511aSVenki Rajagopalan 
165*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_CREATE_COMMON_DONE;
166*b494511aSVenki Rajagopalan 
167*b494511aSVenki Rajagopalan 	/*
168*b494511aSVenki Rajagopalan 	 * Return the created vnic
169*b494511aSVenki Rajagopalan 	 */
170*b494511aSVenki Rajagopalan 	if (vnicp) {
171*b494511aSVenki Rajagopalan 		*vnicp = vnic;
172*b494511aSVenki Rajagopalan 	}
173*b494511aSVenki Rajagopalan 
174*b494511aSVenki Rajagopalan 	eib_vnic_modify_exit(ss, EIB_VN_BEING_CREATED);
175*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
176*b494511aSVenki Rajagopalan 
177*b494511aSVenki Rajagopalan vnic_create_fail:
178*b494511aSVenki Rajagopalan 	eib_rb_vnic_create(ss, vnic, progress);
179*b494511aSVenki Rajagopalan 	eib_vnic_modify_exit(ss, EIB_VN_BEING_CREATED);
180*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
181*b494511aSVenki Rajagopalan }
182*b494511aSVenki Rajagopalan 
183*b494511aSVenki Rajagopalan void
eib_vnic_delete(eib_t * ss,eib_vnic_t * vnic)184*b494511aSVenki Rajagopalan eib_vnic_delete(eib_t *ss, eib_vnic_t *vnic)
185*b494511aSVenki Rajagopalan {
186*b494511aSVenki Rajagopalan 	eib_vnic_modify_enter(ss, EIB_VN_BEING_DELETED);
187*b494511aSVenki Rajagopalan 	eib_rb_vnic_create(ss, vnic, ~0);
188*b494511aSVenki Rajagopalan 	eib_vnic_modify_exit(ss, EIB_VN_BEING_DELETED);
189*b494511aSVenki Rajagopalan }
190*b494511aSVenki Rajagopalan 
191*b494511aSVenki Rajagopalan /*ARGSUSED*/
192*b494511aSVenki Rajagopalan int
eib_vnic_wait_for_login_ack(eib_t * ss,eib_vnic_t * vnic,int * err)193*b494511aSVenki Rajagopalan eib_vnic_wait_for_login_ack(eib_t *ss, eib_vnic_t *vnic, int *err)
194*b494511aSVenki Rajagopalan {
195*b494511aSVenki Rajagopalan 	clock_t deadline;
196*b494511aSVenki Rajagopalan 	int ret = EIB_E_SUCCESS;
197*b494511aSVenki Rajagopalan 
198*b494511aSVenki Rajagopalan 	deadline = ddi_get_lbolt() + drv_usectohz(EIB_LOGIN_TIMEOUT_USEC);
199*b494511aSVenki Rajagopalan 
200*b494511aSVenki Rajagopalan 	/*
201*b494511aSVenki Rajagopalan 	 * Wait for login ack/nack or wait time to get over. If we wake up
202*b494511aSVenki Rajagopalan 	 * with a login failure, record the reason.
203*b494511aSVenki Rajagopalan 	 */
204*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
205*b494511aSVenki Rajagopalan 	while (vnic->vn_state == EIB_LOGIN_ACK_WAIT) {
206*b494511aSVenki Rajagopalan 		if (cv_timedwait(&vnic->vn_cv, &vnic->vn_lock,
207*b494511aSVenki Rajagopalan 		    deadline) == -1) {
208*b494511aSVenki Rajagopalan 			if (vnic->vn_state == EIB_LOGIN_ACK_WAIT)
209*b494511aSVenki Rajagopalan 				vnic->vn_state = EIB_LOGIN_TIMED_OUT;
210*b494511aSVenki Rajagopalan 		}
211*b494511aSVenki Rajagopalan 	}
212*b494511aSVenki Rajagopalan 
213*b494511aSVenki Rajagopalan 	if (vnic->vn_state != EIB_LOGIN_ACK_RCVD) {
214*b494511aSVenki Rajagopalan 		ret = EIB_E_FAILURE;
215*b494511aSVenki Rajagopalan 		*err =  (vnic->vn_state == EIB_LOGIN_TIMED_OUT) ?
216*b494511aSVenki Rajagopalan 		    ETIME : ECANCELED;
217*b494511aSVenki Rajagopalan 	}
218*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
219*b494511aSVenki Rajagopalan 
220*b494511aSVenki Rajagopalan 	return (ret);
221*b494511aSVenki Rajagopalan }
222*b494511aSVenki Rajagopalan 
223*b494511aSVenki Rajagopalan void
eib_vnic_login_ack(eib_t * ss,eib_login_data_t * ld)224*b494511aSVenki Rajagopalan eib_vnic_login_ack(eib_t *ss, eib_login_data_t *ld)
225*b494511aSVenki Rajagopalan {
226*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic;
227*b494511aSVenki Rajagopalan 	uint_t vnic_instance;
228*b494511aSVenki Rajagopalan 	uint_t hdrs_sz;
229*b494511aSVenki Rajagopalan 	uint16_t vnic_id;
230*b494511aSVenki Rajagopalan 	int nack = 1;
231*b494511aSVenki Rajagopalan 
232*b494511aSVenki Rajagopalan 	/*
233*b494511aSVenki Rajagopalan 	 * The msb in the vnic id in login ack message is not
234*b494511aSVenki Rajagopalan 	 * part of our vNIC id.
235*b494511aSVenki Rajagopalan 	 */
236*b494511aSVenki Rajagopalan 	vnic_id = ld->ld_vnic_id & (~FIP_VL_VNIC_ID_MSBIT);
237*b494511aSVenki Rajagopalan 
238*b494511aSVenki Rajagopalan 	/*
239*b494511aSVenki Rajagopalan 	 * Now, we deconstruct the vnic id and determine the vnic
240*b494511aSVenki Rajagopalan 	 * instance number. If this vnic_instance number isn't
241*b494511aSVenki Rajagopalan 	 * valid or the vnic_id of the vnic for this instance
242*b494511aSVenki Rajagopalan 	 * number doesn't match in our records, we quit.
243*b494511aSVenki Rajagopalan 	 */
244*b494511aSVenki Rajagopalan 	vnic_instance = EIB_VNIC_INSTANCE(vnic_id);
245*b494511aSVenki Rajagopalan 	if (vnic_instance >= EIB_MAX_VNICS)
246*b494511aSVenki Rajagopalan 		return;
247*b494511aSVenki Rajagopalan 
248*b494511aSVenki Rajagopalan 	/*
249*b494511aSVenki Rajagopalan 	 * At this point, we haven't fully created the vnic, so
250*b494511aSVenki Rajagopalan 	 * this vnic should be present as ei_vnic_pending.
251*b494511aSVenki Rajagopalan 	 */
252*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
253*b494511aSVenki Rajagopalan 	if ((vnic = ss->ei_vnic_pending) == NULL) {
254*b494511aSVenki Rajagopalan 		mutex_exit(&ss->ei_vnic_lock);
255*b494511aSVenki Rajagopalan 		return;
256*b494511aSVenki Rajagopalan 	} else if (vnic->vn_id != vnic_id) {
257*b494511aSVenki Rajagopalan 		mutex_exit(&ss->ei_vnic_lock);
258*b494511aSVenki Rajagopalan 		return;
259*b494511aSVenki Rajagopalan 	}
260*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
261*b494511aSVenki Rajagopalan 
262*b494511aSVenki Rajagopalan 	/*
263*b494511aSVenki Rajagopalan 	 * First check if the vnic is still sleeping, waiting
264*b494511aSVenki Rajagopalan 	 * for login ack.  If not, we might as well quit now.
265*b494511aSVenki Rajagopalan 	 */
266*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
267*b494511aSVenki Rajagopalan 	if (vnic->vn_state != EIB_LOGIN_ACK_WAIT) {
268*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
269*b494511aSVenki Rajagopalan 		return;
270*b494511aSVenki Rajagopalan 	}
271*b494511aSVenki Rajagopalan 
272*b494511aSVenki Rajagopalan 	/*
273*b494511aSVenki Rajagopalan 	 * We NACK the waiter under these conditions:
274*b494511aSVenki Rajagopalan 	 *
275*b494511aSVenki Rajagopalan 	 * . syndrome was set
276*b494511aSVenki Rajagopalan 	 * . vhub mtu is bigger than our max mtu (minus eoib/eth hdrs sz)
277*b494511aSVenki Rajagopalan 	 * . assigned vlan is different from requested vlan (except
278*b494511aSVenki Rajagopalan 	 *   when we didn't request a specific vlan)
279*b494511aSVenki Rajagopalan 	 * . when the assigned mac is different from the requested mac
280*b494511aSVenki Rajagopalan 	 *   (except when we didn't request a specific mac)
281*b494511aSVenki Rajagopalan 	 * . when the VP bit indicates that vlan tag should be used
282*b494511aSVenki Rajagopalan 	 *   but we had not specified a vlan tag in our request
283*b494511aSVenki Rajagopalan 	 * . when the VP bit indicates that vlan tag should not be
284*b494511aSVenki Rajagopalan 	 *   present and we'd specified a vlan tag in our request
285*b494511aSVenki Rajagopalan 	 *
286*b494511aSVenki Rajagopalan 	 * The last case is interesting: if we had not specified any vlan id
287*b494511aSVenki Rajagopalan 	 * in our request, but the gateway has assigned a vlan and asks us
288*b494511aSVenki Rajagopalan 	 * to use/expect that tag on every packet dealt by this vnic, it
289*b494511aSVenki Rajagopalan 	 * means effectively the EoIB driver has to insert/remove vlan
290*b494511aSVenki Rajagopalan 	 * tagging on this vnic traffic, since the nw layer on Solaris
291*b494511aSVenki Rajagopalan 	 * won't be using/expecting any tag on traffic for this vnic. This
292*b494511aSVenki Rajagopalan 	 * feature is not supported currently.
293*b494511aSVenki Rajagopalan 	 */
294*b494511aSVenki Rajagopalan 	hdrs_sz = EIB_ENCAP_HDR_SZ + sizeof (struct ether_header) + VLAN_TAGSZ;
295*b494511aSVenki Rajagopalan 	if (ld->ld_syndrome) {
296*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
297*b494511aSVenki Rajagopalan 		    "non-zero syndrome 0x%lx, NACK", ld->ld_syndrome);
298*b494511aSVenki Rajagopalan 
299*b494511aSVenki Rajagopalan 	} else if (ld->ld_vhub_mtu > (ss->ei_props->ep_mtu - hdrs_sz)) {
300*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
301*b494511aSVenki Rajagopalan 		    "vhub mtu (0x%x) bigger than port mtu (0x%x), NACK",
302*b494511aSVenki Rajagopalan 		    ld->ld_vhub_mtu, ss->ei_props->ep_mtu);
303*b494511aSVenki Rajagopalan 
304*b494511aSVenki Rajagopalan 	} else if ((vnic->vn_vlan) && (vnic->vn_vlan != ld->ld_assigned_vlan)) {
305*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
306*b494511aSVenki Rajagopalan 		    "assigned vlan (0x%x) different from asked (0x%x), "
307*b494511aSVenki Rajagopalan 		    "for vnic id 0x%x, NACK", ld->ld_assigned_vlan,
308*b494511aSVenki Rajagopalan 		    vnic->vn_vlan, vnic->vn_id);
309*b494511aSVenki Rajagopalan 
310*b494511aSVenki Rajagopalan 	} else if (bcmp(vnic->vn_macaddr, eib_zero_mac, ETHERADDRL) &&
311*b494511aSVenki Rajagopalan 	    bcmp(vnic->vn_macaddr, ld->ld_assigned_mac, ETHERADDRL)) {
312*b494511aSVenki Rajagopalan 		uint8_t *asked, *got;
313*b494511aSVenki Rajagopalan 
314*b494511aSVenki Rajagopalan 		asked = vnic->vn_macaddr;
315*b494511aSVenki Rajagopalan 		got = ld->ld_assigned_mac;
316*b494511aSVenki Rajagopalan 
317*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
318*b494511aSVenki Rajagopalan 		    "assigned mac (%x:%x:%x:%x:%x:%x) different from "
319*b494511aSVenki Rajagopalan 		    "asked (%x:%x:%x:%x:%x:%x) for vnic id 0x%x, NACK",
320*b494511aSVenki Rajagopalan 		    got[0], got[1], got[2], got[3], got[4], got[5], asked[0],
321*b494511aSVenki Rajagopalan 		    asked[1], asked[2], asked[3], asked[4], asked[5]);
322*b494511aSVenki Rajagopalan 
323*b494511aSVenki Rajagopalan 	} else if ((vnic->vn_vlan == 0) && (ld->ld_vlan_in_packets)) {
324*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
325*b494511aSVenki Rajagopalan 		    "asked for tagless vlan, but VP flag is set "
326*b494511aSVenki Rajagopalan 		    "for vnic id 0x%x, NACK", vnic->vn_id);
327*b494511aSVenki Rajagopalan 
328*b494511aSVenki Rajagopalan 	} else if ((vnic->vn_vlan) && (!ld->ld_vlan_in_packets)) {
329*b494511aSVenki Rajagopalan 		if (eib_wa_no_good_vp_flag) {
330*b494511aSVenki Rajagopalan 			ld->ld_vlan_in_packets = 1;
331*b494511aSVenki Rajagopalan 			ld->ld_vhub_id = EIB_VHUB_ID(ld->ld_gw_port_id,
332*b494511aSVenki Rajagopalan 			    ld->ld_assigned_vlan);
333*b494511aSVenki Rajagopalan 			nack = 0;
334*b494511aSVenki Rajagopalan 		} else {
335*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_login_ack: "
336*b494511aSVenki Rajagopalan 			    "vlan was assigned correctly, but VP flag is not "
337*b494511aSVenki Rajagopalan 			    "set for vnic id 0x%x, NACK", vnic->vn_id);
338*b494511aSVenki Rajagopalan 		}
339*b494511aSVenki Rajagopalan 	} else {
340*b494511aSVenki Rajagopalan 		ld->ld_vhub_id = EIB_VHUB_ID(ld->ld_gw_port_id,
341*b494511aSVenki Rajagopalan 		    ld->ld_assigned_vlan);
342*b494511aSVenki Rajagopalan 		nack = 0;
343*b494511aSVenki Rajagopalan 	}
344*b494511aSVenki Rajagopalan 
345*b494511aSVenki Rajagopalan 	/*
346*b494511aSVenki Rajagopalan 	 * ACK/NACK the waiter
347*b494511aSVenki Rajagopalan 	 */
348*b494511aSVenki Rajagopalan 	if (nack) {
349*b494511aSVenki Rajagopalan 		vnic->vn_state = EIB_LOGIN_NACK_RCVD;
350*b494511aSVenki Rajagopalan 	} else {
351*b494511aSVenki Rajagopalan 		bcopy(ld, &vnic->vn_login_data, sizeof (eib_login_data_t));
352*b494511aSVenki Rajagopalan 		vnic->vn_state = EIB_LOGIN_ACK_RCVD;
353*b494511aSVenki Rajagopalan 	}
354*b494511aSVenki Rajagopalan 
355*b494511aSVenki Rajagopalan 	cv_signal(&vnic->vn_cv);
356*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
357*b494511aSVenki Rajagopalan }
358*b494511aSVenki Rajagopalan 
359*b494511aSVenki Rajagopalan int
eib_vnic_wait_for_table(eib_t * ss,eib_vnic_t * vnic,int * err)360*b494511aSVenki Rajagopalan eib_vnic_wait_for_table(eib_t *ss, eib_vnic_t *vnic, int *err)
361*b494511aSVenki Rajagopalan {
362*b494511aSVenki Rajagopalan 	clock_t deadline;
363*b494511aSVenki Rajagopalan 	int ret = EIB_E_SUCCESS;
364*b494511aSVenki Rajagopalan 
365*b494511aSVenki Rajagopalan 	/*
366*b494511aSVenki Rajagopalan 	 * The EoIB spec does not detail exactly within what time a vhub table
367*b494511aSVenki Rajagopalan 	 * request is expected to be answered.  However, it does mention that
368*b494511aSVenki Rajagopalan 	 * in the worst case, the vhub update messages from the gateway must
369*b494511aSVenki Rajagopalan 	 * be seen atleast once in 2.5 * GW_KA_PERIOD (already saved in
370*b494511aSVenki Rajagopalan 	 * pp_gw_ka_ticks), so we'll settle for that limit.
371*b494511aSVenki Rajagopalan 	 */
372*b494511aSVenki Rajagopalan 	deadline = ddi_get_lbolt() + ss->ei_gw_props->pp_gw_ka_ticks;
373*b494511aSVenki Rajagopalan 
374*b494511aSVenki Rajagopalan 	/*
375*b494511aSVenki Rajagopalan 	 * Wait for vhub table to be constructed. If we wake up with a
376*b494511aSVenki Rajagopalan 	 * vhub table construction failure, record the reason.
377*b494511aSVenki Rajagopalan 	 */
378*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
379*b494511aSVenki Rajagopalan 	while (vnic->vn_state == EIB_LOGIN_TBL_WAIT) {
380*b494511aSVenki Rajagopalan 		if (cv_timedwait(&vnic->vn_cv, &vnic->vn_lock,
381*b494511aSVenki Rajagopalan 		    deadline) == -1) {
382*b494511aSVenki Rajagopalan 			if (vnic->vn_state == EIB_LOGIN_TBL_WAIT)
383*b494511aSVenki Rajagopalan 				vnic->vn_state = EIB_LOGIN_TIMED_OUT;
384*b494511aSVenki Rajagopalan 		}
385*b494511aSVenki Rajagopalan 	}
386*b494511aSVenki Rajagopalan 
387*b494511aSVenki Rajagopalan 	if (vnic->vn_state != EIB_LOGIN_TBL_DONE) {
388*b494511aSVenki Rajagopalan 		ret = EIB_E_FAILURE;
389*b494511aSVenki Rajagopalan 		*err =  (vnic->vn_state == EIB_LOGIN_TIMED_OUT) ?
390*b494511aSVenki Rajagopalan 		    ETIME : ECANCELED;
391*b494511aSVenki Rajagopalan 	}
392*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
393*b494511aSVenki Rajagopalan 
394*b494511aSVenki Rajagopalan 	return (ret);
395*b494511aSVenki Rajagopalan }
396*b494511aSVenki Rajagopalan 
397*b494511aSVenki Rajagopalan void
eib_vnic_vhub_table_done(eib_vnic_t * vnic,uint_t result_state)398*b494511aSVenki Rajagopalan eib_vnic_vhub_table_done(eib_vnic_t *vnic, uint_t result_state)
399*b494511aSVenki Rajagopalan {
400*b494511aSVenki Rajagopalan 	ASSERT(result_state == EIB_LOGIN_TBL_DONE ||
401*b494511aSVenki Rajagopalan 	    result_state == EIB_LOGIN_TBL_FAILED);
402*b494511aSVenki Rajagopalan 
403*b494511aSVenki Rajagopalan 	/*
404*b494511aSVenki Rajagopalan 	 * Construction of vhub table for the vnic is done one way or
405*b494511aSVenki Rajagopalan 	 * the other.  Set the login wait state appropriately and signal
406*b494511aSVenki Rajagopalan 	 * the waiter. If it's a vhub table failure, we shouldn't parse
407*b494511aSVenki Rajagopalan 	 * any more vhub table or vhub update packets until the vnic state
408*b494511aSVenki Rajagopalan 	 * is changed.
409*b494511aSVenki Rajagopalan 	 */
410*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
411*b494511aSVenki Rajagopalan 	vnic->vn_state = result_state;
412*b494511aSVenki Rajagopalan 	cv_signal(&vnic->vn_cv);
413*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
414*b494511aSVenki Rajagopalan }
415*b494511aSVenki Rajagopalan 
416*b494511aSVenki Rajagopalan int
eib_vnic_join_data_mcg(eib_t * ss,eib_vnic_t * vnic,uint8_t * mcast_mac,boolean_t rejoin,int * err)417*b494511aSVenki Rajagopalan eib_vnic_join_data_mcg(eib_t *ss, eib_vnic_t *vnic, uint8_t *mcast_mac,
418*b494511aSVenki Rajagopalan     boolean_t rejoin, int *err)
419*b494511aSVenki Rajagopalan {
420*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_data_chan;
421*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
422*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
423*b494511aSVenki Rajagopalan 	eib_mcg_t *elem;
424*b494511aSVenki Rajagopalan 	eib_mcg_t *tail;
425*b494511aSVenki Rajagopalan 	ibt_mcg_info_t *mcg_info;
426*b494511aSVenki Rajagopalan 	ibt_mcg_attr_t mcg_attr;
427*b494511aSVenki Rajagopalan 	ibt_status_t ret;
428*b494511aSVenki Rajagopalan 
429*b494511aSVenki Rajagopalan 	/*
430*b494511aSVenki Rajagopalan 	 * Compose the multicast MGID to join
431*b494511aSVenki Rajagopalan 	 */
432*b494511aSVenki Rajagopalan 	bzero(&mcg_attr, sizeof (ibt_mcg_attr_t));
433*b494511aSVenki Rajagopalan 
434*b494511aSVenki Rajagopalan 	eib_vnic_make_vhub_mgid(ld->ld_gw_mgid_prefix,
435*b494511aSVenki Rajagopalan 	    (uint8_t)EIB_MGID_VHUB_DATA, mcast_mac, ld->ld_n_mac_mcgid, 0,
436*b494511aSVenki Rajagopalan 	    ld->ld_vhub_id, &(mcg_attr.mc_mgid));
437*b494511aSVenki Rajagopalan 	mcg_attr.mc_pkey = (ib_pkey_t)ld->ld_vhub_pkey;
438*b494511aSVenki Rajagopalan 	mcg_attr.mc_qkey = (ib_qkey_t)EIB_DATA_QKEY;
439*b494511aSVenki Rajagopalan 
440*b494511aSVenki Rajagopalan 	/*
441*b494511aSVenki Rajagopalan 	 * Allocate for and prepare the mcg to add to our list
442*b494511aSVenki Rajagopalan 	 */
443*b494511aSVenki Rajagopalan 	mcg_info = kmem_zalloc(sizeof (ibt_mcg_info_t), KM_NOSLEEP);
444*b494511aSVenki Rajagopalan 	if (mcg_info == NULL) {
445*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_join_data_mcg: "
446*b494511aSVenki Rajagopalan 		    "no memory, failed to join mcg (mac=%x:%x:%x:%x:%x:%x)",
447*b494511aSVenki Rajagopalan 		    mcast_mac[0], mcast_mac[1], mcast_mac[2],
448*b494511aSVenki Rajagopalan 		    mcast_mac[3], mcast_mac[4], mcast_mac[5]);
449*b494511aSVenki Rajagopalan 
450*b494511aSVenki Rajagopalan 		*err = ENOMEM;
451*b494511aSVenki Rajagopalan 		goto vnic_join_data_mcg_fail;
452*b494511aSVenki Rajagopalan 	}
453*b494511aSVenki Rajagopalan 	mcg = kmem_zalloc(sizeof (eib_mcg_t), KM_NOSLEEP);
454*b494511aSVenki Rajagopalan 	if (mcg == NULL) {
455*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_join_data_mcg: "
456*b494511aSVenki Rajagopalan 		    "no memory, failed to join mcg (mac=%x:%x:%x:%x:%x:%x)",
457*b494511aSVenki Rajagopalan 		    mcast_mac[0], mcast_mac[1], mcast_mac[2],
458*b494511aSVenki Rajagopalan 		    mcast_mac[3], mcast_mac[4], mcast_mac[5]);
459*b494511aSVenki Rajagopalan 
460*b494511aSVenki Rajagopalan 		*err = ENOMEM;
461*b494511aSVenki Rajagopalan 		goto vnic_join_data_mcg_fail;
462*b494511aSVenki Rajagopalan 	}
463*b494511aSVenki Rajagopalan 	mcg->mg_next = NULL;
464*b494511aSVenki Rajagopalan 	mcg->mg_rgid = ss->ei_props->ep_sgid;
465*b494511aSVenki Rajagopalan 	mcg->mg_mgid = mcg_attr.mc_mgid;
466*b494511aSVenki Rajagopalan 	mcg->mg_join_state = IB_MC_JSTATE_FULL;
467*b494511aSVenki Rajagopalan 	mcg->mg_mcginfo = mcg_info;
468*b494511aSVenki Rajagopalan 	bcopy(mcast_mac, mcg->mg_mac, ETHERADDRL);
469*b494511aSVenki Rajagopalan 
470*b494511aSVenki Rajagopalan 	/*
471*b494511aSVenki Rajagopalan 	 * Join the multicast group
472*b494511aSVenki Rajagopalan 	 *
473*b494511aSVenki Rajagopalan 	 * Should we query for the mcg and join instead of attempting to
474*b494511aSVenki Rajagopalan 	 * join directly ?
475*b494511aSVenki Rajagopalan 	 */
476*b494511aSVenki Rajagopalan 	mcg_attr.mc_join_state = mcg->mg_join_state;
477*b494511aSVenki Rajagopalan 	mcg_attr.mc_flow = 0;
478*b494511aSVenki Rajagopalan 	mcg_attr.mc_tclass = 0;
479*b494511aSVenki Rajagopalan 	mcg_attr.mc_sl = 0;
480*b494511aSVenki Rajagopalan 	mcg_attr.mc_scope = 0;	/* IB_MC_SCOPE_SUBNET_LOCAL perhaps ? */
481*b494511aSVenki Rajagopalan 
482*b494511aSVenki Rajagopalan 	ret = ibt_join_mcg(mcg->mg_rgid, &mcg_attr, mcg_info, NULL, NULL);
483*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
484*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_join_data_mcg: "
485*b494511aSVenki Rajagopalan 		    "ibt_join_mcg(mgid=%llx.%llx, pkey=0x%x, qkey=0x%lx, "
486*b494511aSVenki Rajagopalan 		    "jstate=0x%x) failed, ret=%d", mcg_attr.mc_mgid.gid_prefix,
487*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey,
488*b494511aSVenki Rajagopalan 		    mcg_attr.mc_qkey, mcg_attr.mc_join_state, ret);
489*b494511aSVenki Rajagopalan 
490*b494511aSVenki Rajagopalan 		*err = EINVAL;
491*b494511aSVenki Rajagopalan 		goto vnic_join_data_mcg_fail;
492*b494511aSVenki Rajagopalan 	}
493*b494511aSVenki Rajagopalan 
494*b494511aSVenki Rajagopalan 	/*
495*b494511aSVenki Rajagopalan 	 * Attach to the group to receive multicast messages
496*b494511aSVenki Rajagopalan 	 */
497*b494511aSVenki Rajagopalan 	ret = ibt_attach_mcg(chan->ch_chan, mcg_info);
498*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
499*b494511aSVenki Rajagopalan 		*err = EINVAL;
500*b494511aSVenki Rajagopalan 
501*b494511aSVenki Rajagopalan 		ret = ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
502*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
503*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
504*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
505*b494511aSVenki Rajagopalan 			    "eib_vnic_join_data_mcg: "
506*b494511aSVenki Rajagopalan 			    "ibt_leave_mcg(mgid=%llx.%llx, jstate=0x%x) "
507*b494511aSVenki Rajagopalan 			    "failed, ret=%d", mcg->mg_mgid.gid_prefix,
508*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, mcg->mg_join_state, ret);
509*b494511aSVenki Rajagopalan 		}
510*b494511aSVenki Rajagopalan 
511*b494511aSVenki Rajagopalan 		goto vnic_join_data_mcg_fail;
512*b494511aSVenki Rajagopalan 	}
513*b494511aSVenki Rajagopalan 
514*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
515*b494511aSVenki Rajagopalan 
516*b494511aSVenki Rajagopalan 	tail = NULL;
517*b494511aSVenki Rajagopalan 	for (elem = chan->ch_vhub_data; elem != NULL; elem = elem->mg_next) {
518*b494511aSVenki Rajagopalan 		if ((elem->mg_mgid.gid_prefix == mcg_attr.mc_mgid.gid_prefix) &&
519*b494511aSVenki Rajagopalan 		    (elem->mg_mgid.gid_guid == mcg_attr.mc_mgid.gid_guid)) {
520*b494511aSVenki Rajagopalan 			break;
521*b494511aSVenki Rajagopalan 		}
522*b494511aSVenki Rajagopalan 		tail = elem;
523*b494511aSVenki Rajagopalan 	}
524*b494511aSVenki Rajagopalan 
525*b494511aSVenki Rajagopalan 	/*
526*b494511aSVenki Rajagopalan 	 * If we had't already joined to this mcg, add the newly joined mcg
527*b494511aSVenki Rajagopalan 	 * to the tail and return success
528*b494511aSVenki Rajagopalan 	 */
529*b494511aSVenki Rajagopalan 	if (elem == NULL) {
530*b494511aSVenki Rajagopalan 		if (tail)
531*b494511aSVenki Rajagopalan 			tail->mg_next = mcg;
532*b494511aSVenki Rajagopalan 		else
533*b494511aSVenki Rajagopalan 			chan->ch_vhub_data = mcg;
534*b494511aSVenki Rajagopalan 		mutex_exit(&chan->ch_vhub_lock);
535*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
536*b494511aSVenki Rajagopalan 	}
537*b494511aSVenki Rajagopalan 
538*b494511aSVenki Rajagopalan 	/*
539*b494511aSVenki Rajagopalan 	 * Duplicate.  We need to leave one of the two joins.  If "rejoin"
540*b494511aSVenki Rajagopalan 	 * was requested, leave the old join, otherwise leave the new join.
541*b494511aSVenki Rajagopalan 	 *
542*b494511aSVenki Rajagopalan 	 * Note that we must not detach the qp from the mcg, since if this
543*b494511aSVenki Rajagopalan 	 * was a dup, a second ibt_attach_mcg() above would've simply been
544*b494511aSVenki Rajagopalan 	 * a nop.
545*b494511aSVenki Rajagopalan 	 *
546*b494511aSVenki Rajagopalan 	 * Note also that the leave may not be successful here if our presence
547*b494511aSVenki Rajagopalan 	 * has been removed by the SM, but we need to do this to prevent leaks
548*b494511aSVenki Rajagopalan 	 * in ibtf.
549*b494511aSVenki Rajagopalan 	 */
550*b494511aSVenki Rajagopalan 	if (rejoin) {
551*b494511aSVenki Rajagopalan 		ASSERT(elem->mg_mcginfo != NULL);
552*b494511aSVenki Rajagopalan 		kmem_free(elem->mg_mcginfo, sizeof (ibt_mcg_info_t));
553*b494511aSVenki Rajagopalan 		(void) ibt_leave_mcg(elem->mg_rgid, elem->mg_mgid,
554*b494511aSVenki Rajagopalan 		    eib_reserved_gid, elem->mg_join_state);
555*b494511aSVenki Rajagopalan 		/*
556*b494511aSVenki Rajagopalan 		 * Copy the new mcg over the old one (including the new
557*b494511aSVenki Rajagopalan 		 * mg_mcginfo), but preserve the link to the next element
558*b494511aSVenki Rajagopalan 		 * on the list
559*b494511aSVenki Rajagopalan 		 */
560*b494511aSVenki Rajagopalan 		mcg->mg_next = elem->mg_next;
561*b494511aSVenki Rajagopalan 		bcopy(mcg, elem, sizeof (eib_mcg_t));
562*b494511aSVenki Rajagopalan 	} else {
563*b494511aSVenki Rajagopalan 		ASSERT(mcg->mg_mcginfo != NULL);
564*b494511aSVenki Rajagopalan 		kmem_free(mcg->mg_mcginfo, sizeof (ibt_mcg_info_t));
565*b494511aSVenki Rajagopalan 		(void) ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
566*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
567*b494511aSVenki Rajagopalan 	}
568*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
569*b494511aSVenki Rajagopalan 
570*b494511aSVenki Rajagopalan 	kmem_free(mcg, sizeof (eib_mcg_t));
571*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
572*b494511aSVenki Rajagopalan 
573*b494511aSVenki Rajagopalan vnic_join_data_mcg_fail:
574*b494511aSVenki Rajagopalan 	if (mcg) {
575*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
576*b494511aSVenki Rajagopalan 	}
577*b494511aSVenki Rajagopalan 	if (mcg_info) {
578*b494511aSVenki Rajagopalan 		kmem_free(mcg_info, sizeof (ibt_mcg_info_t));
579*b494511aSVenki Rajagopalan 	}
580*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
581*b494511aSVenki Rajagopalan }
582*b494511aSVenki Rajagopalan 
583*b494511aSVenki Rajagopalan int
eib_vnic_setup_dest(eib_vnic_t * vnic,eib_wqe_t * swqe,uint8_t * dmac,uint16_t vlan)584*b494511aSVenki Rajagopalan eib_vnic_setup_dest(eib_vnic_t *vnic, eib_wqe_t *swqe, uint8_t *dmac,
585*b494511aSVenki Rajagopalan     uint16_t vlan)
586*b494511aSVenki Rajagopalan {
587*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
588*b494511aSVenki Rajagopalan 	eib_stats_t *stats = ss->ei_stats;
589*b494511aSVenki Rajagopalan 	eib_avect_t *av;
590*b494511aSVenki Rajagopalan 	eib_vhub_map_t ucast;
591*b494511aSVenki Rajagopalan 	ibt_mcg_info_t mcast;
592*b494511aSVenki Rajagopalan 	ibt_status_t ret;
593*b494511aSVenki Rajagopalan 	int dtype;
594*b494511aSVenki Rajagopalan 	int rv;
595*b494511aSVenki Rajagopalan 
596*b494511aSVenki Rajagopalan 	/*
597*b494511aSVenki Rajagopalan 	 * Lookup the destination in the vhub table or in our mcg list
598*b494511aSVenki Rajagopalan 	 */
599*b494511aSVenki Rajagopalan 	rv = eib_vnic_lookup_dest(vnic, dmac, vlan, &ucast, &mcast, &dtype);
600*b494511aSVenki Rajagopalan 	if (rv != EIB_E_SUCCESS) {
601*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_setup_dest: "
602*b494511aSVenki Rajagopalan 		    "eib_vnic_lookup_dest(dmac=%x:%x:%x:%x:%x:%x, vlan=0x%x) "
603*b494511aSVenki Rajagopalan 		    "failed", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
604*b494511aSVenki Rajagopalan 		    dmac[5], vlan);
605*b494511aSVenki Rajagopalan 
606*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
607*b494511aSVenki Rajagopalan 	}
608*b494511aSVenki Rajagopalan 
609*b494511aSVenki Rajagopalan 	/*
610*b494511aSVenki Rajagopalan 	 * If we found a unicast address, get an address vector for the lid
611*b494511aSVenki Rajagopalan 	 * and sl, modify the ud dest based on the address vector and return.
612*b494511aSVenki Rajagopalan 	 * If we found a multicast address, use the address vector in the
613*b494511aSVenki Rajagopalan 	 * mcg info to modify the ud dest and return.
614*b494511aSVenki Rajagopalan 	 */
615*b494511aSVenki Rajagopalan 	if (dtype == EIB_TX_UNICAST) {
616*b494511aSVenki Rajagopalan 		if ((av = eib_ibt_hold_avect(ss, ucast.mp_lid,
617*b494511aSVenki Rajagopalan 		    ucast.mp_sl)) == NULL) {
618*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
619*b494511aSVenki Rajagopalan 			    "eib_vnic_setup_dest: "
620*b494511aSVenki Rajagopalan 			    "eib_ibt_hold_avect(lid=0x%x, sl=0x%x) failed",
621*b494511aSVenki Rajagopalan 			    ucast.mp_lid, ucast.mp_sl);
622*b494511aSVenki Rajagopalan 
623*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
624*b494511aSVenki Rajagopalan 		}
625*b494511aSVenki Rajagopalan 		ret = ibt_modify_ud_dest(swqe->qe_dest, EIB_DATA_QKEY,
626*b494511aSVenki Rajagopalan 		    ucast.mp_qpn, &av->av_vect);
627*b494511aSVenki Rajagopalan 
628*b494511aSVenki Rajagopalan 		eib_ibt_release_avect(ss, av);
629*b494511aSVenki Rajagopalan 
630*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
631*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
632*b494511aSVenki Rajagopalan 			    "eib_vnic_setup_dest: "
633*b494511aSVenki Rajagopalan 			    "ibt_modify_ud_dest(qpn=0x%lx, qkey=0x%lx) "
634*b494511aSVenki Rajagopalan 			    "failed, ret=%d", ucast.mp_qpn, EIB_DATA_QKEY, ret);
635*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
636*b494511aSVenki Rajagopalan 		}
637*b494511aSVenki Rajagopalan 	} else {
638*b494511aSVenki Rajagopalan 		ret = ibt_modify_ud_dest(swqe->qe_dest, EIB_DATA_QKEY,
639*b494511aSVenki Rajagopalan 		    IB_MC_QPN, &(mcast.mc_adds_vect));
640*b494511aSVenki Rajagopalan 
641*b494511aSVenki Rajagopalan 		if (dtype == EIB_TX_BROADCAST)
642*b494511aSVenki Rajagopalan 			EIB_INCR_COUNTER(&stats->st_brdcstxmit);
643*b494511aSVenki Rajagopalan 		else
644*b494511aSVenki Rajagopalan 			EIB_INCR_COUNTER(&stats->st_multixmit);
645*b494511aSVenki Rajagopalan 
646*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
647*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
648*b494511aSVenki Rajagopalan 			    "eib_vnic_setup_dest: "
649*b494511aSVenki Rajagopalan 			    "ibt_modify_ud_dest(mc_qpn=0x%lx, qkey=0x%lx) "
650*b494511aSVenki Rajagopalan 			    "failed, ret=%d", IB_MC_QPN, EIB_DATA_QKEY, ret);
651*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
652*b494511aSVenki Rajagopalan 		}
653*b494511aSVenki Rajagopalan 	}
654*b494511aSVenki Rajagopalan 
655*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
656*b494511aSVenki Rajagopalan }
657*b494511aSVenki Rajagopalan 
658*b494511aSVenki Rajagopalan void
eib_vnic_leave_data_mcg(eib_t * ss,eib_vnic_t * vnic,uint8_t * mcast_mac)659*b494511aSVenki Rajagopalan eib_vnic_leave_data_mcg(eib_t *ss, eib_vnic_t *vnic, uint8_t *mcast_mac)
660*b494511aSVenki Rajagopalan {
661*b494511aSVenki Rajagopalan 	eib_rb_vnic_join_data_mcg(ss, vnic, mcast_mac);
662*b494511aSVenki Rajagopalan }
663*b494511aSVenki Rajagopalan 
664*b494511aSVenki Rajagopalan /*ARGSUSED*/
665*b494511aSVenki Rajagopalan void
eib_vnic_init_tables(eib_t * ss,eib_vnic_t * vnic)666*b494511aSVenki Rajagopalan eib_vnic_init_tables(eib_t *ss, eib_vnic_t *vnic)
667*b494511aSVenki Rajagopalan {
668*b494511aSVenki Rajagopalan 	eib_vhub_table_t *tbl;
669*b494511aSVenki Rajagopalan 	eib_vhub_update_t *upd;
670*b494511aSVenki Rajagopalan 
671*b494511aSVenki Rajagopalan 	tbl = kmem_zalloc(sizeof (eib_vhub_table_t), KM_SLEEP);
672*b494511aSVenki Rajagopalan 	mutex_init(&tbl->tb_lock, NULL, MUTEX_DRIVER, NULL);
673*b494511aSVenki Rajagopalan 	tbl->tb_eport_state = FIP_EPORT_UP;
674*b494511aSVenki Rajagopalan 
675*b494511aSVenki Rajagopalan 	upd = kmem_zalloc(sizeof (eib_vhub_update_t), KM_SLEEP);
676*b494511aSVenki Rajagopalan 	mutex_init(&upd->up_lock, NULL, MUTEX_DRIVER, NULL);
677*b494511aSVenki Rajagopalan 
678*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
679*b494511aSVenki Rajagopalan 	vnic->vn_vhub_table = tbl;
680*b494511aSVenki Rajagopalan 	vnic->vn_vhub_update = upd;
681*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
682*b494511aSVenki Rajagopalan }
683*b494511aSVenki Rajagopalan 
684*b494511aSVenki Rajagopalan /*ARGSUSED*/
685*b494511aSVenki Rajagopalan void
eib_vnic_fini_tables(eib_t * ss,eib_vnic_t * vnic,boolean_t clobber)686*b494511aSVenki Rajagopalan eib_vnic_fini_tables(eib_t *ss, eib_vnic_t *vnic, boolean_t clobber)
687*b494511aSVenki Rajagopalan {
688*b494511aSVenki Rajagopalan 	eib_vhub_update_t *upd;
689*b494511aSVenki Rajagopalan 	eib_vhub_table_t *tbl;
690*b494511aSVenki Rajagopalan 	eib_vhub_map_t *elem;
691*b494511aSVenki Rajagopalan 	eib_vhub_map_t *nxt;
692*b494511aSVenki Rajagopalan 	int i;
693*b494511aSVenki Rajagopalan 
694*b494511aSVenki Rajagopalan 	/*
695*b494511aSVenki Rajagopalan 	 * We come here only when we've either completely detached from
696*b494511aSVenki Rajagopalan 	 * the vhub multicast groups and so cannot receive anymore table
697*b494511aSVenki Rajagopalan 	 * or update control messages, or we've had a recent vhub table
698*b494511aSVenki Rajagopalan 	 * construction failure and the vnic state is currently
699*b494511aSVenki Rajagopalan 	 * EIB_LOGIN_TBL_FAILED and so won't parse any table or update
700*b494511aSVenki Rajagopalan 	 * control messages.  Also, since we haven't completed the vnic
701*b494511aSVenki Rajagopalan 	 * creation, no one from the tx path will be accessing the
702*b494511aSVenki Rajagopalan 	 * vn_vhub_table entries either.  All said, we're free to play
703*b494511aSVenki Rajagopalan 	 * around with the vnic's vn_vhub_table and vn_vhub_update here.
704*b494511aSVenki Rajagopalan 	 */
705*b494511aSVenki Rajagopalan 
706*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
707*b494511aSVenki Rajagopalan 	upd = vnic->vn_vhub_update;
708*b494511aSVenki Rajagopalan 	tbl = vnic->vn_vhub_table;
709*b494511aSVenki Rajagopalan 	if (clobber) {
710*b494511aSVenki Rajagopalan 		vnic->vn_vhub_update = NULL;
711*b494511aSVenki Rajagopalan 		vnic->vn_vhub_table = NULL;
712*b494511aSVenki Rajagopalan 	}
713*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
714*b494511aSVenki Rajagopalan 
715*b494511aSVenki Rajagopalan 	/*
716*b494511aSVenki Rajagopalan 	 * Destroy the vhub update entries if any
717*b494511aSVenki Rajagopalan 	 */
718*b494511aSVenki Rajagopalan 	if (upd) {
719*b494511aSVenki Rajagopalan 		/*
720*b494511aSVenki Rajagopalan 		 * Wipe clean the list of vnic entries accumulated via
721*b494511aSVenki Rajagopalan 		 * vhub updates so far.  Release eib_vhub_update_t only
722*b494511aSVenki Rajagopalan 		 * if explicitly asked to do so
723*b494511aSVenki Rajagopalan 		 */
724*b494511aSVenki Rajagopalan 		mutex_enter(&upd->up_lock);
725*b494511aSVenki Rajagopalan 		for (elem = upd->up_vnic_entry; elem != NULL; elem = nxt) {
726*b494511aSVenki Rajagopalan 			nxt = elem->mp_next;
727*b494511aSVenki Rajagopalan 			kmem_free(elem, sizeof (eib_vhub_map_t));
728*b494511aSVenki Rajagopalan 		}
729*b494511aSVenki Rajagopalan 		upd->up_vnic_entry = NULL;
730*b494511aSVenki Rajagopalan 		upd->up_tusn = 0;
731*b494511aSVenki Rajagopalan 		upd->up_eport_state = 0;
732*b494511aSVenki Rajagopalan 		mutex_exit(&upd->up_lock);
733*b494511aSVenki Rajagopalan 
734*b494511aSVenki Rajagopalan 		if (clobber) {
735*b494511aSVenki Rajagopalan 			mutex_destroy(&upd->up_lock);
736*b494511aSVenki Rajagopalan 			kmem_free(upd, sizeof (eib_vhub_update_t));
737*b494511aSVenki Rajagopalan 		}
738*b494511aSVenki Rajagopalan 	}
739*b494511aSVenki Rajagopalan 
740*b494511aSVenki Rajagopalan 	/*
741*b494511aSVenki Rajagopalan 	 * Destroy the vhub table entries
742*b494511aSVenki Rajagopalan 	 */
743*b494511aSVenki Rajagopalan 	if (tbl == NULL)
744*b494511aSVenki Rajagopalan 		return;
745*b494511aSVenki Rajagopalan 
746*b494511aSVenki Rajagopalan 	/*
747*b494511aSVenki Rajagopalan 	 * Wipe clean the list of entries in the vhub table collected so
748*b494511aSVenki Rajagopalan 	 * far. Release eib_vhub_table_t only if explicitly asked to do so.
749*b494511aSVenki Rajagopalan 	 */
750*b494511aSVenki Rajagopalan 	mutex_enter(&tbl->tb_lock);
751*b494511aSVenki Rajagopalan 
752*b494511aSVenki Rajagopalan 	if (tbl->tb_gateway) {
753*b494511aSVenki Rajagopalan 		kmem_free(tbl->tb_gateway, sizeof (eib_vhub_map_t));
754*b494511aSVenki Rajagopalan 		tbl->tb_gateway = NULL;
755*b494511aSVenki Rajagopalan 	}
756*b494511aSVenki Rajagopalan 
757*b494511aSVenki Rajagopalan 	if (tbl->tb_unicast_miss) {
758*b494511aSVenki Rajagopalan 		kmem_free(tbl->tb_unicast_miss, sizeof (eib_vhub_map_t));
759*b494511aSVenki Rajagopalan 		tbl->tb_unicast_miss = NULL;
760*b494511aSVenki Rajagopalan 	}
761*b494511aSVenki Rajagopalan 
762*b494511aSVenki Rajagopalan 	if (tbl->tb_vhub_multicast) {
763*b494511aSVenki Rajagopalan 		kmem_free(tbl->tb_vhub_multicast, sizeof (eib_vhub_map_t));
764*b494511aSVenki Rajagopalan 		tbl->tb_vhub_multicast = NULL;
765*b494511aSVenki Rajagopalan 	}
766*b494511aSVenki Rajagopalan 
767*b494511aSVenki Rajagopalan 	if (!eib_wa_no_mcast_entries) {
768*b494511aSVenki Rajagopalan 		for (i = 0; i < EIB_TB_NBUCKETS; i++) {
769*b494511aSVenki Rajagopalan 			for (elem = tbl->tb_mcast_entry[i]; elem != NULL;
770*b494511aSVenki Rajagopalan 			    elem = nxt) {
771*b494511aSVenki Rajagopalan 				nxt = elem->mp_next;
772*b494511aSVenki Rajagopalan 				kmem_free(elem, sizeof (eib_vhub_map_t));
773*b494511aSVenki Rajagopalan 			}
774*b494511aSVenki Rajagopalan 			tbl->tb_mcast_entry[i] = NULL;
775*b494511aSVenki Rajagopalan 		}
776*b494511aSVenki Rajagopalan 	}
777*b494511aSVenki Rajagopalan 
778*b494511aSVenki Rajagopalan 	for (i = 0; i < EIB_TB_NBUCKETS; i++) {
779*b494511aSVenki Rajagopalan 		for (elem = tbl->tb_vnic_entry[i]; elem != NULL; elem = nxt) {
780*b494511aSVenki Rajagopalan 			nxt = elem->mp_next;
781*b494511aSVenki Rajagopalan 			kmem_free(elem, sizeof (eib_vhub_map_t));
782*b494511aSVenki Rajagopalan 		}
783*b494511aSVenki Rajagopalan 		tbl->tb_vnic_entry[i] = NULL;
784*b494511aSVenki Rajagopalan 	}
785*b494511aSVenki Rajagopalan 
786*b494511aSVenki Rajagopalan 	tbl->tb_tusn = 0;
787*b494511aSVenki Rajagopalan 	tbl->tb_eport_state = 0;
788*b494511aSVenki Rajagopalan 	tbl->tb_entries_seen = 0;
789*b494511aSVenki Rajagopalan 	tbl->tb_entries_in_table = 0;
790*b494511aSVenki Rajagopalan 	tbl->tb_checksum = 0;
791*b494511aSVenki Rajagopalan 
792*b494511aSVenki Rajagopalan 	mutex_exit(&tbl->tb_lock);
793*b494511aSVenki Rajagopalan 
794*b494511aSVenki Rajagopalan 	/*
795*b494511aSVenki Rajagopalan 	 * Don't throw away space created for holding vhub table if we haven't
796*b494511aSVenki Rajagopalan 	 * been explicitly asked to do so
797*b494511aSVenki Rajagopalan 	 */
798*b494511aSVenki Rajagopalan 	if (clobber) {
799*b494511aSVenki Rajagopalan 		mutex_destroy(&tbl->tb_lock);
800*b494511aSVenki Rajagopalan 		kmem_free(tbl, sizeof (eib_vhub_table_t));
801*b494511aSVenki Rajagopalan 	}
802*b494511aSVenki Rajagopalan }
803*b494511aSVenki Rajagopalan 
804*b494511aSVenki Rajagopalan eib_chan_t *
eib_vnic_get_data_chan(eib_t * ss,int vinst)805*b494511aSVenki Rajagopalan eib_vnic_get_data_chan(eib_t *ss, int vinst)
806*b494511aSVenki Rajagopalan {
807*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic;
808*b494511aSVenki Rajagopalan 	eib_chan_t *chan = NULL;
809*b494511aSVenki Rajagopalan 
810*b494511aSVenki Rajagopalan 	if (vinst >= 0 && vinst < EIB_MAX_VNICS) {
811*b494511aSVenki Rajagopalan 		mutex_enter(&ss->ei_vnic_lock);
812*b494511aSVenki Rajagopalan 		if ((vnic = ss->ei_vnic[vinst]) != NULL)
813*b494511aSVenki Rajagopalan 			chan = vnic->vn_data_chan;
814*b494511aSVenki Rajagopalan 		mutex_exit(&ss->ei_vnic_lock);
815*b494511aSVenki Rajagopalan 	}
816*b494511aSVenki Rajagopalan 
817*b494511aSVenki Rajagopalan 	return (chan);
818*b494511aSVenki Rajagopalan }
819*b494511aSVenki Rajagopalan 
820*b494511aSVenki Rajagopalan void
eib_vnic_need_new(eib_t * ss,uint8_t * mac,uint16_t vlan)821*b494511aSVenki Rajagopalan eib_vnic_need_new(eib_t *ss, uint8_t *mac, uint16_t vlan)
822*b494511aSVenki Rajagopalan {
823*b494511aSVenki Rajagopalan 	eib_vnic_req_t *vrq;
824*b494511aSVenki Rajagopalan 
825*b494511aSVenki Rajagopalan 	EIB_INCR_COUNTER(&ss->ei_stats->st_noxmitbuf);
826*b494511aSVenki Rajagopalan 
827*b494511aSVenki Rajagopalan 	/*
828*b494511aSVenki Rajagopalan 	 * Create a new vnic request for this {mac,vlan} tuple
829*b494511aSVenki Rajagopalan 	 */
830*b494511aSVenki Rajagopalan 	vrq = kmem_zalloc(sizeof (eib_vnic_req_t), KM_NOSLEEP);
831*b494511aSVenki Rajagopalan 	if (vrq == NULL) {
832*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_need_new: "
833*b494511aSVenki Rajagopalan 		    "no memory, failed to queue new vnic creation request");
834*b494511aSVenki Rajagopalan 		return;
835*b494511aSVenki Rajagopalan 	}
836*b494511aSVenki Rajagopalan 	vrq->vr_next = NULL;
837*b494511aSVenki Rajagopalan 	vrq->vr_req = EIB_CR_REQ_NEW_VNIC;
838*b494511aSVenki Rajagopalan 	bcopy(mac, vrq->vr_mac, ETHERADDRL);
839*b494511aSVenki Rajagopalan 	vrq->vr_vlan = vlan;
840*b494511aSVenki Rajagopalan 
841*b494511aSVenki Rajagopalan 	eib_vnic_enqueue_req(ss, vrq);
842*b494511aSVenki Rajagopalan }
843*b494511aSVenki Rajagopalan 
844*b494511aSVenki Rajagopalan void
eib_vnic_enqueue_req(eib_t * ss,eib_vnic_req_t * vrq)845*b494511aSVenki Rajagopalan eib_vnic_enqueue_req(eib_t *ss, eib_vnic_req_t *vrq)
846*b494511aSVenki Rajagopalan {
847*b494511aSVenki Rajagopalan 	eib_vnic_req_t *elem = NULL;
848*b494511aSVenki Rajagopalan 	uint8_t *m;
849*b494511aSVenki Rajagopalan 
850*b494511aSVenki Rajagopalan 	/*
851*b494511aSVenki Rajagopalan 	 * Enqueue this new vnic request with the vnic creator and
852*b494511aSVenki Rajagopalan 	 * signal it.
853*b494511aSVenki Rajagopalan 	 */
854*b494511aSVenki Rajagopalan 	m = vrq->vr_mac;
855*b494511aSVenki Rajagopalan 	EIB_DPRINTF_DEBUG(ss->ei_instance, "eib_vnic_enqueue_req: "
856*b494511aSVenki Rajagopalan 	    "BEGIN file request for creation of %x:%x:%x:%x:%x:%x, 0x%x",
857*b494511aSVenki Rajagopalan 	    m[0], m[1], m[2], m[3], m[4], m[5], vrq->vr_vlan);
858*b494511aSVenki Rajagopalan 
859*b494511aSVenki Rajagopalan 
860*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_req_lock);
861*b494511aSVenki Rajagopalan 
862*b494511aSVenki Rajagopalan 	/*
863*b494511aSVenki Rajagopalan 	 * Death request has the highest priority.  If we've already been asked
864*b494511aSVenki Rajagopalan 	 * to die, we don't entertain any more requests.
865*b494511aSVenki Rajagopalan 	 */
866*b494511aSVenki Rajagopalan 	if (ss->ei_vnic_req) {
867*b494511aSVenki Rajagopalan 		if (ss->ei_vnic_req->vr_req == EIB_CR_REQ_DIE) {
868*b494511aSVenki Rajagopalan 			mutex_exit(&ss->ei_vnic_req_lock);
869*b494511aSVenki Rajagopalan 			kmem_free(vrq, sizeof (eib_vnic_req_t));
870*b494511aSVenki Rajagopalan 			return;
871*b494511aSVenki Rajagopalan 		}
872*b494511aSVenki Rajagopalan 	}
873*b494511aSVenki Rajagopalan 
874*b494511aSVenki Rajagopalan 	if (vrq->vr_req == EIB_CR_REQ_DIE || vrq->vr_req == EIB_CR_REQ_FLUSH) {
875*b494511aSVenki Rajagopalan 		vrq->vr_next = ss->ei_vnic_req;
876*b494511aSVenki Rajagopalan 		ss->ei_vnic_req = vrq;
877*b494511aSVenki Rajagopalan 	} else {
878*b494511aSVenki Rajagopalan 		/*
879*b494511aSVenki Rajagopalan 		 * If there's already a creation request for this vnic that's
880*b494511aSVenki Rajagopalan 		 * being processed, return immediately without adding a new
881*b494511aSVenki Rajagopalan 		 * request.
882*b494511aSVenki Rajagopalan 		 */
883*b494511aSVenki Rajagopalan 		if ((elem = ss->ei_pending_vnic_req) != NULL) {
884*b494511aSVenki Rajagopalan 			EIB_DPRINTF_DEBUG(ss->ei_instance,
885*b494511aSVenki Rajagopalan 			    "eib_vnic_enqueue_req: "
886*b494511aSVenki Rajagopalan 			    "ei_pending_vnic_req not NULL");
887*b494511aSVenki Rajagopalan 
888*b494511aSVenki Rajagopalan 			if ((elem->vr_vlan == vrq->vr_vlan) &&
889*b494511aSVenki Rajagopalan 			    (bcmp(elem->vr_mac, vrq->vr_mac,
890*b494511aSVenki Rajagopalan 			    ETHERADDRL) == 0)) {
891*b494511aSVenki Rajagopalan 				EIB_DPRINTF_DEBUG(ss->ei_instance,
892*b494511aSVenki Rajagopalan 				    "eib_vnic_enqueue_req: "
893*b494511aSVenki Rajagopalan 				    "pending request already present for "
894*b494511aSVenki Rajagopalan 				    "%x:%x:%x:%x:%x:%x, 0x%x", m[0], m[1], m[2],
895*b494511aSVenki Rajagopalan 				    m[3], m[4], m[5], vrq->vr_vlan);
896*b494511aSVenki Rajagopalan 
897*b494511aSVenki Rajagopalan 				mutex_exit(&ss->ei_vnic_req_lock);
898*b494511aSVenki Rajagopalan 				kmem_free(vrq, sizeof (eib_vnic_req_t));
899*b494511aSVenki Rajagopalan 
900*b494511aSVenki Rajagopalan 				EIB_DPRINTF_DEBUG(ss->ei_instance,
901*b494511aSVenki Rajagopalan 				    "eib_vnic_enqueue_req: "
902*b494511aSVenki Rajagopalan 				    "END file request");
903*b494511aSVenki Rajagopalan 				return;
904*b494511aSVenki Rajagopalan 			}
905*b494511aSVenki Rajagopalan 
906*b494511aSVenki Rajagopalan 			EIB_DPRINTF_DEBUG(ss->ei_instance,
907*b494511aSVenki Rajagopalan 			    "eib_vnic_enqueue_req: "
908*b494511aSVenki Rajagopalan 			    "NO pending request for %x:%x:%x:%x:%x:%x, 0x%x",
909*b494511aSVenki Rajagopalan 			    m[0], m[1], m[2], m[3], m[4], m[5], vrq->vr_vlan);
910*b494511aSVenki Rajagopalan 		}
911*b494511aSVenki Rajagopalan 
912*b494511aSVenki Rajagopalan 		/*
913*b494511aSVenki Rajagopalan 		 * Or if there's one waiting in the queue for processing, do
914*b494511aSVenki Rajagopalan 		 * the same thing
915*b494511aSVenki Rajagopalan 		 */
916*b494511aSVenki Rajagopalan 		for (elem = ss->ei_vnic_req; elem; elem = elem->vr_next) {
917*b494511aSVenki Rajagopalan 			/*
918*b494511aSVenki Rajagopalan 			 * If there's already a create request for this vnic
919*b494511aSVenki Rajagopalan 			 * waiting in the queue, return immediately
920*b494511aSVenki Rajagopalan 			 */
921*b494511aSVenki Rajagopalan 			if (elem->vr_req == EIB_CR_REQ_NEW_VNIC) {
922*b494511aSVenki Rajagopalan 				if ((elem->vr_vlan == vrq->vr_vlan) &&
923*b494511aSVenki Rajagopalan 				    (bcmp(elem->vr_mac, vrq->vr_mac,
924*b494511aSVenki Rajagopalan 				    ETHERADDRL) == 0)) {
925*b494511aSVenki Rajagopalan 
926*b494511aSVenki Rajagopalan 					EIB_DPRINTF_DEBUG(ss->ei_instance,
927*b494511aSVenki Rajagopalan 					    "eib_vnic_enqueue_req: "
928*b494511aSVenki Rajagopalan 					    "request already present for "
929*b494511aSVenki Rajagopalan 					    "%x:%x:%x:%x:%x:%x, 0x%x", m[0],
930*b494511aSVenki Rajagopalan 					    m[1], m[2], m[3], m[4], m[5],
931*b494511aSVenki Rajagopalan 					    vrq->vr_vlan);
932*b494511aSVenki Rajagopalan 
933*b494511aSVenki Rajagopalan 					mutex_exit(&ss->ei_vnic_req_lock);
934*b494511aSVenki Rajagopalan 					kmem_free(vrq, sizeof (eib_vnic_req_t));
935*b494511aSVenki Rajagopalan 
936*b494511aSVenki Rajagopalan 					EIB_DPRINTF_DEBUG(ss->ei_instance,
937*b494511aSVenki Rajagopalan 					    "eib_vnic_enqueue_req: "
938*b494511aSVenki Rajagopalan 					    "END file request");
939*b494511aSVenki Rajagopalan 					return;
940*b494511aSVenki Rajagopalan 				}
941*b494511aSVenki Rajagopalan 			}
942*b494511aSVenki Rajagopalan 
943*b494511aSVenki Rajagopalan 			if (elem->vr_next == NULL) {
944*b494511aSVenki Rajagopalan 				EIB_DPRINTF_DEBUG(ss->ei_instance,
945*b494511aSVenki Rajagopalan 				    "eib_vnic_enqueue_req: "
946*b494511aSVenki Rajagopalan 				    "request not found, filing afresh");
947*b494511aSVenki Rajagopalan 				break;
948*b494511aSVenki Rajagopalan 			}
949*b494511aSVenki Rajagopalan 		}
950*b494511aSVenki Rajagopalan 
951*b494511aSVenki Rajagopalan 		/*
952*b494511aSVenki Rajagopalan 		 * Otherwise queue up this new creation request and signal the
953*b494511aSVenki Rajagopalan 		 * service thread.
954*b494511aSVenki Rajagopalan 		 */
955*b494511aSVenki Rajagopalan 		if (elem) {
956*b494511aSVenki Rajagopalan 			elem->vr_next = vrq;
957*b494511aSVenki Rajagopalan 		} else {
958*b494511aSVenki Rajagopalan 			ss->ei_vnic_req = vrq;
959*b494511aSVenki Rajagopalan 		}
960*b494511aSVenki Rajagopalan 	}
961*b494511aSVenki Rajagopalan 
962*b494511aSVenki Rajagopalan 	cv_signal(&ss->ei_vnic_req_cv);
963*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_req_lock);
964*b494511aSVenki Rajagopalan 
965*b494511aSVenki Rajagopalan 	EIB_DPRINTF_DEBUG(ss->ei_instance,
966*b494511aSVenki Rajagopalan 	    "eib_vnic_enqueue_req: END file request");
967*b494511aSVenki Rajagopalan }
968*b494511aSVenki Rajagopalan 
969*b494511aSVenki Rajagopalan void
eib_vnic_update_failed_macs(eib_t * ss,uint8_t * old_mac,uint16_t old_vlan,uint8_t * new_mac,uint16_t new_vlan)970*b494511aSVenki Rajagopalan eib_vnic_update_failed_macs(eib_t *ss, uint8_t *old_mac, uint16_t old_vlan,
971*b494511aSVenki Rajagopalan     uint8_t *new_mac, uint16_t new_vlan)
972*b494511aSVenki Rajagopalan {
973*b494511aSVenki Rajagopalan 	eib_vnic_req_t *vrq;
974*b494511aSVenki Rajagopalan 	eib_vnic_req_t *elem;
975*b494511aSVenki Rajagopalan 	eib_vnic_req_t *prev;
976*b494511aSVenki Rajagopalan 
977*b494511aSVenki Rajagopalan 	vrq = kmem_zalloc(sizeof (eib_vnic_req_t), KM_NOSLEEP);
978*b494511aSVenki Rajagopalan 	if (vrq == NULL) {
979*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
980*b494511aSVenki Rajagopalan 		    "eib_vnic_update_failed_macs: "
981*b494511aSVenki Rajagopalan 		    "no memory, failed to drop old mac");
982*b494511aSVenki Rajagopalan 	} else {
983*b494511aSVenki Rajagopalan 		vrq->vr_next = NULL;
984*b494511aSVenki Rajagopalan 		vrq->vr_req = 0;	/* unused */
985*b494511aSVenki Rajagopalan 		bcopy(old_mac, vrq->vr_mac, ETHERADDRL);
986*b494511aSVenki Rajagopalan 		vrq->vr_vlan = old_vlan;
987*b494511aSVenki Rajagopalan 	}
988*b494511aSVenki Rajagopalan 
989*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_req_lock);
990*b494511aSVenki Rajagopalan 
991*b494511aSVenki Rajagopalan 	/*
992*b494511aSVenki Rajagopalan 	 * We'll search the failed vnics list to see if the new {mac,vlan}
993*b494511aSVenki Rajagopalan 	 * tuple is in there and remove it if present (since the new address
994*b494511aSVenki Rajagopalan 	 * is no longer "failed").
995*b494511aSVenki Rajagopalan 	 */
996*b494511aSVenki Rajagopalan 	prev = NULL;
997*b494511aSVenki Rajagopalan 	for (elem = ss->ei_failed_vnic_req; elem; elem = elem->vr_next) {
998*b494511aSVenki Rajagopalan 		if ((bcmp(elem->vr_mac, new_mac, ETHERADDRL) == 0) &&
999*b494511aSVenki Rajagopalan 		    (elem->vr_vlan == new_vlan)) {
1000*b494511aSVenki Rajagopalan 			if (prev) {
1001*b494511aSVenki Rajagopalan 				prev->vr_next = elem->vr_next;
1002*b494511aSVenki Rajagopalan 			} else {
1003*b494511aSVenki Rajagopalan 				ss->ei_failed_vnic_req = elem->vr_next;
1004*b494511aSVenki Rajagopalan 			}
1005*b494511aSVenki Rajagopalan 			elem->vr_next = NULL;
1006*b494511aSVenki Rajagopalan 			break;
1007*b494511aSVenki Rajagopalan 		}
1008*b494511aSVenki Rajagopalan 	}
1009*b494511aSVenki Rajagopalan 	if (elem) {
1010*b494511aSVenki Rajagopalan 		kmem_free(elem, sizeof (eib_vnic_req_t));
1011*b494511aSVenki Rajagopalan 	}
1012*b494511aSVenki Rajagopalan 
1013*b494511aSVenki Rajagopalan 	/*
1014*b494511aSVenki Rajagopalan 	 * We'll also insert the old {mac,vlan} tuple to the "failed vnic req"
1015*b494511aSVenki Rajagopalan 	 * list (it shouldn't be there already), to avoid trying to recreate
1016*b494511aSVenki Rajagopalan 	 * the vnic we just explicitly discarded.
1017*b494511aSVenki Rajagopalan 	 */
1018*b494511aSVenki Rajagopalan 	if (vrq) {
1019*b494511aSVenki Rajagopalan 		vrq->vr_next = ss->ei_failed_vnic_req;
1020*b494511aSVenki Rajagopalan 		ss->ei_failed_vnic_req = vrq;
1021*b494511aSVenki Rajagopalan 	}
1022*b494511aSVenki Rajagopalan 
1023*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_req_lock);
1024*b494511aSVenki Rajagopalan }
1025*b494511aSVenki Rajagopalan 
1026*b494511aSVenki Rajagopalan void
eib_vnic_resurrect_zombies(eib_t * ss,uint8_t * vn0_mac)1027*b494511aSVenki Rajagopalan eib_vnic_resurrect_zombies(eib_t *ss, uint8_t *vn0_mac)
1028*b494511aSVenki Rajagopalan {
1029*b494511aSVenki Rajagopalan 	int inst;
1030*b494511aSVenki Rajagopalan 
1031*b494511aSVenki Rajagopalan 	/*
1032*b494511aSVenki Rajagopalan 	 * We want to restart/relogin each vnic instance with the gateway,
1033*b494511aSVenki Rajagopalan 	 * but with the same vnic id and instance as before.
1034*b494511aSVenki Rajagopalan 	 */
1035*b494511aSVenki Rajagopalan 	while ((inst = EIB_FIND_LSB_SET(ss->ei_zombie_vnics)) != -1) {
1036*b494511aSVenki Rajagopalan 		EIB_DPRINTF_DEBUG(ss->ei_instance,
1037*b494511aSVenki Rajagopalan 		    "eib_vnic_resurrect_zombies: "
1038*b494511aSVenki Rajagopalan 		    "calling eib_vnic_restart(vn_inst=%d)", inst);
1039*b494511aSVenki Rajagopalan 
1040*b494511aSVenki Rajagopalan 		eib_vnic_restart(ss, inst, vn0_mac);
1041*b494511aSVenki Rajagopalan 
1042*b494511aSVenki Rajagopalan 		EIB_DPRINTF_DEBUG(ss->ei_instance,
1043*b494511aSVenki Rajagopalan 		    "eib_vnic_resurrect_zombies: "
1044*b494511aSVenki Rajagopalan 		    "eib_vnic_restart(vn_inst=%d) done", inst);
1045*b494511aSVenki Rajagopalan 	}
1046*b494511aSVenki Rajagopalan }
1047*b494511aSVenki Rajagopalan 
1048*b494511aSVenki Rajagopalan void
eib_vnic_restart(eib_t * ss,int inst,uint8_t * vn0_mac)1049*b494511aSVenki Rajagopalan eib_vnic_restart(eib_t *ss, int inst, uint8_t *vn0_mac)
1050*b494511aSVenki Rajagopalan {
1051*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic;
1052*b494511aSVenki Rajagopalan 	eib_login_data_t *ld;
1053*b494511aSVenki Rajagopalan 	uint8_t old_mac[ETHERADDRL];
1054*b494511aSVenki Rajagopalan 	int ret;
1055*b494511aSVenki Rajagopalan 	int err;
1056*b494511aSVenki Rajagopalan 
1057*b494511aSVenki Rajagopalan 	if (inst < 0 || inst >= EIB_MAX_VNICS) {
1058*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1059*b494511aSVenki Rajagopalan 		    "eib_vnic_restart: "
1060*b494511aSVenki Rajagopalan 		    "vnic instance (%d) invalid", inst);
1061*b494511aSVenki Rajagopalan 		return;
1062*b494511aSVenki Rajagopalan 	}
1063*b494511aSVenki Rajagopalan 
1064*b494511aSVenki Rajagopalan 	eib_vnic_modify_enter(ss, EIB_VN_BEING_MODIFIED);
1065*b494511aSVenki Rajagopalan 	if ((vnic = ss->ei_vnic[inst]) != NULL) {
1066*b494511aSVenki Rajagopalan 		/*
1067*b494511aSVenki Rajagopalan 		 * Remember what mac was allocated for this vnic last time
1068*b494511aSVenki Rajagopalan 		 */
1069*b494511aSVenki Rajagopalan 		bcopy(vnic->vn_login_data.ld_assigned_mac, old_mac, ETHERADDRL);
1070*b494511aSVenki Rajagopalan 
1071*b494511aSVenki Rajagopalan 		/*
1072*b494511aSVenki Rajagopalan 		 * Tear down and restart this vnic instance
1073*b494511aSVenki Rajagopalan 		 */
1074*b494511aSVenki Rajagopalan 		eib_rb_vnic_create_common(ss, vnic, ~0);
1075*b494511aSVenki Rajagopalan 		ret = eib_vnic_create_common(ss, vnic, &err);
1076*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
1077*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1078*b494511aSVenki Rajagopalan 			    "eib_vnic_restart: "
1079*b494511aSVenki Rajagopalan 			    "eib_vnic_create_common(vnic_inst=%d) failed, "
1080*b494511aSVenki Rajagopalan 			    "ret=%d", inst, err);
1081*b494511aSVenki Rajagopalan 		}
1082*b494511aSVenki Rajagopalan 
1083*b494511aSVenki Rajagopalan 		/*
1084*b494511aSVenki Rajagopalan 		 * If this is vnic instance 0 and if our current assigned mac is
1085*b494511aSVenki Rajagopalan 		 * different from what was assigned last time, we need to pass
1086*b494511aSVenki Rajagopalan 		 * this information back to the caller, so the mac layer can be
1087*b494511aSVenki Rajagopalan 		 * appropriately informed. We will also queue up the old mac
1088*b494511aSVenki Rajagopalan 		 * and vlan in the "failed vnic req" list, so any future packets
1089*b494511aSVenki Rajagopalan 		 * to this address on this interface will be dropped.
1090*b494511aSVenki Rajagopalan 		 */
1091*b494511aSVenki Rajagopalan 		ld = &vnic->vn_login_data;
1092*b494511aSVenki Rajagopalan 		if ((inst == 0) &&
1093*b494511aSVenki Rajagopalan 		    (bcmp(ld->ld_assigned_mac, old_mac, ETHERADDRL) != 0)) {
1094*b494511aSVenki Rajagopalan 			uint8_t *m = ld->ld_assigned_mac;
1095*b494511aSVenki Rajagopalan 
1096*b494511aSVenki Rajagopalan 			if (vn0_mac != NULL) {
1097*b494511aSVenki Rajagopalan 				bcopy(ld->ld_assigned_mac, vn0_mac,
1098*b494511aSVenki Rajagopalan 				    ETHERADDRL);
1099*b494511aSVenki Rajagopalan 			}
1100*b494511aSVenki Rajagopalan 
1101*b494511aSVenki Rajagopalan 			EIB_DPRINTF_VERBOSE(ss->ei_instance,
1102*b494511aSVenki Rajagopalan 			    "eib_vnic_restart: updating failed macs list "
1103*b494511aSVenki Rajagopalan 			    "old=%x:%x:%x:%x:%x:%x, new=%x:%x:%x:%x:%x:%x, "
1104*b494511aSVenki Rajagopalan 			    "vlan=0x%x", old_mac[0], old_mac[1], old_mac[2],
1105*b494511aSVenki Rajagopalan 			    old_mac[3], old_mac[4], old_mac[5], m[0], m[1],
1106*b494511aSVenki Rajagopalan 			    m[2], m[3], m[4], m[5], vnic->vn_vlan);
1107*b494511aSVenki Rajagopalan 
1108*b494511aSVenki Rajagopalan 			eib_vnic_update_failed_macs(ss, old_mac, vnic->vn_vlan,
1109*b494511aSVenki Rajagopalan 			    ld->ld_assigned_mac, vnic->vn_vlan);
1110*b494511aSVenki Rajagopalan 		}
1111*b494511aSVenki Rajagopalan 
1112*b494511aSVenki Rajagopalan 		/*
1113*b494511aSVenki Rajagopalan 		 * No longer a zombie or need to rejoin mcgs
1114*b494511aSVenki Rajagopalan 		 */
1115*b494511aSVenki Rajagopalan 		mutex_enter(&ss->ei_vnic_lock);
1116*b494511aSVenki Rajagopalan 		ss->ei_zombie_vnics &= (~((uint64_t)1 << inst));
1117*b494511aSVenki Rajagopalan 		ss->ei_rejoin_vnics &= (~((uint64_t)1 << inst));
1118*b494511aSVenki Rajagopalan 		mutex_exit(&ss->ei_vnic_lock);
1119*b494511aSVenki Rajagopalan 	}
1120*b494511aSVenki Rajagopalan 	eib_vnic_modify_exit(ss, EIB_VN_BEING_MODIFIED);
1121*b494511aSVenki Rajagopalan }
1122*b494511aSVenki Rajagopalan 
1123*b494511aSVenki Rajagopalan void
eib_vnic_rejoin_mcgs(eib_t * ss)1124*b494511aSVenki Rajagopalan eib_vnic_rejoin_mcgs(eib_t *ss)
1125*b494511aSVenki Rajagopalan {
1126*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic;
1127*b494511aSVenki Rajagopalan 	int inst;
1128*b494511aSVenki Rajagopalan 
1129*b494511aSVenki Rajagopalan 	/*
1130*b494511aSVenki Rajagopalan 	 * For each vnic that still requires re-join, go through the
1131*b494511aSVenki Rajagopalan 	 * control channels and data channel and reattach/rejoin mcgs.
1132*b494511aSVenki Rajagopalan 	 */
1133*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1134*b494511aSVenki Rajagopalan 	while ((inst = EIB_FIND_LSB_SET(ss->ei_rejoin_vnics)) != -1) {
1135*b494511aSVenki Rajagopalan 		if ((vnic = ss->ei_vnic[inst]) != NULL) {
1136*b494511aSVenki Rajagopalan 			eib_vnic_reattach_ctl_mcgs(ss, vnic);
1137*b494511aSVenki Rajagopalan 			eib_vnic_rejoin_data_mcgs(ss, vnic);
1138*b494511aSVenki Rajagopalan 		}
1139*b494511aSVenki Rajagopalan 		ss->ei_rejoin_vnics &= (~((uint64_t)1 << inst));
1140*b494511aSVenki Rajagopalan 	}
1141*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1142*b494511aSVenki Rajagopalan }
1143*b494511aSVenki Rajagopalan 
1144*b494511aSVenki Rajagopalan void
eib_rb_vnic_create(eib_t * ss,eib_vnic_t * vnic,uint_t progress)1145*b494511aSVenki Rajagopalan eib_rb_vnic_create(eib_t *ss, eib_vnic_t *vnic, uint_t progress)
1146*b494511aSVenki Rajagopalan {
1147*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_CREATE_COMMON_DONE) {
1148*b494511aSVenki Rajagopalan 		eib_rb_vnic_create_common(ss, vnic, ~0);
1149*b494511aSVenki Rajagopalan 	}
1150*b494511aSVenki Rajagopalan 
1151*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_GOT_INSTANCE) {
1152*b494511aSVenki Rajagopalan 		eib_vnic_ret_instance(ss, vnic->vn_instance);
1153*b494511aSVenki Rajagopalan 		vnic->vn_instance = -1;
1154*b494511aSVenki Rajagopalan 	}
1155*b494511aSVenki Rajagopalan 
1156*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_STRUCT_ALLOCD) {
1157*b494511aSVenki Rajagopalan 		cv_destroy(&vnic->vn_cv);
1158*b494511aSVenki Rajagopalan 		mutex_destroy(&vnic->vn_lock);
1159*b494511aSVenki Rajagopalan 		kmem_free(vnic, sizeof (eib_vnic_t));
1160*b494511aSVenki Rajagopalan 	}
1161*b494511aSVenki Rajagopalan }
1162*b494511aSVenki Rajagopalan 
1163*b494511aSVenki Rajagopalan /*
1164*b494511aSVenki Rajagopalan  * Currently, we only allow 64 vnics per eoib device instance, for
1165*b494511aSVenki Rajagopalan  * reasons described in eib.h (see EIB_VNIC_ID() definition), so we
1166*b494511aSVenki Rajagopalan  * could use a simple bitmap to assign the vnic instance numbers.
1167*b494511aSVenki Rajagopalan  * Once we start allowing more vnics per device instance, this
1168*b494511aSVenki Rajagopalan  * allocation scheme will need to be changed.
1169*b494511aSVenki Rajagopalan  */
1170*b494511aSVenki Rajagopalan static int
eib_vnic_get_instance(eib_t * ss,int * vinst)1171*b494511aSVenki Rajagopalan eib_vnic_get_instance(eib_t *ss, int *vinst)
1172*b494511aSVenki Rajagopalan {
1173*b494511aSVenki Rajagopalan 	int bitpos;
1174*b494511aSVenki Rajagopalan 	uint64_t nval;
1175*b494511aSVenki Rajagopalan 
1176*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1177*b494511aSVenki Rajagopalan 
1178*b494511aSVenki Rajagopalan 	/*
1179*b494511aSVenki Rajagopalan 	 * What we have is the active vnics list --  the in-use vnics are
1180*b494511aSVenki Rajagopalan 	 * indicated by a 1 in the bit position, and the free ones are
1181*b494511aSVenki Rajagopalan 	 * indicated by 0.  We need to find the least significant '0' bit
1182*b494511aSVenki Rajagopalan 	 * to get the first free vnic instance.  Or we could bit-reverse
1183*b494511aSVenki Rajagopalan 	 * the active list and locate the least significant '1'.
1184*b494511aSVenki Rajagopalan 	 */
1185*b494511aSVenki Rajagopalan 	nval = ~(ss->ei_active_vnics);
1186*b494511aSVenki Rajagopalan 	if (nval == 0)
1187*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1188*b494511aSVenki Rajagopalan 
1189*b494511aSVenki Rajagopalan 	/*
1190*b494511aSVenki Rajagopalan 	 * The single bit-position values in a 64-bit integer are relatively
1191*b494511aSVenki Rajagopalan 	 * prime with 67, so performing a modulus division with 67 guarantees
1192*b494511aSVenki Rajagopalan 	 * a unique number between 0 and 63 for each value (setbit_mod67[]).
1193*b494511aSVenki Rajagopalan 	 */
1194*b494511aSVenki Rajagopalan 	bitpos = EIB_FIND_LSB_SET(nval);
1195*b494511aSVenki Rajagopalan 	if (bitpos == -1)
1196*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1197*b494511aSVenki Rajagopalan 
1198*b494511aSVenki Rajagopalan 	ss->ei_active_vnics |= ((uint64_t)1 << bitpos);
1199*b494511aSVenki Rajagopalan 	*vinst = bitpos;
1200*b494511aSVenki Rajagopalan 
1201*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1202*b494511aSVenki Rajagopalan 
1203*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1204*b494511aSVenki Rajagopalan }
1205*b494511aSVenki Rajagopalan 
1206*b494511aSVenki Rajagopalan static void
eib_vnic_ret_instance(eib_t * ss,int vinst)1207*b494511aSVenki Rajagopalan eib_vnic_ret_instance(eib_t *ss, int vinst)
1208*b494511aSVenki Rajagopalan {
1209*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1210*b494511aSVenki Rajagopalan 
1211*b494511aSVenki Rajagopalan 	if (vinst >= EIB_MAX_VNICS) {
1212*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1213*b494511aSVenki Rajagopalan 		    "eib_vnic_ret_instance: "
1214*b494511aSVenki Rajagopalan 		    "vnic instance (%d) invalid", vinst);
1215*b494511aSVenki Rajagopalan 	} else if ((ss->ei_active_vnics & ((uint64_t)1 << vinst)) == 0) {
1216*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1217*b494511aSVenki Rajagopalan 		    "eib_vnic_ret_instance: "
1218*b494511aSVenki Rajagopalan 		    "vnic instance (%d) not active!", vinst);
1219*b494511aSVenki Rajagopalan 	} else {
1220*b494511aSVenki Rajagopalan 		ss->ei_active_vnics &= (~((uint64_t)1 << vinst));
1221*b494511aSVenki Rajagopalan 	}
1222*b494511aSVenki Rajagopalan 
1223*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1224*b494511aSVenki Rajagopalan }
1225*b494511aSVenki Rajagopalan 
1226*b494511aSVenki Rajagopalan static void
eib_vnic_modify_enter(eib_t * ss,uint_t op)1227*b494511aSVenki Rajagopalan eib_vnic_modify_enter(eib_t *ss, uint_t op)
1228*b494511aSVenki Rajagopalan {
1229*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1230*b494511aSVenki Rajagopalan 	while (ss->ei_vnic_state & EIB_VN_BEING_MODIFIED)
1231*b494511aSVenki Rajagopalan 		cv_wait(&ss->ei_vnic_cv, &ss->ei_vnic_lock);
1232*b494511aSVenki Rajagopalan 
1233*b494511aSVenki Rajagopalan 	ss->ei_vnic_state |= op;
1234*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1235*b494511aSVenki Rajagopalan }
1236*b494511aSVenki Rajagopalan 
1237*b494511aSVenki Rajagopalan static void
eib_vnic_modify_exit(eib_t * ss,uint_t op)1238*b494511aSVenki Rajagopalan eib_vnic_modify_exit(eib_t *ss, uint_t op)
1239*b494511aSVenki Rajagopalan {
1240*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1241*b494511aSVenki Rajagopalan 	ss->ei_vnic_state &= (~op);
1242*b494511aSVenki Rajagopalan 	cv_broadcast(&ss->ei_vnic_cv);
1243*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1244*b494511aSVenki Rajagopalan }
1245*b494511aSVenki Rajagopalan 
1246*b494511aSVenki Rajagopalan static int
eib_vnic_create_common(eib_t * ss,eib_vnic_t * vnic,int * err)1247*b494511aSVenki Rajagopalan eib_vnic_create_common(eib_t *ss, eib_vnic_t *vnic, int *err)
1248*b494511aSVenki Rajagopalan {
1249*b494511aSVenki Rajagopalan 	uint_t progress = 0;
1250*b494511aSVenki Rajagopalan 
1251*b494511aSVenki Rajagopalan 	/*
1252*b494511aSVenki Rajagopalan 	 * When we receive login acks within this vnic creation
1253*b494511aSVenki Rajagopalan 	 * routine we need a way to retrieve the vnic structure
1254*b494511aSVenki Rajagopalan 	 * from the vnic instance, so store this somewhere. Note
1255*b494511aSVenki Rajagopalan 	 * that there can be only one outstanding vnic creation
1256*b494511aSVenki Rajagopalan 	 * at any point of time, so we only need one vnic struct.
1257*b494511aSVenki Rajagopalan 	 */
1258*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1259*b494511aSVenki Rajagopalan 	ASSERT(ss->ei_vnic_pending == NULL);
1260*b494511aSVenki Rajagopalan 	ss->ei_vnic_pending = vnic;
1261*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1262*b494511aSVenki Rajagopalan 
1263*b494511aSVenki Rajagopalan 	/*
1264*b494511aSVenki Rajagopalan 	 * Create a control qp for this vnic
1265*b494511aSVenki Rajagopalan 	 */
1266*b494511aSVenki Rajagopalan 	if (eib_ctl_create_qp(ss, vnic, err) != EIB_E_SUCCESS) {
1267*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1268*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1269*b494511aSVenki Rajagopalan 		    "eib_ctl_create_qp(vn_id=0x%x) failed, ret=%d",
1270*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1271*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1272*b494511aSVenki Rajagopalan 	}
1273*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_CTLQP_CREATED;
1274*b494511aSVenki Rajagopalan 
1275*b494511aSVenki Rajagopalan 	/*
1276*b494511aSVenki Rajagopalan 	 * Create a data qp for this vnic
1277*b494511aSVenki Rajagopalan 	 */
1278*b494511aSVenki Rajagopalan 	if (eib_data_create_qp(ss, vnic, err) != EIB_E_SUCCESS) {
1279*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1280*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1281*b494511aSVenki Rajagopalan 		    "eib_data_create_qp(vn_id=0x%x) failed, ret=%d",
1282*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1283*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1284*b494511aSVenki Rajagopalan 	}
1285*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_DATAQP_CREATED;
1286*b494511aSVenki Rajagopalan 
1287*b494511aSVenki Rajagopalan 	/*
1288*b494511aSVenki Rajagopalan 	 * Login to the gateway with this vnic's parameters
1289*b494511aSVenki Rajagopalan 	 */
1290*b494511aSVenki Rajagopalan 	if (eib_fip_login(ss, vnic, err) != EIB_E_SUCCESS) {
1291*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1292*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1293*b494511aSVenki Rajagopalan 		    "eib_fip_login(vn_id=0x%x) failed, ret=%d",
1294*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1295*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1296*b494511aSVenki Rajagopalan 	}
1297*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_LOGIN_DONE;
1298*b494511aSVenki Rajagopalan 
1299*b494511aSVenki Rajagopalan 	/*
1300*b494511aSVenki Rajagopalan 	 * Associate the control and data qps for the vnic with the
1301*b494511aSVenki Rajagopalan 	 * vHUB partition
1302*b494511aSVenki Rajagopalan 	 */
1303*b494511aSVenki Rajagopalan 	if (eib_vnic_set_partition(ss, vnic, err) != EIB_E_SUCCESS) {
1304*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1305*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1306*b494511aSVenki Rajagopalan 		    "eib_vnic_set_partition(vn_id=0x%x) failed, ret=%d",
1307*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1308*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1309*b494511aSVenki Rajagopalan 	}
1310*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_PARTITION_SET;
1311*b494511aSVenki Rajagopalan 
1312*b494511aSVenki Rajagopalan 	/*
1313*b494511aSVenki Rajagopalan 	 * Post initial set of rx buffers on the control qp to the HCA
1314*b494511aSVenki Rajagopalan 	 */
1315*b494511aSVenki Rajagopalan 	if (eib_chan_post_rx(ss, vnic->vn_ctl_chan, NULL) != EIB_E_SUCCESS) {
1316*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1317*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1318*b494511aSVenki Rajagopalan 		    "eib_chan_post_rx(vn_id=0x%x, CTL_QP) failed, ret=%d",
1319*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1320*b494511aSVenki Rajagopalan 
1321*b494511aSVenki Rajagopalan 		*err = ENOMEM;
1322*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1323*b494511aSVenki Rajagopalan 	}
1324*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_RX_POSTED_TO_CTLQP;
1325*b494511aSVenki Rajagopalan 
1326*b494511aSVenki Rajagopalan 	/*
1327*b494511aSVenki Rajagopalan 	 * Post initial set of rx buffers on the data qp to the HCA
1328*b494511aSVenki Rajagopalan 	 */
1329*b494511aSVenki Rajagopalan 	if (eib_chan_post_rx(ss, vnic->vn_data_chan, NULL) != EIB_E_SUCCESS) {
1330*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1331*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1332*b494511aSVenki Rajagopalan 		    "eib_chan_post_rx(vn_id=0x%x, DATA_QP) failed, ret=%d",
1333*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1334*b494511aSVenki Rajagopalan 
1335*b494511aSVenki Rajagopalan 		*err = ENOMEM;
1336*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1337*b494511aSVenki Rajagopalan 	}
1338*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_RX_POSTED_TO_DATAQP;
1339*b494511aSVenki Rajagopalan 
1340*b494511aSVenki Rajagopalan 	/*
1341*b494511aSVenki Rajagopalan 	 * Attach to the vHUB table and vHUB update multicast groups
1342*b494511aSVenki Rajagopalan 	 */
1343*b494511aSVenki Rajagopalan 	if (eib_vnic_attach_ctl_mcgs(ss, vnic, err) != EIB_E_SUCCESS) {
1344*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1345*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1346*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_ctl_mcgs(vn_id=0x%x) failed, ret=%d",
1347*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1348*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1349*b494511aSVenki Rajagopalan 	}
1350*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_ATTACHED_TO_CTL_MCGS;
1351*b494511aSVenki Rajagopalan 
1352*b494511aSVenki Rajagopalan 	/*
1353*b494511aSVenki Rajagopalan 	 * Send the vHUB table request and construct the vhub table
1354*b494511aSVenki Rajagopalan 	 */
1355*b494511aSVenki Rajagopalan 	if (eib_fip_vhub_table(ss, vnic, err) != EIB_E_SUCCESS) {
1356*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1357*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1358*b494511aSVenki Rajagopalan 		    "eib_fip_vhub_table(vn_id=0x%x) failed, ret=%d",
1359*b494511aSVenki Rajagopalan 		    vnic->vn_id, *err);
1360*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1361*b494511aSVenki Rajagopalan 	}
1362*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_GOT_VHUB_TABLE;
1363*b494511aSVenki Rajagopalan 
1364*b494511aSVenki Rajagopalan 	/*
1365*b494511aSVenki Rajagopalan 	 * Detach from the vHUB table mcg (we no longer need the vHUB
1366*b494511aSVenki Rajagopalan 	 * table messages) and start the keepalives for this vnic.
1367*b494511aSVenki Rajagopalan 	 */
1368*b494511aSVenki Rajagopalan 	eib_vnic_start_keepalives(ss, vnic);
1369*b494511aSVenki Rajagopalan 	eib_rb_vnic_attach_vhub_table(ss, vnic);
1370*b494511aSVenki Rajagopalan 
1371*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_KEEPALIVES_STARTED;
1372*b494511aSVenki Rajagopalan 
1373*b494511aSVenki Rajagopalan 	/*
1374*b494511aSVenki Rajagopalan 	 * All ethernet vnics are automatically members of the broadcast
1375*b494511aSVenki Rajagopalan 	 * group for the vlan they are participating in, so join the
1376*b494511aSVenki Rajagopalan 	 * ethernet broadcast group.  Note that when we restart vnics,
1377*b494511aSVenki Rajagopalan 	 * we rejoin the mcgs, so we pass B_TRUE to eib_vnic_join_data_mcg().
1378*b494511aSVenki Rajagopalan 	 */
1379*b494511aSVenki Rajagopalan 	if (eib_vnic_join_data_mcg(ss, vnic, eib_broadcast_mac, B_TRUE,
1380*b494511aSVenki Rajagopalan 	    err) != EIB_E_SUCCESS) {
1381*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1382*b494511aSVenki Rajagopalan 		    "eib_vnic_create_common: "
1383*b494511aSVenki Rajagopalan 		    "eib_vnic_join_data_mcg(vn_id=0x%x, BCAST_GROUP) failed, "
1384*b494511aSVenki Rajagopalan 		    "ret=%d", vnic->vn_id, *err);
1385*b494511aSVenki Rajagopalan 		goto vnic_create_common_fail;
1386*b494511aSVenki Rajagopalan 	}
1387*b494511aSVenki Rajagopalan 	progress |= EIB_VNIC_BROADCAST_JOINED;
1388*b494511aSVenki Rajagopalan 
1389*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1390*b494511aSVenki Rajagopalan 	if (ss->ei_vnic[vnic->vn_instance] == NULL) {
1391*b494511aSVenki Rajagopalan 		ss->ei_vnic[vnic->vn_instance] = vnic;
1392*b494511aSVenki Rajagopalan 	}
1393*b494511aSVenki Rajagopalan 	ss->ei_vnic_pending = NULL;
1394*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1395*b494511aSVenki Rajagopalan 
1396*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1397*b494511aSVenki Rajagopalan 
1398*b494511aSVenki Rajagopalan vnic_create_common_fail:
1399*b494511aSVenki Rajagopalan 	eib_rb_vnic_create_common(ss, vnic, progress);
1400*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
1401*b494511aSVenki Rajagopalan }
1402*b494511aSVenki Rajagopalan 
1403*b494511aSVenki Rajagopalan static int
eib_vnic_set_partition(eib_t * ss,eib_vnic_t * vnic,int * err)1404*b494511aSVenki Rajagopalan eib_vnic_set_partition(eib_t *ss, eib_vnic_t *vnic, int *err)
1405*b494511aSVenki Rajagopalan {
1406*b494511aSVenki Rajagopalan 	int ret;
1407*b494511aSVenki Rajagopalan 
1408*b494511aSVenki Rajagopalan 	/*
1409*b494511aSVenki Rajagopalan 	 * Associate the control channel with the vhub partition
1410*b494511aSVenki Rajagopalan 	 */
1411*b494511aSVenki Rajagopalan 	ret = eib_ibt_modify_chan_pkey(ss, vnic->vn_ctl_chan,
1412*b494511aSVenki Rajagopalan 	    vnic->vn_login_data.ld_vhub_pkey);
1413*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
1414*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1415*b494511aSVenki Rajagopalan 		    "eib_vnic_set_partition: "
1416*b494511aSVenki Rajagopalan 		    "eib_ibt_modify_chan_pkey(vn_id=0x%x, CTL_CHAN, "
1417*b494511aSVenki Rajagopalan 		    "vhub_pkey=0x%x) failed", vnic->vn_id,
1418*b494511aSVenki Rajagopalan 		    vnic->vn_login_data.ld_vhub_pkey);
1419*b494511aSVenki Rajagopalan 		*err = EINVAL;
1420*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1421*b494511aSVenki Rajagopalan 	}
1422*b494511aSVenki Rajagopalan 
1423*b494511aSVenki Rajagopalan 	/*
1424*b494511aSVenki Rajagopalan 	 * Now, do the same thing for the data channel. Note that if a
1425*b494511aSVenki Rajagopalan 	 * failure happens, the channel state(s) are left as-is, since
1426*b494511aSVenki Rajagopalan 	 * it is pointless to try to change them back using the same
1427*b494511aSVenki Rajagopalan 	 * interfaces that have just failed.
1428*b494511aSVenki Rajagopalan 	 */
1429*b494511aSVenki Rajagopalan 	ret = eib_ibt_modify_chan_pkey(ss, vnic->vn_data_chan,
1430*b494511aSVenki Rajagopalan 	    vnic->vn_login_data.ld_vhub_pkey);
1431*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
1432*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1433*b494511aSVenki Rajagopalan 		    "eib_vnic_set_partition: "
1434*b494511aSVenki Rajagopalan 		    "eib_ibt_modify_chan_pkey(vn_id=0x%x, DATA_CHAN, "
1435*b494511aSVenki Rajagopalan 		    "vhub_pkey=0x%x) failed", vnic->vn_id,
1436*b494511aSVenki Rajagopalan 		    vnic->vn_login_data.ld_vhub_pkey);
1437*b494511aSVenki Rajagopalan 		*err = EINVAL;
1438*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1439*b494511aSVenki Rajagopalan 	}
1440*b494511aSVenki Rajagopalan 
1441*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1442*b494511aSVenki Rajagopalan }
1443*b494511aSVenki Rajagopalan 
1444*b494511aSVenki Rajagopalan static void
eib_vnic_make_vhub_mgid(uint8_t * mg_prefix,uint8_t mg_type,uint8_t * mcast_mac,uint8_t n_mac,uint8_t rss_hash,uint32_t vhub_id,ib_gid_t * mgid)1445*b494511aSVenki Rajagopalan eib_vnic_make_vhub_mgid(uint8_t *mg_prefix, uint8_t mg_type,
1446*b494511aSVenki Rajagopalan     uint8_t *mcast_mac, uint8_t n_mac, uint8_t rss_hash, uint32_t vhub_id,
1447*b494511aSVenki Rajagopalan     ib_gid_t *mgid)
1448*b494511aSVenki Rajagopalan {
1449*b494511aSVenki Rajagopalan 	eib_mgid_t em;
1450*b494511aSVenki Rajagopalan 	uint64_t dmac_mask;
1451*b494511aSVenki Rajagopalan 	uint64_t dmac = 0;
1452*b494511aSVenki Rajagopalan 	uint8_t *dmac_str = (uint8_t *)&dmac;
1453*b494511aSVenki Rajagopalan 	uint_t	vhub_id_nw;
1454*b494511aSVenki Rajagopalan 	uint8_t *vhub_id_str = (uint8_t *)&vhub_id_nw;
1455*b494511aSVenki Rajagopalan 
1456*b494511aSVenki Rajagopalan 	/*
1457*b494511aSVenki Rajagopalan 	 * Copy mgid prefix and type
1458*b494511aSVenki Rajagopalan 	 */
1459*b494511aSVenki Rajagopalan 	bcopy(mg_prefix, em.gd_spec.sp_mgid_prefix, FIP_MGID_PREFIX_LEN);
1460*b494511aSVenki Rajagopalan 	em.gd_spec.sp_type = mg_type;
1461*b494511aSVenki Rajagopalan 
1462*b494511aSVenki Rajagopalan 	/*
1463*b494511aSVenki Rajagopalan 	 * Take n_mac bits from mcast_mac and copy dmac
1464*b494511aSVenki Rajagopalan 	 */
1465*b494511aSVenki Rajagopalan 	bcopy(mcast_mac, dmac_str + 2, ETHERADDRL);
1466*b494511aSVenki Rajagopalan 	dmac_mask = ((uint64_t)1 << n_mac) - 1;
1467*b494511aSVenki Rajagopalan 	dmac_mask = htonll(dmac_mask);
1468*b494511aSVenki Rajagopalan 	dmac &= dmac_mask;
1469*b494511aSVenki Rajagopalan 	bcopy(dmac_str + 2, em.gd_spec.sp_dmac, ETHERADDRL);
1470*b494511aSVenki Rajagopalan 
1471*b494511aSVenki Rajagopalan 	/*
1472*b494511aSVenki Rajagopalan 	 * Copy rss hash and prepare vhub id from gw port id and vlan
1473*b494511aSVenki Rajagopalan 	 */
1474*b494511aSVenki Rajagopalan 	em.gd_spec.sp_rss_hash = rss_hash;
1475*b494511aSVenki Rajagopalan 
1476*b494511aSVenki Rajagopalan 	vhub_id_nw = htonl(vhub_id);
1477*b494511aSVenki Rajagopalan 	bcopy(vhub_id_str + 1, em.gd_spec.sp_vhub_id, FIP_VHUBID_LEN);
1478*b494511aSVenki Rajagopalan 
1479*b494511aSVenki Rajagopalan 	/*
1480*b494511aSVenki Rajagopalan 	 * Ok, now we've assembled the mgid as per EoIB spec. We now have to
1481*b494511aSVenki Rajagopalan 	 * represent it in the way Solaris IBTF wants it and return (sigh).
1482*b494511aSVenki Rajagopalan 	 */
1483*b494511aSVenki Rajagopalan 	mgid->gid_prefix = ntohll(em.gd_sol.gid_prefix);
1484*b494511aSVenki Rajagopalan 	mgid->gid_guid = ntohll(em.gd_sol.gid_guid);
1485*b494511aSVenki Rajagopalan }
1486*b494511aSVenki Rajagopalan 
1487*b494511aSVenki Rajagopalan static int
eib_vnic_attach_ctl_mcgs(eib_t * ss,eib_vnic_t * vnic,int * err)1488*b494511aSVenki Rajagopalan eib_vnic_attach_ctl_mcgs(eib_t *ss, eib_vnic_t *vnic, int *err)
1489*b494511aSVenki Rajagopalan {
1490*b494511aSVenki Rajagopalan 	/*
1491*b494511aSVenki Rajagopalan 	 * Get tb_vhub_table and tb_vhub_update allocated and ready before
1492*b494511aSVenki Rajagopalan 	 * attaching to the vhub table and vhub update mcgs
1493*b494511aSVenki Rajagopalan 	 */
1494*b494511aSVenki Rajagopalan 	eib_vnic_init_tables(ss, vnic);
1495*b494511aSVenki Rajagopalan 
1496*b494511aSVenki Rajagopalan 	if (eib_vnic_attach_vhub_update(ss, vnic) != EIB_E_SUCCESS) {
1497*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1498*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_ctl_mcgs: "
1499*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update(vn_id=0x%x) failed",
1500*b494511aSVenki Rajagopalan 		    vnic->vn_id);
1501*b494511aSVenki Rajagopalan 
1502*b494511aSVenki Rajagopalan 		*err = EINVAL;
1503*b494511aSVenki Rajagopalan 		eib_vnic_fini_tables(ss, vnic, B_TRUE);
1504*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1505*b494511aSVenki Rajagopalan 	}
1506*b494511aSVenki Rajagopalan 
1507*b494511aSVenki Rajagopalan 	if (eib_vnic_attach_vhub_table(ss, vnic) != EIB_E_SUCCESS) {
1508*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1509*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_ctl_mcgs: "
1510*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table(vn_id=0x%x) failed",
1511*b494511aSVenki Rajagopalan 		    vnic->vn_id);
1512*b494511aSVenki Rajagopalan 
1513*b494511aSVenki Rajagopalan 		*err = EINVAL;
1514*b494511aSVenki Rajagopalan 		eib_rb_vnic_attach_vhub_update(ss, vnic);
1515*b494511aSVenki Rajagopalan 		eib_vnic_fini_tables(ss, vnic, B_TRUE);
1516*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1517*b494511aSVenki Rajagopalan 	}
1518*b494511aSVenki Rajagopalan 
1519*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1520*b494511aSVenki Rajagopalan }
1521*b494511aSVenki Rajagopalan 
1522*b494511aSVenki Rajagopalan static int
eib_vnic_attach_vhub_table(eib_t * ss,eib_vnic_t * vnic)1523*b494511aSVenki Rajagopalan eib_vnic_attach_vhub_table(eib_t *ss, eib_vnic_t *vnic)
1524*b494511aSVenki Rajagopalan {
1525*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_ctl_chan;
1526*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
1527*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
1528*b494511aSVenki Rajagopalan 	ibt_mcg_info_t *tbl_mcginfo;
1529*b494511aSVenki Rajagopalan 	ibt_mcg_attr_t mcg_attr;
1530*b494511aSVenki Rajagopalan 	ibt_status_t ret;
1531*b494511aSVenki Rajagopalan 	uint_t entries;
1532*b494511aSVenki Rajagopalan 
1533*b494511aSVenki Rajagopalan 	/*
1534*b494511aSVenki Rajagopalan 	 * Compose the MGID for receiving VHUB table
1535*b494511aSVenki Rajagopalan 	 */
1536*b494511aSVenki Rajagopalan 	bzero(&mcg_attr, sizeof (ibt_mcg_attr_t));
1537*b494511aSVenki Rajagopalan 
1538*b494511aSVenki Rajagopalan 	eib_vnic_make_vhub_mgid(ld->ld_gw_mgid_prefix,
1539*b494511aSVenki Rajagopalan 	    (uint8_t)EIB_MGID_VHUB_TABLE, eib_broadcast_mac, ld->ld_n_mac_mcgid,
1540*b494511aSVenki Rajagopalan 	    0, ld->ld_vhub_id, &(mcg_attr.mc_mgid));
1541*b494511aSVenki Rajagopalan 	mcg_attr.mc_pkey = (ib_pkey_t)ld->ld_vhub_pkey;
1542*b494511aSVenki Rajagopalan 	mcg_attr.mc_qkey = (ib_qkey_t)EIB_FIP_QKEY;
1543*b494511aSVenki Rajagopalan 
1544*b494511aSVenki Rajagopalan 	/*
1545*b494511aSVenki Rajagopalan 	 * Locate the multicast group for receiving vhub table
1546*b494511aSVenki Rajagopalan 	 */
1547*b494511aSVenki Rajagopalan 	ret = ibt_query_mcg(ss->ei_props->ep_sgid, &mcg_attr, 1,
1548*b494511aSVenki Rajagopalan 	    &tbl_mcginfo, &entries);
1549*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1550*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1551*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table: "
1552*b494511aSVenki Rajagopalan 		    "ibt_query_mcg(mgid=%llx.%llx, pkey=0x%x) failed, "
1553*b494511aSVenki Rajagopalan 		    "ret=%d", mcg_attr.mc_mgid.gid_prefix,
1554*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey, ret);
1555*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1556*b494511aSVenki Rajagopalan 	}
1557*b494511aSVenki Rajagopalan 
1558*b494511aSVenki Rajagopalan 	/*
1559*b494511aSVenki Rajagopalan 	 * Allocate for and prepare the mcg to add to our list
1560*b494511aSVenki Rajagopalan 	 */
1561*b494511aSVenki Rajagopalan 	mcg = kmem_zalloc(sizeof (eib_mcg_t), KM_NOSLEEP);
1562*b494511aSVenki Rajagopalan 	if (mcg == NULL) {
1563*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1564*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table: "
1565*b494511aSVenki Rajagopalan 		    "no memory, failed to attach to vhub table "
1566*b494511aSVenki Rajagopalan 		    "(mgid=%llx.%llx, pkey=0x%x)", mcg_attr.mc_mgid.gid_prefix,
1567*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey);
1568*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(tbl_mcginfo, 1);
1569*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1570*b494511aSVenki Rajagopalan 	}
1571*b494511aSVenki Rajagopalan 
1572*b494511aSVenki Rajagopalan 	mcg->mg_next = NULL;
1573*b494511aSVenki Rajagopalan 	mcg->mg_rgid = ss->ei_props->ep_sgid;
1574*b494511aSVenki Rajagopalan 	mcg->mg_mgid = mcg_attr.mc_mgid;
1575*b494511aSVenki Rajagopalan 	mcg->mg_join_state = IB_MC_JSTATE_FULL;
1576*b494511aSVenki Rajagopalan 	mcg->mg_mcginfo = tbl_mcginfo;
1577*b494511aSVenki Rajagopalan 	bcopy(eib_broadcast_mac, mcg->mg_mac, ETHERADDRL);
1578*b494511aSVenki Rajagopalan 
1579*b494511aSVenki Rajagopalan 	/*
1580*b494511aSVenki Rajagopalan 	 * Join the multicast group
1581*b494511aSVenki Rajagopalan 	 */
1582*b494511aSVenki Rajagopalan 	mcg_attr.mc_join_state = mcg->mg_join_state;
1583*b494511aSVenki Rajagopalan 	mcg_attr.mc_flow = tbl_mcginfo->mc_adds_vect.av_flow;
1584*b494511aSVenki Rajagopalan 	mcg_attr.mc_tclass = tbl_mcginfo->mc_adds_vect.av_tclass;
1585*b494511aSVenki Rajagopalan 	mcg_attr.mc_sl = tbl_mcginfo->mc_adds_vect.av_srvl;
1586*b494511aSVenki Rajagopalan 	mcg_attr.mc_scope = 0;	/* IB_MC_SCOPE_SUBNET_LOCAL perhaps ? */
1587*b494511aSVenki Rajagopalan 
1588*b494511aSVenki Rajagopalan 	ret = ibt_join_mcg(mcg->mg_rgid, &mcg_attr, tbl_mcginfo, NULL, NULL);
1589*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1590*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1591*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table: "
1592*b494511aSVenki Rajagopalan 		    "ibt_join_mcg(mgid=%llx.%llx, pkey=0x%x, jstate=0x%x) "
1593*b494511aSVenki Rajagopalan 		    "failed, ret=%d", mcg_attr.mc_mgid.gid_prefix,
1594*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey,
1595*b494511aSVenki Rajagopalan 		    mcg_attr.mc_join_state, ret);
1596*b494511aSVenki Rajagopalan 
1597*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1598*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(tbl_mcginfo, 1);
1599*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1600*b494511aSVenki Rajagopalan 	}
1601*b494511aSVenki Rajagopalan 
1602*b494511aSVenki Rajagopalan 	/*
1603*b494511aSVenki Rajagopalan 	 * Attach to the multicast group to receive tbl multicasts
1604*b494511aSVenki Rajagopalan 	 */
1605*b494511aSVenki Rajagopalan 	ret = ibt_attach_mcg(chan->ch_chan, tbl_mcginfo);
1606*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1607*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1608*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table: "
1609*b494511aSVenki Rajagopalan 		    "ibt_attach_mcg(mgid=%llx.%llx, pkey=0x%x) "
1610*b494511aSVenki Rajagopalan 		    "failed, ret=%d", mcg_attr.mc_mgid.gid_prefix,
1611*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey);
1612*b494511aSVenki Rajagopalan 
1613*b494511aSVenki Rajagopalan 		(void) ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
1614*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
1615*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1616*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(tbl_mcginfo, 1);
1617*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1618*b494511aSVenki Rajagopalan 	}
1619*b494511aSVenki Rajagopalan 
1620*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
1621*b494511aSVenki Rajagopalan 	chan->ch_vhub_table = mcg;
1622*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
1623*b494511aSVenki Rajagopalan 
1624*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1625*b494511aSVenki Rajagopalan }
1626*b494511aSVenki Rajagopalan 
1627*b494511aSVenki Rajagopalan static int
eib_vnic_attach_vhub_update(eib_t * ss,eib_vnic_t * vnic)1628*b494511aSVenki Rajagopalan eib_vnic_attach_vhub_update(eib_t *ss, eib_vnic_t *vnic)
1629*b494511aSVenki Rajagopalan {
1630*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_ctl_chan;
1631*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
1632*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
1633*b494511aSVenki Rajagopalan 	ibt_mcg_info_t *upd_mcginfo;
1634*b494511aSVenki Rajagopalan 	ibt_mcg_attr_t mcg_attr;
1635*b494511aSVenki Rajagopalan 	ibt_status_t ret;
1636*b494511aSVenki Rajagopalan 	uint_t entries;
1637*b494511aSVenki Rajagopalan 
1638*b494511aSVenki Rajagopalan 	/*
1639*b494511aSVenki Rajagopalan 	 * Compose the MGID for receiving VHUB updates
1640*b494511aSVenki Rajagopalan 	 */
1641*b494511aSVenki Rajagopalan 	bzero(&mcg_attr, sizeof (ibt_mcg_attr_t));
1642*b494511aSVenki Rajagopalan 
1643*b494511aSVenki Rajagopalan 	eib_vnic_make_vhub_mgid(ld->ld_gw_mgid_prefix,
1644*b494511aSVenki Rajagopalan 	    (uint8_t)EIB_MGID_VHUB_UPDATE, eib_broadcast_mac,
1645*b494511aSVenki Rajagopalan 	    ld->ld_n_mac_mcgid, 0, ld->ld_vhub_id, &(mcg_attr.mc_mgid));
1646*b494511aSVenki Rajagopalan 	mcg_attr.mc_pkey = (ib_pkey_t)ld->ld_vhub_pkey;
1647*b494511aSVenki Rajagopalan 	mcg_attr.mc_qkey = (ib_qkey_t)EIB_FIP_QKEY;
1648*b494511aSVenki Rajagopalan 
1649*b494511aSVenki Rajagopalan 	/*
1650*b494511aSVenki Rajagopalan 	 * Locate the multicast group for receiving vhub updates
1651*b494511aSVenki Rajagopalan 	 */
1652*b494511aSVenki Rajagopalan 	ret = ibt_query_mcg(ss->ei_props->ep_sgid, &mcg_attr, 1,
1653*b494511aSVenki Rajagopalan 	    &upd_mcginfo, &entries);
1654*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1655*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1656*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update: "
1657*b494511aSVenki Rajagopalan 		    "ibt_query_mcg(mgid=%llx.%llx, pkey=0x%x) failed, "
1658*b494511aSVenki Rajagopalan 		    "ret=%d", mcg_attr.mc_mgid.gid_prefix,
1659*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey, ret);
1660*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1661*b494511aSVenki Rajagopalan 	}
1662*b494511aSVenki Rajagopalan 
1663*b494511aSVenki Rajagopalan 	/*
1664*b494511aSVenki Rajagopalan 	 * Allocate for and prepare the mcg to add to our list
1665*b494511aSVenki Rajagopalan 	 */
1666*b494511aSVenki Rajagopalan 	mcg = kmem_zalloc(sizeof (eib_mcg_t), KM_NOSLEEP);
1667*b494511aSVenki Rajagopalan 	if (mcg == NULL) {
1668*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1669*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update: "
1670*b494511aSVenki Rajagopalan 		    "no memory, failed to attach to vhub update "
1671*b494511aSVenki Rajagopalan 		    "(mgid=%llx.%llx, pkey=0x%x)", mcg_attr.mc_mgid.gid_prefix,
1672*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey);
1673*b494511aSVenki Rajagopalan 
1674*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(upd_mcginfo, 1);
1675*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1676*b494511aSVenki Rajagopalan 	}
1677*b494511aSVenki Rajagopalan 
1678*b494511aSVenki Rajagopalan 	mcg->mg_next = NULL;
1679*b494511aSVenki Rajagopalan 	mcg->mg_rgid = ss->ei_props->ep_sgid;
1680*b494511aSVenki Rajagopalan 	mcg->mg_mgid = mcg_attr.mc_mgid;
1681*b494511aSVenki Rajagopalan 	mcg->mg_join_state = IB_MC_JSTATE_FULL;
1682*b494511aSVenki Rajagopalan 	mcg->mg_mcginfo = upd_mcginfo;
1683*b494511aSVenki Rajagopalan 	bcopy(eib_broadcast_mac, mcg->mg_mac, ETHERADDRL);
1684*b494511aSVenki Rajagopalan 
1685*b494511aSVenki Rajagopalan 	/*
1686*b494511aSVenki Rajagopalan 	 * Join the multicast group
1687*b494511aSVenki Rajagopalan 	 */
1688*b494511aSVenki Rajagopalan 	mcg_attr.mc_join_state = mcg->mg_join_state;
1689*b494511aSVenki Rajagopalan 	mcg_attr.mc_flow = upd_mcginfo->mc_adds_vect.av_flow;
1690*b494511aSVenki Rajagopalan 	mcg_attr.mc_tclass = upd_mcginfo->mc_adds_vect.av_tclass;
1691*b494511aSVenki Rajagopalan 	mcg_attr.mc_sl = upd_mcginfo->mc_adds_vect.av_srvl;
1692*b494511aSVenki Rajagopalan 	mcg_attr.mc_scope = 0;	/* IB_MC_SCOPE_SUBNET_LOCAL perhaps ? */
1693*b494511aSVenki Rajagopalan 
1694*b494511aSVenki Rajagopalan 	ret = ibt_join_mcg(mcg->mg_rgid, &mcg_attr, upd_mcginfo, NULL, NULL);
1695*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1696*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1697*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update: "
1698*b494511aSVenki Rajagopalan 		    "ibt_join_mcg(mgid=%llx.%llx, pkey=0x%x, jstate=0x%x) "
1699*b494511aSVenki Rajagopalan 		    "failed, ret=%d", mcg_attr.mc_mgid.gid_prefix,
1700*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey,
1701*b494511aSVenki Rajagopalan 		    mcg_attr.mc_join_state, ret);
1702*b494511aSVenki Rajagopalan 
1703*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1704*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(upd_mcginfo, 1);
1705*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1706*b494511aSVenki Rajagopalan 	}
1707*b494511aSVenki Rajagopalan 
1708*b494511aSVenki Rajagopalan 	/*
1709*b494511aSVenki Rajagopalan 	 * Attach to the multicast group to receive upd multicasts
1710*b494511aSVenki Rajagopalan 	 */
1711*b494511aSVenki Rajagopalan 	ret = ibt_attach_mcg(chan->ch_chan, upd_mcginfo);
1712*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
1713*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1714*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update: "
1715*b494511aSVenki Rajagopalan 		    "ibt_attach_mcg(mgid=%llx.%llx, pkey=0x%x) "
1716*b494511aSVenki Rajagopalan 		    "failed, ret=%d", mcg_attr.mc_mgid.gid_prefix,
1717*b494511aSVenki Rajagopalan 		    mcg_attr.mc_mgid.gid_guid, mcg_attr.mc_pkey);
1718*b494511aSVenki Rajagopalan 
1719*b494511aSVenki Rajagopalan 		(void) ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
1720*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
1721*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1722*b494511aSVenki Rajagopalan 		ibt_free_mcg_info(upd_mcginfo, 1);
1723*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1724*b494511aSVenki Rajagopalan 	}
1725*b494511aSVenki Rajagopalan 
1726*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
1727*b494511aSVenki Rajagopalan 	chan->ch_vhub_update = mcg;
1728*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
1729*b494511aSVenki Rajagopalan 
1730*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1731*b494511aSVenki Rajagopalan }
1732*b494511aSVenki Rajagopalan 
1733*b494511aSVenki Rajagopalan static void
eib_vnic_start_keepalives(eib_t * ss,eib_vnic_t * vnic)1734*b494511aSVenki Rajagopalan eib_vnic_start_keepalives(eib_t *ss, eib_vnic_t *vnic)
1735*b494511aSVenki Rajagopalan {
1736*b494511aSVenki Rajagopalan 	eib_ka_vnics_t *kav;
1737*b494511aSVenki Rajagopalan 	eib_ka_vnics_t *elem;
1738*b494511aSVenki Rajagopalan 	int err;
1739*b494511aSVenki Rajagopalan 
1740*b494511aSVenki Rajagopalan 	kav = kmem_zalloc(sizeof (eib_ka_vnics_t), KM_SLEEP);
1741*b494511aSVenki Rajagopalan 	kav->ka_vnic = vnic;
1742*b494511aSVenki Rajagopalan 	kav->ka_next = NULL;
1743*b494511aSVenki Rajagopalan 
1744*b494511aSVenki Rajagopalan 	/*
1745*b494511aSVenki Rajagopalan 	 * Send the first keepalive and then queue this vnic up with
1746*b494511aSVenki Rajagopalan 	 * the keepalives manager
1747*b494511aSVenki Rajagopalan 	 */
1748*b494511aSVenki Rajagopalan 	(void) eib_fip_heartbeat(ss, vnic, &err);
1749*b494511aSVenki Rajagopalan 
1750*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_ka_vnics_lock);
1751*b494511aSVenki Rajagopalan 	for (elem = ss->ei_ka_vnics; elem; elem = elem->ka_next) {
1752*b494511aSVenki Rajagopalan 		if (elem->ka_next == NULL)
1753*b494511aSVenki Rajagopalan 			break;
1754*b494511aSVenki Rajagopalan 	}
1755*b494511aSVenki Rajagopalan 	if (elem) {
1756*b494511aSVenki Rajagopalan 		elem->ka_next = kav;
1757*b494511aSVenki Rajagopalan 	} else {
1758*b494511aSVenki Rajagopalan 		ss->ei_ka_vnics = kav;
1759*b494511aSVenki Rajagopalan 	}
1760*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_ka_vnics_lock);
1761*b494511aSVenki Rajagopalan }
1762*b494511aSVenki Rajagopalan 
1763*b494511aSVenki Rajagopalan /*ARGSUSED*/
1764*b494511aSVenki Rajagopalan static int
eib_vnic_lookup_dest(eib_vnic_t * vnic,uint8_t * dmac,uint16_t vlan,eib_vhub_map_t * ucast,ibt_mcg_info_t * mcast,int * dtype)1765*b494511aSVenki Rajagopalan eib_vnic_lookup_dest(eib_vnic_t *vnic, uint8_t *dmac, uint16_t vlan,
1766*b494511aSVenki Rajagopalan     eib_vhub_map_t *ucast, ibt_mcg_info_t *mcast, int *dtype)
1767*b494511aSVenki Rajagopalan {
1768*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
1769*b494511aSVenki Rajagopalan 	eib_vhub_map_t *elem;
1770*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
1771*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_data_chan;
1772*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
1773*b494511aSVenki Rajagopalan 	eib_vhub_map_t *gw;
1774*b494511aSVenki Rajagopalan 	eib_vhub_table_t *tbl;
1775*b494511aSVenki Rajagopalan 	uint8_t bkt = (dmac[ETHERADDRL-1]) % EIB_TB_NBUCKETS;
1776*b494511aSVenki Rajagopalan 	ib_gid_t mgid;
1777*b494511aSVenki Rajagopalan 
1778*b494511aSVenki Rajagopalan 	/*
1779*b494511aSVenki Rajagopalan 	 * If this was a unicast dmac, locate the vhub entry matching the
1780*b494511aSVenki Rajagopalan 	 * unicast dmac in our vhub table.  If it's not found, return the
1781*b494511aSVenki Rajagopalan 	 * gateway entry
1782*b494511aSVenki Rajagopalan 	 */
1783*b494511aSVenki Rajagopalan 	if (EIB_UNICAST_MAC(dmac)) {
1784*b494511aSVenki Rajagopalan 
1785*b494511aSVenki Rajagopalan 		mutex_enter(&vnic->vn_lock);
1786*b494511aSVenki Rajagopalan 		if ((tbl = vnic->vn_vhub_table) == NULL) {
1787*b494511aSVenki Rajagopalan 			mutex_exit(&vnic->vn_lock);
1788*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
1789*b494511aSVenki Rajagopalan 		}
1790*b494511aSVenki Rajagopalan 
1791*b494511aSVenki Rajagopalan 		mutex_enter(&tbl->tb_lock);
1792*b494511aSVenki Rajagopalan 		gw = tbl->tb_gateway;
1793*b494511aSVenki Rajagopalan 		for (elem = tbl->tb_vnic_entry[bkt]; elem != NULL;
1794*b494511aSVenki Rajagopalan 		    elem = elem->mp_next) {
1795*b494511aSVenki Rajagopalan 			if (bcmp(elem->mp_mac, dmac, ETHERADDRL) == 0)
1796*b494511aSVenki Rajagopalan 				break;
1797*b494511aSVenki Rajagopalan 		}
1798*b494511aSVenki Rajagopalan 		mutex_exit(&tbl->tb_lock);
1799*b494511aSVenki Rajagopalan 
1800*b494511aSVenki Rajagopalan 		if ((elem == NULL) && (gw == NULL)) {
1801*b494511aSVenki Rajagopalan 			mutex_exit(&vnic->vn_lock);
1802*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
1803*b494511aSVenki Rajagopalan 		}
1804*b494511aSVenki Rajagopalan 
1805*b494511aSVenki Rajagopalan 		*dtype = EIB_TX_UNICAST;
1806*b494511aSVenki Rajagopalan 		if (elem) {
1807*b494511aSVenki Rajagopalan 			bcopy(elem, ucast, sizeof (eib_vhub_map_t));
1808*b494511aSVenki Rajagopalan 		} else {
1809*b494511aSVenki Rajagopalan 			bcopy(gw, ucast, sizeof (eib_vhub_map_t));
1810*b494511aSVenki Rajagopalan 		}
1811*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
1812*b494511aSVenki Rajagopalan 
1813*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
1814*b494511aSVenki Rajagopalan 	}
1815*b494511aSVenki Rajagopalan 
1816*b494511aSVenki Rajagopalan 	/*
1817*b494511aSVenki Rajagopalan 	 * Is it a broadcast ?
1818*b494511aSVenki Rajagopalan 	 */
1819*b494511aSVenki Rajagopalan 	*dtype = (bcmp(dmac, eib_broadcast_mac, ETHERADDRL) == 0) ?
1820*b494511aSVenki Rajagopalan 	    EIB_TX_BROADCAST : EIB_TX_MULTICAST;
1821*b494511aSVenki Rajagopalan 
1822*b494511aSVenki Rajagopalan 	/*
1823*b494511aSVenki Rajagopalan 	 * If this was a multicast dmac, prepare the mgid and look for it
1824*b494511aSVenki Rajagopalan 	 * in the list of mcgs we've joined and use the address vector from
1825*b494511aSVenki Rajagopalan 	 * the mcginfo stored there.
1826*b494511aSVenki Rajagopalan 	 *
1827*b494511aSVenki Rajagopalan 	 * Note that since we don't have a way to associate each vlan with
1828*b494511aSVenki Rajagopalan 	 * the mcg (see eib_m_multicast()), we'll prepare the mgid to use
1829*b494511aSVenki Rajagopalan 	 * the broadcast channel all the time.
1830*b494511aSVenki Rajagopalan 	 */
1831*b494511aSVenki Rajagopalan 	eib_vnic_make_vhub_mgid(ld->ld_gw_mgid_prefix,
1832*b494511aSVenki Rajagopalan 	    (uint8_t)EIB_MGID_VHUB_DATA, eib_broadcast_mac, ld->ld_n_mac_mcgid,
1833*b494511aSVenki Rajagopalan 	    0, ld->ld_vhub_id, &mgid);
1834*b494511aSVenki Rajagopalan 
1835*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
1836*b494511aSVenki Rajagopalan 	for (mcg = chan->ch_vhub_data; mcg; mcg = mcg->mg_next) {
1837*b494511aSVenki Rajagopalan 		if ((mcg->mg_mgid.gid_prefix == mgid.gid_prefix) &&
1838*b494511aSVenki Rajagopalan 		    (mcg->mg_mgid.gid_guid == mgid.gid_guid)) {
1839*b494511aSVenki Rajagopalan 			break;
1840*b494511aSVenki Rajagopalan 		}
1841*b494511aSVenki Rajagopalan 	}
1842*b494511aSVenki Rajagopalan 	if (mcg == NULL) {
1843*b494511aSVenki Rajagopalan 		mutex_exit(&chan->ch_vhub_lock);
1844*b494511aSVenki Rajagopalan 
1845*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_vnic_lookup_dest: "
1846*b494511aSVenki Rajagopalan 		    "could not find mgid %llx.%llx",
1847*b494511aSVenki Rajagopalan 		    mgid.gid_prefix, mgid.gid_guid);
1848*b494511aSVenki Rajagopalan 
1849*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1850*b494511aSVenki Rajagopalan 	}
1851*b494511aSVenki Rajagopalan 
1852*b494511aSVenki Rajagopalan 	bcopy(mcg->mg_mcginfo, mcast, sizeof (ibt_mcg_info_t));
1853*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
1854*b494511aSVenki Rajagopalan 
1855*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1856*b494511aSVenki Rajagopalan }
1857*b494511aSVenki Rajagopalan 
1858*b494511aSVenki Rajagopalan /*ARGSUSED*/
1859*b494511aSVenki Rajagopalan static void
eib_vnic_leave_all_data_mcgs(eib_t * ss,eib_vnic_t * vnic)1860*b494511aSVenki Rajagopalan eib_vnic_leave_all_data_mcgs(eib_t *ss, eib_vnic_t *vnic)
1861*b494511aSVenki Rajagopalan {
1862*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_data_chan;
1863*b494511aSVenki Rajagopalan 	eib_mcg_t *mcglist;
1864*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
1865*b494511aSVenki Rajagopalan 	eib_mcg_t *nxt = NULL;
1866*b494511aSVenki Rajagopalan 	ibt_status_t ret;
1867*b494511aSVenki Rajagopalan 
1868*b494511aSVenki Rajagopalan 	/*
1869*b494511aSVenki Rajagopalan 	 * First, take the ch_vhub_data mcg chain out of chan
1870*b494511aSVenki Rajagopalan 	 */
1871*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
1872*b494511aSVenki Rajagopalan 	mcglist = chan->ch_vhub_data;
1873*b494511aSVenki Rajagopalan 	chan->ch_vhub_data = NULL;
1874*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
1875*b494511aSVenki Rajagopalan 
1876*b494511aSVenki Rajagopalan 	/*
1877*b494511aSVenki Rajagopalan 	 * Go through the chain of mcgs we've joined, detach the qp from the
1878*b494511aSVenki Rajagopalan 	 * mcg, leave the group and free all associated stuff
1879*b494511aSVenki Rajagopalan 	 */
1880*b494511aSVenki Rajagopalan 	for (mcg = mcglist; mcg != NULL; mcg = nxt) {
1881*b494511aSVenki Rajagopalan 		nxt = mcg->mg_next;
1882*b494511aSVenki Rajagopalan 
1883*b494511aSVenki Rajagopalan 		ret = ibt_detach_mcg(chan->ch_chan, mcg->mg_mcginfo);
1884*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
1885*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1886*b494511aSVenki Rajagopalan 			    "eib_vnic_leave_all_data_mcgs: "
1887*b494511aSVenki Rajagopalan 			    "ibt_detach_mcg(chan_hdl=0x%llx, mcinfo=0x%llx, "
1888*b494511aSVenki Rajagopalan 			    "mgid=%llx.%llx) failed, ret=%d", chan->ch_chan,
1889*b494511aSVenki Rajagopalan 			    mcg->mg_mcginfo, mcg->mg_mgid.gid_prefix,
1890*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, ret);
1891*b494511aSVenki Rajagopalan 		}
1892*b494511aSVenki Rajagopalan 
1893*b494511aSVenki Rajagopalan 		ret = ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
1894*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
1895*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
1896*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1897*b494511aSVenki Rajagopalan 			    "eib_vnic_leave_all_data_mcgs: "
1898*b494511aSVenki Rajagopalan 			    "ibt_leave_mcg(mgid=%llx.%llx, jstate=0x%x) "
1899*b494511aSVenki Rajagopalan 			    "failed, ret=%d", mcg->mg_mgid.gid_prefix,
1900*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, mcg->mg_join_state, ret);
1901*b494511aSVenki Rajagopalan 		}
1902*b494511aSVenki Rajagopalan 
1903*b494511aSVenki Rajagopalan 		if (mcg->mg_mcginfo)
1904*b494511aSVenki Rajagopalan 			kmem_free(mcg->mg_mcginfo, sizeof (ibt_mcg_info_t));
1905*b494511aSVenki Rajagopalan 
1906*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1907*b494511aSVenki Rajagopalan 	}
1908*b494511aSVenki Rajagopalan }
1909*b494511aSVenki Rajagopalan 
1910*b494511aSVenki Rajagopalan static void
eib_vnic_rejoin_data_mcgs(eib_t * ss,eib_vnic_t * vnic)1911*b494511aSVenki Rajagopalan eib_vnic_rejoin_data_mcgs(eib_t *ss, eib_vnic_t *vnic)
1912*b494511aSVenki Rajagopalan {
1913*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_data_chan;
1914*b494511aSVenki Rajagopalan 	eib_mcg_t *mcglist;
1915*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
1916*b494511aSVenki Rajagopalan 	eib_mcg_t *next;
1917*b494511aSVenki Rajagopalan 	int err;
1918*b494511aSVenki Rajagopalan 
1919*b494511aSVenki Rajagopalan 	/*
1920*b494511aSVenki Rajagopalan 	 * Grab the current list of mcgs
1921*b494511aSVenki Rajagopalan 	 */
1922*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
1923*b494511aSVenki Rajagopalan 	mcglist = chan->ch_vhub_data;
1924*b494511aSVenki Rajagopalan 	chan->ch_vhub_data = NULL;
1925*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
1926*b494511aSVenki Rajagopalan 
1927*b494511aSVenki Rajagopalan 	/*
1928*b494511aSVenki Rajagopalan 	 * When rejoin data mcgs is called, we may not even be marked as
1929*b494511aSVenki Rajagopalan 	 * joined in SM's records.  But we still have to leave the old
1930*b494511aSVenki Rajagopalan 	 * one first to prevent leaks in ibtf.
1931*b494511aSVenki Rajagopalan 	 */
1932*b494511aSVenki Rajagopalan 	for (mcg = mcglist; mcg != NULL; mcg = next) {
1933*b494511aSVenki Rajagopalan 		next = mcg->mg_next;
1934*b494511aSVenki Rajagopalan 		mcg->mg_next = NULL;
1935*b494511aSVenki Rajagopalan 
1936*b494511aSVenki Rajagopalan 		(void) ibt_detach_mcg(chan->ch_chan, mcg->mg_mcginfo);
1937*b494511aSVenki Rajagopalan 		(void) ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
1938*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
1939*b494511aSVenki Rajagopalan 
1940*b494511aSVenki Rajagopalan 		if (eib_vnic_join_data_mcg(ss, vnic, mcg->mg_mac, B_TRUE,
1941*b494511aSVenki Rajagopalan 		    &err) != EIB_E_SUCCESS) {
1942*b494511aSVenki Rajagopalan 			uint8_t *m;
1943*b494511aSVenki Rajagopalan 
1944*b494511aSVenki Rajagopalan 			m = mcg->mg_mac;
1945*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1946*b494511aSVenki Rajagopalan 			    "eib_vnic_rejoin_data_mcgs: "
1947*b494511aSVenki Rajagopalan 			    "eib_vnic_join_data_mcg(mcmac=%x:%x:%x:%x:%x:%x) "
1948*b494511aSVenki Rajagopalan 			    "failed, ret=%d", m[0], m[1], m[2], m[3],
1949*b494511aSVenki Rajagopalan 			    m[4], m[5], err);
1950*b494511aSVenki Rajagopalan 		}
1951*b494511aSVenki Rajagopalan 		if (mcg->mg_mcginfo) {
1952*b494511aSVenki Rajagopalan 			kmem_free(mcg->mg_mcginfo, sizeof (ibt_mcg_info_t));
1953*b494511aSVenki Rajagopalan 		}
1954*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
1955*b494511aSVenki Rajagopalan 	}
1956*b494511aSVenki Rajagopalan }
1957*b494511aSVenki Rajagopalan 
1958*b494511aSVenki Rajagopalan static void
eib_vnic_reattach_ctl_mcgs(eib_t * ss,eib_vnic_t * vnic)1959*b494511aSVenki Rajagopalan eib_vnic_reattach_ctl_mcgs(eib_t *ss, eib_vnic_t *vnic)
1960*b494511aSVenki Rajagopalan {
1961*b494511aSVenki Rajagopalan 	/*
1962*b494511aSVenki Rajagopalan 	 * For reattaching to control mcgs, we will not reinitialize the
1963*b494511aSVenki Rajagopalan 	 * vhub table/vhub update we've constructed.  We'll simply detach
1964*b494511aSVenki Rajagopalan 	 * from the table and update mcgs and reattach to them.  Hopefully,
1965*b494511aSVenki Rajagopalan 	 * we wouldn't have missed any updates and won't have to restart
1966*b494511aSVenki Rajagopalan 	 * the vnic.
1967*b494511aSVenki Rajagopalan 	 */
1968*b494511aSVenki Rajagopalan 	eib_rb_vnic_attach_vhub_table(ss, vnic);
1969*b494511aSVenki Rajagopalan 	eib_rb_vnic_attach_vhub_update(ss, vnic);
1970*b494511aSVenki Rajagopalan 
1971*b494511aSVenki Rajagopalan 	if (eib_vnic_attach_vhub_update(ss, vnic) != EIB_E_SUCCESS) {
1972*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1973*b494511aSVenki Rajagopalan 		    "eib_vnic_reattach_ctl_mcgs: "
1974*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_update(vn_id=0x%x) failed",
1975*b494511aSVenki Rajagopalan 		    vnic->vn_id);
1976*b494511aSVenki Rajagopalan 	}
1977*b494511aSVenki Rajagopalan 
1978*b494511aSVenki Rajagopalan 	if (eib_vnic_attach_vhub_table(ss, vnic) != EIB_E_SUCCESS) {
1979*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
1980*b494511aSVenki Rajagopalan 		    "eib_vnic_reattach_ctl_mcgs: "
1981*b494511aSVenki Rajagopalan 		    "eib_vnic_attach_vhub_table(vn_id=0x%x) failed",
1982*b494511aSVenki Rajagopalan 		    vnic->vn_id);
1983*b494511aSVenki Rajagopalan 
1984*b494511aSVenki Rajagopalan 		eib_rb_vnic_attach_vhub_update(ss, vnic);
1985*b494511aSVenki Rajagopalan 	}
1986*b494511aSVenki Rajagopalan }
1987*b494511aSVenki Rajagopalan 
1988*b494511aSVenki Rajagopalan static void
eib_rb_vnic_create_common(eib_t * ss,eib_vnic_t * vnic,uint_t progress)1989*b494511aSVenki Rajagopalan eib_rb_vnic_create_common(eib_t *ss, eib_vnic_t *vnic, uint_t progress)
1990*b494511aSVenki Rajagopalan {
1991*b494511aSVenki Rajagopalan 	int err;
1992*b494511aSVenki Rajagopalan 
1993*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_vnic_lock);
1994*b494511aSVenki Rajagopalan 	ss->ei_vnic[vnic->vn_instance] = NULL;
1995*b494511aSVenki Rajagopalan 	ss->ei_vnic_pending = NULL;
1996*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_vnic_lock);
1997*b494511aSVenki Rajagopalan 
1998*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_BROADCAST_JOINED) {
1999*b494511aSVenki Rajagopalan 		eib_vnic_leave_all_data_mcgs(ss, vnic);
2000*b494511aSVenki Rajagopalan 	}
2001*b494511aSVenki Rajagopalan 
2002*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_KEEPALIVES_STARTED) {
2003*b494511aSVenki Rajagopalan 		eib_rb_vnic_start_keepalives(ss, vnic);
2004*b494511aSVenki Rajagopalan 	}
2005*b494511aSVenki Rajagopalan 
2006*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_ATTACHED_TO_CTL_MCGS) {
2007*b494511aSVenki Rajagopalan 		eib_rb_vnic_attach_ctl_mcgs(ss, vnic);
2008*b494511aSVenki Rajagopalan 	}
2009*b494511aSVenki Rajagopalan 
2010*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_LOGIN_DONE) {
2011*b494511aSVenki Rajagopalan 		(void) eib_fip_logout(ss, vnic, &err);
2012*b494511aSVenki Rajagopalan 	}
2013*b494511aSVenki Rajagopalan 
2014*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_DATAQP_CREATED) {
2015*b494511aSVenki Rajagopalan 		eib_rb_data_create_qp(ss, vnic);
2016*b494511aSVenki Rajagopalan 	}
2017*b494511aSVenki Rajagopalan 
2018*b494511aSVenki Rajagopalan 	if (progress & EIB_VNIC_CTLQP_CREATED) {
2019*b494511aSVenki Rajagopalan 		eib_rb_ctl_create_qp(ss, vnic);
2020*b494511aSVenki Rajagopalan 	}
2021*b494511aSVenki Rajagopalan }
2022*b494511aSVenki Rajagopalan 
2023*b494511aSVenki Rajagopalan static void
eib_rb_vnic_attach_ctl_mcgs(eib_t * ss,eib_vnic_t * vnic)2024*b494511aSVenki Rajagopalan eib_rb_vnic_attach_ctl_mcgs(eib_t *ss, eib_vnic_t *vnic)
2025*b494511aSVenki Rajagopalan {
2026*b494511aSVenki Rajagopalan 	/*
2027*b494511aSVenki Rajagopalan 	 * Detach from the vhub table and vhub update mcgs before blowing
2028*b494511aSVenki Rajagopalan 	 * up vn_vhub_table and vn_vhub_update, since these are assumed to
2029*b494511aSVenki Rajagopalan 	 * be available by the control cq handler.
2030*b494511aSVenki Rajagopalan 	 */
2031*b494511aSVenki Rajagopalan 	eib_rb_vnic_attach_vhub_table(ss, vnic);
2032*b494511aSVenki Rajagopalan 	eib_rb_vnic_attach_vhub_update(ss, vnic);
2033*b494511aSVenki Rajagopalan 	eib_vnic_fini_tables(ss, vnic, B_TRUE);
2034*b494511aSVenki Rajagopalan }
2035*b494511aSVenki Rajagopalan 
2036*b494511aSVenki Rajagopalan /*ARGSUSED*/
2037*b494511aSVenki Rajagopalan static void
eib_rb_vnic_attach_vhub_table(eib_t * ss,eib_vnic_t * vnic)2038*b494511aSVenki Rajagopalan eib_rb_vnic_attach_vhub_table(eib_t *ss, eib_vnic_t *vnic)
2039*b494511aSVenki Rajagopalan {
2040*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_ctl_chan;
2041*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
2042*b494511aSVenki Rajagopalan 	ibt_channel_hdl_t chan_hdl;
2043*b494511aSVenki Rajagopalan 	ibt_status_t ret;
2044*b494511aSVenki Rajagopalan 
2045*b494511aSVenki Rajagopalan 	if (chan == NULL)
2046*b494511aSVenki Rajagopalan 		return;
2047*b494511aSVenki Rajagopalan 
2048*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
2049*b494511aSVenki Rajagopalan 	chan_hdl = chan->ch_chan;
2050*b494511aSVenki Rajagopalan 	mcg = chan->ch_vhub_table;
2051*b494511aSVenki Rajagopalan 	chan->ch_vhub_table = NULL;
2052*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
2053*b494511aSVenki Rajagopalan 
2054*b494511aSVenki Rajagopalan 	if (chan_hdl && mcg) {
2055*b494511aSVenki Rajagopalan 		ret = ibt_detach_mcg(chan_hdl, mcg->mg_mcginfo);
2056*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
2057*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
2058*b494511aSVenki Rajagopalan 			    "eib_rb_vnic_attach_vhub_table: "
2059*b494511aSVenki Rajagopalan 			    "ibt_detach_mcg(chan_hdl=0x%llx, mcinfo=0x%llx, "
2060*b494511aSVenki Rajagopalan 			    "mgid=%llx.%llx) failed, ret=%d", chan_hdl,
2061*b494511aSVenki Rajagopalan 			    mcg->mg_mcginfo, mcg->mg_mgid.gid_prefix,
2062*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, ret);
2063*b494511aSVenki Rajagopalan 		}
2064*b494511aSVenki Rajagopalan 
2065*b494511aSVenki Rajagopalan 		ret = ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
2066*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
2067*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
2068*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
2069*b494511aSVenki Rajagopalan 			    "eib_rb_vnic_attach_vhub_table: "
2070*b494511aSVenki Rajagopalan 			    "ibt_leave_mcg(mgid=%llx.%llx, jstate=0x%x) "
2071*b494511aSVenki Rajagopalan 			    "failed, ret=%d", mcg->mg_mgid.gid_prefix,
2072*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, mcg->mg_join_state, ret);
2073*b494511aSVenki Rajagopalan 		}
2074*b494511aSVenki Rajagopalan 
2075*b494511aSVenki Rajagopalan 		if (mcg->mg_mcginfo) {
2076*b494511aSVenki Rajagopalan 			ibt_free_mcg_info(mcg->mg_mcginfo, 1);
2077*b494511aSVenki Rajagopalan 		}
2078*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
2079*b494511aSVenki Rajagopalan 	}
2080*b494511aSVenki Rajagopalan }
2081*b494511aSVenki Rajagopalan 
2082*b494511aSVenki Rajagopalan /*ARGSUSED*/
2083*b494511aSVenki Rajagopalan static void
eib_rb_vnic_attach_vhub_update(eib_t * ss,eib_vnic_t * vnic)2084*b494511aSVenki Rajagopalan eib_rb_vnic_attach_vhub_update(eib_t *ss, eib_vnic_t *vnic)
2085*b494511aSVenki Rajagopalan {
2086*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_ctl_chan;
2087*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
2088*b494511aSVenki Rajagopalan 	ibt_channel_hdl_t chan_hdl;
2089*b494511aSVenki Rajagopalan 	ibt_status_t ret;
2090*b494511aSVenki Rajagopalan 
2091*b494511aSVenki Rajagopalan 	if (chan == NULL)
2092*b494511aSVenki Rajagopalan 		return;
2093*b494511aSVenki Rajagopalan 
2094*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
2095*b494511aSVenki Rajagopalan 	chan_hdl = chan->ch_chan;
2096*b494511aSVenki Rajagopalan 	mcg = chan->ch_vhub_update;
2097*b494511aSVenki Rajagopalan 	chan->ch_vhub_update = NULL;
2098*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
2099*b494511aSVenki Rajagopalan 
2100*b494511aSVenki Rajagopalan 	if (chan_hdl && mcg) {
2101*b494511aSVenki Rajagopalan 		ret = ibt_detach_mcg(chan_hdl, mcg->mg_mcginfo);
2102*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
2103*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
2104*b494511aSVenki Rajagopalan 			    "eib_rb_vnic_attach_vhub_update: "
2105*b494511aSVenki Rajagopalan 			    "ibt_detach_mcg(chan_hdl=0x%llx, mcinfo=0x%llx, "
2106*b494511aSVenki Rajagopalan 			    "mgid=%llx.%llx) failed, ret=%d", chan_hdl,
2107*b494511aSVenki Rajagopalan 			    mcg->mg_mcginfo, mcg->mg_mgid.gid_prefix,
2108*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, ret);
2109*b494511aSVenki Rajagopalan 		}
2110*b494511aSVenki Rajagopalan 
2111*b494511aSVenki Rajagopalan 		ret = ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid,
2112*b494511aSVenki Rajagopalan 		    eib_reserved_gid, mcg->mg_join_state);
2113*b494511aSVenki Rajagopalan 		if (ret != IBT_SUCCESS) {
2114*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
2115*b494511aSVenki Rajagopalan 			    "eib_rb_vnic_attach_vhub_update: "
2116*b494511aSVenki Rajagopalan 			    "ibt_leave_mcg(mgid=%llx.%llx, jstate=0x%x) "
2117*b494511aSVenki Rajagopalan 			    "failed, ret=%d", mcg->mg_mgid.gid_prefix,
2118*b494511aSVenki Rajagopalan 			    mcg->mg_mgid.gid_guid, mcg->mg_join_state, ret);
2119*b494511aSVenki Rajagopalan 		}
2120*b494511aSVenki Rajagopalan 
2121*b494511aSVenki Rajagopalan 		if (mcg->mg_mcginfo) {
2122*b494511aSVenki Rajagopalan 			ibt_free_mcg_info(mcg->mg_mcginfo, 1);
2123*b494511aSVenki Rajagopalan 		}
2124*b494511aSVenki Rajagopalan 		kmem_free(mcg, sizeof (eib_mcg_t));
2125*b494511aSVenki Rajagopalan 	}
2126*b494511aSVenki Rajagopalan }
2127*b494511aSVenki Rajagopalan 
2128*b494511aSVenki Rajagopalan /*ARGSUSED*/
2129*b494511aSVenki Rajagopalan static void
eib_rb_vnic_start_keepalives(eib_t * ss,eib_vnic_t * vnic)2130*b494511aSVenki Rajagopalan eib_rb_vnic_start_keepalives(eib_t *ss, eib_vnic_t *vnic)
2131*b494511aSVenki Rajagopalan {
2132*b494511aSVenki Rajagopalan 	eib_ka_vnics_t *prev;
2133*b494511aSVenki Rajagopalan 	eib_ka_vnics_t *elem;
2134*b494511aSVenki Rajagopalan 
2135*b494511aSVenki Rajagopalan 	/*
2136*b494511aSVenki Rajagopalan 	 * We only need to locate and remove the vnic entry from the
2137*b494511aSVenki Rajagopalan 	 * keepalives manager list
2138*b494511aSVenki Rajagopalan 	 */
2139*b494511aSVenki Rajagopalan 
2140*b494511aSVenki Rajagopalan 	mutex_enter(&ss->ei_ka_vnics_lock);
2141*b494511aSVenki Rajagopalan 
2142*b494511aSVenki Rajagopalan 	prev = NULL;
2143*b494511aSVenki Rajagopalan 	for (elem = ss->ei_ka_vnics; elem; elem = elem->ka_next) {
2144*b494511aSVenki Rajagopalan 		if (elem->ka_vnic == vnic)
2145*b494511aSVenki Rajagopalan 			break;
2146*b494511aSVenki Rajagopalan 
2147*b494511aSVenki Rajagopalan 		prev = elem;
2148*b494511aSVenki Rajagopalan 	}
2149*b494511aSVenki Rajagopalan 	if (elem == NULL) {
2150*b494511aSVenki Rajagopalan 		EIB_DPRINTF_DEBUG(ss->ei_instance,
2151*b494511aSVenki Rajagopalan 		    "eib_rb_vnic_start_keepalives: no keepalive element found "
2152*b494511aSVenki Rajagopalan 		    "for vnic 0x%llx (vn_inst=%d) with keepalive manager",
2153*b494511aSVenki Rajagopalan 		    vnic, vnic->vn_instance);
2154*b494511aSVenki Rajagopalan 	} else {
2155*b494511aSVenki Rajagopalan 		if (prev) {
2156*b494511aSVenki Rajagopalan 			prev->ka_next = elem->ka_next;
2157*b494511aSVenki Rajagopalan 		} else {
2158*b494511aSVenki Rajagopalan 			ss->ei_ka_vnics = elem->ka_next;
2159*b494511aSVenki Rajagopalan 		}
2160*b494511aSVenki Rajagopalan 		kmem_free(elem, sizeof (eib_ka_vnics_t));
2161*b494511aSVenki Rajagopalan 	}
2162*b494511aSVenki Rajagopalan 	mutex_exit(&ss->ei_ka_vnics_lock);
2163*b494511aSVenki Rajagopalan }
2164*b494511aSVenki Rajagopalan 
2165*b494511aSVenki Rajagopalan /*ARGSUSED*/
2166*b494511aSVenki Rajagopalan static void
eib_rb_vnic_join_data_mcg(eib_t * ss,eib_vnic_t * vnic,uint8_t * mcast_mac)2167*b494511aSVenki Rajagopalan eib_rb_vnic_join_data_mcg(eib_t *ss, eib_vnic_t *vnic, uint8_t *mcast_mac)
2168*b494511aSVenki Rajagopalan {
2169*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_data_chan;
2170*b494511aSVenki Rajagopalan 	eib_mcg_t *prev;
2171*b494511aSVenki Rajagopalan 	eib_mcg_t *mcg;
2172*b494511aSVenki Rajagopalan 	ibt_status_t ret;
2173*b494511aSVenki Rajagopalan 
2174*b494511aSVenki Rajagopalan 	/*
2175*b494511aSVenki Rajagopalan 	 * Search our list and remove the item if found
2176*b494511aSVenki Rajagopalan 	 */
2177*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_vhub_lock);
2178*b494511aSVenki Rajagopalan 
2179*b494511aSVenki Rajagopalan 	prev = NULL;
2180*b494511aSVenki Rajagopalan 	for (mcg = chan->ch_vhub_data; mcg != NULL; mcg = mcg->mg_next) {
2181*b494511aSVenki Rajagopalan 		if (bcmp(mcg->mg_mac, mcast_mac, ETHERADDRL) == 0)
2182*b494511aSVenki Rajagopalan 			break;
2183*b494511aSVenki Rajagopalan 		prev = mcg;
2184*b494511aSVenki Rajagopalan 	}
2185*b494511aSVenki Rajagopalan 
2186*b494511aSVenki Rajagopalan 	if (mcg == NULL) {
2187*b494511aSVenki Rajagopalan 		mutex_exit(&chan->ch_vhub_lock);
2188*b494511aSVenki Rajagopalan 		return;
2189*b494511aSVenki Rajagopalan 	}
2190*b494511aSVenki Rajagopalan 
2191*b494511aSVenki Rajagopalan 	if (prev != NULL)
2192*b494511aSVenki Rajagopalan 		prev->mg_next = mcg->mg_next;
2193*b494511aSVenki Rajagopalan 	else
2194*b494511aSVenki Rajagopalan 		chan->ch_vhub_data = mcg->mg_next;
2195*b494511aSVenki Rajagopalan 
2196*b494511aSVenki Rajagopalan 	mcg->mg_next = NULL;
2197*b494511aSVenki Rajagopalan 
2198*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_vhub_lock);
2199*b494511aSVenki Rajagopalan 
2200*b494511aSVenki Rajagopalan 	/*
2201*b494511aSVenki Rajagopalan 	 * Detach data channel qp from the mcg, leave the group and free
2202*b494511aSVenki Rajagopalan 	 * all associated stuff
2203*b494511aSVenki Rajagopalan 	 */
2204*b494511aSVenki Rajagopalan 	ret = ibt_detach_mcg(chan->ch_chan, mcg->mg_mcginfo);
2205*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
2206*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
2207*b494511aSVenki Rajagopalan 		    "eib_rb_vnic_join_data_mcg: "
2208*b494511aSVenki Rajagopalan 		    "ibt_detach_mcg(chan_hdl=0x%llx, mcinfo=0x%llx, "
2209*b494511aSVenki Rajagopalan 		    "mgid=%llx.%llx) failed, ret=%d", chan->ch_chan,
2210*b494511aSVenki Rajagopalan 		    mcg->mg_mcginfo, mcg->mg_mgid.gid_prefix,
2211*b494511aSVenki Rajagopalan 		    mcg->mg_mgid.gid_guid, ret);
2212*b494511aSVenki Rajagopalan 	}
2213*b494511aSVenki Rajagopalan 
2214*b494511aSVenki Rajagopalan 	ret = ibt_leave_mcg(mcg->mg_rgid, mcg->mg_mgid, eib_reserved_gid,
2215*b494511aSVenki Rajagopalan 	    mcg->mg_join_state);
2216*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
2217*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance,
2218*b494511aSVenki Rajagopalan 		    "eib_rb_vnic_join_data_mcg: "
2219*b494511aSVenki Rajagopalan 		    "ibt_leave_mcg(mgid=%llx.%llx, jstate=0x%x) "
2220*b494511aSVenki Rajagopalan 		    "failed, ret=%d", mcg->mg_mgid.gid_prefix,
2221*b494511aSVenki Rajagopalan 		    mcg->mg_mgid.gid_guid, mcg->mg_join_state, ret);
2222*b494511aSVenki Rajagopalan 	}
2223*b494511aSVenki Rajagopalan 
2224*b494511aSVenki Rajagopalan 	if (mcg->mg_mcginfo)
2225*b494511aSVenki Rajagopalan 		kmem_free(mcg->mg_mcginfo, sizeof (ibt_mcg_info_t));
2226*b494511aSVenki Rajagopalan 
2227*b494511aSVenki Rajagopalan 	kmem_free(mcg, sizeof (eib_mcg_t));
2228*b494511aSVenki Rajagopalan }
2229