xref: /trueos/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c (revision 8fe640108653f13042f1b15213769e338aa524f6)
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
osmv_txn_init(IN osm_bind_handle_t h_bind,IN uint64_t tid,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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
osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind,IN osmv_txn_ctx_t * p_txn,IN osm_madw_t * p_madw)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
osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind,IN osmv_txn_ctx_t * p_txn,IN boolean_t is_init_by_peer)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
osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind,IN uint64_t key,IN uint64_t msec)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  */
osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind,IN uint64_t key)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
osmv_txn_done(IN osm_bind_handle_t h_bind,IN uint64_t key,IN boolean_t is_in_cb)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
osmv_txn_lookup(IN osm_bind_handle_t h_bind,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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 
osmv_txn_abort_rmpp_txns(osm_bind_handle_t h_bind)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
osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr,IN osm_log_t * p_log,IN cl_spinlock_t * p_lock)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 
osmv_txnmgr_done(IN osm_bind_handle_t h_bind)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
__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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
__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr,IN osmv_txn_ctx_t * p_txn,IN uint64_t key)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
__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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 
__osmv_txn_all_done(osm_bind_handle_t h_bind)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 
osmv_txn_lock(IN osm_bind_handle_t h_bind)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 
osmv_txn_unlock(IN osm_bind_handle_t h_bind)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
__osmv_txn_timeout_cb(IN uint64_t key,IN uint32_t num_regs,IN void * cb_context)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 }
676