1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *    Implementation of osm_sm_mad_ctrl_t.
39219820Sjeff * This object represents the SM MAD request controller object.
40219820Sjeff * This object is part of the opensm family of objects.
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <string.h>
48219820Sjeff#include <complib/cl_debug.h>
49219820Sjeff#include <iba/ib_types.h>
50219820Sjeff#include <opensm/osm_sm_mad_ctrl.h>
51219820Sjeff#include <vendor/osm_vendor_api.h>
52219820Sjeff#include <opensm/osm_madw.h>
53219820Sjeff#include <opensm/osm_msgdef.h>
54219820Sjeff#include <opensm/osm_helper.h>
55219820Sjeff#include <opensm/osm_opensm.h>
56219820Sjeff
57219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_retire_trans_mad
58219820Sjeff * NAME
59219820Sjeff * __osm_sm_mad_ctrl_retire_trans_mad
60219820Sjeff *
61219820Sjeff * DESCRIPTION
62219820Sjeff * This function handles clean-up of MADs associated with the SM's
63219820Sjeff * outstanding transactions on the wire.
64219820Sjeff *
65219820Sjeff * SYNOPSIS
66219820Sjeff */
67219820Sjeff
68219820Sjeffstatic void
69219820Sjeff__osm_sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * const p_ctrl,
70219820Sjeff				   IN osm_madw_t * const p_madw)
71219820Sjeff{
72219820Sjeff	uint32_t outstanding;
73219820Sjeff
74219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
75219820Sjeff
76219820Sjeff	CL_ASSERT(p_madw);
77219820Sjeff	/*
78219820Sjeff	   Return the MAD & wrapper to the pool.
79219820Sjeff	 */
80219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
81219820Sjeff		"Retiring MAD with TID 0x%" PRIx64 "\n",
82219820Sjeff		cl_ntoh64(osm_madw_get_smp_ptr(p_madw)->trans_id));
83219820Sjeff
84219820Sjeff	osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
85219820Sjeff
86219820Sjeff	outstanding = osm_stats_dec_qp0_outstanding(p_ctrl->p_stats);
87219820Sjeff
88219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding%s\n",
89219820Sjeff		p_ctrl->p_stats->qp0_mads_outstanding,
90219820Sjeff		outstanding ? "" : ": wire is clean.");
91219820Sjeff
92219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
93219820Sjeff}
94219820Sjeff
95219820Sjeff/************/
96219820Sjeff
97219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_disp_done_callback
98219820Sjeff * NAME
99219820Sjeff * __osm_sm_mad_ctrl_disp_done_callback
100219820Sjeff *
101219820Sjeff * DESCRIPTION
102219820Sjeff * This function is the Dispatcher callback that indicates
103219820Sjeff * a received MAD has been processed by the recipient.
104219820Sjeff *
105219820Sjeff * SYNOPSIS
106219820Sjeff */
107219820Sjeffstatic void
108219820Sjeff__osm_sm_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data)
109219820Sjeff{
110219820Sjeff	osm_sm_mad_ctrl_t *const p_ctrl = (osm_sm_mad_ctrl_t *) context;
111219820Sjeff	osm_madw_t *const p_madw = (osm_madw_t *) p_data;
112219820Sjeff	ib_smp_t *p_smp;
113219820Sjeff
114219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
115219820Sjeff
116219820Sjeff	/*
117219820Sjeff	   If the MAD that just finished processing was a response,
118219820Sjeff	   then retire the transaction, since we must have generated
119219820Sjeff	   the request.
120219820Sjeff
121219820Sjeff	   Otherwise, retire the transaction if a response was expected,
122219820Sjeff	   as in the case of a send failure. If a response was not expected,
123219820Sjeff	   just put the MAD back in the pool, because the MAD was a query
124219820Sjeff	   from some outside agent, e.g. Get(SMInfo) from another SM.
125219820Sjeff	 */
126219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
127219820Sjeff	if (ib_smp_is_response(p_smp)) {
128219820Sjeff		CL_ASSERT(p_madw->resp_expected == FALSE);
129219820Sjeff		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
130219820Sjeff	} else if (p_madw->resp_expected == TRUE)
131219820Sjeff		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
132219820Sjeff	else
133219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
134219820Sjeff
135219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
136219820Sjeff}
137219820Sjeff
138219820Sjeff/************/
139219820Sjeff
140219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_update_wire_stats
141219820Sjeff * NAME
142219820Sjeff * __osm_sm_mad_ctrl_update_wire_stats
143219820Sjeff *
144219820Sjeff * DESCRIPTION
145219820Sjeff * Updates wire stats for outstanding MADs and calls the VL15 poller.
146219820Sjeff *
147219820Sjeff * SYNOPSIS
148219820Sjeff */
149219820Sjeffstatic void
150219820Sjeff__osm_sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * const p_ctrl)
151219820Sjeff{
152219820Sjeff	uint32_t mads_on_wire;
153219820Sjeff
154219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
155219820Sjeff
156219820Sjeff	mads_on_wire =
157219820Sjeff	    cl_atomic_dec(&p_ctrl->p_stats->qp0_mads_outstanding_on_wire);
158219820Sjeff
159219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
160219820Sjeff		"%u SMPs on the wire, %u outstanding\n", mads_on_wire,
161219820Sjeff		p_ctrl->p_stats->qp0_mads_outstanding);
162219820Sjeff
163219820Sjeff	/*
164219820Sjeff	   We can signal the VL15 controller to send another MAD
165219820Sjeff	   if any are waiting for transmission.
166219820Sjeff	 */
167219820Sjeff	osm_vl15_poll(p_ctrl->p_vl15);
168219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
169219820Sjeff}
170219820Sjeff
171219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_process_get_resp
172219820Sjeff * NAME
173219820Sjeff * __osm_sm_mad_ctrl_process_get_resp
174219820Sjeff *
175219820Sjeff * DESCRIPTION
176219820Sjeff * This function handles method GetResp() for received MADs.
177219820Sjeff * This is the most common path for QP0 MADs.
178219820Sjeff *
179219820Sjeff * SYNOPSIS
180219820Sjeff */
181219820Sjeffstatic void
182219820Sjeff__osm_sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * const p_ctrl,
183219820Sjeff				   IN osm_madw_t * p_madw,
184219820Sjeff				   IN void *transaction_context)
185219820Sjeff{
186219820Sjeff	ib_smp_t *p_smp;
187219820Sjeff	cl_status_t status;
188219820Sjeff	osm_madw_t *p_old_madw;
189219820Sjeff	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
190219820Sjeff
191219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
192219820Sjeff
193219820Sjeff	CL_ASSERT(p_madw);
194219820Sjeff	CL_ASSERT(transaction_context);
195219820Sjeff
196219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
197219820Sjeff
198219820Sjeff	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR && !ib_smp_is_d(p_smp)) {
199219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3102: "
200219820Sjeff			"'D' bit not set in returned SMP\n");
201219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
202219820Sjeff	}
203219820Sjeff
204219820Sjeff	p_old_madw = (osm_madw_t *) transaction_context;
205219820Sjeff
206219820Sjeff	__osm_sm_mad_ctrl_update_wire_stats(p_ctrl);
207219820Sjeff
208219820Sjeff	/*
209219820Sjeff	   Copy the MAD Wrapper context from the requesting MAD
210219820Sjeff	   to the new MAD.  This mechanism allows the recipient
211219820Sjeff	   controller to recover its own context regarding this
212219820Sjeff	   MAD transaction.  Once we've copied the context, we
213219820Sjeff	   can return the original MAD to the pool.
214219820Sjeff	 */
215219820Sjeff	osm_madw_copy_context(p_madw, p_old_madw);
216219820Sjeff	osm_mad_pool_put(p_ctrl->p_mad_pool, p_old_madw);
217219820Sjeff
218219820Sjeff	/*
219219820Sjeff	   Note that attr_id (like the rest of the MAD) is in
220219820Sjeff	   network byte order.
221219820Sjeff	 */
222219820Sjeff	switch (p_smp->attr_id) {
223219820Sjeff	case IB_MAD_ATTR_NODE_DESC:
224219820Sjeff		msg_id = OSM_MSG_MAD_NODE_DESC;
225219820Sjeff		break;
226219820Sjeff	case IB_MAD_ATTR_NODE_INFO:
227219820Sjeff		msg_id = OSM_MSG_MAD_NODE_INFO;
228219820Sjeff		break;
229219820Sjeff	case IB_MAD_ATTR_SWITCH_INFO:
230219820Sjeff		msg_id = OSM_MSG_MAD_SWITCH_INFO;
231219820Sjeff		break;
232219820Sjeff	case IB_MAD_ATTR_PORT_INFO:
233219820Sjeff		msg_id = OSM_MSG_MAD_PORT_INFO;
234219820Sjeff		break;
235219820Sjeff	case IB_MAD_ATTR_LIN_FWD_TBL:
236219820Sjeff		msg_id = OSM_MSG_MAD_LFT;
237219820Sjeff		break;
238219820Sjeff	case IB_MAD_ATTR_MCAST_FWD_TBL:
239219820Sjeff		msg_id = OSM_MSG_MAD_MFT;
240219820Sjeff		break;
241219820Sjeff	case IB_MAD_ATTR_SM_INFO:
242219820Sjeff		msg_id = OSM_MSG_MAD_SM_INFO;
243219820Sjeff		break;
244219820Sjeff	case IB_MAD_ATTR_SLVL_TABLE:
245219820Sjeff		msg_id = OSM_MSG_MAD_SLVL;
246219820Sjeff		break;
247219820Sjeff	case IB_MAD_ATTR_VL_ARBITRATION:
248219820Sjeff		msg_id = OSM_MSG_MAD_VL_ARB;
249219820Sjeff		break;
250219820Sjeff	case IB_MAD_ATTR_P_KEY_TABLE:
251219820Sjeff		msg_id = OSM_MSG_MAD_PKEY;
252219820Sjeff		break;
253219820Sjeff
254219820Sjeff	case IB_MAD_ATTR_GUID_INFO:
255219820Sjeff	case IB_MAD_ATTR_CLASS_PORT_INFO:
256219820Sjeff	case IB_MAD_ATTR_NOTICE:
257219820Sjeff	case IB_MAD_ATTR_INFORM_INFO:
258219820Sjeff	default:
259219820Sjeff		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
260219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3103: "
261219820Sjeff			"Unsupported attribute = 0x%X\n",
262219820Sjeff			cl_ntoh16(p_smp->attr_id));
263219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
264219820Sjeff		goto Exit;
265219820Sjeff	}
266219820Sjeff
267219820Sjeff	if (msg_id == CL_DISP_MSGID_NONE)
268219820Sjeff		goto Exit;
269219820Sjeff
270219820Sjeff	/*
271219820Sjeff	   Post this MAD to the dispatcher for asynchronous
272219820Sjeff	   processing by the appropriate controller.
273219820Sjeff	 */
274219820Sjeff
275219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
276219820Sjeff		osm_get_disp_msg_str(msg_id));
277219820Sjeff
278219820Sjeff	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
279219820Sjeff			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
280219820Sjeff
281219820Sjeff	if (status != CL_SUCCESS) {
282219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3104: "
283219820Sjeff			"Dispatcher post message failed (%s) for attribute = 0x%X\n",
284219820Sjeff			CL_STATUS_MSG(status), cl_ntoh16(p_smp->attr_id));
285219820Sjeff		goto Exit;
286219820Sjeff	}
287219820Sjeff
288219820SjeffExit:
289219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
290219820Sjeff}
291219820Sjeff
292219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_process_get
293219820Sjeff * NAME
294219820Sjeff * __osm_sm_mad_ctrl_process_get
295219820Sjeff *
296219820Sjeff * DESCRIPTION
297219820Sjeff * This function handles method Get() for received MADs.
298219820Sjeff *
299219820Sjeff * SYNOPSIS
300219820Sjeff */
301219820Sjeffstatic void
302219820Sjeff__osm_sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * const p_ctrl,
303219820Sjeff			      IN osm_madw_t * p_madw)
304219820Sjeff{
305219820Sjeff	ib_smp_t *p_smp;
306219820Sjeff	cl_status_t status;
307219820Sjeff	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
308219820Sjeff
309219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
310219820Sjeff
311219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
312219820Sjeff
313219820Sjeff	/*
314219820Sjeff	   Note that attr_id (like the rest of the MAD) is in
315219820Sjeff	   network byte order.
316219820Sjeff	 */
317219820Sjeff	switch (p_smp->attr_id) {
318219820Sjeff	case IB_MAD_ATTR_SM_INFO:
319219820Sjeff		msg_id = OSM_MSG_MAD_SM_INFO;
320219820Sjeff		break;
321219820Sjeff
322219820Sjeff	default:
323219820Sjeff		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
324219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
325219820Sjeff			"Ignoring SubnGet MAD - unsupported attribute = 0x%X\n",
326219820Sjeff			cl_ntoh16(p_smp->attr_id));
327219820Sjeff		break;
328219820Sjeff	}
329219820Sjeff
330219820Sjeff	if (msg_id == CL_DISP_MSGID_NONE) {
331219820Sjeff		/*
332219820Sjeff		   There is an unknown MAD attribute type for which there is
333219820Sjeff		   no recipient.  Simply retire the MAD here.
334219820Sjeff		 */
335219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
336219820Sjeff		goto Exit;
337219820Sjeff	}
338219820Sjeff
339219820Sjeff	/*
340219820Sjeff	   Post this MAD to the dispatcher for asynchronous
341219820Sjeff	   processing by the appropriate controller.
342219820Sjeff	 */
343219820Sjeff
344219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
345219820Sjeff		osm_get_disp_msg_str(msg_id));
346219820Sjeff
347219820Sjeff	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
348219820Sjeff			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
349219820Sjeff
350219820Sjeff	if (status != CL_SUCCESS) {
351219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3106: "
352219820Sjeff			"Dispatcher post message failed (%s)\n",
353219820Sjeff			CL_STATUS_MSG(status));
354219820Sjeff		goto Exit;
355219820Sjeff	}
356219820Sjeff
357219820SjeffExit:
358219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
359219820Sjeff}
360219820Sjeff
361219820Sjeff/*
362219820Sjeff * PARAMETERS
363219820Sjeff *
364219820Sjeff * RETURN VALUES
365219820Sjeff *
366219820Sjeff * NOTES
367219820Sjeff *
368219820Sjeff * SEE ALSO
369219820Sjeff *********/
370219820Sjeff
371219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_process_set
372219820Sjeff * NAME
373219820Sjeff * __osm_sm_mad_ctrl_process_set
374219820Sjeff *
375219820Sjeff * DESCRIPTION
376219820Sjeff * This function handles method Set() for received MADs.
377219820Sjeff *
378219820Sjeff * SYNOPSIS
379219820Sjeff */
380219820Sjeffstatic void
381219820Sjeff__osm_sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * const p_ctrl,
382219820Sjeff			      IN osm_madw_t * p_madw)
383219820Sjeff{
384219820Sjeff	ib_smp_t *p_smp;
385219820Sjeff	cl_status_t status;
386219820Sjeff	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
387219820Sjeff
388219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
389219820Sjeff
390219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
391219820Sjeff
392219820Sjeff	/*
393219820Sjeff	   Note that attr_id (like the rest of the MAD) is in
394219820Sjeff	   network byte order.
395219820Sjeff	 */
396219820Sjeff	switch (p_smp->attr_id) {
397219820Sjeff	case IB_MAD_ATTR_SM_INFO:
398219820Sjeff		msg_id = OSM_MSG_MAD_SM_INFO;
399219820Sjeff		break;
400219820Sjeff
401219820Sjeff	default:
402219820Sjeff		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
403219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3107: "
404219820Sjeff			"Unsupported attribute = 0x%X\n",
405219820Sjeff			cl_ntoh16(p_smp->attr_id));
406219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
407219820Sjeff		break;
408219820Sjeff	}
409219820Sjeff
410219820Sjeff	if (msg_id == CL_DISP_MSGID_NONE) {
411219820Sjeff		/*
412219820Sjeff		   There is an unknown MAD attribute type for which there is
413219820Sjeff		   no recipient.  Simply retire the MAD here.
414219820Sjeff		 */
415219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
416219820Sjeff		goto Exit;
417219820Sjeff	}
418219820Sjeff
419219820Sjeff	/*
420219820Sjeff	   Post this MAD to the dispatcher for asynchronous
421219820Sjeff	   processing by the appropriate controller.
422219820Sjeff	 */
423219820Sjeff
424219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
425219820Sjeff		osm_get_disp_msg_str(msg_id));
426219820Sjeff
427219820Sjeff	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
428219820Sjeff			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
429219820Sjeff
430219820Sjeff	if (status != CL_SUCCESS) {
431219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3108: "
432219820Sjeff			"Dispatcher post message failed (%s)\n",
433219820Sjeff			CL_STATUS_MSG(status));
434219820Sjeff		goto Exit;
435219820Sjeff	}
436219820Sjeff
437219820SjeffExit:
438219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
439219820Sjeff}
440219820Sjeff
441219820Sjeff/*
442219820Sjeff * PARAMETERS
443219820Sjeff *
444219820Sjeff * RETURN VALUES
445219820Sjeff *
446219820Sjeff * NOTES
447219820Sjeff *
448219820Sjeff * SEE ALSO
449219820Sjeff *********/
450219820Sjeff
451219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_process_trap
452219820Sjeff * NAME
453219820Sjeff * __osm_sm_mad_ctrl_process_trap
454219820Sjeff *
455219820Sjeff * DESCRIPTION
456219820Sjeff * This function handles method Trap() for received MADs.
457219820Sjeff *
458219820Sjeff * SYNOPSIS
459219820Sjeff */
460219820Sjeffstatic void
461219820Sjeff__osm_sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * const p_ctrl,
462219820Sjeff			       IN osm_madw_t * p_madw)
463219820Sjeff{
464219820Sjeff	ib_smp_t *p_smp;
465219820Sjeff	cl_status_t status;
466219820Sjeff	cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
467219820Sjeff
468219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
469219820Sjeff
470219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
471219820Sjeff
472219820Sjeff	/* Make sure OpenSM is master. If not - then we should not process the trap */
473219820Sjeff	if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) {
474219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
475219820Sjeff			"Received trap but OpenSM is not in MASTER state. "
476219820Sjeff			"Dropping mad\n");
477219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
478219820Sjeff		goto Exit;
479219820Sjeff	}
480219820Sjeff
481219820Sjeff	/*
482219820Sjeff	   Note that attr_id (like the rest of the MAD) is in
483219820Sjeff	   network byte order.
484219820Sjeff	 */
485219820Sjeff	switch (p_smp->attr_id) {
486219820Sjeff	case IB_MAD_ATTR_NOTICE:
487219820Sjeff		msg_id = OSM_MSG_MAD_NOTICE;
488219820Sjeff		break;
489219820Sjeff
490219820Sjeff	default:
491219820Sjeff		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
492219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3109: "
493219820Sjeff			"Unsupported attribute = 0x%X\n",
494219820Sjeff			cl_ntoh16(p_smp->attr_id));
495219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
496219820Sjeff		break;
497219820Sjeff	}
498219820Sjeff
499219820Sjeff	if (msg_id == CL_DISP_MSGID_NONE) {
500219820Sjeff		/*
501219820Sjeff		   There is an unknown MAD attribute type for which there is
502219820Sjeff		   no recipient.  Simply retire the MAD here.
503219820Sjeff		 */
504219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
505219820Sjeff		goto Exit;
506219820Sjeff	}
507219820Sjeff
508219820Sjeff	/*
509219820Sjeff	   Post this MAD to the dispatcher for asynchronous
510219820Sjeff	   processing by the appropriate controller.
511219820Sjeff	 */
512219820Sjeff
513219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n",
514219820Sjeff		osm_get_disp_msg_str(msg_id));
515219820Sjeff
516219820Sjeff	status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw,
517219820Sjeff			      __osm_sm_mad_ctrl_disp_done_callback, p_ctrl);
518219820Sjeff
519219820Sjeff	if (status != CL_SUCCESS) {
520219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3110: "
521219820Sjeff			"Dispatcher post message failed (%s)\n",
522219820Sjeff			CL_STATUS_MSG(status));
523219820Sjeff		goto Exit;
524219820Sjeff	}
525219820Sjeff
526219820SjeffExit:
527219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
528219820Sjeff}
529219820Sjeff
530219820Sjeff/*
531219820Sjeff * PARAMETERS
532219820Sjeff *
533219820Sjeff * RETURN VALUES
534219820Sjeff *
535219820Sjeff * NOTES
536219820Sjeff *
537219820Sjeff * SEE ALSO
538219820Sjeff *********/
539219820Sjeff
540219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_rcv_callback
541219820Sjeff * NAME
542219820Sjeff * __osm_sm_mad_ctrl_rcv_callback
543219820Sjeff *
544219820Sjeff * DESCRIPTION
545219820Sjeff * This is the callback from the transport layer for received MADs.
546219820Sjeff *
547219820Sjeff * SYNOPSIS
548219820Sjeff */
549219820Sjeffstatic void
550219820Sjeff__osm_sm_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw,
551219820Sjeff			       IN void *bind_context,
552219820Sjeff			       IN osm_madw_t * p_req_madw)
553219820Sjeff{
554219820Sjeff	osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context;
555219820Sjeff	ib_smp_t *p_smp;
556219820Sjeff	ib_net16_t status;
557219820Sjeff
558219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
559219820Sjeff
560219820Sjeff	CL_ASSERT(p_madw);
561219820Sjeff
562219820Sjeff	/*
563219820Sjeff	   A MAD was received from the wire, possibly in response to a request.
564219820Sjeff	 */
565219820Sjeff	cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd);
566219820Sjeff
567219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs received\n",
568219820Sjeff		p_ctrl->p_stats->qp0_mads_rcvd);
569219820Sjeff
570219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
571219820Sjeff
572219820Sjeff	/* if we are closing down simply do nothing */
573219820Sjeff	if (osm_exit_flag) {
574219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR,
575219820Sjeff			"Ignoring received mad - since we are exiting\n");
576219820Sjeff
577219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_DEBUG);
578219820Sjeff
579219820Sjeff		/* retire the mad or put it back */
580219820Sjeff		if (ib_smp_is_response(p_smp) ||
581219820Sjeff		    (p_smp->method == IB_MAD_METHOD_TRAP_REPRESS)) {
582219820Sjeff			CL_ASSERT(p_madw->resp_expected == FALSE);
583219820Sjeff			__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
584219820Sjeff		} else if (p_madw->resp_expected == TRUE)
585219820Sjeff			__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
586219820Sjeff		else
587219820Sjeff			osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
588219820Sjeff
589219820Sjeff		goto Exit;
590219820Sjeff	}
591219820Sjeff
592219820Sjeff	if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES))
593219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_FRAMES);
594219820Sjeff
595219820Sjeff	if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
596219820Sjeff		status = ib_smp_get_status(p_smp);
597219820Sjeff	else
598219820Sjeff		status = p_smp->status;
599219820Sjeff
600219820Sjeff	if (status != 0) {
601219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3111: "
602219820Sjeff			"Error status = 0x%X\n", status);
603219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
604219820Sjeff	}
605219820Sjeff
606219820Sjeff	switch (p_smp->method) {
607219820Sjeff	case IB_MAD_METHOD_GET_RESP:
608219820Sjeff		CL_ASSERT(p_req_madw != NULL);
609219820Sjeff		__osm_sm_mad_ctrl_process_get_resp(p_ctrl, p_madw, p_req_madw);
610219820Sjeff		break;
611219820Sjeff
612219820Sjeff	case IB_MAD_METHOD_GET:
613219820Sjeff		CL_ASSERT(p_req_madw == NULL);
614219820Sjeff		__osm_sm_mad_ctrl_process_get(p_ctrl, p_madw);
615219820Sjeff		break;
616219820Sjeff
617219820Sjeff	case IB_MAD_METHOD_TRAP:
618219820Sjeff		CL_ASSERT(p_req_madw == NULL);
619219820Sjeff		__osm_sm_mad_ctrl_process_trap(p_ctrl, p_madw);
620219820Sjeff		break;
621219820Sjeff
622219820Sjeff	case IB_MAD_METHOD_SET:
623219820Sjeff		CL_ASSERT(p_req_madw == NULL);
624219820Sjeff		__osm_sm_mad_ctrl_process_set(p_ctrl, p_madw);
625219820Sjeff		break;
626219820Sjeff
627219820Sjeff	case IB_MAD_METHOD_SEND:
628219820Sjeff	case IB_MAD_METHOD_REPORT:
629219820Sjeff	case IB_MAD_METHOD_REPORT_RESP:
630219820Sjeff	case IB_MAD_METHOD_TRAP_REPRESS:
631219820Sjeff	default:
632219820Sjeff		cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown);
633219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3112: "
634219820Sjeff			"Unsupported method = 0x%X\n", p_smp->method);
635219820Sjeff		osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR);
636219820Sjeff		osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
637219820Sjeff		goto Exit;
638219820Sjeff	}
639219820Sjeff
640219820SjeffExit:
641219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
642219820Sjeff}
643219820Sjeff
644219820Sjeff/*
645219820Sjeff * PARAMETERS
646219820Sjeff *
647219820Sjeff * RETURN VALUES
648219820Sjeff *
649219820Sjeff * NOTES
650219820Sjeff *
651219820Sjeff * SEE ALSO
652219820Sjeff *********/
653219820Sjeff
654219820Sjeff/****f* opensm: SM/__osm_sm_mad_ctrl_send_err_cb
655219820Sjeff * NAME
656219820Sjeff * __osm_sm_mad_ctrl_send_err_cb
657219820Sjeff *
658219820Sjeff * DESCRIPTION
659219820Sjeff * This is the callback from the transport layer for send errors
660219820Sjeff * on MADs that were expecting a response.
661219820Sjeff *
662219820Sjeff * SYNOPSIS
663219820Sjeff */
664219820Sjeffstatic void
665219820Sjeff__osm_sm_mad_ctrl_send_err_cb(IN void *bind_context, IN osm_madw_t * p_madw)
666219820Sjeff{
667219820Sjeff	osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context;
668219820Sjeff	ib_api_status_t status;
669219820Sjeff	ib_smp_t *p_smp;
670219820Sjeff
671219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
672219820Sjeff
673219820Sjeff	CL_ASSERT(p_madw);
674219820Sjeff
675219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3113: "
676219820Sjeff		"MAD completed in error (%s)\n",
677219820Sjeff		ib_get_err_str(p_madw->status));
678219820Sjeff
679219820Sjeff	/*
680219820Sjeff	   If this was a SubnSet MAD, then this error might indicate a problem
681219820Sjeff	   in configuring the subnet. In this case - need to mark that there was
682219820Sjeff	   such a problem. The subnet will not be up, and the next sweep should
683219820Sjeff	   be a heavy sweep as well.
684219820Sjeff	 */
685219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
686219820Sjeff	if (p_smp->method == IB_MAD_METHOD_SET &&
687219820Sjeff	    (p_smp->attr_id == IB_MAD_ATTR_PORT_INFO ||
688219820Sjeff	     p_smp->attr_id == IB_MAD_ATTR_MCAST_FWD_TBL ||
689219820Sjeff	     p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO ||
690219820Sjeff	     p_smp->attr_id == IB_MAD_ATTR_LIN_FWD_TBL)) {
691219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3119: "
692219820Sjeff			"Set method failed\n");
693219820Sjeff		p_ctrl->p_subn->subnet_initialization_error = TRUE;
694219820Sjeff	}
695219820Sjeff
696219820Sjeff	/*
697219820Sjeff	   Since we did not get any response we suspect the DR path
698219820Sjeff	   used for the target port.
699219820Sjeff	   Find it and replace it with an alternate path.
700219820Sjeff	   This is true only if the destination lid is not 0xFFFF, since
701219820Sjeff	   then we are aiming for a specific path and not specific destination
702219820Sjeff	   lid.
703219820Sjeff	 */
704219820Sjeff	/* For now - do not add the alternate dr path to the release */
705219820Sjeff#if 0
706219820Sjeff	if (p_madw->mad_addr.dest_lid != 0xFFFF) {
707219820Sjeff		osm_physp_t *p_physp =
708219820Sjeff		    osm_get_physp_by_mad_addr(p_ctrl->p_log,
709219820Sjeff					      p_ctrl->p_subn,
710219820Sjeff					      &(p_madw->mad_addr));
711219820Sjeff		if (!p_physp) {
712219820Sjeff			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3114: "
713219820Sjeff				"Failed to find the corresponding phys port\n");
714219820Sjeff		} else {
715219820Sjeff			osm_physp_replace_dr_path_with_alternate_dr_path
716219820Sjeff			    (p_ctrl->p_log, p_ctrl->p_subn, p_physp,
717219820Sjeff			     p_madw->h_bind);
718219820Sjeff		}
719219820Sjeff	}
720219820Sjeff#endif
721219820Sjeff
722219820Sjeff	/*
723219820Sjeff	   An error occurred.  No response was received to a request MAD.
724219820Sjeff	   Retire the original request MAD.
725219820Sjeff	 */
726219820Sjeff
727219820Sjeff	osm_dump_dr_smp(p_ctrl->p_log, osm_madw_get_smp_ptr(p_madw),
728219820Sjeff			OSM_LOG_ERROR);
729219820Sjeff
730219820Sjeff	__osm_sm_mad_ctrl_update_wire_stats(p_ctrl);
731219820Sjeff
732219820Sjeff	if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
733219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
734219820Sjeff			"Posting Dispatcher message %s\n",
735219820Sjeff			osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
736219820Sjeff
737219820Sjeff		status = cl_disp_post(p_ctrl->h_disp,
738219820Sjeff				      osm_madw_get_err_msg(p_madw),
739219820Sjeff				      p_madw,
740219820Sjeff				      __osm_sm_mad_ctrl_disp_done_callback,
741219820Sjeff				      p_ctrl);
742219820Sjeff		if (status != CL_SUCCESS)
743219820Sjeff			OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3115: "
744219820Sjeff				"Dispatcher post message failed (%s)\n",
745219820Sjeff				CL_STATUS_MSG(status));
746219820Sjeff	} else
747219820Sjeff		/*
748219820Sjeff		   No error message was provided, just retire the MAD.
749219820Sjeff		 */
750219820Sjeff		__osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw);
751219820Sjeff
752219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
753219820Sjeff}
754219820Sjeff
755219820Sjeff/*
756219820Sjeff * PARAMETERS
757219820Sjeff *
758219820Sjeff * RETURN VALUES
759219820Sjeff *
760219820Sjeff * NOTES
761219820Sjeff *
762219820Sjeff * SEE ALSO
763219820Sjeff *********/
764219820Sjeff
765219820Sjeff/**********************************************************************
766219820Sjeff **********************************************************************/
767219820Sjeffvoid osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * const p_ctrl)
768219820Sjeff{
769219820Sjeff	CL_ASSERT(p_ctrl);
770219820Sjeff	memset(p_ctrl, 0, sizeof(*p_ctrl));
771219820Sjeff	p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
772219820Sjeff}
773219820Sjeff
774219820Sjeff/**********************************************************************
775219820Sjeff **********************************************************************/
776219820Sjeffvoid osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * const p_ctrl)
777219820Sjeff{
778219820Sjeff	CL_ASSERT(p_ctrl);
779219820Sjeff
780219820Sjeff	if (p_ctrl->h_bind != CL_DISP_INVALID_HANDLE)
781219820Sjeff		osm_vendor_unbind(p_ctrl->h_bind);
782219820Sjeff	cl_disp_unregister(p_ctrl->h_disp);
783219820Sjeff}
784219820Sjeff
785219820Sjeff/**********************************************************************
786219820Sjeff **********************************************************************/
787219820Sjeffib_api_status_t
788219820Sjeffosm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * const p_ctrl,
789219820Sjeff		     IN osm_subn_t * const p_subn,
790219820Sjeff		     IN osm_mad_pool_t * const p_mad_pool,
791219820Sjeff		     IN osm_vl15_t * const p_vl15,
792219820Sjeff		     IN osm_vendor_t * const p_vendor,
793219820Sjeff		     IN osm_log_t * const p_log,
794219820Sjeff		     IN osm_stats_t * const p_stats,
795219820Sjeff		     IN cl_plock_t * const p_lock,
796219820Sjeff		     IN cl_dispatcher_t * const p_disp)
797219820Sjeff{
798219820Sjeff	ib_api_status_t status = IB_SUCCESS;
799219820Sjeff
800219820Sjeff	OSM_LOG_ENTER(p_log);
801219820Sjeff
802219820Sjeff	osm_sm_mad_ctrl_construct(p_ctrl);
803219820Sjeff
804219820Sjeff	p_ctrl->p_subn = p_subn;
805219820Sjeff	p_ctrl->p_log = p_log;
806219820Sjeff	p_ctrl->p_disp = p_disp;
807219820Sjeff	p_ctrl->p_mad_pool = p_mad_pool;
808219820Sjeff	p_ctrl->p_vendor = p_vendor;
809219820Sjeff	p_ctrl->p_stats = p_stats;
810219820Sjeff	p_ctrl->p_lock = p_lock;
811219820Sjeff	p_ctrl->p_vl15 = p_vl15;
812219820Sjeff
813219820Sjeff	p_ctrl->h_disp = cl_disp_register(p_disp,
814219820Sjeff					  CL_DISP_MSGID_NONE, NULL, NULL);
815219820Sjeff
816219820Sjeff	if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
817219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3116: "
818219820Sjeff			"Dispatcher registration failed\n");
819219820Sjeff		status = IB_INSUFFICIENT_RESOURCES;
820219820Sjeff		goto Exit;
821219820Sjeff	}
822219820Sjeff
823219820SjeffExit:
824219820Sjeff	OSM_LOG_EXIT(p_log);
825219820Sjeff	return (status);
826219820Sjeff}
827219820Sjeff
828219820Sjeff/**********************************************************************
829219820Sjeff **********************************************************************/
830219820Sjeffib_api_status_t
831219820Sjeffosm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * const p_ctrl,
832219820Sjeff		     IN const ib_net64_t port_guid)
833219820Sjeff{
834219820Sjeff	osm_bind_info_t bind_info;
835219820Sjeff	ib_api_status_t status = IB_SUCCESS;
836219820Sjeff
837219820Sjeff	OSM_LOG_ENTER(p_ctrl->p_log);
838219820Sjeff
839219820Sjeff	if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
840219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3117: "
841219820Sjeff			"Multiple binds not allowed\n");
842219820Sjeff		status = IB_ERROR;
843219820Sjeff		goto Exit;
844219820Sjeff	}
845219820Sjeff
846219820Sjeff	bind_info.class_version = 1;
847219820Sjeff	bind_info.is_report_processor = FALSE;
848219820Sjeff	bind_info.is_responder = TRUE;
849219820Sjeff	bind_info.is_trap_processor = TRUE;
850219820Sjeff	bind_info.mad_class = IB_MCLASS_SUBN_DIR;
851219820Sjeff	bind_info.port_guid = port_guid;
852219820Sjeff	bind_info.recv_q_size = OSM_SM_DEFAULT_QP0_RCV_SIZE;
853219820Sjeff	bind_info.send_q_size = OSM_SM_DEFAULT_QP0_SEND_SIZE;
854219820Sjeff
855219820Sjeff	OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
856219820Sjeff		"Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
857219820Sjeff
858219820Sjeff	p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor,
859219820Sjeff					 &bind_info,
860219820Sjeff					 p_ctrl->p_mad_pool,
861219820Sjeff					 __osm_sm_mad_ctrl_rcv_callback,
862219820Sjeff					 __osm_sm_mad_ctrl_send_err_cb, p_ctrl);
863219820Sjeff
864219820Sjeff	if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
865219820Sjeff		status = IB_ERROR;
866219820Sjeff		OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3118: "
867219820Sjeff			"Vendor specific bind failed\n");
868219820Sjeff		goto Exit;
869219820Sjeff	}
870219820Sjeff
871219820SjeffExit:
872219820Sjeff	OSM_LOG_EXIT(p_ctrl->p_log);
873219820Sjeff	return (status);
874219820Sjeff}
875