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#include <string.h>
42#include <vendor/osm_vendor_mlx.h>
43#include <vendor/osm_vendor_mlx_transport.h>
44#include <vendor/osm_vendor_mlx_svc.h>
45#include <vendor/osm_vendor_mlx_sender.h>
46#include <vendor/osm_vendor_mlx_hca.h>
47#include <vendor/osm_pkt_randomizer.h>
48
49/**
50 *      FORWARD REFERENCES
51 */
52static ib_api_status_t
53__osmv_get_send_txn(IN osm_bind_handle_t h_bind,
54		    IN osm_madw_t * const p_madw,
55		    IN boolean_t is_rmpp,
56		    IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn);
57
58static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind);
59
60/*
61 *  NAME            osm_vendor_new
62 *
63 *  DESCRIPTION     Create and Initialize the osm_vendor_t Object
64 */
65
66osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
67			     IN const uint32_t timeout)
68{
69	ib_api_status_t status;
70	osm_vendor_t *p_vend;
71
72	OSM_LOG_ENTER(p_log);
73
74	CL_ASSERT(p_log);
75
76	p_vend = malloc(sizeof(*p_vend));
77	if (p_vend != NULL) {
78		memset(p_vend, 0, sizeof(*p_vend));
79
80		status = osm_vendor_init(p_vend, p_log, timeout);
81		if (status != IB_SUCCESS) {
82			osm_vendor_delete(&p_vend);
83		}
84	} else {
85		osm_log(p_vend->p_log, OSM_LOG_ERROR,
86			"osm_vendor_new: ERR 7301: "
87			"Fail to allocate vendor object.\n");
88	}
89
90	OSM_LOG_EXIT(p_log);
91	return (p_vend);
92}
93
94/*
95 *  NAME            osm_vendor_delete
96 *
97 *  DESCRIPTION     Delete all the binds behind the vendor + free the vendor object
98 */
99
100void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
101{
102	cl_list_item_t *p_item;
103	cl_list_obj_t *p_obj;
104	osm_bind_handle_t bind_h;
105	osm_log_t *p_log;
106
107	OSM_LOG_ENTER((*pp_vend)->p_log);
108	p_log = (*pp_vend)->p_log;
109
110	/* go over the bind handles , unbind them and remove from list */
111	p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles));
112	while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) {
113
114		p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
115		bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj);
116		osm_log(p_log, OSM_LOG_DEBUG,
117			"osm_vendor_delete: unbinding bind_h:%p \n", bind_h);
118
119		__osm_vendor_internal_unbind(bind_h);
120
121		free(p_obj);
122		/*removing from list */
123		p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles));
124	}
125
126	if (NULL != ((*pp_vend)->p_transport_info)) {
127		free((*pp_vend)->p_transport_info);
128		(*pp_vend)->p_transport_info = NULL;
129	}
130
131	/* remove the packet randomizer object */
132	if ((*pp_vend)->run_randomizer == TRUE)
133		osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer),
134					   p_log);
135
136	free(*pp_vend);
137	*pp_vend = NULL;
138
139	OSM_LOG_EXIT(p_log);
140}
141
142/*
143 *  NAME            osm_vendor_init
144 *
145 *  DESCRIPTION     Initialize the vendor object
146 */
147
148ib_api_status_t
149osm_vendor_init(IN osm_vendor_t * const p_vend,
150		IN osm_log_t * const p_log, IN const uint32_t timeout)
151{
152	ib_api_status_t status = IB_SUCCESS;
153
154	OSM_LOG_ENTER(p_log);
155
156	p_vend->p_transport_info = NULL;
157	p_vend->p_log = p_log;
158	p_vend->resp_timeout = timeout;
159	p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR;
160
161	cl_qlist_init(&p_vend->bind_handles);
162
163	/* update the run_randomizer flag */
164	if (getenv("OSM_PKT_DROP_RATE") != NULL
165	    && atol(getenv("OSM_PKT_DROP_RATE")) != 0) {
166		/* if the OSM_PKT_DROP_RATE global variable is defined to a non-zero value -
167		   then the randomizer should be called.
168		   Need to create the packet randomizer object */
169		p_vend->run_randomizer = TRUE;
170		status =
171		    osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log);
172		if (status != IB_SUCCESS)
173			return status;
174	} else {
175		p_vend->run_randomizer = FALSE;
176		p_vend->p_pkt_randomizer = NULL;
177	}
178
179	OSM_LOG_EXIT(p_log);
180	return (IB_SUCCESS);
181}
182
183/*
184 *  NAME            osm_vendor_bind
185 *
186 *  DESCRIPTION     Create a new bind object under the vendor object
187 */
188
189osm_bind_handle_t
190osm_vendor_bind(IN osm_vendor_t * const p_vend,
191		IN osm_bind_info_t * const p_bind_info,
192		IN osm_mad_pool_t * const p_mad_pool,
193		IN osm_vend_mad_recv_callback_t mad_recv_callback,
194		IN osm_vend_mad_send_err_callback_t send_err_callback,
195		IN void *context)
196{
197	osmv_bind_obj_t *p_bo;
198	ib_api_status_t status;
199	char hca_id[32];
200	cl_status_t cl_st;
201	cl_list_obj_t *p_obj;
202	uint8_t hca_index;
203
204	if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool
205	    || NULL == mad_recv_callback || NULL == send_err_callback) {
206		osm_log(p_vend->p_log, OSM_LOG_ERROR,
207			"osm_vendor_bind: ERR 7302: "
208			"NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n",
209			p_vend, p_bind_info, p_mad_pool, mad_recv_callback,
210			send_err_callback);
211
212		return OSM_BIND_INVALID_HANDLE;
213	}
214
215	p_bo = malloc(sizeof(osmv_bind_obj_t));
216	if (NULL == p_bo) {
217		osm_log(p_vend->p_log, OSM_LOG_ERROR,
218			"osm_vendor_bind: ERR 7303: could not allocate the bind object\n");
219		return OSM_BIND_INVALID_HANDLE;
220	}
221
222	memset(p_bo, 0, sizeof(osmv_bind_obj_t));
223	p_bo->p_vendor = p_vend;
224	p_bo->recv_cb = mad_recv_callback;
225	p_bo->send_err_cb = send_err_callback;
226	p_bo->cb_context = context;
227	p_bo->p_osm_pool = p_mad_pool;
228
229	/* obtain the hca name and port num from the guid */
230	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
231		"osm_vendor_bind: "
232		"Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
233		cl_ntoh64(p_bind_info->port_guid));
234
235	status = osm_vendor_get_guid_ca_and_port(p_bo->p_vendor,
236						 p_bind_info->port_guid,
237						 &(p_bo->hca_hndl),
238						 hca_id,
239						 &hca_index, &(p_bo->port_num));
240	if (status != IB_SUCCESS) {
241		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
242			"osm_vendor_bind: ERR 7304: "
243			"Fail to find port number of port guid:0x%016" PRIx64
244			"\n", p_bind_info->port_guid);
245		free(p_bo);
246		return OSM_BIND_INVALID_HANDLE;
247	}
248
249	/* Initialize the magic_ptr to the pointer of the p_bo info.
250	   This will be used to signal when the object is being destroyed, so no
251	   real action will be done then. */
252	p_bo->magic_ptr = p_bo;
253
254	p_bo->is_closing = FALSE;
255
256	cl_spinlock_construct(&(p_bo->lock));
257	cl_st = cl_spinlock_init(&(p_bo->lock));
258	if (cl_st != CL_SUCCESS) {
259		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
260			"osm_vendor_bind: ERR 7305: "
261			"could not initialize the spinlock ...\n");
262		free(p_bo);
263		return OSM_BIND_INVALID_HANDLE;
264	}
265
266	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
267		"osm_vendor_bind: osmv_txnmgr_init ... \n");
268	if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) !=
269	    IB_SUCCESS) {
270		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
271			"osm_vendor_bind: ERR 7306: "
272			"osmv_txnmgr_init failed \n");
273		cl_spinlock_destroy(&p_bo->lock);
274		free(p_bo);
275		return OSM_BIND_INVALID_HANDLE;
276	}
277
278	/* Do the real job! (Transport-dependent) */
279	if (IB_SUCCESS !=
280	    osmv_transport_init(p_bind_info, hca_id, hca_index, p_bo)) {
281		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
282			"osm_vendor_bind: ERR 7307: "
283			"osmv_transport_init failed \n");
284		osmv_txnmgr_done((osm_bind_handle_t) p_bo);
285		cl_spinlock_destroy(&p_bo->lock);
286		free(p_bo);
287		return OSM_BIND_INVALID_HANDLE;
288	}
289
290	/* insert bind handle into db */
291	p_obj = malloc(sizeof(cl_list_obj_t));
292	if (NULL == p_obj) {
293
294		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
295			"osm_vendor_bind: ERR 7308: "
296			"osm_vendor_bind: could not allocate the list object\n");
297
298		osmv_transport_done(p_bo->p_transp_mgr);
299		osmv_txnmgr_done((osm_bind_handle_t) p_bo);
300		cl_spinlock_destroy(&p_bo->lock);
301		free(p_bo);
302		return OSM_BIND_INVALID_HANDLE;
303	}
304	memset(p_obj, 0, sizeof(cl_list_obj_t));
305	cl_qlist_set_obj(p_obj, p_bo);
306
307	cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item);
308
309	return (osm_bind_handle_t) p_bo;
310}
311
312/*
313 *  NAME            osm_vendor_unbind
314 *
315 *  DESCRIPTION     Destroy the bind object and remove it from the vendor's list
316 */
317
318void osm_vendor_unbind(IN osm_bind_handle_t h_bind)
319{
320	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
321	osm_log_t *p_log = p_bo->p_vendor->p_log;
322	cl_list_obj_t *p_obj = NULL;
323	cl_list_item_t *p_item, *p_item_tmp;
324	cl_qlist_t *const p_bh_list =
325	    (cl_qlist_t * const)&p_bo->p_vendor->bind_handles;
326
327	OSM_LOG_ENTER(p_log);
328
329	/* go over all the items in the list and remove the specific item */
330	p_item = cl_qlist_head(p_bh_list);
331	while (p_item != cl_qlist_end(p_bh_list)) {
332		p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
333		if (cl_qlist_obj(p_obj) == h_bind) {
334			break;
335		}
336		p_item_tmp = cl_qlist_next(p_item);
337		p_item = p_item_tmp;
338	}
339
340	CL_ASSERT(p_item != cl_qlist_end(p_bh_list));
341
342	cl_qlist_remove_item(p_bh_list, p_item);
343	if (p_obj)
344		free(p_obj);
345
346	if (h_bind != 0) {
347		__osm_vendor_internal_unbind(h_bind);
348	}
349
350	OSM_LOG_EXIT(p_log);
351}
352
353/*
354 *  NAME            osm_vendor_get
355 *
356 *  DESCRIPTION     Allocate the space for a new MAD
357 */
358
359ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
360			 IN const uint32_t mad_size,
361			 IN osm_vend_wrap_t * const p_vw)
362{
363	ib_mad_t *p_mad;
364	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
365	osm_vendor_t const *p_vend = p_bo->p_vendor;
366	uint32_t act_mad_size;
367
368	OSM_LOG_ENTER(p_vend->p_log);
369
370	CL_ASSERT(p_vw);
371
372	if (mad_size < MAD_BLOCK_SIZE) {
373		/* Stupid, but the applications want that! */
374		act_mad_size = MAD_BLOCK_SIZE;
375	} else {
376		act_mad_size = mad_size;
377	}
378
379	/* allocate it */
380	p_mad = (ib_mad_t *) malloc(act_mad_size);
381	if (p_mad == NULL) {
382		osm_log(p_vend->p_log, OSM_LOG_ERROR,
383			"osm_vendor_get: ERR 7309: "
384			"Error Obtaining MAD buffer.\n");
385		goto Exit;
386	}
387
388	memset(p_mad, 0, act_mad_size);
389
390	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
391		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
392			"osm_vendor_get: "
393			"Allocated MAD %p, size = %u.\n", p_mad, act_mad_size);
394	}
395	p_vw->p_mad = p_mad;
396
397Exit:
398	OSM_LOG_EXIT(p_vend->p_log);
399	return (p_mad);
400}
401
402/*
403 *  NAME            osm_vendor_send
404 *
405 *  DESCRIPTION     Send a MAD buffer (RMPP or simple send).
406 *
407 *                  Semantics:
408 *                   (1) The RMPP send completes when every segment
409 *                       is acknowledged (synchronous)
410 *                   (2) The simple send completes when the send completion
411 *                       is received (asynchronous)
412 */
413
414ib_api_status_t
415osm_vendor_send(IN osm_bind_handle_t h_bind,
416		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
417{
418	ib_api_status_t ret = IB_SUCCESS;
419	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
420	boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE;
421	osmv_txn_ctx_t *p_txn = NULL;
422	ib_mad_t *p_mad;
423	osm_log_t *p_log = p_bo->p_vendor->p_log;
424	osm_mad_pool_t *p_mad_pool = p_bo->p_osm_pool;
425	OSM_LOG_ENTER(p_log);
426
427	if (NULL == h_bind || NULL == p_madw ||
428	    NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) ||
429	    NULL == osm_madw_get_mad_addr_ptr(p_madw)) {
430
431		return IB_INVALID_PARAMETER;
432	}
433
434	is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE
435		   || osmv_mad_is_rmpp(p_mad));
436	/* is this rmpp double sided? This means we expect a response that can be
437	   an rmpp or not */
438	is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected);
439
440	/* Make our operations with the send context atomic */
441	osmv_txn_lock(p_bo);
442
443	if (TRUE == p_bo->is_closing) {
444
445		osm_log(p_log, OSM_LOG_ERROR,
446			"osm_vendor_send: ERR 7310: "
447			"The handle %p is being unbound, cannot send.\n",
448			h_bind);
449		ret = IB_INTERRUPTED;
450		/* When closing p_bo could be detroyed or is going to , thus could not refer to it */
451		goto send_done;
452	}
453
454	if (TRUE == resp_expected || TRUE == is_rmpp) {
455
456		/* We must run under a transaction framework.
457		 * Get the transaction object (old or new) */
458		ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp,
459					  resp_expected, &p_txn);
460		if (IB_SUCCESS != ret) {
461			goto send_done;
462		}
463	}
464
465	if (TRUE == is_rmpp) {
466		/* Do the job - RMPP!
467		 * The call returns as all the packets are ACK'ed/upon error
468		 * The txn lock will be released each time the function sleeps
469		 * and re-acquired when it wakes up
470		 */
471		ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds);
472	} else {
473
474		/* Do the job - single MAD!
475		 * The call returns as soon as the MAD is put on the wire
476		 */
477		ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE);
478	}
479
480	if (IB_SUCCESS == ret) {
481
482		if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) {
483			/* For double-sided sends, the txn continues to live */
484			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
485				      FALSE /*not in callback */ );
486		}
487
488		if (FALSE == resp_expected) {
489			osm_mad_pool_put(p_mad_pool, p_madw);
490		}
491	} else if (IB_INTERRUPTED != ret) {
492		if (NULL != p_txn) {
493			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
494				      FALSE /*not in callback */ );
495		}
496
497		osm_log(p_log, OSM_LOG_ERROR,
498			"osm_vendor_send: ERR 7311: failed to send MADW %p\n",
499			p_madw);
500
501		if (TRUE == resp_expected) {
502			/* Change the status on the p_madw */
503			p_madw->status = ret;
504			/* Only the requester expects the error callback */
505			p_bo->send_err_cb(p_bo->cb_context, p_madw);
506		} else {
507			/* put back the mad - it is useless ... */
508			osm_mad_pool_put(p_mad_pool, p_madw);
509		}
510	} else {		/* the transaction was aborted due to p_bo exit */
511
512		osm_mad_pool_put(p_mad_pool, p_madw);
513		goto aborted;
514	}
515send_done:
516
517	osmv_txn_unlock(p_bo);
518aborted:
519	OSM_LOG_EXIT(p_log);
520	return ret;
521}
522
523/*
524 *  NAME            osm_vendor_put
525 *
526 *  DESCRIPTION     Free the MAD's memory
527 */
528
529void
530osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
531{
532
533	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
534	osm_vendor_t const *p_vend = p_bo->p_vendor;
535
536	if (p_bo->is_closing != TRUE) {
537		OSM_LOG_ENTER(p_vend->p_log);
538
539		CL_ASSERT(p_vw);
540		CL_ASSERT(p_vw->p_mad);
541
542		if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
543			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
544				"osm_vendor_put: " "Retiring MAD %p.\n",
545				p_vw->p_mad);
546		}
547
548		free(p_vw->p_mad);
549		p_vw->p_mad = NULL;
550
551		OSM_LOG_EXIT(p_vend->p_log);
552	}
553}
554
555/*
556 *  NAME            osm_vendor_local_lid_change
557 *
558 *  DESCRIPTION     Notifies the vendor transport layer that the local address
559 *                  has changed.  This allows the vendor layer to perform
560 *                  housekeeping functions such as address vector updates.
561 */
562
563ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
564{
565	osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor;
566	OSM_LOG_ENTER(p_vend->p_log);
567
568	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
569		"osm_vendor_local_lid_change: " "Change of LID.\n");
570
571	OSM_LOG_EXIT(p_vend->p_log);
572
573	return (IB_SUCCESS);
574
575}
576
577/*
578 *  NAME            osm_vendor_set_sm
579 *
580 *  DESCRIPTION     Modifies the port info for the bound port to set the "IS_SM" bit
581 *                  according to the value given (TRUE or FALSE).
582 */
583#if !(defined(OSM_VENDOR_INTF_TS_NO_VAPI) || defined(OSM_VENDOR_INTF_SIM) || defined(OSM_VENDOR_INTF_TS))
584void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
585{
586	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
587	osm_vendor_t const *p_vend = p_bo->p_vendor;
588	VAPI_ret_t status;
589	VAPI_hca_attr_t attr_mod;
590	VAPI_hca_attr_mask_t attr_mask;
591
592	OSM_LOG_ENTER(p_vend->p_log);
593
594	memset(&attr_mod, 0, sizeof(attr_mod));
595	memset(&attr_mask, 0, sizeof(attr_mask));
596
597	attr_mod.is_sm = is_sm_val;
598	attr_mask = HCA_ATTR_IS_SM;
599
600	status =
601	    VAPI_modify_hca_attr(p_bo->hca_hndl, p_bo->port_num, &attr_mod,
602				 &attr_mask);
603	if (status != VAPI_OK) {
604		osm_log(p_vend->p_log, OSM_LOG_ERROR,
605			"osm_vendor_set_sm: ERR 7312: "
606			"Unable set 'IS_SM' bit to:%u in port attributes (%d).\n",
607			is_sm_val, status);
608	}
609
610	OSM_LOG_EXIT(p_vend->p_log);
611}
612
613#endif
614
615/*
616 *  NAME            __osm_vendor_internal_unbind
617 *
618 *  DESCRIPTION     Destroying a bind:
619 *                    (1) Wait for the completion of the sends in flight
620 *                    (2) Destroy the associated data structures
621 */
622
623static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind)
624{
625	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
626	osm_log_t *p_log = p_bo->p_vendor->p_log;
627
628	OSM_LOG_ENTER(p_log);
629
630	/* "notifying" all that from now on no new sends can be done */
631	p_bo->txn_mgr.p_event_wheel->closing = TRUE;
632
633	osmv_txn_lock(p_bo);
634
635	/*
636	   the is_closing is set under lock we we know we only need to
637	   check for it after obtaining the lock
638	 */
639	p_bo->is_closing = TRUE;
640
641	/* notifying all sleeping rmpp sends to exit */
642	osmv_txn_abort_rmpp_txns(h_bind);
643
644	/* unlock the bo to allow for any residual mads to be dispatched */
645	osmv_txn_unlock(p_bo);
646	osm_log(p_log, OSM_LOG_DEBUG,
647		"__osm_vendor_internal_unbind: destroying transport mgr.. \n");
648	/* wait for the receiver thread to exit */
649	osmv_transport_done(h_bind);
650
651	/* lock to avoid any collissions while we cleanup the structs */
652	osmv_txn_lock(p_bo);
653	osm_log(p_log, OSM_LOG_DEBUG,
654		"__osm_vendor_internal_unbind: destroying txn mgr.. \n");
655	osmv_txnmgr_done(h_bind);
656	osm_log(p_log, OSM_LOG_DEBUG,
657		"__osm_vendor_internal_unbind: destroying bind lock.. \n");
658	osmv_txn_unlock(p_bo);
659
660	/*
661	   we intentionally let the p_bo and its lock leak -
662	   as we did not implement a way to track active bind handles provided to
663	   the client - and the client might use them
664
665	   cl_spinlock_destroy(&p_bo->lock);
666	   free(p_bo);
667	 */
668
669	OSM_LOG_EXIT(p_log);
670}
671
672/*
673 *  NAME            __osmv_get_send_txn
674 *
675 *  DESCRIPTION     Return a transaction object that corresponds to this MAD.
676 *                  Optionally, create it, if the new request (query) is sent or received.
677 */
678
679static ib_api_status_t
680__osmv_get_send_txn(IN osm_bind_handle_t h_bind,
681		    IN osm_madw_t * const p_madw,
682		    IN boolean_t is_rmpp,
683		    IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn)
684{
685	ib_api_status_t ret;
686	uint64_t tid, key;
687	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
688	ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw);
689
690	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
691	CL_ASSERT(NULL != pp_txn);
692
693	key = tid = cl_ntoh64(p_mad->trans_id);
694	if (TRUE == resp_expected) {
695		/* Create a unique identifier at the requester side */
696		key = osmv_txn_uniq_key(tid);
697	}
698
699	/* We must run under a transaction framework */
700	ret = osmv_txn_lookup(h_bind, key, pp_txn);
701	if (IB_NOT_FOUND == ret) {
702		/* Generally, we start a new transaction */
703		ret = osmv_txn_init(h_bind, tid, key, pp_txn);
704		if (IB_SUCCESS != ret) {
705			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
706				"__osmv_get_send_txn: ERR 7313: "
707				"The transaction id=0x%llX failed to init.\n",
708				tid);
709			goto get_send_txn_done;
710		}
711	} else {
712		CL_ASSERT(NULL != *pp_txn);
713		/* The transaction context exists.
714		 * This is legal only if I am going to return an
715		 * (RMPP?) reply to an RMPP request sent by the other part
716		 * (double-sided RMPP transfer)
717		 */
718		if (FALSE == is_rmpp
719		    || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) {
720			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
721				"__osmv_get_send_txn: ERR 7314: "
722				"The transaction id=0x%llX is not unique. Send failed.\n",
723				tid);
724
725			ret = IB_INVALID_SETTING;
726			goto get_send_txn_done;
727		}
728
729		if (TRUE == resp_expected) {
730			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
731				"__osmv_get_send_txn: ERR 7315: "
732				"The transaction id=%llX can't expect a response. Send failed.\n",
733				tid);
734
735			ret = IB_INVALID_PARAMETER;
736			goto get_send_txn_done;
737		}
738	}
739
740	if (TRUE == is_rmpp) {
741		ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw);
742		if (IB_SUCCESS != ret) {
743			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
744				"__osmv_get_send_txn: ERR 7316: "
745				"The transaction id=%llX failed to init the rmpp mad. Send failed.\n",
746				tid);
747			osmv_txn_done(h_bind, tid, FALSE);
748			goto get_send_txn_done;
749		}
750	}
751
752	/* Save a reference to the MAD in the txn context
753	 * We'll need to match it in two cases:
754	 *  (1) When the response is returned, if I am the requester
755	 *  (2) In RMPP retransmissions
756	 */
757	osmv_txn_set_madw(*pp_txn, p_madw);
758
759get_send_txn_done:
760	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
761
762	return ret;
763}
764
765/**********************************************************************
766 **********************************************************************/
767void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
768{
769
770}
771