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