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