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.
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.
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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
30 #include <sys/sunddi.h>
31 #include <sys/ksynch.h>
33 #include <sys/ib/clients/eoib/enx_impl.h>
41 eibnx_acquire_swqe(eibnx_thr_info_t
*info
, int flag
)
43 eibnx_wqe_t
*wqe
= NULL
;
44 eibnx_tx_t
*snd_p
= &info
->ti_snd
;
47 for (i
= 0; i
< ENX_NUM_SWQE
; i
++) {
48 wqe
= &(snd_p
->tx_wqe
[i
]);
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
);
56 mutex_exit(&wqe
->qe_lock
);
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.
64 if (i
== ENX_NUM_SWQE
)
71 * Return a SWQE from completion. We may have to release
75 eibnx_return_swqe(eibnx_wqe_t
*wqe
)
77 ASSERT(wqe
->qe_type
== ENX_QETYP_SWQE
);
79 mutex_enter(&wqe
->qe_lock
);
82 * This send wqe is from the completion queue. We need to
83 * clear the 'posted' flag first.
85 ASSERT((wqe
->qe_flags
& ENX_QEFL_POSTED
) == ENX_QEFL_POSTED
);
86 wqe
->qe_flags
&= (~ENX_QEFL_POSTED
);
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.
93 if (wqe
->qe_flags
& ENX_QEFL_RELONCOMP
) {
94 wqe
->qe_sgl
.ds_len
= wqe
->qe_bufsz
;
95 wqe
->qe_flags
&= (~ENX_QEFL_INUSE
);
97 wqe
->qe_flags
&= (~ENX_QEFL_RELONCOMP
);
100 mutex_exit(&wqe
->qe_lock
);
104 * Return a RWQE from completion. We probably have to repost it.
107 eibnx_return_rwqe(eibnx_thr_info_t
*info
, eibnx_wqe_t
*wqe
)
111 ASSERT(wqe
->qe_type
== ENX_QETYP_RWQE
);
113 mutex_enter(&wqe
->qe_lock
);
116 * We should never need to free an rwqe on completion.
118 ASSERT((wqe
->qe_flags
& ENX_QEFL_RELONCOMP
) == 0);
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
125 wqe
->qe_sgl
.ds_len
= wqe
->qe_bufsz
;
128 * Repost the recv wqe
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
);
136 mutex_exit(&wqe
->qe_lock
);
140 * Release an SWQE that was acquired earlier.
143 eibnx_release_swqe(eibnx_wqe_t
*wqe
)
145 ASSERT(wqe
->qe_type
== ENX_QETYP_SWQE
);
147 mutex_enter(&wqe
->qe_lock
);
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.
154 ASSERT((wqe
->qe_flags
& ENX_QEFL_INUSE
) == ENX_QEFL_INUSE
);
157 mutex_exit(&wqe
->qe_lock
);
161 * Insert the passed child to the head of the queue
164 eibnx_enqueue_child(eibnx_thr_info_t
*info
, eibnx_gw_info_t
*gwi
,
165 char *node_name
, dev_info_t
*dip
)
168 eibnx_child_t
*new_ch
;
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
;
175 mutex_enter(&info
->ti_child_lock
);
178 * Search existing children to see if we already have this
179 * child. If so, simply update its dip and node_name
181 for (ch
= info
->ti_child
; ch
; ch
= ch
->ch_next
) {
182 if (ch
->ch_gwi
->gw_portid
== gwi
->gw_portid
) {
184 if (ch
->ch_node_name
) {
185 kmem_free(ch
->ch_node_name
, MAXNAMELEN
);
187 ch
->ch_node_name
= node_name
;
188 kmem_free(new_ch
, sizeof (eibnx_child_t
));
194 * If not, add the new child to the list of children
196 new_ch
->ch_next
= info
->ti_child
;
197 info
->ti_child
= new_ch
;
199 mutex_exit(&info
->ti_child_lock
);
203 eibnx_update_child(eibnx_thr_info_t
*info
, eibnx_gw_info_t
*gwi
,
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
);
217 mutex_exit(&info
->ti_child_lock
);
219 return (ENX_E_SUCCESS
);
222 mutex_exit(&info
->ti_child_lock
);
224 return (ENX_E_FAILURE
);
228 eibnx_find_child_dip_by_inst(eibnx_thr_info_t
*info
, int inst
)
231 dev_info_t
*dip
= NULL
;
233 mutex_enter(&info
->ti_child_lock
);
234 for (ch
= info
->ti_child
; ch
!= NULL
; ch
= ch
->ch_next
) {
236 if (ddi_get_instance(dip
) == inst
)
239 mutex_exit(&info
->ti_child_lock
);
245 eibnx_find_child_dip_by_gw(eibnx_thr_info_t
*info
, uint16_t gw_portid
)
248 dev_info_t
*dip
= NULL
;
250 mutex_enter(&info
->ti_child_lock
);
251 for (ch
= info
->ti_child
; ch
!= NULL
; ch
= ch
->ch_next
) {
253 if (ch
->ch_gwi
->gw_portid
== gw_portid
)
256 mutex_exit(&info
->ti_child_lock
);
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
267 eibnx_find_gw_in_gwlist(eibnx_thr_info_t
*info
, eibnx_gw_info_t
*gwi
)
269 eibnx_gw_info_t
*lgw
= NULL
;
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
)
276 mutex_exit(&info
->ti_gw_lock
);
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.
291 eibnx_add_gw_to_gwlist(eibnx_thr_info_t
*info
, eibnx_gw_info_t
*gwi
,
292 ibt_wc_t
*wc
, uint8_t *recv_buf
)
294 eibnx_gw_info_t
*new_gwi
;
298 clock_t timeout_usecs
;
301 * For now, we'll simply do KM_NOSLEEP allocation, since this code
302 * is called from within rx processing
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
);
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.
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
));
328 * Initialize gw state and wqe information.
330 new_gwi
->gw_next
= NULL
;
331 new_gwi
->gw_swqe
= wqe
;
332 new_gwi
->gw_state
= gwi
->gw_state
;
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.
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
);
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.
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
);
357 sgid
= info
->ti_pi
->p_sgid_tbl
[0];
358 new_gwi
->gw_addr
.ga_gid
.gid_prefix
=
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
;
367 * Initialize gateway parameters received via the advertisement
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
));
391 * Queue up the new gwi and return it
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
);
402 * Update old data for the gateway in our list with the new data.
405 eibnx_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
)
409 ib_sn_prefix_t new_gw_sn_prefix
;
412 boolean_t changed
= B_FALSE
;
413 boolean_t gw_addr_changed
= B_TRUE
;
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
420 mutex_enter(&info
->ti_gw_lock
);
422 orig_gwi
->gw_state
= new_gwi
->gw_state
;
425 * The guids shouldn't really change for the "same" gateway
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
);
432 orig_gwi
->gw_system_guid
= new_gwi
->gw_system_guid
;
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
);
440 orig_gwi
->gw_guid
= new_gwi
->gw_guid
;
442 gw_addr_changed
= B_TRUE
;
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
);
450 orig_gwi
->gw_adv_period
= new_gwi
->gw_adv_period
;
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
);
458 orig_gwi
->gw_ka_period
= new_gwi
->gw_ka_period
;
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
);
466 orig_gwi
->gw_vnic_ka_period
= new_gwi
->gw_vnic_ka_period
;
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
);
474 orig_gwi
->gw_ctrl_qpn
= new_gwi
->gw_ctrl_qpn
;
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
);
481 orig_gwi
->gw_lid
= new_gwi
->gw_lid
;
483 gw_addr_changed
= B_TRUE
;
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.
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
,
497 orig_gwi
->gw_portid
= new_gwi
->gw_portid
;
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
);
506 orig_gwi
->gw_is_host_adm_vnics
= new_gwi
->gw_is_host_adm_vnics
;
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
);
513 orig_gwi
->gw_sl
= new_gwi
->gw_sl
;
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
);
520 orig_gwi
->gw_n_rss_qpn
= new_gwi
->gw_n_rss_qpn
;
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
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
;
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
);
539 bcopy(new_gwi
->gw_system_name
, orig_gwi
->gw_system_name
,
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
);
548 bcopy(new_gwi
->gw_port_name
, orig_gwi
->gw_port_name
,
549 EIB_GW_PORTNAME_LEN
);
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
);
557 bcopy(new_gwi
->gw_vendor_id
, orig_gwi
->gw_vendor_id
,
563 * See if the subnet prefix for the gateway has changed
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
);
569 sgid
= info
->ti_pi
->p_sgid_tbl
[0];
570 new_gw_sn_prefix
= sgid
.gid_prefix
;
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
);
577 gw_addr_changed
= B_TRUE
;
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.
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
;
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
;
599 mutex_exit(&info
->ti_gw_lock
);
602 *gwi_changed
= changed
;
607 * Queue up a node for EoIB instantiation and wake up the thread
608 * that creates eoib nodes.
611 eibnx_queue_for_creation(eibnx_thr_info_t
*info
, eibnx_gw_info_t
*gwi
)
613 eibnx_t
*ss
= enx_global_ss
;
614 eibnx_nodeq_t
*new_node
;
617 * For now, we'll simply do KM_NOSLEEP allocation, since this
618 * code is called from within rx processing
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
);
628 new_node
->nc_info
= info
;
629 new_node
->nc_gwi
= gwi
;
632 * If the eoib node creation thread is dying (or dead), don't
633 * queue up any more requests for creation
635 mutex_enter(&ss
->nx_nodeq_lock
);
636 if (ss
->nx_nodeq_thr_die
) {
637 kmem_free(new_node
, sizeof (eibnx_nodeq_t
));
639 new_node
->nc_next
= ss
->nx_nodeq
;
640 ss
->nx_nodeq
= new_node
;
641 cv_signal(&ss
->nx_nodeq_cv
);
643 mutex_exit(&ss
->nx_nodeq_lock
);