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  */
59 static 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 
65 static 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 
73 osm_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 
106 void 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 
160 ib_api_status_t
161 osm_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 
224 osm_bind_handle_t
225 osm_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 
335 void 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 
373 ib_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 
411 Exit:
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 
428 ib_api_status_t
429 osm_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 
521 send_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 
535 void
536 osm_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 
566 ib_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 
586 void 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 
621 static 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 
670 static 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 
742 get_send_txn_done:
743 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
744 
745 	return ret;
746 }
747 
748 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
749 {
750 
751 }
752