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