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_sm_mad_ctrl_t.
39 * This object represents the SM MAD request controller object.
40 * This object is part of the opensm family of objects.
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_sm_mad_ctrl.h>
51#include <vendor/osm_vendor_api.h>
52#include <opensm/osm_madw.h>
53#include <opensm/osm_msgdef.h>
54#include <opensm/osm_helper.h>
55#include <opensm/osm_opensm.h>
56
57/****f* opensm: SM/__osm_sm_mad_ctrl_retire_trans_mad
58 * NAME
59 * __osm_sm_mad_ctrl_retire_trans_mad
60 *
61 * DESCRIPTION
62 * This function handles clean-up of MADs associated with the SM's
63 * outstanding transactions on the wire.
64 *
65 * SYNOPSIS
66 */
67
68static void
69__osm_sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * const p_ctrl,
70				   IN osm_madw_t * const p_madw)
71{
72	uint32_t outstanding;
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_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
81		"Retiring MAD with TID 0x%" PRIx64 "\n",
82		cl_ntoh64(osm_madw_get_smp_ptr(p_madw)->trans_id));
83
84	osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
85
86	outstanding = osm_stats_dec_qp0_outstanding(p_ctrl->p_stats);
87
88	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding%s\n",
89		p_ctrl->p_stats->qp0_mads_outstanding,
90		outstanding ? "" : ": wire is clean.");
91
92	OSM_LOG_EXIT(p_ctrl->p_log);
93}
94
95/************/
96
97/****f* opensm: SM/__osm_sm_mad_ctrl_disp_done_callback
98 * NAME
99 * __osm_sm_mad_ctrl_disp_done_callback
100 *
101 * DESCRIPTION
102 * This function is the Dispatcher callback that indicates
103 * a received MAD has been processed by the recipient.
104 *
105 * SYNOPSIS
106 */
107static void
108__osm_sm_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data)
109{
110	osm_sm_mad_ctrl_t *const p_ctrl = (osm_sm_mad_ctrl_t *) context;
111	osm_madw_t *const p_madw = (osm_madw_t *) p_data;
112	ib_smp_t *p_smp;
113
114	OSM_LOG_ENTER(p_ctrl->p_log);
115
116	/*
117	   If the MAD that just finished processing was a response,
118	   then retire the transaction, since we must have generated
119	   the request.
120
121	   Otherwise, retire the transaction if a response was expected,
122	   as in the case of a send failure. If a response was not expected,
123	   just put the MAD back in the pool, because the MAD was a query
124	   from some outside agent, e.g. Get(SMInfo) from another SM.
125	 */
126	p_smp = osm_madw_get_smp_ptr(p_madw);
127	if (ib_smp_is_response(p_smp)) {
128		CL_ASSERT(p_madw->resp_expected == FALSE);
129		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
130	} else if (p_madw->resp_expected == TRUE)
131		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
132	else
133		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
134
135	OSM_LOG_EXIT(p_ctrl->p_log);
136}
137
138/************/
139
140/****f* opensm: SM/__osm_sm_mad_ctrl_update_wire_stats
141 * NAME
142 * __osm_sm_mad_ctrl_update_wire_stats
143 *
144 * DESCRIPTION
145 * Updates wire stats for outstanding MADs and calls the VL15 poller.
146 *
147 * SYNOPSIS
148 */
149static void
150__osm_sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * const p_ctrl)
151{
152	uint32_t mads_on_wire;
153
154	OSM_LOG_ENTER(p_ctrl->p_log);
155
156	mads_on_wire =
157	    cl_atomic_dec(&p_ctrl->p_stats->qp0_mads_outstanding_on_wire);
158
159	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
160		"%u SMPs on the wire, %u outstanding\n", mads_on_wire,
161		p_ctrl->p_stats->qp0_mads_outstanding);
162
163	/*
164	   We can signal the VL15 controller to send another MAD
165	   if any are waiting for transmission.
166	 */
167	osm_vl15_poll(p_ctrl->p_vl15);
168	OSM_LOG_EXIT(p_ctrl->p_log);
169}
170
171/****f* opensm: SM/__osm_sm_mad_ctrl_process_get_resp
172 * NAME
173 * __osm_sm_mad_ctrl_process_get_resp
174 *
175 * DESCRIPTION
176 * This function handles method GetResp() for received MADs.
177 * This is the most common path for QP0 MADs.
178 *
179 * SYNOPSIS
180 */
181static void
182__osm_sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * const 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(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
202	}
203
204	p_old_madw = (osm_madw_t *) transaction_context;
205
206	__osm_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_SWITCH_INFO:
230		msg_id = OSM_MSG_MAD_SWITCH_INFO;
231		break;
232	case IB_MAD_ATTR_PORT_INFO:
233		msg_id = OSM_MSG_MAD_PORT_INFO;
234		break;
235	case IB_MAD_ATTR_LIN_FWD_TBL:
236		msg_id = OSM_MSG_MAD_LFT;
237		break;
238	case IB_MAD_ATTR_MCAST_FWD_TBL:
239		msg_id = OSM_MSG_MAD_MFT;
240		break;
241	case IB_MAD_ATTR_SM_INFO:
242		msg_id = OSM_MSG_MAD_SM_INFO;
243		break;
244	case IB_MAD_ATTR_SLVL_TABLE:
245		msg_id = OSM_MSG_MAD_SLVL;
246		break;
247	case IB_MAD_ATTR_VL_ARBITRATION:
248		msg_id = OSM_MSG_MAD_VL_ARB;
249		break;
250	case IB_MAD_ATTR_P_KEY_TABLE:
251		msg_id = OSM_MSG_MAD_PKEY;
252		break;
253
254	case IB_MAD_ATTR_GUID_INFO:
255	case IB_MAD_ATTR_CLASS_PORT_INFO:
256	case IB_MAD_ATTR_NOTICE:
257	case IB_MAD_ATTR_INFORM_INFO:
258	default:
259		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
260		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3103: "
261			"Unsupported attribute = 0x%X\n",
262			cl_ntoh16(p_smp->attr_id));
263		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
264		goto Exit;
265	}
266
267	if (msg_id == CL_DISP_MSGID_NONE)
268		goto Exit;
269
270	/*
271	   Post this MAD to the dispatcher for asynchronous
272	   processing by the appropriate controller.
273	 */
274
275	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
276		osm_get_disp_msg_str(msg_id));
277
278	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
279			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
280
281	if (status != CL_SUCCESS) {
282		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3104: "
283			"Dispatcher post message failed (%s) for attribute = 0x%X\n",
284			CL_STATUS_MSG(status), cl_ntoh16(p_smp->attr_id));
285		goto Exit;
286	}
287
288Exit:
289	OSM_LOG_EXIT(p_ctrl->p_log);
290}
291
292/****f* opensm: SM/__osm_sm_mad_ctrl_process_get
293 * NAME
294 * __osm_sm_mad_ctrl_process_get
295 *
296 * DESCRIPTION
297 * This function handles method Get() for received MADs.
298 *
299 * SYNOPSIS
300 */
301static void
302__osm_sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * const p_ctrl,
303			      IN osm_madw_t * p_madw)
304{
305	ib_smp_t *p_smp;
306	cl_status_t status;
307	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
308
309	OSM_LOG_ENTER(p_ctrl->p_log);
310
311	p_smp = osm_madw_get_smp_ptr(p_madw);
312
313	/*
314	   Note that attr_id (like the rest of the MAD) is in
315	   network byte order.
316	 */
317	switch (p_smp->attr_id) {
318	case IB_MAD_ATTR_SM_INFO:
319		msg_id = OSM_MSG_MAD_SM_INFO;
320		break;
321
322	default:
323		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
324		OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
325			"Ignoring SubnGet MAD - unsupported attribute = 0x%X\n",
326			cl_ntoh16(p_smp->attr_id));
327		break;
328	}
329
330	if (msg_id == CL_DISP_MSGID_NONE) {
331		/*
332		   There is an unknown MAD attribute type for which there is
333		   no recipient.  Simply retire the MAD here.
334		 */
335		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
336		goto Exit;
337	}
338
339	/*
340	   Post this MAD to the dispatcher for asynchronous
341	   processing by the appropriate controller.
342	 */
343
344	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
345		osm_get_disp_msg_str(msg_id));
346
347	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
348			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
349
350	if (status != CL_SUCCESS) {
351		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3106: "
352			"Dispatcher post message failed (%s)\n",
353			CL_STATUS_MSG(status));
354		goto Exit;
355	}
356
357Exit:
358	OSM_LOG_EXIT(p_ctrl->p_log);
359}
360
361/*
362 * PARAMETERS
363 *
364 * RETURN VALUES
365 *
366 * NOTES
367 *
368 * SEE ALSO
369 *********/
370
371/****f* opensm: SM/__osm_sm_mad_ctrl_process_set
372 * NAME
373 * __osm_sm_mad_ctrl_process_set
374 *
375 * DESCRIPTION
376 * This function handles method Set() for received MADs.
377 *
378 * SYNOPSIS
379 */
380static void
381__osm_sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * const p_ctrl,
382			      IN osm_madw_t * p_madw)
383{
384	ib_smp_t *p_smp;
385	cl_status_t status;
386	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
387
388	OSM_LOG_ENTER(p_ctrl->p_log);
389
390	p_smp = osm_madw_get_smp_ptr(p_madw);
391
392	/*
393	   Note that attr_id (like the rest of the MAD) is in
394	   network byte order.
395	 */
396	switch (p_smp->attr_id) {
397	case IB_MAD_ATTR_SM_INFO:
398		msg_id = OSM_MSG_MAD_SM_INFO;
399		break;
400
401	default:
402		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
403		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3107: "
404			"Unsupported attribute = 0x%X\n",
405			cl_ntoh16(p_smp->attr_id));
406		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
407		break;
408	}
409
410	if (msg_id == CL_DISP_MSGID_NONE) {
411		/*
412		   There is an unknown MAD attribute type for which there is
413		   no recipient.  Simply retire the MAD here.
414		 */
415		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
416		goto Exit;
417	}
418
419	/*
420	   Post this MAD to the dispatcher for asynchronous
421	   processing by the appropriate controller.
422	 */
423
424	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
425		osm_get_disp_msg_str(msg_id));
426
427	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
428			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
429
430	if (status != CL_SUCCESS) {
431		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3108: "
432			"Dispatcher post message failed (%s)\n",
433			CL_STATUS_MSG(status));
434		goto Exit;
435	}
436
437Exit:
438	OSM_LOG_EXIT(p_ctrl->p_log);
439}
440
441/*
442 * PARAMETERS
443 *
444 * RETURN VALUES
445 *
446 * NOTES
447 *
448 * SEE ALSO
449 *********/
450
451/****f* opensm: SM/__osm_sm_mad_ctrl_process_trap
452 * NAME
453 * __osm_sm_mad_ctrl_process_trap
454 *
455 * DESCRIPTION
456 * This function handles method Trap() for received MADs.
457 *
458 * SYNOPSIS
459 */
460static void
461__osm_sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * const p_ctrl,
462			       IN osm_madw_t * p_madw)
463{
464	ib_smp_t *p_smp;
465	cl_status_t status;
466	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
467
468	OSM_LOG_ENTER(p_ctrl->p_log);
469
470	p_smp = osm_madw_get_smp_ptr(p_madw);
471
472	/* Make sure OpenSM is master. If not - then we should not process the trap */
473	if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) {
474		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
475			"Received trap but OpenSM is not in MASTER state. "
476			"Dropping mad\n");
477		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
478		goto Exit;
479	}
480
481	/*
482	   Note that attr_id (like the rest of the MAD) is in
483	   network byte order.
484	 */
485	switch (p_smp->attr_id) {
486	case IB_MAD_ATTR_NOTICE:
487		msg_id = OSM_MSG_MAD_NOTICE;
488		break;
489
490	default:
491		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
492		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3109: "
493			"Unsupported attribute = 0x%X\n",
494			cl_ntoh16(p_smp->attr_id));
495		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
496		break;
497	}
498
499	if (msg_id == CL_DISP_MSGID_NONE) {
500		/*
501		   There is an unknown MAD attribute type for which there is
502		   no recipient.  Simply retire the MAD here.
503		 */
504		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
505		goto Exit;
506	}
507
508	/*
509	   Post this MAD to the dispatcher for asynchronous
510	   processing by the appropriate controller.
511	 */
512
513	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
514		osm_get_disp_msg_str(msg_id));
515
516	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
517			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
518
519	if (status != CL_SUCCESS) {
520		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3110: "
521			"Dispatcher post message failed (%s)\n",
522			CL_STATUS_MSG(status));
523		goto Exit;
524	}
525
526Exit:
527	OSM_LOG_EXIT(p_ctrl->p_log);
528}
529
530/*
531 * PARAMETERS
532 *
533 * RETURN VALUES
534 *
535 * NOTES
536 *
537 * SEE ALSO
538 *********/
539
540/****f* opensm: SM/__osm_sm_mad_ctrl_rcv_callback
541 * NAME
542 * __osm_sm_mad_ctrl_rcv_callback
543 *
544 * DESCRIPTION
545 * This is the callback from the transport layer for received MADs.
546 *
547 * SYNOPSIS
548 */
549static void
550__osm_sm_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw,
551			       IN void *bind_context,
552			       IN osm_madw_t * p_req_madw)
553{
554	osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context;
555	ib_smp_t *p_smp;
556	ib_net16_t status;
557
558	OSM_LOG_ENTER(p_ctrl->p_log);
559
560	CL_ASSERT(p_madw);
561
562	/*
563	   A MAD was received from the wire, possibly in response to a request.
564	 */
565	cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd);
566
567	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs received\n",
568		p_ctrl->p_stats->qp0_mads_rcvd);
569
570	p_smp = osm_madw_get_smp_ptr(p_madw);
571
572	/* if we are closing down simply do nothing */
573	if (osm_exit_flag) {
574		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR,
575			"Ignoring received mad - since we are exiting\n");
576
577		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_DEBUG);
578
579		/* retire the mad or put it back */
580		if (ib_smp_is_response(p_smp) ||
581		    (p_smp->method == IB_MAD_METHOD_TRAP_REPRESS)) {
582			CL_ASSERT(p_madw->resp_expected == FALSE);
583			__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
584		} else if (p_madw->resp_expected == TRUE)
585			__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
586		else
587			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
588
589		goto Exit;
590	}
591
592	if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES))
593		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_FRAMES);
594
595	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
596		status = ib_smp_get_status(p_smp);
597	else
598		status = p_smp->status;
599
600	if (status != 0) {
601		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3111: "
602			"Error status = 0x%X\n", status);
603		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
604	}
605
606	switch (p_smp->method) {
607	case IB_MAD_METHOD_GET_RESP:
608		CL_ASSERT(p_req_madw != NULL);
609		__osm_sm_mad_ctrl_process_get_resp(p_ctrl, p_madw, p_req_madw);
610		break;
611
612	case IB_MAD_METHOD_GET:
613		CL_ASSERT(p_req_madw == NULL);
614		__osm_sm_mad_ctrl_process_get(p_ctrl, p_madw);
615		break;
616
617	case IB_MAD_METHOD_TRAP:
618		CL_ASSERT(p_req_madw == NULL);
619		__osm_sm_mad_ctrl_process_trap(p_ctrl, p_madw);
620		break;
621
622	case IB_MAD_METHOD_SET:
623		CL_ASSERT(p_req_madw == NULL);
624		__osm_sm_mad_ctrl_process_set(p_ctrl, p_madw);
625		break;
626
627	case IB_MAD_METHOD_SEND:
628	case IB_MAD_METHOD_REPORT:
629	case IB_MAD_METHOD_REPORT_RESP:
630	case IB_MAD_METHOD_TRAP_REPRESS:
631	default:
632		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
633		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3112: "
634			"Unsupported method = 0x%X\n", p_smp->method);
635		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
636		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
637		goto Exit;
638	}
639
640Exit:
641	OSM_LOG_EXIT(p_ctrl->p_log);
642}
643
644/*
645 * PARAMETERS
646 *
647 * RETURN VALUES
648 *
649 * NOTES
650 *
651 * SEE ALSO
652 *********/
653
654/****f* opensm: SM/__osm_sm_mad_ctrl_send_err_cb
655 * NAME
656 * __osm_sm_mad_ctrl_send_err_cb
657 *
658 * DESCRIPTION
659 * This is the callback from the transport layer for send errors
660 * on MADs that were expecting a response.
661 *
662 * SYNOPSIS
663 */
664static void
665__osm_sm_mad_ctrl_send_err_cb(IN void *bind_context, IN osm_madw_t * p_madw)
666{
667	osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context;
668	ib_api_status_t status;
669	ib_smp_t *p_smp;
670
671	OSM_LOG_ENTER(p_ctrl->p_log);
672
673	CL_ASSERT(p_madw);
674
675	OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3113: "
676		"MAD completed in error (%s)\n",
677		ib_get_err_str(p_madw->status));
678
679	/*
680	   If this was a SubnSet MAD, then this error might indicate a problem
681	   in configuring the subnet. In this case - need to mark that there was
682	   such a problem. The subnet will not be up, and the next sweep should
683	   be a heavy sweep as well.
684	 */
685	p_smp = osm_madw_get_smp_ptr(p_madw);
686	if (p_smp->method == IB_MAD_METHOD_SET &&
687	    (p_smp->attr_id == IB_MAD_ATTR_PORT_INFO ||
688	     p_smp->attr_id == IB_MAD_ATTR_MCAST_FWD_TBL ||
689	     p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO ||
690	     p_smp->attr_id == IB_MAD_ATTR_LIN_FWD_TBL)) {
691		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3119: "
692			"Set method failed\n");
693		p_ctrl->p_subn->subnet_initialization_error = TRUE;
694	}
695
696	/*
697	   Since we did not get any response we suspect the DR path
698	   used for the target port.
699	   Find it and replace it with an alternate path.
700	   This is true only if the destination lid is not 0xFFFF, since
701	   then we are aiming for a specific path and not specific destination
702	   lid.
703	 */
704	/* For now - do not add the alternate dr path to the release */
705#if 0
706	if (p_madw->mad_addr.dest_lid != 0xFFFF) {
707		osm_physp_t *p_physp =
708		    osm_get_physp_by_mad_addr(p_ctrl->p_log,
709					      p_ctrl->p_subn,
710					      &(p_madw->mad_addr));
711		if (!p_physp) {
712			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3114: "
713				"Failed to find the corresponding phys port\n");
714		} else {
715			osm_physp_replace_dr_path_with_alternate_dr_path
716			    (p_ctrl->p_log, p_ctrl->p_subn, p_physp,
717			     p_madw->h_bind);
718		}
719	}
720#endif
721
722	/*
723	   An error occurred.  No response was received to a request MAD.
724	   Retire the original request MAD.
725	 */
726
727	osm_dump_dr_smp(p_ctrl->p_log, osm_madw_get_smp_ptr(p_madw),
728			OSM_LOG_ERROR);
729
730	__osm_sm_mad_ctrl_update_wire_stats(p_ctrl);
731
732	if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
733		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
734			"Posting Dispatcher message %s\n",
735			osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
736
737		status = cl_disp_post(p_ctrl->h_disp,
738				      osm_madw_get_err_msg(p_madw),
739				      p_madw,
740				      __osm_sm_mad_ctrl_disp_done_callback,
741				      p_ctrl);
742		if (status != CL_SUCCESS)
743			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3115: "
744				"Dispatcher post message failed (%s)\n",
745				CL_STATUS_MSG(status));
746	} else
747		/*
748		   No error message was provided, just retire the MAD.
749		 */
750		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
751
752	OSM_LOG_EXIT(p_ctrl->p_log);
753}
754
755/*
756 * PARAMETERS
757 *
758 * RETURN VALUES
759 *
760 * NOTES
761 *
762 * SEE ALSO
763 *********/
764
765/**********************************************************************
766 **********************************************************************/
767void osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * const p_ctrl)
768{
769	CL_ASSERT(p_ctrl);
770	memset(p_ctrl, 0, sizeof(*p_ctrl));
771	p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
772}
773
774/**********************************************************************
775 **********************************************************************/
776void osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * const p_ctrl)
777{
778	CL_ASSERT(p_ctrl);
779
780	if (p_ctrl->h_bind != CL_DISP_INVALID_HANDLE)
781		osm_vendor_unbind(p_ctrl->h_bind);
782	cl_disp_unregister(p_ctrl->h_disp);
783}
784
785/**********************************************************************
786 **********************************************************************/
787ib_api_status_t
788osm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * const p_ctrl,
789		     IN osm_subn_t * const p_subn,
790		     IN osm_mad_pool_t * const p_mad_pool,
791		     IN osm_vl15_t * const p_vl15,
792		     IN osm_vendor_t * const p_vendor,
793		     IN osm_log_t * const p_log,
794		     IN osm_stats_t * const p_stats,
795		     IN cl_plock_t * const p_lock,
796		     IN cl_dispatcher_t * const p_disp)
797{
798	ib_api_status_t status = IB_SUCCESS;
799
800	OSM_LOG_ENTER(p_log);
801
802	osm_sm_mad_ctrl_construct(p_ctrl);
803
804	p_ctrl->p_subn = p_subn;
805	p_ctrl->p_log = p_log;
806	p_ctrl->p_disp = p_disp;
807	p_ctrl->p_mad_pool = p_mad_pool;
808	p_ctrl->p_vendor = p_vendor;
809	p_ctrl->p_stats = p_stats;
810	p_ctrl->p_lock = p_lock;
811	p_ctrl->p_vl15 = p_vl15;
812
813	p_ctrl->h_disp = cl_disp_register(p_disp,
814					  CL_DISP_MSGID_NONE, NULL, NULL);
815
816	if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
817		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3116: "
818			"Dispatcher registration failed\n");
819		status = IB_INSUFFICIENT_RESOURCES;
820		goto Exit;
821	}
822
823Exit:
824	OSM_LOG_EXIT(p_log);
825	return (status);
826}
827
828/**********************************************************************
829 **********************************************************************/
830ib_api_status_t
831osm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * const p_ctrl,
832		     IN const ib_net64_t port_guid)
833{
834	osm_bind_info_t bind_info;
835	ib_api_status_t status = IB_SUCCESS;
836
837	OSM_LOG_ENTER(p_ctrl->p_log);
838
839	if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
840		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3117: "
841			"Multiple binds not allowed\n");
842		status = IB_ERROR;
843		goto Exit;
844	}
845
846	bind_info.class_version = 1;
847	bind_info.is_report_processor = FALSE;
848	bind_info.is_responder = TRUE;
849	bind_info.is_trap_processor = TRUE;
850	bind_info.mad_class = IB_MCLASS_SUBN_DIR;
851	bind_info.port_guid = port_guid;
852	bind_info.recv_q_size = OSM_SM_DEFAULT_QP0_RCV_SIZE;
853	bind_info.send_q_size = OSM_SM_DEFAULT_QP0_SEND_SIZE;
854
855	OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
856		"Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
857
858	p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor,
859					 &bind_info,
860					 p_ctrl->p_mad_pool,
861					 __osm_sm_mad_ctrl_rcv_callback,
862					 __osm_sm_mad_ctrl_send_err_cb, p_ctrl);
863
864	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
865		status = IB_ERROR;
866		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3118: "
867			"Vendor specific bind failed\n");
868		goto Exit;
869	}
870
871Exit:
872	OSM_LOG_EXIT(p_ctrl->p_log);
873	return (status);
874}
875