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 */
38ib_gid_t eib_reserved_gid;
39
40uint8_t eib_zero_mac[] = {
41	0x0, 0x0, 0x0, 0x0, 0x0, 0x0
42};
43
44uint8_t eib_broadcast_mac[] = {
45	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
46};
47
48int 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
60char *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 */
117int 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 */
123int eib_wa_no_cksum_offload = 1;
124int 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 */
132int 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 */
138int 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 */
145int 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 */
154int eib_wa_no_good_vhub_cksum = 1;
155
156int
157eib_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
263get_props_fail:
264	eib_rb_get_props(ss);
265	return (EIB_E_FAILURE);
266}
267
268void
269eib_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
365void
366eib_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