1 /*
2  * Copyright (c) 2004-2009 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  * Copyright (c) 2009 HNR Consulting. All rights reserved.
6  *
7  * This software is available to you under a choice of one of two
8  * licenses.  You may choose to be licensed under the terms of the GNU
9  * General Public License (GPL) Version 2, available from the file
10  * COPYING in the main directory of this source tree, or the
11  * OpenIB.org BSD license below:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
21  *      - Redistributions in binary form must reproduce the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer in the documentation and/or other materials
24  *        provided with the distribution.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33  * SOFTWARE.
34  *
35  */
36 
37 /*
38  * Abstract:
39  *    Implementation of osm_sa_mad_ctrl_t.
40  * This object is part of the SA object.
41  */
42 
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif				/* HAVE_CONFIG_H */
46 
47 #include <string.h>
48 #include <complib/cl_debug.h>
49 #include <iba/ib_types.h>
50 #include <opensm/osm_file_ids.h>
51 #define FILE_ID OSM_FILE_SA_MAD_CTRL_C
52 #include <vendor/osm_vendor_api.h>
53 #include <opensm/osm_sa_mad_ctrl.h>
54 #include <opensm/osm_msgdef.h>
55 #include <opensm/osm_helper.h>
56 #include <opensm/osm_sa.h>
57 #include <opensm/osm_opensm.h>
58 
59 /****f* opensm: SA/sa_mad_ctrl_disp_done_callback
60  * NAME
61  * sa_mad_ctrl_disp_done_callback
62  *
63  * DESCRIPTION
64  * This function is the Dispatcher callback that indicates
65  * a received MAD has been processed by the recipient.
66  *
67  * SYNOPSIS
68  */
69 static void sa_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data)
70 {
71 	osm_sa_mad_ctrl_t *p_ctrl = context;
72 	osm_madw_t *p_madw = p_data;
73 
74 	OSM_LOG_ENTER(p_ctrl->p_log);
75 
76 	CL_ASSERT(p_madw);
77 	/*
78 	   Return the MAD & wrapper to the pool.
79 	 */
80 	osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
81 	OSM_LOG_EXIT(p_ctrl->p_log);
82 }
83 
84 /************/
85 
86 /****f* opensm: SA/sa_mad_ctrl_process
87  * NAME
88  * sa_mad_ctrl_process
89  *
90  * DESCRIPTION
91  * This function handles known methods for received MADs.
92  *
93  * SYNOPSIS
94  */
95 static void sa_mad_ctrl_process(IN osm_sa_mad_ctrl_t * p_ctrl,
96 				IN osm_madw_t * p_madw,
97 				IN boolean_t is_get_request)
98 {
99 	ib_sa_mad_t *p_sa_mad;
100 	cl_disp_reg_handle_t h_disp;
101 	cl_status_t status;
102 	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
103 	uint64_t last_dispatched_msg_queue_time_msec;
104 	uint32_t num_messages;
105 
106 	OSM_LOG_ENTER(p_ctrl->p_log);
107 
108 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
109 
110 	/*
111 	   If the dispatcher is showing us that it is overloaded
112 	   there is no point in placing the request in. We should instead
113 	   provide immediate response - IB_RESOURCE_BUSY
114 	   But how do we know?
115 	   The dispatcher reports back the number of outstanding messages and
116 	   the time the last message stayed in the queue.
117 	   HACK: Actually, we cannot send a mad from within the receive callback;
118 	   thus - we will just drop it.
119 	 */
120 
121 	if (!is_get_request && p_ctrl->p_set_disp) {
122 		h_disp = p_ctrl->h_set_disp;
123 		goto SKIP_QUEUE_CHECK;
124 	}
125 
126 	h_disp = p_ctrl->h_disp;
127 	cl_disp_get_queue_status(h_disp, &num_messages,
128 				 &last_dispatched_msg_queue_time_msec);
129 
130 	if (num_messages > 1 && p_ctrl->p_subn->opt.max_msg_fifo_timeout &&
131 	    last_dispatched_msg_queue_time_msec >
132 	    p_ctrl->p_subn->opt.max_msg_fifo_timeout) {
133 		OSM_LOG(p_ctrl->p_log, OSM_LOG_INFO,
134 			/*             "Responding BUSY status since the dispatcher is already" */
135 			"Dropping MAD since the dispatcher is already"
136 			" overloaded with %u messages and queue time of:"
137 			"%" PRIu64 "[msec]\n",
138 			num_messages, last_dispatched_msg_queue_time_msec);
139 
140 		/* send a busy response */
141 		/* osm_sa_send_error(p_ctrl->p_resp, p_madw, IB_RESOURCE_BUSY); */
142 
143 		/* return the request to the pool */
144 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
145 
146 		goto Exit;
147 	}
148 
149 SKIP_QUEUE_CHECK:
150 	/*
151 	   Note that attr_id (like the rest of the MAD) is in
152 	   network byte order.
153 	 */
154 	switch (p_sa_mad->attr_id) {
155 	case IB_MAD_ATTR_CLASS_PORT_INFO:
156 		msg_id = OSM_MSG_MAD_CLASS_PORT_INFO;
157 		break;
158 
159 	case IB_MAD_ATTR_NODE_RECORD:
160 		msg_id = OSM_MSG_MAD_NODE_RECORD;
161 		break;
162 
163 	case IB_MAD_ATTR_PORTINFO_RECORD:
164 		msg_id = OSM_MSG_MAD_PORTINFO_RECORD;
165 		break;
166 
167 	case IB_MAD_ATTR_LINK_RECORD:
168 		msg_id = OSM_MSG_MAD_LINK_RECORD;
169 		break;
170 
171 	case IB_MAD_ATTR_SMINFO_RECORD:
172 		msg_id = OSM_MSG_MAD_SMINFO_RECORD;
173 		break;
174 
175 	case IB_MAD_ATTR_SERVICE_RECORD:
176 		msg_id = OSM_MSG_MAD_SERVICE_RECORD;
177 		break;
178 
179 	case IB_MAD_ATTR_PATH_RECORD:
180 		msg_id = OSM_MSG_MAD_PATH_RECORD;
181 		break;
182 
183 	case IB_MAD_ATTR_MCMEMBER_RECORD:
184 		msg_id = OSM_MSG_MAD_MCMEMBER_RECORD;
185 		break;
186 
187 	case IB_MAD_ATTR_INFORM_INFO:
188 		msg_id = OSM_MSG_MAD_INFORM_INFO;
189 		break;
190 
191 	case IB_MAD_ATTR_VLARB_RECORD:
192 		msg_id = OSM_MSG_MAD_VL_ARB_RECORD;
193 		break;
194 
195 	case IB_MAD_ATTR_SLVL_RECORD:
196 		msg_id = OSM_MSG_MAD_SLVL_TBL_RECORD;
197 		break;
198 
199 	case IB_MAD_ATTR_PKEY_TBL_RECORD:
200 		msg_id = OSM_MSG_MAD_PKEY_TBL_RECORD;
201 		break;
202 
203 	case IB_MAD_ATTR_LFT_RECORD:
204 		msg_id = OSM_MSG_MAD_LFT_RECORD;
205 		break;
206 
207 	case IB_MAD_ATTR_GUIDINFO_RECORD:
208 		msg_id = OSM_MSG_MAD_GUIDINFO_RECORD;
209 		break;
210 
211 	case IB_MAD_ATTR_INFORM_INFO_RECORD:
212 		msg_id = OSM_MSG_MAD_INFORM_INFO_RECORD;
213 		break;
214 
215 	case IB_MAD_ATTR_SWITCH_INFO_RECORD:
216 		msg_id = OSM_MSG_MAD_SWITCH_INFO_RECORD;
217 		break;
218 
219 	case IB_MAD_ATTR_MFT_RECORD:
220 		msg_id = OSM_MSG_MAD_MFT_RECORD;
221 		break;
222 
223 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
224 	case IB_MAD_ATTR_MULTIPATH_RECORD:
225 		msg_id = OSM_MSG_MAD_MULTIPATH_RECORD;
226 		break;
227 #endif
228 
229 	default:
230 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A01: "
231 			"Unsupported attribute 0x%X (%s)\n",
232 			cl_ntoh16(p_sa_mad->attr_id),
233 			ib_get_sa_attr_str(p_sa_mad->attr_id));
234 		osm_dump_sa_mad_v2(p_ctrl->p_log, p_sa_mad, FILE_ID, OSM_LOG_ERROR);
235 	}
236 
237 	if (msg_id != CL_DISP_MSGID_NONE) {
238 		/*
239 		   Post this MAD to the dispatcher for asynchronous
240 		   processing by the appropriate controller.
241 		 */
242 
243 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
244 			"Posting Dispatcher message %s\n",
245 			osm_get_disp_msg_str(msg_id));
246 
247 		status = cl_disp_post(h_disp, msg_id, p_madw,
248 				      sa_mad_ctrl_disp_done_callback, p_ctrl);
249 
250 		if (status != CL_SUCCESS) {
251 			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A02: "
252 				"Dispatcher post message failed (%s) for attribute 0x%X (%s)\n",
253 				CL_STATUS_MSG(status),
254 				cl_ntoh16(p_sa_mad->attr_id),
255 				ib_get_sa_attr_str(p_sa_mad->attr_id));
256 
257 			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
258 			goto Exit;
259 		}
260 	} else {
261 		/*
262 		   There is an unknown MAD attribute type for which there is
263 		   no recipient.  Simply retire the MAD here.
264 		 */
265 		cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown);
266 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
267 	}
268 
269 Exit:
270 	OSM_LOG_EXIT(p_ctrl->p_log);
271 }
272 
273 /*
274  * PARAMETERS
275  *
276  * RETURN VALUES
277  *
278  * NOTES
279  *
280  * SEE ALSO
281  *********/
282 
283 /****f* opensm: SA/sa_mad_ctrl_rcv_callback
284  * NAME
285  * sa_mad_ctrl_rcv_callback
286  *
287  * DESCRIPTION
288  * This is the callback from the transport layer for received MADs.
289  *
290  * SYNOPSIS
291  */
292 static void sa_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw, IN void *context,
293 				     IN osm_madw_t * p_req_madw)
294 {
295 	osm_sa_mad_ctrl_t *p_ctrl = context;
296 	ib_sa_mad_t *p_sa_mad;
297 	boolean_t is_get_request = FALSE;
298 
299 	OSM_LOG_ENTER(p_ctrl->p_log);
300 
301 	CL_ASSERT(p_madw);
302 
303 	/*
304 	   A MAD was received from the wire, possibly in response to a request.
305 	 */
306 	cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd);
307 
308 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
309 		"%u SA MADs received\n", p_ctrl->p_stats->sa_mads_rcvd);
310 
311 	/*
312 	 * C15-0.1.3 requires not responding to any MAD if the SM is
313 	 * not in active state!
314 	 * We will not respond if the sm_state is not MASTER, or if the
315 	 * first_time_master_sweep flag (of the subnet) is TRUE - this
316 	 * flag indicates that the master still didn't finish its first
317 	 * sweep, so the subnet is not up and stable yet.
318 	 */
319 	if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) {
320 		cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored);
321 		OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
322 			"Received SA MAD while SM not MASTER. MAD ignored\n");
323 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
324 		goto Exit;
325 	}
326 	if (p_ctrl->p_subn->first_time_master_sweep == TRUE) {
327 		cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored);
328 		OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
329 			"Received SA MAD while SM in first sweep. MAD ignored\n");
330 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
331 		goto Exit;
332 	}
333 
334 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
335 
336 	if (OSM_LOG_IS_ACTIVE_V2(p_ctrl->p_log, OSM_LOG_FRAMES))
337 		osm_dump_sa_mad_v2(p_ctrl->p_log, p_sa_mad, FILE_ID, OSM_LOG_FRAMES);
338 
339 	/*
340 	 * C15-0.1.5 - Table 185: SA Header - p884
341 	 * SM_key should be either 0 or match the current SM_Key
342 	 * otherwise discard the MAD.
343 	 */
344 	if (p_sa_mad->sm_key != 0 &&
345 	    p_sa_mad->sm_key != p_ctrl->p_subn->opt.sa_key) {
346 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A04: "
347 			"Non-Zero MAD SM_Key: 0x%" PRIx64 " != SM_Key: 0x%"
348 			PRIx64 "; SA MAD ignored for method 0x%X attribute 0x%X (%s)\n",
349 			cl_ntoh64(p_sa_mad->sm_key),
350 			cl_ntoh64(p_ctrl->p_subn->opt.sa_key),
351 			p_sa_mad->method, cl_ntoh16(p_sa_mad->attr_id),
352 			ib_get_sa_attr_str(p_sa_mad->attr_id));
353 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
354 		goto Exit;
355 	}
356 
357 	switch (p_sa_mad->method) {
358 	case IB_MAD_METHOD_REPORT_RESP:
359 		/* we do not really do anything with report responses -
360 		   just retire the transaction */
361 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
362 			"Received Report Response. Retiring the transaction\n");
363 
364 		if (p_req_madw)
365 			osm_mad_pool_put(p_ctrl->p_mad_pool, p_req_madw);
366 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
367 
368 		break;
369 
370 	case IB_MAD_METHOD_GET:
371 	case IB_MAD_METHOD_GETTABLE:
372 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
373 	case IB_MAD_METHOD_GETMULTI:
374 #endif
375 		is_get_request = TRUE;
376 		/* FALLTHROUGH */
377 	case IB_MAD_METHOD_SET:
378 	case IB_MAD_METHOD_DELETE:
379 		/* if we are closing down simply do nothing */
380 		if (osm_exit_flag)
381 			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
382 		else
383 			sa_mad_ctrl_process(p_ctrl, p_madw, is_get_request);
384 		break;
385 
386 	default:
387 		cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown);
388 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A05: "
389 			"Unsupported method = 0x%X\n", p_sa_mad->method);
390 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
391 		goto Exit;
392 	}
393 
394 Exit:
395 	OSM_LOG_EXIT(p_ctrl->p_log);
396 }
397 
398 /*
399  * PARAMETERS
400  *
401  * RETURN VALUES
402  *
403  * NOTES
404  *
405  * SEE ALSO
406  *********/
407 
408 /****f* opensm: SA/sa_mad_ctrl_send_err_callback
409  * NAME
410  * sa_mad_ctrl_send_err_callback
411  *
412  * DESCRIPTION
413  * This is the callback from the transport layer for send errors
414  * on MADs that were expecting a response.
415  *
416  * SYNOPSIS
417  */
418 static void sa_mad_ctrl_send_err_callback(IN void *context,
419 					  IN osm_madw_t * p_madw)
420 {
421 	osm_sa_mad_ctrl_t *p_ctrl = context;
422 	cl_status_t status;
423 
424 	OSM_LOG_ENTER(p_ctrl->p_log);
425 
426 	/*
427 	   We should never be here since the SA never originates a request.
428 	   Unless we generated a Report(Notice)
429 	 */
430 
431 	CL_ASSERT(p_madw);
432 
433 	OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A06: "
434 		"MAD completed in error (%s): "
435 		"%s(%s), attr_mod 0x%x, LID %u, TID 0x%" PRIx64 "\n",
436 		ib_get_err_str(p_madw->status),
437 		ib_get_sa_method_str(p_madw->p_mad->method),
438 		ib_get_sa_attr_str(p_madw->p_mad->attr_id),
439 		cl_ntoh32(p_madw->p_mad->attr_mod),
440 		cl_ntoh16(p_madw->mad_addr.dest_lid),
441 		cl_ntoh64(p_madw->p_mad->trans_id));
442 
443 	osm_dump_sa_mad_v2(p_ctrl->p_log, osm_madw_get_sa_mad_ptr(p_madw),
444 			   FILE_ID, OSM_LOG_ERROR);
445 
446 	/*
447 	   An error occurred.  No response was received to a request MAD.
448 	   Retire the original request MAD.
449 	 */
450 
451 	if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
452 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
453 			"Posting Dispatcher message %s\n",
454 			osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
455 
456 		if (p_ctrl->p_set_disp &&
457 		    (p_madw->p_mad->method == IB_MAD_METHOD_SET ||
458 		     p_madw->p_mad->method == IB_MAD_METHOD_DELETE))
459 			status = cl_disp_post(p_ctrl->h_set_disp,
460 					      osm_madw_get_err_msg(p_madw),
461 					      p_madw,
462 					      sa_mad_ctrl_disp_done_callback,
463 					      p_ctrl);
464 		else
465 			status = cl_disp_post(p_ctrl->h_disp,
466 					      osm_madw_get_err_msg(p_madw),
467 					      p_madw,
468 					      sa_mad_ctrl_disp_done_callback,
469 					      p_ctrl);
470 		if (status != CL_SUCCESS) {
471 			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A07: "
472 				"Dispatcher post message failed (%s)\n",
473 				CL_STATUS_MSG(status));
474 		}
475 	} else			/* No error message was provided, just retire the MAD. */
476 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
477 
478 	OSM_LOG_EXIT(p_ctrl->p_log);
479 }
480 
481 /*
482  * PARAMETERS
483  *
484  * RETURN VALUES
485  *
486  * NOTES
487  *
488  * SEE ALSO
489  *********/
490 
491 void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * p_ctrl)
492 {
493 	CL_ASSERT(p_ctrl);
494 	memset(p_ctrl, 0, sizeof(*p_ctrl));
495 	p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
496 	p_ctrl->h_set_disp = CL_DISP_INVALID_HANDLE;
497 }
498 
499 void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * p_ctrl)
500 {
501 	CL_ASSERT(p_ctrl);
502 	cl_disp_unregister(p_ctrl->h_disp);
503 	cl_disp_unregister(p_ctrl->h_set_disp);
504 }
505 
506 ib_api_status_t osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * p_ctrl,
507 				     IN osm_sa_t * sa,
508 				     IN osm_mad_pool_t * p_mad_pool,
509 				     IN osm_vendor_t * p_vendor,
510 				     IN osm_subn_t * p_subn,
511 				     IN osm_log_t * p_log,
512 				     IN osm_stats_t * p_stats,
513 				     IN cl_dispatcher_t * p_disp,
514 				     IN cl_dispatcher_t * p_set_disp)
515 {
516 	ib_api_status_t status = IB_SUCCESS;
517 
518 	OSM_LOG_ENTER(p_log);
519 
520 	osm_sa_mad_ctrl_construct(p_ctrl);
521 
522 	p_ctrl->sa = sa;
523 	p_ctrl->p_log = p_log;
524 	p_ctrl->p_disp = p_disp;
525 	p_ctrl->p_set_disp = p_set_disp;
526 	p_ctrl->p_mad_pool = p_mad_pool;
527 	p_ctrl->p_vendor = p_vendor;
528 	p_ctrl->p_stats = p_stats;
529 	p_ctrl->p_subn = p_subn;
530 
531 	p_ctrl->h_disp = cl_disp_register(p_disp, CL_DISP_MSGID_NONE, NULL,
532 					  p_ctrl);
533 
534 	if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
535 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A08: "
536 			"Dispatcher registration failed\n");
537 		status = IB_INSUFFICIENT_RESOURCES;
538 		goto Exit;
539 	}
540 
541 	if (p_set_disp) {
542 		p_ctrl->h_set_disp =
543 		    cl_disp_register(p_set_disp, CL_DISP_MSGID_NONE, NULL,
544 				     p_ctrl);
545 
546 		if (p_ctrl->h_set_disp == CL_DISP_INVALID_HANDLE) {
547 			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A0A: "
548 				"SA set dispatcher registration failed\n");
549 			status = IB_INSUFFICIENT_RESOURCES;
550 			goto Exit;
551 		}
552 	}
553 
554 Exit:
555 	OSM_LOG_EXIT(p_log);
556 	return status;
557 }
558 
559 ib_api_status_t osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * p_ctrl,
560 				     IN ib_net64_t port_guid)
561 {
562 	osm_bind_info_t bind_info;
563 	ib_api_status_t status = IB_SUCCESS;
564 
565 	OSM_LOG_ENTER(p_ctrl->p_log);
566 
567 	if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
568 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A09: "
569 			"Multiple binds not allowed\n");
570 		status = IB_ERROR;
571 		goto Exit;
572 	}
573 
574 	bind_info.class_version = 2;
575 	bind_info.is_responder = TRUE;
576 	bind_info.is_report_processor = FALSE;
577 	bind_info.is_trap_processor = FALSE;
578 	bind_info.mad_class = IB_MCLASS_SUBN_ADM;
579 	bind_info.port_guid = port_guid;
580 	bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE;
581 	bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE;
582 	bind_info.timeout = p_ctrl->sa->p_subn->opt.transaction_timeout;
583 	bind_info.retries = p_ctrl->sa->p_subn->opt.transaction_retries;
584 
585 	OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
586 		"Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
587 
588 	p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, &bind_info,
589 					 p_ctrl->p_mad_pool,
590 					 sa_mad_ctrl_rcv_callback,
591 					 sa_mad_ctrl_send_err_callback, p_ctrl);
592 
593 	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
594 		status = IB_ERROR;
595 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A10: "
596 			"Vendor specific bind failed (%s)\n",
597 			ib_get_err_str(status));
598 		goto Exit;
599 	}
600 
601 Exit:
602 	OSM_LOG_EXIT(p_ctrl->p_log);
603 	return status;
604 }
605 
606 ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * p_ctrl)
607 {
608 	ib_api_status_t status = IB_SUCCESS;
609 
610 	OSM_LOG_ENTER(p_ctrl->p_log);
611 
612 	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
613 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A11: "
614 			"No previous bind\n");
615 		status = IB_ERROR;
616 		goto Exit;
617 	}
618 
619 	osm_vendor_unbind(p_ctrl->h_bind);
620 Exit:
621 	OSM_LOG_EXIT(p_ctrl->p_log);
622 	return status;
623 }
624