]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / libvendor / osm_vendor_mlx_txn.c
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
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%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
107 insert_txn_failed:
108         free(p_txn);
109
110         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
111         return st;
112 }
113
114 ib_api_status_t
115 osmv_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
141 ib_api_status_t
142 osmv_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  */
192 ib_api_status_t
193 osmv_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  */
216 void 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
223 void
224 osmv_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
266 ib_api_status_t
267 osmv_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
274 void 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
306 ib_api_status_t
307 osmv_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
346 void 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
357 ib_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
398 ib_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
437 ib_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
470 void __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
495 void 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
508 void 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
525 static 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
672 txn_done:
673         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
674         return ret;
675 }