1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/kmem.h>
28 #include <sys/conf.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/ksynch.h>
32 
33 #include <sys/ib/clients/eoib/eib_impl.h>
34 
35 /*
36  * Definitions private to this file
37  */
38 ib_gid_t eib_reserved_gid;
39 
40 uint8_t eib_zero_mac[] = {
41 	0x0, 0x0, 0x0, 0x0, 0x0, 0x0
42 };
43 
44 uint8_t eib_broadcast_mac[] = {
45 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
46 };
47 
48 int eib_setbit_mod67[] = {
49 	-1,  0,  1, 39,  2, 15, 40, 23,
50 	3,  12, 16, 59, 41, 19, 24, 54,
51 	4,  -1, 13, 10, 17, 62, 60, 28,
52 	42, 30, 20, 51, 25, 44, 55, 47,
53 	5,  32, -1, 38, 14, 22, 11, 58,
54 	18, 53, 63,  9, 61, 27, 29, 50,
55 	43, 46, 31, 37, 21, 57, 52,  8,
56 	26, 49, 45, 36, 56,  7, 48, 35,
57 	6,  34, 33
58 };
59 
60 char *eib_pvt_props[] = {
61 	EIB_DLPROP_GW_EPORT_STATE,
62 	EIB_DLPROP_HCA_GUID,
63 	EIB_DLPROP_PORT_GUID,
64 	NULL
65 };
66 
67 #define	eib_prop_get_and_test(inst, dp, propname, propval)		\
68 {                                                                       \
69 	(propval) = ddi_prop_get_int(DDI_DEV_T_ANY, (dp),               \
70 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname), -1);      \
71 	if ((propval) == -1) {                                          \
72 		EIB_DPRINTF_WARN((inst), "eib_get_props: "		\
73 		    "ddi_prop_get_int() could not find "		\
74 		    "property '%s'", (propname));			\
75 		goto get_props_fail;                                    \
76 	}                                                               \
77 }
78 
79 #define	eib_prop64_get_and_test(inst, dp, propname, propval)		\
80 {                                                                       \
81 	(propval) = ddi_prop_get_int64(DDI_DEV_T_ANY, (dp),             \
82 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname), -1);      \
83 	if ((propval) == -1) {                                          \
84 		EIB_DPRINTF_WARN((inst), "eib_get_props: "		\
85 		    "ddi_prop_get_int64() could not find "		\
86 		    "property '%s'", (propname));			\
87 		goto get_props_fail;                                    \
88 	}                                                               \
89 }
90 
91 #define	eib_propstr_get_and_test(inst, dp, propname, propval_p)		\
92 {                                                                       \
93 	int rv;                                                         \
94 									\
95 	*(propval_p) = NULL;                                            \
96 									\
97 	rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, (dp),                \
98 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname),           \
99 	    (propval_p));                                               \
100 	if (rv != DDI_PROP_SUCCESS) {                                   \
101 		EIB_DPRINTF_WARN((inst), "eib_get_props: "		\
102 		    "ddi_prop_lookup_string() could not find "		\
103 		    "property '%s'", (propname));			\
104 		goto get_props_fail;                                    \
105 	}                                                               \
106 }
107 
108 /*
109  * HW/FW workarounds
110  */
111 
112 /*
113  * 1. Verification of descriptor list length in the received packets is
114  *    disabled, since experimentation shows that BX does not set the desc
115  *    list length correctly. True for EoIB nexus as well.
116  */
117 int eib_wa_no_desc_list_len = 1;
118 
119 /*
120  * 2. LSO/Checksum_Offload for EoIB packets does not seem to be supported
121  *    currently, so we'll disable both temporarily.
122  */
123 int eib_wa_no_cksum_offload = 1;
124 int eib_wa_no_lso = 1;
125 
126 /*
127  * 3. The "multicast entry" types are not clearly defined in the spec
128  *    at the moment.  The current BX software/firmware appears to ignore
129  *    the type of the context table entries, so we will treat these
130  *    addresses just like regular vnic addresses.
131  */
132 int eib_wa_no_mcast_entries = 1;
133 
134 /*
135  * 4. VHUB updates from the gateways provide us with destination LIDs,
136  *    and we will hand-create these address vectors.
137  */
138 int eib_wa_no_av_discover = 1;
139 
140 /*
141  * 5. The older BX software does not seem to set the VP flag correctly
142  *    in the login acknowledgements even when it successfully allocates
143  *    a vlan, so we will ignore it for now.
144  */
145 int eib_wa_no_good_vp_flag = 1;
146 
147 /*
148  * 6. Each vhub table is expected to carry a checksum at the end to
149  *    verify the contents of the received vhub table. The current BX
150  *    software/firmware does not seem to fill this field with the
151  *    correct value (and/or the spec description is ambiguous). We
152  *    will ignore the vhub table checksum verification for now.
153  */
154 int eib_wa_no_good_vhub_cksum = 1;
155 
156 int
eib_get_props(eib_t * ss)157 eib_get_props(eib_t *ss)
158 {
159 	int val;
160 	int64_t val64;
161 	char *str;
162 	clock_t gw_ka_usecs;
163 	clock_t vnic_ka_usecs;
164 
165 	ss->ei_gw_props = kmem_zalloc(sizeof (eib_gw_props_t), KM_SLEEP);
166 	ss->ei_props = kmem_zalloc(sizeof (eib_props_t), KM_SLEEP);
167 
168 	mutex_init(&ss->ei_gw_props->pp_gw_lock, NULL, MUTEX_DRIVER, NULL);
169 
170 	/*
171 	 * The interface speed is currently set to 10Gb/s, since we don't
172 	 * have a way yet to figure this virtual-wire specific data from
173 	 * the gateway.  The rest of the properties are handed over to us
174 	 * by the EoIB nexus.
175 	 */
176 	ss->ei_props->ep_ifspeed = 10000000000;
177 
178 	eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip,
179 	    EIB_PROP_HCA_GUID, val64);
180 	ss->ei_props->ep_hca_guid = (ib_guid_t)val64;
181 
182 	eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip,
183 	    EIB_PROP_GW_SYS_GUID, val64);
184 	ss->ei_gw_props->pp_gw_system_guid = (ib_guid_t)val64;
185 
186 	eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip,
187 	    EIB_PROP_GW_GUID, val64);
188 	ss->ei_gw_props->pp_gw_guid = (ib_guid_t)val64;
189 
190 	eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip,
191 	    EIB_PROP_GW_SN_PREFIX, val64);
192 	ss->ei_gw_props->pp_gw_sn_prefix = (ib_sn_prefix_t)val64;
193 
194 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
195 	    EIB_PROP_GW_ADV_PERIOD, val);
196 	ss->ei_gw_props->pp_gw_adv_period = (uint_t)val;
197 
198 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
199 	    EIB_PROP_GW_KA_PERIOD, val);
200 	ss->ei_gw_props->pp_gw_ka_period = (uint_t)val;
201 
202 	gw_ka_usecs = ss->ei_gw_props->pp_gw_ka_period * 1000;
203 	gw_ka_usecs = ((gw_ka_usecs << 2) + gw_ka_usecs) >> 1;
204 	ss->ei_gw_props->pp_gw_ka_ticks = drv_usectohz(gw_ka_usecs);
205 
206 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
207 	    EIB_PROP_VNIC_KA_PERIOD, val);
208 	ss->ei_gw_props->pp_vnic_ka_period = (uint_t)val;
209 
210 	vnic_ka_usecs = ss->ei_gw_props->pp_vnic_ka_period * 1000;
211 	ss->ei_gw_props->pp_vnic_ka_ticks = drv_usectohz(vnic_ka_usecs);
212 
213 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
214 	    EIB_PROP_GW_CTRL_QPN, val);
215 	ss->ei_gw_props->pp_gw_ctrl_qpn = (ib_qpn_t)val;
216 
217 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
218 	    EIB_PROP_GW_LID, val);
219 	ss->ei_gw_props->pp_gw_lid = (ib_lid_t)val;
220 
221 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
222 	    EIB_PROP_GW_PORTID, val);
223 	ss->ei_gw_props->pp_gw_portid = (uint16_t)val;
224 
225 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
226 	    EIB_PROP_GW_NUM_NET_VNICS, val);
227 	ss->ei_gw_props->pp_gw_num_net_vnics = (uint16_t)val;
228 
229 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
230 	    EIB_PROP_GW_AVAILABLE, val);
231 	ss->ei_gw_props->pp_gw_flag_available = (uint8_t)val;
232 
233 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
234 	    EIB_PROP_GW_HOST_VNICS, val);
235 	ss->ei_gw_props->pp_gw_is_host_adm_vnics = (uint8_t)val;
236 
237 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
238 	    EIB_PROP_GW_SL, val);
239 	ss->ei_gw_props->pp_gw_sl = (uint8_t)val;
240 
241 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
242 	    EIB_PROP_GW_N_RSS_QPN, val);
243 	ss->ei_gw_props->pp_gw_n_rss_qpn = (uint8_t)val;
244 
245 	eib_prop_get_and_test(ss->ei_instance, ss->ei_dip,
246 	    EIB_PROP_HCA_PORTNUM, val);
247 	ss->ei_props->ep_port_num = (uint8_t)val;
248 
249 	eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip,
250 	    EIB_PROP_GW_SYS_NAME, &str);
251 	ss->ei_gw_props->pp_gw_system_name = (uint8_t *)str;
252 
253 	eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip,
254 	    EIB_PROP_GW_PORT_NAME, &str);
255 	ss->ei_gw_props->pp_gw_port_name = (uint8_t *)str;
256 
257 	eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip,
258 	    EIB_PROP_GW_VENDOR_ID, &str);
259 	ss->ei_gw_props->pp_gw_vendor_id = (uint8_t *)str;
260 
261 	return (EIB_E_SUCCESS);
262 
263 get_props_fail:
264 	eib_rb_get_props(ss);
265 	return (EIB_E_FAILURE);
266 }
267 
268 void
eib_update_props(eib_t * ss,eib_gw_info_t * new_gw_info)269 eib_update_props(eib_t *ss, eib_gw_info_t *new_gw_info)
270 {
271 	eib_gw_props_t *gwp = ss->ei_gw_props;
272 	dev_info_t *dip = ss->ei_dip;
273 	char *str;
274 
275 	ASSERT(gwp != NULL && dip != NULL);
276 
277 	mutex_enter(&gwp->pp_gw_lock);
278 
279 	gwp->pp_gw_system_guid = new_gw_info->gi_system_guid;
280 	(void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SYS_GUID,
281 	    gwp->pp_gw_system_guid);
282 
283 	gwp->pp_gw_guid = new_gw_info->gi_guid;
284 	(void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_GUID,
285 	    gwp->pp_gw_guid);
286 
287 	gwp->pp_gw_sn_prefix = new_gw_info->gi_sn_prefix;
288 	(void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SN_PREFIX,
289 	    gwp->pp_gw_sn_prefix);
290 
291 	gwp->pp_gw_adv_period = new_gw_info->gi_adv_period;
292 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_ADV_PERIOD,
293 	    gwp->pp_gw_adv_period);
294 
295 	gwp->pp_gw_ka_period = new_gw_info->gi_ka_period;
296 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_KA_PERIOD,
297 	    gwp->pp_gw_ka_period);
298 
299 	gwp->pp_vnic_ka_period = new_gw_info->gi_vnic_ka_period;
300 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_VNIC_KA_PERIOD,
301 	    gwp->pp_vnic_ka_period);
302 
303 	gwp->pp_gw_ctrl_qpn = new_gw_info->gi_ctrl_qpn;
304 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_CTRL_QPN,
305 	    gwp->pp_gw_ctrl_qpn);
306 
307 	gwp->pp_gw_lid = new_gw_info->gi_lid;
308 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_LID,
309 	    gwp->pp_gw_lid);
310 
311 	gwp->pp_gw_portid = new_gw_info->gi_portid;
312 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_PORTID,
313 	    gwp->pp_gw_portid);
314 
315 	gwp->pp_gw_num_net_vnics = new_gw_info->gi_num_net_vnics;
316 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
317 	    EIB_PROP_GW_NUM_NET_VNICS, gwp->pp_gw_num_net_vnics);
318 
319 	gwp->pp_gw_flag_available = new_gw_info->gi_flag_available;
320 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_AVAILABLE,
321 	    gwp->pp_gw_flag_available);
322 
323 	gwp->pp_gw_is_host_adm_vnics = new_gw_info->gi_is_host_adm_vnics;
324 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_HOST_VNICS,
325 	    gwp->pp_gw_is_host_adm_vnics);
326 
327 	gwp->pp_gw_sl = new_gw_info->gi_sl;
328 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SL,
329 	    gwp->pp_gw_sl);
330 
331 	gwp->pp_gw_n_rss_qpn = new_gw_info->gi_n_rss_qpn;
332 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_N_RSS_QPN,
333 	    gwp->pp_gw_n_rss_qpn);
334 
335 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
336 	    EIB_PROP_GW_SYS_NAME, (char *)(new_gw_info->gi_system_name));
337 	(void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
338 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_SYS_NAME, &str);
339 	if (gwp->pp_gw_system_name) {
340 		ddi_prop_free(gwp->pp_gw_system_name);
341 	}
342 	gwp->pp_gw_system_name = (uint8_t *)str;
343 
344 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
345 	    EIB_PROP_GW_PORT_NAME, (char *)(new_gw_info->gi_port_name));
346 	(void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
347 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_PORT_NAME, &str);
348 	if (gwp->pp_gw_port_name) {
349 		ddi_prop_free(gwp->pp_gw_port_name);
350 	}
351 	gwp->pp_gw_port_name = (uint8_t *)str;
352 
353 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
354 	    EIB_PROP_GW_VENDOR_ID, (char *)(new_gw_info->gi_vendor_id));
355 	(void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
356 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_VENDOR_ID, &str);
357 	if (gwp->pp_gw_vendor_id) {
358 		ddi_prop_free(gwp->pp_gw_vendor_id);
359 	}
360 	gwp->pp_gw_vendor_id = (uint8_t *)str;
361 
362 	mutex_exit(&gwp->pp_gw_lock);
363 }
364 
365 void
eib_rb_get_props(eib_t * ss)366 eib_rb_get_props(eib_t *ss)
367 {
368 	/*
369 	 * Free any allocations
370 	 */
371 	if (ss->ei_gw_props->pp_gw_vendor_id) {
372 		ddi_prop_free(ss->ei_gw_props->pp_gw_vendor_id);
373 		ss->ei_gw_props->pp_gw_vendor_id = NULL;
374 	}
375 	if (ss->ei_gw_props->pp_gw_port_name) {
376 		ddi_prop_free(ss->ei_gw_props->pp_gw_port_name);
377 		ss->ei_gw_props->pp_gw_port_name = NULL;
378 	}
379 	if (ss->ei_gw_props->pp_gw_system_name) {
380 		ddi_prop_free(ss->ei_gw_props->pp_gw_system_name);
381 		ss->ei_gw_props->pp_gw_system_name = NULL;
382 	}
383 
384 	mutex_destroy(&ss->ei_gw_props->pp_gw_lock);
385 
386 	/*
387 	 * Free space allocated for holding the props
388 	 */
389 	kmem_free(ss->ei_props, sizeof (eib_props_t));
390 	kmem_free(ss->ei_gw_props, sizeof (eib_gw_props_t));
391 
392 	ss->ei_props = NULL;
393 	ss->ei_gw_props = NULL;
394 }
395