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/ddi.h>
28*b494511aSVenki Rajagopalan #include <sys/sunddi.h>
29*b494511aSVenki Rajagopalan #include <sys/ksynch.h>
30*b494511aSVenki Rajagopalan #include <sys/byteorder.h>
31*b494511aSVenki Rajagopalan 
32*b494511aSVenki Rajagopalan #include <sys/ib/clients/eoib/eib_impl.h>
33*b494511aSVenki Rajagopalan 
34*b494511aSVenki Rajagopalan /*
35*b494511aSVenki Rajagopalan  * Declarations private to this file
36*b494511aSVenki Rajagopalan  */
37*b494511aSVenki Rajagopalan static int eib_fip_make_login(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
38*b494511aSVenki Rajagopalan static int eib_fip_make_update(eib_t *, eib_vnic_t *, eib_wqe_t *, int, int *);
39*b494511aSVenki Rajagopalan static int eib_fip_make_table(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
40*b494511aSVenki Rajagopalan static int eib_fip_make_ka(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
41*b494511aSVenki Rajagopalan static int eib_fip_make_logout(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
42*b494511aSVenki Rajagopalan 
43*b494511aSVenki Rajagopalan static int eib_fip_send_login(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
44*b494511aSVenki Rajagopalan static int eib_fip_send_update(eib_t *, eib_vnic_t *, eib_wqe_t *,
45*b494511aSVenki Rajagopalan     uint_t, int *);
46*b494511aSVenki Rajagopalan static int eib_fip_send_table(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
47*b494511aSVenki Rajagopalan static int eib_fip_send_ka(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
48*b494511aSVenki Rajagopalan static int eib_fip_send_logout(eib_t *, eib_vnic_t *, eib_wqe_t *, int *);
49*b494511aSVenki Rajagopalan 
50*b494511aSVenki Rajagopalan static int eib_fip_parse_vhub_table(uint8_t *, eib_vnic_t *);
51*b494511aSVenki Rajagopalan static int eib_fip_parse_vhub_update(uint8_t *, eib_vnic_t *);
52*b494511aSVenki Rajagopalan static void eib_fip_update_eport_state(eib_t *, eib_vhub_table_t *,
53*b494511aSVenki Rajagopalan     eib_vhub_update_t *, boolean_t, uint8_t);
54*b494511aSVenki Rajagopalan static void eib_fip_queue_tbl_entry(eib_vhub_table_t *, eib_vhub_map_t *,
55*b494511aSVenki Rajagopalan     uint32_t, uint8_t);
56*b494511aSVenki Rajagopalan static void eib_fip_queue_upd_entry(eib_vhub_update_t *, eib_vhub_map_t *,
57*b494511aSVenki Rajagopalan     uint32_t, uint8_t);
58*b494511aSVenki Rajagopalan static void eib_fip_queue_gw_entry(eib_vnic_t *, eib_vhub_table_t *, uint32_t,
59*b494511aSVenki Rajagopalan     uint8_t);
60*b494511aSVenki Rajagopalan static int eib_fip_apply_updates(eib_t *, eib_vhub_table_t *,
61*b494511aSVenki Rajagopalan     eib_vhub_update_t *);
62*b494511aSVenki Rajagopalan static void eib_fip_dequeue_tbl_entry(eib_vhub_table_t *, uint8_t *, uint32_t,
63*b494511aSVenki Rajagopalan     uint8_t);
64*b494511aSVenki Rajagopalan static eib_vhub_map_t *eib_fip_get_vhub_map(void);
65*b494511aSVenki Rajagopalan 
66*b494511aSVenki Rajagopalan /*
67*b494511aSVenki Rajagopalan  * Definitions private to this file
68*b494511aSVenki Rajagopalan  */
69*b494511aSVenki Rajagopalan const char eib_vendor_mellanox[] = {
70*b494511aSVenki Rajagopalan 	0x4d, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x6f, 0x78
71*b494511aSVenki Rajagopalan };
72*b494511aSVenki Rajagopalan 
73*b494511aSVenki Rajagopalan /*
74*b494511aSVenki Rajagopalan  * The three requests to the gateway - request a vHUB table, request a
75*b494511aSVenki Rajagopalan  * vHUB update (aka keepalive) and vNIC logout - all need the same
76*b494511aSVenki Rajagopalan  * vnic identity descriptor to be sent with different flag settings.
77*b494511aSVenki Rajagopalan  *
78*b494511aSVenki Rajagopalan  *      vHUB table: R=1, U=0, TUSN=last, subcode=KEEPALIVE
79*b494511aSVenki Rajagopalan  *      keepalive/vHUB update: R=0, U=1, TUSN=last, subcode=KEEPALIVE
80*b494511aSVenki Rajagopalan  *      vNIC logout: R=0, U=0, TUSN=0, subcode=LOGOUT
81*b494511aSVenki Rajagopalan  */
82*b494511aSVenki Rajagopalan #define	EIB_UPD_REQ_TABLE	1
83*b494511aSVenki Rajagopalan #define	EIB_UPD_REQ_KA		2
84*b494511aSVenki Rajagopalan #define	EIB_UPD_REQ_LOGOUT	3
85*b494511aSVenki Rajagopalan 
86*b494511aSVenki Rajagopalan int
eib_fip_login(eib_t * ss,eib_vnic_t * vnic,int * err)87*b494511aSVenki Rajagopalan eib_fip_login(eib_t *ss, eib_vnic_t *vnic, int *err)
88*b494511aSVenki Rajagopalan {
89*b494511aSVenki Rajagopalan 	eib_wqe_t *swqe;
90*b494511aSVenki Rajagopalan 	int ret;
91*b494511aSVenki Rajagopalan 	int ntries = 0;
92*b494511aSVenki Rajagopalan 
93*b494511aSVenki Rajagopalan 	do {
94*b494511aSVenki Rajagopalan 		if ((swqe = eib_rsrc_grab_swqe(ss, EIB_WPRI_LO)) == NULL) {
95*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_login: "
96*b494511aSVenki Rajagopalan 			    "no swqe available, not sending "
97*b494511aSVenki Rajagopalan 			    "vnic login request");
98*b494511aSVenki Rajagopalan 			*err = ENOMEM;
99*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
100*b494511aSVenki Rajagopalan 		}
101*b494511aSVenki Rajagopalan 
102*b494511aSVenki Rajagopalan 		ret = eib_fip_make_login(ss, vnic, swqe, err);
103*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
104*b494511aSVenki Rajagopalan 			eib_rsrc_return_swqe(ss, swqe, NULL);
105*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
106*b494511aSVenki Rajagopalan 		}
107*b494511aSVenki Rajagopalan 
108*b494511aSVenki Rajagopalan 		ret = eib_fip_send_login(ss, vnic, swqe, err);
109*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
110*b494511aSVenki Rajagopalan 			eib_rsrc_return_swqe(ss, swqe, NULL);
111*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
112*b494511aSVenki Rajagopalan 		}
113*b494511aSVenki Rajagopalan 
114*b494511aSVenki Rajagopalan 		ret = eib_vnic_wait_for_login_ack(ss, vnic, err);
115*b494511aSVenki Rajagopalan 		if (ret == EIB_E_SUCCESS)
116*b494511aSVenki Rajagopalan 			break;
117*b494511aSVenki Rajagopalan 
118*b494511aSVenki Rajagopalan 	} while ((*err == ETIME) && (ntries++ < EIB_MAX_LOGIN_ATTEMPTS));
119*b494511aSVenki Rajagopalan 
120*b494511aSVenki Rajagopalan 	return (ret);
121*b494511aSVenki Rajagopalan }
122*b494511aSVenki Rajagopalan 
123*b494511aSVenki Rajagopalan int
eib_fip_vhub_table(eib_t * ss,eib_vnic_t * vnic,int * err)124*b494511aSVenki Rajagopalan eib_fip_vhub_table(eib_t *ss, eib_vnic_t *vnic, int *err)
125*b494511aSVenki Rajagopalan {
126*b494511aSVenki Rajagopalan 	eib_wqe_t *swqe;
127*b494511aSVenki Rajagopalan 	int ret;
128*b494511aSVenki Rajagopalan 	int ntries = 0;
129*b494511aSVenki Rajagopalan 
130*b494511aSVenki Rajagopalan 	do {
131*b494511aSVenki Rajagopalan 		if ((swqe = eib_rsrc_grab_swqe(ss, EIB_WPRI_LO)) == NULL) {
132*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_vhub_table: "
133*b494511aSVenki Rajagopalan 			    "no swqe available, not sending "
134*b494511aSVenki Rajagopalan 			    "vhub table request");
135*b494511aSVenki Rajagopalan 			*err = ENOMEM;
136*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
137*b494511aSVenki Rajagopalan 		}
138*b494511aSVenki Rajagopalan 
139*b494511aSVenki Rajagopalan 		ret = eib_fip_make_table(ss, vnic, swqe, err);
140*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
141*b494511aSVenki Rajagopalan 			eib_rsrc_return_swqe(ss, swqe, NULL);
142*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
143*b494511aSVenki Rajagopalan 		}
144*b494511aSVenki Rajagopalan 
145*b494511aSVenki Rajagopalan 		ret = eib_fip_send_table(ss, vnic, swqe, err);
146*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS) {
147*b494511aSVenki Rajagopalan 			eib_rsrc_return_swqe(ss, swqe, NULL);
148*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
149*b494511aSVenki Rajagopalan 		}
150*b494511aSVenki Rajagopalan 
151*b494511aSVenki Rajagopalan 		ret = eib_vnic_wait_for_table(ss, vnic, err);
152*b494511aSVenki Rajagopalan 		if (ret == EIB_E_SUCCESS) {
153*b494511aSVenki Rajagopalan 			return (EIB_E_SUCCESS);
154*b494511aSVenki Rajagopalan 		}
155*b494511aSVenki Rajagopalan 
156*b494511aSVenki Rajagopalan 		/*
157*b494511aSVenki Rajagopalan 		 * If we'd failed in constructing a proper vhub table above,
158*b494511aSVenki Rajagopalan 		 * the vnic login state would be set to EIB_LOGIN_TBL_FAILED.
159*b494511aSVenki Rajagopalan 		 * We need to clean up any pending entries from the vhub
160*b494511aSVenki Rajagopalan 		 * table and vhub update structures and reset the vnic state
161*b494511aSVenki Rajagopalan 		 * to EIB_LOGIN_ACK_RCVD before we can try again.
162*b494511aSVenki Rajagopalan 		 */
163*b494511aSVenki Rajagopalan 		eib_vnic_fini_tables(ss, vnic, B_FALSE);
164*b494511aSVenki Rajagopalan 		mutex_enter(&vnic->vn_lock);
165*b494511aSVenki Rajagopalan 		vnic->vn_state = EIB_LOGIN_ACK_RCVD;
166*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
167*b494511aSVenki Rajagopalan 
168*b494511aSVenki Rajagopalan 	} while ((*err == ETIME) && (ntries++ < EIB_MAX_VHUB_TBL_ATTEMPTS));
169*b494511aSVenki Rajagopalan 
170*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
171*b494511aSVenki Rajagopalan }
172*b494511aSVenki Rajagopalan 
173*b494511aSVenki Rajagopalan int
eib_fip_heartbeat(eib_t * ss,eib_vnic_t * vnic,int * err)174*b494511aSVenki Rajagopalan eib_fip_heartbeat(eib_t *ss, eib_vnic_t *vnic, int *err)
175*b494511aSVenki Rajagopalan {
176*b494511aSVenki Rajagopalan 	eib_wqe_t *swqe;
177*b494511aSVenki Rajagopalan 	int ntries = 0;
178*b494511aSVenki Rajagopalan 	int ret;
179*b494511aSVenki Rajagopalan 
180*b494511aSVenki Rajagopalan 	/*
181*b494511aSVenki Rajagopalan 	 * Even if we're running low on the wqe resource, we want to be
182*b494511aSVenki Rajagopalan 	 * able to grab a wqe to send the keepalive, to avoid getting
183*b494511aSVenki Rajagopalan 	 * logged out by the gateway, so we use EIB_WPRI_HI.
184*b494511aSVenki Rajagopalan 	 */
185*b494511aSVenki Rajagopalan 	if ((swqe = eib_rsrc_grab_swqe(ss, EIB_WPRI_HI)) == NULL) {
186*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_heartbeat: "
187*b494511aSVenki Rajagopalan 		    "no swqe available, not sending heartbeat");
188*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
189*b494511aSVenki Rajagopalan 	}
190*b494511aSVenki Rajagopalan 
191*b494511aSVenki Rajagopalan 	while (ntries++ < EIB_MAX_KA_ATTEMPTS) {
192*b494511aSVenki Rajagopalan 		ret = eib_fip_make_ka(ss, vnic, swqe, err);
193*b494511aSVenki Rajagopalan 		if (ret != EIB_E_SUCCESS)
194*b494511aSVenki Rajagopalan 			continue;
195*b494511aSVenki Rajagopalan 
196*b494511aSVenki Rajagopalan 		ret = eib_fip_send_ka(ss, vnic, swqe, err);
197*b494511aSVenki Rajagopalan 		if (ret == EIB_E_SUCCESS)
198*b494511aSVenki Rajagopalan 			break;
199*b494511aSVenki Rajagopalan 	}
200*b494511aSVenki Rajagopalan 
201*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS)
202*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
203*b494511aSVenki Rajagopalan 
204*b494511aSVenki Rajagopalan 	return (ret);
205*b494511aSVenki Rajagopalan }
206*b494511aSVenki Rajagopalan 
207*b494511aSVenki Rajagopalan int
eib_fip_logout(eib_t * ss,eib_vnic_t * vnic,int * err)208*b494511aSVenki Rajagopalan eib_fip_logout(eib_t *ss, eib_vnic_t *vnic, int *err)
209*b494511aSVenki Rajagopalan {
210*b494511aSVenki Rajagopalan 	eib_wqe_t *swqe;
211*b494511aSVenki Rajagopalan 	int ret;
212*b494511aSVenki Rajagopalan 
213*b494511aSVenki Rajagopalan 	/*
214*b494511aSVenki Rajagopalan 	 * This routine is only called after the vnic has successfully
215*b494511aSVenki Rajagopalan 	 * logged in to the gateway. If that's really the case, there
216*b494511aSVenki Rajagopalan 	 * is nothing in terms of resources we need to release: the swqe
217*b494511aSVenki Rajagopalan 	 * that was acquired during login has already been posted, the
218*b494511aSVenki Rajagopalan 	 * work has been completed and the swqe has also been reaped back
219*b494511aSVenki Rajagopalan 	 * into the free pool. The only thing we need to rollback is the
220*b494511aSVenki Rajagopalan 	 * fact that we're logged in to the gateway at all -- and the way
221*b494511aSVenki Rajagopalan 	 * to do this is to send a logout request.
222*b494511aSVenki Rajagopalan 	 */
223*b494511aSVenki Rajagopalan 	if ((swqe = eib_rsrc_grab_swqe(ss, EIB_WPRI_LO)) == NULL) {
224*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_logout: "
225*b494511aSVenki Rajagopalan 		    "no swqe available, not sending logout");
226*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
227*b494511aSVenki Rajagopalan 	}
228*b494511aSVenki Rajagopalan 
229*b494511aSVenki Rajagopalan 	ret = eib_fip_make_logout(ss, vnic, swqe, err);
230*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
231*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
232*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
233*b494511aSVenki Rajagopalan 	}
234*b494511aSVenki Rajagopalan 
235*b494511aSVenki Rajagopalan 	ret = eib_fip_send_logout(ss, vnic, swqe, err);
236*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
237*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
238*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
239*b494511aSVenki Rajagopalan 	}
240*b494511aSVenki Rajagopalan 
241*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
242*b494511aSVenki Rajagopalan }
243*b494511aSVenki Rajagopalan 
244*b494511aSVenki Rajagopalan int
eib_fip_parse_login_ack(eib_t * ss,uint8_t * pkt,eib_login_data_t * ld)245*b494511aSVenki Rajagopalan eib_fip_parse_login_ack(eib_t *ss, uint8_t *pkt, eib_login_data_t *ld)
246*b494511aSVenki Rajagopalan {
247*b494511aSVenki Rajagopalan 	fip_login_ack_t *ack;
248*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
249*b494511aSVenki Rajagopalan 	fip_desc_iba_t *iba;
250*b494511aSVenki Rajagopalan 	fip_desc_vnic_login_t *login;
251*b494511aSVenki Rajagopalan 	fip_desc_partition_t *partition;
252*b494511aSVenki Rajagopalan 	ib_guid_t guid;
253*b494511aSVenki Rajagopalan 	uint32_t syn_ctl_qpn;
254*b494511aSVenki Rajagopalan 	uint16_t sl_portid;
255*b494511aSVenki Rajagopalan 	uint16_t flags_vlan;
256*b494511aSVenki Rajagopalan 	uint16_t opcode;
257*b494511aSVenki Rajagopalan 	uint8_t subcode;
258*b494511aSVenki Rajagopalan 
259*b494511aSVenki Rajagopalan 	/*
260*b494511aSVenki Rajagopalan 	 * Note that 'pkt' is always atleast double-word aligned
261*b494511aSVenki Rajagopalan 	 * when it is passed to us, so we can cast it without any
262*b494511aSVenki Rajagopalan 	 * problems.
263*b494511aSVenki Rajagopalan 	 */
264*b494511aSVenki Rajagopalan 	ack = (fip_login_ack_t *)(void *)pkt;
265*b494511aSVenki Rajagopalan 	hdr = &(ack->ak_fip_header);
266*b494511aSVenki Rajagopalan 
267*b494511aSVenki Rajagopalan 	/*
268*b494511aSVenki Rajagopalan 	 * Verify that the opcode is EoIB
269*b494511aSVenki Rajagopalan 	 */
270*b494511aSVenki Rajagopalan 	if ((opcode = ntohs(hdr->hd_opcode)) != FIP_OPCODE_EOIB) {
271*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
272*b494511aSVenki Rajagopalan 		    "unsupported opcode 0x%x in login ack, ignoring",
273*b494511aSVenki Rajagopalan 		    opcode);
274*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
275*b494511aSVenki Rajagopalan 	}
276*b494511aSVenki Rajagopalan 
277*b494511aSVenki Rajagopalan 	/*
278*b494511aSVenki Rajagopalan 	 * The admin qp in the EoIB driver should receive only the login
279*b494511aSVenki Rajagopalan 	 * acknowledgements
280*b494511aSVenki Rajagopalan 	 */
281*b494511aSVenki Rajagopalan 	subcode = hdr->hd_subcode;
282*b494511aSVenki Rajagopalan 	if (subcode != FIP_SUBCODE_G_VNIC_LOGIN_ACK) {
283*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
284*b494511aSVenki Rajagopalan 		    "unexpected subcode 0x%x received by adm qp, ignoring",
285*b494511aSVenki Rajagopalan 		    subcode);
286*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
287*b494511aSVenki Rajagopalan 	}
288*b494511aSVenki Rajagopalan 
289*b494511aSVenki Rajagopalan 	/*
290*b494511aSVenki Rajagopalan 	 * Verify if the descriptor list length in the received packet is
291*b494511aSVenki Rajagopalan 	 * valid if the workaround to disable it explicitly is absent.
292*b494511aSVenki Rajagopalan 	 */
293*b494511aSVenki Rajagopalan 	if (!eib_wa_no_desc_list_len) {
294*b494511aSVenki Rajagopalan 		uint_t pkt_data_sz;
295*b494511aSVenki Rajagopalan 
296*b494511aSVenki Rajagopalan 		pkt_data_sz = (ntohs(hdr->hd_desc_list_len) + 2) << 2;
297*b494511aSVenki Rajagopalan 		if (pkt_data_sz < sizeof (fip_login_ack_t)) {
298*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
299*b494511aSVenki Rajagopalan 			    "eib_fip_parse_login_ack: "
300*b494511aSVenki Rajagopalan 			    "login ack desc list len (0x%lx) too small "
301*b494511aSVenki Rajagopalan 			    "(min 0x%lx)",
302*b494511aSVenki Rajagopalan 			    pkt_data_sz, sizeof (fip_login_ack_t));
303*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
304*b494511aSVenki Rajagopalan 		}
305*b494511aSVenki Rajagopalan 	}
306*b494511aSVenki Rajagopalan 
307*b494511aSVenki Rajagopalan 	/*
308*b494511aSVenki Rajagopalan 	 * Validate all the header and descriptor types and lengths
309*b494511aSVenki Rajagopalan 	 */
310*b494511aSVenki Rajagopalan 	if (hdr->hd_type != FIP_DESC_TYPE_VENDOR_ID ||
311*b494511aSVenki Rajagopalan 	    hdr->hd_len != FIP_DESC_LEN_VENDOR_ID) {
312*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
313*b494511aSVenki Rajagopalan 		    "invalid type/len in basic hdr: expected (0x%x,0x%x), "
314*b494511aSVenki Rajagopalan 		    "got (0x%x,0x%x)", FIP_DESC_TYPE_VENDOR_ID,
315*b494511aSVenki Rajagopalan 		    FIP_DESC_LEN_VENDOR_ID, hdr->hd_type, hdr->hd_len);
316*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
317*b494511aSVenki Rajagopalan 	}
318*b494511aSVenki Rajagopalan 	iba = &(ack->ak_iba);
319*b494511aSVenki Rajagopalan 	if (iba->ia_type != FIP_DESC_TYPE_IBA ||
320*b494511aSVenki Rajagopalan 	    iba->ia_len != FIP_DESC_LEN_IBA) {
321*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
322*b494511aSVenki Rajagopalan 		    "invalid type/len in iba desc: expected (0x%x,0x%x), "
323*b494511aSVenki Rajagopalan 		    "got (0x%x,0x%x)", FIP_DESC_TYPE_IBA, FIP_DESC_LEN_IBA,
324*b494511aSVenki Rajagopalan 		    iba->ia_type, iba->ia_len);
325*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
326*b494511aSVenki Rajagopalan 	}
327*b494511aSVenki Rajagopalan 	login = &(ack->ak_vnic_login);
328*b494511aSVenki Rajagopalan 	if (login->vl_type != FIP_DESC_TYPE_VNIC_LOGIN ||
329*b494511aSVenki Rajagopalan 	    login->vl_len != FIP_DESC_LEN_VNIC_LOGIN) {
330*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
331*b494511aSVenki Rajagopalan 		    "invalid type/len in login desc: expected (0x%x,0x%x), "
332*b494511aSVenki Rajagopalan 		    "got (0x%x,0x%x)", FIP_DESC_TYPE_VNIC_LOGIN,
333*b494511aSVenki Rajagopalan 		    FIP_DESC_LEN_VNIC_LOGIN, login->vl_type, login->vl_len);
334*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
335*b494511aSVenki Rajagopalan 	}
336*b494511aSVenki Rajagopalan 	partition = &(ack->ak_vhub_partition);
337*b494511aSVenki Rajagopalan 	if (partition->pn_type != FIP_DESC_TYPE_PARTITION ||
338*b494511aSVenki Rajagopalan 	    partition->pn_len != FIP_DESC_LEN_PARTITION) {
339*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_login_ack: "
340*b494511aSVenki Rajagopalan 		    "invalid type/len in partition desc: expected (0x%x,0x%x), "
341*b494511aSVenki Rajagopalan 		    "got (0x%x,0x%x)", FIP_DESC_TYPE_PARTITION,
342*b494511aSVenki Rajagopalan 		    FIP_DESC_LEN_PARTITION, partition->pn_type,
343*b494511aSVenki Rajagopalan 		    partition->pn_len);
344*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
345*b494511aSVenki Rajagopalan 	}
346*b494511aSVenki Rajagopalan 
347*b494511aSVenki Rajagopalan 	/*
348*b494511aSVenki Rajagopalan 	 * Note that we'll return the vnic id as-is.  The msb is not actually
349*b494511aSVenki Rajagopalan 	 * part of the vnic id in our internal records, so we'll mask it out
350*b494511aSVenki Rajagopalan 	 * later before we do our searches.
351*b494511aSVenki Rajagopalan 	 */
352*b494511aSVenki Rajagopalan 	ld->ld_vnic_id = ntohs(login->vl_vnic_id);
353*b494511aSVenki Rajagopalan 
354*b494511aSVenki Rajagopalan 	syn_ctl_qpn = ntohl(login->vl_syndrome_ctl_qpn);
355*b494511aSVenki Rajagopalan 
356*b494511aSVenki Rajagopalan 	/*
357*b494511aSVenki Rajagopalan 	 * If the syndrome indicates a nack, we're done.  No need to collect
358*b494511aSVenki Rajagopalan 	 * any more information
359*b494511aSVenki Rajagopalan 	 */
360*b494511aSVenki Rajagopalan 	ld->ld_syndrome = (uint8_t)((syn_ctl_qpn & FIP_VL_SYN_MASK) >>
361*b494511aSVenki Rajagopalan 	    FIP_VL_SYN_SHIFT);
362*b494511aSVenki Rajagopalan 	if (ld->ld_syndrome) {
363*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
364*b494511aSVenki Rajagopalan 	}
365*b494511aSVenki Rajagopalan 
366*b494511aSVenki Rajagopalan 	/*
367*b494511aSVenki Rajagopalan 	 * Let's get the rest of the information out of the login ack
368*b494511aSVenki Rajagopalan 	 */
369*b494511aSVenki Rajagopalan 	sl_portid = ntohs(iba->ia_sl_portid);
370*b494511aSVenki Rajagopalan 	ld->ld_gw_port_id = sl_portid & FIP_IBA_PORTID_MASK;
371*b494511aSVenki Rajagopalan 	ld->ld_gw_sl = (sl_portid & FIP_IBA_SL_MASK) >> FIP_IBA_SL_SHIFT;
372*b494511aSVenki Rajagopalan 
373*b494511aSVenki Rajagopalan 	ld->ld_gw_data_qpn = ntohl(iba->ia_qpn) & FIP_IBA_QPN_MASK;
374*b494511aSVenki Rajagopalan 	ld->ld_gw_lid = ntohs(iba->ia_lid);
375*b494511aSVenki Rajagopalan 
376*b494511aSVenki Rajagopalan 	bcopy(iba->ia_guid, &guid, sizeof (ib_guid_t));
377*b494511aSVenki Rajagopalan 	ld->ld_gw_guid = ntohll(guid);
378*b494511aSVenki Rajagopalan 	ld->ld_vhub_mtu = ntohs(login->vl_mtu);
379*b494511aSVenki Rajagopalan 	bcopy(login->vl_mac, ld->ld_assigned_mac, ETHERADDRL);
380*b494511aSVenki Rajagopalan 	bcopy(login->vl_gw_mgid_prefix, ld->ld_gw_mgid_prefix,
381*b494511aSVenki Rajagopalan 	    FIP_MGID_PREFIX_LEN);
382*b494511aSVenki Rajagopalan 	ld->ld_n_rss_mcgid = login->vl_flags_rss & FIP_VL_N_RSS_MCGID_MASK;
383*b494511aSVenki Rajagopalan 	ld->ld_n_mac_mcgid = login->vl_n_mac_mcgid & FIP_VL_N_MAC_MCGID_MASK;
384*b494511aSVenki Rajagopalan 	ld->ld_gw_ctl_qpn = (syn_ctl_qpn & FIP_VL_CTL_QPN_MASK);
385*b494511aSVenki Rajagopalan 
386*b494511aSVenki Rajagopalan 	flags_vlan = ntohs(login->vl_flags_vlan);
387*b494511aSVenki Rajagopalan 	ld->ld_assigned_vlan = flags_vlan & FIP_VL_VLAN_MASK;
388*b494511aSVenki Rajagopalan 	ld->ld_vlan_in_packets = (flags_vlan & FIP_VL_FLAGS_VP) ? 1 : 0;
389*b494511aSVenki Rajagopalan 	bcopy(login->vl_vnic_name, ld->ld_vnic_name, FIP_VNIC_NAME_LEN);
390*b494511aSVenki Rajagopalan 
391*b494511aSVenki Rajagopalan 	ld->ld_vhub_pkey = ntohs(partition->pn_pkey);
392*b494511aSVenki Rajagopalan 
393*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
394*b494511aSVenki Rajagopalan }
395*b494511aSVenki Rajagopalan 
396*b494511aSVenki Rajagopalan int
eib_fip_parse_ctl_pkt(uint8_t * pkt,eib_vnic_t * vnic)397*b494511aSVenki Rajagopalan eib_fip_parse_ctl_pkt(uint8_t *pkt, eib_vnic_t *vnic)
398*b494511aSVenki Rajagopalan {
399*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
400*b494511aSVenki Rajagopalan 	fip_vhub_pkt_t *vhb;
401*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
402*b494511aSVenki Rajagopalan 	uint16_t opcode;
403*b494511aSVenki Rajagopalan 	uint8_t subcode;
404*b494511aSVenki Rajagopalan 	uint_t vnic_state;
405*b494511aSVenki Rajagopalan 	int ret = EIB_E_FAILURE;
406*b494511aSVenki Rajagopalan 
407*b494511aSVenki Rajagopalan 	/*
408*b494511aSVenki Rajagopalan 	 * Note that 'pkt' is always atleast double-word aligned when it is
409*b494511aSVenki Rajagopalan 	 * passed to us, so we can cast it without any problems.
410*b494511aSVenki Rajagopalan 	 */
411*b494511aSVenki Rajagopalan 	vhb = (fip_vhub_pkt_t *)(void *)pkt;
412*b494511aSVenki Rajagopalan 	hdr = &(vhb->hb_fip_header);
413*b494511aSVenki Rajagopalan 
414*b494511aSVenki Rajagopalan 	/*
415*b494511aSVenki Rajagopalan 	 * Verify that the opcode is EoIB
416*b494511aSVenki Rajagopalan 	 */
417*b494511aSVenki Rajagopalan 	if ((opcode = ntohs(hdr->hd_opcode)) != FIP_OPCODE_EOIB) {
418*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_ctl_pkt: "
419*b494511aSVenki Rajagopalan 		    "unsupported opcode 0x%x in ctl pkt, ignoring",
420*b494511aSVenki Rajagopalan 		    opcode);
421*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
422*b494511aSVenki Rajagopalan 	}
423*b494511aSVenki Rajagopalan 
424*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
425*b494511aSVenki Rajagopalan 	vnic_state = vnic->vn_state;
426*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
427*b494511aSVenki Rajagopalan 
428*b494511aSVenki Rajagopalan 	/*
429*b494511aSVenki Rajagopalan 	 * The ctl qp in the EoIB driver should receive only vHUB messages
430*b494511aSVenki Rajagopalan 	 */
431*b494511aSVenki Rajagopalan 	subcode = hdr->hd_subcode;
432*b494511aSVenki Rajagopalan 	if (subcode == FIP_SUBCODE_G_VHUB_UPDATE) {
433*b494511aSVenki Rajagopalan 		if (vnic_state != EIB_LOGIN_TBL_WAIT &&
434*b494511aSVenki Rajagopalan 		    vnic_state != EIB_LOGIN_TBL_INPROG &&
435*b494511aSVenki Rajagopalan 		    vnic_state != EIB_LOGIN_TBL_DONE &&
436*b494511aSVenki Rajagopalan 		    vnic_state != EIB_LOGIN_DONE) {
437*b494511aSVenki Rajagopalan 
438*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
439*b494511aSVenki Rajagopalan 			    "eib_fip_parse_ctl_pkt: unexpected vnic state "
440*b494511aSVenki Rajagopalan 			    "(0x%lx) for subcode (VHUB_UPDATE 0x%x)",
441*b494511aSVenki Rajagopalan 			    vnic_state, subcode);
442*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
443*b494511aSVenki Rajagopalan 		}
444*b494511aSVenki Rajagopalan 
445*b494511aSVenki Rajagopalan 		ret = eib_fip_parse_vhub_update(pkt, vnic);
446*b494511aSVenki Rajagopalan 
447*b494511aSVenki Rajagopalan 	} else if (subcode == FIP_SUBCODE_G_VHUB_TABLE) {
448*b494511aSVenki Rajagopalan 		if ((vnic_state != EIB_LOGIN_TBL_WAIT) &&
449*b494511aSVenki Rajagopalan 		    (vnic_state != EIB_LOGIN_TBL_INPROG)) {
450*b494511aSVenki Rajagopalan 
451*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
452*b494511aSVenki Rajagopalan 			    "eib_fip_parse_ctl_pkt: unexpected vnic state "
453*b494511aSVenki Rajagopalan 			    "(0x%lx) for subcode (VHUB_TABLE 0x%x)",
454*b494511aSVenki Rajagopalan 			    vnic_state, subcode);
455*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
456*b494511aSVenki Rajagopalan 		}
457*b494511aSVenki Rajagopalan 
458*b494511aSVenki Rajagopalan 		ret = eib_fip_parse_vhub_table(pkt, vnic);
459*b494511aSVenki Rajagopalan 
460*b494511aSVenki Rajagopalan 	} else {
461*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_ctl_pkt: "
462*b494511aSVenki Rajagopalan 		    "unexpected subcode 0x%x for ctl pkt", subcode);
463*b494511aSVenki Rajagopalan 	}
464*b494511aSVenki Rajagopalan 
465*b494511aSVenki Rajagopalan 	if (ret == EIB_E_SUCCESS) {
466*b494511aSVenki Rajagopalan 		/*
467*b494511aSVenki Rajagopalan 		 * Update last gateway heartbeat received time and
468*b494511aSVenki Rajagopalan 		 * gateway eport state.  The eport state should only
469*b494511aSVenki Rajagopalan 		 * be updated if the vnic's vhub table has been fully
470*b494511aSVenki Rajagopalan 		 * constructed.
471*b494511aSVenki Rajagopalan 		 */
472*b494511aSVenki Rajagopalan 		mutex_enter(&ss->ei_vnic_lock);
473*b494511aSVenki Rajagopalan 		ss->ei_gw_last_heartbeat = ddi_get_lbolt64();
474*b494511aSVenki Rajagopalan 		if (vnic_state == EIB_LOGIN_TBL_DONE ||
475*b494511aSVenki Rajagopalan 		    vnic_state == EIB_LOGIN_DONE) {
476*b494511aSVenki Rajagopalan 			ss->ei_gw_eport_state =
477*b494511aSVenki Rajagopalan 			    vnic->vn_vhub_table->tb_eport_state;
478*b494511aSVenki Rajagopalan 		}
479*b494511aSVenki Rajagopalan 		mutex_exit(&ss->ei_vnic_lock);
480*b494511aSVenki Rajagopalan 	}
481*b494511aSVenki Rajagopalan 
482*b494511aSVenki Rajagopalan 	return (ret);
483*b494511aSVenki Rajagopalan }
484*b494511aSVenki Rajagopalan 
485*b494511aSVenki Rajagopalan static int
eib_fip_make_login(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)486*b494511aSVenki Rajagopalan eib_fip_make_login(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
487*b494511aSVenki Rajagopalan {
488*b494511aSVenki Rajagopalan 	fip_login_t *login;
489*b494511aSVenki Rajagopalan 	fip_proto_t *proto;
490*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
491*b494511aSVenki Rajagopalan 	fip_desc_iba_t *iba;
492*b494511aSVenki Rajagopalan 	fip_desc_vnic_login_t *vlg;
493*b494511aSVenki Rajagopalan 	ib_gid_t port_gid;
494*b494511aSVenki Rajagopalan 	ib_guid_t port_guid;
495*b494511aSVenki Rajagopalan 	uint16_t sl_portid;
496*b494511aSVenki Rajagopalan 	uint16_t flags_vlan;
497*b494511aSVenki Rajagopalan 
498*b494511aSVenki Rajagopalan 	uint16_t gw_portid = ss->ei_gw_props->pp_gw_portid;
499*b494511aSVenki Rajagopalan 	uint16_t sl = ss->ei_gw_props->pp_gw_sl;
500*b494511aSVenki Rajagopalan 	uint8_t *pkt = (uint8_t *)(uintptr_t)(swqe->qe_sgl.ds_va);
501*b494511aSVenki Rajagopalan 	uint_t pktsz = swqe->qe_sgl.ds_len;
502*b494511aSVenki Rajagopalan 	uint_t login_sz = sizeof (fip_login_t);
503*b494511aSVenki Rajagopalan 
504*b494511aSVenki Rajagopalan 	if (pktsz < login_sz) {
505*b494511aSVenki Rajagopalan 		*err = EINVAL;
506*b494511aSVenki Rajagopalan 
507*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_make_login: "
508*b494511aSVenki Rajagopalan 		    "send buffer size (0x%lx) too small to send"
509*b494511aSVenki Rajagopalan 		    "login request (min 0x%lx)",
510*b494511aSVenki Rajagopalan 		    pktsz, login_sz);
511*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
512*b494511aSVenki Rajagopalan 	}
513*b494511aSVenki Rajagopalan 
514*b494511aSVenki Rajagopalan 	/*
515*b494511aSVenki Rajagopalan 	 * Lint complains that there may be an alignment issue here,
516*b494511aSVenki Rajagopalan 	 * but we know that the "pkt" is atleast double-word aligned,
517*b494511aSVenki Rajagopalan 	 * so it's ok.
518*b494511aSVenki Rajagopalan 	 */
519*b494511aSVenki Rajagopalan 	login = (fip_login_t *)(void *)pkt;
520*b494511aSVenki Rajagopalan 	bzero(pkt, login_sz);
521*b494511aSVenki Rajagopalan 
522*b494511aSVenki Rajagopalan 	/*
523*b494511aSVenki Rajagopalan 	 * Fill in the FIP protocol version
524*b494511aSVenki Rajagopalan 	 */
525*b494511aSVenki Rajagopalan 	proto = &login->lg_proto_version;
526*b494511aSVenki Rajagopalan 	proto->pr_version = FIP_PROTO_VERSION;
527*b494511aSVenki Rajagopalan 
528*b494511aSVenki Rajagopalan 	/*
529*b494511aSVenki Rajagopalan 	 * Fill in the basic header
530*b494511aSVenki Rajagopalan 	 */
531*b494511aSVenki Rajagopalan 	hdr = &login->lg_fip_header;
532*b494511aSVenki Rajagopalan 	hdr->hd_opcode = htons(FIP_OPCODE_EOIB);
533*b494511aSVenki Rajagopalan 	hdr->hd_subcode = FIP_SUBCODE_H_VNIC_LOGIN;
534*b494511aSVenki Rajagopalan 	hdr->hd_desc_list_len = htons((login_sz >> 2) - 2);
535*b494511aSVenki Rajagopalan 	hdr->hd_flags = 0;
536*b494511aSVenki Rajagopalan 	hdr->hd_type = FIP_DESC_TYPE_VENDOR_ID;
537*b494511aSVenki Rajagopalan 	hdr->hd_len = FIP_DESC_LEN_VENDOR_ID;
538*b494511aSVenki Rajagopalan 	bcopy(eib_vendor_mellanox, hdr->hd_vendor_id, FIP_VENDOR_LEN);
539*b494511aSVenki Rajagopalan 
540*b494511aSVenki Rajagopalan 	/*
541*b494511aSVenki Rajagopalan 	 * Fill in the Infiniband Address descriptor
542*b494511aSVenki Rajagopalan 	 */
543*b494511aSVenki Rajagopalan 	iba = &login->lg_iba;
544*b494511aSVenki Rajagopalan 	iba->ia_type = FIP_DESC_TYPE_IBA;
545*b494511aSVenki Rajagopalan 	iba->ia_len = FIP_DESC_LEN_IBA;
546*b494511aSVenki Rajagopalan 	bcopy(eib_vendor_mellanox, iba->ia_vendor_id, FIP_VENDOR_LEN);
547*b494511aSVenki Rajagopalan 	iba->ia_qpn = htonl(vnic->vn_data_chan->ch_qpn);
548*b494511aSVenki Rajagopalan 
549*b494511aSVenki Rajagopalan 	sl_portid = (gw_portid & FIP_IBA_PORTID_MASK) |
550*b494511aSVenki Rajagopalan 	    ((sl << FIP_IBA_SL_SHIFT) & FIP_IBA_SL_MASK);
551*b494511aSVenki Rajagopalan 	iba->ia_sl_portid = htons(sl_portid);
552*b494511aSVenki Rajagopalan 
553*b494511aSVenki Rajagopalan 	iba->ia_lid = htons(ss->ei_props->ep_blid);
554*b494511aSVenki Rajagopalan 
555*b494511aSVenki Rajagopalan 	port_gid = ss->ei_props->ep_sgid;
556*b494511aSVenki Rajagopalan 	port_guid = htonll(port_gid.gid_guid);
557*b494511aSVenki Rajagopalan 	bcopy(&port_guid, iba->ia_guid, FIP_GUID_LEN);
558*b494511aSVenki Rajagopalan 
559*b494511aSVenki Rajagopalan 	/*
560*b494511aSVenki Rajagopalan 	 * Now, fill in the vNIC Login descriptor
561*b494511aSVenki Rajagopalan 	 */
562*b494511aSVenki Rajagopalan 
563*b494511aSVenki Rajagopalan 	vlg = &login->lg_vnic_login;
564*b494511aSVenki Rajagopalan 	vlg->vl_type = FIP_DESC_TYPE_VNIC_LOGIN;
565*b494511aSVenki Rajagopalan 	vlg->vl_len = FIP_DESC_LEN_VNIC_LOGIN;
566*b494511aSVenki Rajagopalan 	bcopy(eib_vendor_mellanox, vlg->vl_vendor_id, FIP_VENDOR_LEN);
567*b494511aSVenki Rajagopalan 
568*b494511aSVenki Rajagopalan 	/*
569*b494511aSVenki Rajagopalan 	 * Only for the physlink instance 0, we ask the gateway to assign
570*b494511aSVenki Rajagopalan 	 * the mac address and a VLAN (tagless, actually).  For this vnic
571*b494511aSVenki Rajagopalan 	 * only, we do not set the H bit. All other vnics are created by
572*b494511aSVenki Rajagopalan 	 * Solaris admin and will have the H bit set. Note also that we
573*b494511aSVenki Rajagopalan 	 * need to clear the vnic id's most significant bit for those that
574*b494511aSVenki Rajagopalan 	 * are administered by the gateway, so vnic0's vnic_id's msb should
575*b494511aSVenki Rajagopalan 	 * be 0 as well.
576*b494511aSVenki Rajagopalan 	 */
577*b494511aSVenki Rajagopalan 	if (vnic->vn_instance == 0) {
578*b494511aSVenki Rajagopalan 		vlg->vl_vnic_id = htons(vnic->vn_id);
579*b494511aSVenki Rajagopalan 		flags_vlan = vnic->vn_vlan & FIP_VL_VLAN_MASK;
580*b494511aSVenki Rajagopalan 	} else {
581*b494511aSVenki Rajagopalan 		vlg->vl_vnic_id = htons(vnic->vn_id | FIP_VL_VNIC_ID_MSBIT);
582*b494511aSVenki Rajagopalan 		flags_vlan = (vnic->vn_vlan & FIP_VL_VLAN_MASK) |
583*b494511aSVenki Rajagopalan 		    FIP_VL_FLAGS_H | FIP_VL_FLAGS_M;
584*b494511aSVenki Rajagopalan 
585*b494511aSVenki Rajagopalan 		if (vnic->vn_vlan & FIP_VL_VLAN_MASK)
586*b494511aSVenki Rajagopalan 			flags_vlan |= (FIP_VL_FLAGS_V | FIP_VL_FLAGS_VP);
587*b494511aSVenki Rajagopalan 	}
588*b494511aSVenki Rajagopalan 
589*b494511aSVenki Rajagopalan 	vlg->vl_flags_vlan = htons(flags_vlan);
590*b494511aSVenki Rajagopalan 	bcopy(vnic->vn_macaddr, vlg->vl_mac, ETHERADDRL);
591*b494511aSVenki Rajagopalan 
592*b494511aSVenki Rajagopalan 	/*
593*b494511aSVenki Rajagopalan 	 * We aren't ready to enable rss, so we set the RSS bit and
594*b494511aSVenki Rajagopalan 	 * the n_rss_mcgid field to 0.  Set the mac mcgid to 0 as well.
595*b494511aSVenki Rajagopalan 	 */
596*b494511aSVenki Rajagopalan 	vlg->vl_flags_rss = 0;
597*b494511aSVenki Rajagopalan 	vlg->vl_n_mac_mcgid = 0;
598*b494511aSVenki Rajagopalan 
599*b494511aSVenki Rajagopalan 	/*
600*b494511aSVenki Rajagopalan 	 * Set the syndrome to 0 and pass the control qpn
601*b494511aSVenki Rajagopalan 	 */
602*b494511aSVenki Rajagopalan 	vlg->vl_syndrome_ctl_qpn =
603*b494511aSVenki Rajagopalan 	    htonl(vnic->vn_ctl_chan->ch_qpn & FIP_VL_CTL_QPN_MASK);
604*b494511aSVenki Rajagopalan 
605*b494511aSVenki Rajagopalan 	/*
606*b494511aSVenki Rajagopalan 	 * Try to set as unique a name as possible for this vnic
607*b494511aSVenki Rajagopalan 	 */
608*b494511aSVenki Rajagopalan 	(void) snprintf((char *)(vlg->vl_vnic_name), FIP_VNIC_NAME_LEN,
609*b494511aSVenki Rajagopalan 	    "eoib_%02x_%02x", ss->ei_instance, vnic->vn_instance);
610*b494511aSVenki Rajagopalan 
611*b494511aSVenki Rajagopalan 	/*
612*b494511aSVenki Rajagopalan 	 * Adjust the ds_len in the sgl to indicate the size of this
613*b494511aSVenki Rajagopalan 	 * request before returning
614*b494511aSVenki Rajagopalan 	 */
615*b494511aSVenki Rajagopalan 	swqe->qe_sgl.ds_len = login_sz;
616*b494511aSVenki Rajagopalan 
617*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
618*b494511aSVenki Rajagopalan }
619*b494511aSVenki Rajagopalan 
620*b494511aSVenki Rajagopalan static int
eib_fip_make_update(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int req,int * err)621*b494511aSVenki Rajagopalan eib_fip_make_update(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int req,
622*b494511aSVenki Rajagopalan     int *err)
623*b494511aSVenki Rajagopalan {
624*b494511aSVenki Rajagopalan 	fip_keep_alive_t *ka;
625*b494511aSVenki Rajagopalan 	fip_proto_t *proto;
626*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
627*b494511aSVenki Rajagopalan 	fip_desc_vnic_identity_t *vid;
628*b494511aSVenki Rajagopalan 	ib_gid_t port_gid;
629*b494511aSVenki Rajagopalan 	ib_guid_t port_guid;
630*b494511aSVenki Rajagopalan 	uint32_t flags_vhub_id;
631*b494511aSVenki Rajagopalan 
632*b494511aSVenki Rajagopalan 	uint8_t *pkt = (uint8_t *)(uintptr_t)(swqe->qe_sgl.ds_va);
633*b494511aSVenki Rajagopalan 	uint_t pktsz = swqe->qe_sgl.ds_len;
634*b494511aSVenki Rajagopalan 	uint_t ka_sz = sizeof (fip_keep_alive_t);
635*b494511aSVenki Rajagopalan 
636*b494511aSVenki Rajagopalan 	if (pktsz < ka_sz) {
637*b494511aSVenki Rajagopalan 		*err = EINVAL;
638*b494511aSVenki Rajagopalan 
639*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_make_update: "
640*b494511aSVenki Rajagopalan 		    "send buffer size (0x%lx) too small to send"
641*b494511aSVenki Rajagopalan 		    "keepalive/update request (min 0x%lx)",
642*b494511aSVenki Rajagopalan 		    pktsz, ka_sz);
643*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
644*b494511aSVenki Rajagopalan 	}
645*b494511aSVenki Rajagopalan 
646*b494511aSVenki Rajagopalan 	/*
647*b494511aSVenki Rajagopalan 	 * Lint complains that there may be an alignment issue here,
648*b494511aSVenki Rajagopalan 	 * but we know that the "pkt" is atleast double-word aligned,
649*b494511aSVenki Rajagopalan 	 * so it's ok.
650*b494511aSVenki Rajagopalan 	 */
651*b494511aSVenki Rajagopalan 	ka = (fip_keep_alive_t *)(void *)pkt;
652*b494511aSVenki Rajagopalan 	bzero(pkt, ka_sz);
653*b494511aSVenki Rajagopalan 
654*b494511aSVenki Rajagopalan 	/*
655*b494511aSVenki Rajagopalan 	 * Fill in the FIP protocol version
656*b494511aSVenki Rajagopalan 	 */
657*b494511aSVenki Rajagopalan 	proto = &ka->ka_proto_version;
658*b494511aSVenki Rajagopalan 	proto->pr_version = FIP_PROTO_VERSION;
659*b494511aSVenki Rajagopalan 
660*b494511aSVenki Rajagopalan 	/*
661*b494511aSVenki Rajagopalan 	 * Fill in the basic header
662*b494511aSVenki Rajagopalan 	 */
663*b494511aSVenki Rajagopalan 	hdr = &ka->ka_fip_header;
664*b494511aSVenki Rajagopalan 	hdr->hd_opcode = htons(FIP_OPCODE_EOIB);
665*b494511aSVenki Rajagopalan 	hdr->hd_subcode = (req == EIB_UPD_REQ_LOGOUT) ?
666*b494511aSVenki Rajagopalan 	    FIP_SUBCODE_H_VNIC_LOGOUT : FIP_SUBCODE_H_KEEP_ALIVE;
667*b494511aSVenki Rajagopalan 	hdr->hd_desc_list_len = htons((ka_sz >> 2) - 2);
668*b494511aSVenki Rajagopalan 	hdr->hd_flags = 0;
669*b494511aSVenki Rajagopalan 	hdr->hd_type = FIP_DESC_TYPE_VENDOR_ID;
670*b494511aSVenki Rajagopalan 	hdr->hd_len = FIP_DESC_LEN_VENDOR_ID;
671*b494511aSVenki Rajagopalan 	bcopy(eib_vendor_mellanox, hdr->hd_vendor_id, FIP_VENDOR_LEN);
672*b494511aSVenki Rajagopalan 
673*b494511aSVenki Rajagopalan 	/*
674*b494511aSVenki Rajagopalan 	 * Fill in the vNIC Identity descriptor
675*b494511aSVenki Rajagopalan 	 */
676*b494511aSVenki Rajagopalan 	vid = &ka->ka_vnic_identity;
677*b494511aSVenki Rajagopalan 
678*b494511aSVenki Rajagopalan 	vid->vi_type = FIP_DESC_TYPE_VNIC_IDENTITY;
679*b494511aSVenki Rajagopalan 	vid->vi_len = FIP_DESC_LEN_VNIC_IDENTITY;
680*b494511aSVenki Rajagopalan 	bcopy(eib_vendor_mellanox, vid->vi_vendor_id, FIP_VENDOR_LEN);
681*b494511aSVenki Rajagopalan 
682*b494511aSVenki Rajagopalan 	flags_vhub_id = vnic->vn_login_data.ld_vhub_id;
683*b494511aSVenki Rajagopalan 	if (vnic->vn_login_data.ld_vlan_in_packets) {
684*b494511aSVenki Rajagopalan 		flags_vhub_id |= FIP_VI_FLAG_VP;
685*b494511aSVenki Rajagopalan 	}
686*b494511aSVenki Rajagopalan 	if (req == EIB_UPD_REQ_TABLE) {
687*b494511aSVenki Rajagopalan 		flags_vhub_id |= FIP_VI_FLAG_R;
688*b494511aSVenki Rajagopalan 	} else if (req == EIB_UPD_REQ_KA) {
689*b494511aSVenki Rajagopalan 		flags_vhub_id |= FIP_VI_FLAG_U;
690*b494511aSVenki Rajagopalan 	}
691*b494511aSVenki Rajagopalan 	vid->vi_flags_vhub_id = htonl(flags_vhub_id);
692*b494511aSVenki Rajagopalan 
693*b494511aSVenki Rajagopalan 	vid->vi_tusn = (req != EIB_UPD_REQ_LOGOUT) ?
694*b494511aSVenki Rajagopalan 	    htonl(vnic->vn_vhub_table->tb_tusn) : 0;
695*b494511aSVenki Rajagopalan 
696*b494511aSVenki Rajagopalan 	vid->vi_vnic_id = htons(vnic->vn_login_data.ld_vnic_id);
697*b494511aSVenki Rajagopalan 	bcopy(vnic->vn_login_data.ld_assigned_mac, vid->vi_mac, ETHERADDRL);
698*b494511aSVenki Rajagopalan 
699*b494511aSVenki Rajagopalan 	port_gid = ss->ei_props->ep_sgid;
700*b494511aSVenki Rajagopalan 	port_guid = htonll(port_gid.gid_guid);
701*b494511aSVenki Rajagopalan 	bcopy(&port_guid, vid->vi_port_guid, FIP_GUID_LEN);
702*b494511aSVenki Rajagopalan 	bcopy(vnic->vn_login_data.ld_vnic_name, vid->vi_vnic_name,
703*b494511aSVenki Rajagopalan 	    FIP_VNIC_NAME_LEN);
704*b494511aSVenki Rajagopalan 
705*b494511aSVenki Rajagopalan 	/*
706*b494511aSVenki Rajagopalan 	 * Adjust the ds_len in the sgl to indicate the size of this
707*b494511aSVenki Rajagopalan 	 * request before returning
708*b494511aSVenki Rajagopalan 	 */
709*b494511aSVenki Rajagopalan 	swqe->qe_sgl.ds_len = ka_sz;
710*b494511aSVenki Rajagopalan 
711*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
712*b494511aSVenki Rajagopalan }
713*b494511aSVenki Rajagopalan 
714*b494511aSVenki Rajagopalan static int
eib_fip_make_table(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)715*b494511aSVenki Rajagopalan eib_fip_make_table(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
716*b494511aSVenki Rajagopalan {
717*b494511aSVenki Rajagopalan 	return (eib_fip_make_update(ss, vnic, swqe, EIB_UPD_REQ_TABLE, err));
718*b494511aSVenki Rajagopalan }
719*b494511aSVenki Rajagopalan 
720*b494511aSVenki Rajagopalan static int
eib_fip_make_ka(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)721*b494511aSVenki Rajagopalan eib_fip_make_ka(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
722*b494511aSVenki Rajagopalan {
723*b494511aSVenki Rajagopalan 	return (eib_fip_make_update(ss, vnic, swqe, EIB_UPD_REQ_KA, err));
724*b494511aSVenki Rajagopalan }
725*b494511aSVenki Rajagopalan 
726*b494511aSVenki Rajagopalan static int
eib_fip_make_logout(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)727*b494511aSVenki Rajagopalan eib_fip_make_logout(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
728*b494511aSVenki Rajagopalan {
729*b494511aSVenki Rajagopalan 	return (eib_fip_make_update(ss, vnic, swqe, EIB_UPD_REQ_LOGOUT, err));
730*b494511aSVenki Rajagopalan }
731*b494511aSVenki Rajagopalan 
732*b494511aSVenki Rajagopalan static int
eib_fip_send_login(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)733*b494511aSVenki Rajagopalan eib_fip_send_login(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
734*b494511aSVenki Rajagopalan {
735*b494511aSVenki Rajagopalan 	eib_avect_t *av;
736*b494511aSVenki Rajagopalan 	eib_chan_t *chan = ss->ei_admin_chan;
737*b494511aSVenki Rajagopalan 	ibt_status_t ret;
738*b494511aSVenki Rajagopalan 
739*b494511aSVenki Rajagopalan 	/*
740*b494511aSVenki Rajagopalan 	 * Get an address vector for this destination
741*b494511aSVenki Rajagopalan 	 */
742*b494511aSVenki Rajagopalan 	if ((av = eib_ibt_hold_avect(ss, ss->ei_gw_props->pp_gw_lid,
743*b494511aSVenki Rajagopalan 	    ss->ei_gw_props->pp_gw_sl)) == NULL) {
744*b494511aSVenki Rajagopalan 		*err = ENOMEM;
745*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_login: "
746*b494511aSVenki Rajagopalan 		    "eib_ibt_hold_avect(gw_lid=0x%x, sl=0x%x) failed",
747*b494511aSVenki Rajagopalan 		    ss->ei_gw_props->pp_gw_lid, ss->ei_gw_props->pp_gw_sl);
748*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
749*b494511aSVenki Rajagopalan 	}
750*b494511aSVenki Rajagopalan 
751*b494511aSVenki Rajagopalan 	/*
752*b494511aSVenki Rajagopalan 	 * Modify the UD destination handle to the gateway
753*b494511aSVenki Rajagopalan 	 */
754*b494511aSVenki Rajagopalan 	ret = ibt_modify_ud_dest(swqe->qe_dest, EIB_FIP_QKEY,
755*b494511aSVenki Rajagopalan 	    ss->ei_gw_props->pp_gw_ctrl_qpn, &av->av_vect);
756*b494511aSVenki Rajagopalan 
757*b494511aSVenki Rajagopalan 	eib_ibt_release_avect(ss, av);
758*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
759*b494511aSVenki Rajagopalan 		*err = EINVAL;
760*b494511aSVenki Rajagopalan 
761*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_login: "
762*b494511aSVenki Rajagopalan 		    "ibt_modify_ud_dest(gw_ctl_qpn=0x%lx, qkey=0x%lx) failed, "
763*b494511aSVenki Rajagopalan 		    "ret=%d", ss->ei_gw_props->pp_gw_ctrl_qpn,
764*b494511aSVenki Rajagopalan 		    EIB_FIP_QKEY, ret);
765*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
766*b494511aSVenki Rajagopalan 	}
767*b494511aSVenki Rajagopalan 
768*b494511aSVenki Rajagopalan 	/*
769*b494511aSVenki Rajagopalan 	 * Send the login packet to the destination gateway. Posting
770*b494511aSVenki Rajagopalan 	 * the login and setting the login state to wait-for-ack should
771*b494511aSVenki Rajagopalan 	 * ideally be atomic to avoid race.
772*b494511aSVenki Rajagopalan 	 */
773*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
774*b494511aSVenki Rajagopalan 	ret = ibt_post_send(chan->ch_chan, &(swqe->qe_wr.send), 1, NULL);
775*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
776*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
777*b494511aSVenki Rajagopalan 		*err = EINVAL;
778*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_login: "
779*b494511aSVenki Rajagopalan 		    "ibt_post_send() failed for vnic id 0x%x, ret=%d",
780*b494511aSVenki Rajagopalan 		    vnic->vn_id, ret);
781*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
782*b494511aSVenki Rajagopalan 	}
783*b494511aSVenki Rajagopalan 	vnic->vn_state = EIB_LOGIN_ACK_WAIT;
784*b494511aSVenki Rajagopalan 
785*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_tx_lock);
786*b494511aSVenki Rajagopalan 	chan->ch_tx_posted++;
787*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_tx_lock);
788*b494511aSVenki Rajagopalan 
789*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
790*b494511aSVenki Rajagopalan 
791*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
792*b494511aSVenki Rajagopalan }
793*b494511aSVenki Rajagopalan 
794*b494511aSVenki Rajagopalan static int
eib_fip_send_update(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,uint_t nxt_state,int * err)795*b494511aSVenki Rajagopalan eib_fip_send_update(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe,
796*b494511aSVenki Rajagopalan     uint_t nxt_state, int *err)
797*b494511aSVenki Rajagopalan {
798*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
799*b494511aSVenki Rajagopalan 	eib_chan_t *chan = vnic->vn_ctl_chan;
800*b494511aSVenki Rajagopalan 	eib_avect_t *av;
801*b494511aSVenki Rajagopalan 	ibt_status_t ret;
802*b494511aSVenki Rajagopalan 
803*b494511aSVenki Rajagopalan 	/*
804*b494511aSVenki Rajagopalan 	 * Get an address vector for this destination
805*b494511aSVenki Rajagopalan 	 */
806*b494511aSVenki Rajagopalan 	if ((av = eib_ibt_hold_avect(ss, ld->ld_gw_lid,
807*b494511aSVenki Rajagopalan 	    ld->ld_gw_sl)) == NULL) {
808*b494511aSVenki Rajagopalan 		*err = ENOMEM;
809*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_update: "
810*b494511aSVenki Rajagopalan 		    "eib_ibt_hold_avect(gw_lid=0x%x, sl=0x%x) failed",
811*b494511aSVenki Rajagopalan 		    ld->ld_gw_lid, ld->ld_gw_sl);
812*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
813*b494511aSVenki Rajagopalan 	}
814*b494511aSVenki Rajagopalan 
815*b494511aSVenki Rajagopalan 	/*
816*b494511aSVenki Rajagopalan 	 * Modify the UD destination handle to the destination appropriately
817*b494511aSVenki Rajagopalan 	 */
818*b494511aSVenki Rajagopalan 	ret = ibt_modify_ud_dest(swqe->qe_dest, EIB_FIP_QKEY,
819*b494511aSVenki Rajagopalan 	    ld->ld_gw_ctl_qpn, &av->av_vect);
820*b494511aSVenki Rajagopalan 
821*b494511aSVenki Rajagopalan 	eib_ibt_release_avect(ss, av);
822*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
823*b494511aSVenki Rajagopalan 		*err = EINVAL;
824*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_update: "
825*b494511aSVenki Rajagopalan 		    "ibt_modify_ud_dest(gw_ctl_qpn=0x%lx, qkey=0x%lx) failed, "
826*b494511aSVenki Rajagopalan 		    "ret=%d", ld->ld_gw_ctl_qpn, EIB_FIP_QKEY, ret);
827*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
828*b494511aSVenki Rajagopalan 	}
829*b494511aSVenki Rajagopalan 
830*b494511aSVenki Rajagopalan 	/*
831*b494511aSVenki Rajagopalan 	 * Send the update packet to the destination. Posting the update request
832*b494511aSVenki Rajagopalan 	 * and setting the login state to wait-for-vhub_table needs to be atomic
833*b494511aSVenki Rajagopalan 	 * to avoid race.
834*b494511aSVenki Rajagopalan 	 */
835*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
836*b494511aSVenki Rajagopalan 	ret = ibt_post_send(chan->ch_chan, &(swqe->qe_wr.send), 1, NULL);
837*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
838*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
839*b494511aSVenki Rajagopalan 		*err = EINVAL;
840*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_send_update: "
841*b494511aSVenki Rajagopalan 		    "ibt_post_send() failed for vnic id 0x%x, ret=%d",
842*b494511aSVenki Rajagopalan 		    vnic->vn_id, ret);
843*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
844*b494511aSVenki Rajagopalan 	}
845*b494511aSVenki Rajagopalan 	vnic->vn_state = nxt_state;
846*b494511aSVenki Rajagopalan 
847*b494511aSVenki Rajagopalan 	mutex_enter(&chan->ch_tx_lock);
848*b494511aSVenki Rajagopalan 	chan->ch_tx_posted++;
849*b494511aSVenki Rajagopalan 	mutex_exit(&chan->ch_tx_lock);
850*b494511aSVenki Rajagopalan 
851*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
852*b494511aSVenki Rajagopalan 
853*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
854*b494511aSVenki Rajagopalan }
855*b494511aSVenki Rajagopalan 
856*b494511aSVenki Rajagopalan static int
eib_fip_send_table(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)857*b494511aSVenki Rajagopalan eib_fip_send_table(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
858*b494511aSVenki Rajagopalan {
859*b494511aSVenki Rajagopalan 	return (eib_fip_send_update(ss, vnic, swqe, EIB_LOGIN_TBL_WAIT, err));
860*b494511aSVenki Rajagopalan }
861*b494511aSVenki Rajagopalan 
862*b494511aSVenki Rajagopalan static int
eib_fip_send_ka(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)863*b494511aSVenki Rajagopalan eib_fip_send_ka(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
864*b494511aSVenki Rajagopalan {
865*b494511aSVenki Rajagopalan 	return (eib_fip_send_update(ss, vnic, swqe, EIB_LOGIN_DONE, err));
866*b494511aSVenki Rajagopalan }
867*b494511aSVenki Rajagopalan 
868*b494511aSVenki Rajagopalan static int
eib_fip_send_logout(eib_t * ss,eib_vnic_t * vnic,eib_wqe_t * swqe,int * err)869*b494511aSVenki Rajagopalan eib_fip_send_logout(eib_t *ss, eib_vnic_t *vnic, eib_wqe_t *swqe, int *err)
870*b494511aSVenki Rajagopalan {
871*b494511aSVenki Rajagopalan 	return (eib_fip_send_update(ss, vnic, swqe, EIB_LOGOUT_DONE, err));
872*b494511aSVenki Rajagopalan }
873*b494511aSVenki Rajagopalan 
874*b494511aSVenki Rajagopalan static int
eib_fip_parse_vhub_table(uint8_t * pkt,eib_vnic_t * vnic)875*b494511aSVenki Rajagopalan eib_fip_parse_vhub_table(uint8_t *pkt, eib_vnic_t *vnic)
876*b494511aSVenki Rajagopalan {
877*b494511aSVenki Rajagopalan 	fip_vhub_table_t *tbl;
878*b494511aSVenki Rajagopalan 	fip_desc_vhub_table_t *desc_tbl;
879*b494511aSVenki Rajagopalan 	fip_vhub_table_entry_t *entry;
880*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
881*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
882*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
883*b494511aSVenki Rajagopalan 	eib_vhub_table_t *etbl = vnic->vn_vhub_table;
884*b494511aSVenki Rajagopalan 	eib_vhub_update_t *eupd = vnic->vn_vhub_update;
885*b494511aSVenki Rajagopalan 	eib_vhub_map_t *newmap;
886*b494511aSVenki Rajagopalan 
887*b494511aSVenki Rajagopalan 	uint32_t *ipkt;
888*b494511aSVenki Rajagopalan 	uint32_t init_checksum = 0;
889*b494511aSVenki Rajagopalan 	uint32_t tusn;
890*b494511aSVenki Rajagopalan 	uint32_t vhub_id;
891*b494511aSVenki Rajagopalan 	uint_t entries_in_pkt;
892*b494511aSVenki Rajagopalan 	uint_t ndx;
893*b494511aSVenki Rajagopalan 	uint_t i;
894*b494511aSVenki Rajagopalan 
895*b494511aSVenki Rajagopalan 	/*
896*b494511aSVenki Rajagopalan 	 * If we're here receiving vhub table messages, we certainly should
897*b494511aSVenki Rajagopalan 	 * have the vhub table structure allocated and present at this point.
898*b494511aSVenki Rajagopalan 	 */
899*b494511aSVenki Rajagopalan 	if (etbl == NULL) {
900*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
901*b494511aSVenki Rajagopalan 		    "vhub table missing for vnic id 0x%x", vnic->vn_id);
902*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
903*b494511aSVenki Rajagopalan 	}
904*b494511aSVenki Rajagopalan 
905*b494511aSVenki Rajagopalan 	/*
906*b494511aSVenki Rajagopalan 	 * Note that 'pkt' is always atleast double-word aligned when it is
907*b494511aSVenki Rajagopalan 	 * passed to us, so we can cast it without any problems.
908*b494511aSVenki Rajagopalan 	 */
909*b494511aSVenki Rajagopalan 	ipkt = (uint32_t *)(void *)pkt;
910*b494511aSVenki Rajagopalan 	tbl = (fip_vhub_table_t *)(void *)pkt;
911*b494511aSVenki Rajagopalan 	hdr = &(tbl->vt_fip_header);
912*b494511aSVenki Rajagopalan 
913*b494511aSVenki Rajagopalan 	/*
914*b494511aSVenki Rajagopalan 	 * Validate all the header and descriptor types and lengths
915*b494511aSVenki Rajagopalan 	 */
916*b494511aSVenki Rajagopalan 	if (hdr->hd_type != FIP_DESC_TYPE_VENDOR_ID ||
917*b494511aSVenki Rajagopalan 	    hdr->hd_len != FIP_DESC_LEN_VENDOR_ID) {
918*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
919*b494511aSVenki Rajagopalan 		    "invalid type/len in fip basic header, "
920*b494511aSVenki Rajagopalan 		    "exp (0x%x,0x%x), got (0x%x,0x%x)",
921*b494511aSVenki Rajagopalan 		    FIP_DESC_TYPE_VENDOR_ID, FIP_DESC_LEN_VENDOR_ID,
922*b494511aSVenki Rajagopalan 		    hdr->hd_type, hdr->hd_len);
923*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
924*b494511aSVenki Rajagopalan 	}
925*b494511aSVenki Rajagopalan 	desc_tbl = &(tbl->vt_vhub_table);
926*b494511aSVenki Rajagopalan 	if (desc_tbl->tb_type != FIP_DESC_TYPE_VHUB_TABLE) {
927*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
928*b494511aSVenki Rajagopalan 		    "invalid type in vhub desc, exp 0x%x, got 0x%x",
929*b494511aSVenki Rajagopalan 		    FIP_DESC_TYPE_VHUB_TABLE, desc_tbl->tb_type);
930*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
931*b494511aSVenki Rajagopalan 	}
932*b494511aSVenki Rajagopalan 
933*b494511aSVenki Rajagopalan 	/*
934*b494511aSVenki Rajagopalan 	 * Verify that the vhub id is ok for this vnic
935*b494511aSVenki Rajagopalan 	 */
936*b494511aSVenki Rajagopalan 	vhub_id = ntohl(desc_tbl->tb_flags_vhub_id) & FIP_TB_VHUB_ID_MASK;
937*b494511aSVenki Rajagopalan 	if (vhub_id != ld->ld_vhub_id) {
938*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
939*b494511aSVenki Rajagopalan 		    "invalid vhub id in vhub table pkt: exp 0x%x, got 0x%x",
940*b494511aSVenki Rajagopalan 		    ld->ld_vhub_id, vhub_id);
941*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
942*b494511aSVenki Rajagopalan 	}
943*b494511aSVenki Rajagopalan 
944*b494511aSVenki Rajagopalan 	/*
945*b494511aSVenki Rajagopalan 	 * Count the number of vhub table entries in this packet
946*b494511aSVenki Rajagopalan 	 */
947*b494511aSVenki Rajagopalan 	entries_in_pkt = (desc_tbl->tb_len - FIP_DESC_VHUB_TABLE_WORDS) /
948*b494511aSVenki Rajagopalan 	    FIP_VHUB_TABLE_ENTRY_WORDS;
949*b494511aSVenki Rajagopalan 
950*b494511aSVenki Rajagopalan 	/*
951*b494511aSVenki Rajagopalan 	 * While we're here, also compute the 32-bit 2's complement carry-
952*b494511aSVenki Rajagopalan 	 * discarded checksum of the vHUB table descriptor in this packet
953*b494511aSVenki Rajagopalan 	 * till the first vhub table entry.
954*b494511aSVenki Rajagopalan 	 */
955*b494511aSVenki Rajagopalan 	for (i = 0; i < FIP_DESC_VHUB_TABLE_WORDS; i++)
956*b494511aSVenki Rajagopalan 		init_checksum += ipkt[i];
957*b494511aSVenki Rajagopalan 
958*b494511aSVenki Rajagopalan 	/*
959*b494511aSVenki Rajagopalan 	 * Initialize the vhub's Table Update Sequence Number (tusn),
960*b494511aSVenki Rajagopalan 	 * checksum and record the total number of entries in in the table
961*b494511aSVenki Rajagopalan 	 * if this is the first pkt of the table.
962*b494511aSVenki Rajagopalan 	 */
963*b494511aSVenki Rajagopalan 	tusn = ntohl(desc_tbl->tb_tusn);
964*b494511aSVenki Rajagopalan 	if (desc_tbl->tb_hdr & FIP_TB_HDR_FIRST) {
965*b494511aSVenki Rajagopalan 		etbl->tb_entries_in_table = ntohs(desc_tbl->tb_table_size);
966*b494511aSVenki Rajagopalan 		etbl->tb_tusn = tusn;
967*b494511aSVenki Rajagopalan 		etbl->tb_checksum = 0;
968*b494511aSVenki Rajagopalan 
969*b494511aSVenki Rajagopalan 		mutex_enter(&vnic->vn_lock);
970*b494511aSVenki Rajagopalan 		vnic->vn_state = EIB_LOGIN_TBL_INPROG;
971*b494511aSVenki Rajagopalan 		mutex_exit(&vnic->vn_lock);
972*b494511aSVenki Rajagopalan 	}
973*b494511aSVenki Rajagopalan 
974*b494511aSVenki Rajagopalan 	/*
975*b494511aSVenki Rajagopalan 	 * First, middle or last, the current table TUSN we have must match this
976*b494511aSVenki Rajagopalan 	 * packet's TUSN.
977*b494511aSVenki Rajagopalan 	 */
978*b494511aSVenki Rajagopalan 	if (etbl->tb_tusn != tusn) {
979*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
980*b494511aSVenki Rajagopalan 		    "unexpected TUSN (0x%lx) during vhub table construction, "
981*b494511aSVenki Rajagopalan 		    "expected 0x%lx", etbl->tb_tusn, tusn);
982*b494511aSVenki Rajagopalan 		goto vhub_table_fail;
983*b494511aSVenki Rajagopalan 	}
984*b494511aSVenki Rajagopalan 
985*b494511aSVenki Rajagopalan 	/*
986*b494511aSVenki Rajagopalan 	 * See if we've overrun/underrun our original entries count
987*b494511aSVenki Rajagopalan 	 */
988*b494511aSVenki Rajagopalan 	if ((etbl->tb_entries_seen + entries_in_pkt) >
989*b494511aSVenki Rajagopalan 	    etbl->tb_entries_in_table) {
990*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
991*b494511aSVenki Rajagopalan 		    "vhub table overrun, total_exp=%d, so_far=%d, this_pkt=%d",
992*b494511aSVenki Rajagopalan 		    etbl->tb_entries_in_table, etbl->tb_entries_seen,
993*b494511aSVenki Rajagopalan 		    entries_in_pkt);
994*b494511aSVenki Rajagopalan 		goto vhub_table_fail;
995*b494511aSVenki Rajagopalan 	} else if (((etbl->tb_entries_seen + entries_in_pkt) <
996*b494511aSVenki Rajagopalan 	    etbl->tb_entries_in_table) &&
997*b494511aSVenki Rajagopalan 	    (desc_tbl->tb_hdr & FIP_TB_HDR_LAST)) {
998*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_table: "
999*b494511aSVenki Rajagopalan 		    "vhub table underrun, total_exp=%d, so_far=%d, last_pkt=%d",
1000*b494511aSVenki Rajagopalan 		    etbl->tb_entries_in_table, etbl->tb_entries_seen,
1001*b494511aSVenki Rajagopalan 		    entries_in_pkt);
1002*b494511aSVenki Rajagopalan 		goto vhub_table_fail;
1003*b494511aSVenki Rajagopalan 	}
1004*b494511aSVenki Rajagopalan 
1005*b494511aSVenki Rajagopalan 	/*
1006*b494511aSVenki Rajagopalan 	 * Process and add the entries we have in this packet
1007*b494511aSVenki Rajagopalan 	 */
1008*b494511aSVenki Rajagopalan 	etbl->tb_checksum += init_checksum;
1009*b494511aSVenki Rajagopalan 	entry = (fip_vhub_table_entry_t *)(void *)
1010*b494511aSVenki Rajagopalan 	    ((uint8_t *)desc_tbl + FIP_DESC_VHUB_TABLE_SZ);
1011*b494511aSVenki Rajagopalan 
1012*b494511aSVenki Rajagopalan 	for (ndx = 0; ndx < entries_in_pkt; ndx++, entry++) {
1013*b494511aSVenki Rajagopalan 		/*
1014*b494511aSVenki Rajagopalan 		 * Allocate a eib_vhub_map_t, copy the current entry details
1015*b494511aSVenki Rajagopalan 		 * and chain it to the appropriate queue.
1016*b494511aSVenki Rajagopalan 		 */
1017*b494511aSVenki Rajagopalan 		if ((newmap = eib_fip_get_vhub_map()) == NULL) {
1018*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1019*b494511aSVenki Rajagopalan 			    "eib_fip_parse_vhub_table: no memory for vhub "
1020*b494511aSVenki Rajagopalan 			    "table entry, ignoring this vhub table packet");
1021*b494511aSVenki Rajagopalan 			goto vhub_table_fail;
1022*b494511aSVenki Rajagopalan 		}
1023*b494511aSVenki Rajagopalan 
1024*b494511aSVenki Rajagopalan 		ASSERT((entry->te_v_rss_type & FIP_TE_VALID) == FIP_TE_VALID);
1025*b494511aSVenki Rajagopalan 		newmap->mp_v_rss_type = entry->te_v_rss_type;
1026*b494511aSVenki Rajagopalan 		bcopy(entry->te_mac, newmap->mp_mac, ETHERADDRL);
1027*b494511aSVenki Rajagopalan 		newmap->mp_qpn = (ntohl(entry->te_qpn) & FIP_TE_QPN_MASK);
1028*b494511aSVenki Rajagopalan 		newmap->mp_sl = (entry->te_sl & FIP_TE_SL_MASK);
1029*b494511aSVenki Rajagopalan 		newmap->mp_lid = ntohs(entry->te_lid);
1030*b494511aSVenki Rajagopalan 		newmap->mp_tusn = tusn;
1031*b494511aSVenki Rajagopalan 		newmap->mp_next = NULL;
1032*b494511aSVenki Rajagopalan 
1033*b494511aSVenki Rajagopalan 		/*
1034*b494511aSVenki Rajagopalan 		 * The vhub table messages do not provide status on eport
1035*b494511aSVenki Rajagopalan 		 * state, so we'll simply assume that the eport is up.
1036*b494511aSVenki Rajagopalan 		 */
1037*b494511aSVenki Rajagopalan 		eib_fip_queue_tbl_entry(etbl, newmap, tusn, FIP_EPORT_UP);
1038*b494511aSVenki Rajagopalan 
1039*b494511aSVenki Rajagopalan 		/*
1040*b494511aSVenki Rajagopalan 		 * Update table checksum with this entry's computed checksum
1041*b494511aSVenki Rajagopalan 		 */
1042*b494511aSVenki Rajagopalan 		ipkt = (uint32_t *)entry;
1043*b494511aSVenki Rajagopalan 		for (i = 0; i < FIP_VHUB_TABLE_ENTRY_WORDS; i++)
1044*b494511aSVenki Rajagopalan 			etbl->tb_checksum += ipkt[i];
1045*b494511aSVenki Rajagopalan 	}
1046*b494511aSVenki Rajagopalan 	etbl->tb_entries_seen += entries_in_pkt;
1047*b494511aSVenki Rajagopalan 
1048*b494511aSVenki Rajagopalan 	/*
1049*b494511aSVenki Rajagopalan 	 * If this is the last packet of this vhub table, complete vhub
1050*b494511aSVenki Rajagopalan 	 * table by verifying checksum and applying all the vhub updates
1051*b494511aSVenki Rajagopalan 	 * that may have come in while we were constructing this table.
1052*b494511aSVenki Rajagopalan 	 */
1053*b494511aSVenki Rajagopalan 	if (desc_tbl->tb_hdr & FIP_TB_HDR_LAST) {
1054*b494511aSVenki Rajagopalan 
1055*b494511aSVenki Rajagopalan 		ipkt = (uint32_t *)entry;
1056*b494511aSVenki Rajagopalan 		if (!eib_wa_no_good_vhub_cksum) {
1057*b494511aSVenki Rajagopalan 			if (*ipkt != etbl->tb_checksum) {
1058*b494511aSVenki Rajagopalan 				EIB_DPRINTF_VERBOSE(ss->ei_instance,
1059*b494511aSVenki Rajagopalan 				    "eib_fip_parse_vhub_table: "
1060*b494511aSVenki Rajagopalan 				    "vhub table checksum invalid, "
1061*b494511aSVenki Rajagopalan 				    "computed=0x%lx, found=0x%lx",
1062*b494511aSVenki Rajagopalan 				    etbl->tb_checksum, *ipkt);
1063*b494511aSVenki Rajagopalan 			}
1064*b494511aSVenki Rajagopalan 		}
1065*b494511aSVenki Rajagopalan 
1066*b494511aSVenki Rajagopalan 		/*
1067*b494511aSVenki Rajagopalan 		 * Per the EoIB specification, the gateway is supposed to
1068*b494511aSVenki Rajagopalan 		 * include its address information for data messages in the
1069*b494511aSVenki Rajagopalan 		 * vhub table.  But we've observed that it doesn't do this
1070*b494511aSVenki Rajagopalan 		 * (with the current version). If this is the case, we'll
1071*b494511aSVenki Rajagopalan 		 * hand-create and add a vhub map for the gateway from the
1072*b494511aSVenki Rajagopalan 		 * information we got in login ack.
1073*b494511aSVenki Rajagopalan 		 */
1074*b494511aSVenki Rajagopalan 		if (etbl->tb_gateway == NULL)
1075*b494511aSVenki Rajagopalan 			eib_fip_queue_gw_entry(vnic, etbl, tusn, FIP_EPORT_UP);
1076*b494511aSVenki Rajagopalan 
1077*b494511aSVenki Rajagopalan 		/*
1078*b494511aSVenki Rajagopalan 		 * Apply pending vhub updates and reset table counters needed
1079*b494511aSVenki Rajagopalan 		 * during table construction.
1080*b494511aSVenki Rajagopalan 		 */
1081*b494511aSVenki Rajagopalan 		if (eib_fip_apply_updates(ss, etbl, eupd) != EIB_E_SUCCESS)
1082*b494511aSVenki Rajagopalan 			goto vhub_table_fail;
1083*b494511aSVenki Rajagopalan 
1084*b494511aSVenki Rajagopalan 		etbl->tb_entries_seen = 0;
1085*b494511aSVenki Rajagopalan 		etbl->tb_entries_in_table = 0;
1086*b494511aSVenki Rajagopalan 
1087*b494511aSVenki Rajagopalan 		eib_vnic_vhub_table_done(vnic, EIB_LOGIN_TBL_DONE);
1088*b494511aSVenki Rajagopalan 	}
1089*b494511aSVenki Rajagopalan 
1090*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1091*b494511aSVenki Rajagopalan 
1092*b494511aSVenki Rajagopalan vhub_table_fail:
1093*b494511aSVenki Rajagopalan 	eib_vnic_vhub_table_done(vnic, EIB_LOGIN_TBL_FAILED);
1094*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
1095*b494511aSVenki Rajagopalan }
1096*b494511aSVenki Rajagopalan 
1097*b494511aSVenki Rajagopalan static int
eib_fip_parse_vhub_update(uint8_t * pkt,eib_vnic_t * vnic)1098*b494511aSVenki Rajagopalan eib_fip_parse_vhub_update(uint8_t *pkt, eib_vnic_t *vnic)
1099*b494511aSVenki Rajagopalan {
1100*b494511aSVenki Rajagopalan 	fip_vhub_update_t *upd;
1101*b494511aSVenki Rajagopalan 	fip_desc_vhub_update_t *desc_upd;
1102*b494511aSVenki Rajagopalan 	fip_vhub_table_entry_t *entry;
1103*b494511aSVenki Rajagopalan 	fip_basic_hdr_t *hdr;
1104*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
1105*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
1106*b494511aSVenki Rajagopalan 	eib_vhub_table_t *etbl = vnic->vn_vhub_table;
1107*b494511aSVenki Rajagopalan 	eib_vhub_update_t *eupd = vnic->vn_vhub_update;
1108*b494511aSVenki Rajagopalan 	eib_vhub_map_t *newmap;
1109*b494511aSVenki Rajagopalan 	boolean_t vhub_tbl_done;
1110*b494511aSVenki Rajagopalan 	uint32_t eport_vp_vhub_id;
1111*b494511aSVenki Rajagopalan 	uint32_t vhub_id;
1112*b494511aSVenki Rajagopalan 	uint32_t tusn;
1113*b494511aSVenki Rajagopalan 	uint32_t prev_tusn;
1114*b494511aSVenki Rajagopalan 	uint8_t eport_state;
1115*b494511aSVenki Rajagopalan 
1116*b494511aSVenki Rajagopalan 	/*
1117*b494511aSVenki Rajagopalan 	 * We should have the vhub table allocated as long as we're receiving
1118*b494511aSVenki Rajagopalan 	 * vhub control messages.
1119*b494511aSVenki Rajagopalan 	 */
1120*b494511aSVenki Rajagopalan 	if (etbl == NULL) {
1121*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_update: "
1122*b494511aSVenki Rajagopalan 		    "vhub table missing for vnic id 0x%x", vnic->vn_id);
1123*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1124*b494511aSVenki Rajagopalan 	}
1125*b494511aSVenki Rajagopalan 
1126*b494511aSVenki Rajagopalan 	mutex_enter(&vnic->vn_lock);
1127*b494511aSVenki Rajagopalan 	vhub_tbl_done = ((vnic->vn_state == EIB_LOGIN_TBL_DONE) ||
1128*b494511aSVenki Rajagopalan 	    (vnic->vn_state == EIB_LOGIN_DONE)) ? B_TRUE : B_FALSE;
1129*b494511aSVenki Rajagopalan 	mutex_exit(&vnic->vn_lock);
1130*b494511aSVenki Rajagopalan 
1131*b494511aSVenki Rajagopalan 	/*
1132*b494511aSVenki Rajagopalan 	 * Note that 'pkt' is always atleast double-word aligned when it is
1133*b494511aSVenki Rajagopalan 	 * passed to us, so we can cast it without any problems.
1134*b494511aSVenki Rajagopalan 	 */
1135*b494511aSVenki Rajagopalan 	upd = (fip_vhub_update_t *)(void *)pkt;
1136*b494511aSVenki Rajagopalan 	hdr = &(upd->vu_fip_header);
1137*b494511aSVenki Rajagopalan 
1138*b494511aSVenki Rajagopalan 	/*
1139*b494511aSVenki Rajagopalan 	 * Validate all the header and descriptor types and lengths
1140*b494511aSVenki Rajagopalan 	 */
1141*b494511aSVenki Rajagopalan 	if (hdr->hd_type != FIP_DESC_TYPE_VENDOR_ID ||
1142*b494511aSVenki Rajagopalan 	    hdr->hd_len != FIP_DESC_LEN_VENDOR_ID) {
1143*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_update: "
1144*b494511aSVenki Rajagopalan 		    "invalid type/len in fip basic header, "
1145*b494511aSVenki Rajagopalan 		    "exp (0x%x,0x%x), got (0x%x,0x%x)",
1146*b494511aSVenki Rajagopalan 		    FIP_DESC_TYPE_VENDOR_ID, FIP_DESC_LEN_VENDOR_ID,
1147*b494511aSVenki Rajagopalan 		    hdr->hd_type, hdr->hd_len);
1148*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1149*b494511aSVenki Rajagopalan 	}
1150*b494511aSVenki Rajagopalan 	desc_upd = &(upd->vu_vhub_update);
1151*b494511aSVenki Rajagopalan 	if (desc_upd->up_type != FIP_DESC_TYPE_VHUB_UPDATE ||
1152*b494511aSVenki Rajagopalan 	    desc_upd->up_len != FIP_DESC_LEN_VHUB_UPDATE) {
1153*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_update: "
1154*b494511aSVenki Rajagopalan 		    "invalid type/len in vhub update desc: "
1155*b494511aSVenki Rajagopalan 		    "exp (0x%x,0x%x), got (0x%x,0x%x)",
1156*b494511aSVenki Rajagopalan 		    FIP_DESC_TYPE_VHUB_UPDATE, FIP_DESC_LEN_VHUB_UPDATE,
1157*b494511aSVenki Rajagopalan 		    desc_upd->up_type, desc_upd->up_len);
1158*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1159*b494511aSVenki Rajagopalan 	}
1160*b494511aSVenki Rajagopalan 
1161*b494511aSVenki Rajagopalan 	/*
1162*b494511aSVenki Rajagopalan 	 * Verify that the vhub id is ok for this vnic and save the eport state
1163*b494511aSVenki Rajagopalan 	 */
1164*b494511aSVenki Rajagopalan 	eport_vp_vhub_id = ntohl(desc_upd->up_eport_vp_vhub_id);
1165*b494511aSVenki Rajagopalan 
1166*b494511aSVenki Rajagopalan 	vhub_id = eport_vp_vhub_id & FIP_UP_VHUB_ID_MASK;
1167*b494511aSVenki Rajagopalan 	if (vhub_id != ld->ld_vhub_id) {
1168*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_update: "
1169*b494511aSVenki Rajagopalan 		    "invalid vhub id in vhub update pkt: exp 0x%x, got 0x%x",
1170*b494511aSVenki Rajagopalan 		    ld->ld_vhub_id, vhub_id);
1171*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1172*b494511aSVenki Rajagopalan 	}
1173*b494511aSVenki Rajagopalan 	eport_state = (uint8_t)((eport_vp_vhub_id >> FIP_UP_EPORT_STATE_SHIFT) &
1174*b494511aSVenki Rajagopalan 	    FIP_UP_EPORT_STATE_MASK);
1175*b494511aSVenki Rajagopalan 
1176*b494511aSVenki Rajagopalan 	/*
1177*b494511aSVenki Rajagopalan 	 * If this is the first update we receive, any tusn is ok.  Otherwise,
1178*b494511aSVenki Rajagopalan 	 * make sure the tusn we see in the packet is appropriate.
1179*b494511aSVenki Rajagopalan 	 */
1180*b494511aSVenki Rajagopalan 	tusn = ntohl(desc_upd->up_tusn);
1181*b494511aSVenki Rajagopalan 	prev_tusn = vhub_tbl_done ? etbl->tb_tusn : eupd->up_tusn;
1182*b494511aSVenki Rajagopalan 
1183*b494511aSVenki Rajagopalan 	if (prev_tusn != 0) {
1184*b494511aSVenki Rajagopalan 		if (tusn == prev_tusn) {
1185*b494511aSVenki Rajagopalan 			eib_fip_update_eport_state(ss, etbl, eupd,
1186*b494511aSVenki Rajagopalan 			    vhub_tbl_done, eport_state);
1187*b494511aSVenki Rajagopalan 			return (EIB_E_SUCCESS);
1188*b494511aSVenki Rajagopalan 		}
1189*b494511aSVenki Rajagopalan 		if (tusn != (prev_tusn + 1)) {
1190*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1191*b494511aSVenki Rajagopalan 			    "eib_fip_parse_vhub_update: "
1192*b494511aSVenki Rajagopalan 			    "out of order TUSN received (exp 0x%lx, "
1193*b494511aSVenki Rajagopalan 			    "got 0x%lx), dropping pkt", prev_tusn + 1, tusn);
1194*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
1195*b494511aSVenki Rajagopalan 		}
1196*b494511aSVenki Rajagopalan 	}
1197*b494511aSVenki Rajagopalan 
1198*b494511aSVenki Rajagopalan 	/*
1199*b494511aSVenki Rajagopalan 	 * EoIB expects only type 0 (vnic address) entries to maintain the
1200*b494511aSVenki Rajagopalan 	 * context table
1201*b494511aSVenki Rajagopalan 	 */
1202*b494511aSVenki Rajagopalan 	entry = &(desc_upd->up_tbl_entry);
1203*b494511aSVenki Rajagopalan 	ASSERT((entry->te_v_rss_type & FIP_TE_TYPE_MASK) == FIP_TE_TYPE_VNIC);
1204*b494511aSVenki Rajagopalan 
1205*b494511aSVenki Rajagopalan 	/*
1206*b494511aSVenki Rajagopalan 	 * If the vHUB table has already been fully constructed and if we've
1207*b494511aSVenki Rajagopalan 	 * now received a notice to remove a vnic entry from it, do it.
1208*b494511aSVenki Rajagopalan 	 */
1209*b494511aSVenki Rajagopalan 	if ((vhub_tbl_done) &&
1210*b494511aSVenki Rajagopalan 	    ((entry->te_v_rss_type & FIP_TE_VALID) == 0)) {
1211*b494511aSVenki Rajagopalan 		eib_fip_dequeue_tbl_entry(etbl, entry->te_mac,
1212*b494511aSVenki Rajagopalan 		    tusn, eport_state);
1213*b494511aSVenki Rajagopalan 
1214*b494511aSVenki Rajagopalan 		if (bcmp(entry->te_mac, ld->ld_assigned_mac, ETHERADDRL) == 0) {
1215*b494511aSVenki Rajagopalan 			uint8_t *mymac;
1216*b494511aSVenki Rajagopalan 
1217*b494511aSVenki Rajagopalan 			mymac = entry->te_mac;
1218*b494511aSVenki Rajagopalan 			EIB_DPRINTF_WARN(ss->ei_instance,
1219*b494511aSVenki Rajagopalan 			    "eib_fip_parse_vhub_update: "
1220*b494511aSVenki Rajagopalan 			    "vhub update pkt received to kill self "
1221*b494511aSVenki Rajagopalan 			    "(%x:%x:%x:%x:%x:%x)", mymac[0], mymac[1], mymac[2],
1222*b494511aSVenki Rajagopalan 			    mymac[3], mymac[4], mymac[5]);
1223*b494511aSVenki Rajagopalan 
1224*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
1225*b494511aSVenki Rajagopalan 		}
1226*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
1227*b494511aSVenki Rajagopalan 	}
1228*b494511aSVenki Rajagopalan 
1229*b494511aSVenki Rajagopalan 	/*
1230*b494511aSVenki Rajagopalan 	 * Otherwise, allocate a new eib_vhub_map_t and fill it in with
1231*b494511aSVenki Rajagopalan 	 * the details of the new entry
1232*b494511aSVenki Rajagopalan 	 */
1233*b494511aSVenki Rajagopalan 	if ((newmap = eib_fip_get_vhub_map()) == NULL) {
1234*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_parse_vhub_update: "
1235*b494511aSVenki Rajagopalan 		    "no memory for vhub update entry, will be ignoring"
1236*b494511aSVenki Rajagopalan 		    "this vhub update packet");
1237*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1238*b494511aSVenki Rajagopalan 	}
1239*b494511aSVenki Rajagopalan 
1240*b494511aSVenki Rajagopalan 	newmap->mp_v_rss_type = entry->te_v_rss_type;
1241*b494511aSVenki Rajagopalan 	bcopy(entry->te_mac, newmap->mp_mac, ETHERADDRL);
1242*b494511aSVenki Rajagopalan 	newmap->mp_qpn = (ntohl(entry->te_qpn) & FIP_TE_QPN_MASK);
1243*b494511aSVenki Rajagopalan 	newmap->mp_sl = (entry->te_sl & FIP_TE_SL_MASK);
1244*b494511aSVenki Rajagopalan 	newmap->mp_lid = ntohs(entry->te_lid);
1245*b494511aSVenki Rajagopalan 	newmap->mp_tusn = tusn;
1246*b494511aSVenki Rajagopalan 	newmap->mp_next = NULL;
1247*b494511aSVenki Rajagopalan 
1248*b494511aSVenki Rajagopalan 	/*
1249*b494511aSVenki Rajagopalan 	 * Update the full vhub table or chain it to the list of pending
1250*b494511aSVenki Rajagopalan 	 * updates depending on if the vhub table construction is over
1251*b494511aSVenki Rajagopalan 	 * or not.
1252*b494511aSVenki Rajagopalan 	 */
1253*b494511aSVenki Rajagopalan 	if (vhub_tbl_done) {
1254*b494511aSVenki Rajagopalan 		eib_fip_queue_tbl_entry(etbl, newmap, tusn, eport_state);
1255*b494511aSVenki Rajagopalan 	} else {
1256*b494511aSVenki Rajagopalan 		eib_fip_queue_upd_entry(eupd, newmap, tusn, eport_state);
1257*b494511aSVenki Rajagopalan 	}
1258*b494511aSVenki Rajagopalan 
1259*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1260*b494511aSVenki Rajagopalan }
1261*b494511aSVenki Rajagopalan 
1262*b494511aSVenki Rajagopalan static void
eib_fip_update_eport_state(eib_t * ss,eib_vhub_table_t * tbl,eib_vhub_update_t * upd,boolean_t tbl_done,uint8_t eport_state)1263*b494511aSVenki Rajagopalan eib_fip_update_eport_state(eib_t *ss, eib_vhub_table_t *tbl,
1264*b494511aSVenki Rajagopalan     eib_vhub_update_t *upd, boolean_t tbl_done, uint8_t eport_state)
1265*b494511aSVenki Rajagopalan {
1266*b494511aSVenki Rajagopalan 	if (tbl_done) {
1267*b494511aSVenki Rajagopalan 		mutex_enter(&tbl->tb_lock);
1268*b494511aSVenki Rajagopalan 		if (tbl->tb_eport_state != eport_state) {
1269*b494511aSVenki Rajagopalan 			EIB_DPRINTF_DEBUG(ss->ei_instance,
1270*b494511aSVenki Rajagopalan 			    "eib_fip_update_eport_state: "
1271*b494511aSVenki Rajagopalan 			    "eport state changing from %d to %d",
1272*b494511aSVenki Rajagopalan 			    tbl->tb_eport_state, eport_state);
1273*b494511aSVenki Rajagopalan 			tbl->tb_eport_state = eport_state;
1274*b494511aSVenki Rajagopalan 		}
1275*b494511aSVenki Rajagopalan 		mutex_exit(&tbl->tb_lock);
1276*b494511aSVenki Rajagopalan 	} else {
1277*b494511aSVenki Rajagopalan 		mutex_enter(&upd->up_lock);
1278*b494511aSVenki Rajagopalan 		if (upd->up_eport_state != eport_state) {
1279*b494511aSVenki Rajagopalan 			EIB_DPRINTF_DEBUG(ss->ei_instance,
1280*b494511aSVenki Rajagopalan 			    "eib_fip_update_eport_state: "
1281*b494511aSVenki Rajagopalan 			    "eport state changing from %d to %d",
1282*b494511aSVenki Rajagopalan 			    upd->up_eport_state, eport_state);
1283*b494511aSVenki Rajagopalan 			upd->up_eport_state = eport_state;
1284*b494511aSVenki Rajagopalan 		}
1285*b494511aSVenki Rajagopalan 		mutex_exit(&upd->up_lock);
1286*b494511aSVenki Rajagopalan 	}
1287*b494511aSVenki Rajagopalan }
1288*b494511aSVenki Rajagopalan 
1289*b494511aSVenki Rajagopalan static void
eib_fip_queue_tbl_entry(eib_vhub_table_t * tbl,eib_vhub_map_t * map,uint32_t tusn,uint8_t eport_state)1290*b494511aSVenki Rajagopalan eib_fip_queue_tbl_entry(eib_vhub_table_t *tbl, eib_vhub_map_t *map,
1291*b494511aSVenki Rajagopalan     uint32_t tusn, uint8_t eport_state)
1292*b494511aSVenki Rajagopalan {
1293*b494511aSVenki Rajagopalan 	uint8_t bkt;
1294*b494511aSVenki Rajagopalan 
1295*b494511aSVenki Rajagopalan 	mutex_enter(&tbl->tb_lock);
1296*b494511aSVenki Rajagopalan 
1297*b494511aSVenki Rajagopalan 	switch (map->mp_v_rss_type & FIP_TE_TYPE_MASK) {
1298*b494511aSVenki Rajagopalan 	case FIP_TE_TYPE_GATEWAY:
1299*b494511aSVenki Rajagopalan 		if (tbl->tb_gateway) {
1300*b494511aSVenki Rajagopalan 			kmem_free(tbl->tb_gateway,
1301*b494511aSVenki Rajagopalan 			    sizeof (eib_vhub_map_t));
1302*b494511aSVenki Rajagopalan 		}
1303*b494511aSVenki Rajagopalan 		tbl->tb_gateway = map;
1304*b494511aSVenki Rajagopalan 		break;
1305*b494511aSVenki Rajagopalan 
1306*b494511aSVenki Rajagopalan 	case FIP_TE_TYPE_UNICAST_MISS:
1307*b494511aSVenki Rajagopalan 		if (tbl->tb_unicast_miss) {
1308*b494511aSVenki Rajagopalan 			kmem_free(tbl->tb_unicast_miss,
1309*b494511aSVenki Rajagopalan 			    sizeof (eib_vhub_map_t));
1310*b494511aSVenki Rajagopalan 		}
1311*b494511aSVenki Rajagopalan 		tbl->tb_unicast_miss = map;
1312*b494511aSVenki Rajagopalan 		break;
1313*b494511aSVenki Rajagopalan 
1314*b494511aSVenki Rajagopalan 	case FIP_TE_TYPE_VHUB_MULTICAST:
1315*b494511aSVenki Rajagopalan 		if (tbl->tb_vhub_multicast) {
1316*b494511aSVenki Rajagopalan 			kmem_free(tbl->tb_vhub_multicast,
1317*b494511aSVenki Rajagopalan 			    sizeof (eib_vhub_map_t));
1318*b494511aSVenki Rajagopalan 		}
1319*b494511aSVenki Rajagopalan 		tbl->tb_vhub_multicast = map;
1320*b494511aSVenki Rajagopalan 		break;
1321*b494511aSVenki Rajagopalan 
1322*b494511aSVenki Rajagopalan 	case FIP_TE_TYPE_MULTICAST_ENTRY:
1323*b494511aSVenki Rajagopalan 		/*
1324*b494511aSVenki Rajagopalan 		 * If multicast entry types are not to be specially
1325*b494511aSVenki Rajagopalan 		 * processed, treat them like regular vnic addresses.
1326*b494511aSVenki Rajagopalan 		 */
1327*b494511aSVenki Rajagopalan 		if (!eib_wa_no_mcast_entries) {
1328*b494511aSVenki Rajagopalan 			bkt = (map->mp_mac[ETHERADDRL-1]) % EIB_TB_NBUCKETS;
1329*b494511aSVenki Rajagopalan 			map->mp_next = tbl->tb_mcast_entry[bkt];
1330*b494511aSVenki Rajagopalan 			tbl->tb_mcast_entry[bkt] = map;
1331*b494511aSVenki Rajagopalan 			break;
1332*b494511aSVenki Rajagopalan 		}
1333*b494511aSVenki Rajagopalan 		/*FALLTHROUGH*/
1334*b494511aSVenki Rajagopalan 
1335*b494511aSVenki Rajagopalan 	case FIP_TE_TYPE_VNIC:
1336*b494511aSVenki Rajagopalan 		bkt = (map->mp_mac[ETHERADDRL-1]) % EIB_TB_NBUCKETS;
1337*b494511aSVenki Rajagopalan 		map->mp_next = tbl->tb_vnic_entry[bkt];
1338*b494511aSVenki Rajagopalan 		tbl->tb_vnic_entry[bkt] = map;
1339*b494511aSVenki Rajagopalan 		break;
1340*b494511aSVenki Rajagopalan 	}
1341*b494511aSVenki Rajagopalan 
1342*b494511aSVenki Rajagopalan 	tbl->tb_tusn = tusn;
1343*b494511aSVenki Rajagopalan 	tbl->tb_eport_state = eport_state;
1344*b494511aSVenki Rajagopalan 
1345*b494511aSVenki Rajagopalan 	mutex_exit(&tbl->tb_lock);
1346*b494511aSVenki Rajagopalan }
1347*b494511aSVenki Rajagopalan 
1348*b494511aSVenki Rajagopalan static void
eib_fip_queue_upd_entry(eib_vhub_update_t * upd,eib_vhub_map_t * map,uint32_t tusn,uint8_t eport_state)1349*b494511aSVenki Rajagopalan eib_fip_queue_upd_entry(eib_vhub_update_t *upd, eib_vhub_map_t *map,
1350*b494511aSVenki Rajagopalan     uint32_t tusn, uint8_t eport_state)
1351*b494511aSVenki Rajagopalan {
1352*b494511aSVenki Rajagopalan 	eib_vhub_map_t *tail;
1353*b494511aSVenki Rajagopalan 
1354*b494511aSVenki Rajagopalan 	/*
1355*b494511aSVenki Rajagopalan 	 * The eib_vhub_update_t list is only touched/traversed when the
1356*b494511aSVenki Rajagopalan 	 * control cq handler is parsing either update or table message,
1357*b494511aSVenki Rajagopalan 	 * or by the table cleanup routine when we aren't attached to any
1358*b494511aSVenki Rajagopalan 	 * control mcgs.  Bottom line is that this list traversal is always
1359*b494511aSVenki Rajagopalan 	 * single-threaded and we could probably do away with the lock.
1360*b494511aSVenki Rajagopalan 	 */
1361*b494511aSVenki Rajagopalan 	mutex_enter(&upd->up_lock);
1362*b494511aSVenki Rajagopalan 	for (tail = upd->up_vnic_entry;  tail != NULL; tail = tail->mp_next) {
1363*b494511aSVenki Rajagopalan 		if (tail->mp_next == NULL)
1364*b494511aSVenki Rajagopalan 			break;
1365*b494511aSVenki Rajagopalan 	}
1366*b494511aSVenki Rajagopalan 	if (tail) {
1367*b494511aSVenki Rajagopalan 		tail->mp_next = map;
1368*b494511aSVenki Rajagopalan 	} else {
1369*b494511aSVenki Rajagopalan 		upd->up_vnic_entry = map;
1370*b494511aSVenki Rajagopalan 	}
1371*b494511aSVenki Rajagopalan 
1372*b494511aSVenki Rajagopalan 	upd->up_tusn = tusn;
1373*b494511aSVenki Rajagopalan 	upd->up_eport_state = eport_state;
1374*b494511aSVenki Rajagopalan 
1375*b494511aSVenki Rajagopalan 	mutex_exit(&upd->up_lock);
1376*b494511aSVenki Rajagopalan }
1377*b494511aSVenki Rajagopalan 
1378*b494511aSVenki Rajagopalan static void
eib_fip_queue_gw_entry(eib_vnic_t * vnic,eib_vhub_table_t * tbl,uint32_t tusn,uint8_t eport_state)1379*b494511aSVenki Rajagopalan eib_fip_queue_gw_entry(eib_vnic_t *vnic, eib_vhub_table_t *tbl, uint32_t tusn,
1380*b494511aSVenki Rajagopalan     uint8_t eport_state)
1381*b494511aSVenki Rajagopalan {
1382*b494511aSVenki Rajagopalan 	eib_t *ss = vnic->vn_ss;
1383*b494511aSVenki Rajagopalan 	eib_vhub_map_t *newmap;
1384*b494511aSVenki Rajagopalan 	eib_login_data_t *ld = &vnic->vn_login_data;
1385*b494511aSVenki Rajagopalan 
1386*b494511aSVenki Rajagopalan 	if ((newmap = eib_fip_get_vhub_map()) == NULL) {
1387*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_queue_gw_entry: "
1388*b494511aSVenki Rajagopalan 		    "no memory to queue gw entry, transactions could fail");
1389*b494511aSVenki Rajagopalan 		return;
1390*b494511aSVenki Rajagopalan 	}
1391*b494511aSVenki Rajagopalan 
1392*b494511aSVenki Rajagopalan 	newmap->mp_v_rss_type = FIP_TE_VALID | FIP_TE_TYPE_GATEWAY;
1393*b494511aSVenki Rajagopalan 	bcopy(eib_zero_mac, newmap->mp_mac, ETHERADDRL);
1394*b494511aSVenki Rajagopalan 	newmap->mp_qpn = ld->ld_gw_data_qpn;
1395*b494511aSVenki Rajagopalan 	newmap->mp_sl = ld->ld_gw_sl;
1396*b494511aSVenki Rajagopalan 	newmap->mp_lid = ld->ld_gw_lid;
1397*b494511aSVenki Rajagopalan 	newmap->mp_tusn = tusn;
1398*b494511aSVenki Rajagopalan 	newmap->mp_next = NULL;
1399*b494511aSVenki Rajagopalan 
1400*b494511aSVenki Rajagopalan 	eib_fip_queue_tbl_entry(tbl, newmap, tusn, eport_state);
1401*b494511aSVenki Rajagopalan }
1402*b494511aSVenki Rajagopalan 
1403*b494511aSVenki Rajagopalan static int
eib_fip_apply_updates(eib_t * ss,eib_vhub_table_t * tbl,eib_vhub_update_t * upd)1404*b494511aSVenki Rajagopalan eib_fip_apply_updates(eib_t *ss, eib_vhub_table_t *tbl, eib_vhub_update_t *upd)
1405*b494511aSVenki Rajagopalan {
1406*b494511aSVenki Rajagopalan 	eib_vhub_map_t *list;
1407*b494511aSVenki Rajagopalan 	eib_vhub_map_t *map;
1408*b494511aSVenki Rajagopalan 	eib_vhub_map_t *nxt;
1409*b494511aSVenki Rajagopalan 	uint32_t tbl_tusn = tbl->tb_tusn;
1410*b494511aSVenki Rajagopalan 
1411*b494511aSVenki Rajagopalan 	/*
1412*b494511aSVenki Rajagopalan 	 * Take the update list out
1413*b494511aSVenki Rajagopalan 	 */
1414*b494511aSVenki Rajagopalan 	mutex_enter(&upd->up_lock);
1415*b494511aSVenki Rajagopalan 	list = upd->up_vnic_entry;
1416*b494511aSVenki Rajagopalan 	upd->up_vnic_entry = NULL;
1417*b494511aSVenki Rajagopalan 	mutex_exit(&upd->up_lock);
1418*b494511aSVenki Rajagopalan 
1419*b494511aSVenki Rajagopalan 	/*
1420*b494511aSVenki Rajagopalan 	 * Skip any updates with older/same tusn as our vhub table
1421*b494511aSVenki Rajagopalan 	 */
1422*b494511aSVenki Rajagopalan 	nxt = NULL;
1423*b494511aSVenki Rajagopalan 	for (map = list; (map) && (map->mp_tusn <= tbl_tusn); map = nxt) {
1424*b494511aSVenki Rajagopalan 		nxt = map->mp_next;
1425*b494511aSVenki Rajagopalan 		kmem_free(map, sizeof (eib_vhub_map_t));
1426*b494511aSVenki Rajagopalan 	}
1427*b494511aSVenki Rajagopalan 
1428*b494511aSVenki Rajagopalan 	if (map == NULL)
1429*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
1430*b494511aSVenki Rajagopalan 
1431*b494511aSVenki Rajagopalan 	/*
1432*b494511aSVenki Rajagopalan 	 * If we missed any updates between table tusn and the first
1433*b494511aSVenki Rajagopalan 	 * update tusn we got, we need to fail.
1434*b494511aSVenki Rajagopalan 	 */
1435*b494511aSVenki Rajagopalan 	if (map->mp_tusn > (tbl_tusn + 1)) {
1436*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_fip_apply_updates: "
1437*b494511aSVenki Rajagopalan 		    "vhub update missed tusn(s), expected=0x%lx, got=0x%lx",
1438*b494511aSVenki Rajagopalan 		    (tbl_tusn + 1), map->mp_tusn);
1439*b494511aSVenki Rajagopalan 		for (; map != NULL; map = nxt) {
1440*b494511aSVenki Rajagopalan 			nxt = map->mp_next;
1441*b494511aSVenki Rajagopalan 			kmem_free(map, sizeof (eib_vhub_map_t));
1442*b494511aSVenki Rajagopalan 		}
1443*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
1444*b494511aSVenki Rajagopalan 	}
1445*b494511aSVenki Rajagopalan 
1446*b494511aSVenki Rajagopalan 	/*
1447*b494511aSVenki Rajagopalan 	 * If everything is fine, apply all the updates we received
1448*b494511aSVenki Rajagopalan 	 */
1449*b494511aSVenki Rajagopalan 	for (; map != NULL; map = nxt) {
1450*b494511aSVenki Rajagopalan 		nxt = map->mp_next;
1451*b494511aSVenki Rajagopalan 		map->mp_next = NULL;
1452*b494511aSVenki Rajagopalan 
1453*b494511aSVenki Rajagopalan 		if (map->mp_v_rss_type & FIP_TE_VALID) {
1454*b494511aSVenki Rajagopalan 			eib_fip_queue_tbl_entry(tbl, map, upd->up_tusn,
1455*b494511aSVenki Rajagopalan 			    upd->up_eport_state);
1456*b494511aSVenki Rajagopalan 		} else {
1457*b494511aSVenki Rajagopalan 			eib_fip_dequeue_tbl_entry(tbl, map->mp_mac,
1458*b494511aSVenki Rajagopalan 			    upd->up_tusn, upd->up_eport_state);
1459*b494511aSVenki Rajagopalan 			kmem_free(map, sizeof (eib_vhub_map_t));
1460*b494511aSVenki Rajagopalan 		}
1461*b494511aSVenki Rajagopalan 	}
1462*b494511aSVenki Rajagopalan 
1463*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
1464*b494511aSVenki Rajagopalan }
1465*b494511aSVenki Rajagopalan 
1466*b494511aSVenki Rajagopalan static void
eib_fip_dequeue_tbl_entry(eib_vhub_table_t * tbl,uint8_t * mac,uint32_t tusn,uint8_t eport_state)1467*b494511aSVenki Rajagopalan eib_fip_dequeue_tbl_entry(eib_vhub_table_t *tbl, uint8_t *mac, uint32_t tusn,
1468*b494511aSVenki Rajagopalan     uint8_t eport_state)
1469*b494511aSVenki Rajagopalan {
1470*b494511aSVenki Rajagopalan 	uint8_t bkt;
1471*b494511aSVenki Rajagopalan 	eib_vhub_map_t *prev;
1472*b494511aSVenki Rajagopalan 	eib_vhub_map_t *elem;
1473*b494511aSVenki Rajagopalan 
1474*b494511aSVenki Rajagopalan 	bkt = (mac[ETHERADDRL-1]) % EIB_TB_NBUCKETS;
1475*b494511aSVenki Rajagopalan 
1476*b494511aSVenki Rajagopalan 	mutex_enter(&tbl->tb_lock);
1477*b494511aSVenki Rajagopalan 
1478*b494511aSVenki Rajagopalan 	/*
1479*b494511aSVenki Rajagopalan 	 * Note that for EoIB, the vhub table is maintained using only
1480*b494511aSVenki Rajagopalan 	 * vnic entry updates
1481*b494511aSVenki Rajagopalan 	 */
1482*b494511aSVenki Rajagopalan 	prev = NULL;
1483*b494511aSVenki Rajagopalan 	for (elem = tbl->tb_vnic_entry[bkt]; elem; elem = elem->mp_next) {
1484*b494511aSVenki Rajagopalan 		if (bcmp(elem->mp_mac, mac, ETHERADDRL) == 0)
1485*b494511aSVenki Rajagopalan 			break;
1486*b494511aSVenki Rajagopalan 		prev = elem;
1487*b494511aSVenki Rajagopalan 	}
1488*b494511aSVenki Rajagopalan 
1489*b494511aSVenki Rajagopalan 	if (prev && elem) {
1490*b494511aSVenki Rajagopalan 		prev->mp_next = elem->mp_next;
1491*b494511aSVenki Rajagopalan 		kmem_free(elem, sizeof (eib_vhub_map_t));
1492*b494511aSVenki Rajagopalan 	}
1493*b494511aSVenki Rajagopalan 
1494*b494511aSVenki Rajagopalan 	tbl->tb_tusn = tusn;
1495*b494511aSVenki Rajagopalan 	tbl->tb_eport_state = eport_state;
1496*b494511aSVenki Rajagopalan 
1497*b494511aSVenki Rajagopalan 	mutex_exit(&tbl->tb_lock);
1498*b494511aSVenki Rajagopalan }
1499*b494511aSVenki Rajagopalan 
1500*b494511aSVenki Rajagopalan static eib_vhub_map_t *
eib_fip_get_vhub_map(void)1501*b494511aSVenki Rajagopalan eib_fip_get_vhub_map(void)
1502*b494511aSVenki Rajagopalan {
1503*b494511aSVenki Rajagopalan 	return (kmem_zalloc(sizeof (eib_vhub_map_t), KM_NOSLEEP));
1504*b494511aSVenki Rajagopalan }
1505