1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff#if HAVE_CONFIG_H
37219820Sjeff#  include <config.h>
38219820Sjeff#endif				/* HAVE_CONFIG_H */
39219820Sjeff
40219820Sjeff#include <stdlib.h>
41219820Sjeff
42219820Sjeff#include <vendor/osm_vendor_mlx.h>
43219820Sjeff#include <vendor/osm_vendor_mlx_defs.h>
44219820Sjeff#include <vendor/osm_vendor_mlx_txn.h>
45219820Sjeff#include <vendor/osm_vendor_mlx_svc.h>
46219820Sjeff#include <vendor/osm_vendor_mlx_sender.h>
47219820Sjeff
48219820Sjeffstatic ib_api_status_t
49219820Sjeff__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr,
50219820Sjeff		     IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn);
51219820Sjeff
52219820Sjeffstatic ib_api_status_t
53219820Sjeff__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr,
54219820Sjeff			 IN osmv_txn_ctx_t * p_txn, IN uint64_t key);
55219820Sjeff
56219820Sjeffstatic ib_api_status_t
57219820Sjeff__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr,
58219820Sjeff			 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn);
59219820Sjeff
60219820Sjeffstatic void __osmv_txn_all_done(osm_bind_handle_t h_bind);
61219820Sjeff
62219820Sjeffstatic uint64_t
63219820Sjeff__osmv_txn_timeout_cb(IN uint64_t key,
64219820Sjeff		      IN uint32_t num_regs, IN void *cb_context);
65219820Sjeff
66219820Sjeffib_api_status_t
67219820Sjeffosmv_txn_init(IN osm_bind_handle_t h_bind,
68219820Sjeff	      IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn)
69219820Sjeff{
70219820Sjeff	ib_api_status_t st;
71219820Sjeff	osmv_txn_ctx_t *p_txn;
72219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
73219820Sjeff
74219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
75219820Sjeff
76219820Sjeff	CL_ASSERT(NULL != h_bind && NULL != pp_txn);
77219820Sjeff
78219820Sjeff	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
79219820Sjeff		"Starting transaction 0x%llX (key=0x%llX)\n", tid, key);
80219820Sjeff
81219820Sjeff	p_txn = malloc(sizeof(osmv_txn_ctx_t));
82219820Sjeff	if (!p_txn) {
83219820Sjeff		return IB_INSUFFICIENT_MEMORY;
84219820Sjeff	}
85219820Sjeff
86219820Sjeff	memset(p_txn, 0, sizeof(osmv_txn_ctx_t));
87219820Sjeff	p_txn->p_log = p_bo->txn_mgr.p_log;
88219820Sjeff	p_txn->tid = tid;
89219820Sjeff	p_txn->key = key;
90219820Sjeff	p_txn->p_madw = NULL;
91219820Sjeff	p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_NONE;
92219820Sjeff
93219820Sjeff	/* insert into transaction manager DB */
94219820Sjeff	st = __osmv_txnmgr_insert_txn(&p_bo->txn_mgr, p_txn, key);
95219820Sjeff	if (IB_SUCCESS != st) {
96219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
97219820Sjeff			"osmv_txn_init: ERR 6703: "
98219820Sjeff			"Failed to insert to transaction 0x%llX (key=0x%llX) to manager DB\n",
99219820Sjeff			tid, key);
100219820Sjeff		goto insert_txn_failed;
101219820Sjeff	}
102219820Sjeff
103219820Sjeff	*pp_txn = p_txn;
104219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
105219820Sjeff	return IB_SUCCESS;
106219820Sjeff
107219820Sjeffinsert_txn_failed:
108219820Sjeff	free(p_txn);
109219820Sjeff
110219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
111219820Sjeff	return st;
112219820Sjeff}
113219820Sjeff
114219820Sjeffib_api_status_t
115219820Sjeffosmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind,
116219820Sjeff			  IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw)
117219820Sjeff{
118219820Sjeff	ib_api_status_t st;
119219820Sjeff
120219820Sjeff	CL_ASSERT(p_txn);
121219820Sjeff
122219820Sjeff	/* Double-Sided RMPP Direction Switch */
123219820Sjeff	osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn));
124219820Sjeff
125219820Sjeff	p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_SENDER;
126219820Sjeff	p_txn->rmpp_txfr.p_rmpp_send_ctx = malloc(sizeof(osmv_rmpp_send_ctx_t));
127219820Sjeff
128219820Sjeff	if (!p_txn->rmpp_txfr.p_rmpp_send_ctx) {
129219820Sjeff		return IB_INSUFFICIENT_MEMORY;
130219820Sjeff	}
131219820Sjeff
132219820Sjeff	memset(p_txn->rmpp_txfr.p_rmpp_send_ctx, 0,
133219820Sjeff	       sizeof(osmv_rmpp_send_ctx_t));
134219820Sjeff
135219820Sjeff	st = osmv_rmpp_send_ctx_init(p_txn->rmpp_txfr.p_rmpp_send_ctx,
136219820Sjeff				     (void *)p_madw->p_mad,
137219820Sjeff				     p_madw->mad_size, p_txn->p_log);
138219820Sjeff	return st;
139219820Sjeff}
140219820Sjeff
141219820Sjeffib_api_status_t
142219820Sjeffosmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind,
143219820Sjeff			    IN osmv_txn_ctx_t * p_txn,
144219820Sjeff			    IN boolean_t is_init_by_peer)
145219820Sjeff{
146219820Sjeff	ib_api_status_t st;
147219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
148219820Sjeff	uint64_t key = osmv_txn_get_key(p_txn);
149219820Sjeff
150219820Sjeff	CL_ASSERT(p_txn);
151219820Sjeff
152219820Sjeff	/* Double-Sided RMPP Direction Switch */
153219820Sjeff	osmv_txn_remove_timeout_ev(h_bind, key);
154219820Sjeff
155219820Sjeff	/* Set the Transaction Timeout value */
156219820Sjeff	st = osmv_txn_set_timeout_ev(h_bind, key,
157219820Sjeff				     p_bo->p_vendor->ttime_timeout);
158219820Sjeff	if (IB_SUCCESS != st) {
159219820Sjeff
160219820Sjeff		return st;
161219820Sjeff	}
162219820Sjeff
163219820Sjeff	p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_RECEIVER;
164219820Sjeff	p_txn->rmpp_txfr.is_rmpp_init_by_peer = is_init_by_peer;
165219820Sjeff
166219820Sjeff	p_txn->rmpp_txfr.p_rmpp_recv_ctx = malloc(sizeof(osmv_rmpp_recv_ctx_t));
167219820Sjeff
168219820Sjeff	if (!p_txn->rmpp_txfr.p_rmpp_recv_ctx) {
169219820Sjeff
170219820Sjeff		osmv_txn_remove_timeout_ev(h_bind, key);
171219820Sjeff		return IB_INSUFFICIENT_MEMORY;
172219820Sjeff	}
173219820Sjeff
174219820Sjeff	memset(p_txn->rmpp_txfr.p_rmpp_recv_ctx, 0,
175219820Sjeff	       sizeof(osmv_rmpp_recv_ctx_t));
176219820Sjeff
177219820Sjeff	st = osmv_rmpp_recv_ctx_init(p_txn->rmpp_txfr.p_rmpp_recv_ctx,
178219820Sjeff				     p_txn->p_log);
179219820Sjeff
180219820Sjeff	return st;
181219820Sjeff}
182219820Sjeff
183219820Sjeff/*
184219820Sjeff * NAME
185219820Sjeff *  osmv_txn_set_timeout_ev
186219820Sjeff *
187219820Sjeff * DESCRIPTION
188219820Sjeff *
189219820Sjeff * SEE ALSO
190219820Sjeff *
191219820Sjeff */
192219820Sjeffib_api_status_t
193219820Sjeffosmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind,
194219820Sjeff			IN uint64_t key, IN uint64_t msec)
195219820Sjeff{
196219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
197219820Sjeff	cl_event_wheel_t *p_event_wheel = p_bo->txn_mgr.p_event_wheel;
198219820Sjeff	cl_status_t status;
199219820Sjeff
200219820Sjeff	status = cl_event_wheel_reg(p_event_wheel, key, cl_get_time_stamp() + 1000 * msec,	/* TTL */
201219820Sjeff				    __osmv_txn_timeout_cb,
202219820Sjeff				    p_bo /* The context */ );
203219820Sjeff
204219820Sjeff	return (ib_api_status_t) status;
205219820Sjeff}
206219820Sjeff
207219820Sjeff/*
208219820Sjeff * NAME
209219820Sjeff *  osmv_txn_remove_timeout_ev
210219820Sjeff *
211219820Sjeff * DESCRIPTION
212219820Sjeff
213219820Sjeff * SEE ALSO
214219820Sjeff *
215219820Sjeff */
216219820Sjeffvoid osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind, IN uint64_t key)
217219820Sjeff{
218219820Sjeff	cl_event_wheel_t *p_event_wheel =
219219820Sjeff	    ((osmv_bind_obj_t *) h_bind)->txn_mgr.p_event_wheel;
220219820Sjeff	cl_event_wheel_unreg(p_event_wheel, key);
221219820Sjeff}
222219820Sjeff
223219820Sjeffvoid
224219820Sjeffosmv_txn_done(IN osm_bind_handle_t h_bind,
225219820Sjeff	      IN uint64_t key, IN boolean_t is_in_cb)
226219820Sjeff{
227219820Sjeff	osmv_txn_ctx_t *p_ctx;
228219820Sjeff	osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) h_bind;
229219820Sjeff
230219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
231219820Sjeff
232219820Sjeff	CL_ASSERT(h_bind);
233219820Sjeff
234219820Sjeff	/* Cancel the (single) timeout possibly outstanding for this txn
235219820Sjeff	 * Don't do this if you are in the callback context, for 2 reasons:
236219820Sjeff	 * (1) The event wheel will remove the context itself.
237219820Sjeff	 * (2) If we try to, there is a deadlock in the event wheel
238219820Sjeff	 */
239219820Sjeff	if (FALSE == is_in_cb) {
240219820Sjeff		osmv_txn_remove_timeout_ev(h_bind, key);
241219820Sjeff	}
242219820Sjeff
243219820Sjeff	/* Remove from DB */
244219820Sjeff	if (IB_NOT_FOUND ==
245219820Sjeff	    __osmv_txnmgr_remove_txn(&p_bo->txn_mgr, key, &p_ctx)) {
246219820Sjeff		return;
247219820Sjeff	}
248219820Sjeff
249219820Sjeff	/* Destroy the transaction's RMPP contexts
250219820Sjeff	 * (can be more than one in the case of double sided transfer)
251219820Sjeff	 */
252219820Sjeff
253219820Sjeff	if (p_ctx->rmpp_txfr.p_rmpp_send_ctx) {
254219820Sjeff		osmv_rmpp_send_ctx_done(p_ctx->rmpp_txfr.p_rmpp_send_ctx);
255219820Sjeff	}
256219820Sjeff
257219820Sjeff	if (p_ctx->rmpp_txfr.p_rmpp_recv_ctx) {
258219820Sjeff		osmv_rmpp_recv_ctx_done(p_ctx->rmpp_txfr.p_rmpp_recv_ctx);
259219820Sjeff	}
260219820Sjeff
261219820Sjeff	free(p_ctx);
262219820Sjeff
263219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
264219820Sjeff}
265219820Sjeff
266219820Sjeffib_api_status_t
267219820Sjeffosmv_txn_lookup(IN osm_bind_handle_t h_bind,
268219820Sjeff		IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn)
269219820Sjeff{
270219820Sjeff	return __osmv_txnmgr_lookup(&(((osmv_bind_obj_t *) h_bind)->txn_mgr),
271219820Sjeff				    key, pp_txn);
272219820Sjeff}
273219820Sjeff
274219820Sjeffvoid osmv_txn_abort_rmpp_txns(osm_bind_handle_t h_bind)
275219820Sjeff{
276219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
277219820Sjeff	cl_map_item_t *p_item;
278219820Sjeff	cl_map_obj_t *p_obj;
279219820Sjeff	osmv_txn_ctx_t *p_txn;
280219820Sjeff	osmv_rmpp_send_ctx_t *p_send_ctx;
281219820Sjeff	cl_qmap_t *p_map = p_bo->txn_mgr.p_txn_map;
282219820Sjeff
283219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
284219820Sjeff
285219820Sjeff	while (FALSE == cl_is_qmap_empty(p_map)) {
286219820Sjeff
287219820Sjeff		p_item = cl_qmap_head(p_map);
288219820Sjeff		p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item);
289219820Sjeff		p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj);
290219820Sjeff		p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
291219820Sjeff
292219820Sjeff		if (NULL != p_send_ctx) {
293219820Sjeff
294219820Sjeff			p_send_ctx->status = IB_INTERRUPTED;
295219820Sjeff
296219820Sjeff			/* Wake up the sender thread to let it break out */
297219820Sjeff			cl_event_signal(&p_send_ctx->event);
298219820Sjeff		}
299219820Sjeff
300219820Sjeff		cl_qmap_remove_item(p_map, p_item);
301219820Sjeff	}
302219820Sjeff
303219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
304219820Sjeff}
305219820Sjeff
306219820Sjeffib_api_status_t
307219820Sjeffosmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr,
308219820Sjeff		 IN osm_log_t * p_log, IN cl_spinlock_t * p_lock)
309219820Sjeff{
310219820Sjeff	cl_status_t cl_st = CL_SUCCESS;
311219820Sjeff
312219820Sjeff	p_tx_mgr->p_event_wheel = malloc(sizeof(cl_event_wheel_t));
313219820Sjeff	if (!p_tx_mgr->p_event_wheel) {
314219820Sjeff		return IB_INSUFFICIENT_MEMORY;
315219820Sjeff	}
316219820Sjeff
317219820Sjeff	memset(p_tx_mgr->p_event_wheel, 0, sizeof(cl_event_wheel_t));
318219820Sjeff
319219820Sjeff	cl_event_wheel_construct(p_tx_mgr->p_event_wheel);
320219820Sjeff
321219820Sjeff	/* NOTE! We are using an extended constructor.
322219820Sjeff	 * We tell the Event Wheel run in a non-protected manner in the reg/unreg calls,
323219820Sjeff	 * and acquire an external lock in the asynchronous callback.
324219820Sjeff	 */
325219820Sjeff	cl_st = cl_event_wheel_init_ex(p_tx_mgr->p_event_wheel, p_lock);
326219820Sjeff	if (cl_st != CL_SUCCESS) {
327219820Sjeff		free(p_tx_mgr->p_event_wheel);
328219820Sjeff		return (ib_api_status_t) cl_st;
329219820Sjeff	}
330219820Sjeff
331219820Sjeff	p_tx_mgr->p_txn_map = malloc(sizeof(cl_qmap_t));
332219820Sjeff	if (!p_tx_mgr->p_txn_map) {
333219820Sjeff		cl_event_wheel_destroy(p_tx_mgr->p_event_wheel);
334219820Sjeff		free(p_tx_mgr->p_event_wheel);
335219820Sjeff		return IB_INSUFFICIENT_MEMORY;
336219820Sjeff	}
337219820Sjeff
338219820Sjeff	memset(p_tx_mgr->p_txn_map, 0, sizeof(cl_qmap_t));
339219820Sjeff
340219820Sjeff	cl_qmap_init(p_tx_mgr->p_txn_map);
341219820Sjeff	p_tx_mgr->p_log = p_log;
342219820Sjeff
343219820Sjeff	return cl_st;
344219820Sjeff}
345219820Sjeff
346219820Sjeffvoid osmv_txnmgr_done(IN osm_bind_handle_t h_bind)
347219820Sjeff{
348219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
349219820Sjeff
350219820Sjeff	__osmv_txn_all_done(h_bind);
351219820Sjeff	free(p_bo->txn_mgr.p_txn_map);
352219820Sjeff
353219820Sjeff	cl_event_wheel_destroy(p_bo->txn_mgr.p_event_wheel);
354219820Sjeff	free(p_bo->txn_mgr.p_event_wheel);
355219820Sjeff}
356219820Sjeff
357219820Sjeffib_api_status_t
358219820Sjeff__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr,
359219820Sjeff		     IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn)
360219820Sjeff{
361219820Sjeff	ib_api_status_t status = IB_SUCCESS;
362219820Sjeff	cl_map_item_t *p_item;
363219820Sjeff	cl_map_obj_t *p_obj;
364219820Sjeff
365219820Sjeff	uint64_t tmp_key;
366219820Sjeff
367219820Sjeff	OSM_LOG_ENTER(p_tx_mgr->p_log);
368219820Sjeff
369219820Sjeff	CL_ASSERT(p_tx_mgr);
370219820Sjeff	CL_ASSERT(pp_txn);
371219820Sjeff
372219820Sjeff	osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG,
373219820Sjeff		"__osmv_txnmgr_lookup: "
374219820Sjeff		"Looking for key: 0x%llX in map ptr:%p\n", key,
375219820Sjeff		p_tx_mgr->p_txn_map);
376219820Sjeff
377219820Sjeff	p_item = cl_qmap_head(p_tx_mgr->p_txn_map);
378219820Sjeff	while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) {
379219820Sjeff		tmp_key = cl_qmap_key(p_item);
380219820Sjeff		osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG,
381219820Sjeff			"__osmv_txnmgr_lookup: "
382219820Sjeff			"Found key 0x%llX \n", tmp_key);
383219820Sjeff		p_item = cl_qmap_next(p_item);
384219820Sjeff	}
385219820Sjeff
386219820Sjeff	p_item = cl_qmap_get(p_tx_mgr->p_txn_map, key);
387219820Sjeff	if (cl_qmap_end(p_tx_mgr->p_txn_map) == p_item) {
388219820Sjeff		status = IB_NOT_FOUND;
389219820Sjeff	} else {
390219820Sjeff		p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item);
391219820Sjeff		*pp_txn = cl_qmap_obj(p_obj);
392219820Sjeff	}
393219820Sjeff
394219820Sjeff	OSM_LOG_EXIT(p_tx_mgr->p_log);
395219820Sjeff	return status;
396219820Sjeff}
397219820Sjeff
398219820Sjeffib_api_status_t
399219820Sjeff__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr,
400219820Sjeff			 IN osmv_txn_ctx_t * p_txn, IN uint64_t key)
401219820Sjeff{
402219820Sjeff	cl_map_obj_t *p_obj = NULL;
403219820Sjeff	cl_map_item_t *p_item;
404219820Sjeff	uint64_t tmp_key;
405219820Sjeff
406219820Sjeff	CL_ASSERT(p_tx_mgr);
407219820Sjeff	CL_ASSERT(p_txn);
408219820Sjeff
409219820Sjeff	key = osmv_txn_get_key(p_txn);
410219820Sjeff	p_obj = malloc(sizeof(cl_map_obj_t));
411219820Sjeff	if (NULL == p_obj)
412219820Sjeff		return IB_INSUFFICIENT_MEMORY;
413219820Sjeff
414219820Sjeff	osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG,
415219820Sjeff		"__osmv_txnmgr_insert_txn: "
416219820Sjeff		"Inserting key: 0x%llX to map ptr:%p\n", key,
417219820Sjeff		p_tx_mgr->p_txn_map);
418219820Sjeff
419219820Sjeff	memset(p_obj, 0, sizeof(cl_map_obj_t));
420219820Sjeff
421219820Sjeff	cl_qmap_set_obj(p_obj, p_txn);
422219820Sjeff	/* assuming lookup with this key was made and the result was IB_NOT_FOUND */
423219820Sjeff	cl_qmap_insert(p_tx_mgr->p_txn_map, key, &p_obj->item);
424219820Sjeff
425219820Sjeff	p_item = cl_qmap_head(p_tx_mgr->p_txn_map);
426219820Sjeff	while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) {
427219820Sjeff		tmp_key = cl_qmap_key(p_item);
428219820Sjeff		osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG,
429219820Sjeff			"__osmv_txnmgr_insert_txn: "
430219820Sjeff			"Found key 0x%llX \n", tmp_key);
431219820Sjeff		p_item = cl_qmap_next(p_item);
432219820Sjeff	}
433219820Sjeff
434219820Sjeff	return IB_SUCCESS;
435219820Sjeff}
436219820Sjeff
437219820Sjeffib_api_status_t
438219820Sjeff__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr,
439219820Sjeff			 IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn)
440219820Sjeff{
441219820Sjeff	cl_map_obj_t *p_obj;
442219820Sjeff	cl_map_item_t *p_item;
443219820Sjeff
444219820Sjeff	OSM_LOG_ENTER(p_tx_mgr->p_log);
445219820Sjeff
446219820Sjeff	CL_ASSERT(p_tx_mgr);
447219820Sjeff	CL_ASSERT(pp_txn);
448219820Sjeff
449219820Sjeff	p_item = cl_qmap_remove(p_tx_mgr->p_txn_map, key);
450219820Sjeff
451219820Sjeff	if (p_item == cl_qmap_end(p_tx_mgr->p_txn_map)) {
452219820Sjeff
453219820Sjeff		osm_log(p_tx_mgr->p_log, OSM_LOG_ERROR,
454219820Sjeff			"__osmv_txnmgr_remove_txn: ERR 6701: "
455219820Sjeff			"Could not remove the transaction 0x%llX - "
456219820Sjeff			"something is really wrong!\n", key);
457219820Sjeff		OSM_LOG_EXIT(p_tx_mgr->p_log);
458219820Sjeff		return IB_NOT_FOUND;
459219820Sjeff	}
460219820Sjeff
461219820Sjeff	p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item);
462219820Sjeff	*pp_txn = cl_qmap_obj(p_obj);
463219820Sjeff
464219820Sjeff	free(p_obj);
465219820Sjeff
466219820Sjeff	OSM_LOG_EXIT(p_tx_mgr->p_log);
467219820Sjeff	return IB_SUCCESS;
468219820Sjeff}
469219820Sjeff
470219820Sjeffvoid __osmv_txn_all_done(osm_bind_handle_t h_bind)
471219820Sjeff{
472219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
473219820Sjeff	cl_map_item_t *p_item;
474219820Sjeff	cl_map_obj_t *p_obj;
475219820Sjeff	osmv_txn_ctx_t *p_txn;
476219820Sjeff
477219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
478219820Sjeff
479219820Sjeff	p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map);
480219820Sjeff	while (p_item != cl_qmap_end(p_bo->txn_mgr.p_txn_map)) {
481219820Sjeff
482219820Sjeff		p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item);
483219820Sjeff		p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj);
484219820Sjeff		osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE);
485219820Sjeff		free(p_obj);
486219820Sjeff		/* assuming osmv_txn_done has removed the txn from the map */
487219820Sjeff		p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map);
488219820Sjeff	}
489219820Sjeff
490219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
491219820Sjeff}
492219820Sjeff
493219820Sjeff/******************************************************************************/
494219820Sjeff
495219820Sjeffvoid osmv_txn_lock(IN osm_bind_handle_t h_bind)
496219820Sjeff{
497219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
498219820Sjeff
499219820Sjeff	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
500219820Sjeff		"--> Acquiring lock %p on bind handle %p\n", &p_bo->lock, p_bo);
501219820Sjeff
502219820Sjeff	cl_spinlock_acquire(&p_bo->lock);
503219820Sjeff
504219820Sjeff	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
505219820Sjeff		"--> Acquired lock %p on bind handle %p\n", &p_bo->lock, p_bo);
506219820Sjeff}
507219820Sjeff
508219820Sjeffvoid osmv_txn_unlock(IN osm_bind_handle_t h_bind)
509219820Sjeff{
510219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
511219820Sjeff	cl_spinlock_t *p_lock = &p_bo->lock;
512219820Sjeff	osm_log_t *p_log = p_bo->p_vendor->p_log;
513219820Sjeff
514219820Sjeff	osm_log(p_log, OSM_LOG_DEBUG,
515219820Sjeff		"<-- Releasing lock %p on bind handle %p\n", p_lock, p_bo);
516219820Sjeff
517219820Sjeff	cl_spinlock_release(&p_bo->lock);
518219820Sjeff
519219820Sjeff	/* We'll use the saved ptrs, since now the p_bo can be destroyed already */
520219820Sjeff	osm_log(p_log, OSM_LOG_DEBUG,
521219820Sjeff		"<-- Released lock %p on bind handle %p\n", p_lock, p_bo);
522219820Sjeff
523219820Sjeff}
524219820Sjeff
525219820Sjeffstatic uint64_t
526219820Sjeff__osmv_txn_timeout_cb(IN uint64_t key,
527219820Sjeff		      IN uint32_t num_regs, IN void *cb_context)
528219820Sjeff{
529219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) cb_context;
530219820Sjeff	uint64_t ret = 0;
531219820Sjeff	osmv_txn_ctx_t *p_txn;
532219820Sjeff	osmv_rmpp_send_ctx_t *p_send_ctx;
533219820Sjeff	osm_madw_t *p_madw = NULL;
534219820Sjeff	ib_mad_t *p_mad;
535219820Sjeff	osm_mad_addr_t *p_mad_addr;
536219820Sjeff	boolean_t invoke_err_cb = FALSE;
537219820Sjeff
538219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
539219820Sjeff
540219820Sjeff	/* Don't try to acquire a lock on the Bind Object -
541219820Sjeff	 * it's taken by the mechanism that drives the timeout based events!
542219820Sjeff	 * (Recall the special constructor that the Event Wheel is applied with)
543219820Sjeff	 */
544219820Sjeff	if (p_bo->is_closing) {
545219820Sjeff		goto txn_done;
546219820Sjeff	}
547219820Sjeff
548219820Sjeff	ret = osmv_txn_lookup(p_bo, key, &p_txn);
549219820Sjeff	if (IB_NOT_FOUND == ret) {
550219820Sjeff		/* Prevent a race - the transaction is already destroyed */
551219820Sjeff		goto txn_done;
552219820Sjeff	}
553219820Sjeff
554219820Sjeff	p_madw = p_txn->p_madw;
555219820Sjeff
556219820Sjeff	switch (osmv_txn_get_rmpp_state(p_txn)) {
557219820Sjeff
558219820Sjeff	case OSMV_TXN_RMPP_NONE:
559219820Sjeff		if (num_regs <= OSMV_MAX_RETRANSMIT) {
560219820Sjeff			/* We still did not exceed the limit of retransmissions.
561219820Sjeff			 * Set the next timeout's value.
562219820Sjeff			 */
563219820Sjeff			osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
564219820Sjeff				"__osmv_txn_timeout_cb: "
565219820Sjeff				"The transaction request (tid=0x%llX) timed out %d times. "
566219820Sjeff				"Retrying the send.\n",
567219820Sjeff				osmv_txn_get_tid(p_txn), num_regs);
568219820Sjeff
569219820Sjeff			/* resend this mad */
570219820Sjeff			ret = osmv_simple_send_madw((osm_bind_handle_t *) p_bo,
571219820Sjeff						    p_madw, p_txn, TRUE);
572219820Sjeff			if (ret != IB_SUCCESS) {
573219820Sjeff				osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
574219820Sjeff					"__osmv_txn_timeout_cb: "
575219820Sjeff					"Fail to send retry for transaction request (tid=0x%llX).\n",
576219820Sjeff					osmv_txn_get_tid(p_txn));
577219820Sjeff
578219820Sjeff				osmv_txn_done((osm_bind_handle_t) p_bo, key,
579219820Sjeff					      TRUE /*in timeout callback */ );
580219820Sjeff
581219820Sjeff				/* This is a requester. Always apply the callback */
582219820Sjeff				invoke_err_cb = TRUE;
583219820Sjeff			} else {
584219820Sjeff				uint64_t next_timeout_ms;
585219820Sjeff				next_timeout_ms =
586219820Sjeff				    p_bo->p_vendor->resp_timeout * (num_regs +
587219820Sjeff								    1) *
588219820Sjeff				    (num_regs + 1);
589219820Sjeff				/* when do we need to timeout again */
590219820Sjeff				ret =
591219820Sjeff				    cl_get_time_stamp() +
592219820Sjeff				    (uint64_t) (1000 * next_timeout_ms);
593219820Sjeff
594219820Sjeff				osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
595219820Sjeff					"__osmv_txn_timeout_cb: "
596219820Sjeff					"Retry request timout in : %lu [msec].\n",
597219820Sjeff					next_timeout_ms);
598219820Sjeff			}
599219820Sjeff		} else {
600219820Sjeff			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
601219820Sjeff				"__osmv_txn_timeout_cb: ERR 6702: "
602219820Sjeff				"The transaction request (tid=0x%llX) timed out (after %d retries). "
603219820Sjeff				"Invoking the error callback.\n",
604219820Sjeff				osmv_txn_get_tid(p_txn), num_regs);
605219820Sjeff
606219820Sjeff			osmv_txn_done((osm_bind_handle_t) p_bo, key,
607219820Sjeff				      TRUE /*in timeout callback */ );
608219820Sjeff
609219820Sjeff			/* This is a requester. Always apply the callback */
610219820Sjeff			invoke_err_cb = TRUE;
611219820Sjeff		}
612219820Sjeff		break;
613219820Sjeff
614219820Sjeff	case OSMV_TXN_RMPP_SENDER:
615219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
616219820Sjeff			"RMPP sender (tid=0x%llX) did not receive ACK "
617219820Sjeff			"on every segment in the current send window.\n",
618219820Sjeff			osmv_txn_get_tid(p_txn));
619219820Sjeff
620219820Sjeff		p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
621219820Sjeff		if (num_regs <= OSMV_MAX_RETRANSMIT) {
622219820Sjeff			/* We still did not exceed the limit of retransmissions.
623219820Sjeff			 * Set the next timeout's value.
624219820Sjeff			 */
625219820Sjeff			ret =
626219820Sjeff			    cl_get_time_stamp() +
627219820Sjeff			    1000 * p_bo->p_vendor->resp_timeout;
628219820Sjeff		} else {
629219820Sjeff			p_send_ctx->status = IB_TIMEOUT;
630219820Sjeff
631219820Sjeff			p_mad = osm_madw_get_mad_ptr(p_madw);
632219820Sjeff			p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
633219820Sjeff
634219820Sjeff			/* Send an ABORT to the other side */
635219820Sjeff			osmv_rmpp_send_nak((osm_bind_handle_t) p_bo, p_mad,
636219820Sjeff					   p_mad_addr, IB_RMPP_TYPE_ABORT,
637219820Sjeff					   IB_RMPP_STATUS_T2L);
638219820Sjeff		}
639219820Sjeff
640219820Sjeff		/* Wake the RMPP sender thread up */
641219820Sjeff		cl_event_signal(&p_send_ctx->event);
642219820Sjeff		break;
643219820Sjeff
644219820Sjeff	case OSMV_TXN_RMPP_RECEIVER:
645219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
646219820Sjeff			"Transaction timeout on an RMPP receiver (tid=0x%llX). "
647219820Sjeff			"Dropping the transaction.\n", osmv_txn_get_tid(p_txn));
648219820Sjeff
649219820Sjeff		osmv_txn_done((osm_bind_handle_t) p_bo, key,
650219820Sjeff			      TRUE /*in timeout callback */ );
651219820Sjeff
652219820Sjeff		if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) {
653219820Sjeff			/* This is a requester, still waiting for the reply. Apply the callback */
654219820Sjeff			invoke_err_cb = TRUE;
655219820Sjeff		}
656219820Sjeff
657219820Sjeff		break;
658219820Sjeff
659219820Sjeff	default:
660219820Sjeff		CL_ASSERT(FALSE);
661219820Sjeff	}
662219820Sjeff
663219820Sjeff	if (TRUE == invoke_err_cb) {
664219820Sjeff		CL_ASSERT(NULL != p_madw);
665219820Sjeff		/* update the status in the p_madw */
666219820Sjeff		p_madw->status = IB_TIMEOUT;
667219820Sjeff		p_bo->send_err_cb(p_bo->cb_context, p_madw);
668219820Sjeff		/* no re-registration */
669219820Sjeff		ret = 0;
670219820Sjeff	}
671219820Sjeff
672219820Sjefftxn_done:
673219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
674219820Sjeff	return ret;
675219820Sjeff}
676