xref: /freebsd/contrib/ofed/opensm/libvendor/osm_vendor_ts.c (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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 #undef __init
37 #if HAVE_CONFIG_H
38 #  include <config.h>
39 #endif				/* HAVE_CONFIG_H */
40 
41 #include <stdlib.h>
42 #include <string.h>
43 #include <vendor/osm_vendor_ts.h>
44 #include <vendor/osm_vendor_api.h>
45 #include <vendor/osm_ts_useraccess.h>
46 #include <opensm/osm_subnet.h>
47 #include <opensm/osm_opensm.h>
48 
49 /*
50   Since a race can accure on requests. Meaning - a response is received before
51   the send_callback is called - we will save both the madw_p and the fact
52   whether or not it is a response. A race can occure only on requests that did
53   not fail, and then the madw_p will be put back in the pool before the
54   callback.
55 */
56 uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw)
57 {
58 	uint64_t wrid = 0;
59 
60 	CL_ASSERT(p_madw->p_mad);
61 
62 	memcpy(&wrid, &p_madw, sizeof(osm_madw_t *));
63 	wrid = (wrid << 1) |
64 	    ib_mad_is_response(p_madw->p_mad);
65 	return wrid;
66 }
67 
68 void
69 __osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid,
70 				  OUT uint8_t * is_resp,
71 				  OUT osm_madw_t ** pp_madw)
72 {
73 	*is_resp = wrid & 0x0000000000000001;
74 	wrid = wrid >> 1;
75 	memcpy(pp_madw, &wrid, sizeof(osm_madw_t *));
76 }
77 
78 /**********************************************************************
79  * TS MAD to OSM ADDRESS VECTOR
80  **********************************************************************/
81 void
82 __osm_ts_conv_mad_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend,
83 				       IN struct ib_mad *p_mad,
84 				       IN uint8_t is_smi,
85 				       OUT osm_mad_addr_t * p_mad_addr)
86 {
87 	p_mad_addr->dest_lid = cl_hton16(p_mad->slid);
88 	p_mad_addr->static_rate = 0;	/*  HACK - we do not know the rate ! */
89 	p_mad_addr->path_bits = 0;	/*  HACK - no way to know in TS */
90 	if (is_smi) {
91 		/* SMI */
92 		p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid);
93 		p_mad_addr->addr_type.smi.port_num = p_mad->port;
94 	} else {
95 		/* GSI */
96 		p_mad_addr->addr_type.gsi.remote_qp = p_mad->sqpn;
97 		p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
98 		p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index;
99 		p_mad_addr->addr_type.gsi.service_level = 0;	/*  HACK no way to know */
100 
101 		p_mad_addr->addr_type.gsi.global_route = FALSE;	/*  HACK no way to know */
102 		/* copy the GRH data if relevant */
103 		/*
104 		   if (p_mad_addr->addr_type.gsi.global_route)
105 		   {
106 		   p_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
107 		   ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version,
108 		   p_rcv_desc->grh.traffic_class,
109 		   p_rcv_desc->grh.flow_label);
110 		   p_mad_addr->addr_type.gsi.grh_info.hop_limit =  p_rcv_desc->grh.hop_limit;
111 		   memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw,
112 		   &p_rcv_desc->grh.sgid, sizeof(ib_net64_t));
113 		   memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw,
114 		   p_rcv_desc->grh.dgid,  sizeof(ib_net64_t));
115 		   }
116 		 */
117 	}
118 }
119 
120 /**********************************************************************
121  * OSM ADDR VECTOR TO TS MAD:
122  **********************************************************************/
123 void
124 __osm_ts_conv_osm_addr_to_ts_addr(IN osm_mad_addr_t * p_mad_addr,
125 				  IN uint8_t is_smi, OUT struct ib_mad *p_mad)
126 {
127 
128 	/* For global destination or Multicast address: */
129 	p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid);
130 	p_mad->sl = 0;
131 	if (is_smi) {
132 		p_mad->sqpn = 0;
133 		p_mad->dqpn = 0;
134 	} else {
135 		p_mad->sqpn = 1;
136 		p_mad->dqpn = p_mad_addr->addr_type.gsi.remote_qp;
137 	}
138 }
139 
140 void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind)
141 {
142 	osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
143 	osm_vendor_t *p_vend = p_bind->p_vend;
144 	VAPI_ret_t status;
145 	VAPI_hca_attr_t attr_mod;
146 	VAPI_hca_attr_mask_t attr_mask;
147 
148 	OSM_LOG_ENTER(p_vend->p_log);
149 
150 	memset(&attr_mod, 0, sizeof(attr_mod));
151 	memset(&attr_mask, 0, sizeof(attr_mask));
152 
153 	attr_mod.is_sm = FALSE;
154 	attr_mask = HCA_ATTR_IS_SM;
155 
156 	status =
157 	    VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
158 				 &attr_mask);
159 	if (status != VAPI_OK) {
160 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
161 			"__osm_vendor_clear_sm: ERR 5021: "
162 			"Unable set 'IS_SM' bit in port attributes (%d).\n",
163 			status);
164 	}
165 
166 	OSM_LOG_EXIT(p_vend->p_log);
167 }
168 
169 /**********************************************************************
170  * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT
171  **********************************************************************/
172 void osm_vendor_construct(IN osm_vendor_t * const p_vend)
173 {
174 	memset(p_vend, 0, sizeof(*p_vend));
175 	cl_thread_construct(&(p_vend->smi_bind.poller));
176 	cl_thread_construct(&(p_vend->gsi_bind.poller));
177 }
178 
179 /**********************************************************************
180  * DEALOCATE osm_vendor_t
181  **********************************************************************/
182 void osm_vendor_destroy(IN osm_vendor_t * const p_vend)
183 {
184 	OSM_LOG_ENTER(p_vend->p_log);
185 	osm_transaction_mgr_destroy(p_vend);
186 
187 	/* Destroy the poller threads */
188 	/* HACK: can you destroy an un-initialized thread ? */
189 	pthread_cancel(p_vend->smi_bind.poller.osd.id);
190 	pthread_cancel(p_vend->gsi_bind.poller.osd.id);
191 	cl_thread_destroy(&(p_vend->smi_bind.poller));
192 	cl_thread_destroy(&(p_vend->gsi_bind.poller));
193 	OSM_LOG_EXIT(p_vend->p_log);
194 }
195 
196 /**********************************************************************
197 DEALLOCATE A POINTER TO osm_vendor_t
198 **********************************************************************/
199 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
200 {
201 	CL_ASSERT(pp_vend);
202 
203 	osm_vendor_destroy(*pp_vend);
204 	free(*pp_vend);
205 	*pp_vend = NULL;
206 }
207 
208 /**********************************************************************
209  Initializes the vendor:
210 **********************************************************************/
211 
212 ib_api_status_t
213 osm_vendor_init(IN osm_vendor_t * const p_vend,
214 		IN osm_log_t * const p_log, IN const uint32_t timeout)
215 {
216 	ib_api_status_t status = IB_SUCCESS;
217 
218 	OSM_LOG_ENTER(p_log);
219 
220 	p_vend->p_log = p_log;
221 	p_vend->p_transaction_mgr = NULL;
222 	osm_transaction_mgr_init(p_vend);
223 	p_vend->timeout = timeout;
224 
225 	/* we use the file handle to track the binding */
226 	p_vend->smi_bind.ul_dev_fd = -1;
227 	p_vend->gsi_bind.ul_dev_fd = -1;
228 
229 	OSM_LOG_EXIT(p_log);
230 	return (status);
231 }
232 
233 /**********************************************************************
234  *  Create and Initialize osm_vendor_t Object
235  **********************************************************************/
236 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
237 			     IN const uint32_t timeout)
238 {
239 	ib_api_status_t status;
240 	osm_vendor_t *p_vend;
241 
242 	OSM_LOG_ENTER(p_log);
243 
244 	CL_ASSERT(p_log);
245 
246 	p_vend = malloc(sizeof(*p_vend));
247 	if (p_vend != NULL) {
248 		memset(p_vend, 0, sizeof(*p_vend));
249 
250 		status = osm_vendor_init(p_vend, p_log, timeout);
251 		if (status != IB_SUCCESS) {
252 			osm_vendor_delete(&p_vend);
253 		}
254 	} else {
255 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
256 			"osm_vendor_new: ERR 5007: "
257 			"Fail to allocate vendor object.\n");
258 	}
259 
260 	OSM_LOG_EXIT(p_log);
261 	return (p_vend);
262 }
263 
264 /**********************************************************************
265  * TS RCV Thread callback
266  * HACK: - we need to make this support arbitrary size mads.
267  **********************************************************************/
268 void
269 __osm_ts_rcv_callback(IN osm_ts_bind_info_t * p_bind,
270 		      IN osm_mad_addr_t * p_mad_addr,
271 		      IN uint32_t mad_size, IN void *p_mad)
272 {
273 	ib_api_status_t status;
274 	osm_madw_t *p_req_madw = NULL;
275 	osm_madw_t *p_madw;
276 	osm_vend_wrap_t *p_new_vw;
277 	ib_mad_t *p_mad_buf;
278 	osm_log_t *const p_log = p_bind->p_vend->p_log;
279 
280 	OSM_LOG_ENTER(p_log);
281 
282 	/* if it is a response MAD we mustbe able to get the request */
283 	if (ib_mad_is_response((ib_mad_t *) p_mad)) {
284 		/* can we find a matching madw by this payload TID */
285 		status =
286 		    osm_transaction_mgr_get_madw_for_tid(p_bind->p_vend,
287 							 (ib_mad_t *) p_mad,
288 							 &p_req_madw);
289 		if (status != IB_SUCCESS) {
290 			osm_log(p_log, OSM_LOG_ERROR,
291 				"__osm_ts_rcv_callback: ERR 5008: "
292 				"Error obtaining request madw by TID (%d).\n",
293 				status);
294 			p_req_madw = NULL;
295 		}
296 
297 		if (p_req_madw == NULL) {
298 			osm_log(p_log, OSM_LOG_ERROR,
299 				"__osm_ts_rcv_callback: ERR 5009:  "
300 				"Fail to obtain request madw for receined MAD. Aborting CB.\n");
301 			goto Exit;
302 		}
303 	}
304 
305 	/* do we have a request ??? */
306 	if (p_req_madw == NULL) {
307 
308 		/* if not - get new osm_madw and arrange it. */
309 		/* create the new madw in the pool */
310 		p_madw = osm_mad_pool_get(p_bind->p_osm_pool,
311 					  (osm_bind_handle_t) p_bind,
312 					  mad_size, p_mad_addr);
313 		if (p_madw == NULL) {
314 			osm_log(p_log, OSM_LOG_ERROR,
315 				"__osm_ts_rcv_callback: ERR 5010: "
316 				"Error request for a new madw.\n");
317 			goto Exit;
318 		}
319 		/* HACK: we cust to avoid the const ??? */
320 		p_mad_buf = (void *)p_madw->p_mad;
321 	} else {
322 		/* we have the madw defined during the send and stored in the vend_wrap */
323 		/* we need to make sure the wrapper is correctly init there */
324 		CL_ASSERT(p_req_madw->vend_wrap.p_resp_madw != 0);
325 		p_madw = p_req_madw->vend_wrap.p_resp_madw;
326 
327 		CL_ASSERT(p_madw->h_bind);
328 		p_mad_buf =
329 		    osm_vendor_get(p_madw->h_bind, mad_size,
330 				   &p_madw->vend_wrap);
331 
332 		if (p_mad_buf == NULL) {
333 			osm_log(p_log, OSM_LOG_ERROR,
334 				"__osm_ts_rcv_callback: ERR 5011: "
335 				"Unable to acquire wire MAD.\n");
336 
337 			goto Exit;
338 		}
339 
340 		/*
341 		   Finally, attach the wire MAD to this wrapper.
342 		 */
343 		osm_madw_set_mad(p_madw, p_mad_buf);
344 	}
345 
346 	/* init some fields of the vendor wrapper */
347 	p_new_vw = osm_madw_get_vend_ptr(p_madw);
348 	p_new_vw->h_bind = p_bind;
349 	p_new_vw->size = mad_size;
350 	p_new_vw->p_resp_madw = NULL;
351 	p_new_vw->p_mad_buf = p_mad_buf;
352 
353 	memcpy(p_new_vw->p_mad_buf, p_mad, mad_size);
354 
355 	/* attach the buffer to the wrapper */
356 	p_madw->p_mad = p_mad_buf;
357 
358 	/* we can also make sure we marked the size and bind on the returned madw */
359 	p_madw->h_bind = p_new_vw->h_bind;
360 
361 	/* call the CB */
362 	(*(osm_vend_mad_recv_callback_t) p_bind->rcv_callback)
363 	    (p_madw, p_bind->client_context, p_req_madw);
364 
365 Exit:
366 	OSM_LOG_EXIT(p_log);
367 }
368 
369 /**********************************************************************
370  * TS Send callback : invoked after each send
371  *
372  **********************************************************************/
373 void
374 __osm_ts_send_callback(IN osm_ts_bind_info_t * bind_info_p,
375 		       IN boolean_t is_resp,
376 		       IN osm_madw_t * madw_p, IN IB_comp_status_t status)
377 {
378 	osm_log_t *const p_log = bind_info_p->p_vend->p_log;
379 	osm_vend_wrap_t *p_vw;
380 
381 	OSM_LOG_ENTER(p_log);
382 
383 	osm_log(p_log, OSM_LOG_DEBUG,
384 		"__osm_ts_send_callback: INFO 1008: "
385 		"Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp);
386 
387 	/* we need to handle requests and responses differently */
388 	if (is_resp) {
389 		if (status != IB_COMP_SUCCESS) {
390 			osm_log(p_log, OSM_LOG_ERROR,
391 				"__osm_ts_send_callback: ERR 5012: "
392 				"Error Sending Response MADW:%p.\n", madw_p);
393 		} else {
394 			osm_log(p_log, OSM_LOG_DEBUG,
395 				"__osm_ts_send_callback: DBG 1008: "
396 				"Completed Sending Response MADW:%p.\n",
397 				madw_p);
398 		}
399 
400 		/* if we are a response - we need to clean it up */
401 		osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p);
402 	} else {
403 
404 		/* this call back is invoked on completion of send - error or not */
405 		if (status != IB_COMP_SUCCESS) {
406 
407 			osm_log(p_log, OSM_LOG_ERROR,
408 				"__osm_ts_send_callback: ERR 5013: "
409 				"Received an Error from IB_MGT Send (%d).\n",
410 				status);
411 
412 			p_vw = osm_madw_get_vend_ptr(madw_p);
413 			CL_ASSERT(p_vw);
414 
415 			/*
416 			   Return any wrappers to the pool that may have been
417 			   pre-emptively allocated to handle a receive.
418 			 */
419 			if (p_vw->p_resp_madw) {
420 				osm_mad_pool_put(bind_info_p->p_osm_pool,
421 						 p_vw->p_resp_madw);
422 				p_vw->p_resp_madw = NULL;
423 			}
424 
425 			/* invoke the CB */
426 			(*(osm_vend_mad_send_err_callback_t) bind_info_p->
427 			 send_err_callback)
428 			    (bind_info_p->client_context, madw_p);
429 		} else {
430 			/* successful request send - do nothing - the response will need the
431 			   out mad */
432 			osm_log(p_log, OSM_LOG_DEBUG,
433 				"__osm_ts_send_callback: DBG 1008: "
434 				"Completed Sending Request MADW:%p.\n", madw_p);
435 		}
436 	}
437 
438 	OSM_LOG_EXIT(p_log);
439 }
440 
441 /**********************************************************************
442  * Poller thread:
443  * Always receive 256byte mads from the devcie file
444  **********************************************************************/
445 void __osm_vendor_ts_poller(IN void *p_ptr)
446 {
447 	int ts_ret_code;
448 	struct ib_mad mad;
449 	osm_mad_addr_t mad_addr;
450 	osm_ts_bind_info_t *const p_bind = (osm_ts_bind_info_t *) p_ptr;
451 
452 	OSM_LOG_ENTER(p_bind->p_vend->p_log);
453 	/* we set the type of cancelation for this thread */
454 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
455 
456 	while (1) {
457 		/* we read one mad at a time and pass it to the read callback function */
458 		ts_ret_code = read(p_bind->ul_dev_fd, &mad, sizeof(mad));
459 		if (ts_ret_code != sizeof(mad)) {
460 			osm_log(p_bind->p_vend->p_log, OSM_LOG_ERROR,
461 				"__osm_vendor_ts_poller: ERR 5003: "
462 				"error with read, bytes = %d, errno = %d\n",
463 				ts_ret_code, errno);
464 		} else {
465 			osm_log(p_bind->p_vend->p_log, OSM_LOG_DEBUG,
466 				"__osm_vendor_ts_poller: "
467 				"MAD QPN:%d SLID:0x%04x class:0x%02x "
468 				"__osm_vendor_ts_poller:0x%02x attr:0x%04x status:0x%04x "
469 				"__osm_vendor_ts_poller:0x%016" PRIx64 "\n",
470 				cl_ntoh32(mad.dqpn),
471 				cl_ntoh16(mad.slid),
472 				mad.mgmt_class,
473 				mad.r_method,
474 				cl_ntoh16(mad.attribute_id),
475 				cl_ntoh16(mad.status),
476 				cl_ntoh64(mad.transaction_id));
477 
478 			/* first arrange an address */
479 			__osm_ts_conv_mad_rcv_desc_to_osm_addr(p_bind->p_vend,
480 							       &mad,
481 							       (((ib_mad_t *) &
482 								 mad)->
483 								mgmt_class ==
484 								IB_MCLASS_SUBN_LID)
485 							       ||
486 							       (((ib_mad_t *) &
487 								 mad)->
488 								mgmt_class ==
489 								IB_MCLASS_SUBN_DIR),
490 							       &mad_addr);
491 
492 			/* call the receiver callback */
493 			/* HACK: this should be replaced with a call to the RMPP Assembly ... */
494 			__osm_ts_rcv_callback(p_bind, &mad_addr, 256, &mad);
495 		}
496 	}
497 
498 	OSM_LOG_EXIT(p_bind->p_vend->p_log);
499 }
500 
501 /**********************************************************************
502  * BINDs a callback (rcv and send error) for a given class and method
503  * defined by the given:  osm_bind_info_t
504  **********************************************************************/
505 osm_bind_handle_t
506 osm_vendor_bind(IN osm_vendor_t * const p_vend,
507 		IN osm_bind_info_t * const p_user_bind,
508 		IN osm_mad_pool_t * const p_mad_pool,
509 		IN osm_vend_mad_recv_callback_t mad_recv_callback,
510 		IN osm_vend_mad_send_err_callback_t send_err_callback,
511 		IN void *context)
512 {
513 	ib_net64_t port_guid;
514 	osm_ts_bind_info_t *p_bind = NULL;
515 	VAPI_hca_hndl_t hca_hndl;
516 	VAPI_hca_id_t hca_id;
517 	uint32_t port_num;
518 	ib_api_status_t status;
519 	int device_fd;
520 	char device_file[16];
521 	osm_ts_user_mad_filter filter;
522 	int ts_ioctl_ret;
523 	int qpn;
524 
525 	OSM_LOG_ENTER(p_vend->p_log);
526 
527 	CL_ASSERT(p_mad_pool);
528 
529 	port_guid = p_user_bind->port_guid;
530 
531 	osm_log(p_vend->p_log, OSM_LOG_INFO,
532 		"osm_vendor_bind: "
533 		"Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid));
534 
535 	switch (p_user_bind->mad_class) {
536 	case IB_MCLASS_SUBN_LID:
537 	case IB_MCLASS_SUBN_DIR:
538 		p_bind = &(p_vend->smi_bind);
539 		qpn = 0;
540 		break;
541 
542 	case IB_MCLASS_SUBN_ADM:
543 	default:
544 		p_bind = &(p_vend->gsi_bind);
545 		qpn = 1;
546 		break;
547 	}
548 
549 	/* Make sure we did not previously opened the file */
550 	if (p_bind->ul_dev_fd >= 0) {
551 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
552 			"osm_vendor_bind: ERR 5004: "
553 			"Already binded to port %u\n", p_bind->port_num);
554 		goto Exit;
555 	}
556 
557 	/*
558 	   We need to figure out what is the TS file name to attach to.
559 	   I guess it is following the index of the port in the table of
560 	   ports.
561 	 */
562 
563 	/* obtain the hca name and port num from the guid */
564 	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
565 		"osm_vendor_bind: "
566 		"Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
567 		cl_ntoh64(port_guid));
568 	status =
569 	    osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl,
570 					    &hca_id, &port_num);
571 	if (status != IB_SUCCESS) {
572 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
573 			"osm_vendor_bind: ERR 5005: "
574 			"Fail to find port number of port guid:0x%016" PRIx64
575 			"\n", port_guid);
576 		goto Exit;
577 	}
578 
579 	/* the file name is just /dev/ts_ua0: */
580 	strcpy(device_file, "/dev/ts_ua0");
581 
582 	osm_log(p_vend->p_log, OSM_LOG_ERROR,
583 		"osm_vendor_bind: " "Opening TS UL dev file:%s\n", device_file);
584 
585 	/* Open the file ... */
586 	device_fd = open(device_file, O_RDWR);
587 	if (device_fd < 0) {
588 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
589 			"osm_vendor_bind: ERR 5006: "
590 			"Fail to open TS UL dev file:%s\n", device_file);
591 		goto Exit;
592 	}
593 
594 	/* track this bind request info */
595 	p_bind->ul_dev_fd = device_fd;
596 	p_bind->port_num = port_num;
597 	p_bind->p_vend = p_vend;
598 	p_bind->client_context = context;
599 	p_bind->rcv_callback = mad_recv_callback;
600 	p_bind->send_err_callback = send_err_callback;
601 	p_bind->p_osm_pool = p_mad_pool;
602 	p_bind->hca_hndl = hca_hndl;
603 
604 	/*
605 	 * Create the MAD filter on this file handle.
606 	 */
607 	filter.port = port_num;
608 
609 	filter.qpn = qpn;
610 	filter.mgmt_class = p_user_bind->mad_class;
611 	filter.direction = TS_IB_MAD_DIRECTION_IN;
612 	filter.mask =
613 	    TS_IB_MAD_FILTER_DIRECTION |
614 	    TS_IB_MAD_FILTER_PORT |
615 	    TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS;
616 
617 	ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter);
618 	if (ts_ioctl_ret < 0) {
619 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
620 			"osm_vendor_bind: ERR 5014: "
621 			"Fail to register MAD filter with err:%u\n",
622 			ts_ioctl_ret);
623 		goto Exit;
624 	}
625 
626 	/* Initialize the listener thread for this port */
627 	status = cl_thread_init(&p_bind->poller,
628 				__osm_vendor_ts_poller, p_bind,
629 				"osm ts poller");
630 	if (status != IB_SUCCESS)
631 		goto Exit;
632 
633 Exit:
634 	OSM_LOG_EXIT(p_vend->p_log);
635 	return ((osm_bind_handle_t) p_bind);
636 }
637 
638 /**********************************************************************
639 Get a mad from the lower level.
640 The osm_vend_wrap_t is a wrapper used to connect the mad to the response.
641 **********************************************************************/
642 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
643 			 IN const uint32_t mad_size,
644 			 IN osm_vend_wrap_t * const p_vw)
645 {
646 	ib_mad_t *p_mad;
647 	osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
648 	osm_vendor_t *p_vend = p_bind->p_vend;
649 
650 	OSM_LOG_ENTER(p_vend->p_log);
651 
652 	CL_ASSERT(p_vw);
653 
654 	p_vw->size = mad_size;
655 
656 	/* allocate it */
657 	p_mad = (ib_mad_t *) malloc(p_vw->size);
658 	if (p_mad == NULL) {
659 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
660 			"osm_vendor_get: ERR 5022: "
661 			"Error Obtaining MAD buffer.\n");
662 		goto Exit;
663 	}
664 
665 	memset(p_mad, 0, p_vw->size);
666 
667 	/* track locally */
668 	p_vw->p_mad_buf = p_mad;
669 	p_vw->h_bind = h_bind;
670 	p_vw->p_resp_madw = NULL;
671 
672 	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
673 		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
674 			"osm_vendor_get: "
675 			"Acquired MAD %p, size = %u.\n", p_mad, p_vw->size);
676 	}
677 
678 Exit:
679 	OSM_LOG_EXIT(p_vend->p_log);
680 	return (p_mad);
681 }
682 
683 /**********************************************************************
684  * Return a MAD by providing it's wrapper object.
685  **********************************************************************/
686 void
687 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
688 {
689 	osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
690 	osm_vendor_t *p_vend = p_bind->p_vend;
691 	osm_madw_t *p_madw;
692 
693 	OSM_LOG_ENTER(p_vend->p_log);
694 
695 	CL_ASSERT(p_vw);
696 	CL_ASSERT(p_vw->p_mad_buf);
697 
698 	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
699 		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
700 			"osm_vendor_put: " "Retiring MAD %p.\n",
701 			p_vw->p_mad_buf);
702 	}
703 
704 	/*
705 	 * We moved the removal of the transaction to immediatly after
706 	 * it was looked up.
707 	 */
708 
709 	/* free the mad but the wrapper is part of the madw object */
710 	free(p_vw->p_mad_buf);
711 	p_vw->p_mad_buf = NULL;
712 	p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
713 	p_madw->p_mad = NULL;
714 
715 	OSM_LOG_EXIT(p_vend->p_log);
716 }
717 
718 /**********************************************************************
719 Actually Send a MAD
720 
721 MADs are buffers of type: struct ib_mad - so they are limited by size.
722 This is for internal use by osm_vendor_send and the transaction mgr
723 retry too.
724 **********************************************************************/
725 ib_api_status_t
726 osm_ts_send_mad(IN osm_ts_bind_info_t * p_bind, IN osm_madw_t * const p_madw)
727 {
728 	osm_vendor_t *const p_vend = p_bind->p_vend;
729 	osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
730 	ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
731 	struct ib_mad ts_mad;
732 	int ret;
733 	ib_api_status_t status;
734 
735 	OSM_LOG_ENTER(p_vend->p_log);
736 
737 	/*
738 	 * Copy the MAD over to the sent mad
739 	 */
740 	memcpy(&ts_mad, p_mad, 256);
741 
742 	/*
743 	 * For all sends other than directed route SM MADs,
744 	 * acquire an address vector for the destination.
745 	 */
746 	if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
747 		__osm_ts_conv_osm_addr_to_ts_addr(p_mad_addr,
748 						  p_mad->mgmt_class ==
749 						  IB_MCLASS_SUBN_LID, &ts_mad);
750 	} else {
751 		/* is a directed route - we need to construct a permissive address */
752 		/* we do not need port number since it is part of the mad_hndl */
753 		ts_mad.dlid = IB_LID_PERMISSIVE;
754 		ts_mad.slid = IB_LID_PERMISSIVE;
755 	}
756 	if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) ||
757 	    (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) {
758 		ts_mad.sqpn = 0;
759 		ts_mad.dqpn = 0;
760 	} else {
761 		ts_mad.sqpn = 1;
762 		ts_mad.dqpn = 1;
763 	}
764 	ts_mad.port = p_bind->port_num;
765 
766 	/* send it */
767 	ret = write(p_bind->ul_dev_fd, &ts_mad, sizeof(ts_mad));
768 
769 	if (ret != sizeof(ts_mad)) {
770 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
771 			"osm_ts_send_mad: ERR 5026: "
772 			"Error sending mad (%d).\n", ret);
773 		status = IB_ERROR;
774 		goto Exit;
775 	}
776 
777 	status = IB_SUCCESS;
778 
779 Exit:
780 	OSM_LOG_EXIT(p_vend->p_log);
781 	return (status);
782 }
783 
784 /**********************************************************************
785 Send a MAD through.
786 
787 What is unclear to me is the need for the setting of all the MAD Wrapper
788 fields. Seems like the OSM uses these values during it's processing...
789 **********************************************************************/
790 ib_api_status_t
791 osm_vendor_send(IN osm_bind_handle_t h_bind,
792 		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
793 {
794 	osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
795 	osm_vendor_t *const p_vend = p_bind->p_vend;
796 	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
797 	ib_api_status_t status;
798 
799 	OSM_LOG_ENTER(p_vend->p_log);
800 
801 	/*
802 	 * If a response is expected to this MAD, then preallocate
803 	 * a mad wrapper to contain the wire MAD received in the
804 	 * response.  Allocating a wrapper here allows for easier
805 	 * failure paths than after we already received the wire mad.
806 	 */
807 	if (resp_expected == TRUE) {
808 		/* we track it in the vendor wrapper */
809 		p_vw->p_resp_madw =
810 		    osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool);
811 		if (p_vw->p_resp_madw == NULL) {
812 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
813 				"osm_vendor_send: ERR 5024: "
814 				"Unable to allocate MAD wrapper.\n");
815 			status = IB_INSUFFICIENT_RESOURCES;
816 			goto Exit;
817 		}
818 
819 		/* put some minimal info on that wrapper */
820 		((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind;
821 
822 		/* we also want to track it in the TID based map */
823 		status = osm_transaction_mgr_insert_madw((osm_bind_handle_t *)
824 							 p_bind, p_madw);
825 		if (status != IB_SUCCESS) {
826 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
827 				"osm_vendor_send: ERR 5025: "
828 				"Error inserting request madw by TID (%d).\n",
829 				status);
830 		}
831 	} else
832 		p_vw->p_resp_madw = NULL;
833 
834 	/* do the actual send */
835 	/* HACK: to be replaced by call to RMPP Segmentation */
836 	status = osm_ts_send_mad(p_bind, p_madw);
837 
838 	/* we do not get an asycn callback so call it ourselves */
839 	/* this will handle all cleanup if neccessary */
840 	__osm_ts_send_callback(p_bind, !resp_expected, p_madw, status);
841 
842 Exit:
843 	OSM_LOG_EXIT(p_vend->p_log);
844 	return (status);
845 }
846 
847 /**********************************************************************
848  * the idea here is to change the content of the bind such that it
849  * will hold the local address used for sending directed route by the SMA.
850  **********************************************************************/
851 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
852 {
853 	osm_vendor_t *p_vend = ((osm_ts_bind_info_t *) h_bind)->p_vend;
854 
855 	OSM_LOG_ENTER(p_vend->p_log);
856 
857 	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
858 		"osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n");
859 
860 	OSM_LOG_EXIT(p_vend->p_log);
861 
862 	return (IB_SUCCESS);
863 }
864 
865 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
866 {
867 	osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
868 	osm_vendor_t *p_vend = p_bind->p_vend;
869 	VAPI_ret_t status;
870 	VAPI_hca_attr_t attr_mod;
871 	VAPI_hca_attr_mask_t attr_mask;
872 
873 	OSM_LOG_ENTER(p_vend->p_log);
874 
875 	memset(&attr_mod, 0, sizeof(attr_mod));
876 	memset(&attr_mask, 0, sizeof(attr_mask));
877 
878 	attr_mod.is_sm = is_sm_val;
879 	attr_mask = HCA_ATTR_IS_SM;
880 
881 	status =
882 	    VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
883 				 &attr_mask);
884 	if (status != VAPI_OK) {
885 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
886 			"osm_vendor_set_sm: ERR 5027: "
887 			"Unable set 'IS_SM' bit to:%u in port attributes (%d).\n",
888 			is_sm_val, status);
889 	}
890 
891 	OSM_LOG_EXIT(p_vend->p_log);
892 }
893 
894 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
895 {
896 
897 }
898