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
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%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
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)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
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)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
osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind,IN uint64_t key,IN uint64_t msec)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  */
osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind,IN uint64_t key)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
osmv_txn_done(IN osm_bind_handle_t h_bind,IN uint64_t key,IN boolean_t is_in_cb)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
osmv_txn_lookup(IN osm_bind_handle_t h_bind,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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 
osmv_txn_abort_rmpp_txns(osm_bind_handle_t h_bind)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
osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr,IN osm_log_t * p_log,IN cl_spinlock_t * p_lock)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 
osmv_txnmgr_done(IN osm_bind_handle_t h_bind)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
__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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
__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr,IN osmv_txn_ctx_t * p_txn,IN uint64_t key)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
__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr,IN uint64_t key,OUT osmv_txn_ctx_t ** pp_txn)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 
__osmv_txn_all_done(osm_bind_handle_t h_bind)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 
osmv_txn_lock(IN osm_bind_handle_t h_bind)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 
osmv_txn_unlock(IN osm_bind_handle_t h_bind)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
__osmv_txn_timeout_cb(IN uint64_t key,IN uint32_t num_regs,IN void * cb_context)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 }
681