xref: /freebsd/contrib/ofed/opensm/opensm/osm_sm_mad_ctrl.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2011 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  * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  */
37 
38 /*
39  * Abstract:
40  *    Implementation of osm_sm_mad_ctrl_t.
41  * This object represents the SM MAD request controller object.
42  * This object is part of the opensm family of objects.
43  */
44 
45 #if HAVE_CONFIG_H
46 #  include <config.h>
47 #endif				/* HAVE_CONFIG_H */
48 
49 #include <string.h>
50 #include <complib/cl_debug.h>
51 #include <iba/ib_types.h>
52 #include <opensm/osm_file_ids.h>
53 #define FILE_ID OSM_FILE_SM_MAD_CTRL_C
54 #include <opensm/osm_sm_mad_ctrl.h>
55 #include <vendor/osm_vendor_api.h>
56 #include <opensm/osm_madw.h>
57 #include <opensm/osm_msgdef.h>
58 #include <opensm/osm_helper.h>
59 #include <opensm/osm_opensm.h>
60 
61 /****f* opensm: SM/sm_mad_ctrl_retire_trans_mad
62  * NAME
63  * sm_mad_ctrl_retire_trans_mad
64  *
65  * DESCRIPTION
66  * This function handles clean-up of MADs associated with the SM's
67  * outstanding transactions on the wire.
68  *
69  * SYNOPSIS
70  */
71 
sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw)72 static void sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * p_ctrl,
73 					 IN osm_madw_t * p_madw)
74 {
75 	uint32_t outstanding;
76 
77 	OSM_LOG_ENTER(p_ctrl->p_log);
78 
79 	CL_ASSERT(p_madw);
80 	/*
81 	   Return the MAD & wrapper to the pool.
82 	 */
83 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
84 		"Retiring MAD with TID 0x%" PRIx64 "\n",
85 		cl_ntoh64(osm_madw_get_smp_ptr(p_madw)->trans_id));
86 
87 	osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
88 
89 	outstanding = osm_stats_dec_qp0_outstanding(p_ctrl->p_stats);
90 
91 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding%s\n",
92 		p_ctrl->p_stats->qp0_mads_outstanding,
93 		outstanding ? "" : ": wire is clean.");
94 
95 	OSM_LOG_EXIT(p_ctrl->p_log);
96 }
97 
98 /************/
99 
100 /****f* opensm: SM/sm_mad_ctrl_disp_done_callback
101  * NAME
102  * sm_mad_ctrl_disp_done_callback
103  *
104  * DESCRIPTION
105  * This function is the Dispatcher callback that indicates
106  * a received MAD has been processed by the recipient.
107  *
108  * SYNOPSIS
109  */
sm_mad_ctrl_disp_done_callback(IN void * context,IN void * p_data)110 static void sm_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data)
111 {
112 	osm_sm_mad_ctrl_t *p_ctrl = context;
113 	osm_madw_t *p_madw = p_data;
114 	ib_smp_t *p_smp;
115 
116 	OSM_LOG_ENTER(p_ctrl->p_log);
117 
118 	/*
119 	   If the MAD that just finished processing was a response,
120 	   then retire the transaction, since we must have generated
121 	   the request.
122 
123 	   Otherwise, retire the transaction if a response was expected,
124 	   as in the case of a send failure. If a response was not expected,
125 	   just put the MAD back in the pool, because the MAD was a query
126 	   from some outside agent, e.g. Get(SMInfo) from another SM.
127 	 */
128 	p_smp = osm_madw_get_smp_ptr(p_madw);
129 	if (ib_smp_is_response(p_smp)) {
130 		CL_ASSERT(p_madw->resp_expected == FALSE);
131 		sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
132 	} else if (p_madw->resp_expected == TRUE)
133 		sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
134 	else
135 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
136 
137 	OSM_LOG_EXIT(p_ctrl->p_log);
138 }
139 
140 /************/
141 
142 /****f* opensm: SM/sm_mad_ctrl_update_wire_stats
143  * NAME
144  * sm_mad_ctrl_update_wire_stats
145  *
146  * DESCRIPTION
147  * Updates wire stats for outstanding MADs and calls the VL15 poller.
148  *
149  * SYNOPSIS
150  */
sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * p_ctrl)151 static void sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * p_ctrl)
152 {
153 	uint32_t mads_on_wire;
154 
155 	OSM_LOG_ENTER(p_ctrl->p_log);
156 
157 	mads_on_wire =
158 	    cl_atomic_dec(&p_ctrl->p_stats->qp0_mads_outstanding_on_wire);
159 
160 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
161 		"%u SMPs on the wire, %u outstanding\n", mads_on_wire,
162 		p_ctrl->p_stats->qp0_mads_outstanding);
163 
164 	/*
165 	   We can signal the VL15 controller to send another MAD
166 	   if any are waiting for transmission.
167 	 */
168 	osm_vl15_poll(p_ctrl->p_vl15);
169 	OSM_LOG_EXIT(p_ctrl->p_log);
170 }
171 
172 /****f* opensm: SM/sm_mad_ctrl_process_get_resp
173  * NAME
174  * sm_mad_ctrl_process_get_resp
175  *
176  * DESCRIPTION
177  * This function handles method GetResp() for received MADs.
178  * This is the most common path for QP0 MADs.
179  *
180  * SYNOPSIS
181  */
sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw,IN void * transaction_context)182 static void sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * p_ctrl,
183 					 IN osm_madw_t * p_madw,
184 					 IN void *transaction_context)
185 {
186 	ib_smp_t *p_smp;
187 	cl_status_t status;
188 	osm_madw_t *p_old_madw;
189 	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
190 
191 	OSM_LOG_ENTER(p_ctrl->p_log);
192 
193 	CL_ASSERT(p_madw);
194 	CL_ASSERT(transaction_context);
195 
196 	p_smp = osm_madw_get_smp_ptr(p_madw);
197 
198 	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR && !ib_smp_is_d(p_smp)) {
199 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3102: "
200 			"'D' bit not set in returned SMP\n");
201 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
202 	}
203 
204 	p_old_madw = transaction_context;
205 
206 	sm_mad_ctrl_update_wire_stats(p_ctrl);
207 
208 	/*
209 	   Copy the MAD Wrapper context from the requesting MAD
210 	   to the new MAD.  This mechanism allows the recipient
211 	   controller to recover its own context regarding this
212 	   MAD transaction.  Once we've copied the context, we
213 	   can return the original MAD to the pool.
214 	 */
215 	osm_madw_copy_context(p_madw, p_old_madw);
216 	osm_mad_pool_put(p_ctrl->p_mad_pool, p_old_madw);
217 
218 	/*
219 	   Note that attr_id (like the rest of the MAD) is in
220 	   network byte order.
221 	 */
222 	switch (p_smp->attr_id) {
223 	case IB_MAD_ATTR_NODE_DESC:
224 		msg_id = OSM_MSG_MAD_NODE_DESC;
225 		break;
226 	case IB_MAD_ATTR_NODE_INFO:
227 		msg_id = OSM_MSG_MAD_NODE_INFO;
228 		break;
229 	case IB_MAD_ATTR_GUID_INFO:
230 		msg_id = OSM_MSG_MAD_GUID_INFO;
231 		break;
232 	case IB_MAD_ATTR_SWITCH_INFO:
233 		msg_id = OSM_MSG_MAD_SWITCH_INFO;
234 		break;
235 	case IB_MAD_ATTR_PORT_INFO:
236 		msg_id = OSM_MSG_MAD_PORT_INFO;
237 		break;
238 	case IB_MAD_ATTR_LIN_FWD_TBL:
239 		msg_id = OSM_MSG_MAD_LFT;
240 		break;
241 	case IB_MAD_ATTR_MCAST_FWD_TBL:
242 		msg_id = OSM_MSG_MAD_MFT;
243 		break;
244 	case IB_MAD_ATTR_SM_INFO:
245 		msg_id = OSM_MSG_MAD_SM_INFO;
246 		break;
247 	case IB_MAD_ATTR_SLVL_TABLE:
248 		msg_id = OSM_MSG_MAD_SLVL;
249 		break;
250 	case IB_MAD_ATTR_VL_ARBITRATION:
251 		msg_id = OSM_MSG_MAD_VL_ARB;
252 		break;
253 	case IB_MAD_ATTR_P_KEY_TABLE:
254 		msg_id = OSM_MSG_MAD_PKEY;
255 		break;
256 	case IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO:
257 		msg_id = OSM_MSG_MAD_MLNX_EXT_PORT_INFO;
258 		break;
259 	case IB_MAD_ATTR_CLASS_PORT_INFO:
260 	case IB_MAD_ATTR_NOTICE:
261 	case IB_MAD_ATTR_INFORM_INFO:
262 	default:
263 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
264 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3103: "
265 			"Unsupported attribute 0x%X (%s)\n",
266 			cl_ntoh16(p_smp->attr_id),
267 			ib_get_sm_attr_str(p_smp->attr_id));
268 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
269 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
270 		goto Exit;
271 	}
272 
273 	/*
274 	   Post this MAD to the dispatcher for asynchronous
275 	   processing by the appropriate controller.
276 	 */
277 
278 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
279 		osm_get_disp_msg_str(msg_id));
280 
281 	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
282 			      sm_mad_ctrl_disp_done_callback, p_ctrl);
283 
284 	if (status != CL_SUCCESS) {
285 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3104: "
286 			"Dispatcher post message failed (%s) for attribute 0x%X (%s)\n",
287 			CL_STATUS_MSG(status), cl_ntoh16(p_smp->attr_id),
288 			ib_get_sm_attr_str(p_smp->attr_id));
289 		goto Exit;
290 	}
291 
292 Exit:
293 	OSM_LOG_EXIT(p_ctrl->p_log);
294 }
295 
296 /****f* opensm: SM/sm_mad_ctrl_process_get
297  * NAME
298  * sm_mad_ctrl_process_get
299  *
300  * DESCRIPTION
301  * This function handles method Get() for received MADs.
302  *
303  * SYNOPSIS
304  */
sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw)305 static void sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * p_ctrl,
306 				    IN osm_madw_t * p_madw)
307 {
308 	ib_smp_t *p_smp;
309 	cl_status_t status;
310 	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
311 
312 	OSM_LOG_ENTER(p_ctrl->p_log);
313 
314 	p_smp = osm_madw_get_smp_ptr(p_madw);
315 
316 	/*
317 	   Note that attr_id (like the rest of the MAD) is in
318 	   network byte order.
319 	 */
320 	switch (p_smp->attr_id) {
321 	case IB_MAD_ATTR_SM_INFO:
322 		msg_id = OSM_MSG_MAD_SM_INFO;
323 		break;
324 	default:
325 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
326 		OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
327 			"Ignoring SubnGet MAD - unsupported attribute 0x%X\n",
328 			cl_ntoh16(p_smp->attr_id));
329 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
330 		goto Exit;
331 	}
332 
333 	/*
334 	   Post this MAD to the dispatcher for asynchronous
335 	   processing by the appropriate controller.
336 	 */
337 
338 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
339 		osm_get_disp_msg_str(msg_id));
340 
341 	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
342 			      sm_mad_ctrl_disp_done_callback, p_ctrl);
343 
344 	if (status != CL_SUCCESS) {
345 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3106: "
346 			"Dispatcher post message failed (%s)\n",
347 			CL_STATUS_MSG(status));
348 		goto Exit;
349 	}
350 
351 Exit:
352 	OSM_LOG_EXIT(p_ctrl->p_log);
353 }
354 
355 /*
356  * PARAMETERS
357  *
358  * RETURN VALUES
359  *
360  * NOTES
361  *
362  * SEE ALSO
363  *********/
364 
365 /****f* opensm: SM/sm_mad_ctrl_process_set
366  * NAME
367  * sm_mad_ctrl_process_set
368  *
369  * DESCRIPTION
370  * This function handles method Set() for received MADs.
371  *
372  * SYNOPSIS
373  */
sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw)374 static void sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * p_ctrl,
375 				    IN osm_madw_t * p_madw)
376 {
377 	ib_smp_t *p_smp;
378 	cl_status_t status;
379 	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
380 
381 	OSM_LOG_ENTER(p_ctrl->p_log);
382 
383 	p_smp = osm_madw_get_smp_ptr(p_madw);
384 
385 	/*
386 	   Note that attr_id (like the rest of the MAD) is in
387 	   network byte order.
388 	 */
389 	switch (p_smp->attr_id) {
390 	case IB_MAD_ATTR_SM_INFO:
391 		msg_id = OSM_MSG_MAD_SM_INFO;
392 		break;
393 	default:
394 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
395 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3107: "
396 			"Unsupported attribute 0x%X (%s)\n",
397 			cl_ntoh16(p_smp->attr_id),
398 			ib_get_sm_attr_str(p_smp->attr_id));
399 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
400 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
401 		goto Exit;
402 	}
403 
404 	/*
405 	   Post this MAD to the dispatcher for asynchronous
406 	   processing by the appropriate controller.
407 	 */
408 
409 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
410 		osm_get_disp_msg_str(msg_id));
411 
412 	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
413 			      sm_mad_ctrl_disp_done_callback, p_ctrl);
414 
415 	if (status != CL_SUCCESS) {
416 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3108: "
417 			"Dispatcher post message failed (%s)\n",
418 			CL_STATUS_MSG(status));
419 		goto Exit;
420 	}
421 
422 Exit:
423 	OSM_LOG_EXIT(p_ctrl->p_log);
424 }
425 
426 /*
427  * PARAMETERS
428  *
429  * RETURN VALUES
430  *
431  * NOTES
432  *
433  * SEE ALSO
434  *********/
435 
436 /****f* opensm: SM/sm_mad_ctrl_process_trap
437  * NAME
438  * sm_mad_ctrl_process_trap
439  *
440  * DESCRIPTION
441  * This function handles method Trap() for received MADs.
442  *
443  * SYNOPSIS
444  */
sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw)445 static void sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * p_ctrl,
446 				     IN osm_madw_t * p_madw)
447 {
448 	ib_smp_t *p_smp;
449 	cl_status_t status;
450 	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
451 
452 	OSM_LOG_ENTER(p_ctrl->p_log);
453 
454 	p_smp = osm_madw_get_smp_ptr(p_madw);
455 
456 	/* Make sure OpenSM is master. If not - then we should not process the trap */
457 	if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) {
458 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
459 			"Received trap but OpenSM is not in MASTER state. "
460 			"Dropping mad\n");
461 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
462 		goto Exit;
463 	}
464 
465 	/*
466 	   Note that attr_id (like the rest of the MAD) is in
467 	   network byte order.
468 	 */
469 	switch (p_smp->attr_id) {
470 	case IB_MAD_ATTR_NOTICE:
471 		msg_id = OSM_MSG_MAD_NOTICE;
472 		break;
473 	default:
474 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
475 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3109: "
476 			"Unsupported attribute 0x%X (%s)\n",
477 			cl_ntoh16(p_smp->attr_id),
478 			ib_get_sm_attr_str(p_smp->attr_id));
479 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
480 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
481 		goto Exit;
482 	}
483 
484 	/*
485 	   Post this MAD to the dispatcher for asynchronous
486 	   processing by the appropriate controller.
487 	 */
488 
489 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
490 		osm_get_disp_msg_str(msg_id));
491 
492 	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
493 			      sm_mad_ctrl_disp_done_callback, p_ctrl);
494 
495 	if (status != CL_SUCCESS) {
496 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3110: "
497 			"Dispatcher post message failed (%s)\n",
498 			CL_STATUS_MSG(status));
499 		goto Exit;
500 	}
501 
502 Exit:
503 	OSM_LOG_EXIT(p_ctrl->p_log);
504 }
505 
506 /*
507  * PARAMETERS
508  *
509  * RETURN VALUES
510  *
511  * NOTES
512  *
513  * SEE ALSO
514  *********/
515 
516 /****f* opensm: SM/sm_mad_ctrl_process_trap_repress
517  * NAME
518  * sm_mad_ctrl_process_trap_repress
519  *
520  * DESCRIPTION
521  * This function handles method TrapRepress() for received MADs.
522  *
523  * SYNOPSIS
524  */
sm_mad_ctrl_process_trap_repress(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_madw_t * p_madw)525 static void sm_mad_ctrl_process_trap_repress(IN osm_sm_mad_ctrl_t * p_ctrl,
526 					     IN osm_madw_t * p_madw)
527 {
528 	ib_smp_t *p_smp;
529 
530 	OSM_LOG_ENTER(p_ctrl->p_log);
531 
532 	p_smp = osm_madw_get_smp_ptr(p_madw);
533 
534 	/*
535 	   Note that attr_id (like the rest of the MAD) is in
536 	   network byte order.
537 	 */
538 	switch (p_smp->attr_id) {
539 	case IB_MAD_ATTR_NOTICE:
540 		sm_mad_ctrl_update_wire_stats(p_ctrl);
541 		sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
542 		break;
543 	default:
544 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
545 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3105: "
546 			"Unsupported attribute 0x%X (%s)\n",
547 			cl_ntoh16(p_smp->attr_id),
548 			ib_get_sm_attr_str(p_smp->attr_id));
549 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
550 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
551 		break;
552 	}
553 
554 	OSM_LOG_EXIT(p_ctrl->p_log);
555 }
556 
log_rcv_cb_error(osm_log_t * p_log,ib_smp_t * p_smp,ib_net16_t status)557 static void log_rcv_cb_error(osm_log_t *p_log, ib_smp_t *p_smp, ib_net16_t status)
558 {
559 	char buf[BUF_SIZE];
560 	uint32_t i;
561 
562 	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) {
563 		char ipath[BUF_SIZE], rpath[BUF_SIZE];
564 		int ni = sprintf(ipath, "%d", p_smp->initial_path[0]);
565 		int nr = sprintf(rpath, "%d", p_smp->return_path[0]);
566 		for (i = 1; i <= p_smp->hop_count; i++) {
567 			ni += sprintf(ipath + ni, ",%d", p_smp->initial_path[i]);
568 			nr += sprintf(rpath + nr, ",%d", p_smp->return_path[i]);
569 		}
570 		snprintf(buf, sizeof(buf),
571 			 "\n\t\t\tInitial path: %s Return path: %s",
572 			 ipath, rpath);
573 	}
574 
575 	OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3111: "
576 		"Received MAD with error status = 0x%X\n"
577 		"\t\t\t%s(%s), attr_mod 0x%x, TID 0x%" PRIx64 "%s\n",
578 		cl_ntoh16(status), ib_get_sm_method_str(p_smp->method),
579 		ib_get_sm_attr_str(p_smp->attr_id), cl_ntoh32(p_smp->attr_mod),
580 		cl_ntoh64(p_smp->trans_id),
581 		p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ? buf : "");
582 
583 	osm_dump_dr_smp_v2(p_log, p_smp, FILE_ID, OSM_LOG_VERBOSE);
584 }
585 
586 /*
587  * PARAMETERS
588  *
589  * RETURN VALUES
590  *
591  * NOTES
592  *
593  * SEE ALSO
594  *********/
595 
596 /****f* opensm: SM/sm_mad_ctrl_rcv_callback
597  * NAME
598  * sm_mad_ctrl_rcv_callback
599  *
600  * DESCRIPTION
601  * This is the callback from the transport layer for received MADs.
602  *
603  * SYNOPSIS
604  */
sm_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw,IN void * bind_context,IN osm_madw_t * p_req_madw)605 static void sm_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw,
606 				     IN void *bind_context,
607 				     IN osm_madw_t * p_req_madw)
608 {
609 	osm_sm_mad_ctrl_t *p_ctrl = bind_context;
610 	ib_smp_t *p_smp;
611 	ib_net16_t status;
612 
613 	OSM_LOG_ENTER(p_ctrl->p_log);
614 
615 	CL_ASSERT(p_madw);
616 
617 	/*
618 	   A MAD was received from the wire, possibly in response to a request.
619 	 */
620 	cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd);
621 
622 	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs received\n",
623 		p_ctrl->p_stats->qp0_mads_rcvd);
624 
625 	p_smp = osm_madw_get_smp_ptr(p_madw);
626 
627 	/* if we are closing down simply do nothing */
628 	if (osm_exit_flag) {
629 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR,
630 			"Ignoring received mad - since we are exiting\n");
631 
632 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_DEBUG);
633 
634 		/* retire the mad or put it back */
635 		if (ib_smp_is_response(p_smp)) {
636 			CL_ASSERT(p_madw->resp_expected == FALSE);
637 			sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
638 		} else if (p_madw->resp_expected == TRUE)
639 			sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
640 		else
641 			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
642 
643 		goto Exit;
644 	}
645 
646 	if (OSM_LOG_IS_ACTIVE_V2(p_ctrl->p_log, OSM_LOG_FRAMES))
647 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_FRAMES);
648 
649 	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
650 		status = ib_smp_get_status(p_smp);
651 	else
652 		status = p_smp->status;
653 
654 	if (status != 0)
655 		log_rcv_cb_error(p_ctrl->p_log, p_smp, status);
656 
657 	switch (p_smp->method) {
658 	case IB_MAD_METHOD_GET_RESP:
659 		CL_ASSERT(p_req_madw != NULL);
660 		sm_mad_ctrl_process_get_resp(p_ctrl, p_madw, p_req_madw);
661 		break;
662 	case IB_MAD_METHOD_GET:
663 		CL_ASSERT(p_req_madw == NULL);
664 		sm_mad_ctrl_process_get(p_ctrl, p_madw);
665 		break;
666 	case IB_MAD_METHOD_TRAP:
667 		CL_ASSERT(p_req_madw == NULL);
668 		sm_mad_ctrl_process_trap(p_ctrl, p_madw);
669 		break;
670 	case IB_MAD_METHOD_SET:
671 		CL_ASSERT(p_req_madw == NULL);
672 		sm_mad_ctrl_process_set(p_ctrl, p_madw);
673 		break;
674 	case IB_MAD_METHOD_TRAP_REPRESS:
675 		CL_ASSERT(p_req_madw != NULL);
676 		sm_mad_ctrl_process_trap_repress(p_ctrl, p_madw);
677 		break;
678 	case IB_MAD_METHOD_SEND:
679 	case IB_MAD_METHOD_REPORT:
680 	case IB_MAD_METHOD_REPORT_RESP:
681 	default:
682 		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
683 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3112: "
684 			"Unsupported method = 0x%X\n", p_smp->method);
685 		osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
686 		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
687 		goto Exit;
688 	}
689 
690 Exit:
691 	OSM_LOG_EXIT(p_ctrl->p_log);
692 }
693 
694 /*
695  * PARAMETERS
696  *
697  * RETURN VALUES
698  *
699  * NOTES
700  *
701  * SEE ALSO
702  *********/
703 
704 /****f* opensm: SM/sm_mad_ctrl_send_err_cb
705  * NAME
706  * sm_mad_ctrl_send_err_cb
707  *
708  * DESCRIPTION
709  * This is the callback from the transport layer for send errors
710  * on MADs that were expecting a response.
711  *
712  * SYNOPSIS
713  */
sm_mad_ctrl_send_err_cb(IN void * context,IN osm_madw_t * p_madw)714 static void sm_mad_ctrl_send_err_cb(IN void *context, IN osm_madw_t * p_madw)
715 {
716 	osm_sm_mad_ctrl_t *p_ctrl = context;
717 	ib_api_status_t status;
718 	ib_smp_t *p_smp;
719 
720 	OSM_LOG_ENTER(p_ctrl->p_log);
721 
722 	CL_ASSERT(p_madw);
723 
724 	p_smp = osm_madw_get_smp_ptr(p_madw);
725 	OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3113: "
726 		"MAD completed in error (%s): "
727 		"%s(%s), attr_mod 0x%x, TID 0x%" PRIx64 "\n",
728 		ib_get_err_str(p_madw->status),
729 		ib_get_sm_method_str(p_smp->method),
730 		ib_get_sm_attr_str(p_smp->attr_id), cl_ntoh32(p_smp->attr_mod),
731 		cl_ntoh64(p_smp->trans_id));
732 
733 	/*
734 	   If this was a SubnSet MAD, then this error might indicate a problem
735 	   in configuring the subnet. In this case - need to mark that there was
736 	   such a problem. The subnet will not be up, and the next sweep should
737 	   be a heavy sweep as well.
738 	 */
739 	if (p_smp->method == IB_MAD_METHOD_SET &&
740 	    (p_smp->attr_id == IB_MAD_ATTR_PORT_INFO ||
741 	     p_smp->attr_id == IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO ||
742 	     p_smp->attr_id == IB_MAD_ATTR_MCAST_FWD_TBL ||
743 	     p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO ||
744 	     p_smp->attr_id == IB_MAD_ATTR_LIN_FWD_TBL ||
745 	     p_smp->attr_id == IB_MAD_ATTR_P_KEY_TABLE)) {
746 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3119: "
747 			"Set method failed for attribute 0x%X (%s)\n",
748 			cl_ntoh16(p_smp->attr_id),
749 			ib_get_sm_attr_str(p_smp->attr_id));
750 		p_ctrl->p_subn->subnet_initialization_error = TRUE;
751 	} else if (p_madw->status == IB_TIMEOUT &&
752 		   p_smp->method == IB_MAD_METHOD_GET) {
753 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3120: "
754 			"Timeout while getting attribute 0x%X (%s); "
755 			"Possible mis-set mkey?\n",
756 			cl_ntoh16(p_smp->attr_id),
757 			ib_get_sm_attr_str(p_smp->attr_id));
758 	}
759 
760 	osm_dump_dr_smp_v2(p_ctrl->p_log, p_smp, FILE_ID, OSM_LOG_VERBOSE);
761 
762 	/*
763 	   Since we did not get any response we suspect the DR path
764 	   used for the target port.
765 	   Find it and replace it with an alternate path.
766 	   This is true only if the destination lid is not 0xFFFF, since
767 	   then we are aiming for a specific path and not specific destination
768 	   lid.
769 	 */
770 	/* For now - do not add the alternate dr path to the release */
771 #if 0
772 	if (p_madw->mad_addr.dest_lid != 0xFFFF) {
773 		osm_physp_t *p_physp = osm_get_physp_by_mad_addr(p_ctrl->p_log,
774 								 p_ctrl->p_subn,
775 								 &(p_madw->
776 								   mad_addr));
777 		if (!p_physp) {
778 			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3114: "
779 				"Failed to find the corresponding phys port\n");
780 		} else {
781 			osm_physp_replace_dr_path_with_alternate_dr_path
782 			    (p_ctrl->p_log, p_ctrl->p_subn, p_physp,
783 			     p_madw->h_bind);
784 		}
785 	}
786 #endif
787 
788 	/*
789 	   An error occurred.  No response was received to a request MAD.
790 	   Retire the original request MAD.
791 	 */
792 	sm_mad_ctrl_update_wire_stats(p_ctrl);
793 
794 	if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
795 		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
796 			"Posting Dispatcher message %s\n",
797 			osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
798 
799 		status = cl_disp_post(p_ctrl->h_disp,
800 				      osm_madw_get_err_msg(p_madw), p_madw,
801 				      sm_mad_ctrl_disp_done_callback, p_ctrl);
802 		if (status != CL_SUCCESS)
803 			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3115: "
804 				"Dispatcher post message failed (%s)\n",
805 				CL_STATUS_MSG(status));
806 	} else
807 		/*
808 		   No error message was provided, just retire the MAD.
809 		 */
810 		sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
811 
812 	OSM_LOG_EXIT(p_ctrl->p_log);
813 }
814 
815 /*
816  * PARAMETERS
817  *
818  * RETURN VALUES
819  *
820  * NOTES
821  *
822  * SEE ALSO
823  *********/
824 
osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * p_ctrl)825 void osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * p_ctrl)
826 {
827 	CL_ASSERT(p_ctrl);
828 	memset(p_ctrl, 0, sizeof(*p_ctrl));
829 	p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
830 }
831 
osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * p_ctrl)832 void osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * p_ctrl)
833 {
834 	CL_ASSERT(p_ctrl);
835 
836 	if (p_ctrl->h_bind != CL_DISP_INVALID_HANDLE)
837 		osm_vendor_unbind(p_ctrl->h_bind);
838 	cl_disp_unregister(p_ctrl->h_disp);
839 }
840 
osm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * p_ctrl,IN osm_subn_t * p_subn,IN osm_mad_pool_t * p_mad_pool,IN osm_vl15_t * p_vl15,IN osm_vendor_t * p_vendor,IN osm_log_t * p_log,IN osm_stats_t * p_stats,IN cl_plock_t * p_lock,IN cl_dispatcher_t * p_disp)841 ib_api_status_t osm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * p_ctrl,
842 				     IN osm_subn_t * p_subn,
843 				     IN osm_mad_pool_t * p_mad_pool,
844 				     IN osm_vl15_t * p_vl15,
845 				     IN osm_vendor_t * p_vendor,
846 				     IN osm_log_t * p_log,
847 				     IN osm_stats_t * p_stats,
848 				     IN cl_plock_t * p_lock,
849 				     IN cl_dispatcher_t * p_disp)
850 {
851 	ib_api_status_t status = IB_SUCCESS;
852 
853 	OSM_LOG_ENTER(p_log);
854 
855 	osm_sm_mad_ctrl_construct(p_ctrl);
856 
857 	p_ctrl->p_subn = p_subn;
858 	p_ctrl->p_log = p_log;
859 	p_ctrl->p_disp = p_disp;
860 	p_ctrl->p_mad_pool = p_mad_pool;
861 	p_ctrl->p_vendor = p_vendor;
862 	p_ctrl->p_stats = p_stats;
863 	p_ctrl->p_lock = p_lock;
864 	p_ctrl->p_vl15 = p_vl15;
865 
866 	p_ctrl->h_disp = cl_disp_register(p_disp, CL_DISP_MSGID_NONE, NULL,
867 					  NULL);
868 
869 	if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
870 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3116: "
871 			"Dispatcher registration failed\n");
872 		status = IB_INSUFFICIENT_RESOURCES;
873 		goto Exit;
874 	}
875 
876 Exit:
877 	OSM_LOG_EXIT(p_log);
878 	return status;
879 }
880 
osm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * p_ctrl,IN ib_net64_t port_guid)881 ib_api_status_t osm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * p_ctrl,
882 				     IN ib_net64_t port_guid)
883 {
884 	osm_bind_info_t bind_info;
885 	ib_api_status_t status = IB_SUCCESS;
886 
887 	OSM_LOG_ENTER(p_ctrl->p_log);
888 
889 	if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
890 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3117: "
891 			"Multiple binds not allowed\n");
892 		status = IB_ERROR;
893 		goto Exit;
894 	}
895 
896 	bind_info.class_version = 1;
897 	bind_info.is_report_processor = FALSE;
898 	bind_info.is_responder = TRUE;
899 	bind_info.is_trap_processor = TRUE;
900 	bind_info.mad_class = IB_MCLASS_SUBN_DIR;
901 	bind_info.port_guid = port_guid;
902 	bind_info.recv_q_size = OSM_SM_DEFAULT_QP0_RCV_SIZE;
903 	bind_info.send_q_size = OSM_SM_DEFAULT_QP0_SEND_SIZE;
904 	bind_info.timeout = p_ctrl->p_subn->opt.transaction_timeout;
905 	bind_info.retries = p_ctrl->p_subn->opt.transaction_retries;
906 
907 	OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
908 		"Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
909 
910 	p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, &bind_info,
911 					 p_ctrl->p_mad_pool,
912 					 sm_mad_ctrl_rcv_callback,
913 					 sm_mad_ctrl_send_err_cb, p_ctrl);
914 
915 	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
916 		status = IB_ERROR;
917 		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3118: "
918 			"Vendor specific bind failed\n");
919 		goto Exit;
920 	}
921 
922 Exit:
923 	OSM_LOG_EXIT(p_ctrl->p_log);
924 	return status;
925 }
926