xref: /freebsd/contrib/ofed/opensm/libvendor/osm_vendor_mtl.c (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 #ifdef OSM_VENDOR_INTF_MTL
41 
42 #include <stdlib.h>
43 #include <string.h>
44 #include <opensm/osm_helper.h>
45 #include <opensm/osm_log.h>
46 /* HACK - I do not know how to prevent complib from loading kernel H files */
47 #undef __init
48 #include <vendor/osm_vendor_mtl.h>
49 #include <vendor/osm_vendor_api.h>
50 #include <opensm/osm_subnet.h>
51 #include <opensm/osm_opensm.h>
52 #include <vendor/osm_vendor_mtl_transaction_mgr.h>
53 #include <vendor/osm_mtl_bind.h>
54 
55 /*
56   Since a race can accure on requests. Meaning - a response is received before
57   the send_callback is called - we will save both the madw_p and the fact
58   whether or not it is a response. A race can occure only on requests that did
59   not fail, and then the madw_p will be put back in the pool before the callback.
60 */
61 uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw)
62 {
63 	uint64_t wrid = 0;
64 
65 	CL_ASSERT(p_madw->p_mad);
66 
67 	memcpy(&wrid, &p_madw, sizeof(osm_madw_t *));
68 	wrid = (wrid << 1) |
69 	    ib_mad_is_response(p_madw->p_mad);
70 	return wrid;
71 }
72 
73 void
74 __osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid,
75 				  OUT uint8_t * is_resp,
76 				  OUT osm_madw_t ** pp_madw)
77 {
78 	*is_resp = wrid & 0x0000000000000001;
79 	wrid = wrid >> 1;
80 	memcpy(pp_madw, &wrid, sizeof(osm_madw_t *));
81 }
82 
83 /**********************************************************************
84  * IB_MGT to OSM ADDRESS VECTOR
85  **********************************************************************/
86 void
87 __osm_mtl_conv_ibmgt_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend,
88 					  IN IB_MGT_mad_rcv_desc_t * p_rcv_desc,
89 					  IN uint8_t is_smi,
90 					  OUT osm_mad_addr_t * p_mad_addr)
91 {
92 	/*  p_mad_addr->dest_lid = p_osm->subn.sm_base_lid; - for resp we use the dest lid ... */
93 	p_mad_addr->dest_lid = cl_hton16(p_rcv_desc->remote_lid);
94 	p_mad_addr->static_rate = 0;	/*  HACK - we do not  know the rate ! */
95 	p_mad_addr->path_bits = p_rcv_desc->local_path_bits;
96 	if (is_smi) {
97 		/* SMI */
98 		p_mad_addr->addr_type.smi.source_lid =
99 		    cl_hton16(p_rcv_desc->remote_lid);
100 		p_mad_addr->addr_type.smi.port_num = 99;	/*  HACK - if used - should fail */
101 	} else {
102 		/* GSI */
103 		/* seems to me there is a IBMGT bug reversing the QPN ... */
104 		/* Does IBMGT supposed to provide the QPN is network or HOST ? */
105 		p_mad_addr->addr_type.gsi.remote_qp = cl_hton32(p_rcv_desc->qp);
106 
107 		p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
108 		/*  we do have the p_mad_addr->pkey_ix but how to get the PKey by index ? */
109 		/*  the only way seems to be to use VAPI_query_hca_pkey_tbl and obtain */
110 		/*  the full PKey table - than go by the index. */
111 		/*  since this does not seem reasonable to me I simply use the default */
112 		/*  There is a TAVOR limitation that only one P_KEY is supported per  */
113 		/*  QP - so QP1 must use IB_DEFAULT_PKEY */
114 		p_mad_addr->addr_type.gsi.pkey_ix = 0;
115 		p_mad_addr->addr_type.gsi.service_level = p_rcv_desc->sl;
116 
117 		p_mad_addr->addr_type.gsi.global_route = p_rcv_desc->grh_flag;
118 		/* copy the GRH data if relevant */
119 		if (p_mad_addr->addr_type.gsi.global_route) {
120 			p_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
121 			    ib_grh_set_ver_class_flow(p_rcv_desc->grh.
122 						      IP_version,
123 						      p_rcv_desc->grh.
124 						      traffic_class,
125 						      p_rcv_desc->grh.
126 						      flow_label);
127 			p_mad_addr->addr_type.gsi.grh_info.hop_limit =
128 			    p_rcv_desc->grh.hop_limit;
129 			memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw,
130 			       &p_rcv_desc->grh.sgid, sizeof(ib_net64_t));
131 			memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw,
132 			       p_rcv_desc->grh.dgid, sizeof(ib_net64_t));
133 		}
134 	}
135 }
136 
137 /**********************************************************************
138  * OSM ADDR VECTOR TO IB_MGT
139  **********************************************************************/
140 void
141 __osm_mtl_conv_osm_addr_to_ibmgt_addr(IN osm_mad_addr_t * p_mad_addr,
142 				      IN uint8_t is_smi, OUT IB_ud_av_t * p_av)
143 {
144 
145 	/* For global destination or Multicast address: */
146 	u_int8_t ver;
147 
148 	memset(p_av, 0, sizeof(IB_ud_av_t));
149 
150 	p_av->src_path_bits = p_mad_addr->path_bits;
151 	p_av->static_rate = p_mad_addr->static_rate;
152 	p_av->dlid = cl_ntoh16(p_mad_addr->dest_lid);
153 
154 	if (is_smi) {
155 		p_av->sl = 0;	/*  Just to note we use 0 here. */
156 	} else {
157 		p_av->sl = p_mad_addr->addr_type.gsi.service_level;
158 		p_av->grh_flag = p_mad_addr->addr_type.gsi.global_route;
159 
160 		if (p_mad_addr->addr_type.gsi.global_route) {
161 			ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi.
162 						  grh_info.ver_class_flow, &ver,
163 						  &p_av->traffic_class,
164 						  &p_av->flow_label);
165 			p_av->hop_limit =
166 			    p_mad_addr->addr_type.gsi.grh_info.hop_limit;
167 			p_av->sgid_index = 0;	/*  we always use source GID 0 */
168 			memcpy(&p_av->dgid,
169 			       &p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw,
170 			       sizeof(ib_net64_t));
171 
172 		}
173 	}
174 }
175 
176 void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind)
177 {
178 	osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind;
179 	osm_vendor_t *p_vend = p_bind->p_vend;
180 	VAPI_ret_t status;
181 	VAPI_hca_attr_t attr_mod;
182 	VAPI_hca_attr_mask_t attr_mask;
183 
184 	OSM_LOG_ENTER(p_vend->p_log);
185 
186 	memset(&attr_mod, 0, sizeof(attr_mod));
187 	memset(&attr_mask, 0, sizeof(attr_mask));
188 
189 	attr_mod.is_sm = FALSE;
190 	attr_mask = HCA_ATTR_IS_SM;
191 
192 	status =
193 	    VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
194 				 &attr_mask);
195 	if (status != VAPI_OK) {
196 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
197 			"__osm_vendor_clear_sm: ERR 3C21: "
198 			"Unable set 'IS_SM' bit in port attributes (%d).\n",
199 			status);
200 	}
201 
202 	OSM_LOG_EXIT(p_vend->p_log);
203 }
204 
205 /**********************************************************************
206  * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT
207  **********************************************************************/
208 void osm_vendor_construct(IN osm_vendor_t * const p_vend)
209 {
210 	memset(p_vend, 0, sizeof(*p_vend));
211 }
212 
213 /**********************************************************************
214  * DEALOCATE osm_vendor_t
215  **********************************************************************/
216 void osm_vendor_destroy(IN osm_vendor_t * const p_vend)
217 {
218 	osm_vendor_mgt_bind_t *vendor_mgt_bind_p;
219 	IB_MGT_ret_t mgt_ret;
220 	OSM_LOG_ENTER(p_vend->p_log);
221 
222 	if (p_vend->h_al != NULL) {
223 		vendor_mgt_bind_p = (osm_vendor_mgt_bind_t *) p_vend->h_al;
224 		if (vendor_mgt_bind_p->gsi_init) {
225 
226 			/* un register the class */
227 			/* HACK WE ASSUME WE ONLY GOT SA CLASS REGISTERD ON GSI !!! */
228 			mgt_ret =
229 			    IB_MGT_unbind_gsi_class(vendor_mgt_bind_p->
230 						    gsi_mads_hdl,
231 						    IB_MCLASS_SUBN_ADM);
232 			if (mgt_ret != IB_MGT_OK) {
233 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
234 					"osm_vendor_destroy: ERR 3C03: "
235 					"Fail to unbind the SA class.\n");
236 			}
237 
238 			/* un bind the handle */
239 			if (IB_MGT_release_handle
240 			    (vendor_mgt_bind_p->gsi_mads_hdl) != IB_MGT_OK) {
241 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
242 					"osm_vendor_destroy: ERR 3C02: "
243 					"Fail to unbind the SA GSI handle.\n");
244 			}
245 			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
246 				"osm_vendor_destroy: DBG 1002: "
247 				"Unbind the GSI handles.\n");
248 		}
249 		if (vendor_mgt_bind_p->smi_init) {
250 			/* first - clear the IS_SM in the capability mask */
251 			__osm_vendor_clear_sm((osm_bind_handle_t)
252 					      (vendor_mgt_bind_p->smi_p_bind));
253 
254 			/* un register the class */
255 			mgt_ret =
256 			    IB_MGT_unbind_sm(vendor_mgt_bind_p->smi_mads_hdl);
257 			if (mgt_ret != IB_MGT_OK) {
258 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
259 					"osm_vendor_destroy: ERR 3C04: "
260 					"Fail to unbind the SM class.\n");
261 			}
262 
263 			/* un bind the handle */
264 			if (IB_MGT_release_handle
265 			    (vendor_mgt_bind_p->smi_mads_hdl) != IB_MGT_OK) {
266 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
267 					"osm_vendor_destroy: ERR 3C05: "
268 					"Fail to unbind the SMI handle.\n");
269 			}
270 			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
271 				"osm_vendor_destroy: DBG 1003: "
272 				"Unbind the SMI handles.\n");
273 
274 		}
275 	}
276 	osm_transaction_mgr_destroy(p_vend);
277 	/*  __osm_mtl_destroy_tid_mad_map( p_vend ); */
278 	OSM_LOG_EXIT(p_vend->p_log);
279 }
280 
281 /**********************************************************************
282 DEALLOCATE A POINTER TO osm_vendor_t
283 **********************************************************************/
284 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
285 {
286 	CL_ASSERT(pp_vend);
287 
288 	osm_vendor_destroy(*pp_vend);
289 	free(*pp_vend);
290 	*pp_vend = NULL;
291 }
292 
293 /**********************************************************************
294  * This proc actuall binds the handle to the lower level.
295  *
296  * We might have here as a result a casting of our struct to the ib_al_handle_t
297  *
298  * Q: Do we need 2 of those - one for MSI and one for GSI ?
299  * A: Yes! We should be able to do the SA too. So we need a struct!
300  *
301  **********************************************************************/
302 
303 ib_api_status_t
304 osm_vendor_init(IN osm_vendor_t * const p_vend,
305 		IN osm_log_t * const p_log, IN const uint32_t timeout)
306 {
307 	osm_vendor_mgt_bind_t *ib_mgt_hdl_p;
308 	ib_api_status_t status = IB_SUCCESS;
309 
310 	OSM_LOG_ENTER(p_log);
311 
312 	p_vend->p_log = p_log;
313 
314 	/*
315 	 * HACK: We need no handle. Assuming the driver is up.
316 	 */
317 	ib_mgt_hdl_p = (osm_vendor_mgt_bind_t *)
318 	    malloc(sizeof(osm_vendor_mgt_bind_t));
319 	if (ib_mgt_hdl_p == NULL) {
320 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
321 			"osm_vendor_init: ERR 3C06: "
322 			"Fail to allocate vendor mgt handle.\n");
323 		goto Exit;
324 	}
325 
326 	ib_mgt_hdl_p->smi_init = FALSE;
327 	ib_mgt_hdl_p->gsi_init = FALSE;
328 	/* cast it into the ib_al_handle_t h_al */
329 	p_vend->h_al = (ib_al_handle_t) ib_mgt_hdl_p;
330 	p_vend->p_transaction_mgr = NULL;
331 	osm_transaction_mgr_init(p_vend);
332 	/*  p_vend->madw_by_tid_map_p = NULL; */
333 	/*  __osm_mtl_init_tid_mad_map( p_vend ); */
334 	p_vend->timeout = timeout;
335 
336 Exit:
337 	OSM_LOG_EXIT(p_log);
338 	return (status);
339 }
340 
341 /**********************************************************************
342  *  Create and Initialize osm_vendor_t Object
343  **********************************************************************/
344 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
345 			     IN const uint32_t timeout)
346 {
347 	ib_api_status_t status;
348 	osm_vendor_t *p_vend;
349 
350 	OSM_LOG_ENTER(p_log);
351 
352 	CL_ASSERT(p_log);
353 
354 	p_vend = malloc(sizeof(*p_vend));
355 	if (p_vend != NULL) {
356 		memset(p_vend, 0, sizeof(*p_vend));
357 		status = osm_vendor_init(p_vend, p_log, timeout);
358 		if (status != IB_SUCCESS) {
359 			osm_vendor_delete(&p_vend);
360 		}
361 	} else {
362 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
363 			"osm_vendor_new: ERR 3C07: "
364 			"Fail to allocate vendor object.\n");
365 	}
366 
367 	OSM_LOG_EXIT(p_log);
368 	return (p_vend);
369 }
370 
371 /**********************************************************************
372  * IB_MGT RCV callback
373  *
374  **********************************************************************/
375 void
376 __osm_mtl_rcv_callback(IN IB_MGT_mad_hndl_t mad_hndl,
377 		       IN void *private_ctx_p,
378 		       IN void *payload_p,
379 		       IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p)
380 {
381 	IB_MGT_ret_t status;
382 	osm_mtl_bind_info_t *bind_info_p = private_ctx_p;
383 	osm_madw_t *req_madw_p = NULL;
384 	osm_madw_t *madw_p;
385 	osm_vend_wrap_t *p_new_vw;
386 	osm_mad_addr_t mad_addr;
387 	ib_mad_t *mad_buf_p;
388 	osm_log_t *const p_log = bind_info_p->p_vend->p_log;
389 
390 	OSM_LOG_ENTER(p_log);
391 
392 	/* if it is a response MAD we mustbe able to get the request */
393 	if (ib_mad_is_response((ib_mad_t *) payload_p)) {
394 		/* can we find a matching madw by this payload TID */
395 		status =
396 		    osm_transaction_mgr_get_madw_for_tid(bind_info_p->p_vend,
397 							 (ib_mad_t *) payload_p,
398 							 &req_madw_p);
399 		if (status != IB_MGT_OK) {
400 			osm_log(p_log, OSM_LOG_ERROR,
401 				"__osm_mtl_rcv_callback: ERR 3C08: "
402 				"Error obtaining request madw by TID (%d).\n",
403 				status);
404 			req_madw_p = NULL;
405 		}
406 
407 		if (req_madw_p == NULL) {
408 			osm_log(p_log, OSM_LOG_ERROR,
409 				"__osm_mtl_rcv_callback: ERR 3C09:  "
410 				"Fail to obtain request madw for received MAD.(method=%X attr=%X) Aborting CB.\n",
411 				((ib_mad_t *) payload_p)->method,
412 				cl_ntoh16(((ib_mad_t *) payload_p)->attr_id)
413 
414 			    );
415 			goto Exit;
416 		}
417 	}
418 
419 	/* do we have a request ??? */
420 	if (req_madw_p == NULL) {
421 
422 		/* first arrange an address */
423 		__osm_mtl_conv_ibmgt_rcv_desc_to_osm_addr(bind_info_p->p_vend,
424 							  rcv_remote_info_p,
425 							  (((ib_mad_t *)
426 							    payload_p)->
427 							   mgmt_class ==
428 							   IB_MCLASS_SUBN_LID)
429 							  || (((ib_mad_t *)
430 							       payload_p)->
431 							      mgmt_class ==
432 							      IB_MCLASS_SUBN_DIR),
433 							  &mad_addr);
434 
435 		osm_log(p_log, OSM_LOG_ERROR,
436 			"__osm_mtl_rcv_callback: : "
437 			"Received MAD from QP:%X.\n",
438 			cl_ntoh32(mad_addr.addr_type.gsi.remote_qp)
439 		    );
440 
441 		/* if not - get new osm_madw and arrange it. */
442 		/* create the new madw in the pool */
443 		madw_p = osm_mad_pool_get(bind_info_p->p_osm_pool,
444 					  (osm_bind_handle_t) bind_info_p,
445 					  MAD_BLOCK_SIZE, &mad_addr);
446 		if (madw_p == NULL) {
447 			osm_log(p_log, OSM_LOG_ERROR,
448 				"__osm_mtl_rcv_callback: ERR 3C10: "
449 				"Error request for a new madw.\n");
450 			goto Exit;
451 		}
452 		/* HACK: we cust to avoid the const ??? */
453 		mad_buf_p = (void *)madw_p->p_mad;
454 	} else {
455 		/* we have the madw defined during the send and stored in the vend_wrap */
456 		/* we need to make sure the wrapper is correctly init there */
457 		CL_ASSERT(req_madw_p->vend_wrap.p_resp_madw != 0);
458 		madw_p = req_madw_p->vend_wrap.p_resp_madw;
459 
460 		/* HACK: we do not Support RMPP */
461 		CL_ASSERT(madw_p->h_bind);
462 		mad_buf_p =
463 		    osm_vendor_get(madw_p->h_bind, MAD_BLOCK_SIZE,
464 				   &madw_p->vend_wrap);
465 
466 		if (mad_buf_p == NULL) {
467 			osm_log(p_log, OSM_LOG_ERROR,
468 				"__osm_mtl_rcv_callback: ERR 3C11: "
469 				"Unable to acquire wire MAD.\n");
470 
471 			goto Exit;
472 		}
473 
474 		/*
475 		   Finally, attach the wire MAD to this wrapper.
476 		 */
477 		osm_madw_set_mad(madw_p, mad_buf_p);
478 
479 		/* also we need to handle the size of the mad since we did not init ... */
480 		madw_p->mad_size = MAD_BLOCK_SIZE;
481 	}
482 
483 	/* init some fields of the vendor wrapper */
484 	p_new_vw = osm_madw_get_vend_ptr(madw_p);
485 	p_new_vw->h_bind = bind_info_p;
486 	p_new_vw->size = MAD_BLOCK_SIZE;
487 	p_new_vw->p_resp_madw = NULL;
488 	p_new_vw->mad_buf_p = mad_buf_p;
489 
490 	/* HACK: We do not support RMPP in receiving MADS */
491 	memcpy(p_new_vw->mad_buf_p, payload_p, MAD_BLOCK_SIZE);
492 
493 	/* attach the buffer to the wrapper */
494 	madw_p->p_mad = mad_buf_p;
495 
496 	/* we can also make sure we marked the size and bind on the returned madw */
497 	madw_p->h_bind = p_new_vw->h_bind;
498 
499 	/* call the CB */
500 	(*bind_info_p->rcv_callback) (madw_p, bind_info_p->client_context,
501 				      req_madw_p);
502 
503 Exit:
504 	OSM_LOG_EXIT(p_log);
505 }
506 
507 /**********************************************************************
508  * IB_MGT Send callback : invoked after each send
509  *
510  **********************************************************************/
511 void
512 __osm_mtl_send_callback(IN IB_MGT_mad_hndl_t mad_hndl,
513 			IN u_int64_t wrid,
514 			IN IB_comp_status_t status, IN void *private_ctx_p)
515 {
516 	osm_madw_t *madw_p;
517 	osm_mtl_bind_info_t *bind_info_p =
518 	    (osm_mtl_bind_info_t *) private_ctx_p;
519 	osm_log_t *const p_log = bind_info_p->p_vend->p_log;
520 	osm_vend_wrap_t *p_vw;
521 	uint8_t is_resp;
522 
523 	OSM_LOG_ENTER(p_log);
524 
525 	/* obtain the madp from the wrid */
526 	__osm_set_p_madw_and_resp_by_wrid(wrid, &is_resp, &madw_p);
527 
528 	osm_log(p_log, OSM_LOG_DEBUG,
529 		"__osm_mtl_send_callback: INFO 1008: "
530 		"Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp);
531 
532 	/* we need to handle requests and responses differently */
533 	if (is_resp) {
534 		if (status != IB_COMP_SUCCESS) {
535 			osm_log(p_log, OSM_LOG_ERROR,
536 				"__osm_mtl_send_callback: ERR 3C12: "
537 				"Error Sending Response MADW:%p.\n", madw_p);
538 		} else {
539 			osm_log(p_log, OSM_LOG_DEBUG,
540 				"__osm_mtl_send_callback: DBG 1008: "
541 				"Completed Sending Response MADW:%p.\n",
542 				madw_p);
543 		}
544 
545 		/* if we are a response - we need to clean it up */
546 		osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p);
547 	} else {
548 
549 		/* this call back is invoked on completion of send - error or not */
550 		if (status != IB_COMP_SUCCESS) {
551 
552 			osm_log(p_log, OSM_LOG_ERROR,
553 				"__osm_mtl_send_callback: ERR 3C13: "
554 				"Received an Error from IB_MGT Send (%d).\n",
555 				status);
556 
557 			p_vw = osm_madw_get_vend_ptr(madw_p);
558 			CL_ASSERT(p_vw);
559 
560 			/*
561 			   Return any wrappers to the pool that may have been
562 			   pre-emptively allocated to handle a receive.
563 			 */
564 			if (p_vw->p_resp_madw) {
565 				osm_mad_pool_put(bind_info_p->p_osm_pool,
566 						 p_vw->p_resp_madw);
567 				p_vw->p_resp_madw = NULL;
568 			}
569 
570 			/* invoke the CB */
571 			(*bind_info_p->send_err_callback) (bind_info_p->
572 							   client_context,
573 							   madw_p);
574 		} else {
575 			/* successful request send - do nothing - the response will need the
576 			   out mad */
577 			osm_log(p_log, OSM_LOG_DEBUG,
578 				"__osm_mtl_send_callback: DBG 1008: "
579 				"Completed Sending Request MADW:%p.\n", madw_p);
580 		}
581 	}
582 
583 	OSM_LOG_EXIT(p_log);
584 }
585 
586 /**********************************************************************
587  * BINDs a callback (rcv and send error) for a given class and method
588  * defined by the given:  osm_bind_info_t
589  **********************************************************************/
590 osm_bind_handle_t
591 osm_vendor_bind(IN osm_vendor_t * const p_vend,
592 		IN osm_bind_info_t * const p_user_bind,
593 		IN osm_mad_pool_t * const p_mad_pool,
594 		IN osm_vend_mad_recv_callback_t mad_recv_callback,
595 		IN osm_vend_mad_send_err_callback_t send_err_callback,
596 		IN void *context)
597 {
598 	ib_net64_t port_guid;
599 	osm_mtl_bind_info_t *p_bind = NULL;
600 	VAPI_hca_hndl_t hca_hndl;
601 	VAPI_hca_id_t hca_id;
602 	IB_MGT_mad_type_t mad_type;
603 	uint32_t port_num;
604 	osm_vendor_mgt_bind_t *ib_mgt_hdl_p;
605 	IB_MGT_ret_t mgt_ret;
606 
607 	OSM_LOG_ENTER(p_vend->p_log);
608 
609 	CL_ASSERT(p_user_bind);
610 	CL_ASSERT(p_mad_pool);
611 	CL_ASSERT(mad_recv_callback);
612 	CL_ASSERT(send_err_callback);
613 
614 	/* cast back the AL handle to vendor mgt bind */
615 	ib_mgt_hdl_p = (osm_vendor_mgt_bind_t *) p_vend->h_al;
616 
617 	port_guid = p_user_bind->port_guid;
618 
619 	osm_log(p_vend->p_log, OSM_LOG_INFO,
620 		"osm_vendor_bind: "
621 		"Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid));
622 
623 	/* obtain the hca name and port num from the guid */
624 	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
625 		"osm_vendor_bind: "
626 		"Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
627 		port_guid);
628 
629 	mgt_ret =
630 	    osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl,
631 					    &hca_id, &port_num);
632 	if (mgt_ret != IB_MGT_OK) {
633 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
634 			"osm_vendor_bind: ERR 3C14: "
635 			"Unable to obtain CA and port (%d).\n");
636 		goto Exit;
637 	}
638 
639 	/* create the bind object tracking this binding */
640 	p_bind = (osm_mtl_bind_info_t *) malloc(sizeof(osm_mtl_bind_info_t));
641 	memset(p_bind, 0, sizeof(osm_mtl_bind_info_t));
642 	if (p_bind == NULL) {
643 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
644 			"osm_vendor_bind: ERR 3C15: "
645 			"Unable to allocate internal bind object.\n");
646 		goto Exit;
647 	}
648 
649 	/* track this bind request info */
650 	memcpy(p_bind->hca_id, hca_id, sizeof(VAPI_hca_id_t));
651 	p_bind->port_num = port_num;
652 	p_bind->p_vend = p_vend;
653 	p_bind->client_context = context;
654 	p_bind->rcv_callback = mad_recv_callback;
655 	p_bind->send_err_callback = send_err_callback;
656 	p_bind->p_osm_pool = p_mad_pool;
657 
658 	CL_ASSERT(p_bind->port_num);
659 
660 	/*
661 	 * Get the proper CLASS
662 	 */
663 
664 	switch (p_user_bind->mad_class) {
665 	case IB_MCLASS_SUBN_LID:
666 	case IB_MCLASS_SUBN_DIR:
667 		mad_type = IB_MGT_SMI;
668 		break;
669 
670 	case IB_MCLASS_SUBN_ADM:
671 	default:
672 		mad_type = IB_MGT_GSI;
673 		break;
674 	}
675 
676 	/* we split here - based on the type of MADS GSI / SMI */
677 	/* HACK: we only support one class registration per SMI/GSI !!! */
678 	if (mad_type == IB_MGT_SMI) {
679 		/*
680 		 *  SMI CASE
681 		 */
682 
683 		/* we do not need to bind the handle if already available */
684 		if (ib_mgt_hdl_p->smi_init == FALSE) {
685 
686 			/* First we have to reg and get the handle for the mad */
687 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
688 				"osm_vendor_bind: "
689 				"Binding to IB_MGT SMI of %s port %u\n", hca_id,
690 				port_num);
691 
692 			mgt_ret =
693 			    IB_MGT_get_handle(hca_id, port_num, IB_MGT_SMI,
694 					      &(ib_mgt_hdl_p->smi_mads_hdl));
695 			if (IB_MGT_OK != mgt_ret) {
696 				free(p_bind);
697 				p_bind = NULL;
698 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
699 					"osm_vendor_bind: ERR 3C16: "
700 					"Error obtaining IB_MGT handle to SMI.\n");
701 				goto Exit;
702 			}
703 
704 			/* bind it */
705 			mgt_ret = IB_MGT_bind_sm(ib_mgt_hdl_p->smi_mads_hdl);
706 			if (IB_MGT_OK != mgt_ret) {
707 				free(p_bind);
708 				p_bind = NULL;
709 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
710 					"osm_vendor_bind: ERR 3C17: "
711 					"Error binding IB_MGT handle to SM.\n");
712 				goto Exit;
713 			}
714 
715 			ib_mgt_hdl_p->smi_init = TRUE;
716 
717 		}
718 
719 		/* attach to this bind info */
720 		p_bind->mad_hndl = ib_mgt_hdl_p->smi_mads_hdl;
721 		ib_mgt_hdl_p->smi_p_bind = p_bind;
722 
723 		/* now register the callback */
724 		mgt_ret = IB_MGT_reg_cb(p_bind->mad_hndl,
725 					&__osm_mtl_rcv_callback,
726 					p_bind,
727 					&__osm_mtl_send_callback,
728 					p_bind,
729 					IB_MGT_RCV_CB_MASK |
730 					IB_MGT_SEND_CB_MASK);
731 
732 	} else {
733 		/*
734 		 *  GSI CASE
735 		 */
736 
737 		if (ib_mgt_hdl_p->gsi_init == FALSE) {
738 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
739 				"osm_vendor_bind: " "Binding to IB_MGT GSI\n");
740 
741 			/* First we have to reg and get the handle for the mad */
742 			mgt_ret =
743 			    IB_MGT_get_handle(hca_id, port_num, IB_MGT_GSI,
744 					      &(ib_mgt_hdl_p->gsi_mads_hdl));
745 			if (IB_MGT_OK != mgt_ret) {
746 				free(p_bind);
747 				p_bind = NULL;
748 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
749 					"osm_vendor_bind: ERR 3C20: "
750 					"Error obtaining IB_MGT handle to GSI.\n");
751 				goto Exit;
752 			}
753 
754 			/* bind it */
755 			mgt_ret =
756 			    IB_MGT_bind_gsi_class(ib_mgt_hdl_p->gsi_mads_hdl,
757 						  p_user_bind->mad_class);
758 			if (IB_MGT_OK != mgt_ret) {
759 				free(p_bind);
760 				p_bind = NULL;
761 				osm_log(p_vend->p_log, OSM_LOG_ERROR,
762 					"osm_vendor_bind: ERR 3C22: "
763 					"Error binding IB_MGT handle to GSI.\n");
764 				goto Exit;
765 			}
766 
767 			ib_mgt_hdl_p->gsi_init = TRUE;
768 
769 			/* attach to this bind info */
770 			p_bind->mad_hndl = ib_mgt_hdl_p->gsi_mads_hdl;
771 
772 			/* now register the callback */
773 			mgt_ret = IB_MGT_reg_cb(p_bind->mad_hndl,
774 						&__osm_mtl_rcv_callback,
775 						p_bind,
776 						&__osm_mtl_send_callback,
777 						p_bind,
778 						IB_MGT_RCV_CB_MASK |
779 						IB_MGT_SEND_CB_MASK);
780 
781 		} else {
782 			/* we can use the existing handle */
783 			p_bind->mad_hndl = ib_mgt_hdl_p->gsi_mads_hdl;
784 			mgt_ret = IB_MGT_OK;
785 		}
786 
787 	}
788 
789 	if (IB_MGT_OK != mgt_ret) {
790 		free(p_bind);
791 		p_bind = NULL;
792 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
793 			"osm_vendor_bind: ERR 3C23: "
794 			"Error binding IB_MGT CB (%d).\n", mgt_ret);
795 		goto Exit;
796 	}
797 
798 	/* HACK: Do we need to initialize an address vector ???? */
799 
800 Exit:
801 	OSM_LOG_EXIT(p_vend->p_log);
802 	return ((osm_bind_handle_t) p_bind);
803 }
804 
805 /**********************************************************************
806 Get a mad from the lower level.
807 The osm_vend_wrap_t is a wrapper used to connect the mad to the response.
808 **********************************************************************/
809 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
810 			 IN const uint32_t mad_size,
811 			 IN osm_vend_wrap_t * const p_vw)
812 {
813 	ib_mad_t *mad_p;
814 	osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind;
815 	osm_vendor_t *p_vend = p_bind->p_vend;
816 
817 	OSM_LOG_ENTER(p_vend->p_log);
818 
819 	CL_ASSERT(p_vw);
820 	/* HACK: We know we can not send through IB_MGT */
821 	CL_ASSERT(mad_size <= MAD_BLOCK_SIZE);
822 
823 	/* IB_MGT assumes it is 256 - we must follow */
824 	p_vw->size = MAD_BLOCK_SIZE;
825 
826 	/* allocate it */
827 	mad_p = (ib_mad_t *) malloc(p_vw->size);
828 	if (mad_p == NULL) {
829 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
830 			"osm_vendor_get: ERR 3C24: "
831 			"Error Obtaining MAD buffer.\n");
832 		goto Exit;
833 	}
834 
835 	memset(mad_p, 0, p_vw->size);
836 
837 	/* track locally */
838 	p_vw->mad_buf_p = mad_p;
839 	p_vw->h_bind = h_bind;
840 	p_vw->p_resp_madw = NULL;
841 
842 	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
843 		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
844 			"osm_vendor_get: "
845 			"Acquired MAD %p, size = %u.\n", mad_p, p_vw->size);
846 	}
847 
848 Exit:
849 	OSM_LOG_EXIT(p_vend->p_log);
850 	return (mad_p);
851 }
852 
853 /**********************************************************************
854  * Return a MAD by providing it's wrapper object.
855  **********************************************************************/
856 void
857 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
858 {
859 	osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind;
860 	osm_vendor_t *p_vend = p_bind->p_vend;
861 	osm_madw_t *p_madw;
862 
863 	OSM_LOG_ENTER(p_vend->p_log);
864 
865 	CL_ASSERT(p_vw);
866 	CL_ASSERT(p_vw->mad_buf_p);
867 
868 	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
869 		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
870 			"osm_vendor_put: " "Retiring MAD %p.\n",
871 			p_vw->mad_buf_p);
872 	}
873 
874 	/*
875 	 * We moved the removal of the transaction to immediatly after
876 	 * it was looked up.
877 	 */
878 
879 	/* free the mad but the wrapper is part of the madw object */
880 	free(p_vw->mad_buf_p);
881 	p_vw->mad_buf_p = NULL;
882 	p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
883 	p_madw->p_mad = NULL;
884 
885 	OSM_LOG_EXIT(p_vend->p_log);
886 }
887 
888 /**********************************************************************
889 Actually Send a MAD
890 
891 This is for internal use by osm_vendor_send and the transaction mgr
892 retry too.
893 **********************************************************************/
894 ib_api_status_t
895 osm_mtl_send_mad(IN osm_mtl_bind_info_t * p_bind, IN osm_madw_t * const p_madw)
896 {
897 	osm_vendor_t *const p_vend = p_bind->p_vend;
898 	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
899 	osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
900 	ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
901 	ib_api_status_t status;
902 	IB_MGT_ret_t mgt_res;
903 	IB_ud_av_t av;
904 	uint64_t wrid;
905 	uint32_t qpn;
906 
907 	OSM_LOG_ENTER(p_vend->p_log);
908 
909 	/*
910 	 * For all sends other than directed route SM MADs,
911 	 * acquire an address vector for the destination.
912 	 */
913 	if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
914 		__osm_mtl_conv_osm_addr_to_ibmgt_addr(p_mad_addr,
915 						      p_mad->mgmt_class ==
916 						      IB_MCLASS_SUBN_LID, &av);
917 	} else {
918 		/* is a directed route - we need to construct a permissive address */
919 		memset(&av, 0, sizeof(av));
920 		/* we do not need port number since it is part of the mad_hndl */
921 		av.dlid = IB_LID_PERMISSIVE;
922 	}
923 
924 	wrid = __osm_set_wrid_by_p_madw(p_madw);
925 
926 	/* send it */
927 	if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) ||
928 	    (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) {
929 
930 		/* SMI CASE */
931 		if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
932 			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
933 				"osm_mtl_send_mad: "
934 				"av.dlid 0x%X, "
935 				"av.static_rate %d, "
936 				"av.path_bits %d.\n",
937 				cl_ntoh16(av.dlid), av.static_rate,
938 				av.src_path_bits);
939 		}
940 
941 		mgt_res = IB_MGT_send_mad(p_bind->mad_hndl, p_mad,	/*  actual payload */
942 					  &av,	/*  address vector */
943 					  wrid,	/*  casting the mad wrapper pointer for err cb */
944 					  p_vend->timeout);
945 
946 	} else {
947 		/* GSI CASE - Support Remote QP */
948 		if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
949 			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
950 				"osm_mtl_send_mad: "
951 				"av.dlid 0x%X, av.static_rate %d, "
952 				"av.path_bits %d, remote qp: 0x%06X \n",
953 				av.dlid,
954 				av.static_rate,
955 				av.src_path_bits,
956 				cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp)
957 			    );
958 		}
959 
960 		/* IBMGT have a bug sending to a QP not 1 -
961 		   the QPN must be in network order except when it qpn 1 ... */
962 		qpn = cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp);
963 
964 		mgt_res = IB_MGT_send_mad_to_qp(p_bind->mad_hndl, p_mad,	/*  actual payload */
965 						&av,	/* address vector */
966 						wrid,	/* casting the mad wrapper pointer for err cb */
967 						p_vend->timeout, qpn);
968 	}
969 
970 	if (mgt_res != IB_MGT_OK) {
971 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
972 			"osm_mtl_send_mad: ERR 3C26: "
973 			"Error sending mad (%d).\n", mgt_res);
974 		if (p_vw->p_resp_madw)
975 			osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw);
976 		status = IB_ERROR;
977 		goto Exit;
978 	}
979 
980 	status = IB_SUCCESS;
981 
982 Exit:
983 	OSM_LOG_EXIT(p_vend->p_log);
984 	return (status);
985 }
986 
987 /**********************************************************************
988 Send a MAD through.
989 
990 What is unclear to me is the need for the setting of all the MAD Wrapper
991 fields. Seems like the OSM uses these values during it's processing...
992 **********************************************************************/
993 ib_api_status_t
994 osm_vendor_send(IN osm_bind_handle_t h_bind,
995 		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
996 {
997 	osm_mtl_bind_info_t *const p_bind = (osm_mtl_bind_info_t *) h_bind;
998 	osm_vendor_t *const p_vend = p_bind->p_vend;
999 	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
1000 	ib_api_status_t status;
1001 
1002 	OSM_LOG_ENTER(p_vend->p_log);
1003 
1004 	/*
1005 	 * If a response is expected to this MAD, then preallocate
1006 	 * a mad wrapper to contain the wire MAD received in the
1007 	 * response.  Allocating a wrapper here allows for easier
1008 	 * failure paths than after we already received the wire mad.
1009 	 */
1010 	if (resp_expected == TRUE) {
1011 		/* we track it in the vendor wrapper */
1012 		p_vw->p_resp_madw =
1013 		    osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool);
1014 		if (p_vw->p_resp_madw == NULL) {
1015 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
1016 				"osm_vendor_send: ERR 3C27: "
1017 				"Unable to allocate MAD wrapper.\n");
1018 			status = IB_INSUFFICIENT_RESOURCES;
1019 			goto Exit;
1020 		}
1021 
1022 		/* put some minimal info on that wrapper */
1023 		((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind;
1024 
1025 		/* we also want to track it in the TID based map */
1026 		status = osm_transaction_mgr_insert_madw((osm_bind_handle_t)
1027 							 p_bind, p_madw);
1028 		if (status != IB_SUCCESS) {
1029 			osm_log(p_vend->p_log, OSM_LOG_ERROR,
1030 				"osm_vendor_send: ERR 3C25: "
1031 				"Error inserting request madw by TID (%d).\n",
1032 				status);
1033 		}
1034 
1035 	} else
1036 		p_vw->p_resp_madw = NULL;
1037 
1038 	/* do the actual send */
1039 	status = osm_mtl_send_mad(p_bind, p_madw);
1040 
1041 Exit:
1042 	OSM_LOG_EXIT(p_vend->p_log);
1043 	return (status);
1044 }
1045 
1046 /**********************************************************************
1047  * the idea here is to change the content of the bind such that it
1048  * will hold the local address used for sending directed route by the SMA.
1049  **********************************************************************/
1050 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
1051 {
1052 	osm_vendor_t *p_vend = ((osm_mtl_bind_info_t *) h_bind)->p_vend;
1053 
1054 	OSM_LOG_ENTER(p_vend->p_log);
1055 
1056 	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1057 		"osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n");
1058 
1059 	OSM_LOG_EXIT(p_vend->p_log);
1060 
1061 	return (IB_SUCCESS);
1062 }
1063 
1064 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
1065 {
1066 	osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind;
1067 	osm_vendor_t *p_vend = p_bind->p_vend;
1068 	VAPI_ret_t status;
1069 	VAPI_hca_attr_t attr_mod;
1070 	VAPI_hca_attr_mask_t attr_mask;
1071 
1072 	OSM_LOG_ENTER(p_vend->p_log);
1073 
1074 	memset(&attr_mod, 0, sizeof(attr_mod));
1075 	memset(&attr_mask, 0, sizeof(attr_mask));
1076 
1077 	attr_mod.is_sm = is_sm_val;
1078 	attr_mask = HCA_ATTR_IS_SM;
1079 
1080 	status =
1081 	    VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
1082 				 &attr_mask);
1083 	if (status != VAPI_OK) {
1084 		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1085 			"osm_vendor_set_sm: ERR 3C28: "
1086 			"Unable set 'IS_SM' bit to:%u in port attributes (%d).\n",
1087 			is_sm_val, status);
1088 	}
1089 
1090 	OSM_LOG_EXIT(p_vend->p_log);
1091 }
1092 
1093 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
1094 {
1095 
1096 }
1097 
1098 #endif				/* OSM_VENDOR_INTF_TEST */
1099