]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/libvendor/osm_vendor_mlx_txn.c
MFV r353606: 10067 Miscellaneous man page typos
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / libvendor / osm_vendor_mlx_txn.c
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
48 static 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
52 static 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
56 static 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
60 static void __osmv_txn_all_done(osm_bind_handle_t h_bind);
61
62 static uint64_t
63 __osmv_txn_timeout_cb(IN uint64_t key,
64                       IN uint32_t num_regs, IN void *cb_context);
65
66 ib_api_status_t
67 osmv_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
109 insert_txn_failed:
110         free(p_txn);
111
112         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
113         return st;
114 }
115
116 ib_api_status_t
117 osmv_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
143 ib_api_status_t
144 osmv_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  */
194 ib_api_status_t
195 osmv_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  */
218 void 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
225 void
226 osmv_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
268 ib_api_status_t
269 osmv_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
276 void 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
308 ib_api_status_t
309 osmv_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
348 void 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
359 ib_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
400 ib_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
439 ib_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
472 void __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
497 void 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
510 void 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
527 static 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
677 txn_done:
678         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
679         return ret;
680 }