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 	case IB_MAD_METHOD_SET:
377 	case IB_MAD_METHOD_DELETE:
378 		/* if we are closing down simply do nothing */
379 		if (osm_exit_flag)
380 			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
381 		else
382 			sa_mad_ctrl_process(p_ctrl, p_madw, is_get_request);
383 		break;
384 
385 	default:
386 		cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown);
387 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A05: "
388 			"Unsupported method = 0x%X\n", p_sa_mad->method);
389 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
390 		goto Exit;
391 	}
392 
393 Exit:
394 	OSM_LOG_EXIT(p_ctrl->p_log);
395 }
396 
397 /*
398  * PARAMETERS
399  *
400  * RETURN VALUES
401  *
402  * NOTES
403  *
404  * SEE ALSO
405  *********/
406 
407 /****f* opensm: SA/sa_mad_ctrl_send_err_callback
408  * NAME
409  * sa_mad_ctrl_send_err_callback
410  *
411  * DESCRIPTION
412  * This is the callback from the transport layer for send errors
413  * on MADs that were expecting a response.
414  *
415  * SYNOPSIS
416  */
417 static void sa_mad_ctrl_send_err_callback(IN void *context,
418 					  IN osm_madw_t * p_madw)
419 {
420 	osm_sa_mad_ctrl_t *p_ctrl = context;
421 	cl_status_t status;
422 
423 	OSM_LOG_ENTER(p_ctrl->p_log);
424 
425 	/*
426 	   We should never be here since the SA never originates a request.
427 	   Unless we generated a Report(Notice)
428 	 */
429 
430 	CL_ASSERT(p_madw);
431 
432 	OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A06: "
433 		"MAD completed in error (%s): "
434 		"%s(%s), attr_mod 0x%x, LID %u, TID 0x%" PRIx64 "\n",
435 		ib_get_err_str(p_madw->status),
436 		ib_get_sa_method_str(p_madw->p_mad->method),
437 		ib_get_sa_attr_str(p_madw->p_mad->attr_id),
438 		cl_ntoh32(p_madw->p_mad->attr_mod),
439 		cl_ntoh16(p_madw->mad_addr.dest_lid),
440 		cl_ntoh64(p_madw->p_mad->trans_id));
441 
442 	osm_dump_sa_mad_v2(p_ctrl->p_log, osm_madw_get_sa_mad_ptr(p_madw),
443 			   FILE_ID, OSM_LOG_ERROR);
444 
445 	/*
446 	   An error occurred.  No response was received to a request MAD.
447 	   Retire the original request MAD.
448 	 */
449 
450 	if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
451 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
452 			"Posting Dispatcher message %s\n",
453 			osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
454 
455 		if (p_ctrl->p_set_disp &&
456 		    (p_madw->p_mad->method == IB_MAD_METHOD_SET ||
457 		     p_madw->p_mad->method == IB_MAD_METHOD_DELETE))
458 			status = cl_disp_post(p_ctrl->h_set_disp,
459 					      osm_madw_get_err_msg(p_madw),
460 					      p_madw,
461 					      sa_mad_ctrl_disp_done_callback,
462 					      p_ctrl);
463 		else
464 			status = cl_disp_post(p_ctrl->h_disp,
465 					      osm_madw_get_err_msg(p_madw),
466 					      p_madw,
467 					      sa_mad_ctrl_disp_done_callback,
468 					      p_ctrl);
469 		if (status != CL_SUCCESS) {
470 			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A07: "
471 				"Dispatcher post message failed (%s)\n",
472 				CL_STATUS_MSG(status));
473 		}
474 	} else			/* No error message was provided, just retire the MAD. */
475 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
476 
477 	OSM_LOG_EXIT(p_ctrl->p_log);
478 }
479 
480 /*
481  * PARAMETERS
482  *
483  * RETURN VALUES
484  *
485  * NOTES
486  *
487  * SEE ALSO
488  *********/
489 
490 void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * p_ctrl)
491 {
492 	CL_ASSERT(p_ctrl);
493 	memset(p_ctrl, 0, sizeof(*p_ctrl));
494 	p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
495 	p_ctrl->h_set_disp = CL_DISP_INVALID_HANDLE;
496 }
497 
498 void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * p_ctrl)
499 {
500 	CL_ASSERT(p_ctrl);
501 	cl_disp_unregister(p_ctrl->h_disp);
502 	cl_disp_unregister(p_ctrl->h_set_disp);
503 }
504 
505 ib_api_status_t osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * p_ctrl,
506 				     IN osm_sa_t * sa,
507 				     IN osm_mad_pool_t * p_mad_pool,
508 				     IN osm_vendor_t * p_vendor,
509 				     IN osm_subn_t * p_subn,
510 				     IN osm_log_t * p_log,
511 				     IN osm_stats_t * p_stats,
512 				     IN cl_dispatcher_t * p_disp,
513 				     IN cl_dispatcher_t * p_set_disp)
514 {
515 	ib_api_status_t status = IB_SUCCESS;
516 
517 	OSM_LOG_ENTER(p_log);
518 
519 	osm_sa_mad_ctrl_construct(p_ctrl);
520 
521 	p_ctrl->sa = sa;
522 	p_ctrl->p_log = p_log;
523 	p_ctrl->p_disp = p_disp;
524 	p_ctrl->p_set_disp = p_set_disp;
525 	p_ctrl->p_mad_pool = p_mad_pool;
526 	p_ctrl->p_vendor = p_vendor;
527 	p_ctrl->p_stats = p_stats;
528 	p_ctrl->p_subn = p_subn;
529 
530 	p_ctrl->h_disp = cl_disp_register(p_disp, CL_DISP_MSGID_NONE, NULL,
531 					  p_ctrl);
532 
533 	if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
534 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A08: "
535 			"Dispatcher registration failed\n");
536 		status = IB_INSUFFICIENT_RESOURCES;
537 		goto Exit;
538 	}
539 
540 	if (p_set_disp) {
541 		p_ctrl->h_set_disp =
542 		    cl_disp_register(p_set_disp, CL_DISP_MSGID_NONE, NULL,
543 				     p_ctrl);
544 
545 		if (p_ctrl->h_set_disp == CL_DISP_INVALID_HANDLE) {
546 			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A0A: "
547 				"SA set dispatcher registration failed\n");
548 			status = IB_INSUFFICIENT_RESOURCES;
549 			goto Exit;
550 		}
551 	}
552 
553 Exit:
554 	OSM_LOG_EXIT(p_log);
555 	return status;
556 }
557 
558 ib_api_status_t osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * p_ctrl,
559 				     IN ib_net64_t port_guid)
560 {
561 	osm_bind_info_t bind_info;
562 	ib_api_status_t status = IB_SUCCESS;
563 
564 	OSM_LOG_ENTER(p_ctrl->p_log);
565 
566 	if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
567 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A09: "
568 			"Multiple binds not allowed\n");
569 		status = IB_ERROR;
570 		goto Exit;
571 	}
572 
573 	bind_info.class_version = 2;
574 	bind_info.is_responder = TRUE;
575 	bind_info.is_report_processor = FALSE;
576 	bind_info.is_trap_processor = FALSE;
577 	bind_info.mad_class = IB_MCLASS_SUBN_ADM;
578 	bind_info.port_guid = port_guid;
579 	bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE;
580 	bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE;
581 	bind_info.timeout = p_ctrl->sa->p_subn->opt.transaction_timeout;
582 	bind_info.retries = p_ctrl->sa->p_subn->opt.transaction_retries;
583 
584 	OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
585 		"Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
586 
587 	p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, &bind_info,
588 					 p_ctrl->p_mad_pool,
589 					 sa_mad_ctrl_rcv_callback,
590 					 sa_mad_ctrl_send_err_callback, p_ctrl);
591 
592 	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
593 		status = IB_ERROR;
594 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A10: "
595 			"Vendor specific bind failed (%s)\n",
596 			ib_get_err_str(status));
597 		goto Exit;
598 	}
599 
600 Exit:
601 	OSM_LOG_EXIT(p_ctrl->p_log);
602 	return status;
603 }
604 
605 ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * p_ctrl)
606 {
607 	ib_api_status_t status = IB_SUCCESS;
608 
609 	OSM_LOG_ENTER(p_ctrl->p_log);
610 
611 	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
612 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A11: "
613 			"No previous bind\n");
614 		status = IB_ERROR;
615 		goto Exit;
616 	}
617 
618 	osm_vendor_unbind(p_ctrl->h_bind);
619 Exit:
620 	OSM_LOG_EXIT(p_ctrl->p_log);
621 	return status;
622 }
623