1 /* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36 #if HAVE_CONFIG_H 37 # include <config.h> 38 #endif /* HAVE_CONFIG_H */ 39 40 #include <stdlib.h> 41 #include <string.h> 42 #include <vendor/osm_vendor_mlx.h> 43 #include <vendor/osm_vendor_mlx_transport.h> 44 #include <vendor/osm_vendor_mlx_svc.h> 45 #include <vendor/osm_vendor_mlx_sender.h> 46 #include <vendor/osm_vendor_mlx_hca.h> 47 #include <vendor/osm_pkt_randomizer.h> 48 49 /** 50 * FORWARD REFERENCES 51 */ 52 static ib_api_status_t 53 __osmv_get_send_txn(IN osm_bind_handle_t h_bind, 54 IN osm_madw_t * const p_madw, 55 IN boolean_t is_rmpp, 56 IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn); 57 58 static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind); 59 60 /* 61 * NAME osm_vendor_new 62 * 63 * DESCRIPTION Create and Initialize the osm_vendor_t Object 64 */ 65 66 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, 67 IN const uint32_t timeout) 68 { 69 ib_api_status_t status; 70 osm_vendor_t *p_vend; 71 72 OSM_LOG_ENTER(p_log); 73 74 CL_ASSERT(p_log); 75 76 p_vend = malloc(sizeof(*p_vend)); 77 if (p_vend != NULL) { 78 memset(p_vend, 0, sizeof(*p_vend)); 79 80 status = osm_vendor_init(p_vend, p_log, timeout); 81 if (status != IB_SUCCESS) { 82 osm_vendor_delete(&p_vend); 83 } 84 } else { 85 osm_log(p_vend->p_log, OSM_LOG_ERROR, 86 "osm_vendor_new: ERR 7301: " 87 "Fail to allocate vendor object.\n"); 88 } 89 90 OSM_LOG_EXIT(p_log); 91 return (p_vend); 92 } 93 94 /* 95 * NAME osm_vendor_delete 96 * 97 * DESCRIPTION Delete all the binds behind the vendor + free the vendor object 98 */ 99 100 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) 101 { 102 cl_list_item_t *p_item; 103 cl_list_obj_t *p_obj; 104 osm_bind_handle_t bind_h; 105 osm_log_t *p_log; 106 107 OSM_LOG_ENTER((*pp_vend)->p_log); 108 p_log = (*pp_vend)->p_log; 109 110 /* go over the bind handles , unbind them and remove from list */ 111 p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); 112 while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) { 113 114 p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); 115 bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj); 116 osm_log(p_log, OSM_LOG_DEBUG, 117 "osm_vendor_delete: unbinding bind_h:%p \n", bind_h); 118 119 __osm_vendor_internal_unbind(bind_h); 120 121 free(p_obj); 122 /*removing from list */ 123 p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); 124 } 125 126 if (NULL != ((*pp_vend)->p_transport_info)) { 127 free((*pp_vend)->p_transport_info); 128 (*pp_vend)->p_transport_info = NULL; 129 } 130 131 /* remove the packet randomizer object */ 132 if ((*pp_vend)->run_randomizer == TRUE) 133 osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer), 134 p_log); 135 136 free(*pp_vend); 137 *pp_vend = NULL; 138 139 OSM_LOG_EXIT(p_log); 140 } 141 142 /* 143 * NAME osm_vendor_init 144 * 145 * DESCRIPTION Initialize the vendor object 146 */ 147 148 ib_api_status_t 149 osm_vendor_init(IN osm_vendor_t * const p_vend, 150 IN osm_log_t * const p_log, IN const uint32_t timeout) 151 { 152 ib_api_status_t status = IB_SUCCESS; 153 154 OSM_LOG_ENTER(p_log); 155 156 p_vend->p_transport_info = NULL; 157 p_vend->p_log = p_log; 158 p_vend->resp_timeout = timeout; 159 p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR; 160 161 cl_qlist_init(&p_vend->bind_handles); 162 163 /* update the run_randomizer flag */ 164 if (getenv("OSM_PKT_DROP_RATE") != NULL 165 && atol(getenv("OSM_PKT_DROP_RATE")) != 0) { 166 /* if the OSM_PKT_DROP_RATE global variable is defined to a non-zero value - 167 then the randomizer should be called. 168 Need to create the packet randomizer object */ 169 p_vend->run_randomizer = TRUE; 170 status = 171 osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log); 172 if (status != IB_SUCCESS) 173 return status; 174 } else { 175 p_vend->run_randomizer = FALSE; 176 p_vend->p_pkt_randomizer = NULL; 177 } 178 179 OSM_LOG_EXIT(p_log); 180 return (IB_SUCCESS); 181 } 182 183 /* 184 * NAME osm_vendor_bind 185 * 186 * DESCRIPTION Create a new bind object under the vendor object 187 */ 188 189 osm_bind_handle_t 190 osm_vendor_bind(IN osm_vendor_t * const p_vend, 191 IN osm_bind_info_t * const p_bind_info, 192 IN osm_mad_pool_t * const p_mad_pool, 193 IN osm_vend_mad_recv_callback_t mad_recv_callback, 194 IN osm_vend_mad_send_err_callback_t send_err_callback, 195 IN void *context) 196 { 197 osmv_bind_obj_t *p_bo; 198 ib_api_status_t status; 199 char hca_id[32]; 200 cl_status_t cl_st; 201 cl_list_obj_t *p_obj; 202 uint8_t hca_index; 203 204 if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool 205 || NULL == mad_recv_callback || NULL == send_err_callback) { 206 osm_log(p_vend->p_log, OSM_LOG_ERROR, 207 "osm_vendor_bind: ERR 7302: " 208 "NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n", 209 p_vend, p_bind_info, p_mad_pool, mad_recv_callback, 210 send_err_callback); 211 212 return OSM_BIND_INVALID_HANDLE; 213 } 214 215 p_bo = malloc(sizeof(osmv_bind_obj_t)); 216 if (NULL == p_bo) { 217 osm_log(p_vend->p_log, OSM_LOG_ERROR, 218 "osm_vendor_bind: ERR 7303: could not allocate the bind object\n"); 219 return OSM_BIND_INVALID_HANDLE; 220 } 221 222 memset(p_bo, 0, sizeof(osmv_bind_obj_t)); 223 p_bo->p_vendor = p_vend; 224 p_bo->recv_cb = mad_recv_callback; 225 p_bo->send_err_cb = send_err_callback; 226 p_bo->cb_context = context; 227 p_bo->p_osm_pool = p_mad_pool; 228 229 /* obtain the hca name and port num from the guid */ 230 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 231 "osm_vendor_bind: " 232 "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", 233 cl_ntoh64(p_bind_info->port_guid)); 234 235 status = osm_vendor_get_guid_ca_and_port(p_bo->p_vendor, 236 p_bind_info->port_guid, 237 &(p_bo->hca_hndl), 238 hca_id, 239 &hca_index, &(p_bo->port_num)); 240 if (status != IB_SUCCESS) { 241 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 242 "osm_vendor_bind: ERR 7304: " 243 "Fail to find port number of port guid:0x%016" PRIx64 244 "\n", p_bind_info->port_guid); 245 free(p_bo); 246 return OSM_BIND_INVALID_HANDLE; 247 } 248 249 /* Initialize the magic_ptr to the pointer of the p_bo info. 250 This will be used to signal when the object is being destroyed, so no 251 real action will be done then. */ 252 p_bo->magic_ptr = p_bo; 253 254 p_bo->is_closing = FALSE; 255 256 cl_spinlock_construct(&(p_bo->lock)); 257 cl_st = cl_spinlock_init(&(p_bo->lock)); 258 if (cl_st != CL_SUCCESS) { 259 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 260 "osm_vendor_bind: ERR 7305: " 261 "could not initialize the spinlock ...\n"); 262 free(p_bo); 263 return OSM_BIND_INVALID_HANDLE; 264 } 265 266 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 267 "osm_vendor_bind: osmv_txnmgr_init ... \n"); 268 if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) != 269 IB_SUCCESS) { 270 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 271 "osm_vendor_bind: ERR 7306: " 272 "osmv_txnmgr_init failed \n"); 273 cl_spinlock_destroy(&p_bo->lock); 274 free(p_bo); 275 return OSM_BIND_INVALID_HANDLE; 276 } 277 278 /* Do the real job! (Transport-dependent) */ 279 if (IB_SUCCESS != 280 osmv_transport_init(p_bind_info, hca_id, hca_index, p_bo)) { 281 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 282 "osm_vendor_bind: ERR 7307: " 283 "osmv_transport_init failed \n"); 284 osmv_txnmgr_done((osm_bind_handle_t) p_bo); 285 cl_spinlock_destroy(&p_bo->lock); 286 free(p_bo); 287 return OSM_BIND_INVALID_HANDLE; 288 } 289 290 /* insert bind handle into db */ 291 p_obj = malloc(sizeof(cl_list_obj_t)); 292 if (NULL == p_obj) { 293 294 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 295 "osm_vendor_bind: ERR 7308: " 296 "osm_vendor_bind: could not allocate the list object\n"); 297 298 osmv_transport_done(p_bo->p_transp_mgr); 299 osmv_txnmgr_done((osm_bind_handle_t) p_bo); 300 cl_spinlock_destroy(&p_bo->lock); 301 free(p_bo); 302 return OSM_BIND_INVALID_HANDLE; 303 } 304 memset(p_obj, 0, sizeof(cl_list_obj_t)); 305 cl_qlist_set_obj(p_obj, p_bo); 306 307 cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item); 308 309 return (osm_bind_handle_t) p_bo; 310 } 311 312 /* 313 * NAME osm_vendor_unbind 314 * 315 * DESCRIPTION Destroy the bind object and remove it from the vendor's list 316 */ 317 318 void osm_vendor_unbind(IN osm_bind_handle_t h_bind) 319 { 320 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 321 osm_log_t *p_log = p_bo->p_vendor->p_log; 322 cl_list_obj_t *p_obj = NULL; 323 cl_list_item_t *p_item, *p_item_tmp; 324 cl_qlist_t *const p_bh_list = 325 (cl_qlist_t * const)&p_bo->p_vendor->bind_handles; 326 327 OSM_LOG_ENTER(p_log); 328 329 /* go over all the items in the list and remove the specific item */ 330 p_item = cl_qlist_head(p_bh_list); 331 while (p_item != cl_qlist_end(p_bh_list)) { 332 p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); 333 if (cl_qlist_obj(p_obj) == h_bind) { 334 break; 335 } 336 p_item_tmp = cl_qlist_next(p_item); 337 p_item = p_item_tmp; 338 } 339 340 CL_ASSERT(p_item != cl_qlist_end(p_bh_list)); 341 342 cl_qlist_remove_item(p_bh_list, p_item); 343 if (p_obj) 344 free(p_obj); 345 346 if (h_bind != 0) { 347 __osm_vendor_internal_unbind(h_bind); 348 } 349 350 OSM_LOG_EXIT(p_log); 351 } 352 353 /* 354 * NAME osm_vendor_get 355 * 356 * DESCRIPTION Allocate the space for a new MAD 357 */ 358 359 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, 360 IN const uint32_t mad_size, 361 IN osm_vend_wrap_t * const p_vw) 362 { 363 ib_mad_t *p_mad; 364 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 365 osm_vendor_t const *p_vend = p_bo->p_vendor; 366 uint32_t act_mad_size; 367 368 OSM_LOG_ENTER(p_vend->p_log); 369 370 CL_ASSERT(p_vw); 371 372 if (mad_size < MAD_BLOCK_SIZE) { 373 /* Stupid, but the applications want that! */ 374 act_mad_size = MAD_BLOCK_SIZE; 375 } else { 376 act_mad_size = mad_size; 377 } 378 379 /* allocate it */ 380 p_mad = (ib_mad_t *) malloc(act_mad_size); 381 if (p_mad == NULL) { 382 osm_log(p_vend->p_log, OSM_LOG_ERROR, 383 "osm_vendor_get: ERR 7309: " 384 "Error Obtaining MAD buffer.\n"); 385 goto Exit; 386 } 387 388 memset(p_mad, 0, act_mad_size); 389 390 if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { 391 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 392 "osm_vendor_get: " 393 "Allocated MAD %p, size = %u.\n", p_mad, act_mad_size); 394 } 395 p_vw->p_mad = p_mad; 396 397 Exit: 398 OSM_LOG_EXIT(p_vend->p_log); 399 return (p_mad); 400 } 401 402 /* 403 * NAME osm_vendor_send 404 * 405 * DESCRIPTION Send a MAD buffer (RMPP or simple send). 406 * 407 * Semantics: 408 * (1) The RMPP send completes when every segment 409 * is acknowledged (synchronous) 410 * (2) The simple send completes when the send completion 411 * is received (asynchronous) 412 */ 413 414 ib_api_status_t 415 osm_vendor_send(IN osm_bind_handle_t h_bind, 416 IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) 417 { 418 ib_api_status_t ret = IB_SUCCESS; 419 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 420 boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE; 421 osmv_txn_ctx_t *p_txn = NULL; 422 ib_mad_t *p_mad; 423 osm_log_t *p_log = p_bo->p_vendor->p_log; 424 osm_mad_pool_t *p_mad_pool = p_bo->p_osm_pool; 425 OSM_LOG_ENTER(p_log); 426 427 if (NULL == h_bind || NULL == p_madw || 428 NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) || 429 NULL == osm_madw_get_mad_addr_ptr(p_madw)) { 430 431 return IB_INVALID_PARAMETER; 432 } 433 434 is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE 435 || osmv_mad_is_rmpp(p_mad)); 436 /* is this rmpp double sided? This means we expect a response that can be 437 an rmpp or not */ 438 is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected); 439 440 /* Make our operations with the send context atomic */ 441 osmv_txn_lock(p_bo); 442 443 if (TRUE == p_bo->is_closing) { 444 445 osm_log(p_log, OSM_LOG_ERROR, 446 "osm_vendor_send: ERR 7310: " 447 "The handle %p is being unbound, cannot send.\n", 448 h_bind); 449 ret = IB_INTERRUPTED; 450 /* When closing p_bo could be detroyed or is going to , thus could not refer to it */ 451 goto send_done; 452 } 453 454 if (TRUE == resp_expected || TRUE == is_rmpp) { 455 456 /* We must run under a transaction framework. 457 * Get the transaction object (old or new) */ 458 ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp, 459 resp_expected, &p_txn); 460 if (IB_SUCCESS != ret) { 461 goto send_done; 462 } 463 } 464 465 if (TRUE == is_rmpp) { 466 /* Do the job - RMPP! 467 * The call returns as all the packets are ACK'ed/upon error 468 * The txn lock will be released each time the function sleeps 469 * and re-acquired when it wakes up 470 */ 471 ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds); 472 } else { 473 474 /* Do the job - single MAD! 475 * The call returns as soon as the MAD is put on the wire 476 */ 477 ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE); 478 } 479 480 if (IB_SUCCESS == ret) { 481 482 if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) { 483 /* For double-sided sends, the txn continues to live */ 484 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), 485 FALSE /*not in callback */ ); 486 } 487 488 if (FALSE == resp_expected) { 489 osm_mad_pool_put(p_mad_pool, p_madw); 490 } 491 } else if (IB_INTERRUPTED != ret) { 492 if (NULL != p_txn) { 493 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), 494 FALSE /*not in callback */ ); 495 } 496 497 osm_log(p_log, OSM_LOG_ERROR, 498 "osm_vendor_send: ERR 7311: failed to send MADW %p\n", 499 p_madw); 500 501 if (TRUE == resp_expected) { 502 /* Change the status on the p_madw */ 503 p_madw->status = ret; 504 /* Only the requester expects the error callback */ 505 p_bo->send_err_cb(p_bo->cb_context, p_madw); 506 } else { 507 /* put back the mad - it is useless ... */ 508 osm_mad_pool_put(p_mad_pool, p_madw); 509 } 510 } else { /* the transaction was aborted due to p_bo exit */ 511 512 osm_mad_pool_put(p_mad_pool, p_madw); 513 goto aborted; 514 } 515 send_done: 516 517 osmv_txn_unlock(p_bo); 518 aborted: 519 OSM_LOG_EXIT(p_log); 520 return ret; 521 } 522 523 /* 524 * NAME osm_vendor_put 525 * 526 * DESCRIPTION Free the MAD's memory 527 */ 528 529 void 530 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) 531 { 532 533 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 534 osm_vendor_t const *p_vend = p_bo->p_vendor; 535 536 if (p_bo->is_closing != TRUE) { 537 OSM_LOG_ENTER(p_vend->p_log); 538 539 CL_ASSERT(p_vw); 540 CL_ASSERT(p_vw->p_mad); 541 542 if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { 543 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 544 "osm_vendor_put: " "Retiring MAD %p.\n", 545 p_vw->p_mad); 546 } 547 548 free(p_vw->p_mad); 549 p_vw->p_mad = NULL; 550 551 OSM_LOG_EXIT(p_vend->p_log); 552 } 553 } 554 555 /* 556 * NAME osm_vendor_local_lid_change 557 * 558 * DESCRIPTION Notifies the vendor transport layer that the local address 559 * has changed. This allows the vendor layer to perform 560 * housekeeping functions such as address vector updates. 561 */ 562 563 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) 564 { 565 osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor; 566 OSM_LOG_ENTER(p_vend->p_log); 567 568 osm_log(p_vend->p_log, OSM_LOG_DEBUG, 569 "osm_vendor_local_lid_change: " "Change of LID.\n"); 570 571 OSM_LOG_EXIT(p_vend->p_log); 572 573 return (IB_SUCCESS); 574 575 } 576 577 /* 578 * NAME osm_vendor_set_sm 579 * 580 * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit 581 * according to the value given (TRUE or FALSE). 582 */ 583 #if !(defined(OSM_VENDOR_INTF_TS_NO_VAPI) || defined(OSM_VENDOR_INTF_SIM) || defined(OSM_VENDOR_INTF_TS)) 584 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) 585 { 586 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 587 osm_vendor_t const *p_vend = p_bo->p_vendor; 588 VAPI_ret_t status; 589 VAPI_hca_attr_t attr_mod; 590 VAPI_hca_attr_mask_t attr_mask; 591 592 OSM_LOG_ENTER(p_vend->p_log); 593 594 memset(&attr_mod, 0, sizeof(attr_mod)); 595 memset(&attr_mask, 0, sizeof(attr_mask)); 596 597 attr_mod.is_sm = is_sm_val; 598 attr_mask = HCA_ATTR_IS_SM; 599 600 status = 601 VAPI_modify_hca_attr(p_bo->hca_hndl, p_bo->port_num, &attr_mod, 602 &attr_mask); 603 if (status != VAPI_OK) { 604 osm_log(p_vend->p_log, OSM_LOG_ERROR, 605 "osm_vendor_set_sm: ERR 7312: " 606 "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", 607 is_sm_val, status); 608 } 609 610 OSM_LOG_EXIT(p_vend->p_log); 611 } 612 613 #endif 614 615 /* 616 * NAME __osm_vendor_internal_unbind 617 * 618 * DESCRIPTION Destroying a bind: 619 * (1) Wait for the completion of the sends in flight 620 * (2) Destroy the associated data structures 621 */ 622 623 static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind) 624 { 625 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 626 osm_log_t *p_log = p_bo->p_vendor->p_log; 627 628 OSM_LOG_ENTER(p_log); 629 630 /* "notifying" all that from now on no new sends can be done */ 631 p_bo->txn_mgr.p_event_wheel->closing = TRUE; 632 633 osmv_txn_lock(p_bo); 634 635 /* 636 the is_closing is set under lock we we know we only need to 637 check for it after obtaining the lock 638 */ 639 p_bo->is_closing = TRUE; 640 641 /* notifying all sleeping rmpp sends to exit */ 642 osmv_txn_abort_rmpp_txns(h_bind); 643 644 /* unlock the bo to allow for any residual mads to be dispatched */ 645 osmv_txn_unlock(p_bo); 646 osm_log(p_log, OSM_LOG_DEBUG, 647 "__osm_vendor_internal_unbind: destroying transport mgr.. \n"); 648 /* wait for the receiver thread to exit */ 649 osmv_transport_done(h_bind); 650 651 /* lock to avoid any collissions while we cleanup the structs */ 652 osmv_txn_lock(p_bo); 653 osm_log(p_log, OSM_LOG_DEBUG, 654 "__osm_vendor_internal_unbind: destroying txn mgr.. \n"); 655 osmv_txnmgr_done(h_bind); 656 osm_log(p_log, OSM_LOG_DEBUG, 657 "__osm_vendor_internal_unbind: destroying bind lock.. \n"); 658 osmv_txn_unlock(p_bo); 659 660 /* 661 we intentionally let the p_bo and its lock leak - 662 as we did not implement a way to track active bind handles provided to 663 the client - and the client might use them 664 665 cl_spinlock_destroy(&p_bo->lock); 666 free(p_bo); 667 */ 668 669 OSM_LOG_EXIT(p_log); 670 } 671 672 /* 673 * NAME __osmv_get_send_txn 674 * 675 * DESCRIPTION Return a transaction object that corresponds to this MAD. 676 * Optionally, create it, if the new request (query) is sent or received. 677 */ 678 679 static ib_api_status_t 680 __osmv_get_send_txn(IN osm_bind_handle_t h_bind, 681 IN osm_madw_t * const p_madw, 682 IN boolean_t is_rmpp, 683 IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn) 684 { 685 ib_api_status_t ret; 686 uint64_t tid, key; 687 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 688 ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); 689 690 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 691 CL_ASSERT(NULL != pp_txn); 692 693 key = tid = cl_ntoh64(p_mad->trans_id); 694 if (TRUE == resp_expected) { 695 /* Create a unique identifier at the requester side */ 696 key = osmv_txn_uniq_key(tid); 697 } 698 699 /* We must run under a transaction framework */ 700 ret = osmv_txn_lookup(h_bind, key, pp_txn); 701 if (IB_NOT_FOUND == ret) { 702 /* Generally, we start a new transaction */ 703 ret = osmv_txn_init(h_bind, tid, key, pp_txn); 704 if (IB_SUCCESS != ret) { 705 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 706 "__osmv_get_send_txn: ERR 7313: " 707 "The transaction id=0x%" PRIx64 " failed to init.\n", 708 tid); 709 goto get_send_txn_done; 710 } 711 } else { 712 CL_ASSERT(NULL != *pp_txn); 713 /* The transaction context exists. 714 * This is legal only if I am going to return an 715 * (RMPP?) reply to an RMPP request sent by the other part 716 * (double-sided RMPP transfer) 717 */ 718 if (FALSE == is_rmpp 719 || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) { 720 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 721 "__osmv_get_send_txn: ERR 7314: " 722 "The transaction id=0x%" PRIx64 " is not unique. Send failed.\n", 723 tid); 724 725 ret = IB_INVALID_SETTING; 726 goto get_send_txn_done; 727 } 728 729 if (TRUE == resp_expected) { 730 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 731 "__osmv_get_send_txn: ERR 7315: " 732 "The transaction id=0x%" PRIx64 " can't expect a response. Send failed.\n", 733 tid); 734 735 ret = IB_INVALID_PARAMETER; 736 goto get_send_txn_done; 737 } 738 } 739 740 if (TRUE == is_rmpp) { 741 ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw); 742 if (IB_SUCCESS != ret) { 743 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 744 "__osmv_get_send_txn: ERR 7316: " 745 "The transaction id=0x%" PRIx64 " failed to init the rmpp mad. Send failed.\n", 746 tid); 747 osmv_txn_done(h_bind, tid, FALSE); 748 goto get_send_txn_done; 749 } 750 } 751 752 /* Save a reference to the MAD in the txn context 753 * We'll need to match it in two cases: 754 * (1) When the response is returned, if I am the requester 755 * (2) In RMPP retransmissions 756 */ 757 osmv_txn_set_madw(*pp_txn, p_madw); 758 759 get_send_txn_done: 760 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 761 762 return ret; 763 } 764 765 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) 766 { 767 768 } 769