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