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 <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  */
52 static 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 
58 static 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 
66 osm_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 
100 void 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 
148 ib_api_status_t
149 osm_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 
189 osm_bind_handle_t
190 osm_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 
318 void 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 
359 ib_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 
397 Exit:
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 
414 ib_api_status_t
415 osm_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 	}
515 send_done:
516 
517 	osmv_txn_unlock(p_bo);
518 aborted:
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 
529 void
530 osm_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 
563 ib_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))
584 void 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 
623 static 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 
679 static 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%" PRIx64 " 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%" PRIx64 " 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=0x%" PRIx64 " 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=0x%" PRIx64 " 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 
759 get_send_txn_done:
760 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
761 
762 	return ret;
763 }
764 
765 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
766 {
767 
768 }
769