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/ksynch.h>
29 #include <sys/conf.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/sunndi.h>
33
34 #include <sys/ib/clients/eoib/enx_impl.h>
35
36 static char *eibnx_make_nodename(eibnx_thr_info_t *, uint16_t);
37
38 /*
39 * This routine is only called when the port-monitor thread is
40 * about to die. Between the time the first mcast solicitation
41 * was done by the port-monitor thread and the time it is asked
42 * to die, a lot of things could've happened and we need to
43 * cleanup all of it.
44 */
45 void
eibnx_cleanup_port_nodes(eibnx_thr_info_t * info)46 eibnx_cleanup_port_nodes(eibnx_thr_info_t *info)
47 {
48 eibnx_t *ss = enx_global_ss;
49 eibnx_nodeq_t *node;
50 eibnx_nodeq_t *prev;
51 eibnx_gw_info_t *gwi;
52 eibnx_gw_info_t *gw_list;
53 eibnx_gw_info_t *nxt_gwi;
54 eibnx_child_t *child;
55 eibnx_child_t *nxt_child;
56 eibnx_child_t *children;
57
58 /*
59 * Since we would've already stopped processing completions for
60 * this thread's work queue, we don't have to worry about requests
61 * coming in for creation of new eoib nodes. However, there may
62 * be pending node creation requests for this port (thr_info)
63 * that we will have to drop.
64 */
65 mutex_enter(&ss->nx_nodeq_lock);
66 prev = NULL;
67 for (node = ss->nx_nodeq; node; node = node->nc_next) {
68 if (node->nc_info != info) {
69 prev = node;
70 } else {
71 if (prev == NULL) {
72 ss->nx_nodeq = node->nc_next;
73 } else {
74 prev->nc_next = node->nc_next;
75 }
76 kmem_free(node, sizeof (eibnx_nodeq_t));
77 }
78 }
79 mutex_exit(&ss->nx_nodeq_lock);
80
81 /*
82 * Now go through the list of all children and free up any
83 * resource we might've allocated; note that the child dips
84 * could've been offlined/removed by now, so we don't do
85 * anything with them.
86 */
87 mutex_enter(&info->ti_child_lock);
88 children = info->ti_child;
89 info->ti_child = NULL;
90 mutex_exit(&info->ti_child_lock);
91
92 for (child = children; child; child = nxt_child) {
93 nxt_child = child->ch_next;
94
95 if (child->ch_node_name) {
96 kmem_free(child->ch_node_name, MAXNAMELEN);
97 }
98 kmem_free(child, sizeof (eibnx_child_t));
99 }
100
101 /*
102 * Return all the swqes we've acquired for the gateway unicast
103 * solicitations, free any address vectors we've allocated and
104 * finally free the gw entries from the list.
105 */
106 mutex_enter(&info->ti_gw_lock);
107 gw_list = info->ti_gw;
108 info->ti_gw = NULL;
109 mutex_exit(&info->ti_gw_lock);
110
111 for (gwi = gw_list; gwi; gwi = nxt_gwi) {
112 nxt_gwi = gwi->gw_next;
113
114 eibnx_release_swqe((eibnx_wqe_t *)(gwi->gw_swqe));
115 if ((gwi->gw_addr).ga_vect) {
116 kmem_free((gwi->gw_addr).ga_vect,
117 sizeof (ibt_adds_vect_t));
118 (gwi->gw_addr).ga_vect = NULL;
119 }
120 mutex_destroy(&gwi->gw_adv_lock);
121
122 kmem_free(gwi, sizeof (eibnx_gw_info_t));
123 }
124 }
125
126 /*
127 * Communicate all the details we received about the gateway (via the
128 * advertisement control message) to the eoib instance we're creating.
129 */
130 void
eibnx_create_node_props(dev_info_t * dip,eibnx_thr_info_t * info,eibnx_gw_info_t * gwi)131 eibnx_create_node_props(dev_info_t *dip, eibnx_thr_info_t *info,
132 eibnx_gw_info_t *gwi)
133 {
134 int ret;
135
136 ret = ndi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_HCA_GUID,
137 info->ti_hca_guid);
138 if (ret != DDI_PROP_SUCCESS) {
139 ENX_DPRINTF_WARN("ndi_prop_update_int64() failed to set "
140 "%s property to 0x%llx for child dip 0x%llx, ret=%d",
141 EIB_PROP_HCA_GUID, info->ti_hca_guid, dip, ret);
142 }
143
144 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_HCA_PORTNUM,
145 info->ti_pi->p_port_num);
146 if (ret != DDI_PROP_SUCCESS) {
147 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
148 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
149 EIB_PROP_HCA_PORTNUM, info->ti_pi->p_port_num, dip, ret);
150 }
151
152 ret = ndi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SYS_GUID,
153 gwi->gw_system_guid);
154 if (ret != DDI_PROP_SUCCESS) {
155 ENX_DPRINTF_WARN("ndi_prop_update_int64() failed to set "
156 "%s property to 0x%llx for child dip 0x%llx, ret=%d",
157 EIB_PROP_GW_SYS_GUID, gwi->gw_system_guid, dip, ret);
158 }
159
160 ret = ndi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_GUID,
161 gwi->gw_guid);
162 if (ret != DDI_PROP_SUCCESS) {
163 ENX_DPRINTF_WARN("ndi_prop_update_int64() failed to set "
164 "%s property to 0x%llx for child dip 0x%llx, ret=%d",
165 EIB_PROP_GW_GUID, gwi->gw_guid, dip, ret);
166 }
167
168 ret = ndi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SN_PREFIX,
169 (gwi->gw_addr).ga_gid.gid_prefix);
170 if (ret != DDI_PROP_SUCCESS) {
171 ENX_DPRINTF_WARN("ndi_prop_update_int64() failed to set "
172 "%s property to 0x%llx for child dip 0x%llx, ret=%d",
173 EIB_PROP_GW_SN_PREFIX, (gwi->gw_addr).ga_gid.gid_prefix,
174 dip, ret);
175 }
176
177 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_ADV_PERIOD,
178 gwi->gw_adv_period);
179 if (ret != DDI_PROP_SUCCESS) {
180 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
181 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
182 EIB_PROP_GW_ADV_PERIOD, gwi->gw_adv_period, dip, ret);
183 }
184
185 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_KA_PERIOD,
186 gwi->gw_ka_period);
187 if (ret != DDI_PROP_SUCCESS) {
188 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
189 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
190 EIB_PROP_GW_KA_PERIOD, gwi->gw_ka_period, dip, ret);
191 }
192
193 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_VNIC_KA_PERIOD,
194 gwi->gw_vnic_ka_period);
195 if (ret != DDI_PROP_SUCCESS) {
196 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
197 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
198 EIB_PROP_VNIC_KA_PERIOD, gwi->gw_vnic_ka_period, dip, ret);
199 }
200
201 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_CTRL_QPN,
202 gwi->gw_ctrl_qpn);
203 if (ret != DDI_PROP_SUCCESS) {
204 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
205 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
206 EIB_PROP_GW_CTRL_QPN, gwi->gw_ctrl_qpn, dip, ret);
207 }
208
209 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_LID,
210 gwi->gw_lid);
211 if (ret != DDI_PROP_SUCCESS) {
212 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
213 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
214 EIB_PROP_GW_LID, gwi->gw_lid, dip, ret);
215 }
216
217 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_PORTID,
218 gwi->gw_portid);
219 if (ret != DDI_PROP_SUCCESS) {
220 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
221 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
222 EIB_PROP_GW_PORTID, gwi->gw_portid, dip, ret);
223 }
224
225 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
226 EIB_PROP_GW_NUM_NET_VNICS, gwi->gw_num_net_vnics);
227 if (ret != DDI_PROP_SUCCESS) {
228 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
229 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
230 EIB_PROP_GW_NUM_NET_VNICS, gwi->gw_num_net_vnics, dip, ret);
231 }
232
233 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_AVAILABLE,
234 gwi->gw_flag_available);
235 if (ret != DDI_PROP_SUCCESS) {
236 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
237 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
238 EIB_PROP_GW_AVAILABLE, gwi->gw_flag_available, dip, ret);
239 }
240
241 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_HOST_VNICS,
242 gwi->gw_is_host_adm_vnics);
243 if (ret != DDI_PROP_SUCCESS) {
244 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
245 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
246 EIB_PROP_GW_HOST_VNICS, gwi->gw_is_host_adm_vnics,
247 dip, ret);
248 }
249
250 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SL,
251 gwi->gw_sl);
252 if (ret != DDI_PROP_SUCCESS) {
253 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
254 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
255 EIB_PROP_GW_SL, gwi->gw_sl, dip, ret);
256 }
257
258 ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_N_RSS_QPN,
259 gwi->gw_n_rss_qpn);
260 if (ret != DDI_PROP_SUCCESS) {
261 ENX_DPRINTF_WARN("ndi_prop_update_int() failed to set "
262 "%s property to 0x%lx for child dip 0x%llx, ret=%d",
263 EIB_PROP_GW_N_RSS_QPN, gwi->gw_n_rss_qpn, dip, ret);
264 }
265
266 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SYS_NAME,
267 (char *)(gwi->gw_system_name));
268 if (ret != DDI_PROP_SUCCESS) {
269 ENX_DPRINTF_WARN("ndi_prop_update_string() failed to set "
270 "%s property to '%s' for child dip 0x%llx, ret=%d",
271 EIB_PROP_GW_SYS_NAME, gwi->gw_system_name, dip, ret);
272 }
273
274 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_PORT_NAME,
275 (char *)(gwi->gw_port_name));
276 if (ret != DDI_PROP_SUCCESS) {
277 ENX_DPRINTF_WARN("ndi_prop_update_string() failed to set "
278 "%s property to '%s' for child dip 0x%llx, ret=%d",
279 EIB_PROP_GW_PORT_NAME, gwi->gw_port_name, dip, ret);
280 }
281
282 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_VENDOR_ID,
283 (char *)(gwi->gw_vendor_id));
284 if (ret != DDI_PROP_SUCCESS) {
285 ENX_DPRINTF_WARN("ndi_prop_update_string() failed to set "
286 "%s property to '%s' for child dip 0x%llx, ret=%d",
287 EIB_PROP_GW_VENDOR_ID, gwi->gw_vendor_id, dip, ret);
288 }
289 }
290
291 int
eibnx_name_child(dev_info_t * child,char * name,size_t namesz)292 eibnx_name_child(dev_info_t *child, char *name, size_t namesz)
293 {
294 char *node_name;
295
296 if ((node_name = ddi_get_parent_data(child)) == NULL) {
297 ENX_DPRINTF_ERR("ddi_get_parent_data(child=0x%llx) "
298 "returned NULL", child);
299 return (DDI_NOT_WELL_FORMED);
300 }
301
302 /*
303 * Skip the name and "@" part in the eoib node path and copy the
304 * address part out to the caller.
305 */
306 (void) strlcpy(name, node_name + strlen(EIB_DRV_NAME) + 1, namesz);
307
308 return (DDI_SUCCESS);
309 }
310
311 /*
312 * Synchronization functions to mark/clear the in-progress status of
313 * bus config/unconfig operations
314 */
315
316 void
eibnx_busop_inprog_enter(eibnx_t * ss)317 eibnx_busop_inprog_enter(eibnx_t *ss)
318 {
319 mutex_enter(&ss->nx_busop_lock);
320
321 while (ss->nx_busop_flags & NX_FL_BUSOP_INPROG)
322 cv_wait(&ss->nx_busop_cv, &ss->nx_busop_lock);
323
324 ss->nx_busop_flags |= NX_FL_BUSOP_INPROG;
325
326 mutex_exit(&ss->nx_busop_lock);
327 }
328
329 void
eibnx_busop_inprog_exit(eibnx_t * ss)330 eibnx_busop_inprog_exit(eibnx_t *ss)
331 {
332 mutex_enter(&ss->nx_busop_lock);
333
334 ss->nx_busop_flags &= (~NX_FL_BUSOP_INPROG);
335
336 cv_broadcast(&ss->nx_busop_cv);
337 mutex_exit(&ss->nx_busop_lock);
338 }
339
340 eibnx_thr_info_t *
eibnx_start_port_monitor(eibnx_hca_t * hca,eibnx_port_t * port)341 eibnx_start_port_monitor(eibnx_hca_t *hca, eibnx_port_t *port)
342 {
343 eibnx_thr_info_t *ti;
344 kthread_t *kt;
345 dev_info_t *hca_dip;
346 const char *hca_drv_name;
347 int hca_drv_inst;
348
349 ti = kmem_zalloc(sizeof (eibnx_thr_info_t), KM_SLEEP);
350
351 mutex_init(&ti->ti_mcg_lock, NULL, MUTEX_DRIVER, NULL);
352 mutex_init(&ti->ti_gw_lock, NULL, MUTEX_DRIVER, NULL);
353 mutex_init(&ti->ti_child_lock, NULL, MUTEX_DRIVER, NULL);
354 mutex_init(&ti->ti_event_lock, NULL, MUTEX_DRIVER, NULL);
355 cv_init(&ti->ti_event_cv, NULL, CV_DEFAULT, NULL);
356
357 ti->ti_next = NULL;
358 ti->ti_hca_guid = hca->hc_guid;
359 ti->ti_hca = hca->hc_hdl;
360 ti->ti_pd = hca->hc_pd;
361 ti->ti_pi = port->po_pi;
362 ti->ti_ident = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
363
364 /*
365 * Prepare the "ident" for EoIB nodes from this port monitor. To
366 * associate eoib instances with the corresponding HCA nodes easily,
367 * and to make sure eoib instance numbers do not change when
368 * like-for-like HCA replacements are made, tie up the ident to
369 * HCA driver name, HCA driver instance and the HCA port number.
370 * The eoib node address is later composed using this ident and
371 * the gateway port ids after discovery.
372 */
373 if ((hca_dip = ibtl_ibnex_hcaguid2dip(ti->ti_hca_guid)) == NULL) {
374 ENX_DPRINTF_WARN("ibtl_ibnex_hcaguid2dip(hca_guid=0x%llx) "
375 "returned NULL", ti->ti_hca_guid);
376 } else if ((hca_drv_name = ddi_driver_name(hca_dip)) == NULL) {
377 ENX_DPRINTF_WARN("hca driver name NULL for "
378 "hca_guid=0x%llx, hca_dip=0x%llx",
379 ti->ti_hca_guid, hca_dip);
380 } else if ((hca_drv_inst = ddi_get_instance(hca_dip)) < 0) {
381 ENX_DPRINTF_ERR("hca driver instance (%d) invalid for "
382 "hca_guid=0x%llx, hca_dip=0x%llx",
383 ti->ti_hca_guid, hca_dip);
384 } else {
385 (void) snprintf(ti->ti_ident, MAXNAMELEN, "%s%d,%x",
386 hca_drv_name, hca_drv_inst, ti->ti_pi->p_port_num);
387 }
388
389 kt = thread_create(NULL, 0, eibnx_port_monitor,
390 ti, 0, &p0, TS_RUN, minclsyspri);
391
392 ti->ti_kt_did = kt->t_did;
393
394 return (ti);
395 }
396
397 void
eibnx_stop_port_monitor(eibnx_thr_info_t * ti)398 eibnx_stop_port_monitor(eibnx_thr_info_t *ti)
399 {
400 /*
401 * Tell the port monitor thread to stop and wait for it to
402 * happen. Before marking it for death, make sure there
403 * aren't any completions being processed.
404 */
405 mutex_enter(&ti->ti_event_lock);
406 while (ti->ti_event & ENX_EVENT_COMPLETION) {
407 cv_wait(&ti->ti_event_cv, &ti->ti_event_lock);
408 }
409 ti->ti_event |= ENX_EVENT_DIE;
410 cv_broadcast(&ti->ti_event_cv);
411 mutex_exit(&ti->ti_event_lock);
412
413 thread_join(ti->ti_kt_did);
414
415 /*
416 * Destroy synchronization primitives initialized for this ti
417 */
418 cv_destroy(&ti->ti_event_cv);
419 mutex_destroy(&ti->ti_event_lock);
420 mutex_destroy(&ti->ti_child_lock);
421 mutex_destroy(&ti->ti_gw_lock);
422 mutex_destroy(&ti->ti_mcg_lock);
423
424 kmem_free(ti->ti_ident, MAXNAMELEN);
425 kmem_free(ti, sizeof (eibnx_thr_info_t));
426 }
427
428 void
eibnx_terminate_monitors(void)429 eibnx_terminate_monitors(void)
430 {
431 eibnx_t *ss = enx_global_ss;
432 eibnx_thr_info_t *ti_list;
433 eibnx_thr_info_t *ti;
434 eibnx_thr_info_t *ti_next;
435
436 mutex_enter(&ss->nx_lock);
437 ti_list = ss->nx_thr_info;
438 ss->nx_thr_info = NULL;
439 mutex_exit(&ss->nx_lock);
440
441 /*
442 * Ask all the port_monitor threads to die. Before marking them
443 * for death, make sure there aren't any completions being
444 * processed by the thread.
445 */
446 for (ti = ti_list; ti; ti = ti_next) {
447 ti_next = ti->ti_next;
448 eibnx_stop_port_monitor(ti);
449 }
450
451 mutex_enter(&ss->nx_lock);
452 ss->nx_monitors_up = B_FALSE;
453 mutex_exit(&ss->nx_lock);
454 }
455
456 int
eibnx_configure_node(eibnx_thr_info_t * ti,eibnx_gw_info_t * gwi,dev_info_t ** childp)457 eibnx_configure_node(eibnx_thr_info_t *ti, eibnx_gw_info_t *gwi,
458 dev_info_t **childp)
459 {
460 eibnx_t *ss = enx_global_ss;
461 dev_info_t *child_dip;
462 char *node_name;
463 int circular;
464 int ret;
465
466 /*
467 * Prepare the new node's name
468 */
469 if ((node_name = eibnx_make_nodename(ti, gwi->gw_portid)) == NULL)
470 return (ENX_E_FAILURE);
471
472 ndi_devi_enter(ss->nx_dip, &circular);
473
474 if (child_dip = ndi_devi_findchild(ss->nx_dip, node_name)) {
475 ret = eibnx_update_child(ti, gwi, child_dip);
476 if (ret == ENX_E_SUCCESS) {
477 ndi_devi_exit(ss->nx_dip, circular);
478 kmem_free(node_name, MAXNAMELEN);
479
480 if (childp) {
481 *childp = child_dip;
482 }
483 return (ENX_E_SUCCESS);
484 }
485 }
486
487 /*
488 * If the node does not already exist, we may need to create it
489 */
490 if (child_dip == NULL) {
491 ndi_devi_alloc_sleep(ss->nx_dip, EIB_DRV_NAME,
492 (pnode_t)DEVI_SID_NODEID, &child_dip);
493
494 ddi_set_parent_data(child_dip, node_name);
495 eibnx_create_node_props(child_dip, ti, gwi);
496 }
497
498 /*
499 * Whether there was no devinfo node at all for the given node name or
500 * we had a devinfo node, but it wasn't in our list of eoib children,
501 * we'll try to online the instance here.
502 */
503 ENX_DPRINTF_DEBUG("onlining %s", node_name);
504 ret = ndi_devi_online(child_dip, 0);
505 if (ret != NDI_SUCCESS) {
506 ENX_DPRINTF_ERR("ndi_devi_online(node_name=%s) failed "
507 "with ret=0x%x", node_name, ret);
508
509 ddi_set_parent_data(child_dip, NULL);
510 (void) ndi_devi_free(child_dip);
511
512 ndi_devi_exit(ss->nx_dip, circular);
513 kmem_free(node_name, MAXNAMELEN);
514
515 return (ENX_E_FAILURE);
516 }
517
518 eibnx_enqueue_child(ti, gwi, node_name, child_dip);
519
520 ndi_devi_exit(ss->nx_dip, circular);
521
522 if (childp) {
523 *childp = child_dip;
524 }
525
526 return (ENX_E_SUCCESS);
527 }
528
529 int
eibnx_unconfigure_node(eibnx_thr_info_t * ti,eibnx_gw_info_t * gwi)530 eibnx_unconfigure_node(eibnx_thr_info_t *ti, eibnx_gw_info_t *gwi)
531 {
532 /*
533 * To unconfigure an eoib node, we only need to set the child's
534 * dip to NULL. When the node gets configured again, we either
535 * find the dip for the pathname and set it in this child, or
536 * allocate a new dip and set it in this child.
537 */
538 return (eibnx_update_child(ti, gwi, NULL));
539 }
540
541 int
eibnx_locate_node_name(char * devname,eibnx_thr_info_t ** ti_p,eibnx_gw_info_t ** gwi_p)542 eibnx_locate_node_name(char *devname, eibnx_thr_info_t **ti_p,
543 eibnx_gw_info_t **gwi_p)
544 {
545 eibnx_t *ss = enx_global_ss;
546 eibnx_thr_info_t *ti;
547 eibnx_gw_info_t *gwi;
548 char name[MAXNAMELEN];
549
550 /*
551 * Locate the port monitor thread info and gateway info
552 * that corresponds to the supplied devname.
553 */
554 mutex_enter(&ss->nx_lock);
555 for (ti = ss->nx_thr_info; ti; ti = ti->ti_next) {
556 if (ti->ti_ident[0] == '\0')
557 continue;
558
559 mutex_enter(&ti->ti_gw_lock);
560 for (gwi = ti->ti_gw; gwi; gwi = gwi->gw_next) {
561 (void) snprintf(name, MAXNAMELEN,
562 "%s@%s,%x", EIB_DRV_NAME, ti->ti_ident,
563 gwi->gw_portid);
564
565 if (strcmp(name, devname) == 0)
566 break;
567 }
568 mutex_exit(&ti->ti_gw_lock);
569
570 if (gwi) {
571 break;
572 }
573 }
574 mutex_exit(&ss->nx_lock);
575
576 if (ti == NULL || gwi == NULL) {
577 return (ENX_E_FAILURE);
578 }
579
580 *ti_p = ti;
581 *gwi_p = gwi;
582
583 return (ENX_E_SUCCESS);
584 }
585
586 int
eibnx_locate_unconfigured_node(eibnx_thr_info_t ** ti_p,eibnx_gw_info_t ** gwi_p)587 eibnx_locate_unconfigured_node(eibnx_thr_info_t **ti_p, eibnx_gw_info_t **gwi_p)
588 {
589 eibnx_t *ss = enx_global_ss;
590 eibnx_thr_info_t *ti;
591 eibnx_child_t *ch;
592
593 mutex_enter(&ss->nx_lock);
594 for (ti = ss->nx_thr_info; ti; ti = ti->ti_next) {
595 mutex_enter(&ti->ti_child_lock);
596 for (ch = ti->ti_child; ch; ch = ch->ch_next) {
597 if (ch->ch_dip == NULL) {
598 *ti_p = ti;
599 *gwi_p = ch->ch_gwi;
600
601 mutex_exit(&ti->ti_child_lock);
602 mutex_exit(&ss->nx_lock);
603
604 return (ENX_E_SUCCESS);
605 }
606 }
607 mutex_exit(&ti->ti_child_lock);
608 }
609 mutex_exit(&ss->nx_lock);
610
611 return (ENX_E_FAILURE);
612 }
613
614 static char *
eibnx_make_nodename(eibnx_thr_info_t * info,uint16_t gw_portid)615 eibnx_make_nodename(eibnx_thr_info_t *info, uint16_t gw_portid)
616 {
617 char *name;
618
619 if (info->ti_ident[0] == NULL)
620 return (NULL);
621
622 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
623 (void) snprintf(name, MAXNAMELEN, "%s@%s,%x", EIB_DRV_NAME,
624 info->ti_ident, gw_portid);
625
626 return (name);
627 }
628