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