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