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/enx_impl.h>
34
35/*
36 * Acquire an SWQE
37 */
38
39/*ARGSUSED*/
40eibnx_wqe_t *
41eibnx_acquire_swqe(eibnx_thr_info_t *info, int flag)
42{
43	eibnx_wqe_t *wqe = NULL;
44	eibnx_tx_t *snd_p = &info->ti_snd;
45	int i;
46
47	for (i = 0; i < ENX_NUM_SWQE; i++) {
48		wqe = &(snd_p->tx_wqe[i]);
49
50		mutex_enter(&wqe->qe_lock);
51		if ((wqe->qe_flags & ENX_QEFL_INUSE) == 0) {
52			wqe->qe_flags |= ENX_QEFL_INUSE;
53			mutex_exit(&wqe->qe_lock);
54			break;
55		}
56		mutex_exit(&wqe->qe_lock);
57	}
58
59	/*
60	 * We probably have enough swqe entries for doing our solicitations.
61	 * If we find it not enough in practice, we need to implement some
62	 * sort of dynamic allocation.
63	 */
64	if (i == ENX_NUM_SWQE)
65		wqe = NULL;
66
67	return (wqe);
68}
69
70/*
71 * Return a SWQE from completion. We may have to release
72 * it or keep it.
73 */
74void
75eibnx_return_swqe(eibnx_wqe_t *wqe)
76{
77	ASSERT(wqe->qe_type == ENX_QETYP_SWQE);
78
79	mutex_enter(&wqe->qe_lock);
80
81	/*
82	 * This send wqe is from the completion queue.  We need to
83	 * clear the 'posted' flag first.
84	 */
85	ASSERT((wqe->qe_flags & ENX_QEFL_POSTED) == ENX_QEFL_POSTED);
86	wqe->qe_flags &= (~ENX_QEFL_POSTED);
87
88	/*
89	 * See if we need to release this send wqe back to the pool
90	 * on completion. We may not need to do so if, for example,
91	 * this were a swqe acquired specifically for a particular gw.
92	 */
93	if (wqe->qe_flags & ENX_QEFL_RELONCOMP) {
94		wqe->qe_sgl.ds_len = wqe->qe_bufsz;
95		wqe->qe_flags &= (~ENX_QEFL_INUSE);
96
97		wqe->qe_flags &= (~ENX_QEFL_RELONCOMP);
98	}
99
100	mutex_exit(&wqe->qe_lock);
101}
102
103/*
104 * Return a RWQE from completion. We probably have to repost it.
105 */
106void
107eibnx_return_rwqe(eibnx_thr_info_t *info, eibnx_wqe_t *wqe)
108{
109	ibt_status_t ret;
110
111	ASSERT(wqe->qe_type == ENX_QETYP_RWQE);
112
113	mutex_enter(&wqe->qe_lock);
114
115	/*
116	 * We should never need to free an rwqe on completion.
117	 */
118	ASSERT((wqe->qe_flags & ENX_QEFL_RELONCOMP) == 0);
119
120	/*
121	 * An rwqe is always in-use and posted, so we only need to make
122	 * sure the ds_len is adjusted back to the value it's supposed
123	 * to have.
124	 */
125	wqe->qe_sgl.ds_len = wqe->qe_bufsz;
126
127	/*
128	 * Repost the recv wqe
129	 */
130	ret = ibt_post_recv(info->ti_chan, &(wqe->qe_wr.recv), 1, NULL);
131	if (ret != IBT_SUCCESS) {
132		ENX_DPRINTF_WARN("ibt_post_recv(chan_hdl=0x%llx) failed, "
133		    "ret=%d", info->ti_chan, ret);
134	}
135
136	mutex_exit(&wqe->qe_lock);
137}
138
139/*
140 * Release an SWQE that was acquired earlier.
141 */
142void
143eibnx_release_swqe(eibnx_wqe_t *wqe)
144{
145	ASSERT(wqe->qe_type == ENX_QETYP_SWQE);
146
147	mutex_enter(&wqe->qe_lock);
148
149	/*
150	 * Make sure this swqe is in use. Since this routine may also be
151	 * called when we're trying to cleanup the eoib nodes, we
152	 * should clear all flag bits.
153	 */
154	ASSERT((wqe->qe_flags & ENX_QEFL_INUSE) == ENX_QEFL_INUSE);
155	wqe->qe_flags = 0;
156
157	mutex_exit(&wqe->qe_lock);
158}
159
160/*
161 * Insert the passed child to the head of the queue
162 */
163void
164eibnx_enqueue_child(eibnx_thr_info_t *info, eibnx_gw_info_t *gwi,
165    char *node_name, dev_info_t *dip)
166{
167	eibnx_child_t *ch;
168	eibnx_child_t *new_ch;
169
170	new_ch = kmem_zalloc(sizeof (eibnx_child_t), KM_SLEEP);
171	new_ch->ch_dip = dip;
172	new_ch->ch_node_name = node_name;
173	new_ch->ch_gwi = gwi;
174
175	mutex_enter(&info->ti_child_lock);
176
177	/*
178	 * Search existing children to see if we already have this
179	 * child.  If so, simply update its dip and node_name
180	 */
181	for (ch = info->ti_child; ch; ch = ch->ch_next) {
182		if (ch->ch_gwi->gw_portid == gwi->gw_portid) {
183			ch->ch_dip = dip;
184			if (ch->ch_node_name) {
185				kmem_free(ch->ch_node_name, MAXNAMELEN);
186			}
187			ch->ch_node_name = node_name;
188			kmem_free(new_ch, sizeof (eibnx_child_t));
189			return;
190		}
191	}
192
193	/*
194	 * If not, add the new child to the list of children
195	 */
196	new_ch->ch_next = info->ti_child;
197	info->ti_child = new_ch;
198
199	mutex_exit(&info->ti_child_lock);
200}
201
202int
203eibnx_update_child(eibnx_thr_info_t *info, eibnx_gw_info_t *gwi,
204    dev_info_t *dip)
205{
206	eibnx_child_t *ch;
207
208	mutex_enter(&info->ti_child_lock);
209	for (ch = info->ti_child; ch; ch = ch->ch_next) {
210		if (ch->ch_gwi->gw_portid == gwi->gw_portid) {
211			if (ch->ch_dip != dip) {
212				ENX_DPRINTF_DEBUG("updating child dip for "
213				    "gw portid 0x%x to 0x%llx",
214				    gwi->gw_portid, dip);
215				ch->ch_dip = dip;
216			}
217			mutex_exit(&info->ti_child_lock);
218
219			return (ENX_E_SUCCESS);
220		}
221	}
222	mutex_exit(&info->ti_child_lock);
223
224	return (ENX_E_FAILURE);
225}
226
227dev_info_t *
228eibnx_find_child_dip_by_inst(eibnx_thr_info_t *info, int inst)
229{
230	eibnx_child_t *ch;
231	dev_info_t *dip = NULL;
232
233	mutex_enter(&info->ti_child_lock);
234	for (ch = info->ti_child; ch != NULL; ch = ch->ch_next) {
235		dip = ch->ch_dip;
236		if (ddi_get_instance(dip) == inst)
237			break;
238	}
239	mutex_exit(&info->ti_child_lock);
240
241	return (dip);
242}
243
244dev_info_t *
245eibnx_find_child_dip_by_gw(eibnx_thr_info_t *info, uint16_t gw_portid)
246{
247	eibnx_child_t *ch;
248	dev_info_t *dip = NULL;
249
250	mutex_enter(&info->ti_child_lock);
251	for (ch = info->ti_child; ch != NULL; ch = ch->ch_next) {
252		dip = ch->ch_dip;
253		if (ch->ch_gwi->gw_portid == gw_portid)
254			break;
255	}
256	mutex_exit(&info->ti_child_lock);
257
258	return (dip);
259}
260
261/*
262 * See if the passed gateway is already found in our list.  Note
263 * that we assume that the gateway port id uniquely identifies each
264 * gateway.
265 */
266eibnx_gw_info_t *
267eibnx_find_gw_in_gwlist(eibnx_thr_info_t *info, eibnx_gw_info_t *gwi)
268{
269	eibnx_gw_info_t *lgw = NULL;
270
271	mutex_enter(&info->ti_gw_lock);
272	for (lgw = info->ti_gw; lgw; lgw = lgw->gw_next) {
273		if (lgw->gw_portid == gwi->gw_portid)
274			break;
275	}
276	mutex_exit(&info->ti_gw_lock);
277
278	return (lgw);
279}
280
281/*
282 * Add a newly discovered gateway to the gateway list.  Since we'll
283 * need to send unicast solicitations to this gateway soon, we'll
284 * also grab a swqe entry, and initialize basic gw adress parameters
285 * such as the gid, qpn, qkey and pkey of the GW.  When we eventually
286 * get to sending the unicast to this gateway for the first time,
287 * we'll discover the path to this gateway using these parameters
288 * and modify the ud destination handle appropriately.
289 */
290eibnx_gw_info_t *
291eibnx_add_gw_to_gwlist(eibnx_thr_info_t *info, eibnx_gw_info_t *gwi,
292    ibt_wc_t *wc, uint8_t *recv_buf)
293{
294	eibnx_gw_info_t *new_gwi;
295	eibnx_wqe_t *wqe;
296	ib_grh_t *grh;
297	ib_gid_t sgid;
298	clock_t timeout_usecs;
299
300	/*
301	 * For now, we'll simply do KM_NOSLEEP allocation, since this code
302	 * is called from within rx processing
303	 */
304	new_gwi = kmem_zalloc(sizeof (eibnx_gw_info_t), KM_NOSLEEP);
305	if (new_gwi == NULL) {
306		ENX_DPRINTF_WARN("no memory, gw port_id 0x%x "
307		    "will be ignored by hca_guid=0x%llx, port=0x%x",
308		    gwi->gw_portid, info->ti_hca_guid,
309		    info->ti_pi->p_port_num);
310		return (NULL);
311	}
312
313	/*
314	 * We also need to acquire a send wqe to do unicast solicitations
315	 * to this gateway later on. We should've enough pre-allocated swqes
316	 * to do this without sleeping.
317	 */
318	if ((wqe = eibnx_acquire_swqe(info, KM_NOSLEEP)) == NULL) {
319		ENX_DPRINTF_WARN("no swqe available, gw port_id 0x%x "
320		    "will be ignored by hca_guid=0x%llx, port=0x%x",
321		    gwi->gw_portid, info->ti_hca_guid,
322		    info->ti_pi->p_port_num);
323		kmem_free(new_gwi, sizeof (eibnx_gw_info_t));
324		return (NULL);
325	}
326
327	/*
328	 * Initialize gw state and wqe information.
329	 */
330	new_gwi->gw_next = NULL;
331	new_gwi->gw_swqe = wqe;
332	new_gwi->gw_state = gwi->gw_state;
333
334	/*
335	 * Set up gateway advertisement monitoring parameters. Since we
336	 * always need to check against a timeout value of 2.5 * gw_adv_period,
337	 * we'll keep this pre-calculated value as well.
338	 */
339	mutex_init(&new_gwi->gw_adv_lock, NULL, MUTEX_DRIVER, NULL);
340	new_gwi->gw_adv_flag = gwi->gw_adv_flag;
341	new_gwi->gw_adv_last_lbolt = ddi_get_lbolt64();
342	timeout_usecs = gwi->gw_adv_period * 1000;
343	timeout_usecs = ((timeout_usecs << 2) + timeout_usecs) >> 1;
344	new_gwi->gw_adv_timeout_ticks = drv_usectohz(timeout_usecs);
345
346	/*
347	 * Initialize gateway address information. Note that if the message has
348	 * a GRH, we'll use the subnet prefix, otherwise we'll assume that the
349	 * gateway is in the same subnet as ourselves.
350	 */
351	new_gwi->gw_addr.ga_vect = NULL;
352	if (wc->wc_flags & IBT_WC_GRH_PRESENT) {
353		grh = (ib_grh_t *)(uintptr_t)recv_buf;
354		new_gwi->gw_addr.ga_gid.gid_prefix =
355		    ntohll(grh->SGID.gid_prefix);
356	} else {
357		sgid = info->ti_pi->p_sgid_tbl[0];
358		new_gwi->gw_addr.ga_gid.gid_prefix =
359		    sgid.gid_prefix;
360	}
361	new_gwi->gw_addr.ga_gid.gid_guid = gwi->gw_guid;
362	new_gwi->gw_addr.ga_qpn = gwi->gw_ctrl_qpn;
363	new_gwi->gw_addr.ga_qkey = EIB_FIP_QKEY;
364	new_gwi->gw_addr.ga_pkey = EIB_ADMIN_PKEY;
365
366	/*
367	 * Initialize gateway parameters received via the advertisement
368	 */
369	new_gwi->gw_system_guid = gwi->gw_system_guid;
370	new_gwi->gw_guid = gwi->gw_guid;
371	new_gwi->gw_adv_period = gwi->gw_adv_period;
372	new_gwi->gw_ka_period = gwi->gw_ka_period;
373	new_gwi->gw_vnic_ka_period = gwi->gw_vnic_ka_period;
374	new_gwi->gw_ctrl_qpn = gwi->gw_ctrl_qpn;
375	new_gwi->gw_lid = gwi->gw_lid;
376	new_gwi->gw_portid = gwi->gw_portid;
377	new_gwi->gw_num_net_vnics = gwi->gw_num_net_vnics;
378	new_gwi->gw_is_host_adm_vnics = gwi->gw_is_host_adm_vnics;
379	new_gwi->gw_sl = gwi->gw_sl;
380	new_gwi->gw_n_rss_qpn = gwi->gw_n_rss_qpn;
381	new_gwi->gw_flag_ucast_advt = gwi->gw_flag_ucast_advt;
382	new_gwi->gw_flag_available = gwi->gw_flag_available;
383	bcopy(gwi->gw_system_name, new_gwi->gw_system_name,
384	    sizeof (new_gwi->gw_system_name));
385	bcopy(gwi->gw_port_name, new_gwi->gw_port_name,
386	    sizeof (new_gwi->gw_port_name));
387	bcopy(gwi->gw_vendor_id, new_gwi->gw_vendor_id,
388	    sizeof (new_gwi->gw_vendor_id));
389
390	/*
391	 * Queue up the new gwi and return it
392	 */
393	mutex_enter(&info->ti_gw_lock);
394	new_gwi->gw_next = info->ti_gw;
395	info->ti_gw = new_gwi;
396	mutex_exit(&info->ti_gw_lock);
397
398	return (new_gwi);
399}
400
401/*
402 * Update old data for the gateway in our list with the new data.
403 */
404void
405eibnx_replace_gw_in_gwlist(eibnx_thr_info_t *info, eibnx_gw_info_t *orig_gwi,
406    eibnx_gw_info_t *new_gwi, ibt_wc_t *wc, uint8_t *recv_buf,
407    boolean_t *gwi_changed)
408{
409	ib_sn_prefix_t new_gw_sn_prefix;
410	ib_grh_t *grh;
411	ib_gid_t sgid;
412	boolean_t changed = B_FALSE;
413	boolean_t gw_addr_changed = B_TRUE;
414
415	/*
416	 * We'll update all info received in the new advertisement in
417	 * the original gwi and also move the gw_state to that of the state
418	 * in the new gwi.
419	 */
420	mutex_enter(&info->ti_gw_lock);
421
422	orig_gwi->gw_state = new_gwi->gw_state;
423
424	/*
425	 * The guids shouldn't really change for the "same" gateway
426	 */
427	if (new_gwi->gw_system_guid != orig_gwi->gw_system_guid) {
428		ENX_DPRINTF_WARN("gateway system guid changed for the "
429		    "*same* gateway from 0x%llx to 0x%llx",
430		    orig_gwi->gw_system_guid, new_gwi->gw_system_guid);
431
432		orig_gwi->gw_system_guid = new_gwi->gw_system_guid;
433		changed = B_TRUE;
434	}
435	if (new_gwi->gw_guid != orig_gwi->gw_guid) {
436		ENX_DPRINTF_WARN("gateway guid changed for the "
437		    "*same* gateway from 0x%llx to 0x%llx",
438		    orig_gwi->gw_guid, new_gwi->gw_guid);
439
440		orig_gwi->gw_guid = new_gwi->gw_guid;
441		changed = B_TRUE;
442		gw_addr_changed = B_TRUE;
443	}
444
445	if (new_gwi->gw_adv_period != orig_gwi->gw_adv_period) {
446		ENX_DPRINTF_DEBUG("gateway adv period changed "
447		    "from 0x%lx to 0x%lx", orig_gwi->gw_adv_period,
448		    new_gwi->gw_adv_period);
449
450		orig_gwi->gw_adv_period = new_gwi->gw_adv_period;
451		changed = B_TRUE;
452	}
453	if (new_gwi->gw_ka_period != orig_gwi->gw_ka_period) {
454		ENX_DPRINTF_DEBUG("gateway ka period changed "
455		    "from 0x%lx to 0x%lx", orig_gwi->gw_ka_period,
456		    new_gwi->gw_ka_period);
457
458		orig_gwi->gw_ka_period = new_gwi->gw_ka_period;
459		changed = B_TRUE;
460	}
461	if (new_gwi->gw_vnic_ka_period != orig_gwi->gw_vnic_ka_period) {
462		ENX_DPRINTF_DEBUG("vnic ka period changed "
463		    "from 0x%lx to 0x%lx", orig_gwi->gw_vnic_ka_period,
464		    new_gwi->gw_vnic_ka_period);
465
466		orig_gwi->gw_vnic_ka_period = new_gwi->gw_vnic_ka_period;
467		changed = B_TRUE;
468	}
469	if (new_gwi->gw_ctrl_qpn != orig_gwi->gw_ctrl_qpn) {
470		ENX_DPRINTF_DEBUG("gateway control qpn changed "
471		    "from 0x%lx to 0x%lx", orig_gwi->gw_ctrl_qpn,
472		    new_gwi->gw_ctrl_qpn);
473
474		orig_gwi->gw_ctrl_qpn = new_gwi->gw_ctrl_qpn;
475		changed = B_TRUE;
476	}
477	if (new_gwi->gw_lid != orig_gwi->gw_lid) {
478		ENX_DPRINTF_DEBUG("gateway lid changed from 0x%x to 0x%x",
479		    orig_gwi->gw_lid, new_gwi->gw_lid);
480
481		orig_gwi->gw_lid = new_gwi->gw_lid;
482		changed = B_TRUE;
483		gw_addr_changed = B_TRUE;
484	}
485
486	/*
487	 * The identity of the gateway is currently defined by its portid,
488	 * so this cannot be different or eibnx_find_gw_in_gwlist() wouldn't
489	 * have thought it's the same.  For now though, we'll treat it
490	 * like any other parameter, and flag it if we find this different.
491	 */
492	if (new_gwi->gw_portid != orig_gwi->gw_portid) {
493		ENX_DPRINTF_WARN("gateway portid changed for the *same* "
494		    "gateway from 0x%x to 0x%x", orig_gwi->gw_portid,
495		    new_gwi->gw_portid);
496
497		orig_gwi->gw_portid = new_gwi->gw_portid;
498		changed = B_TRUE;
499	}
500
501	if (new_gwi->gw_is_host_adm_vnics != orig_gwi->gw_is_host_adm_vnics) {
502		ENX_DPRINTF_DEBUG("host adm vnics changed from 0x%x to 0x%x",
503		    orig_gwi->gw_is_host_adm_vnics,
504		    new_gwi->gw_is_host_adm_vnics);
505
506		orig_gwi->gw_is_host_adm_vnics = new_gwi->gw_is_host_adm_vnics;
507		changed = B_TRUE;
508	}
509	if (new_gwi->gw_sl != orig_gwi->gw_sl) {
510		ENX_DPRINTF_DEBUG("gateway sl changed from 0x%x to 0x%x",
511		    orig_gwi->gw_sl, new_gwi->gw_sl);
512
513		orig_gwi->gw_sl = new_gwi->gw_sl;
514		changed = B_TRUE;
515	}
516	if (new_gwi->gw_n_rss_qpn != orig_gwi->gw_n_rss_qpn) {
517		ENX_DPRINTF_DEBUG("gateway n_rss_qpn changed from 0x%x to 0x%x",
518		    orig_gwi->gw_n_rss_qpn, new_gwi->gw_n_rss_qpn);
519
520		orig_gwi->gw_n_rss_qpn = new_gwi->gw_n_rss_qpn;
521		changed = B_TRUE;
522	}
523
524	/*
525	 * The gw_flag_ucast_advt and gw_flag_available are expected to
526	 * change over time (and even gw_num_net_vnics could change, but
527	 * it's of no use to us presently), and we shouldn't trigger any
528	 * flag for these
529	 */
530	orig_gwi->gw_flag_ucast_advt = new_gwi->gw_flag_ucast_advt;
531	orig_gwi->gw_flag_available = new_gwi->gw_flag_available;
532	orig_gwi->gw_num_net_vnics = new_gwi->gw_num_net_vnics;
533
534	if (strncmp((const char *)new_gwi->gw_system_name,
535	    (const char *)orig_gwi->gw_system_name, EIB_GW_SYSNAME_LEN) != 0) {
536		ENX_DPRINTF_DEBUG("gateway system name changed from %s to %s",
537		    orig_gwi->gw_system_name, new_gwi->gw_system_name);
538
539		bcopy(new_gwi->gw_system_name, orig_gwi->gw_system_name,
540		    EIB_GW_SYSNAME_LEN);
541		changed = B_TRUE;
542	}
543	if (strncmp((const char *)new_gwi->gw_port_name,
544	    (const char *)orig_gwi->gw_port_name, EIB_GW_PORTNAME_LEN) != 0) {
545		ENX_DPRINTF_DEBUG("gateway port name changed from %s to %s",
546		    orig_gwi->gw_port_name, new_gwi->gw_port_name);
547
548		bcopy(new_gwi->gw_port_name, orig_gwi->gw_port_name,
549		    EIB_GW_PORTNAME_LEN);
550		changed = B_TRUE;
551	}
552	if (strncmp((const char *)new_gwi->gw_vendor_id,
553	    (const char *)orig_gwi->gw_vendor_id, EIB_GW_VENDOR_LEN) != 0) {
554		ENX_DPRINTF_DEBUG("vendor id changed from %s to %s",
555		    orig_gwi->gw_vendor_id, new_gwi->gw_vendor_id);
556
557		bcopy(new_gwi->gw_vendor_id, orig_gwi->gw_vendor_id,
558		    EIB_GW_VENDOR_LEN);
559		changed = B_TRUE;
560	}
561
562	/*
563	 * See if the subnet prefix for the gateway has changed
564	 */
565	if (wc->wc_flags & IBT_WC_GRH_PRESENT) {
566		grh = (ib_grh_t *)(uintptr_t)recv_buf;
567		new_gw_sn_prefix = ntohll(grh->SGID.gid_prefix);
568	} else {
569		sgid = info->ti_pi->p_sgid_tbl[0];
570		new_gw_sn_prefix = sgid.gid_prefix;
571	}
572	if (new_gw_sn_prefix != orig_gwi->gw_addr.ga_gid.gid_prefix) {
573		ENX_DPRINTF_WARN("subnet prefix changed from 0x%llx to 0x%llx",
574		    orig_gwi->gw_addr.ga_gid.gid_prefix, new_gw_sn_prefix);
575
576		changed = B_TRUE;
577		gw_addr_changed = B_TRUE;
578	}
579
580	/*
581	 * If the gateway address has changed in any way, clear the current
582	 * address vector and update the gateway guid and gateway qpn. The
583	 * address vector will be created the next time a unicast solicit
584	 * is attempted for this gateway.
585	 */
586	if (gw_addr_changed) {
587		if (orig_gwi->gw_addr.ga_vect != NULL) {
588			kmem_free(orig_gwi->gw_addr.ga_vect,
589			    sizeof (ibt_adds_vect_t));
590			orig_gwi->gw_addr.ga_vect = NULL;
591		}
592		orig_gwi->gw_addr.ga_gid.gid_prefix = new_gw_sn_prefix;
593		orig_gwi->gw_addr.ga_gid.gid_guid = new_gwi->gw_guid;
594		orig_gwi->gw_addr.ga_qpn = new_gwi->gw_ctrl_qpn;
595		orig_gwi->gw_addr.ga_qkey = EIB_FIP_QKEY;
596		orig_gwi->gw_addr.ga_pkey = EIB_ADMIN_PKEY;
597	}
598
599	mutex_exit(&info->ti_gw_lock);
600
601	if (gwi_changed) {
602		*gwi_changed = changed;
603	}
604}
605
606/*
607 * Queue up a node for EoIB instantiation and wake up the thread
608 * that creates eoib nodes.
609 */
610void
611eibnx_queue_for_creation(eibnx_thr_info_t *info, eibnx_gw_info_t *gwi)
612{
613	eibnx_t *ss = enx_global_ss;
614	eibnx_nodeq_t *new_node;
615
616	/*
617	 * For now, we'll simply do KM_NOSLEEP allocation, since this
618	 * code is called from within rx processing
619	 */
620	new_node = kmem_zalloc(sizeof (eibnx_nodeq_t), KM_NOSLEEP);
621	if (new_node == NULL) {
622		ENX_DPRINTF_WARN("no memory, eoib node will not be "
623		    "created for hca_guid=0x%llx, hca_port=0x%x, "
624		    "gw_port_id=0x%x", info->ti_hca_guid,
625		    info->ti_pi->p_port_num, gwi->gw_portid);
626		return;
627	}
628	new_node->nc_info = info;
629	new_node->nc_gwi = gwi;
630
631	/*
632	 * If the eoib node creation thread is dying (or dead), don't
633	 * queue up any more requests for creation
634	 */
635	mutex_enter(&ss->nx_nodeq_lock);
636	if (ss->nx_nodeq_thr_die) {
637		kmem_free(new_node, sizeof (eibnx_nodeq_t));
638	} else {
639		new_node->nc_next = ss->nx_nodeq;
640		ss->nx_nodeq = new_node;
641		cv_signal(&ss->nx_nodeq_cv);
642	}
643	mutex_exit(&ss->nx_nodeq_lock);
644}
645