1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2005,2009 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 42#include <vendor/osm_vendor_mlx.h> 43#include <vendor/osm_vendor_mlx_defs.h> 44#include <vendor/osm_vendor_mlx_txn.h> 45#include <vendor/osm_vendor_mlx_svc.h> 46#include <vendor/osm_vendor_mlx_sender.h> 47 48static ib_api_status_t 49__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr, 50 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); 51 52static ib_api_status_t 53__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, 54 IN osmv_txn_ctx_t * p_txn, IN uint64_t key); 55 56static ib_api_status_t 57__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr, 58 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); 59 60static void __osmv_txn_all_done(osm_bind_handle_t h_bind); 61 62static uint64_t 63__osmv_txn_timeout_cb(IN uint64_t key, 64 IN uint32_t num_regs, IN void *cb_context); 65 66ib_api_status_t 67osmv_txn_init(IN osm_bind_handle_t h_bind, 68 IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) 69{ 70 ib_api_status_t st; 71 osmv_txn_ctx_t *p_txn; 72 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 73 74 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 75 76 CL_ASSERT(NULL != h_bind && NULL != pp_txn); 77 78 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 79 "Starting transaction 0x%016" PRIx64 80 " (key=0x%016" PRIx64 ")\n", tid, key); 81 82 p_txn = malloc(sizeof(osmv_txn_ctx_t)); 83 if (!p_txn) { 84 return IB_INSUFFICIENT_MEMORY; 85 } 86 87 memset(p_txn, 0, sizeof(osmv_txn_ctx_t)); 88 p_txn->p_log = p_bo->txn_mgr.p_log; 89 p_txn->tid = tid; 90 p_txn->key = key; 91 p_txn->p_madw = NULL; 92 p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_NONE; 93 94 /* insert into transaction manager DB */ 95 st = __osmv_txnmgr_insert_txn(&p_bo->txn_mgr, p_txn, key); 96 if (IB_SUCCESS != st) { 97 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 98 "osmv_txn_init: ERR 6703: " 99 "Failed to insert to transaction 0x%016" PRIx64 100 " (key=0x%016" PRIx64 ") to manager DB\n", 101 tid, key); 102 goto insert_txn_failed; 103 } 104 105 *pp_txn = p_txn; 106 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 107 return IB_SUCCESS; 108 109insert_txn_failed: 110 free(p_txn); 111 112 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 113 return st; 114} 115 116ib_api_status_t 117osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind, 118 IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw) 119{ 120 ib_api_status_t st; 121 122 CL_ASSERT(p_txn); 123 124 /* Double-Sided RMPP Direction Switch */ 125 osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); 126 127 p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_SENDER; 128 p_txn->rmpp_txfr.p_rmpp_send_ctx = malloc(sizeof(osmv_rmpp_send_ctx_t)); 129 130 if (!p_txn->rmpp_txfr.p_rmpp_send_ctx) { 131 return IB_INSUFFICIENT_MEMORY; 132 } 133 134 memset(p_txn->rmpp_txfr.p_rmpp_send_ctx, 0, 135 sizeof(osmv_rmpp_send_ctx_t)); 136 137 st = osmv_rmpp_send_ctx_init(p_txn->rmpp_txfr.p_rmpp_send_ctx, 138 (void *)p_madw->p_mad, 139 p_madw->mad_size, p_txn->p_log); 140 return st; 141} 142 143ib_api_status_t 144osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind, 145 IN osmv_txn_ctx_t * p_txn, 146 IN boolean_t is_init_by_peer) 147{ 148 ib_api_status_t st; 149 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 150 uint64_t key = osmv_txn_get_key(p_txn); 151 152 CL_ASSERT(p_txn); 153 154 /* Double-Sided RMPP Direction Switch */ 155 osmv_txn_remove_timeout_ev(h_bind, key); 156 157 /* Set the Transaction Timeout value */ 158 st = osmv_txn_set_timeout_ev(h_bind, key, 159 p_bo->p_vendor->ttime_timeout); 160 if (IB_SUCCESS != st) { 161 162 return st; 163 } 164 165 p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_RECEIVER; 166 p_txn->rmpp_txfr.is_rmpp_init_by_peer = is_init_by_peer; 167 168 p_txn->rmpp_txfr.p_rmpp_recv_ctx = malloc(sizeof(osmv_rmpp_recv_ctx_t)); 169 170 if (!p_txn->rmpp_txfr.p_rmpp_recv_ctx) { 171 172 osmv_txn_remove_timeout_ev(h_bind, key); 173 return IB_INSUFFICIENT_MEMORY; 174 } 175 176 memset(p_txn->rmpp_txfr.p_rmpp_recv_ctx, 0, 177 sizeof(osmv_rmpp_recv_ctx_t)); 178 179 st = osmv_rmpp_recv_ctx_init(p_txn->rmpp_txfr.p_rmpp_recv_ctx, 180 p_txn->p_log); 181 182 return st; 183} 184 185/* 186 * NAME 187 * osmv_txn_set_timeout_ev 188 * 189 * DESCRIPTION 190 * 191 * SEE ALSO 192 * 193 */ 194ib_api_status_t 195osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind, 196 IN uint64_t key, IN uint64_t msec) 197{ 198 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 199 cl_event_wheel_t *p_event_wheel = p_bo->txn_mgr.p_event_wheel; 200 cl_status_t status; 201 202 status = cl_event_wheel_reg(p_event_wheel, key, cl_get_time_stamp() + 1000 * msec, /* TTL */ 203 __osmv_txn_timeout_cb, 204 p_bo /* The context */ ); 205 206 return (ib_api_status_t) status; 207} 208 209/* 210 * NAME 211 * osmv_txn_remove_timeout_ev 212 * 213 * DESCRIPTION 214 215 * SEE ALSO 216 * 217 */ 218void osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind, IN uint64_t key) 219{ 220 cl_event_wheel_t *p_event_wheel = 221 ((osmv_bind_obj_t *) h_bind)->txn_mgr.p_event_wheel; 222 cl_event_wheel_unreg(p_event_wheel, key); 223} 224 225void 226osmv_txn_done(IN osm_bind_handle_t h_bind, 227 IN uint64_t key, IN boolean_t is_in_cb) 228{ 229 osmv_txn_ctx_t *p_ctx; 230 osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) h_bind; 231 232 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 233 234 CL_ASSERT(h_bind); 235 236 /* Cancel the (single) timeout possibly outstanding for this txn 237 * Don't do this if you are in the callback context, for 2 reasons: 238 * (1) The event wheel will remove the context itself. 239 * (2) If we try to, there is a deadlock in the event wheel 240 */ 241 if (FALSE == is_in_cb) { 242 osmv_txn_remove_timeout_ev(h_bind, key); 243 } 244 245 /* Remove from DB */ 246 if (IB_NOT_FOUND == 247 __osmv_txnmgr_remove_txn(&p_bo->txn_mgr, key, &p_ctx)) { 248 return; 249 } 250 251 /* Destroy the transaction's RMPP contexts 252 * (can be more than one in the case of double sided transfer) 253 */ 254 255 if (p_ctx->rmpp_txfr.p_rmpp_send_ctx) { 256 osmv_rmpp_send_ctx_done(p_ctx->rmpp_txfr.p_rmpp_send_ctx); 257 } 258 259 if (p_ctx->rmpp_txfr.p_rmpp_recv_ctx) { 260 osmv_rmpp_recv_ctx_done(p_ctx->rmpp_txfr.p_rmpp_recv_ctx); 261 } 262 263 free(p_ctx); 264 265 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 266} 267 268ib_api_status_t 269osmv_txn_lookup(IN osm_bind_handle_t h_bind, 270 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) 271{ 272 return __osmv_txnmgr_lookup(&(((osmv_bind_obj_t *) h_bind)->txn_mgr), 273 key, pp_txn); 274} 275 276void osmv_txn_abort_rmpp_txns(osm_bind_handle_t h_bind) 277{ 278 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 279 cl_map_item_t *p_item; 280 cl_map_obj_t *p_obj; 281 osmv_txn_ctx_t *p_txn; 282 osmv_rmpp_send_ctx_t *p_send_ctx; 283 cl_qmap_t *p_map = p_bo->txn_mgr.p_txn_map; 284 285 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 286 287 while (FALSE == cl_is_qmap_empty(p_map)) { 288 289 p_item = cl_qmap_head(p_map); 290 p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); 291 p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj); 292 p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 293 294 if (NULL != p_send_ctx) { 295 296 p_send_ctx->status = IB_INTERRUPTED; 297 298 /* Wake up the sender thread to let it break out */ 299 cl_event_signal(&p_send_ctx->event); 300 } 301 302 cl_qmap_remove_item(p_map, p_item); 303 } 304 305 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 306} 307 308ib_api_status_t 309osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr, 310 IN osm_log_t * p_log, IN cl_spinlock_t * p_lock) 311{ 312 cl_status_t cl_st = CL_SUCCESS; 313 314 p_tx_mgr->p_event_wheel = malloc(sizeof(cl_event_wheel_t)); 315 if (!p_tx_mgr->p_event_wheel) { 316 return IB_INSUFFICIENT_MEMORY; 317 } 318 319 memset(p_tx_mgr->p_event_wheel, 0, sizeof(cl_event_wheel_t)); 320 321 cl_event_wheel_construct(p_tx_mgr->p_event_wheel); 322 323 /* NOTE! We are using an extended constructor. 324 * We tell the Event Wheel run in a non-protected manner in the reg/unreg calls, 325 * and acquire an external lock in the asynchronous callback. 326 */ 327 cl_st = cl_event_wheel_init_ex(p_tx_mgr->p_event_wheel, p_lock); 328 if (cl_st != CL_SUCCESS) { 329 free(p_tx_mgr->p_event_wheel); 330 return (ib_api_status_t) cl_st; 331 } 332 333 p_tx_mgr->p_txn_map = malloc(sizeof(cl_qmap_t)); 334 if (!p_tx_mgr->p_txn_map) { 335 cl_event_wheel_destroy(p_tx_mgr->p_event_wheel); 336 free(p_tx_mgr->p_event_wheel); 337 return IB_INSUFFICIENT_MEMORY; 338 } 339 340 memset(p_tx_mgr->p_txn_map, 0, sizeof(cl_qmap_t)); 341 342 cl_qmap_init(p_tx_mgr->p_txn_map); 343 p_tx_mgr->p_log = p_log; 344 345 return cl_st; 346} 347 348void osmv_txnmgr_done(IN osm_bind_handle_t h_bind) 349{ 350 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 351 352 __osmv_txn_all_done(h_bind); 353 free(p_bo->txn_mgr.p_txn_map); 354 355 cl_event_wheel_destroy(p_bo->txn_mgr.p_event_wheel); 356 free(p_bo->txn_mgr.p_event_wheel); 357} 358 359ib_api_status_t 360__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr, 361 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) 362{ 363 ib_api_status_t status = IB_SUCCESS; 364 cl_map_item_t *p_item; 365 cl_map_obj_t *p_obj; 366 367 uint64_t tmp_key; 368 369 OSM_LOG_ENTER(p_tx_mgr->p_log); 370 371 CL_ASSERT(p_tx_mgr); 372 CL_ASSERT(pp_txn); 373 374 osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, 375 "__osmv_txnmgr_lookup: " 376 "Looking for key: 0x%016" PRIx64 " in map ptr:%p\n", key, 377 p_tx_mgr->p_txn_map); 378 379 p_item = cl_qmap_head(p_tx_mgr->p_txn_map); 380 while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) { 381 tmp_key = cl_qmap_key(p_item); 382 osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, 383 "__osmv_txnmgr_lookup: " 384 "Found key 0x%016" PRIx64 "\n", tmp_key); 385 p_item = cl_qmap_next(p_item); 386 } 387 388 p_item = cl_qmap_get(p_tx_mgr->p_txn_map, key); 389 if (cl_qmap_end(p_tx_mgr->p_txn_map) == p_item) { 390 status = IB_NOT_FOUND; 391 } else { 392 p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); 393 *pp_txn = cl_qmap_obj(p_obj); 394 } 395 396 OSM_LOG_EXIT(p_tx_mgr->p_log); 397 return status; 398} 399 400ib_api_status_t 401__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, 402 IN osmv_txn_ctx_t * p_txn, IN uint64_t key) 403{ 404 cl_map_obj_t *p_obj = NULL; 405 cl_map_item_t *p_item; 406 uint64_t tmp_key; 407 408 CL_ASSERT(p_tx_mgr); 409 CL_ASSERT(p_txn); 410 411 key = osmv_txn_get_key(p_txn); 412 p_obj = malloc(sizeof(cl_map_obj_t)); 413 if (NULL == p_obj) 414 return IB_INSUFFICIENT_MEMORY; 415 416 osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, 417 "__osmv_txnmgr_insert_txn: " 418 "Inserting key: 0x%016" PRIx64 " to map ptr:%p\n", key, 419 p_tx_mgr->p_txn_map); 420 421 memset(p_obj, 0, sizeof(cl_map_obj_t)); 422 423 cl_qmap_set_obj(p_obj, p_txn); 424 /* assuming lookup with this key was made and the result was IB_NOT_FOUND */ 425 cl_qmap_insert(p_tx_mgr->p_txn_map, key, &p_obj->item); 426 427 p_item = cl_qmap_head(p_tx_mgr->p_txn_map); 428 while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) { 429 tmp_key = cl_qmap_key(p_item); 430 osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, 431 "__osmv_txnmgr_insert_txn: " 432 "Found key 0x%016" PRIx64 "\n", tmp_key); 433 p_item = cl_qmap_next(p_item); 434 } 435 436 return IB_SUCCESS; 437} 438 439ib_api_status_t 440__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr, 441 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) 442{ 443 cl_map_obj_t *p_obj; 444 cl_map_item_t *p_item; 445 446 OSM_LOG_ENTER(p_tx_mgr->p_log); 447 448 CL_ASSERT(p_tx_mgr); 449 CL_ASSERT(pp_txn); 450 451 p_item = cl_qmap_remove(p_tx_mgr->p_txn_map, key); 452 453 if (p_item == cl_qmap_end(p_tx_mgr->p_txn_map)) { 454 455 osm_log(p_tx_mgr->p_log, OSM_LOG_ERROR, 456 "__osmv_txnmgr_remove_txn: ERR 6701: " 457 "Could not remove the transaction 0x%016" PRIx64 " - " 458 "something is really wrong!\n", key); 459 OSM_LOG_EXIT(p_tx_mgr->p_log); 460 return IB_NOT_FOUND; 461 } 462 463 p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); 464 *pp_txn = cl_qmap_obj(p_obj); 465 466 free(p_obj); 467 468 OSM_LOG_EXIT(p_tx_mgr->p_log); 469 return IB_SUCCESS; 470} 471 472void __osmv_txn_all_done(osm_bind_handle_t h_bind) 473{ 474 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 475 cl_map_item_t *p_item; 476 cl_map_obj_t *p_obj; 477 osmv_txn_ctx_t *p_txn; 478 479 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 480 481 p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); 482 while (p_item != cl_qmap_end(p_bo->txn_mgr.p_txn_map)) { 483 484 p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); 485 p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj); 486 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); 487 free(p_obj); 488 /* assuming osmv_txn_done has removed the txn from the map */ 489 p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); 490 } 491 492 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 493} 494 495/******************************************************************************/ 496 497void osmv_txn_lock(IN osm_bind_handle_t h_bind) 498{ 499 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 500 501 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 502 "--> Acquiring lock %p on bind handle %p\n", &p_bo->lock, p_bo); 503 504 cl_spinlock_acquire(&p_bo->lock); 505 506 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 507 "--> Acquired lock %p on bind handle %p\n", &p_bo->lock, p_bo); 508} 509 510void osmv_txn_unlock(IN osm_bind_handle_t h_bind) 511{ 512 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 513 cl_spinlock_t *p_lock = &p_bo->lock; 514 osm_log_t *p_log = p_bo->p_vendor->p_log; 515 516 osm_log(p_log, OSM_LOG_DEBUG, 517 "<-- Releasing lock %p on bind handle %p\n", p_lock, p_bo); 518 519 cl_spinlock_release(&p_bo->lock); 520 521 /* We'll use the saved ptrs, since now the p_bo can be destroyed already */ 522 osm_log(p_log, OSM_LOG_DEBUG, 523 "<-- Released lock %p on bind handle %p\n", p_lock, p_bo); 524 525} 526 527static uint64_t 528__osmv_txn_timeout_cb(IN uint64_t key, 529 IN uint32_t num_regs, IN void *cb_context) 530{ 531 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) cb_context; 532 uint64_t ret = 0; 533 osmv_txn_ctx_t *p_txn; 534 osmv_rmpp_send_ctx_t *p_send_ctx; 535 osm_madw_t *p_madw = NULL; 536 ib_mad_t *p_mad; 537 osm_mad_addr_t *p_mad_addr; 538 boolean_t invoke_err_cb = FALSE; 539 540 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 541 542 /* Don't try to acquire a lock on the Bind Object - 543 * it's taken by the mechanism that drives the timeout based events! 544 * (Recall the special constructor that the Event Wheel is applied with) 545 */ 546 if (p_bo->is_closing) { 547 goto txn_done; 548 } 549 550 ret = osmv_txn_lookup(p_bo, key, &p_txn); 551 if (IB_NOT_FOUND == ret) { 552 /* Prevent a race - the transaction is already destroyed */ 553 goto txn_done; 554 } 555 556 p_madw = p_txn->p_madw; 557 558 switch (osmv_txn_get_rmpp_state(p_txn)) { 559 560 case OSMV_TXN_RMPP_NONE: 561 if (num_regs <= OSM_DEFAULT_RETRY_COUNT) { 562 /* We still did not exceed the limit of retransmissions. 563 * Set the next timeout's value. 564 */ 565 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 566 "__osmv_txn_timeout_cb: " 567 "The transaction request (tid=0x%016" PRIx64 ")" 568 " timed out %d times. Retrying the send.\n", 569 osmv_txn_get_tid(p_txn), num_regs); 570 571 /* resend this mad */ 572 ret = osmv_simple_send_madw((osm_bind_handle_t *) p_bo, 573 p_madw, p_txn, TRUE); 574 if (ret != IB_SUCCESS) { 575 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 576 "__osmv_txn_timeout_cb: " 577 "Fail to send retry for transaction" 578 "request (tid=0x%016" PRIx64 ").\n", 579 osmv_txn_get_tid(p_txn)); 580 581 osmv_txn_done((osm_bind_handle_t) p_bo, key, 582 TRUE /*in timeout callback */ ); 583 584 /* This is a requester. Always apply the callback */ 585 invoke_err_cb = TRUE; 586 } else { 587 uint64_t next_timeout_ms; 588 next_timeout_ms = 589 p_bo->p_vendor->resp_timeout * (num_regs + 590 1) * 591 (num_regs + 1); 592 /* when do we need to timeout again */ 593 ret = 594 cl_get_time_stamp() + 595 (uint64_t) (1000 * next_timeout_ms); 596 597 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 598 "__osmv_txn_timeout_cb: " 599 "Retry request timout in : %lu [msec].\n", 600 next_timeout_ms); 601 } 602 } else { 603 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 604 "__osmv_txn_timeout_cb: ERR 6702: " 605 "The transaction request (0x%016" PRIx64 ") " 606 "timed out (after %d retries). " 607 "Invoking the error callback.\n", 608 osmv_txn_get_tid(p_txn), num_regs); 609 610 osmv_txn_done((osm_bind_handle_t) p_bo, key, 611 TRUE /*in timeout callback */ ); 612 613 /* This is a requester. Always apply the callback */ 614 invoke_err_cb = TRUE; 615 } 616 break; 617 618 case OSMV_TXN_RMPP_SENDER: 619 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 620 "RMPP sender (tid=0x%016" PRIx64 ") did not receive ACK " 621 "on every segment in the current send window.\n", 622 osmv_txn_get_tid(p_txn)); 623 624 p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 625 if (num_regs <= OSM_DEFAULT_RETRY_COUNT) { 626 /* We still did not exceed the limit of retransmissions. 627 * Set the next timeout's value. 628 */ 629 ret = 630 cl_get_time_stamp() + 631 1000 * p_bo->p_vendor->resp_timeout; 632 } else { 633 p_send_ctx->status = IB_TIMEOUT; 634 635 p_mad = osm_madw_get_mad_ptr(p_madw); 636 p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); 637 638 /* Send an ABORT to the other side */ 639 osmv_rmpp_send_nak((osm_bind_handle_t) p_bo, p_mad, 640 p_mad_addr, IB_RMPP_TYPE_ABORT, 641 IB_RMPP_STATUS_T2L); 642 } 643 644 /* Wake the RMPP sender thread up */ 645 cl_event_signal(&p_send_ctx->event); 646 break; 647 648 case OSMV_TXN_RMPP_RECEIVER: 649 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 650 "Transaction timeout on an RMPP receiver " 651 "(tid=0x%016" PRIx64 "). Dropping the transaction.\n", 652 osmv_txn_get_tid(p_txn)); 653 654 osmv_txn_done((osm_bind_handle_t) p_bo, key, 655 TRUE /*in timeout callback */ ); 656 657 if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { 658 /* This is a requester, still waiting for the reply. Apply the callback */ 659 invoke_err_cb = TRUE; 660 } 661 662 break; 663 664 default: 665 CL_ASSERT(FALSE); 666 } 667 668 if (TRUE == invoke_err_cb) { 669 CL_ASSERT(NULL != p_madw); 670 /* update the status in the p_madw */ 671 p_madw->status = IB_TIMEOUT; 672 p_bo->send_err_cb(p_bo->cb_context, p_madw); 673 /* no re-registration */ 674 ret = 0; 675 } 676 677txn_done: 678 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 679 return ret; 680} 681