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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2023 Oxide Computer Company 28 */ 29 30 #include <sys/systm.h> 31 #include <sys/sunndi.h> 32 #include <sys/sunmdi.h> 33 #include <sys/ib/ibtl/impl/ibtl.h> 34 #include <sys/ib/ibtl/impl/ibtl_ibnex.h> 35 36 /* 37 * ibtl_ibnex.c 38 * These routines tie the Device Manager into IBTL. 39 * 40 * ibt_reprobe_dev which can be called by IBTF clients. 41 * This results in calls to IBnexus callback. 42 */ 43 44 /* 45 * Globals. 46 */ 47 static char ibtl_ibnex[] = "ibtl_ibnex"; 48 ibtl_ibnex_callback_t ibtl_ibnex_callback_routine = NULL; 49 50 /* 51 * Function: 52 * ibtl_ibnex_get_hca_info 53 * Input: 54 * hca_guid - The HCA's node GUID. 55 * flag - Tells what to do 56 * IBTL_IBNEX_LIST_CLNTS_FLAG - Build a NVLIST containing 57 * client's names, their AP_IDs and 58 * alternate_HCA information. 59 * (-x list_clients option) 60 * IBTL_IBNEX_UNCFG_CLNTS_FLAG - Build a NVLIST containing 61 * clients' devpaths and their 62 * AP_IDs. (-x unconfig_clients) 63 * callback - Callback function to get ap_id from ib(4D) 64 * Output: 65 * buffer - The information is returned in this buffer 66 * bufsiz - The size of the information buffer 67 * Returns: 68 * IBT_SUCCESS/IBT_HCA_INVALID/IBT_INVALID_PARAM 69 * Description: 70 * For a given HCA node GUID it figures out the registered clients 71 * (ie. ones who called ibt_open_hca(9f) on this GUID) and creates 72 * a NVL packed buffer (of client names/ap_ids or devpaths) and returns 73 * it. If flag is not specified, then an error is returned. 74 */ 75 ibt_status_t 76 ibtl_ibnex_get_hca_info(ib_guid_t hca_guid, int flag, char **buffer, 77 size_t *bufsiz, void (*callback)(dev_info_t *, char **)) 78 { 79 char *node_name; 80 char *ret_apid; 81 nvlist_t *nvl; 82 ibtl_hca_t *ibt_hca; 83 ibtl_clnt_t *clntp; 84 dev_info_t *child; 85 dev_info_t *parent; 86 ibtl_hca_devinfo_t *hca_devp; 87 88 IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_info: " 89 "GUID 0x%llX, flag = 0x%x", hca_guid, flag); 90 91 *buffer = NULL; 92 *bufsiz = 0; 93 94 /* verify that valid "flag" is passed */ 95 if (flag != IBTL_IBNEX_LIST_CLNTS_FLAG && 96 flag != IBTL_IBNEX_UNCFG_CLNTS_FLAG) { 97 return (IBT_INVALID_PARAM); 98 } 99 100 mutex_enter(&ibtl_clnt_list_mutex); 101 102 if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) { 103 mutex_exit(&ibtl_clnt_list_mutex); 104 105 /* 106 * If we are here, then the requested HCA device is not 107 * present. Return the status as Invalid HCA GUID. 108 */ 109 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: " 110 "HCA Not Found, Invalid HCA GUID 0x%llX", hca_guid); 111 return (IBT_HCA_INVALID); 112 } 113 114 /* Walk the client list */ 115 ibt_hca = hca_devp->hd_clnt_list; 116 (void) nvlist_alloc(&nvl, 0, KM_SLEEP); 117 118 /* Allocate memory for ret_apid, instead of using stack */ 119 ret_apid = kmem_alloc(IBTL_IBNEX_APID_LEN, KM_SLEEP); 120 121 while (ibt_hca != NULL) { 122 clntp = ibt_hca->ha_clnt_devp; 123 child = clntp->clnt_dip; 124 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: " 125 "Client = %s", clntp->clnt_modinfop->mi_clnt_name); 126 127 if (flag == IBTL_IBNEX_LIST_CLNTS_FLAG) { 128 (void) nvlist_add_string(nvl, "Client", 129 clntp->clnt_modinfop->mi_clnt_name); 130 131 /* 132 * Always check, first, if this client exists 133 * under this HCA anymore? If not, continue. 134 */ 135 if (clntp->clnt_hca_list == NULL) { 136 (void) nvlist_add_string(nvl, "Alt_HCA", "no"); 137 (void) nvlist_add_string(nvl, "ApID", "-"); 138 ibt_hca = ibt_hca->ha_clnt_link; 139 continue; 140 } 141 142 /* Check if this client has more than one HCAs */ 143 if (clntp->clnt_hca_list->ha_hca_link == NULL) 144 (void) nvlist_add_string(nvl, "Alt_HCA", "no"); 145 else 146 (void) nvlist_add_string(nvl, "Alt_HCA", "yes"); 147 148 if (child == NULL) { 149 (void) nvlist_add_string(nvl, "ApID", "-"); 150 ibt_hca = ibt_hca->ha_clnt_link; 151 continue; 152 } 153 154 /* 155 * All IB clients (IOC, VPPA, Port, Pseudo etc.) 156 * need to be looked at. The parent of IOC nodes 157 * is "ib" nexus and node-name is "ioc". "VPPA/Port"s 158 * should have HCA as parent and node-name is "ibport". 159 * HCA validity is checked by looking at parent's "dip" 160 * and the dip saved in the ibtl_hca_devinfo_t. 161 * NOTE: We only want to list this HCA's IB clients. 162 * All others clients are ignored. 163 */ 164 parent = ddi_get_parent(child); 165 if (parent == NULL || /* No parent? */ 166 ddi_get_parent_data(child) == NULL) { 167 (void) nvlist_add_string(nvl, "ApID", "-"); 168 ibt_hca = ibt_hca->ha_clnt_link; 169 continue; 170 } 171 172 node_name = ddi_node_name(child); 173 if ((strcmp(ddi_node_name(parent), "ib") == 0) || 174 ((hca_devp->hd_hca_dip == parent) && 175 (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) { 176 ASSERT(callback != NULL); 177 /* 178 * Callback is invoked to figure out the 179 * ap_id string. 180 */ 181 callback(child, &ret_apid); 182 (void) nvlist_add_string(nvl, "ApID", ret_apid); 183 } else { 184 (void) nvlist_add_string(nvl, "ApID", "-"); 185 } 186 187 } else if (flag == IBTL_IBNEX_UNCFG_CLNTS_FLAG) { 188 char path[MAXPATHLEN]; 189 190 if (child == NULL) { 191 IBTF_DPRINTF_L4(ibtl_ibnex, 192 "ibtl_ibnex_get_hca_info: No dip exists"); 193 ibt_hca = ibt_hca->ha_clnt_link; 194 continue; 195 } 196 197 /* 198 * if the child has a alternate HCA then skip it 199 */ 200 if (clntp->clnt_hca_list->ha_hca_link) { 201 IBTF_DPRINTF_L4(ibtl_ibnex, 202 "ibtl_ibnex_get_hca_info: Alt HCA exists"); 203 ibt_hca = ibt_hca->ha_clnt_link; 204 continue; 205 } 206 207 /* 208 * See earlier comments on how to check if a client 209 * is IOC, VPPA, Port or a Pseudo node. 210 */ 211 parent = ddi_get_parent(child); 212 if (parent == NULL || /* No parent? */ 213 ddi_get_parent_data(child) == NULL) { 214 IBTF_DPRINTF_L4(ibtl_ibnex, 215 "ibtl_ibnex_get_hca_info: no parent"); 216 ibt_hca = ibt_hca->ha_clnt_link; 217 continue; 218 } 219 220 node_name = ddi_node_name(child); 221 if ((strcmp(ddi_node_name(parent), "ib") == 0) || 222 ((hca_devp->hd_hca_dip == parent) && 223 (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) { 224 ASSERT(callback != NULL); 225 /* 226 * Callback is invoked to figure out the 227 * ap_id string. 228 */ 229 callback(child, &ret_apid); 230 (void) nvlist_add_string(nvl, "ApID", ret_apid); 231 232 /* 233 * ddi_pathname() doesn't supply /devices, 234 * so we do 235 */ 236 (void) strcpy(path, "/devices"); 237 (void) ddi_pathname(child, path + strlen(path)); 238 IBTF_DPRINTF_L4(ibtl_ibnex, 239 "ibtl_ibnex_get_hca_info: " 240 "device path = %s", path); 241 242 if (nvlist_add_string(nvl, "devpath", path)) { 243 IBTF_DPRINTF_L2(ibtl_ibnex, 244 "ibtl_ibnex_get_hca_info: " 245 "failed to fill in path %s", path); 246 mutex_exit(&ibtl_clnt_list_mutex); 247 nvlist_free(nvl); 248 kmem_free(ret_apid, 249 IBTL_IBNEX_APID_LEN); 250 return (ibt_get_module_failure( 251 IBT_FAILURE_IBTL, 0)); 252 } 253 } /* end of if */ 254 } /* end of while */ 255 256 ibt_hca = ibt_hca->ha_clnt_link; 257 } /* End of while */ 258 mutex_exit(&ibtl_clnt_list_mutex); 259 260 kmem_free(ret_apid, IBTL_IBNEX_APID_LEN); 261 262 /* Pack all data into "buffer" */ 263 if (nvlist_pack(nvl, buffer, bufsiz, NV_ENCODE_NATIVE, KM_SLEEP)) { 264 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: " 265 "nvlist_pack failed"); 266 nvlist_free(nvl); 267 return (ibt_get_module_failure(IBT_FAILURE_IBTL, 0)); 268 } 269 270 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: size = %x", 271 *bufsiz); 272 nvlist_free(nvl); 273 return (IBT_SUCCESS); 274 } 275 276 277 /* 278 * Function: 279 * ibtl_ibnex_register_callback() 280 * Input: 281 * ibnex_cb - IB nexus driver callback routine 282 * Output: 283 * none 284 * Returns: 285 * none 286 * Description: 287 * Register a callback routine for IB nexus driver 288 */ 289 void 290 ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb) 291 { 292 IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_register_callback:"); 293 294 mutex_enter(&ibtl_clnt_list_mutex); 295 ibtl_ibnex_callback_routine = ibnex_cb; 296 mutex_exit(&ibtl_clnt_list_mutex); 297 } 298 299 /* 300 * Function: 301 * ibtl_ibnex_unregister_callback() 302 * Input: 303 * none 304 * Output: 305 * none 306 * Returns: 307 * none 308 * Description: 309 * Un-register a callback routine for IB nexus driver 310 */ 311 void 312 ibtl_ibnex_unregister_callback() 313 { 314 IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_unregister_callback: ibnex cb"); 315 316 mutex_enter(&ibtl_clnt_list_mutex); 317 ibtl_ibnex_callback_routine = NULL; 318 mutex_exit(&ibtl_clnt_list_mutex); 319 } 320 321 322 /* 323 * Function: 324 * ibtl_ibnex_hcadip2guid 325 * Input: 326 * dev_info_t - The "dip" of this HCA 327 * Output: 328 * hca_guid - The HCA's node GUID. 329 * Returns: 330 * "HCA GUID" on SUCCESS, NULL on FAILURE 331 * Description: 332 * For a given HCA node GUID it figures out the HCA GUID 333 * and returns it. If not found, NULL is returned. 334 */ 335 ib_guid_t 336 ibtl_ibnex_hcadip2guid(dev_info_t *hca_dip) 337 { 338 ib_guid_t hca_guid = 0LL; 339 ibtl_hca_devinfo_t *hca_devp; 340 341 mutex_enter(&ibtl_clnt_list_mutex); 342 hca_devp = ibtl_hca_list; 343 344 while (hca_devp) { 345 if (hca_devp->hd_hca_dip == hca_dip) { 346 hca_guid = hca_devp->hd_hca_attr->hca_node_guid; 347 break; 348 } 349 hca_devp = hca_devp->hd_hca_dev_link; 350 } 351 mutex_exit(&ibtl_clnt_list_mutex); 352 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcadip_guid: hca_guid 0x%llX", 353 hca_guid); 354 return (hca_guid); 355 } 356 357 358 /* 359 * Function: 360 * ibtl_ibnex_hcaguid2dip 361 * Input: 362 * hca_guid - The HCA's node GUID. 363 * Output: 364 * dev_info_t - The "dip" of this HCA 365 * Returns: 366 * "dip" on SUCCESS, NULL on FAILURE 367 * Description: 368 * For a given HCA node GUID it figures out the "dip" 369 * and returns it. If not found, NULL is returned. 370 */ 371 dev_info_t * 372 ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid) 373 { 374 dev_info_t *dip = NULL; 375 ibtl_hca_devinfo_t *hca_devp; 376 377 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcaguid2dip:"); 378 379 mutex_enter(&ibtl_clnt_list_mutex); 380 hca_devp = ibtl_hca_list; 381 382 while (hca_devp) { 383 if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) { 384 dip = hca_devp->hd_hca_dip; 385 break; 386 } 387 hca_devp = hca_devp->hd_hca_dev_link; 388 } 389 mutex_exit(&ibtl_clnt_list_mutex); 390 return (dip); 391 } 392 393 394 /* 395 * Function: 396 * ibtl_ibnex_get_hca_verbose_data 397 * Input: 398 * hca_guid - The HCA's node GUID. 399 * Output: 400 * buffer - The information is returned in this buffer 401 * bufsiz - The size of the information buffer 402 * Returns: 403 * IBT_SUCCESS/IBT_HCA_INVALID 404 * Description: 405 * For a given HCA node GUID it figures out the verbose listing display. 406 */ 407 ibt_status_t 408 ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid, char **buffer, 409 size_t *bufsiz) 410 { 411 char path[IBTL_IBNEX_STR_LEN]; 412 char tmp[MAXPATHLEN]; 413 uint_t ii; 414 ibt_hca_portinfo_t *pinfop; 415 ibtl_hca_devinfo_t *hca_devp; 416 417 IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: " 418 "HCA GUID 0x%llX", hca_guid); 419 420 *buffer = NULL; 421 *bufsiz = 0; 422 423 mutex_enter(&ibtl_clnt_list_mutex); 424 if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) { 425 mutex_exit(&ibtl_clnt_list_mutex); 426 427 /* 428 * If we are here, then the requested HCA device is not 429 * present. Return the status as Invalid HCA GUID. 430 */ 431 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: " 432 "HCA Not Found, Invalid HCA GUID"); 433 return (IBT_HCA_INVALID); 434 } 435 436 (void) snprintf(tmp, MAXPATHLEN, "VID: 0x%x, PID: 0x%x, #ports: 0x%x", 437 hca_devp->hd_hca_attr->hca_vendor_id, 438 hca_devp->hd_hca_attr->hca_device_id, 439 hca_devp->hd_hca_attr->hca_nports); 440 441 pinfop = hca_devp->hd_portinfop; 442 for (ii = 0; ii < hca_devp->hd_hca_attr->hca_nports; ii++) { 443 (void) snprintf(path, IBTL_IBNEX_STR_LEN, 444 ", port%d GUID: 0x%llX", ii + 1, 445 (longlong_t)pinfop[ii].p_sgid_tbl->gid_guid); 446 (void) strcat(tmp, path); 447 } 448 mutex_exit(&ibtl_clnt_list_mutex); 449 450 *bufsiz = strlen(tmp); 451 *buffer = kmem_alloc(*bufsiz, KM_SLEEP); 452 (void) strncpy(*buffer, tmp, *bufsiz); 453 454 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: " 455 "data = %s, size = 0x%x", *buffer, *bufsiz); 456 return (IBT_SUCCESS); 457 } 458 459 /* 460 * Function: 461 * ibt_reprobe_dev() 462 * Input: 463 * dev_info_t *dip 464 * Output: 465 * none 466 * Returns: 467 * Return value from IBnexus callback handler 468 * IBT_ILLEGAL_OP if IBnexus callback is not installed. 469 * Description: 470 * This function passes the IBTF client's "reprobe device 471 * properties" request to IBnexus. See ibt_reprobe_dev(9f) 472 * for details. 473 */ 474 ibt_status_t 475 ibt_reprobe_dev(dev_info_t *dip) 476 { 477 ibt_status_t rv; 478 ibtl_ibnex_cb_args_t cb_args; 479 480 if (dip == NULL) 481 return (IBT_NOT_SUPPORTED); 482 483 /* 484 * Restricting the reprobe request to the children of 485 * ibnexus. Note the IB_CONF_UPDATE_EVENT DDI event can 486 * be subscribed by any device on the IBnexus device tree. 487 */ 488 if (strcmp(ddi_node_name(ddi_get_parent(dip)), "ib") != 0) 489 return (IBT_NOT_SUPPORTED); 490 491 /* Reprobe for IOC nodes only */ 492 if (strncmp(ddi_node_name(dip), IBNEX_IBPORT_CNAME, 6) == 0) 493 return (IBT_NOT_SUPPORTED); 494 495 cb_args.cb_flag = IBTL_IBNEX_REPROBE_DEV_REQ; 496 cb_args.cb_dip = dip; 497 mutex_enter(&ibtl_clnt_list_mutex); 498 if (ibtl_ibnex_callback_routine) { 499 rv = (*ibtl_ibnex_callback_routine)(&cb_args); 500 mutex_exit(&ibtl_clnt_list_mutex); 501 return (rv); 502 } 503 mutex_exit(&ibtl_clnt_list_mutex); 504 505 /* Should -not- come here */ 506 IBTF_DPRINTF_L2("ibtl", "ibt_reprobe_dev: ibnex not registered!!"); 507 return (IBT_ILLEGAL_OP); 508 } 509 510 511 /* 512 * Function: 513 * ibtl_ibnex_valid_hca_parent 514 * Input: 515 * pdip - The parent dip from client's child dev_info_t 516 * Output: 517 * NONE 518 * Returns: 519 * IBT_SUCCESS/IBT_NO_HCAS_AVAILABLE 520 * Description: 521 * For a given pdip, of Port/VPPA devices, match it against all the 522 * registered HCAs's dip. If match found return IBT_SUCCESS, 523 * else IBT_NO_HCAS_AVAILABLE. 524 * 525 * For IOC/Pseudo devices check if the given pdip is that of 526 * the ib(4D) nexus or that of the eoib(4D) nexus. If yes 527 * return IBT_SUCCESS, else IBT_NO_HCAS_AVAILABLE. 528 */ 529 ibt_status_t 530 ibtl_ibnex_valid_hca_parent(dev_info_t *pdip) 531 { 532 ibtl_hca_devinfo_t *hca_devp; 533 534 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_valid_hca_parent: pdip %p", 535 pdip); 536 537 /* For Pseudo devices and IOCs */ 538 if (strncmp(ddi_node_name(pdip), "ib", 2) == 0 || 539 strncmp(ddi_node_name(pdip), "eibnx", 5) == 0) { 540 return (IBT_SUCCESS); 541 } else { 542 /* For Port devices and VPPAs */ 543 mutex_enter(&ibtl_clnt_list_mutex); 544 hca_devp = ibtl_hca_list; 545 while (hca_devp) { 546 if (hca_devp->hd_hca_dip == pdip) { 547 mutex_exit(&ibtl_clnt_list_mutex); 548 return (IBT_SUCCESS); 549 } 550 hca_devp = hca_devp->hd_hca_dev_link; 551 } 552 mutex_exit(&ibtl_clnt_list_mutex); 553 return (IBT_NO_HCAS_AVAILABLE); 554 } 555 } 556 557 /* 558 * Function: 559 * ibtl_ibnex_phci_register 560 * Input: 561 * hca_dip - The HCA dip 562 * Output: 563 * NONE 564 * Returns: 565 * IBT_SUCCESS/IBT_FAILURE 566 * Description: 567 * Register the HCA dip as the MPxIO PCHI. 568 */ 569 ibt_status_t 570 ibtl_ibnex_phci_register(dev_info_t *hca_dip) 571 { 572 /* Register the with MPxIO as PHCI */ 573 if (mdi_phci_register(MDI_HCI_CLASS_IB, hca_dip, 0) != 574 MDI_SUCCESS) { 575 return (IBT_FAILURE); 576 } 577 return (IBT_SUCCESS); 578 } 579 580 /* 581 * Function: 582 * ibtl_ibnex_phci_unregister 583 * Input: 584 * hca_dip - The HCA dip 585 * Output: 586 * NONE 587 * Returns: 588 * IBT_SUCCESS/IBT_FAILURE 589 * Description: 590 * Free up any pending MPxIO Pathinfos and unregister the HCA dip as the 591 * MPxIO PCHI. 592 */ 593 ibt_status_t 594 ibtl_ibnex_phci_unregister(dev_info_t *hca_dip) 595 { 596 mdi_pathinfo_t *pip = NULL; 597 dev_info_t *vdip = 0; 598 599 /* 600 * Should free all the Pathinfos associated with the HCA pdip before 601 * unregistering the PHCI. 602 * 603 * mdi_pi_free will call ib_vhci_pi_uninit() callbackfor each PI where 604 * the ibnex internal datastructures (ibnex_node_data) will have to be 605 * cleaned up if needed. 606 */ 607 vdip = mdi_devi_get_vdip(hca_dip); 608 ndi_devi_enter(vdip); 609 ndi_devi_enter(hca_dip); 610 while (pip = mdi_get_next_client_path(hca_dip, NULL)) { 611 if (mdi_pi_free(pip, 0) == MDI_SUCCESS) { 612 continue; 613 } 614 ndi_devi_exit(hca_dip); 615 ndi_devi_exit(vdip); 616 IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: " 617 "mdi_pi_free failed"); 618 return (IBT_FAILURE); 619 } 620 ndi_devi_exit(hca_dip); 621 ndi_devi_exit(vdip); 622 623 if (mdi_phci_unregister(hca_dip, 0) != MDI_SUCCESS) { 624 IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: PHCI " 625 "unregister failed"); 626 return (IBT_FAILURE); 627 } 628 return (IBT_SUCCESS); 629 } 630 631 /* 632 * Function: 633 * ibtl_ibnex_query_hca_byguid 634 * Input: 635 * hca_guid - The HCA's node GUID. 636 * driver_name_size- size of the caller allocated driver_name buffer 637 * Output: 638 * hca_attrs - caller allocated buffer which will contain 639 * HCA attributes upon success 640 * driver_name - caller allocated buffer which will contain 641 * HCA driver name upon success 642 * driver_instance - HCA driver instance 643 * hca_device_path - caller allocated buffer of size MAXPATHLEN which 644 * will contain hca device path upon success. 645 * Returns: 646 * IBT_SUCCESS/IBT_FAILURE 647 * Description: 648 * Get the HCA attributes, driver name and instance number of the 649 * specified HCA. 650 */ 651 ibt_status_t 652 ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs, 653 char *driver_name, size_t driver_name_size, int *driver_instance, 654 char *hca_device_path) 655 { 656 ibtl_hca_devinfo_t *hca_devp; 657 658 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_query_hca_byguid(" 659 "hca_guid = 0x%llx, hca_attrs = 0x%p, driver_name = 0x%p, " 660 "driver_name_size = 0x%d, driver_instancep = 0x%p)", hca_guid, 661 hca_attrs, driver_name, (int)driver_name_size, driver_instance); 662 663 mutex_enter(&ibtl_clnt_list_mutex); 664 665 hca_devp = ibtl_get_hcadevinfo(hca_guid); 666 if (hca_devp == NULL) { 667 mutex_exit(&ibtl_clnt_list_mutex); 668 return (IBT_HCA_INVALID); 669 } 670 671 if (strlcpy(driver_name, 672 ddi_driver_name(hca_devp->hd_hca_dip), driver_name_size) >= 673 driver_name_size) { 674 mutex_exit(&ibtl_clnt_list_mutex); 675 return (IBT_INSUFF_KERNEL_RESOURCE); 676 } 677 678 (void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path); 679 *driver_instance = ddi_get_instance(hca_devp->hd_hca_dip); 680 bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t)); 681 682 mutex_exit(&ibtl_clnt_list_mutex); 683 return (IBT_SUCCESS); 684 } 685