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 <sys/ioctl.h>
41219820Sjeff#include <stdlib.h>
42219820Sjeff#include <stddef.h>
43219820Sjeff#include <sys/types.h>
44219820Sjeff#include <sys/stat.h>
45219820Sjeff#include <fcntl.h>
46219820Sjeff#include <errno.h>
47219820Sjeff
48219820Sjeff#include <vendor/osm_vendor_mlx.h>
49219820Sjeff#include <vendor/osm_vendor_mlx_transport.h>
50219820Sjeff#include <vendor/osm_vendor_mlx_transport_anafa.h>
51219820Sjeff#include <vendor/osm_vendor_mlx_svc.h>
52219820Sjeff#include <vendor/osm_vendor_mlx_sender.h>
53219820Sjeff#include <vendor/osm_pkt_randomizer.h>
54219820Sjeff#include <vendor/osm_ts_useraccess.h>
55219820Sjeff
56219820Sjeff/**
57219820Sjeff *      FORWARD REFERENCES
58219820Sjeff */
59219820Sjeffstatic ib_api_status_t
60219820Sjeff__osmv_get_send_txn(IN osm_bind_handle_t h_bind,
61219820Sjeff		    IN osm_madw_t * const p_madw,
62219820Sjeff		    IN boolean_t is_rmpp,
63219820Sjeff		    IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn);
64219820Sjeff
65219820Sjeffstatic void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind);
66219820Sjeff
67219820Sjeff/*
68219820Sjeff *  NAME            osm_vendor_new
69219820Sjeff *
70219820Sjeff *  DESCRIPTION     Create and Initialize the osm_vendor_t Object
71219820Sjeff */
72219820Sjeff
73219820Sjeffosm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
74219820Sjeff			     IN const uint32_t timeout)
75219820Sjeff{
76219820Sjeff	ib_api_status_t status;
77219820Sjeff	osm_vendor_t *p_vend;
78219820Sjeff
79219820Sjeff	OSM_LOG_ENTER(p_log);
80219820Sjeff
81219820Sjeff	CL_ASSERT(p_log);
82219820Sjeff
83219820Sjeff	p_vend = malloc(sizeof(*p_vend));
84219820Sjeff	if (p_vend != NULL) {
85219820Sjeff		memset(p_vend, 0, sizeof(*p_vend));
86219820Sjeff		status = osm_vendor_init(p_vend, p_log, timeout);
87219820Sjeff		if (status != IB_SUCCESS) {
88219820Sjeff			osm_vendor_delete(&p_vend);
89219820Sjeff		}
90219820Sjeff	} else {
91219820Sjeff		osm_log(p_vend->p_log, OSM_LOG_ERROR,
92219820Sjeff			"osm_vendor_new: ERR 7401: "
93219820Sjeff			"Fail to allocate vendor object.\n");
94219820Sjeff	}
95219820Sjeff
96219820Sjeff	OSM_LOG_EXIT(p_log);
97219820Sjeff	return (p_vend);
98219820Sjeff}
99219820Sjeff
100219820Sjeff/*
101219820Sjeff *  NAME            osm_vendor_delete
102219820Sjeff *
103219820Sjeff *  DESCRIPTION     Delete all the binds behind the vendor + free the vendor object
104219820Sjeff */
105219820Sjeff
106219820Sjeffvoid osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
107219820Sjeff{
108219820Sjeff	cl_list_item_t *p_item;
109219820Sjeff	cl_list_obj_t *p_obj;
110219820Sjeff	osm_bind_handle_t bind_h;
111219820Sjeff	osm_log_t *p_log;
112219820Sjeff
113219820Sjeff	OSM_LOG_ENTER((*pp_vend)->p_log);
114219820Sjeff	p_log = (*pp_vend)->p_log;
115219820Sjeff
116219820Sjeff	/* go over the bind handles , unbind them and remove from list */
117219820Sjeff	/* Note that if we reached here due to problem in the init, then
118219820Sjeff	   the bind_handles list is not initialized yet */
119219820Sjeff	if ((*pp_vend)->bind_handles.state == CL_INITIALIZED) {
120219820Sjeff		p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles));
121219820Sjeff		while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) {
122219820Sjeff
123219820Sjeff			p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
124219820Sjeff			bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj);
125219820Sjeff			osm_log(p_log, OSM_LOG_DEBUG,
126219820Sjeff				"osm_vendor_delete: unbinding bind_h:%p \n",
127219820Sjeff				bind_h);
128219820Sjeff
129219820Sjeff			__osm_vendor_internal_unbind(bind_h);
130219820Sjeff
131219820Sjeff			free(p_obj);
132219820Sjeff			/* removing from list */
133219820Sjeff			p_item =
134219820Sjeff			    cl_qlist_remove_head(&((*pp_vend)->bind_handles));
135219820Sjeff		}
136219820Sjeff	}
137219820Sjeff
138219820Sjeff	if (NULL != ((*pp_vend)->p_transport_info)) {
139219820Sjeff		free((*pp_vend)->p_transport_info);
140219820Sjeff		(*pp_vend)->p_transport_info = NULL;
141219820Sjeff	}
142219820Sjeff
143219820Sjeff	/* remove the packet randomizer object */
144219820Sjeff	if ((*pp_vend)->run_randomizer == TRUE)
145219820Sjeff		osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer),
146219820Sjeff					   p_log);
147219820Sjeff
148219820Sjeff	free(*pp_vend);
149219820Sjeff	*pp_vend = NULL;
150219820Sjeff
151219820Sjeff	OSM_LOG_EXIT(p_log);
152219820Sjeff}
153219820Sjeff
154219820Sjeff/*
155219820Sjeff *  NAME            osm_vendor_init
156219820Sjeff *
157219820Sjeff *  DESCRIPTION     Initialize the vendor object
158219820Sjeff */
159219820Sjeff
160219820Sjeffib_api_status_t
161219820Sjeffosm_vendor_init(IN osm_vendor_t * const p_vend,
162219820Sjeff		IN osm_log_t * const p_log, IN const uint32_t timeout)
163219820Sjeff{
164219820Sjeff	ib_api_status_t status = IB_SUCCESS;
165219820Sjeff	char device_file[16];
166219820Sjeff	int device_fd;
167219820Sjeff
168219820Sjeff	OSM_LOG_ENTER(p_log);
169219820Sjeff
170219820Sjeff	p_vend->p_log = p_log;
171219820Sjeff	p_vend->resp_timeout = timeout;
172219820Sjeff	p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR;
173219820Sjeff
174219820Sjeff	p_vend->p_transport_info = (osmv_TOPSPIN_ANAFA_transport_info_t *)
175219820Sjeff	    malloc(sizeof(osmv_TOPSPIN_ANAFA_transport_info_t));
176219820Sjeff	if (!p_vend->p_transport_info) {
177219820Sjeff		return IB_ERROR;
178219820Sjeff	}
179219820Sjeff
180219820Sjeff	memset(p_vend->p_transport_info, 0,
181219820Sjeff	       sizeof(osmv_TOPSPIN_ANAFA_transport_info_t));
182219820Sjeff
183219820Sjeff	/* update the run_randomizer flag */
184219820Sjeff	if (getenv("OSM_PKT_DROP_RATE") != NULL
185219820Sjeff	    && atol(getenv("OSM_PKT_DROP_RATE")) != 0) {
186219820Sjeff		/* if the OSM_PKT_DROP_RATE global variable is defined
187219820Sjeff		   to a non-zero value -
188219820Sjeff		   then the randomizer should be called.
189219820Sjeff		   Need to create the packet randomizer object */
190219820Sjeff		p_vend->run_randomizer = TRUE;
191219820Sjeff		status =
192219820Sjeff		    osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log);
193219820Sjeff		if (status != IB_SUCCESS)
194219820Sjeff			return status;
195219820Sjeff	} else {
196219820Sjeff		p_vend->run_randomizer = FALSE;
197219820Sjeff		p_vend->p_pkt_randomizer = NULL;
198219820Sjeff	}
199219820Sjeff
200219820Sjeff	/* open TopSpin file device */
201219820Sjeff	sprintf(device_file, "/dev/ts_ua0");
202219820Sjeff	device_fd = open("/dev/ts_ua0", O_RDWR);
203219820Sjeff	if (device_fd < 0) {
204219820Sjeff		fprintf(stderr, "Fatal: Fail to open the file:%s(%d)\n",
205219820Sjeff			device_file, errno);
206219820Sjeff		return IB_ERROR;
207219820Sjeff	}
208219820Sjeff
209219820Sjeff	((osmv_TOPSPIN_ANAFA_transport_info_t *) p_vend->p_transport_info)->
210219820Sjeff	    device_fd = device_fd;
211219820Sjeff
212219820Sjeff	cl_qlist_init(&p_vend->bind_handles);
213219820Sjeff
214219820Sjeff	OSM_LOG_EXIT(p_log);
215219820Sjeff	return (IB_SUCCESS);
216219820Sjeff}
217219820Sjeff
218219820Sjeff/*
219219820Sjeff *  NAME            osm_vendor_bind
220219820Sjeff *
221219820Sjeff *  DESCRIPTION     Create a new bind object under the vendor object
222219820Sjeff */
223219820Sjeff
224219820Sjeffosm_bind_handle_t
225219820Sjeffosm_vendor_bind(IN osm_vendor_t * const p_vend,
226219820Sjeff		IN osm_bind_info_t * const p_bind_info,
227219820Sjeff		IN osm_mad_pool_t * const p_mad_pool,
228219820Sjeff		IN osm_vend_mad_recv_callback_t mad_recv_callback,
229219820Sjeff		IN osm_vend_mad_send_err_callback_t send_err_callback,
230219820Sjeff		IN void *context)
231219820Sjeff{
232219820Sjeff	osmv_bind_obj_t *p_bo;
233219820Sjeff	cl_status_t cl_st;
234219820Sjeff	cl_list_obj_t *p_obj;
235219820Sjeff	uint8_t hca_idx = 0;
236219820Sjeff
237219820Sjeff	if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool
238219820Sjeff	    || NULL == mad_recv_callback || NULL == send_err_callback) {
239219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
240219820Sjeff			"osm_vendor_bind: ERR 7402: "
241219820Sjeff			"NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n",
242219820Sjeff			p_vend, p_bind_info, p_mad_pool, mad_recv_callback,
243219820Sjeff			send_err_callback);
244219820Sjeff
245219820Sjeff		return OSM_BIND_INVALID_HANDLE;
246219820Sjeff	}
247219820Sjeff
248219820Sjeff	p_bo = malloc(sizeof(osmv_bind_obj_t));
249219820Sjeff	if (NULL == p_bo) {
250219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
251219820Sjeff			"osm_vendor_bind: ERR 7403: "
252219820Sjeff			"could not allocate the bind object\n");
253219820Sjeff		return OSM_BIND_INVALID_HANDLE;
254219820Sjeff	}
255219820Sjeff
256219820Sjeff	memset(p_bo, 0, sizeof(osmv_bind_obj_t));
257219820Sjeff	p_bo->p_vendor = p_vend;
258219820Sjeff	p_bo->recv_cb = mad_recv_callback;
259219820Sjeff	p_bo->send_err_cb = send_err_callback;
260219820Sjeff	p_bo->cb_context = context;
261219820Sjeff	p_bo->p_osm_pool = p_mad_pool;
262219820Sjeff	p_bo->port_num = 1;	/* anafa2 has one port */
263219820Sjeff	p_bo->hca_hndl = 0;	/* only one ca on anafa system */
264219820Sjeff
265219820Sjeff	/* obtain the hca name and port num from the guid */
266219820Sjeff	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
267219820Sjeff		"osm_vendor_bind: "
268219820Sjeff		"Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
269219820Sjeff		cl_ntoh64(p_bind_info->port_guid));
270219820Sjeff
271219820Sjeff	p_bo->is_closing = FALSE;
272219820Sjeff	cl_spinlock_construct(&(p_bo->lock));
273219820Sjeff	cl_st = cl_spinlock_init(&(p_bo->lock));
274219820Sjeff	if (cl_st != CL_SUCCESS) {
275219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
276219820Sjeff			"osm_vendor_bind: ERR 7405: "
277219820Sjeff			"could not initialize the spinlock ...\n");
278219820Sjeff		free(p_bo);
279219820Sjeff		return OSM_BIND_INVALID_HANDLE;
280219820Sjeff	}
281219820Sjeff
282219820Sjeff	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
283219820Sjeff		"osm_vendor_bind: osmv_txnmgr_init ... \n");
284219820Sjeff	if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) !=
285219820Sjeff	    IB_SUCCESS) {
286219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
287219820Sjeff			"osm_vendor_bind: ERR 7406: "
288219820Sjeff			"osmv_txnmgr_init failed \n");
289219820Sjeff		cl_spinlock_destroy(&p_bo->lock);
290219820Sjeff		free(p_bo);
291219820Sjeff		return OSM_BIND_INVALID_HANDLE;
292219820Sjeff	}
293219820Sjeff
294219820Sjeff	/* Do the real job! (Transport-dependent) */
295219820Sjeff	if (IB_SUCCESS !=
296219820Sjeff	    osmv_transport_init(p_bind_info, OSMV_ANAFA_ID, hca_idx, p_bo)) {
297219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
298219820Sjeff			"osm_vendor_bind: ERR 7407: "
299219820Sjeff			"osmv_transport_init failed \n");
300219820Sjeff		osmv_txnmgr_done((osm_bind_handle_t) p_bo);
301219820Sjeff		cl_spinlock_destroy(&p_bo->lock);
302219820Sjeff		free(p_bo);
303219820Sjeff		return OSM_BIND_INVALID_HANDLE;
304219820Sjeff	}
305219820Sjeff
306219820Sjeff	/* insert bind handle into db */
307219820Sjeff	p_obj = malloc(sizeof(cl_list_obj_t));
308219820Sjeff	if (NULL == p_obj) {
309219820Sjeff
310219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
311219820Sjeff			"osm_vendor_bind: ERR 7408: "
312219820Sjeff			"osm_vendor_bind: could not allocate the list object\n");
313219820Sjeff
314219820Sjeff		osmv_transport_done(p_bo->p_transp_mgr);
315219820Sjeff		osmv_txnmgr_done((osm_bind_handle_t) p_bo);
316219820Sjeff		cl_spinlock_destroy(&p_bo->lock);
317219820Sjeff		free(p_bo);
318219820Sjeff		return OSM_BIND_INVALID_HANDLE;
319219820Sjeff	}
320219820Sjeff	if (p_obj)
321219820Sjeff		memset(p_obj, 0, sizeof(cl_list_obj_t));
322219820Sjeff	cl_qlist_set_obj(p_obj, p_bo);
323219820Sjeff
324219820Sjeff	cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item);
325219820Sjeff
326219820Sjeff	return (osm_bind_handle_t) p_bo;
327219820Sjeff}
328219820Sjeff
329219820Sjeff/*
330219820Sjeff *  NAME            osm_vendor_unbind
331219820Sjeff *
332219820Sjeff *  DESCRIPTION     Destroy the bind object and remove it from the vendor's list
333219820Sjeff */
334219820Sjeff
335219820Sjeffvoid osm_vendor_unbind(IN osm_bind_handle_t h_bind)
336219820Sjeff{
337219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
338219820Sjeff	osm_log_t *p_log = p_bo->p_vendor->p_log;
339219820Sjeff	cl_list_obj_t *p_obj;
340219820Sjeff	cl_list_item_t *p_item, *p_item_tmp;
341219820Sjeff	cl_qlist_t *const p_bh_list =
342219820Sjeff	    (cl_qlist_t * const)&p_bo->p_vendor->bind_handles;
343219820Sjeff
344219820Sjeff	OSM_LOG_ENTER(p_log);
345219820Sjeff
346219820Sjeff	/* go over all the items in the list and remove the specific item */
347219820Sjeff	p_item = cl_qlist_head(&p_bo->p_vendor->bind_handles);
348219820Sjeff	while (p_item != cl_qlist_end(&p_bo->p_vendor->bind_handles)) {
349219820Sjeff		p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
350219820Sjeff		if (cl_qlist_obj(p_obj) == h_bind) {
351219820Sjeff			break;
352219820Sjeff		}
353219820Sjeff		p_item_tmp = cl_qlist_next(p_item);
354219820Sjeff		p_item = p_item_tmp;
355219820Sjeff	}
356219820Sjeff
357219820Sjeff	CL_ASSERT(p_item != cl_qlist_end(p_bh_list));
358219820Sjeff
359219820Sjeff	cl_qlist_remove_item(p_bh_list, p_item);
360219820Sjeff	free(p_obj);
361219820Sjeff
362219820Sjeff	__osm_vendor_internal_unbind(h_bind);
363219820Sjeff
364219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
365219820Sjeff}
366219820Sjeff
367219820Sjeff/*
368219820Sjeff *  NAME            osm_vendor_get
369219820Sjeff *
370219820Sjeff *  DESCRIPTION     Allocate the space for a new MAD
371219820Sjeff */
372219820Sjeff
373219820Sjeffib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
374219820Sjeff			 IN const uint32_t mad_size,
375219820Sjeff			 IN osm_vend_wrap_t * const p_vw)
376219820Sjeff{
377219820Sjeff	ib_mad_t *p_mad;
378219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
379219820Sjeff	osm_vendor_t const *p_vend = p_bo->p_vendor;
380219820Sjeff	uint32_t act_mad_size;
381219820Sjeff
382219820Sjeff	OSM_LOG_ENTER(p_vend->p_log);
383219820Sjeff
384219820Sjeff	CL_ASSERT(p_vw);
385219820Sjeff
386219820Sjeff	if (mad_size < MAD_BLOCK_SIZE) {
387219820Sjeff		/* Stupid, but the applications want that! */
388219820Sjeff		act_mad_size = MAD_BLOCK_SIZE;
389219820Sjeff	} else {
390219820Sjeff		act_mad_size = mad_size;
391219820Sjeff	}
392219820Sjeff
393219820Sjeff	/* allocate it */
394219820Sjeff	p_mad = (ib_mad_t *) malloc(act_mad_size);
395219820Sjeff	if (p_mad == NULL) {
396219820Sjeff		osm_log(p_vend->p_log, OSM_LOG_ERROR,
397219820Sjeff			"osm_vendor_get: ERR 7409: "
398219820Sjeff			"Error Obtaining MAD buffer.\n");
399219820Sjeff		goto Exit;
400219820Sjeff	}
401219820Sjeff
402219820Sjeff	memset(p_mad, 0, act_mad_size);
403219820Sjeff
404219820Sjeff	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
405219820Sjeff		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
406219820Sjeff			"osm_vendor_get: "
407219820Sjeff			"Allocated MAD %p, size = %u.\n", p_mad, act_mad_size);
408219820Sjeff	}
409219820Sjeff	p_vw->p_mad = p_mad;
410219820Sjeff
411219820SjeffExit:
412219820Sjeff	OSM_LOG_EXIT(p_vend->p_log);
413219820Sjeff	return (p_mad);
414219820Sjeff}
415219820Sjeff
416219820Sjeff/*
417219820Sjeff *  NAME            osm_vendor_send
418219820Sjeff *
419219820Sjeff *  DESCRIPTION     Send a MAD buffer (RMPP or simple send).
420219820Sjeff *
421219820Sjeff *                  Semantics:
422219820Sjeff *                   (1) The RMPP send completes when every segment
423219820Sjeff *                       is acknowledged (synchronous)
424219820Sjeff *                   (2) The simple send completes when the send completion
425219820Sjeff *                       is received (asynchronous)
426219820Sjeff */
427219820Sjeff
428219820Sjeffib_api_status_t
429219820Sjeffosm_vendor_send(IN osm_bind_handle_t h_bind,
430219820Sjeff		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
431219820Sjeff{
432219820Sjeff	ib_api_status_t ret = IB_SUCCESS;
433219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
434219820Sjeff	boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE;
435219820Sjeff	osmv_txn_ctx_t *p_txn = NULL;
436219820Sjeff	ib_mad_t *p_mad;
437219820Sjeff
438219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
439219820Sjeff
440219820Sjeff	if (NULL == h_bind || NULL == p_madw ||
441219820Sjeff	    NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) ||
442219820Sjeff	    NULL == osm_madw_get_mad_addr_ptr(p_madw)) {
443219820Sjeff
444219820Sjeff		return IB_INVALID_PARAMETER;
445219820Sjeff	}
446219820Sjeff
447219820Sjeff	is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE
448219820Sjeff		   || osmv_mad_is_rmpp(p_mad));
449219820Sjeff	is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected);
450219820Sjeff
451219820Sjeff	/* Make our operations with the send context atomic */
452219820Sjeff	osmv_txn_lock(p_bo);
453219820Sjeff
454219820Sjeff	if (TRUE == p_bo->is_closing) {
455219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
456219820Sjeff			"osm_vendor_send: ERR 7410: "
457219820Sjeff			"The handle %p is being unbound, cannot send.\n",
458219820Sjeff			h_bind);
459219820Sjeff		ret = IB_INTERRUPTED;
460219820Sjeff		goto send_done;
461219820Sjeff	}
462219820Sjeff
463219820Sjeff	if (TRUE == resp_expected || TRUE == is_rmpp) {
464219820Sjeff
465219820Sjeff		/* We must run under a transaction framework.
466219820Sjeff		 * Get the transaction object (old or new) */
467219820Sjeff		ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp,
468219820Sjeff					  resp_expected, &p_txn);
469219820Sjeff		if (IB_SUCCESS != ret) {
470219820Sjeff			goto send_done;
471219820Sjeff		}
472219820Sjeff	}
473219820Sjeff
474219820Sjeff	if (TRUE == is_rmpp) {
475219820Sjeff		/* Do the job - RMPP!
476219820Sjeff		 * The call returns as all the packets are ACK'ed/upon error
477219820Sjeff		 * The txn lock will be released each time the function sleeps
478219820Sjeff		 * and re-acquired when it wakes up
479219820Sjeff		 */
480219820Sjeff		ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds);
481219820Sjeff	} else {
482219820Sjeff
483219820Sjeff		/* Do the job - single MAD!
484219820Sjeff		 * The call returns as soon as the MAD is put on the wire
485219820Sjeff		 */
486219820Sjeff		ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE);	/* anafa2 */
487219820Sjeff	}
488219820Sjeff
489219820Sjeff	if (IB_SUCCESS == ret) {
490219820Sjeff
491219820Sjeff		if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) {
492219820Sjeff			/* For double-sided sends, the txn continues to live */
493219820Sjeff			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
494219820Sjeff				      FALSE /*not in callback */ );
495219820Sjeff		}
496219820Sjeff
497219820Sjeff		if (FALSE == resp_expected) {
498219820Sjeff			osm_mad_pool_put(p_bo->p_osm_pool, p_madw);
499219820Sjeff		}
500219820Sjeff	} else {
501219820Sjeff		if (NULL != p_txn) {
502219820Sjeff			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
503219820Sjeff				      FALSE /*not in callback */ );
504219820Sjeff		}
505219820Sjeff
506219820Sjeff		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
507219820Sjeff			"osm_vendor_send: ERR 7411: failed to send MADW %p\n",
508219820Sjeff			p_madw);
509219820Sjeff
510219820Sjeff		if (TRUE == resp_expected) {
511219820Sjeff			/* Change the status on the p_madw */
512219820Sjeff			p_madw->status = ret;
513219820Sjeff			/* Only the requester expects the error callback */
514219820Sjeff			p_bo->send_err_cb(p_bo->cb_context, p_madw);
515219820Sjeff		} else {
516219820Sjeff			/* put back the mad - it is useless ... */
517219820Sjeff			osm_mad_pool_put(p_bo->p_osm_pool, p_madw);
518219820Sjeff		}
519219820Sjeff	}
520219820Sjeff
521219820Sjeffsend_done:
522219820Sjeff
523219820Sjeff	osmv_txn_unlock(p_bo);
524219820Sjeff
525219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
526219820Sjeff	return ret;
527219820Sjeff}
528219820Sjeff
529219820Sjeff/*
530219820Sjeff *  NAME            osm_vendor_put
531219820Sjeff *
532219820Sjeff *  DESCRIPTION     Free the MAD's memory
533219820Sjeff */
534219820Sjeff
535219820Sjeffvoid
536219820Sjeffosm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
537219820Sjeff{
538219820Sjeff
539219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
540219820Sjeff	osm_vendor_t const *p_vend = p_bo->p_vendor;
541219820Sjeff
542219820Sjeff	OSM_LOG_ENTER(p_vend->p_log);
543219820Sjeff
544219820Sjeff	CL_ASSERT(p_vw);
545219820Sjeff	CL_ASSERT(p_vw->p_mad);
546219820Sjeff
547219820Sjeff	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
548219820Sjeff		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
549219820Sjeff			"osm_vendor_put: " "Retiring MAD %p.\n", p_vw->p_mad);
550219820Sjeff	}
551219820Sjeff
552219820Sjeff	free(p_vw->p_mad);
553219820Sjeff	p_vw->p_mad = NULL;
554219820Sjeff
555219820Sjeff	OSM_LOG_EXIT(p_vend->p_log);
556219820Sjeff}
557219820Sjeff
558219820Sjeff/*
559219820Sjeff *  NAME            osm_vendor_local_lid_change
560219820Sjeff *
561219820Sjeff *  DESCRIPTION     Notifies the vendor transport layer that the local address
562219820Sjeff *                  has changed.  This allows the vendor layer to perform
563219820Sjeff *                  housekeeping functions such as address vector updates.
564219820Sjeff */
565219820Sjeff
566219820Sjeffib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
567219820Sjeff{
568219820Sjeff	osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor;
569219820Sjeff	OSM_LOG_ENTER(p_vend->p_log);
570219820Sjeff
571219820Sjeff	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
572219820Sjeff		"osm_vendor_local_lid_change: " "Change of LID.\n");
573219820Sjeff
574219820Sjeff	OSM_LOG_EXIT(p_vend->p_log);
575219820Sjeff
576219820Sjeff	return (IB_SUCCESS);
577219820Sjeff
578219820Sjeff}
579219820Sjeff
580219820Sjeff/*
581219820Sjeff *  NAME            osm_vendor_set_sm
582219820Sjeff *
583219820Sjeff *  DESCRIPTION     Modifies the port info for the bound port to set the "IS_SM" bit.
584219820Sjeff */
585219820Sjeff
586219820Sjeffvoid osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
587219820Sjeff{
588219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
589219820Sjeff	osm_vendor_t const *p_vend = p_bo->p_vendor;
590219820Sjeff	osmv_TOPSPIN_ANAFA_transport_mgr_t *p_mgr;
591219820Sjeff	int ioctl_ret;
592219820Sjeff	osm_ts_set_port_info_ioctl port_info;
593219820Sjeff
594219820Sjeff	OSM_LOG_ENTER(p_vend->p_log);
595219820Sjeff
596219820Sjeff	port_info.port = 0;	/* anafa has only 1 port */
597219820Sjeff	port_info.port_info.valid_fields = IB_PORT_IS_SM;
598219820Sjeff	port_info.port_info.is_sm = is_sm_val;
599219820Sjeff
600219820Sjeff	p_mgr = (osmv_TOPSPIN_ANAFA_transport_mgr_t *) p_bo->p_transp_mgr;
601219820Sjeff	ioctl_ret = ioctl(p_mgr->device_fd, TS_IB_IOCSPORTINFO, &port_info);
602219820Sjeff
603219820Sjeff	if (ioctl_ret < 0) {
604219820Sjeff		osm_log(p_vend->p_log, OSM_LOG_ERROR,
605219820Sjeff			"osm_vendor_set_sm: ERR 7412: "
606219820Sjeff			"Unable set 'IS_SM' bit to:%u in port attributes (%d). errno=%d\n",
607219820Sjeff			is_sm_val, ioctl_ret, errno);
608219820Sjeff	}
609219820Sjeff
610219820Sjeff	OSM_LOG_EXIT(p_vend->p_log);
611219820Sjeff}
612219820Sjeff
613219820Sjeff/*
614219820Sjeff *  NAME            __osm_vendor_internal_unbind
615219820Sjeff *
616219820Sjeff *  DESCRIPTION     Destroying a bind:
617219820Sjeff *                    (1) Wait for the completion of the sends in flight
618219820Sjeff *                    (2) Destroy the associated data structures
619219820Sjeff */
620219820Sjeff
621219820Sjeffstatic void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind)
622219820Sjeff{
623219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
624219820Sjeff	osm_log_t *p_log = p_bo->p_vendor->p_log;
625219820Sjeff
626219820Sjeff	OSM_LOG_ENTER(p_log);
627219820Sjeff
628219820Sjeff	/* "notifying" all that from now on no new sends can be done */
629219820Sjeff	p_bo->txn_mgr.p_event_wheel->closing = TRUE;
630219820Sjeff
631219820Sjeff	osmv_txn_lock(p_bo);
632219820Sjeff	p_bo->is_closing = TRUE;
633219820Sjeff
634219820Sjeff	/* notifying all sleeping rmpp sends to exit */
635219820Sjeff	osmv_txn_abort_rmpp_txns(h_bind);
636219820Sjeff
637219820Sjeff	/*  frees all data in bind handle   */
638219820Sjeff	osm_log(p_log, OSM_LOG_DEBUG,
639219820Sjeff		"__osm_vendor_internal_unbind: destroying transport mgr.. \n");
640219820Sjeff	osmv_txn_unlock(p_bo);
641219820Sjeff
642219820Sjeff	osmv_transport_done(h_bind);
643219820Sjeff	osm_log(p_log, OSM_LOG_DEBUG,
644219820Sjeff		"__osm_vendor_internal_unbind: destroying txn mgr.. \n");
645219820Sjeff	osmv_txn_lock(p_bo);
646219820Sjeff	osmv_txnmgr_done(h_bind);
647219820Sjeff	osm_log(p_log, OSM_LOG_DEBUG,
648219820Sjeff		"__osm_vendor_internal_unbind: destroying bind lock.. \n");
649219820Sjeff
650219820Sjeff	osmv_txn_unlock(p_bo);
651219820Sjeff	/*
652219820Sjeff	   we intentionally let the p_bo and its lock leak -
653219820Sjeff	   as we did not implement a way to track active bind handles provided to
654219820Sjeff	   the client - and the client might use them
655219820Sjeff
656219820Sjeff	   cl_spinlock_destroy(&p_bo->lock);
657219820Sjeff	   free(p_bo);
658219820Sjeff	 */
659219820Sjeff
660219820Sjeff	OSM_LOG_EXIT(p_log);
661219820Sjeff}
662219820Sjeff
663219820Sjeff/*
664219820Sjeff *  NAME            __osmv_get_send_txn
665219820Sjeff *
666219820Sjeff *  DESCRIPTION     Return a transaction object that corresponds to this MAD.
667219820Sjeff *                  Optionally, create it, if the new request (query) is sent or received.
668219820Sjeff */
669219820Sjeff
670219820Sjeffstatic ib_api_status_t
671219820Sjeff__osmv_get_send_txn(IN osm_bind_handle_t h_bind,
672219820Sjeff		    IN osm_madw_t * const p_madw,
673219820Sjeff		    IN boolean_t is_rmpp,
674219820Sjeff		    IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn)
675219820Sjeff{
676219820Sjeff	ib_api_status_t ret;
677219820Sjeff	uint64_t tid, key;
678219820Sjeff	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
679219820Sjeff	ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw);
680219820Sjeff
681219820Sjeff	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
682219820Sjeff	CL_ASSERT(NULL != pp_txn);
683219820Sjeff
684219820Sjeff	key = tid = cl_ntoh64(p_mad->trans_id);
685219820Sjeff	if (TRUE == resp_expected) {
686219820Sjeff		/* Create a unique identifier at the requester side */
687219820Sjeff		key = osmv_txn_uniq_key(tid);
688219820Sjeff	}
689219820Sjeff
690219820Sjeff	/* We must run under a transaction framework */
691219820Sjeff	ret = osmv_txn_lookup(h_bind, key, pp_txn);
692219820Sjeff	if (IB_NOT_FOUND == ret) {
693219820Sjeff		/* Generally, we start a new transaction */
694219820Sjeff		ret = osmv_txn_init(h_bind, tid, key, pp_txn);
695219820Sjeff		if (IB_SUCCESS != ret) {
696219820Sjeff			goto get_send_txn_done;
697219820Sjeff		}
698219820Sjeff	} else {
699219820Sjeff		CL_ASSERT(NULL != *pp_txn);
700219820Sjeff		/* The transaction context exists.
701219820Sjeff		 * This is legal only if I am going to return an
702219820Sjeff		 * (RMPP?) reply to an RMPP request sent by the other part
703219820Sjeff		 * (double-sided RMPP transfer)
704219820Sjeff		 */
705219820Sjeff		if (FALSE == is_rmpp
706219820Sjeff		    || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) {
707219820Sjeff			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
708219820Sjeff				"__osmv_get_send_txn: ERR 7413: "
709219820Sjeff				"The transaction id=0x%llX is not unique. Send failed.\n",
710219820Sjeff				tid);
711219820Sjeff
712219820Sjeff			ret = IB_INVALID_SETTING;
713219820Sjeff			goto get_send_txn_done;
714219820Sjeff		}
715219820Sjeff
716219820Sjeff		if (TRUE == resp_expected) {
717219820Sjeff			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
718219820Sjeff				"__osmv_get_send_txn: ERR 7414: "
719219820Sjeff				"The transaction id=%llX can\'t expect a response. Send failed.\n",
720219820Sjeff				tid);
721219820Sjeff
722219820Sjeff			ret = IB_INVALID_PARAMETER;
723219820Sjeff			goto get_send_txn_done;
724219820Sjeff		}
725219820Sjeff	}
726219820Sjeff
727219820Sjeff	if (TRUE == is_rmpp) {
728219820Sjeff		ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw);
729219820Sjeff		if (IB_SUCCESS != ret) {
730219820Sjeff			osmv_txn_done(h_bind, tid, FALSE);
731219820Sjeff			goto get_send_txn_done;
732219820Sjeff		}
733219820Sjeff	}
734219820Sjeff
735219820Sjeff	/* Save a reference to the MAD in the txn context
736219820Sjeff	 * We'll need to match it in two cases:
737219820Sjeff	 *  (1) When the response is returned, if I am the requester
738219820Sjeff	 *  (2) In RMPP retransmissions
739219820Sjeff	 */
740219820Sjeff	osmv_txn_set_madw(*pp_txn, p_madw);
741219820Sjeff
742219820Sjeffget_send_txn_done:
743219820Sjeff	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
744219820Sjeff
745219820Sjeff	return ret;
746219820Sjeff}
747219820Sjeff
748219820Sjeff/**********************************************************************
749219820Sjeff **********************************************************************/
750219820Sjeffvoid osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
751219820Sjeff{
752219820Sjeff
753219820Sjeff}
754