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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * ibcm_utils.c 28 * 29 * contains internal lookup functions of IB CM module 30 * along with some other miscellaneous stuff 31 * 32 * TBD: 33 * 1. Code needed to ensure that if any clients are using a service then 34 * don't de-register it. 35 */ 36 37 #include <sys/ib/mgt/ibcm/ibcm_impl.h> 38 #include <sys/ddi.h> 39 40 41 /* statics */ 42 static vmem_t *ibcm_local_sid_arena; 43 static vmem_t *ibcm_ip_sid_arena; 44 static ib_svc_id_t ibcm_local_sid_seed; 45 static ib_com_id_t ibcm_local_cid_seed; 46 _NOTE(READ_ONLY_DATA({ibcm_local_sid_arena ibcm_local_sid_seed 47 ibcm_ip_sid_arena ibcm_local_cid_seed})) 48 static void ibcm_delete_state_from_avl(ibcm_state_data_t *statep); 49 static void ibcm_init_conn_trace(ibcm_state_data_t *statep); 50 static void ibcm_fini_conn_trace(ibcm_state_data_t *statep); 51 static void ibcm_dump_conn_trbuf(void *statep, char *line_prefix, 52 char *buf, int buf_size); 53 extern ibt_status_t ibcm_get_node_rec(ibmf_saa_handle_t, sa_node_record_t *, 54 uint64_t c_mask, void *, size_t *); 55 56 /* 57 * ibcm_lookup_msg: 58 * 59 * Retrieves an existing state structure or creates a new one if none found. 60 * This function is used during 61 * Passive connection side for INCOMING REQ/REJ/RTU/MRA/DREQ/DREP/LAP msgs 62 * Active connection side for INCOMING REP/REJ/MRA/DREQ/DREP/APR msgs 63 * Active side CM for outgoing REQ message. 64 * 65 * NOTE: Only return IBCM_LOOKUP_FAIL if lookup failed to find a match. 66 * 67 * Arguments are:- 68 * event_type - type of message 69 * incoming REQ, REP, REJ, MRA, RTU 70 * remote_qpn - Remote QP number 71 * comid - local/remote comid 72 * remote_hca_guid - Remote HCA GUID 73 * hcap - HCA entry ptr 74 * rstatep - return statep pointer 75 * 76 * Return Values: 77 * IBCM_LOOKUP_NEW - new statep allocated 78 * IBCM_LOOKUP_EXISTS - found an existing entry 79 * IBCM_LOOKUP_FAIL - No lookup entry found 80 * IBCM_MEMORY_FAILURE - Memory allocs failed 81 */ 82 ibcm_status_t 83 ibcm_lookup_msg(ibcm_event_type_t event_type, ib_com_id_t comid, 84 ib_qpn_t remote_qpn, ib_guid_t remote_hca_guid, ibcm_hca_info_t *hcap, 85 ibcm_state_data_t **rstatep) 86 { 87 avl_index_t where; 88 ibcm_state_data_t *sp; 89 90 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: event = 0x%x, comid = 0x%x", 91 event_type, comid); 92 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: rem_qpn = 0x%lX, " 93 "rem_hca_guid = 0x%llX", remote_qpn, remote_hca_guid); 94 95 ASSERT(rw_lock_held(&hcap->hca_state_rwlock)); 96 97 /* 98 * Lookup in "hca_passive_tree" for IBCM_INCOMING_REQ and 99 * IBCM_INCOMING_REP_STALE; 100 * 101 * Lookup in "hca_passive_comid_tree" for IBCM_INCOMING_REQ_STALE 102 * 103 * All other lookups in "hca_active_tree". 104 * 105 * NOTE: "hca_active_tree" lookups are based on the local comid. 106 * "hca_passive_state_tree" lookups are based on remote QPN 107 * and remote hca GUID. 108 * 109 * Call avl_find to lookup in the respective tree and save result in 110 * "sp". If "sp" is null it implies that no match was found. If so, 111 * allocate a new ibcm_state_data_t and insert it into the AVL tree(s). 112 */ 113 if ((event_type == IBCM_INCOMING_REQ) || 114 (event_type == IBCM_INCOMING_REP_STALE)) { 115 ibcm_passive_node_info_t info; 116 117 info.info_qpn = remote_qpn; 118 info.info_hca_guid = remote_hca_guid; 119 120 /* Lookup based on Remote QPN and Remote GUID in Passive Tree */ 121 sp = avl_find(&hcap->hca_passive_tree, &info, &where); 122 } else if ((event_type == IBCM_INCOMING_REQ_STALE) || 123 (event_type == IBCM_INCOMING_REJ_RCOMID)) { 124 ibcm_passive_comid_node_info_t info; 125 126 info.info_comid = comid; 127 info.info_hca_guid = remote_hca_guid; 128 129 /* Lookup based on Remote COMID in Passive Tree */ 130 sp = avl_find(&hcap->hca_passive_comid_tree, &info, &where); 131 } else { /* any other event including IBCM_OUTGOING_REQ */ 132 /* Lookup based on Local comid in Active Tree */ 133 sp = avl_find(&hcap->hca_active_tree, &comid, &where); 134 } 135 136 /* matching entry found !! */ 137 if (sp != NULL) { 138 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: match found " 139 "statep = %p", sp); 140 if (event_type == IBCM_INCOMING_REQ) 141 kmem_free(*rstatep, sizeof (ibcm_state_data_t)); 142 *rstatep = sp; /* return the matched statep */ 143 144 mutex_enter(&(sp->state_mutex)); 145 IBCM_REF_CNT_INCR(sp); /* increment the ref count */ 146 mutex_exit(&(sp->state_mutex)); 147 148 return (IBCM_LOOKUP_EXISTS); 149 } 150 151 /* 152 * If we came here then it implies that CM didn't 153 * find a matching entry. We will create a new entry in avl tree, 154 * if event_type is INCOMING/OUTGOING REQ, REQ_STALE/REP_STALE. 155 * statep is created for INCOMING/OUTGOING REQ. 156 * For all other event_types we return lookup failure 157 */ 158 if (!((event_type == IBCM_INCOMING_REQ) || 159 (event_type == IBCM_INCOMING_REQ_STALE) || 160 (event_type == IBCM_INCOMING_REP_STALE) || 161 (event_type == IBCM_OUTGOING_REQ))) { 162 IBTF_DPRINTF_L2(cmlog, "ibcm_lookup_msg: failed for " 163 "event type %x remote_comid = 0x%x", 164 event_type, comid); 165 166 return (IBCM_LOOKUP_FAIL); 167 } 168 169 if ((event_type == IBCM_INCOMING_REQ) || 170 (event_type == IBCM_OUTGOING_REQ)) { 171 172 /* fill in the new ibcm_state_data */ 173 sp = *rstatep; 174 175 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp)) 176 177 /* initialize statep */ 178 mutex_init(&sp->state_mutex, NULL, MUTEX_DEFAULT, NULL); 179 cv_init(&sp->block_client_cv, NULL, CV_DRIVER, NULL); 180 cv_init(&sp->block_mad_cv, NULL, CV_DRIVER, NULL); 181 182 sp->hcap = hcap; 183 IBCM_REF_CNT_INCR(sp); 184 sp->local_comid = comid; 185 186 if (ibcm_enable_trace != 0) 187 ibcm_init_conn_trace(sp); 188 189 if (event_type == IBCM_INCOMING_REQ) { /* Passive side */ 190 sp->state = IBCM_STATE_REQ_RCVD; 191 sp->clnt_proceed = IBCM_BLOCK; 192 sp->close_nocb_state = IBCM_UNBLOCK; 193 sp->remote_hca_guid = remote_hca_guid; 194 sp->remote_qpn = remote_qpn; 195 196 } else if (event_type == IBCM_OUTGOING_REQ) { /* Active side */ 197 sp->close_nocb_state = IBCM_UNBLOCK; 198 sp->state = IBCM_STATE_IDLE; 199 } 200 201 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp)) 202 203 } else { 204 sp = *rstatep; /* for incoming REQ/REP STALE only */ 205 } 206 207 if ((event_type == IBCM_INCOMING_REQ) || 208 (event_type == IBCM_INCOMING_REP_STALE)) { 209 210 /* First, insert a new "sp" into "hca_passive_tree" @ "where" */ 211 avl_insert(&(hcap->hca_passive_tree), (void *)sp, where); 212 213 if (event_type == IBCM_INCOMING_REQ) { /* Only INCOMING_REQ */ 214 /* 215 * We have to do an avl_find() to figure out 216 * "where" to insert the statep into the active tree. 217 * 218 * CM doesn't care for avl_find's retval. 219 */ 220 (void) avl_find(&hcap->hca_active_tree, 221 &sp->local_comid, &where); 222 223 /* Next, insert the "sp" into "hca_active_tree" */ 224 avl_insert(&hcap->hca_active_tree, (void *)sp, where); 225 } 226 } else if (event_type == IBCM_INCOMING_REQ_STALE) { 227 avl_insert(&(hcap->hca_passive_comid_tree), (void *)sp, where); 228 } else { /* IBCM_OUTGOING_REQ */ 229 /* Insert the new sp only into "hca_active_tree", @ "where" */ 230 avl_insert(&(hcap->hca_active_tree), (void *)sp, where); 231 } 232 233 return (IBCM_LOOKUP_NEW); /* return new lookup */ 234 } 235 236 237 /* 238 * ibcm_active_node_compare: 239 * - AVL active tree node compare 240 * 241 * Arguments: 242 * p1 : pointer to local comid 243 * p2 : pointer to passed ibcm_state_data_t 244 * 245 * Return values: 246 * 0 : match found 247 * -1 : no match but insert to left side of the tree 248 * +1 : no match but insert to right side of the tree 249 */ 250 int 251 ibcm_active_node_compare(const void *p1, const void *p2) 252 { 253 ib_com_id_t *local_comid = (ib_com_id_t *)p1; 254 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2; 255 256 IBTF_DPRINTF_L5(cmlog, "ibcm_active_node_compare: " 257 "comid: 0x%x, statep: 0x%p", *local_comid, statep); 258 259 if (*local_comid > statep->local_comid) { 260 return (+1); 261 } else if (*local_comid < statep->local_comid) { 262 return (-1); 263 } else { 264 return (0); 265 } 266 } 267 268 269 /* 270 * ibcm_passive_node_compare: 271 * - AVL passive tree node compare (passive side) 272 * 273 * Arguments: 274 * p1 : pointer to ibcm_passive_node_info (remote qpn and remote guid) 275 * p2 : pointer to passed ibcm_state_data_t 276 * 277 * Return values: 278 * 0 : match found 279 * -1 : no match but insert to left side of the tree 280 * +1 : no match but insert to right side of the tree 281 */ 282 int 283 ibcm_passive_node_compare(const void *p1, const void *p2) 284 { 285 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2; 286 ibcm_passive_node_info_t *infop = (ibcm_passive_node_info_t *)p1; 287 288 IBTF_DPRINTF_L5(cmlog, "ibcm_passive_node_compare: " 289 "statep: 0x%p, p1: 0x%p", statep, p1); 290 291 /* 292 * PASSIVE SIDE: (REQ, REP, MRA, REJ) 293 * always search by active COMID 294 */ 295 if (infop->info_qpn > statep->remote_qpn) { 296 return (+1); 297 } else if (infop->info_qpn < statep->remote_qpn) { 298 return (-1); 299 } else { 300 if (infop->info_hca_guid < statep->remote_hca_guid) { 301 return (-1); 302 } else if (infop->info_hca_guid > statep->remote_hca_guid) { 303 return (+1); 304 } else { 305 return (0); 306 } 307 } 308 } 309 310 /* 311 * ibcm_passive_comid_node_compare: 312 * - AVL passive comid tree node compare (passive side) 313 * 314 * Arguments: 315 * p1 : pointer to ibcm_passive_comid_node_info 316 * (remote comid and remote guid) 317 * p2 : pointer to passed ibcm_state_data_t 318 * 319 * Return values: 320 * 0 : match found 321 * -1 : no match but insert to left side of the tree 322 * +1 : no match but insert to right side of the tree 323 */ 324 int 325 ibcm_passive_comid_node_compare(const void *p1, const void *p2) 326 { 327 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2; 328 ibcm_passive_comid_node_info_t *infop = 329 (ibcm_passive_comid_node_info_t *)p1; 330 331 IBTF_DPRINTF_L5(cmlog, "ibcm_passive_comid_node_compare: " 332 "statep: 0x%p, p1: 0x%p", statep, p1); 333 334 if (infop->info_comid > statep->remote_comid) { 335 return (+1); 336 } else if (infop->info_comid < statep->remote_comid) { 337 return (-1); 338 } else { 339 if (infop->info_hca_guid < statep->remote_hca_guid) { 340 return (-1); 341 } else if (infop->info_hca_guid > statep->remote_hca_guid) { 342 return (+1); 343 } else { 344 return (0); 345 } 346 } 347 } 348 349 350 void 351 ibcm_delete_state_from_avl(ibcm_state_data_t *statep) 352 { 353 avl_index_t a_where = 0; 354 avl_index_t p_where = 0; 355 avl_index_t pcomid_where = 0; 356 ibcm_hca_info_t *hcap; 357 ibcm_state_data_t *active_nodep, *passive_nodep; 358 ibcm_state_data_t *passive_comid_nodep; 359 ibcm_passive_node_info_t info; 360 ibcm_passive_comid_node_info_t info_comid; 361 362 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_from_avl: statep 0x%p", 363 statep); 364 365 if (statep == NULL) { 366 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_state_from_avl: statep" 367 " NULL"); 368 return; 369 } 370 371 hcap = statep->hcap; 372 373 /* 374 * Once the avl tree lock is acquired, no other thread can increment 375 * ref cnt, until tree lock is exit'ed. Since the statep is removed 376 * from the avl's after acquiring lock below, no other thread can 377 * increment the ref cnt after acquiring the lock below 378 */ 379 380 rw_enter(&hcap->hca_state_rwlock, RW_WRITER); 381 382 /* Lookup based on Local comid in the active tree */ 383 active_nodep = avl_find(&hcap->hca_active_tree, &(statep->local_comid), 384 &a_where); 385 386 /* Lookup based on Remote QPN and Remote GUID in the passive tree */ 387 info.info_qpn = statep->remote_qpn; 388 info.info_hca_guid = statep->remote_hca_guid; 389 passive_nodep = avl_find(&hcap->hca_passive_tree, &info, &p_where); 390 391 /* Lookup based on Remote Comid and Remote GUID in the passive tree */ 392 info_comid.info_comid = statep->remote_comid; 393 info_comid.info_hca_guid = statep->remote_hca_guid; 394 passive_comid_nodep = avl_find(&hcap->hca_passive_comid_tree, 395 &info_comid, &pcomid_where); 396 397 /* remove it from the tree, destroy record and the nodep */ 398 if (active_nodep == statep) { 399 avl_remove(&hcap->hca_active_tree, active_nodep); 400 } 401 402 if (passive_nodep == statep) { 403 avl_remove(&hcap->hca_passive_tree, passive_nodep); 404 } 405 406 if (passive_comid_nodep == statep) { 407 avl_remove(&hcap->hca_passive_comid_tree, passive_comid_nodep); 408 } 409 410 rw_exit(&hcap->hca_state_rwlock); 411 } 412 413 /* 414 * ibcm_dealloc_state_data: 415 * Deallocates all buffers and the memory of state structure 416 * This routine can be called on statep that has ref_cnt of 0, and that is 417 * already deleted from the avl tree's 418 * 419 * Arguments are:- 420 * statep - statep to be deleted 421 * 422 * Return Values: NONE 423 */ 424 void 425 ibcm_dealloc_state_data(ibcm_state_data_t *statep) 426 { 427 timeout_id_t timer_val; 428 int dump_trace; 429 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: statep 0x%p", statep); 430 431 if (statep == NULL) { 432 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_state_data: statep NULL"); 433 return; 434 } 435 436 /* ref_cnt is 0 */ 437 /* If timer is running - expire it */ 438 mutex_enter(&statep->state_mutex); 439 timer_val = statep->timerid; 440 if (timer_val != 0) { 441 statep->timerid = 0; 442 mutex_exit(&statep->state_mutex); 443 (void) untimeout(timer_val); 444 } else 445 mutex_exit(&statep->state_mutex); 446 447 /* release the ref cnt on the associated ibmf qp */ 448 if (statep->stored_reply_addr.cm_qp_entry != NULL) 449 ibcm_release_qp(statep->stored_reply_addr.cm_qp_entry); 450 451 if (statep->stored_msg != NULL) 452 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, 453 &statep->stored_msg); 454 455 if (statep->dreq_msg != NULL) 456 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, 457 &statep->dreq_msg); 458 459 if (statep->drep_msg != NULL) 460 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, 461 &statep->drep_msg); 462 463 if (statep->mra_msg != NULL) 464 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, 465 &statep->mra_msg); 466 467 if (statep->lapr_msg != NULL) 468 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl, 469 &statep->lapr_msg); 470 471 if (statep->defer_cm_msg != NULL) 472 kmem_free(statep->defer_cm_msg, IBCM_MSG_SIZE); 473 474 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: done for sp = 0x%p", 475 statep); 476 477 /* Ensure the thread doing ref cnt decr releases the mutex */ 478 mutex_enter(&statep->state_mutex); 479 dump_trace = statep->cm_retries > 0; 480 mutex_exit(&statep->state_mutex); 481 482 /* 483 * now call the mutex_destroy() and cv_destroy() 484 */ 485 mutex_destroy(&statep->state_mutex); 486 487 cv_destroy(&statep->block_client_cv); 488 cv_destroy(&statep->block_mad_cv); 489 490 /* free the comid */ 491 ibcm_free_comid(statep->hcap, statep->local_comid); 492 493 /* Decrement the resource on hcap */ 494 ibcm_dec_hca_res_cnt(statep->hcap); 495 496 /* dump the trace data into ibtf_debug_buf */ 497 if ((ibcm_enable_trace & 4) || dump_trace) 498 ibcm_dump_conn_trace(statep); 499 500 ibcm_fini_conn_trace(statep); 501 502 /* free the statep */ 503 kmem_free(statep, sizeof (ibcm_state_data_t)); 504 } 505 506 /* 507 * ibcm_delete_state_data: 508 * Deletes the state from avl trees, and tries to deallocate state 509 * 510 * Arguments are:- 511 * statep - statep to be deleted 512 * 513 * Return Values: NONE 514 */ 515 void 516 ibcm_delete_state_data(ibcm_state_data_t *statep) 517 { 518 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data:"); 519 520 ibcm_delete_state_from_avl(statep); 521 522 /* Must acquire the state mutex to set delete_state_data */ 523 mutex_enter(&statep->state_mutex); 524 if (statep->ref_cnt > 0) { 525 statep->delete_state_data = B_TRUE; 526 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data: statep 0x%p " 527 "ref_cnt = %x", statep, statep->ref_cnt); 528 mutex_exit(&statep->state_mutex); 529 return; 530 } 531 mutex_exit(&statep->state_mutex); 532 533 ibcm_dealloc_state_data(statep); 534 } 535 536 /* 537 * ibcm_find_sidr_entry: 538 * Routines for CM SIDR state structure list manipulation. 539 * Finds an entry based on lid, gid and grh exists fields 540 * 541 * INPUTS: 542 * lid: LID of incoming SIDR REQ 543 * gid: GID of incoming SIDR REQ 544 * grh_exists: TRUE if GRH exists in the incoming SIDR REQ 545 * req_id: Request ID 546 * hcap: CM State table to search for SIDR state structure 547 * statep: Returns a valid state structure, if one exists based 548 * on lid, gid and grh_exists fields 549 * flag: IBCM_FLAG_LOOKUP - just lookup 550 * IBCM_FLAG_LOOKUP_AND_ADD - if lookup fails, add it. 551 * Return Values: 552 * IBCM_LOOKUP_EXISTS - found an existing entry 553 * IBCM_LOOKUP_FAIL - failed to find an entry 554 * IBCM_LOOKUP_NEW - created a new entry 555 */ 556 ibcm_status_t 557 ibcm_find_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap, 558 ibcm_ud_state_data_t **ud_statep, ibcm_lookup_flag_t flag) 559 { 560 ibcm_status_t status; 561 ibcm_ud_state_data_t *usp; 562 563 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: srch_params are:" 564 "lid=%x, (%llX, %llX), grh: %x, id: %x", 565 srch_param->srch_lid, srch_param->srch_gid.gid_prefix, 566 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists, 567 srch_param->srch_req_id); 568 569 if (flag == IBCM_FLAG_ADD) { 570 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap); 571 return (IBCM_LOOKUP_NEW); 572 } 573 574 usp = hcap->hca_sidr_list; /* Point to the list */ 575 576 /* traverse the list for a matching entry */ 577 while (usp != NULL) { 578 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: " 579 "lid=%x, (%llX, %llX), grh: %x, id: %x", 580 usp->ud_sidr_req_lid, usp->ud_sidr_req_gid.gid_prefix, 581 usp->ud_sidr_req_gid.gid_guid, usp->ud_grh_exists, 582 usp->ud_req_id); 583 584 if ((usp->ud_sidr_req_lid == srch_param->srch_lid) && 585 ((srch_param->srch_gid.gid_prefix == 0) || 586 (srch_param->srch_gid.gid_prefix == 587 usp->ud_sidr_req_gid.gid_prefix)) && 588 ((srch_param->srch_gid.gid_guid == 0) || 589 (srch_param->srch_gid.gid_guid == 590 usp->ud_sidr_req_gid.gid_guid)) && 591 (srch_param->srch_req_id == usp->ud_req_id) && 592 (usp->ud_grh_exists == srch_param->srch_grh_exists) && 593 (usp->ud_mode == srch_param->srch_mode)) { /* found match */ 594 *ud_statep = usp; 595 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: " 596 "found usp = %p", usp); 597 mutex_enter(&usp->ud_state_mutex); 598 IBCM_UD_REF_CNT_INCR(usp); 599 mutex_exit(&usp->ud_state_mutex); 600 601 return (IBCM_LOOKUP_EXISTS); 602 } 603 usp = usp->ud_nextp; 604 } 605 606 /* 607 * If code came here --> it couldn't find a match. 608 * OR 609 * the "hcap->hca_sidr_list" was NULL 610 */ 611 if (flag == IBCM_FLAG_LOOKUP) { 612 IBTF_DPRINTF_L3(cmlog, "ibcm_find_sidr_entry: no match found " 613 "lid=%x, (%llX, %llX), grh: %x, id: %x", 614 srch_param->srch_lid, srch_param->srch_gid.gid_prefix, 615 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists, 616 srch_param->srch_req_id); 617 status = IBCM_LOOKUP_FAIL; 618 } else { 619 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap); 620 status = IBCM_LOOKUP_NEW; 621 } 622 623 return (status); 624 } 625 626 627 /* 628 * ibcm_add_sidr_entry: 629 * Adds a SIDR entry. Called *ONLY* from ibcm_find_sidr_entry() 630 * 631 * INPUTS: 632 * lid: LID of incoming SIDR REQ 633 * gid: GID of incoming SIDR REQ 634 * grh_exists: TRUE if GRH exists in the incoming SIDR REQ 635 * req_id: Request ID 636 * hcap: CM State table to search for SIDR state structure 637 * Return Values: NONE 638 */ 639 ibcm_ud_state_data_t * 640 ibcm_add_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap) 641 { 642 ibcm_ud_state_data_t *ud_statep; 643 644 IBTF_DPRINTF_L5(cmlog, "ibcm_add_sidr_entry: lid=%x, guid=%llX, " 645 "grh = %x req_id = %x", srch_param->srch_lid, 646 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists, 647 srch_param->srch_req_id); 648 649 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep)) 650 651 /* didn't find the entry - so create new */ 652 ud_statep = kmem_zalloc(sizeof (ibcm_ud_state_data_t), KM_SLEEP); 653 654 mutex_init(&ud_statep->ud_state_mutex, NULL, MUTEX_DEFAULT, NULL); 655 cv_init(&ud_statep->ud_block_client_cv, NULL, CV_DRIVER, NULL); 656 657 /* Initialize some ud_statep fields */ 658 mutex_enter(&ud_statep->ud_state_mutex); 659 ud_statep->ud_hcap = hcap; 660 ud_statep->ud_req_id = srch_param->srch_req_id; 661 ud_statep->ud_ref_cnt = 1; 662 ud_statep->ud_grh_exists = srch_param->srch_grh_exists; 663 ud_statep->ud_sidr_req_lid = srch_param->srch_lid; 664 ud_statep->ud_sidr_req_gid = srch_param->srch_gid; 665 ud_statep->ud_mode = srch_param->srch_mode; 666 ud_statep->ud_max_cm_retries = ibcm_max_retries; 667 mutex_exit(&ud_statep->ud_state_mutex); 668 669 /* Update the list */ 670 ud_statep->ud_nextp = hcap->hca_sidr_list; 671 hcap->hca_sidr_list = ud_statep; 672 673 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep)) 674 675 return (ud_statep); 676 } 677 678 679 /* 680 * ibcm_delete_ud_state_data: 681 * Deletes a given state structure 682 * 683 * Arguments are:- 684 * statep - statep to be deleted 685 * 686 * Return Values: NONE 687 */ 688 void 689 ibcm_delete_ud_state_data(ibcm_ud_state_data_t *ud_statep) 690 { 691 ibcm_ud_state_data_t *prevp, *headp; 692 ibcm_hca_info_t *hcap; 693 694 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: ud_statep 0x%p", 695 ud_statep); 696 697 if (ud_statep == NULL || ud_statep->ud_hcap == NULL) { 698 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_ud_state_data: " 699 "ud_statep or hcap is NULL"); 700 return; 701 } 702 703 hcap = ud_statep->ud_hcap; 704 705 rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER); 706 707 /* Next, remove this from the HCA SIDR list */ 708 if (hcap->hca_sidr_list != NULL) { 709 prevp = NULL; 710 headp = hcap->hca_sidr_list; 711 712 while (headp != NULL) { 713 /* delete the matching entry */ 714 if (headp == ud_statep) { 715 if (prevp) { 716 prevp->ud_nextp = headp->ud_nextp; 717 } else { 718 prevp = headp->ud_nextp; 719 hcap->hca_sidr_list = prevp; 720 } 721 break; 722 } 723 prevp = headp; 724 headp = headp->ud_nextp; 725 } 726 } 727 728 rw_exit(&hcap->hca_sidr_list_lock); 729 730 /* 731 * While ref_cnt > 0 732 * - implies someone else is accessing the statep (possibly in 733 * a timeout function handler etc.) 734 * - don't delete statep unless they are done otherwise potentially 735 * one could access released memory and panic. 736 */ 737 mutex_enter(&ud_statep->ud_state_mutex); 738 if (ud_statep->ud_ref_cnt > 0) { 739 ud_statep->ud_delete_state_data = B_TRUE; 740 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: " 741 "ud_statep 0x%p ud_ref_cnt = %x", ud_statep, 742 ud_statep->ud_ref_cnt); 743 mutex_exit(&ud_statep->ud_state_mutex); 744 return; 745 } 746 mutex_exit(&ud_statep->ud_state_mutex); 747 748 ibcm_dealloc_ud_state_data(ud_statep); 749 } 750 751 /* 752 * ibcm_ud_dealloc_state_data: 753 * Deallocates a given ud state structure 754 * 755 * Arguments are:- 756 * ud statep - ud statep to be deleted 757 * 758 * Return Values: NONE 759 */ 760 void 761 ibcm_dealloc_ud_state_data(ibcm_ud_state_data_t *ud_statep) 762 { 763 timeout_id_t timer_val; 764 765 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_ud_state_data: ud_statep 0x%p", 766 ud_statep); 767 768 /* If timer is running - expire it */ 769 mutex_enter(&ud_statep->ud_state_mutex); 770 if (ud_statep->ud_timerid) { 771 timer_val = ud_statep->ud_timerid; 772 ud_statep->ud_timerid = 0; 773 mutex_exit(&ud_statep->ud_state_mutex); 774 (void) untimeout(timer_val); 775 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_ud_state_data: " 776 "Unexpected timer id 0x%p ud_statep 0x%p", timer_val, 777 ud_statep); 778 } else 779 mutex_exit(&ud_statep->ud_state_mutex); 780 781 if (ud_statep->ud_stored_msg != NULL) { 782 (void) ibcm_free_out_msg( 783 ud_statep->ud_stored_reply_addr.ibmf_hdl, 784 &ud_statep->ud_stored_msg); 785 } 786 787 /* release the ref cnt on the associated ibmf qp */ 788 ASSERT(ud_statep->ud_stored_reply_addr.cm_qp_entry != NULL); 789 ibcm_release_qp(ud_statep->ud_stored_reply_addr.cm_qp_entry); 790 791 /* Ensure the thread doing ref cnt decr releases the mutex */ 792 mutex_enter(&ud_statep->ud_state_mutex); 793 mutex_exit(&ud_statep->ud_state_mutex); 794 795 /* now do the mutex_destroy() and cv_destroy() */ 796 mutex_destroy(&ud_statep->ud_state_mutex); 797 798 cv_destroy(&ud_statep->ud_block_client_cv); 799 800 /* free the req id on SIDR REQ sender side */ 801 if (ud_statep->ud_mode == IBCM_ACTIVE_MODE) 802 ibcm_free_reqid(ud_statep->ud_hcap, ud_statep->ud_req_id); 803 804 /* Decrement the resource on hcap */ 805 ibcm_dec_hca_res_cnt(ud_statep->ud_hcap); 806 807 /* free the statep */ 808 kmem_free(ud_statep, sizeof (ibcm_ud_state_data_t)); 809 } 810 811 812 /* 813 * ibcm_init_ids: 814 * Create the vmem arenas for the various global ids 815 * 816 * Arguments are:- 817 * NONE 818 * 819 * Return Values: ibcm_status_t 820 */ 821 822 ibcm_status_t 823 ibcm_init_ids(void) 824 { 825 timespec_t tv; 826 827 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena)) 828 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena)) 829 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed)) 830 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed)) 831 832 ibcm_local_sid_arena = vmem_create("ibcm_local_sid", 833 (void *)IBCM_INITIAL_SID, IBCM_MAX_LOCAL_SIDS, 1, NULL, NULL, NULL, 834 0, VM_SLEEP | VMC_IDENTIFIER); 835 836 if (!ibcm_local_sid_arena) 837 return (IBCM_FAILURE); 838 839 ibcm_ip_sid_arena = vmem_create("ibcm_ip_sid", (void *)IBCM_INITIAL_SID, 840 IBCM_MAX_IP_SIDS, 1, NULL, NULL, NULL, 0, 841 VM_SLEEP | VMC_IDENTIFIER); 842 843 if (!ibcm_ip_sid_arena) 844 return (IBCM_FAILURE); 845 846 /* create a random starting value for local service ids */ 847 gethrestime(&tv); 848 ibcm_local_sid_seed = ((uint64_t)tv.tv_sec << 20) & 0x007FFFFFFFF00000; 849 ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) == 0); 850 ibcm_local_sid_seed |= IB_SID_AGN_LOCAL; 851 852 ibcm_local_cid_seed = (ib_com_id_t)tv.tv_sec; 853 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena)) 854 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed)) 855 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena)) 856 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed)) 857 858 return (IBCM_SUCCESS); 859 } 860 861 862 /* 863 * ibcm_init_hca_ids: 864 * Create the vmem arenas for the various hca level ids 865 * 866 * Arguments are:- 867 * hcap pointer to ibcm_hca_info_t 868 * 869 * Return Values: ibcm_status_t 870 */ 871 ibcm_status_t 872 ibcm_init_hca_ids(ibcm_hca_info_t *hcap) 873 { 874 hcap->hca_comid_arena = vmem_create("ibcm_com_ids", 875 (void *)IBCM_INITIAL_COMID, IBCM_MAX_COMIDS, 876 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); 877 878 if (!hcap->hca_comid_arena) 879 return (IBCM_FAILURE); 880 881 hcap->hca_reqid_arena = vmem_create("ibcm_req_ids", 882 (void *)IBCM_INITIAL_REQID, IBCM_MAX_REQIDS, 883 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); 884 885 if (!hcap->hca_reqid_arena) { 886 vmem_destroy(hcap->hca_comid_arena); 887 return (IBCM_FAILURE); 888 } 889 890 return (IBCM_SUCCESS); 891 } 892 893 /* 894 * ibcm_free_ids: 895 * Destroy the vmem arenas for the various ids 896 * 897 * Arguments are:- 898 * NONE 899 * 900 * Return Values: NONE 901 */ 902 void 903 ibcm_fini_ids(void) 904 { 905 /* All arenas shall be valid */ 906 vmem_destroy(ibcm_local_sid_arena); 907 vmem_destroy(ibcm_ip_sid_arena); 908 } 909 910 /* 911 * ibcm_free_hca_ids: 912 * Destroy the vmem arenas for the various ids 913 * 914 * Arguments are:- 915 * hcap pointer to ibcm_hca_info_t 916 * 917 * Return Values: NONE 918 */ 919 void 920 ibcm_fini_hca_ids(ibcm_hca_info_t *hcap) 921 { 922 /* All arenas shall be valid */ 923 vmem_destroy(hcap->hca_comid_arena); 924 vmem_destroy(hcap->hca_reqid_arena); 925 } 926 927 /* Communication id management routines ie., allocate, free up comids */ 928 929 /* 930 * ibcm_alloc_comid: 931 * Allocate a new communication id 932 * 933 * Arguments are:- 934 * hcap : pointer to ibcm_hca_info_t 935 * comid: pointer to the newly allocated communication id 936 * 937 * Return Values: ibt_status_t 938 */ 939 ibcm_status_t 940 ibcm_alloc_comid(ibcm_hca_info_t *hcap, ib_com_id_t *comidp) 941 { 942 ib_com_id_t comid; 943 944 /* Use next fit, so least recently used com id is allocated */ 945 comid = (ib_com_id_t)(uintptr_t)vmem_alloc(hcap->hca_comid_arena, 1, 946 VM_SLEEP | VM_NEXTFIT); 947 948 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_comid: hcap 0x%p comid 0x%lX", hcap, 949 comid); 950 951 /* 952 * As comid is 32 bits, and maximum connections possible are 2^24 953 * per hca, comid allocation would never fail 954 */ 955 *comidp = comid + ibcm_local_cid_seed; 956 if (comid == 0) { 957 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_comid: hcap 0x%p" 958 "no more comids available", hcap); 959 return (IBCM_FAILURE); 960 } 961 962 return (IBCM_SUCCESS); 963 } 964 965 /* 966 * ibcm_free_comid: 967 * Releases the given Communication Id 968 * 969 * Arguments are: 970 * hcap : pointer to ibcm_hca_info_t 971 * comid : Communication id to be free'd 972 * 973 * Return Values: NONE 974 */ 975 void 976 ibcm_free_comid(ibcm_hca_info_t *hcap, ib_com_id_t comid) 977 { 978 IBTF_DPRINTF_L4(cmlog, "ibcm_free_comid: hcap 0x%p" 979 "comid %x", hcap, comid); 980 comid -= ibcm_local_cid_seed; 981 vmem_free(hcap->hca_comid_arena, (void *)(uintptr_t)comid, 1); 982 } 983 984 /* Allocate and Free local service ids */ 985 986 /* 987 * ibcm_alloc_local_sids: 988 * Create and destroy the vmem arenas for the service ids 989 * 990 * Arguments are:- 991 * Number of contiguous SIDs needed 992 * 993 * Return Values: starting SID 994 */ 995 ib_svc_id_t 996 ibcm_alloc_local_sids(int num_sids) 997 { 998 ib_svc_id_t sid; 999 1000 sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_local_sid_arena, 1001 num_sids, VM_SLEEP | VM_NEXTFIT); 1002 1003 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: ServiceID 0x%llX " 1004 "num_sids %d", sid, num_sids); 1005 if (sid == 0) { 1006 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_local_sids: " 1007 "no more local sids available"); 1008 } else { 1009 ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) == 1010 IB_SID_AGN_LOCAL); 1011 sid += ibcm_local_sid_seed; 1012 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: Success: " 1013 "allocated 0x%llX:%d", sid, num_sids); 1014 } 1015 return (sid); 1016 } 1017 1018 /* 1019 * ibcm_free_local_sids: 1020 * Releases the given Local service id 1021 * 1022 * Arguments are: 1023 * num_sids: Number of local service id's to be free'd 1024 * service_id: Starting local service id that needs to be free'd 1025 * 1026 * Return Values: NONE 1027 */ 1028 void 1029 ibcm_free_local_sids(ib_svc_id_t service_id, int num_sids) 1030 { 1031 service_id -= ibcm_local_sid_seed; 1032 IBTF_DPRINTF_L4(cmlog, "ibcm_free_local_sids: " 1033 "service_id 0x%llX num_sids %d", service_id, num_sids); 1034 vmem_free(ibcm_local_sid_arena, 1035 (void *)(uintptr_t)service_id, num_sids); 1036 } 1037 1038 /* 1039 * ibcm_alloc_ip_sid: 1040 * Allocate a local IP SID. 1041 */ 1042 ib_svc_id_t 1043 ibcm_alloc_ip_sid() 1044 { 1045 ib_svc_id_t sid; 1046 1047 sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_ip_sid_arena, 1, 1048 VM_SLEEP | VM_NEXTFIT); 1049 if (sid == 0) { 1050 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_ip_sid: no more RDMA IP " 1051 "SIDs available"); 1052 } else { 1053 sid += IB_SID_IPADDR_PREFIX; 1054 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_ip_sid: Success: RDMA IP SID" 1055 " allocated : 0x%016llX", sid); 1056 } 1057 return (sid); 1058 } 1059 1060 /* 1061 * ibcm_free_ip_sid: 1062 * Releases the given IP Service ID 1063 */ 1064 void 1065 ibcm_free_ip_sid(ib_svc_id_t sid) 1066 { 1067 sid -= IB_SID_IPADDR_PREFIX; 1068 vmem_free(ibcm_ip_sid_arena, (void *)(uintptr_t)sid, 1); 1069 } 1070 1071 1072 /* Allocate and free request id routines for SIDR */ 1073 1074 /* 1075 * ibcm_alloc_reqid: 1076 * Allocate a new SIDR REQ request id 1077 * 1078 * Arguments are:- 1079 * hcap : pointer to ibcm_hca_info_t 1080 * *reqid : pointer to the new request id returned 1081 * 1082 * Return Values: ibcm_status_t 1083 */ 1084 ibcm_status_t 1085 ibcm_alloc_reqid(ibcm_hca_info_t *hcap, uint32_t *reqid) 1086 { 1087 /* Use next fit, so least recently used com id is allocated */ 1088 *reqid = (uint32_t)(uintptr_t)vmem_alloc(hcap->hca_reqid_arena, 1, 1089 VM_SLEEP | VM_NEXTFIT); 1090 1091 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_reqid: hcap 0x%p reqid %x", hcap, 1092 *reqid); 1093 if (!(*reqid)) { 1094 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_reqid: " 1095 "no more req ids available"); 1096 return (IBCM_FAILURE); 1097 } 1098 return (IBCM_SUCCESS); 1099 } 1100 1101 /* 1102 * ibcm_free_reqid: 1103 * Releases the given SIDR REQ request id 1104 * 1105 * Arguments are: 1106 * hcap : pointer to ibcm_hca_info_t 1107 * reqid : Request id to be free'd 1108 * 1109 * Return Values: NONE 1110 */ 1111 void 1112 ibcm_free_reqid(ibcm_hca_info_t *hcap, uint32_t reqid) 1113 { 1114 IBTF_DPRINTF_L4(cmlog, "ibcm_free_reqid: hcap 0x%p reqid %x", hcap, 1115 reqid); 1116 vmem_free(hcap->hca_reqid_arena, (void *)(uintptr_t)reqid, 1); 1117 } 1118 1119 /* 1120 * ibcm_generate_tranid: 1121 * Generate a new transaction id based on args 1122 * 1123 * Arguments are:- 1124 * event_type CM Message REQ/DREQ/LAP 1125 * id 32 bit identifier 1126 * cm_tran_priv CM private data to be filled in top 28 MSB bits of 1127 * tran id 1128 * 1129 * 1130 * Return Value: uint64_t 1131 */ 1132 uint64_t 1133 ibcm_generate_tranid(uint8_t event, uint32_t id, uint32_t cm_tran_priv) 1134 { 1135 /* 1136 * copy comid to bits 31-0 of tran id, 1137 * attr id to bits 35-32 of tran id, 1138 * cm_priv to bits 63-36 of tran id 1139 */ 1140 if (cm_tran_priv == 0) 1141 /* 1142 * The below ensures that no duplicate transaction id is 1143 * generated atleast for next 6 months. Calculations: 1144 * (2^28)/(1000 * 60 * 24 * 30) = 6 approx 1145 */ 1146 cm_tran_priv = gethrtime() >> 20; /* ~time in ms */ 1147 1148 return ((((uint64_t)cm_tran_priv << 36) | (uint64_t)event << 32) | id); 1149 } 1150 1151 #ifdef DEBUG 1152 1153 /* 1154 * ibcm_decode_tranid: 1155 * Decodes a given transaction id, assuming certain format. 1156 * 1157 * Arguments are:- 1158 * tran_id Transaction id to be decoded 1159 * cm_tran_priv CM private data retrieved from transaction id 1160 * 1161 * Return Value: None 1162 */ 1163 void 1164 ibcm_decode_tranid(uint64_t tran_id, uint32_t *cm_tran_priv) 1165 { 1166 ib_com_id_t id; 1167 ibcm_event_type_t event; 1168 1169 id = tran_id & 0xFFFFFFFF; 1170 event = (tran_id >> 32) & 0xF; 1171 1172 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: id = 0x%x, event = %x", 1173 id, event); 1174 1175 if (cm_tran_priv) { 1176 *cm_tran_priv = tran_id >> 36; 1177 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: " 1178 "cm_tran_priv = %x", *cm_tran_priv); 1179 } 1180 } 1181 1182 #endif 1183 1184 /* 1185 * Service ID entry create and lookup functions 1186 */ 1187 1188 /* 1189 * ibcm_svc_compare: 1190 * - AVL svc tree node compare 1191 * 1192 * Arguments: 1193 * p1 : pointer to local comid 1194 * p2 : pointer to passed ibcm_state_data_t 1195 * 1196 * Return values: 1197 * 0 : match found 1198 * -1 : no match but insert to left side of the tree 1199 * +1 : no match but insert to right side of the tree 1200 */ 1201 int 1202 ibcm_svc_compare(const void *p1, const void *p2) 1203 { 1204 ibcm_svc_lookup_t *sidp = (ibcm_svc_lookup_t *)p1; 1205 ibcm_svc_info_t *svcp = (ibcm_svc_info_t *)p2; 1206 ib_svc_id_t start_sid = sidp->sid; 1207 ib_svc_id_t end_sid = start_sid + sidp->num_sids - 1; 1208 1209 IBTF_DPRINTF_L5(cmlog, "ibcm_svc_compare: " 1210 "sid: 0x%llx, numsids: %d, node_sid: 0x%llx node_num_sids: %d", 1211 sidp->sid, sidp->num_sids, svcp->svc_id, svcp->svc_num_sids); 1212 1213 ASSERT(MUTEX_HELD(&ibcm_svc_info_lock)); 1214 1215 if (svcp->svc_id > end_sid) 1216 return (-1); 1217 if (svcp->svc_id + svcp->svc_num_sids - 1 < start_sid) 1218 return (+1); 1219 return (0); /* means there is some overlap of SIDs */ 1220 } 1221 1222 1223 /* 1224 * ibcm_create_svc_entry: 1225 * Make sure no conflicting entry exists, then allocate it. 1226 * Fill in the critical "look up" details that are provided 1227 * in the arguments before dropping the lock. 1228 * 1229 * Return values: 1230 * Pointer to ibcm_svc_info_t, if created, otherwise NULL. 1231 */ 1232 ibcm_svc_info_t * 1233 ibcm_create_svc_entry(ib_svc_id_t sid, int num_sids) 1234 { 1235 ibcm_svc_info_t *svcp; 1236 ibcm_svc_info_t *svcinfop; 1237 ibcm_svc_lookup_t svc; 1238 avl_index_t where = 0; 1239 1240 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*svcinfop)) 1241 1242 /* assume success, and avoid kmem while holding the writer lock */ 1243 svcinfop = kmem_zalloc(sizeof (*svcinfop), KM_SLEEP); 1244 svcinfop->svc_id = sid; 1245 svcinfop->svc_num_sids = num_sids; 1246 1247 svc.sid = sid; 1248 svc.num_sids = num_sids; 1249 1250 mutex_enter(&ibcm_svc_info_lock); 1251 #ifdef __lock_lint 1252 ibcm_svc_compare(NULL, NULL); 1253 #endif 1254 svcp = avl_find(&ibcm_svc_avl_tree, &svc, &where); 1255 if (svcp != NULL) { /* overlab exists */ 1256 mutex_exit(&ibcm_svc_info_lock); 1257 kmem_free(svcinfop, sizeof (*svcinfop)); 1258 return (NULL); 1259 } 1260 avl_insert(&ibcm_svc_avl_tree, (void *)svcinfop, where); 1261 mutex_exit(&ibcm_svc_info_lock); 1262 1263 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*svcinfop)) 1264 1265 return (svcinfop); 1266 } 1267 1268 /* 1269 * ibcm_find_svc_entry: 1270 * Finds a ibcm_svc_info_t entry into the CM's global table. 1271 * The search done here assumes the list is sorted by SID. 1272 * 1273 * Arguments are: 1274 * sid - Service ID to look up 1275 * 1276 * Return values: 1277 * Pointer to ibcm_svc_info_t, if found, otherwise NULL. 1278 */ 1279 ibcm_svc_info_t * 1280 ibcm_find_svc_entry(ib_svc_id_t sid) 1281 { 1282 ibcm_svc_info_t *svcp; 1283 ibcm_svc_lookup_t svc; 1284 1285 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: finding SID 0x%llX", sid); 1286 1287 ASSERT(MUTEX_HELD(&ibcm_svc_info_lock)); 1288 1289 svc.sid = sid; 1290 svc.num_sids = 1; 1291 #ifdef __lock_lint 1292 ibcm_svc_compare(NULL, NULL); 1293 #endif 1294 svcp = avl_find(&ibcm_svc_avl_tree, &svc, NULL); 1295 if (svcp != NULL) { 1296 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: " 1297 "found SID = 0x%llX", sid); 1298 return (svcp); /* found it */ 1299 } 1300 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: SID %llX not found", sid); 1301 return (NULL); 1302 } 1303 1304 /* 1305 * ibcm_alloc_ibmf_msg: 1306 * Allocate an ibmf message structure and the additional memory required for 1307 * sending an outgoing CM mad. The ibmf message structure contains two 1308 * ibmf_msg_bufs_t fields, one for the incoming MAD and one for the outgoing 1309 * MAD. The CM must allocate the memory for the outgoing MAD. The msg_buf 1310 * field has three buffers: the mad header, the class header, and the class 1311 * data. To simplify the code and reduce the number of kmem_zalloc() calls, 1312 * ibcm_alloc_ibmf_msg will allocate one buffer and set the pointers to the 1313 * right offsets. No class header is needed so only the mad header and class 1314 * data fields are used. 1315 */ 1316 ibt_status_t 1317 ibcm_alloc_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp, 1318 uint8_t method) 1319 { 1320 ib_mad_hdr_t *output_mad_hdr; 1321 int sa_retval; 1322 1323 if ((sa_retval = 1324 ibmf_alloc_msg(ibmf_handle, IBMF_ALLOC_SLEEP, ibmf_msgpp)) != 1325 IBMF_SUCCESS) { 1326 IBTF_DPRINTF_L1(cmlog, "ibcm_alloc_out_msg: " 1327 "ibmf_alloc_msg failed with IBMF_ALLOC_SLEEP"); 1328 return (ibcm_ibmf_analyze_error(sa_retval)); 1329 } 1330 1331 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr = kmem_zalloc( 1332 IBCM_MAD_SIZE, KM_SLEEP); 1333 1334 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data_len = IBCM_MSG_SIZE; 1335 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data = 1336 (uchar_t *)((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr) + 1337 IBCM_MAD_HDR_SIZE; 1338 1339 /* initialize generic CM MAD header fields */ 1340 output_mad_hdr = IBCM_OUT_HDRP((*ibmf_msgpp)); 1341 output_mad_hdr->BaseVersion = IBCM_MAD_BASE_VERSION; 1342 output_mad_hdr->MgmtClass = MAD_MGMT_CLASS_COMM_MGT; 1343 output_mad_hdr->ClassVersion = IBCM_MAD_CLASS_VERSION; 1344 output_mad_hdr->R_Method = method; 1345 1346 return (IBT_SUCCESS); 1347 } 1348 1349 /* 1350 * ibcm_free_ibmf_msg: 1351 * Frees the buffer and ibmf message associated with an outgoing CM message. 1352 * This function should only be used to free messages created by 1353 * ibcm_alloc_out_msg. Will return IBCM_FAILURE if the ibmf_free_msg() call 1354 * fails and IBCM_SUCCESS otherwise. 1355 */ 1356 ibcm_status_t 1357 ibcm_free_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp) 1358 { 1359 int ibmf_status; 1360 1361 kmem_free((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr, 1362 IBCM_MAD_SIZE); 1363 1364 if ((ibmf_status = ibmf_free_msg(ibmf_handle, ibmf_msgpp)) != 1365 IBMF_SUCCESS) { 1366 IBTF_DPRINTF_L2(cmlog, "ibcm_free_out_msg: " 1367 "ibmf_free_msg failed %d", ibmf_status); 1368 return (IBCM_FAILURE); 1369 } else 1370 return (IBCM_SUCCESS); 1371 } 1372 1373 ibcm_qp_list_t * 1374 ibcm_find_qp(ibcm_hca_info_t *hcap, int port_no, ib_pkey_t pkey) 1375 { 1376 ibcm_qp_list_t *entry; 1377 ibmf_qp_handle_t ibmf_qp; 1378 int ibmf_status; 1379 1380 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry)) 1381 1382 mutex_enter(&ibcm_qp_list_lock); 1383 1384 /* 1385 * CM currently does not track port up and down status. If tracking of 1386 * " port status" is added in the future, then CM could be optimized to 1387 * re-use other ports on hcap, if the port associated with the above 1388 * port_no is down. But, the issue of "reachability" needs to be 1389 * handled, before selecting an alternative port different from above. 1390 */ 1391 entry = hcap->hca_port_info[port_no-1].port_qplist; 1392 while (entry != NULL) { 1393 if (entry->qp_pkey == pkey) { 1394 ++entry->qp_ref_cnt; 1395 mutex_exit(&ibcm_qp_list_lock); 1396 return (entry); 1397 } 1398 entry = entry->qp_next; 1399 } 1400 1401 /* 1402 * entry not found, attempt to alloc a qp 1403 * This may be optimized in the future, to allocate ibmf qp's 1404 * once the "CM mgmt pkeys" are precisely known. 1405 */ 1406 ibmf_status = ibmf_alloc_qp( 1407 hcap->hca_port_info[port_no-1].port_ibmf_hdl, pkey, IB_GSI_QKEY, 1408 IBMF_ALT_QP_MAD_NO_RMPP, &ibmf_qp); 1409 1410 if (ibmf_status != IBMF_SUCCESS) { 1411 mutex_exit(&ibcm_qp_list_lock); 1412 IBTF_DPRINTF_L2(cmlog, "ibcm_find_qp: failed to alloc IBMF QP" 1413 "for Pkey = %x port_no = %x status = %d hcaguid = %llXp", 1414 pkey, port_no, ibmf_status, hcap->hca_guid); 1415 /* 1416 * This may be optimized in the future, so as CM would attempt 1417 * to re-use other QP's whose ref cnt is 0 in the respective 1418 * port_qplist, by doing an ibmf_modify_qp with pkey above. 1419 */ 1420 return (NULL); 1421 } 1422 1423 entry = kmem_alloc(sizeof (ibcm_qp_list_t), KM_SLEEP); 1424 entry->qp_next = hcap->hca_port_info[port_no-1].port_qplist; 1425 hcap->hca_port_info[port_no-1].port_qplist = entry; 1426 entry->qp_cm = ibmf_qp; 1427 entry->qp_ref_cnt = 1; 1428 entry->qp_pkey = pkey; 1429 entry->qp_port = &(hcap->hca_port_info[port_no-1]); 1430 1431 mutex_exit(&ibcm_qp_list_lock); 1432 1433 /* set-up the handler */ 1434 ibmf_status = ibmf_setup_async_cb( 1435 hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp, 1436 ibcm_recv_cb, entry, 0); 1437 1438 ASSERT(ibmf_status == IBMF_SUCCESS); 1439 1440 #ifdef DEBUG 1441 ibcm_query_qp(hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp); 1442 #endif 1443 1444 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*entry)) 1445 1446 return (entry); 1447 } 1448 1449 void 1450 ibcm_release_qp(ibcm_qp_list_t *cm_qp_entry) 1451 { 1452 mutex_enter(&ibcm_qp_list_lock); 1453 --cm_qp_entry->qp_ref_cnt; 1454 ASSERT(cm_qp_entry->qp_ref_cnt >= 0); 1455 mutex_exit(&ibcm_qp_list_lock); 1456 } 1457 1458 1459 /* called holding the ibcm_qp_list_lock mutex */ 1460 ibcm_status_t 1461 ibcm_free_qp(ibcm_qp_list_t *cm_qp_entry) 1462 { 1463 int ibmf_status; 1464 1465 IBTF_DPRINTF_L5(cmlog, "ibcm_free_qp: qp_hdl %p ref_cnt %d pkey %x", 1466 cm_qp_entry->qp_cm, cm_qp_entry->qp_ref_cnt, cm_qp_entry->qp_pkey); 1467 1468 /* check, there are no users of this ibmf qp */ 1469 if (cm_qp_entry->qp_ref_cnt != 0) 1470 return (IBCM_FAILURE); 1471 1472 /* Tear down the receive callback */ 1473 ibmf_status = ibmf_tear_down_async_cb( 1474 cm_qp_entry->qp_port->port_ibmf_hdl, cm_qp_entry->qp_cm, 0); 1475 if (ibmf_status != IBMF_SUCCESS) { 1476 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: " 1477 "ibmf_tear_down_async_cb failed %d port_num %d", 1478 ibmf_status, cm_qp_entry->qp_port->port_num); 1479 return (IBCM_FAILURE); 1480 } 1481 1482 ibmf_status = ibmf_free_qp(cm_qp_entry->qp_port->port_ibmf_hdl, 1483 &cm_qp_entry->qp_cm, 0); 1484 if (ibmf_status != IBMF_SUCCESS) { 1485 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: ibmf_free_qp failed for" 1486 " ibmf_status %d qp hdl %p port_no %x", ibmf_status, 1487 cm_qp_entry->qp_cm, cm_qp_entry->qp_port->port_num); 1488 return (IBCM_FAILURE); 1489 } 1490 1491 return (IBCM_SUCCESS); 1492 } 1493 1494 ibcm_status_t 1495 ibcm_free_allqps(ibcm_hca_info_t *hcap, int port_no) 1496 { 1497 ibcm_qp_list_t *entry, *freed; 1498 ibcm_status_t ibcm_status = IBCM_SUCCESS; 1499 1500 IBTF_DPRINTF_L5(cmlog, "ibcm_free_allqps: hcap %p port_no %d", hcap, 1501 port_no); 1502 1503 mutex_enter(&ibcm_qp_list_lock); 1504 entry = hcap->hca_port_info[port_no-1].port_qplist; 1505 while ((entry != NULL) && 1506 ((ibcm_status = ibcm_free_qp(entry)) == IBCM_SUCCESS)) { 1507 freed = entry; 1508 entry = entry->qp_next; 1509 kmem_free(freed, sizeof (ibcm_qp_list_t)); 1510 } 1511 1512 if (ibcm_status != IBCM_SUCCESS) /* sanity the linked list */ 1513 hcap->hca_port_info[port_no-1].port_qplist = entry; 1514 else /* all ibmf qp's of port must have been free'd successfully */ 1515 hcap->hca_port_info[port_no-1].port_qplist = NULL; 1516 1517 mutex_exit(&ibcm_qp_list_lock); 1518 return (ibcm_status); 1519 } 1520 1521 /* 1522 * ibt_bind_service() and ibt_get_paths() needs the following helper function 1523 * to handle endianess in case of Service Data. 1524 */ 1525 void 1526 ibcm_swizzle_from_srv(ibt_srv_data_t *sb_data, uint8_t *service_bytes) 1527 { 1528 uint8_t *p8 = service_bytes; 1529 uint16_t *p16; 1530 uint32_t *p32; 1531 uint64_t *p64; 1532 int i; 1533 1534 for (i = 0; i < 16; i++) 1535 *p8++ = sb_data->s_data8[i]; 1536 1537 p16 = (uint16_t *)p8; 1538 for (i = 0; i < 8; i++) 1539 *p16++ = h2b16(sb_data->s_data16[i]); 1540 1541 p32 = (uint32_t *)p16; 1542 for (i = 0; i < 4; i++) 1543 *p32++ = h2b32(sb_data->s_data32[i]); 1544 1545 p64 = (uint64_t *)p32; 1546 for (i = 0; i < 2; i++) 1547 *p64++ = h2b64(sb_data->s_data64[i]); 1548 } 1549 1550 void 1551 ibcm_swizzle_to_srv(uint8_t *service_bytes, ibt_srv_data_t *sb_data) 1552 { 1553 uint8_t *p8 = service_bytes; 1554 uint16_t *p16; 1555 uint32_t *p32; 1556 uint64_t *p64; 1557 int i; 1558 1559 for (i = 0; i < 16; i++) 1560 sb_data->s_data8[i] = *p8++; 1561 1562 p16 = (uint16_t *)p8; 1563 for (i = 0; i < 8; i++) 1564 sb_data->s_data16[i] = h2b16(*p16++); 1565 1566 p32 = (uint32_t *)p16; 1567 for (i = 0; i < 4; i++) 1568 sb_data->s_data32[i] = h2b32(*p32++); 1569 p64 = (uint64_t *)p32; 1570 1571 for (i = 0; i < 2; i++) 1572 sb_data->s_data64[i] = h2b64(*p64++); 1573 } 1574 1575 /* Trace related functions */ 1576 1577 void 1578 ibcm_init_conn_trace(ibcm_state_data_t *sp) 1579 { 1580 IBTF_DPRINTF_L5(cmlog, "ibcm_init_conn_trace: statep %p", sp); 1581 1582 /* Initialize trace related fields */ 1583 1584 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp->conn_trace)) 1585 sp->conn_trace = kmem_zalloc(sizeof (ibcm_conn_trace_t), KM_SLEEP); 1586 if ((ibcm_enable_trace & 1) == 0) 1587 sp->conn_trace->conn_base_tm = gethrtime(); 1588 sp->conn_trace->conn_allocated_trcnt = ibcm_conn_max_trcnt; 1589 sp->conn_trace->conn_trace_events = 1590 kmem_zalloc(sp->conn_trace->conn_allocated_trcnt, KM_SLEEP); 1591 sp->conn_trace->conn_trace_event_times = 1592 kmem_zalloc(sp->conn_trace->conn_allocated_trcnt * 1593 sizeof (tm_diff_type), KM_SLEEP); 1594 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp->conn_trace)) 1595 } 1596 1597 void 1598 ibcm_fini_conn_trace(ibcm_state_data_t *statep) 1599 { 1600 IBTF_DPRINTF_L5(cmlog, "ibcm_fini_conn_trace: statep %p tracep %p", 1601 statep, statep->conn_trace); 1602 1603 /* free the trace data */ 1604 if (statep->conn_trace) { 1605 if (statep->conn_trace->conn_trace_events) 1606 kmem_free(statep->conn_trace->conn_trace_events, 1607 statep->conn_trace->conn_allocated_trcnt); 1608 if (statep->conn_trace->conn_trace_event_times) 1609 kmem_free(statep->conn_trace->conn_trace_event_times, 1610 statep->conn_trace->conn_allocated_trcnt * 1611 sizeof (tm_diff_type)); 1612 1613 kmem_free(statep->conn_trace, sizeof (ibcm_conn_trace_t)); 1614 } 1615 } 1616 1617 /* mostly used to profile connection establishment times with dtrace */ 1618 void 1619 ibcm_established(hrtime_t time_diff) 1620 { 1621 if (time_diff > 1000000000LL) /* 1 second */ 1622 IBTF_DPRINTF_L2(cmlog, "slow connection time (%d seconds)", 1623 (uint_t)(time_diff >> 30)); 1624 } 1625 1626 void 1627 ibcm_insert_trace(void *statep, ibcm_state_rc_trace_qualifier_t event_qualifier) 1628 { 1629 ibcm_conn_trace_t *conn_trace; 1630 uint8_t conn_trace_ind; 1631 hrtime_t time_diff; 1632 hrtime_t hrt; 1633 1634 if (!(((ibcm_state_data_t *)statep)->conn_trace)) 1635 return; 1636 1637 conn_trace = ((ibcm_state_data_t *)statep)->conn_trace; 1638 1639 if (!conn_trace->conn_trace_events) 1640 return; 1641 1642 IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p event %d", 1643 statep, event_qualifier); 1644 1645 mutex_enter(&ibcm_trace_mutex); 1646 1647 /* No more trace memory available, hence return */ 1648 if (conn_trace->conn_trace_ind == conn_trace->conn_allocated_trcnt) { 1649 mutex_exit(&ibcm_trace_mutex); 1650 return; 1651 } else 1652 ++conn_trace->conn_trace_ind; 1653 1654 conn_trace_ind = conn_trace->conn_trace_ind - 1; 1655 1656 conn_trace->conn_trace_events[conn_trace_ind] = event_qualifier; 1657 1658 if ((ibcm_enable_trace & 1) == 0) { 1659 hrt = gethrtime(); 1660 time_diff = hrt - conn_trace->conn_base_tm; 1661 if (event_qualifier == IBCM_TRACE_CALLED_CONN_EST_EVENT) 1662 ibcm_established(time_diff); 1663 time_diff >>= 10; 1664 if (time_diff >= TM_DIFF_MAX) { 1665 /* RESET, future times are relative to new base time. */ 1666 conn_trace->conn_base_tm = hrt; 1667 time_diff = 0; 1668 } 1669 conn_trace->conn_trace_event_times[conn_trace_ind] = time_diff; 1670 } 1671 1672 mutex_exit(&ibcm_trace_mutex); 1673 1674 IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p inserted event %d", 1675 statep, event_qualifier); 1676 } 1677 1678 void 1679 ibcm_dump_conn_trace(void *statep) 1680 { 1681 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trace: statep %p", 1682 statep); 1683 1684 mutex_enter(&ibcm_trace_print_mutex); 1685 ibcm_debug_buf[0] = '\0'; 1686 ibcm_dump_conn_trbuf(statep, "ibcm: ", ibcm_debug_buf, 1687 IBCM_DEBUG_BUF_SIZE); 1688 if (ibcm_debug_buf[0] != '\0') 1689 IBTF_DPRINTF_L2(cmlog, "\n%s", ibcm_debug_buf); 1690 1691 #ifdef DEBUG 1692 1693 if (ibcm_test_mode > 1) 1694 cmn_err(CE_CONT, "IBCM DEBUG TRACE:\n%s", ibcm_debug_buf); 1695 #endif 1696 1697 mutex_exit(&ibcm_trace_print_mutex); 1698 } 1699 1700 void 1701 ibcm_dump_conn_trbuf(void *statep, char *line_prefix, char *buf, int buf_size) 1702 { 1703 ibcm_conn_trace_t *conn_trace; 1704 int tr_ind; 1705 ibcm_state_data_t *sp; 1706 int cur_size = 0; /* size of item copied */ 1707 int rem_size; /* remaining size in trace buffer */ 1708 int next_data = 0; /* location where next item copied */ 1709 1710 if ((buf == NULL) || (buf_size <= 0)) 1711 return; 1712 1713 sp = (ibcm_state_data_t *)statep; 1714 1715 if (!sp->conn_trace) 1716 return; 1717 1718 conn_trace = sp->conn_trace; 1719 1720 if (!conn_trace->conn_trace_events) 1721 return; 1722 1723 rem_size = buf_size; 1724 1725 /* Print connection level global data */ 1726 1727 /* Print statep, local comid, local qpn */ 1728 cur_size = snprintf(&buf[next_data], rem_size, "%s%s0x%p\n%s%s0x%p\n" 1729 "%s%s0x%x/%llx/%d\n%s%s0x%x\n%s%s0x%x/%llx\n%s%s0x%x\n%s%s%llu\n", 1730 line_prefix, event_str[IBCM_DISPLAY_SID], (void *)sp, 1731 line_prefix, event_str[IBCM_DISPLAY_CHAN], (void *)sp->channel, 1732 line_prefix, event_str[IBCM_DISPLAY_LCID], sp->local_comid, 1733 (longlong_t)sp->local_hca_guid, sp->prim_port, 1734 line_prefix, event_str[IBCM_DISPLAY_LQPN], sp->local_qpn, 1735 line_prefix, event_str[IBCM_DISPLAY_RCID], sp->remote_comid, 1736 (longlong_t)sp->remote_hca_guid, 1737 line_prefix, event_str[IBCM_DISPLAY_RQPN], sp->remote_qpn, 1738 line_prefix, event_str[IBCM_DISPLAY_TM], conn_trace->conn_base_tm); 1739 1740 rem_size = rem_size - cur_size; 1741 if (rem_size <= 0) { 1742 buf[buf_size-1] = '\n'; 1743 return; 1744 } 1745 1746 next_data = next_data + cur_size; 1747 1748 for (tr_ind = 0; tr_ind < conn_trace->conn_trace_ind; tr_ind++) { 1749 cur_size = snprintf(&buf[next_data], rem_size, 1750 "%s%sTM_DIFF %u\n", line_prefix, 1751 event_str[conn_trace->conn_trace_events[tr_ind]], 1752 conn_trace->conn_trace_event_times[tr_ind]); 1753 rem_size = rem_size - cur_size; 1754 if (rem_size <= 0) { 1755 buf[buf_size-1] = '\n'; 1756 return; 1757 } 1758 next_data = next_data + cur_size; 1759 } 1760 1761 buf[next_data] = '\0'; 1762 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trbuf: statep %p " 1763 "debug buf size %d bytes", statep, next_data); 1764 } 1765 1766 1767 #ifdef DEBUG 1768 1769 void 1770 ibcm_query_qp(ibmf_handle_t ibmf_hdl, ibmf_qp_handle_t ibmf_qp) 1771 { 1772 uint8_t qp_port_num; 1773 ib_qpn_t qp_num; 1774 ib_pkey_t qp_pkey; 1775 ib_qkey_t qp_qkey; 1776 int ibmf_status; 1777 1778 if (ibmf_qp == IBMF_QP_HANDLE_DEFAULT) { 1779 IBTF_DPRINTF_L4(cmlog, "ibcm_query_qp: QP1"); 1780 return; 1781 } 1782 1783 ibmf_status = 1784 ibmf_query_qp(ibmf_hdl, ibmf_qp, &qp_num, &qp_pkey, &qp_qkey, 1785 &qp_port_num, 0); 1786 1787 ASSERT(ibmf_status == IBMF_SUCCESS); 1788 1789 IBTF_DPRINTF_L5(cmlog, "ibcm_query_qp: qpn %x qkey %x pkey %x port %d", 1790 qp_num, qp_qkey, qp_pkey, qp_port_num); 1791 } 1792 1793 /* 1794 * ibcm_dump_raw_message: 1795 * dumps 256 bytes of data of a raw message (REP/REQ/DREQ ...) 1796 * (can be called from the kernel debugger w/ the message pointer) 1797 * 1798 * Arguments: 1799 * msgp - the messages that needs to be dumped 1800 * 1801 * Return values: NONE 1802 */ 1803 void 1804 ibcm_dump_raw_message(uchar_t *c) 1805 { 1806 int i; 1807 1808 for (i = 0; i < IBCM_MAD_SIZE; i += 16) { 1809 /* print in batches of 16 chars at a time */ 1810 IBTF_DPRINTF_L4(cmlog, 1811 "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", 1812 c[i], c[i + 1], c[i + 2], c[i + 3], c[i + 4], c[i + 5], 1813 c[i + 6], c[i + 7], c[i + 8], c[i + 9], c[i + 10], 1814 c[i + 11], c[i + 12], c[i + 13], c[i + 14], c[i + 15]); 1815 } 1816 } 1817 1818 1819 /* 1820 * ibcm_dump_srv_rec: 1821 * Dumps Service Records. 1822 * 1823 * Arguments: 1824 * srv_rec - the pointer to sa_service_record_t struct. 1825 * 1826 * Return values: NONE 1827 */ 1828 void 1829 ibcm_dump_srvrec(sa_service_record_t *srv_rec) 1830 { 1831 uint8_t i; 1832 1833 IBTF_DPRINTF_L4(cmlog, "ibcm_dump_srvrec: Service Records"); 1834 IBTF_DPRINTF_L4(cmlog, "SID : 0x%016llX", srv_rec->ServiceID); 1835 IBTF_DPRINTF_L4(cmlog, "Svc GID : 0x%016llX:0x%016llX", 1836 srv_rec->ServiceGID.gid_prefix, srv_rec->ServiceGID.gid_guid); 1837 IBTF_DPRINTF_L4(cmlog, "Svc PKey : 0x%X", srv_rec->ServiceP_Key); 1838 1839 IBTF_DPRINTF_L4(cmlog, "Svc Lease : 0x%lX", srv_rec->ServiceLease); 1840 IBTF_DPRINTF_L4(cmlog, "Svc Key-hi: 0x%016llX", srv_rec->ServiceKey_hi); 1841 IBTF_DPRINTF_L4(cmlog, "Svc Key-lo: 0x%016llX", srv_rec->ServiceKey_lo); 1842 IBTF_DPRINTF_L4(cmlog, "Svc Name : %s", srv_rec->ServiceName); 1843 IBTF_DPRINTF_L4(cmlog, "Svc Data : "); 1844 for (i = 0; i < IB_SVC_DATA_LEN; i += 8) { 1845 IBTF_DPRINTF_L4(cmlog, 1846 "\t 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X", 1847 srv_rec->ServiceData[i], srv_rec->ServiceData[i+1], 1848 srv_rec->ServiceData[i+2], srv_rec->ServiceData[i+3], 1849 srv_rec->ServiceData[i+4], srv_rec->ServiceData[i+5], 1850 srv_rec->ServiceData[i+6], srv_rec->ServiceData[i+7]); 1851 } 1852 } 1853 1854 1855 /* 1856 * ibcm_dump_pathrec: 1857 * Dumps Path Records. 1858 * 1859 * Arguments: 1860 * path_rec - the pointer to sa_path_record_t struct. 1861 * 1862 * Return values: NONE 1863 */ 1864 void 1865 ibcm_dump_pathrec(sa_path_record_t *path_rec) 1866 { 1867 IBTF_DPRINTF_L5(cmlog, "Path Record:"); 1868 IBTF_DPRINTF_L5(cmlog, "SGID: (sn_prefix) %016llX", 1869 path_rec->SGID.gid_prefix); 1870 IBTF_DPRINTF_L5(cmlog, "SGID: (GUID) %016llX", 1871 path_rec->SGID.gid_guid); 1872 IBTF_DPRINTF_L5(cmlog, "DGID: (sn_prefix) %016llX", 1873 path_rec->DGID.gid_prefix); 1874 IBTF_DPRINTF_L5(cmlog, "DGID: (GUID) %016llX", 1875 path_rec->DGID.gid_guid); 1876 IBTF_DPRINTF_L5(cmlog, "SLID: %04X", path_rec->SLID); 1877 IBTF_DPRINTF_L5(cmlog, "DLID: %04X", path_rec->DLID); 1878 IBTF_DPRINTF_L5(cmlog, "Raw Traffic: %01X", path_rec->RawTraffic); 1879 IBTF_DPRINTF_L5(cmlog, "Flow Label: %05X", path_rec->FlowLabel); 1880 IBTF_DPRINTF_L5(cmlog, "Hop Limit: %02X", path_rec->HopLimit); 1881 IBTF_DPRINTF_L5(cmlog, "TClass: %02X", path_rec->TClass); 1882 IBTF_DPRINTF_L5(cmlog, "Reversible: %01X", path_rec->Reversible); 1883 IBTF_DPRINTF_L5(cmlog, "Numb Paths: %02d", path_rec->NumbPath); 1884 IBTF_DPRINTF_L5(cmlog, "P_Key: %04X", path_rec->P_Key); 1885 IBTF_DPRINTF_L5(cmlog, "SL: %02X", path_rec->SL); 1886 IBTF_DPRINTF_L5(cmlog, "Path MTU Selector: %01X", 1887 path_rec->MtuSelector); 1888 IBTF_DPRINTF_L5(cmlog, "Path MTU: %02X", path_rec->Mtu); 1889 IBTF_DPRINTF_L5(cmlog, "Path Rate Selector:%01X", 1890 path_rec->RateSelector); 1891 IBTF_DPRINTF_L5(cmlog, "Path Rate: %02X", path_rec->Rate); 1892 IBTF_DPRINTF_L5(cmlog, "Packet LT Selector:%01X", 1893 path_rec->PacketLifeTimeSelector); 1894 IBTF_DPRINTF_L5(cmlog, "Packet Life Time: %d (dec)", 1895 path_rec->PacketLifeTime); 1896 IBTF_DPRINTF_L5(cmlog, "Preference Bit: %02X", path_rec->Preference); 1897 } 1898 1899 /* 1900 * ibcm_dump_node_rec: 1901 * Dumps Node Records. 1902 * 1903 * Arguments: 1904 * nrec - the pointer to sa_node_record_t struct. 1905 * 1906 * Return values: NONE 1907 */ 1908 void 1909 ibcm_dump_noderec(sa_node_record_t *nrec) 1910 { 1911 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_noderec: Node Info Record"); 1912 IBTF_DPRINTF_L5(cmlog, "LID : %04X", nrec->LID); 1913 IBTF_DPRINTF_L5(cmlog, "Base Ver : %02X", nrec->NodeInfo.BaseVersion); 1914 IBTF_DPRINTF_L5(cmlog, "Class Ver : %02X", nrec->NodeInfo.ClassVersion); 1915 IBTF_DPRINTF_L5(cmlog, "Node Type : %02d", nrec->NodeInfo.NodeType); 1916 IBTF_DPRINTF_L5(cmlog, "Num Ports : %02X", nrec->NodeInfo.NumPorts); 1917 IBTF_DPRINTF_L5(cmlog, "SysImgGUID: %016llX", 1918 nrec->NodeInfo.SystemImageGUID); 1919 IBTF_DPRINTF_L5(cmlog, "NODE GUID : %016llX", nrec->NodeInfo.NodeGUID); 1920 IBTF_DPRINTF_L5(cmlog, "Port GUID : %016llX", nrec->NodeInfo.PortGUID); 1921 IBTF_DPRINTF_L5(cmlog, "PartionCap: %04X", nrec->NodeInfo.PartitionCap); 1922 IBTF_DPRINTF_L5(cmlog, "Device ID : %04X", nrec->NodeInfo.DeviceID); 1923 IBTF_DPRINTF_L5(cmlog, "Revision : %06X", nrec->NodeInfo.Revision); 1924 IBTF_DPRINTF_L5(cmlog, "LocalPort#: %02X", nrec->NodeInfo.LocalPortNum); 1925 IBTF_DPRINTF_L5(cmlog, "Vendor ID : %06X", nrec->NodeInfo.VendorID); 1926 IBTF_DPRINTF_L5(cmlog, "Description: %s", 1927 (char *)&nrec->NodeDescription); 1928 } 1929 #endif 1930 1931 /* 1932 * ibcm_ibtl_node_info: 1933 * Get the node record of the destination specified by lid via the HCA 1934 * and port specified. 1935 * 1936 * Arguments: 1937 * hca_guid - GUID of the local HCA. 1938 * port - port in the HCA to be used. 1939 * lid - destination LID 1940 * node_info_p - pointer to the Node Info to be returned. 1941 * 1942 * Return values: 1943 * IBT_SUCCESS : Got the node record sucessfully 1944 * IBT_FILURE : Failed to get the node record. 1945 */ 1946 ibt_status_t 1947 ibcm_ibtl_node_info(ib_guid_t hca_guid, uint8_t port, ib_lid_t lid, 1948 ibt_node_info_t *node_info_p) 1949 { 1950 sa_node_record_t nr_req, *nr_resp; 1951 void *res_p; 1952 ibmf_saa_handle_t saa_handle; 1953 ibt_status_t ibt_status; 1954 ibcm_hca_info_t *hcap; 1955 uint_t num_rec; 1956 size_t len; 1957 1958 IBTF_DPRINTF_L3(cmlog, "ibcm_ibtl_node_info: ENTER: port %x " 1959 "guid %llx\n", port, hca_guid); 1960 1961 hcap = ibcm_find_hca_entry(hca_guid); 1962 if (hcap == NULL) { 1963 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: " 1964 "HCA(%llX) info not found", hca_guid); 1965 return (IBT_FAILURE); 1966 } 1967 1968 /* Get SA Access Handle. */ 1969 saa_handle = ibcm_get_saa_handle(hcap, port); 1970 if (saa_handle == NULL) { 1971 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: " 1972 "Port %d of HCA (%llX) is NOT ACTIVE", port, hca_guid); 1973 ibcm_dec_hca_acc_cnt(hcap); 1974 return (IBT_FAILURE); 1975 } 1976 1977 /* Retrieve Node Records from SA Access. */ 1978 bzero(&nr_req, sizeof (sa_node_record_t)); 1979 nr_req.LID = lid; 1980 1981 ibt_status = ibcm_get_node_rec(saa_handle, &nr_req, 1982 SA_NODEINFO_COMPMASK_NODELID, &res_p, &len); 1983 if (ibt_status != IBT_SUCCESS) { 1984 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: " 1985 "failed (%d) to get Node records", ibt_status); 1986 ibcm_dec_hca_acc_cnt(hcap); 1987 return (IBT_FAILURE); 1988 } 1989 1990 num_rec = len/sizeof (sa_node_record_t); 1991 nr_resp = (sa_node_record_t *)(uchar_t *)res_p; 1992 1993 if ((nr_resp != NULL) && (num_rec > 0)) { 1994 IBCM_DUMP_NODE_REC(nr_resp); 1995 1996 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS( 1997 *node_info_p)) 1998 1999 node_info_p->n_sys_img_guid = 2000 nr_resp->NodeInfo.SystemImageGUID; 2001 node_info_p->n_node_guid = 2002 nr_resp->NodeInfo.NodeGUID; 2003 node_info_p->n_port_guid = 2004 nr_resp->NodeInfo.PortGUID; 2005 node_info_p->n_dev_id = 2006 nr_resp->NodeInfo.DeviceID; 2007 node_info_p->n_revision = 2008 nr_resp->NodeInfo.Revision; 2009 node_info_p->n_vendor_id = 2010 nr_resp->NodeInfo.VendorID; 2011 node_info_p->n_num_ports = 2012 nr_resp->NodeInfo.NumPorts; 2013 node_info_p->n_port_num = 2014 nr_resp->NodeInfo.LocalPortNum; 2015 node_info_p->n_node_type = 2016 nr_resp->NodeInfo.NodeType; 2017 (void) strncpy(node_info_p->n_description, 2018 (char *)&nr_resp->NodeDescription, 64); 2019 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS( 2020 *node_info_p)) 2021 2022 2023 kmem_free(nr_resp, len); 2024 } 2025 ibcm_dec_hca_acc_cnt(hcap); 2026 return (IBT_SUCCESS); 2027 } 2028 2029 /* 2030 * ibcm_ibmf_analyze_error: 2031 * Checks IBMF status and determines appropriate ibt status. 2032 * 2033 * Arguments: 2034 * ibmf_status - IBMF Status 2035 * 2036 * Return values: 2037 * ibt_status_t 2038 */ 2039 ibt_status_t 2040 ibcm_ibmf_analyze_error(int ibmf_status) 2041 { 2042 if (ibt_check_failure(ibmf_status, NULL) != IBT_FAILURE_STANDARD) { 2043 /* 2044 * IBMF specific failure, return special error code 2045 * to the client so that it can retrieve any associated ENA. 2046 */ 2047 return (ibmf_status); 2048 } else if (ibmf_status == IBMF_TRANS_TIMEOUT) { 2049 return (IBT_IBMF_TIMEOUT); 2050 } else { 2051 /* 2052 * IBMF failed for some other reason, invalid arguments etc. 2053 * Analyze, log ENA with IBTF and obtain a special ibt_status_t 2054 * that indicates IBMF failure. 2055 */ 2056 if ((ibmf_status == IBMF_BAD_CLASS) || 2057 (ibmf_status == IBMF_BAD_HANDLE) || 2058 (ibmf_status == IBMF_BAD_QP_HANDLE) || 2059 (ibmf_status == IBMF_BAD_NODE) || 2060 (ibmf_status == IBMF_BAD_PORT) || 2061 (ibmf_status == IBMF_BAD_VERSION) || 2062 (ibmf_status == IBMF_BAD_FLAGS) || 2063 (ibmf_status == IBMF_BAD_SIZE) || 2064 (ibmf_status == IBMF_INVALID_GID) || 2065 (ibmf_status == IBMF_INVALID_ARG) || 2066 (ibmf_status == IBMF_INVALID_FIELD) || 2067 (ibmf_status == IBMF_UNSUPP_METHOD) || 2068 (ibmf_status == IBMF_UNSUPP_METHOD_ATTR)) { 2069 2070 /* 2071 * These errors, we should not see... 2072 * something really bad happened!. 2073 */ 2074 IBTF_DPRINTF_L2(cmlog, "ibcm_ibmf_analyze_error: " 2075 "Unexpected ERROR from IBMF - %d", ibmf_status); 2076 } 2077 return (ibt_get_module_failure(IBT_FAILURE_IBMF, 0)); 2078 } 2079 } 2080