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 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 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 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 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 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 * 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 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 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 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 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 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 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 * 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