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
72static 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 */
110static 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 */
151static 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 */
182static 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
292Exit:
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 */
305static 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
351Exit:
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 */
374static 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
422Exit:
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 */
445static 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
502Exit:
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 */
525static 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
557static 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 */
605static 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
690Exit:
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 */
714static 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
825void 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
832void 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
841ib_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
876Exit:
877	OSM_LOG_EXIT(p_log);
878	return status;
879}
880
881ib_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
922Exit:
923	OSM_LOG_EXIT(p_ctrl->p_log);
924	return status;
925}
926