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 * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6219820Sjeff *
7219820Sjeff * This software is available to you under a choice of one of two
8219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
9219820Sjeff * General Public License (GPL) Version 2, available from the file
10219820Sjeff * COPYING in the main directory of this source tree, or the
11219820Sjeff * OpenIB.org BSD license below:
12219820Sjeff *
13219820Sjeff *     Redistribution and use in source and binary forms, with or
14219820Sjeff *     without modification, are permitted provided that the following
15219820Sjeff *     conditions are met:
16219820Sjeff *
17219820Sjeff *      - Redistributions of source code must retain the above
18219820Sjeff *        copyright notice, this list of conditions and the following
19219820Sjeff *        disclaimer.
20219820Sjeff *
21219820Sjeff *      - Redistributions in binary form must reproduce the above
22219820Sjeff *        copyright notice, this list of conditions and the following
23219820Sjeff *        disclaimer in the documentation and/or other materials
24219820Sjeff *        provided with the distribution.
25219820Sjeff *
26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33219820Sjeff * SOFTWARE.
34219820Sjeff *
35219820Sjeff */
36219820Sjeff
37219820Sjeff/*
38219820Sjeff * Abstract:
39219820Sjeff *    Implementation of osm_sa_t.
40219820Sjeff * This object represents the Subnet Administration object.
41219820Sjeff * This object is part of the opensm family of objects.
42219820Sjeff */
43219820Sjeff
44219820Sjeff#if HAVE_CONFIG_H
45219820Sjeff#  include <config.h>
46219820Sjeff#endif				/* HAVE_CONFIG_H */
47219820Sjeff
48219820Sjeff#include <string.h>
49219820Sjeff#include <ctype.h>
50219820Sjeff#include <errno.h>
51219820Sjeff#include <stdlib.h>
52219820Sjeff#include <sys/types.h>
53219820Sjeff#include <sys/stat.h>
54219820Sjeff#include <complib/cl_qmap.h>
55219820Sjeff#include <complib/cl_passivelock.h>
56219820Sjeff#include <complib/cl_debug.h>
57219820Sjeff#include <iba/ib_types.h>
58219820Sjeff#include <opensm/osm_sa.h>
59219820Sjeff#include <opensm/osm_madw.h>
60219820Sjeff#include <opensm/osm_log.h>
61219820Sjeff#include <opensm/osm_subnet.h>
62219820Sjeff#include <opensm/osm_mad_pool.h>
63219820Sjeff#include <opensm/osm_msgdef.h>
64219820Sjeff#include <opensm/osm_opensm.h>
65219820Sjeff#include <opensm/osm_multicast.h>
66219820Sjeff#include <opensm/osm_inform.h>
67219820Sjeff#include <opensm/osm_service.h>
68219820Sjeff#include <opensm/osm_helper.h>
69219820Sjeff#include <vendor/osm_vendor_api.h>
70219820Sjeff
71219820Sjeff#define  OSM_SA_INITIAL_TID_VALUE 0xabc
72219820Sjeff
73219820Sjeffextern void osm_cpi_rcv_process(IN void *context, IN void *data);
74219820Sjeffextern void osm_gir_rcv_process(IN void *context, IN void *data);
75219820Sjeffextern void osm_infr_rcv_process(IN void *context, IN void *data);
76219820Sjeffextern void osm_infir_rcv_process(IN void *context, IN void *data);
77219820Sjeffextern void osm_lftr_rcv_process(IN void *context, IN void *data);
78219820Sjeffextern void osm_lr_rcv_process(IN void *context, IN void *data);
79219820Sjeffextern void osm_mcmr_rcv_process(IN void *context, IN void *data);
80219820Sjeffextern void osm_mftr_rcv_process(IN void *context, IN void *data);
81219820Sjeffextern void osm_mpr_rcv_process(IN void *context, IN void *data);
82219820Sjeffextern void osm_nr_rcv_process(IN void *context, IN void *data);
83219820Sjeffextern void osm_pr_rcv_process(IN void *context, IN void *data);
84219820Sjeffextern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
85219820Sjeffextern void osm_pir_rcv_process(IN void *context, IN void *data);
86219820Sjeffextern void osm_sr_rcv_process(IN void *context, IN void *data);
87219820Sjeffextern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
88219820Sjeffextern void osm_smir_rcv_process(IN void *context, IN void *data);
89219820Sjeffextern void osm_sir_rcv_process(IN void *context, IN void *data);
90219820Sjeffextern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
91219820Sjeffextern void osm_sr_rcv_lease_cb(IN void *context);
92219820Sjeff
93219820Sjeff/**********************************************************************
94219820Sjeff **********************************************************************/
95219820Sjeffvoid osm_sa_construct(IN osm_sa_t * const p_sa)
96219820Sjeff{
97219820Sjeff	memset(p_sa, 0, sizeof(*p_sa));
98219820Sjeff	p_sa->state = OSM_SA_STATE_INIT;
99219820Sjeff	p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE;
100219820Sjeff
101219820Sjeff	cl_timer_construct(&p_sa->sr_timer);
102219820Sjeff}
103219820Sjeff
104219820Sjeff/**********************************************************************
105219820Sjeff **********************************************************************/
106219820Sjeffvoid osm_sa_shutdown(IN osm_sa_t * const p_sa)
107219820Sjeff{
108219820Sjeff	ib_api_status_t status;
109219820Sjeff	OSM_LOG_ENTER(p_sa->p_log);
110219820Sjeff
111219820Sjeff	cl_timer_stop(&p_sa->sr_timer);
112219820Sjeff
113219820Sjeff	/* unbind from the mad service */
114219820Sjeff	status = osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl);
115219820Sjeff
116219820Sjeff	/* remove any registered dispatcher message */
117219820Sjeff	cl_disp_unregister(p_sa->nr_disp_h);
118219820Sjeff	cl_disp_unregister(p_sa->pir_disp_h);
119219820Sjeff	cl_disp_unregister(p_sa->gir_disp_h);
120219820Sjeff	cl_disp_unregister(p_sa->lr_disp_h);
121219820Sjeff	cl_disp_unregister(p_sa->pr_disp_h);
122219820Sjeff#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
123219820Sjeff	cl_disp_unregister(p_sa->mpr_disp_h);
124219820Sjeff#endif
125219820Sjeff	cl_disp_unregister(p_sa->smir_disp_h);
126219820Sjeff	cl_disp_unregister(p_sa->mcmr_disp_h);
127219820Sjeff	cl_disp_unregister(p_sa->sr_disp_h);
128219820Sjeff	cl_disp_unregister(p_sa->infr_disp_h);
129219820Sjeff	cl_disp_unregister(p_sa->infir_disp_h);
130219820Sjeff	cl_disp_unregister(p_sa->vlarb_disp_h);
131219820Sjeff	cl_disp_unregister(p_sa->slvl_disp_h);
132219820Sjeff	cl_disp_unregister(p_sa->pkey_disp_h);
133219820Sjeff	cl_disp_unregister(p_sa->lft_disp_h);
134219820Sjeff	cl_disp_unregister(p_sa->sir_disp_h);
135219820Sjeff	cl_disp_unregister(p_sa->mft_disp_h);
136219820Sjeff	osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl);
137219820Sjeff
138219820Sjeff	OSM_LOG_EXIT(p_sa->p_log);
139219820Sjeff}
140219820Sjeff
141219820Sjeff/**********************************************************************
142219820Sjeff **********************************************************************/
143219820Sjeffvoid osm_sa_destroy(IN osm_sa_t * const p_sa)
144219820Sjeff{
145219820Sjeff	OSM_LOG_ENTER(p_sa->p_log);
146219820Sjeff
147219820Sjeff	p_sa->state = OSM_SA_STATE_INIT;
148219820Sjeff
149219820Sjeff	cl_timer_destroy(&p_sa->sr_timer);
150219820Sjeff
151219820Sjeff	OSM_LOG_EXIT(p_sa->p_log);
152219820Sjeff}
153219820Sjeff
154219820Sjeff/**********************************************************************
155219820Sjeff **********************************************************************/
156219820Sjeffib_api_status_t
157219820Sjeffosm_sa_init(IN osm_sm_t * const p_sm,
158219820Sjeff	    IN osm_sa_t * const p_sa,
159219820Sjeff	    IN osm_subn_t * const p_subn,
160219820Sjeff	    IN osm_vendor_t * const p_vendor,
161219820Sjeff	    IN osm_mad_pool_t * const p_mad_pool,
162219820Sjeff	    IN osm_log_t * const p_log,
163219820Sjeff	    IN osm_stats_t * const p_stats,
164219820Sjeff	    IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock)
165219820Sjeff{
166219820Sjeff	ib_api_status_t status = IB_SUCCESS;
167219820Sjeff
168219820Sjeff	OSM_LOG_ENTER(p_log);
169219820Sjeff
170219820Sjeff	p_sa->sm = p_sm;
171219820Sjeff	p_sa->p_subn = p_subn;
172219820Sjeff	p_sa->p_vendor = p_vendor;
173219820Sjeff	p_sa->p_mad_pool = p_mad_pool;
174219820Sjeff	p_sa->p_log = p_log;
175219820Sjeff	p_sa->p_disp = p_disp;
176219820Sjeff	p_sa->p_lock = p_lock;
177219820Sjeff
178219820Sjeff	p_sa->state = OSM_SA_STATE_READY;
179219820Sjeff
180219820Sjeff	status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl,
181219820Sjeff				      p_sa,
182219820Sjeff				      p_sa->p_mad_pool,
183219820Sjeff				      p_sa->p_vendor,
184219820Sjeff				      p_subn, p_log, p_stats, p_disp);
185219820Sjeff	if (status != IB_SUCCESS)
186219820Sjeff		goto Exit;
187219820Sjeff
188219820Sjeff	status = cl_timer_init(&p_sa->sr_timer, osm_sr_rcv_lease_cb, p_sa);
189219820Sjeff	if (status != IB_SUCCESS)
190219820Sjeff		goto Exit;
191219820Sjeff
192219820Sjeff	p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO,
193219820Sjeff					    osm_cpi_rcv_process, p_sa);
194219820Sjeff	if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE)
195219820Sjeff		goto Exit;
196219820Sjeff
197219820Sjeff	p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD,
198219820Sjeff					   osm_nr_rcv_process, p_sa);
199219820Sjeff	if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE)
200219820Sjeff		goto Exit;
201219820Sjeff
202219820Sjeff	p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD,
203219820Sjeff					    osm_pir_rcv_process, p_sa);
204219820Sjeff	if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE)
205219820Sjeff		goto Exit;
206219820Sjeff
207219820Sjeff	p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
208219820Sjeff					    osm_gir_rcv_process, p_sa);
209219820Sjeff	if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE)
210219820Sjeff		goto Exit;
211219820Sjeff
212219820Sjeff	p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD,
213219820Sjeff					   osm_lr_rcv_process, p_sa);
214219820Sjeff	if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE)
215219820Sjeff		goto Exit;
216219820Sjeff
217219820Sjeff	p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD,
218219820Sjeff					   osm_pr_rcv_process, p_sa);
219219820Sjeff	if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE)
220219820Sjeff		goto Exit;
221219820Sjeff
222219820Sjeff#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
223219820Sjeff	p_sa->mpr_disp_h =
224219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD,
225219820Sjeff			     osm_mpr_rcv_process, p_sa);
226219820Sjeff	if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE)
227219820Sjeff		goto Exit;
228219820Sjeff#endif
229219820Sjeff
230219820Sjeff	p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD,
231219820Sjeff					     osm_smir_rcv_process, p_sa);
232219820Sjeff	if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE)
233219820Sjeff		goto Exit;
234219820Sjeff
235219820Sjeff	p_sa->mcmr_disp_h =
236219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
237219820Sjeff			     osm_mcmr_rcv_process, p_sa);
238219820Sjeff	if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE)
239219820Sjeff		goto Exit;
240219820Sjeff
241219820Sjeff	p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD,
242219820Sjeff					   osm_sr_rcv_process, p_sa);
243219820Sjeff	if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE)
244219820Sjeff		goto Exit;
245219820Sjeff
246219820Sjeff	p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO,
247219820Sjeff					     osm_infr_rcv_process, p_sa);
248219820Sjeff	if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE)
249219820Sjeff		goto Exit;
250219820Sjeff
251219820Sjeff	p_sa->infir_disp_h =
252219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD,
253219820Sjeff			     osm_infir_rcv_process, p_sa);
254219820Sjeff	if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE)
255219820Sjeff		goto Exit;
256219820Sjeff
257219820Sjeff	p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD,
258219820Sjeff					      osm_vlarb_rec_rcv_process, p_sa);
259219820Sjeff	if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE)
260219820Sjeff		goto Exit;
261219820Sjeff
262219820Sjeff	p_sa->slvl_disp_h =
263219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD,
264219820Sjeff			     osm_slvl_rec_rcv_process, p_sa);
265219820Sjeff	if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE)
266219820Sjeff		goto Exit;
267219820Sjeff
268219820Sjeff	p_sa->pkey_disp_h =
269219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD,
270219820Sjeff			     osm_pkey_rec_rcv_process, p_sa);
271219820Sjeff	if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE)
272219820Sjeff		goto Exit;
273219820Sjeff
274219820Sjeff	p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD,
275219820Sjeff					    osm_lftr_rcv_process, p_sa);
276219820Sjeff	if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE)
277219820Sjeff		goto Exit;
278219820Sjeff
279219820Sjeff	p_sa->sir_disp_h =
280219820Sjeff	    cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD,
281219820Sjeff			     osm_sir_rcv_process, p_sa);
282219820Sjeff	if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE)
283219820Sjeff		goto Exit;
284219820Sjeff
285219820Sjeff	p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD,
286219820Sjeff					    osm_mftr_rcv_process, p_sa);
287219820Sjeff	if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE)
288219820Sjeff		goto Exit;
289219820Sjeff
290219820SjeffExit:
291219820Sjeff	OSM_LOG_EXIT(p_log);
292219820Sjeff	return (status);
293219820Sjeff}
294219820Sjeff
295219820Sjeff/**********************************************************************
296219820Sjeff **********************************************************************/
297219820Sjeffib_api_status_t
298219820Sjeffosm_sa_bind(IN osm_sa_t * const p_sa, IN const ib_net64_t port_guid)
299219820Sjeff{
300219820Sjeff	ib_api_status_t status;
301219820Sjeff
302219820Sjeff	OSM_LOG_ENTER(p_sa->p_log);
303219820Sjeff
304219820Sjeff	status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid);
305219820Sjeff
306219820Sjeff	if (status != IB_SUCCESS) {
307219820Sjeff		OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: "
308219820Sjeff			"SA MAD Controller bind failed (%s)\n",
309219820Sjeff			ib_get_err_str(status));
310219820Sjeff		goto Exit;
311219820Sjeff	}
312219820Sjeff
313219820SjeffExit:
314219820Sjeff	OSM_LOG_EXIT(p_sa->p_log);
315219820Sjeff	return (status);
316219820Sjeff}
317219820Sjeff
318219820Sjeffib_api_status_t osm_sa_send(osm_sa_t *sa,
319219820Sjeff			    IN osm_madw_t * const p_madw,
320219820Sjeff			    IN boolean_t const resp_expected)
321219820Sjeff{
322219820Sjeff	ib_api_status_t status;
323219820Sjeff
324219820Sjeff	cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent);
325219820Sjeff	status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected);
326219820Sjeff	if (status != IB_SUCCESS) {
327219820Sjeff		cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent);
328219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: "
329219820Sjeff			"osm_vendor_send failed, status = %s\n",
330219820Sjeff			ib_get_err_str(status));
331219820Sjeff	}
332219820Sjeff	return status;
333219820Sjeff}
334219820Sjeff
335219820Sjeffvoid
336219820Sjeffosm_sa_send_error(IN osm_sa_t * sa,
337219820Sjeff		  IN const osm_madw_t * const p_madw,
338219820Sjeff		  IN const ib_net16_t sa_status)
339219820Sjeff{
340219820Sjeff	osm_madw_t *p_resp_madw;
341219820Sjeff	ib_sa_mad_t *p_resp_sa_mad;
342219820Sjeff	ib_sa_mad_t *p_sa_mad;
343219820Sjeff
344219820Sjeff	OSM_LOG_ENTER(sa->p_log);
345219820Sjeff
346219820Sjeff	/* avoid races - if we are exiting - exit */
347219820Sjeff	if (osm_exit_flag) {
348219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
349219820Sjeff			"Ignoring requested send after exit\n");
350219820Sjeff		goto Exit;
351219820Sjeff	}
352219820Sjeff
353219820Sjeff	p_resp_madw = osm_mad_pool_get(sa->p_mad_pool,
354219820Sjeff				       p_madw->h_bind, MAD_BLOCK_SIZE,
355219820Sjeff				       &p_madw->mad_addr);
356219820Sjeff
357219820Sjeff	if (p_resp_madw == NULL) {
358219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: "
359219820Sjeff			"Unable to acquire response MAD\n");
360219820Sjeff		goto Exit;
361219820Sjeff	}
362219820Sjeff
363219820Sjeff	p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
364219820Sjeff	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
365219820Sjeff
366219820Sjeff	/*  Copy the MAD header back into the response mad */
367219820Sjeff	*p_resp_sa_mad = *p_sa_mad;
368219820Sjeff	p_resp_sa_mad->status = sa_status;
369219820Sjeff
370219820Sjeff	if (p_resp_sa_mad->method == IB_MAD_METHOD_SET)
371219820Sjeff		p_resp_sa_mad->method = IB_MAD_METHOD_GET;
372219820Sjeff	else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE)
373219820Sjeff		p_resp_sa_mad->attr_offset = 0;
374219820Sjeff
375219820Sjeff	p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
376219820Sjeff
377219820Sjeff	/*
378219820Sjeff	 * C15-0.1.5 - always return SM_Key = 0 (table 185 p 884)
379219820Sjeff	 */
380219820Sjeff	p_resp_sa_mad->sm_key = 0;
381219820Sjeff
382219820Sjeff	/*
383219820Sjeff	 * o15-0.2.7 - The PathRecord Attribute ID shall be used in
384219820Sjeff	 * the response (to a SubnAdmGetMulti(MultiPathRecord)
385219820Sjeff	 */
386219820Sjeff	if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD)
387219820Sjeff		p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
388219820Sjeff
389219820Sjeff	if (osm_log_is_active(sa->p_log, OSM_LOG_FRAMES))
390219820Sjeff		osm_dump_sa_mad(sa->p_log, p_resp_sa_mad, OSM_LOG_FRAMES);
391219820Sjeff
392219820Sjeff	osm_sa_send(sa, p_resp_madw, FALSE);
393219820Sjeff
394219820SjeffExit:
395219820Sjeff	OSM_LOG_EXIT(sa->p_log);
396219820Sjeff}
397219820Sjeff
398219820Sjeffvoid osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size,
399219820Sjeff		    cl_qlist_t *list)
400219820Sjeff{
401219820Sjeff	struct item_data {
402219820Sjeff		cl_list_item_t list;
403219820Sjeff		char data[0];
404219820Sjeff	};
405219820Sjeff	cl_list_item_t *item;
406219820Sjeff	osm_madw_t *resp_madw;
407219820Sjeff	ib_sa_mad_t *sa_mad, *resp_sa_mad;
408219820Sjeff	unsigned num_rec, i;
409219820Sjeff#ifndef VENDOR_RMPP_SUPPORT
410219820Sjeff	unsigned trim_num_rec;
411219820Sjeff#endif
412219820Sjeff	void *p;
413219820Sjeff
414219820Sjeff	sa_mad = osm_madw_get_sa_mad_ptr(madw);
415219820Sjeff	num_rec = cl_qlist_count(list);
416219820Sjeff
417219820Sjeff	/*
418219820Sjeff	 * C15-0.1.30:
419219820Sjeff	 * If we do a SubnAdmGet and got more than one record it is an error!
420219820Sjeff	 */
421219820Sjeff	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) {
422219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: "
423219820Sjeff			"Got more than one record for SubnAdmGet (%u)\n",
424219820Sjeff			num_rec);
425219820Sjeff		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS);
426219820Sjeff		goto Exit;
427219820Sjeff	}
428219820Sjeff
429219820Sjeff#ifndef VENDOR_RMPP_SUPPORT
430219820Sjeff	trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size;
431219820Sjeff	if (trim_num_rec < num_rec) {
432219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
433219820Sjeff			"Number of records:%u trimmed to:%u to fit in one MAD\n",
434219820Sjeff			num_rec, trim_num_rec);
435219820Sjeff		num_rec = trim_num_rec;
436219820Sjeff	}
437219820Sjeff#endif
438219820Sjeff
439219820Sjeff	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec);
440219820Sjeff
441219820Sjeff	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) {
442219820Sjeff		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS);
443219820Sjeff		goto Exit;
444219820Sjeff	}
445219820Sjeff
446219820Sjeff	/*
447219820Sjeff	 * Get a MAD to reply. Address of Mad is in the received mad_wrapper
448219820Sjeff	 */
449219820Sjeff	resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind,
450219820Sjeff				     num_rec * attr_size + IB_SA_MAD_HDR_SIZE,
451219820Sjeff				     &madw->mad_addr);
452219820Sjeff	if (!resp_madw) {
453219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: "
454219820Sjeff			"osm_mad_pool_get failed\n");
455219820Sjeff		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES);
456219820Sjeff		goto Exit;
457219820Sjeff	}
458219820Sjeff
459219820Sjeff	resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw);
460219820Sjeff
461219820Sjeff	/*
462219820Sjeff	   Copy the MAD header back into the response mad.
463219820Sjeff	   Set the 'R' bit and the payload length,
464219820Sjeff	   Then copy all records from the list into the response payload.
465219820Sjeff	 */
466219820Sjeff
467219820Sjeff	memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE);
468219820Sjeff	if (resp_sa_mad->method == IB_MAD_METHOD_SET)
469219820Sjeff		resp_sa_mad->method = IB_MAD_METHOD_GET;
470219820Sjeff	resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
471219820Sjeff	/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
472219820Sjeff	resp_sa_mad->sm_key = 0;
473219820Sjeff
474219820Sjeff	/* Fill in the offset (paylen will be done by the rmpp SAR) */
475219820Sjeff	resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0;
476219820Sjeff
477219820Sjeff	p = ib_sa_mad_get_payload_ptr(resp_sa_mad);
478219820Sjeff
479219820Sjeff#ifndef VENDOR_RMPP_SUPPORT
480219820Sjeff	/* we support only one packet RMPP - so we will set the first and
481219820Sjeff	   last flags for gettable */
482219820Sjeff	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) {
483219820Sjeff		resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
484219820Sjeff		resp_sa_mad->rmpp_flags =
485219820Sjeff		    IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST |
486219820Sjeff		    IB_RMPP_FLAG_ACTIVE;
487219820Sjeff	}
488219820Sjeff#else
489219820Sjeff	/* forcefully define the packet as RMPP one */
490219820Sjeff	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
491219820Sjeff		resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
492219820Sjeff#endif
493219820Sjeff
494219820Sjeff	for (i = 0; i < num_rec; i++) {
495219820Sjeff		item = cl_qlist_remove_head(list);
496219820Sjeff		memcpy(p, ((struct item_data *)item)->data, attr_size);
497219820Sjeff		p += attr_size;
498219820Sjeff		free(item);
499219820Sjeff	}
500219820Sjeff
501219820Sjeff	osm_sa_send(sa, resp_madw, FALSE);
502219820Sjeff
503219820Sjeff	osm_dump_sa_mad(sa->p_log, resp_sa_mad, OSM_LOG_FRAMES);
504219820SjeffExit:
505219820Sjeff	/* need to set the mem free ... */
506219820Sjeff	item = cl_qlist_remove_head(list);
507219820Sjeff	while (item != cl_qlist_end(list)) {
508219820Sjeff		free(item);
509219820Sjeff		item = cl_qlist_remove_head(list);
510219820Sjeff	}
511219820Sjeff}
512219820Sjeff
513219820Sjeff/**********************************************************************
514219820Sjeff **********************************************************************/
515219820Sjeff/*
516219820Sjeff *  SA DB Dumper
517219820Sjeff *
518219820Sjeff */
519219820Sjeff
520219820Sjeffstruct opensm_dump_context {
521219820Sjeff	osm_opensm_t *p_osm;
522219820Sjeff	FILE *file;
523219820Sjeff};
524219820Sjeff
525219820Sjeffstatic int
526219820Sjeffopensm_dump_to_file(osm_opensm_t * p_osm, const char *file_name,
527219820Sjeff		    void (*dump_func) (osm_opensm_t * p_osm, FILE * file))
528219820Sjeff{
529219820Sjeff	char path[1024];
530219820Sjeff	FILE *file;
531219820Sjeff
532219820Sjeff	snprintf(path, sizeof(path), "%s/%s",
533219820Sjeff		 p_osm->subn.opt.dump_files_dir, file_name);
534219820Sjeff
535219820Sjeff	file = fopen(path, "w");
536219820Sjeff	if (!file) {
537219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: "
538219820Sjeff			"cannot open file \'%s\': %s\n",
539219820Sjeff			file_name, strerror(errno));
540219820Sjeff		return -1;
541219820Sjeff	}
542219820Sjeff
543219820Sjeff	chmod(path, S_IRUSR | S_IWUSR);
544219820Sjeff
545219820Sjeff	dump_func(p_osm, file);
546219820Sjeff
547219820Sjeff	fclose(file);
548219820Sjeff	return 0;
549219820Sjeff}
550219820Sjeff
551219820Sjeffstatic void mcast_mgr_dump_one_port(cl_map_item_t * p_map_item, void *cxt)
552219820Sjeff{
553219820Sjeff	FILE *file = ((struct opensm_dump_context *)cxt)->file;
554219820Sjeff	osm_mcm_port_t *p_mcm_port = (osm_mcm_port_t *) p_map_item;
555219820Sjeff
556219820Sjeff	fprintf(file, "mcm_port: "
557219820Sjeff		"port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " "
558219820Sjeff		"scope_state=0x%02x proxy_join=0x%x" "\n\n",
559219820Sjeff		cl_ntoh64(p_mcm_port->port_gid.unicast.prefix),
560219820Sjeff		cl_ntoh64(p_mcm_port->port_gid.unicast.interface_id),
561219820Sjeff		p_mcm_port->scope_state, p_mcm_port->proxy_join);
562219820Sjeff}
563219820Sjeff
564219820Sjeffstatic void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, void *cxt)
565219820Sjeff{
566219820Sjeff	struct opensm_dump_context dump_context;
567219820Sjeff	osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm;
568219820Sjeff	FILE *file = ((struct opensm_dump_context *)cxt)->file;
569219820Sjeff
570219820Sjeff	fprintf(file, "MC Group 0x%04x %s:"
571219820Sjeff		" mgid=0x%016" PRIx64 ":0x%016" PRIx64
572219820Sjeff		" port_gid=0x%016" PRIx64 ":0x%016" PRIx64
573219820Sjeff		" qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x"
574219820Sjeff		" pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x"
575219820Sjeff		" scope_state=0x%02x proxy_join=0x%x" "\n\n",
576219820Sjeff		cl_ntoh16(p_mgrp->mlid),
577219820Sjeff		p_mgrp->well_known ? " (well known)" : "",
578219820Sjeff		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
579219820Sjeff		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id),
580219820Sjeff		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix),
581219820Sjeff		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id),
582219820Sjeff		cl_ntoh32(p_mgrp->mcmember_rec.qkey),
583219820Sjeff		cl_ntoh16(p_mgrp->mcmember_rec.mlid),
584219820Sjeff		p_mgrp->mcmember_rec.mtu,
585219820Sjeff		p_mgrp->mcmember_rec.tclass,
586219820Sjeff		cl_ntoh16(p_mgrp->mcmember_rec.pkey),
587219820Sjeff		p_mgrp->mcmember_rec.rate,
588219820Sjeff		p_mgrp->mcmember_rec.pkt_life,
589219820Sjeff		cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop),
590219820Sjeff		p_mgrp->mcmember_rec.scope_state,
591219820Sjeff		p_mgrp->mcmember_rec.proxy_join);
592219820Sjeff
593219820Sjeff	dump_context.p_osm = p_osm;
594219820Sjeff	dump_context.file = file;
595219820Sjeff
596219820Sjeff	cl_qmap_apply_func(&p_mgrp->mcm_port_tbl,
597219820Sjeff			   mcast_mgr_dump_one_port, &dump_context);
598219820Sjeff}
599219820Sjeff
600219820Sjeffstatic void sa_dump_one_inform(cl_list_item_t * p_list_item, void *cxt)
601219820Sjeff{
602219820Sjeff	FILE *file = ((struct opensm_dump_context *)cxt)->file;
603219820Sjeff	osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
604219820Sjeff	ib_inform_info_record_t *p_iir = &p_infr->inform_record;
605219820Sjeff
606219820Sjeff	fprintf(file, "InformInfo Record:"
607219820Sjeff		" subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64
608219820Sjeff		" subscriber_enum=0x%x"
609219820Sjeff		" InformInfo:"
610219820Sjeff		" gid=0x%016" PRIx64 ":0x%016" PRIx64
611219820Sjeff		" lid_range_begin=0x%x"
612219820Sjeff		" lid_range_end=0x%x"
613219820Sjeff		" is_generic=0x%x"
614219820Sjeff		" subscribe=0x%x"
615219820Sjeff		" trap_type=0x%x"
616219820Sjeff		" trap_num=0x%x"
617219820Sjeff		" qpn_resp_time_val=0x%x"
618219820Sjeff		" node_type=0x%06x"
619219820Sjeff		" rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x"
620219820Sjeff		" remote_qp=0x%08x remote_qkey=0x%08x pkey_ix=0x%04x sl=0x%02x"
621219820Sjeff		"\n\n",
622219820Sjeff		cl_ntoh64(p_iir->subscriber_gid.unicast.prefix),
623219820Sjeff		cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id),
624219820Sjeff		cl_ntoh16(p_iir->subscriber_enum),
625219820Sjeff		cl_ntoh64(p_iir->inform_info.gid.unicast.prefix),
626219820Sjeff		cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id),
627219820Sjeff		cl_ntoh16(p_iir->inform_info.lid_range_begin),
628219820Sjeff		cl_ntoh16(p_iir->inform_info.lid_range_end),
629219820Sjeff		p_iir->inform_info.is_generic,
630219820Sjeff		p_iir->inform_info.subscribe,
631219820Sjeff		cl_ntoh16(p_iir->inform_info.trap_type),
632219820Sjeff		cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num),
633219820Sjeff		cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val),
634219820Sjeff		cl_ntoh32(ib_inform_info_get_prod_type(&p_iir->inform_info)),
635219820Sjeff		cl_ntoh16(p_infr->report_addr.dest_lid),
636219820Sjeff		p_infr->report_addr.path_bits,
637219820Sjeff		p_infr->report_addr.static_rate,
638219820Sjeff		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp),
639219820Sjeff		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey),
640219820Sjeff		p_infr->report_addr.addr_type.gsi.pkey_ix,
641219820Sjeff		p_infr->report_addr.addr_type.gsi.service_level);
642219820Sjeff}
643219820Sjeff
644219820Sjeffstatic void sa_dump_one_service(cl_list_item_t * p_list_item, void *cxt)
645219820Sjeff{
646219820Sjeff	FILE *file = ((struct opensm_dump_context *)cxt)->file;
647219820Sjeff	osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item;
648219820Sjeff	ib_service_record_t *p_sr = &p_svcr->service_record;
649219820Sjeff
650219820Sjeff	fprintf(file, "Service Record: id=0x%016" PRIx64
651219820Sjeff		" gid=0x%016" PRIx64 ":0x%016" PRIx64
652219820Sjeff		" pkey=0x%x"
653219820Sjeff		" lease=0x%x"
654219820Sjeff		" key=0x%02x%02x%02x%02x%02x%02x%02x%02x"
655219820Sjeff		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
656219820Sjeff		" name=\'%s\'"
657219820Sjeff		" data8=0x%02x%02x%02x%02x%02x%02x%02x%02x"
658219820Sjeff		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
659219820Sjeff		" data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x"
660219820Sjeff		" data32=0x%08x%08x:0x%08x%08x"
661219820Sjeff		" data64=0x%016" PRIx64 ":0x%016" PRIx64
662219820Sjeff		" modified_time=0x%x lease_period=0x%x\n\n",
663219820Sjeff		cl_ntoh64(p_sr->service_id),
664219820Sjeff		cl_ntoh64(p_sr->service_gid.unicast.prefix),
665219820Sjeff		cl_ntoh64(p_sr->service_gid.unicast.interface_id),
666219820Sjeff		cl_ntoh16(p_sr->service_pkey),
667219820Sjeff		cl_ntoh32(p_sr->service_lease),
668219820Sjeff		p_sr->service_key[0], p_sr->service_key[1],
669219820Sjeff		p_sr->service_key[2], p_sr->service_key[3],
670219820Sjeff		p_sr->service_key[4], p_sr->service_key[5],
671219820Sjeff		p_sr->service_key[6], p_sr->service_key[7],
672219820Sjeff		p_sr->service_key[8], p_sr->service_key[9],
673219820Sjeff		p_sr->service_key[10], p_sr->service_key[11],
674219820Sjeff		p_sr->service_key[12], p_sr->service_key[13],
675219820Sjeff		p_sr->service_key[14], p_sr->service_key[15],
676219820Sjeff		p_sr->service_name,
677219820Sjeff		p_sr->service_data8[0], p_sr->service_data8[1],
678219820Sjeff		p_sr->service_data8[2], p_sr->service_data8[3],
679219820Sjeff		p_sr->service_data8[4], p_sr->service_data8[5],
680219820Sjeff		p_sr->service_data8[6], p_sr->service_data8[7],
681219820Sjeff		p_sr->service_data8[8], p_sr->service_data8[9],
682219820Sjeff		p_sr->service_data8[10], p_sr->service_data8[11],
683219820Sjeff		p_sr->service_data8[12], p_sr->service_data8[13],
684219820Sjeff		p_sr->service_data8[14], p_sr->service_data8[15],
685219820Sjeff		cl_ntoh16(p_sr->service_data16[0]),
686219820Sjeff		cl_ntoh16(p_sr->service_data16[1]),
687219820Sjeff		cl_ntoh16(p_sr->service_data16[2]),
688219820Sjeff		cl_ntoh16(p_sr->service_data16[3]),
689219820Sjeff		cl_ntoh16(p_sr->service_data16[4]),
690219820Sjeff		cl_ntoh16(p_sr->service_data16[5]),
691219820Sjeff		cl_ntoh16(p_sr->service_data16[6]),
692219820Sjeff		cl_ntoh16(p_sr->service_data16[7]),
693219820Sjeff		cl_ntoh32(p_sr->service_data32[0]),
694219820Sjeff		cl_ntoh32(p_sr->service_data32[1]),
695219820Sjeff		cl_ntoh32(p_sr->service_data32[2]),
696219820Sjeff		cl_ntoh32(p_sr->service_data32[3]),
697219820Sjeff		cl_ntoh64(p_sr->service_data64[0]),
698219820Sjeff		cl_ntoh64(p_sr->service_data64[1]),
699219820Sjeff		p_svcr->modified_time, p_svcr->lease_period);
700219820Sjeff}
701219820Sjeff
702219820Sjeffstatic void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
703219820Sjeff{
704219820Sjeff	struct opensm_dump_context dump_context;
705219820Sjeff	osm_mgrp_t *p_mgrp;
706219820Sjeff	int i;
707219820Sjeff
708219820Sjeff	dump_context.p_osm = p_osm;
709219820Sjeff	dump_context.file = file;
710219820Sjeff	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast:\n");
711219820Sjeff	cl_plock_acquire(&p_osm->lock);
712219820Sjeff	for (i = 0; i <= p_osm->subn.max_mcast_lid_ho - IB_LID_MCAST_START_HO;
713219820Sjeff	     i++) {
714219820Sjeff		p_mgrp = p_osm->subn.mgroups[i];
715219820Sjeff		if (p_mgrp)
716219820Sjeff			sa_dump_one_mgrp(p_mgrp, &dump_context);
717219820Sjeff	}
718219820Sjeff	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform:\n");
719219820Sjeff	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
720219820Sjeff			    sa_dump_one_inform, &dump_context);
721219820Sjeff	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump services:\n");
722219820Sjeff	cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
723219820Sjeff			    sa_dump_one_service, &dump_context);
724219820Sjeff	cl_plock_release(&p_osm->lock);
725219820Sjeff}
726219820Sjeff
727219820Sjeffint osm_sa_db_file_dump(osm_opensm_t * p_osm)
728219820Sjeff{
729219820Sjeff	return opensm_dump_to_file(p_osm, "opensm-sa.dump", sa_dump_all_sa);
730219820Sjeff}
731219820Sjeff
732219820Sjeff/*
733219820Sjeff *  SA DB Loader
734219820Sjeff */
735219820Sjeffstatic osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
736219820Sjeff				ib_member_rec_t * p_mcm_rec,
737219820Sjeff				unsigned well_known)
738219820Sjeff{
739219820Sjeff	ib_net64_t comp_mask;
740219820Sjeff	osm_mgrp_t *p_mgrp;
741219820Sjeff
742219820Sjeff	cl_plock_excl_acquire(&p_osm->lock);
743219820Sjeff
744219820Sjeff	p_mgrp = osm_get_mgrp_by_mlid(&p_osm->subn, mlid);
745219820Sjeff	if (p_mgrp) {
746219820Sjeff		if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid,
747219820Sjeff			    sizeof(ib_gid_t))) {
748219820Sjeff			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
749219820Sjeff				"mgrp %04x is already here.", cl_ntoh16(mlid));
750219820Sjeff			goto _out;
751219820Sjeff		}
752219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
753219820Sjeff			"mlid %04x is already used by another MC group. Will "
754219820Sjeff			"request clients reregistration.\n", cl_ntoh16(mlid));
755219820Sjeff		p_mgrp = NULL;
756219820Sjeff		goto _out;
757219820Sjeff	}
758219820Sjeff
759219820Sjeff	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
760219820Sjeff	    | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
761219820Sjeff	if (osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
762219820Sjeff						 comp_mask, p_mcm_rec,
763219820Sjeff						 &p_mgrp) != IB_SUCCESS ||
764219820Sjeff	    !p_mgrp || p_mgrp->mlid != mlid) {
765219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
766219820Sjeff			"cannot create MC group with mlid 0x%04x and mgid "
767219820Sjeff			"0x%016" PRIx64 ":0x%016" PRIx64 "\n", cl_ntoh16(mlid),
768219820Sjeff			cl_ntoh64(p_mcm_rec->mgid.unicast.prefix),
769219820Sjeff			cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id));
770219820Sjeff		p_mgrp = NULL;
771219820Sjeff	} else if (well_known)
772219820Sjeff		p_mgrp->well_known = TRUE;
773219820Sjeff
774219820Sjeff_out:
775219820Sjeff	cl_plock_release(&p_osm->lock);
776219820Sjeff
777219820Sjeff	return p_mgrp;
778219820Sjeff}
779219820Sjeff
780219820Sjeffstatic int load_svcr(osm_opensm_t * p_osm, ib_service_record_t * sr,
781219820Sjeff		     uint32_t modified_time, uint32_t lease_period)
782219820Sjeff{
783219820Sjeff	osm_svcr_t *p_svcr;
784219820Sjeff	int ret = 0;
785219820Sjeff
786219820Sjeff	cl_plock_excl_acquire(&p_osm->lock);
787219820Sjeff
788219820Sjeff	if (osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) {
789219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
790219820Sjeff			"ServiceRecord already exists\n");
791219820Sjeff		goto _out;
792219820Sjeff	}
793219820Sjeff
794219820Sjeff	if (!(p_svcr = osm_svcr_new(sr))) {
795219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
796219820Sjeff			"cannot allocate new service struct\n");
797219820Sjeff		ret = -1;
798219820Sjeff		goto _out;
799219820Sjeff	}
800219820Sjeff
801219820Sjeff	p_svcr->modified_time = modified_time;
802219820Sjeff	p_svcr->lease_period = lease_period;
803219820Sjeff
804219820Sjeff	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding ServiceRecord...\n");
805219820Sjeff
806219820Sjeff	osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr);
807219820Sjeff
808219820Sjeff	if (lease_period != 0xffffffff)
809219820Sjeff		cl_timer_trim(&p_osm->sa.sr_timer, 1000);
810219820Sjeff
811219820Sjeff_out:
812219820Sjeff	cl_plock_release(&p_osm->lock);
813219820Sjeff
814219820Sjeff	return ret;
815219820Sjeff}
816219820Sjeff
817219820Sjeffstatic int load_infr(osm_opensm_t * p_osm, ib_inform_info_record_t * iir,
818219820Sjeff		     osm_mad_addr_t * addr)
819219820Sjeff{
820219820Sjeff	osm_infr_t infr, *p_infr;
821219820Sjeff	int ret = 0;
822219820Sjeff
823219820Sjeff	infr.h_bind = p_osm->sa.mad_ctrl.h_bind;
824219820Sjeff	infr.sa = &p_osm->sa;
825219820Sjeff	/* other possible way to restore mad_addr partially is
826219820Sjeff	   to extract qpn from InformInfo and to find lid by gid */
827219820Sjeff	infr.report_addr = *addr;
828219820Sjeff	infr.inform_record = *iir;
829219820Sjeff
830219820Sjeff	cl_plock_excl_acquire(&p_osm->lock);
831219820Sjeff	if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) {
832219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
833219820Sjeff			"InformInfo Record already exists\n");
834219820Sjeff		goto _out;
835219820Sjeff	}
836219820Sjeff
837219820Sjeff	if (!(p_infr = osm_infr_new(&infr))) {
838219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
839219820Sjeff			"cannot allocate new infr struct\n");
840219820Sjeff		ret = -1;
841219820Sjeff		goto _out;
842219820Sjeff	}
843219820Sjeff
844219820Sjeff	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding InformInfo Record...\n");
845219820Sjeff
846219820Sjeff	osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr);
847219820Sjeff
848219820Sjeff_out:
849219820Sjeff	cl_plock_release(&p_osm->lock);
850219820Sjeff
851219820Sjeff	return ret;
852219820Sjeff}
853219820Sjeff
854219820Sjeff#define UNPACK_FUNC(name,x) \
855219820Sjeffstatic int unpack_##name##x(char *p, uint##x##_t *val_ptr) \
856219820Sjeff{ \
857219820Sjeff	char *q; \
858219820Sjeff	unsigned long long num; \
859219820Sjeff	num = strtoull(p, &q, 16); \
860219820Sjeff	if (num > ~((uint##x##_t)0x0) \
861219820Sjeff	    || q == p || (!isspace(*q) && *q != ':')) { \
862219820Sjeff		*val_ptr = 0; \
863219820Sjeff		return -1; \
864219820Sjeff	} \
865219820Sjeff	*val_ptr = cl_hton##x((uint##x##_t)num); \
866219820Sjeff	return (int)(q - p); \
867219820Sjeff}
868219820Sjeff
869219820Sjeff#define cl_hton8(x) (x)
870219820Sjeff
871219820SjeffUNPACK_FUNC(net, 8);
872219820SjeffUNPACK_FUNC(net, 16);
873219820SjeffUNPACK_FUNC(net, 32);
874219820SjeffUNPACK_FUNC(net, 64);
875219820Sjeff
876219820Sjeffstatic int unpack_string(char *p, uint8_t * buf, unsigned len)
877219820Sjeff{
878219820Sjeff	char *q = p;
879219820Sjeff	char delim = ' ';
880219820Sjeff
881219820Sjeff	if (*q == '\'' || *q == '\"')
882219820Sjeff		delim = *q++;
883219820Sjeff	while (--len && *q && *q != delim)
884219820Sjeff		*buf++ = *q++;
885219820Sjeff	*buf = '\0';
886219820Sjeff	if (*q == delim && delim != ' ')
887219820Sjeff		q++;
888219820Sjeff	return (int)(q - p);
889219820Sjeff}
890219820Sjeff
891219820Sjeffstatic int unpack_string64(char *p, uint8_t * buf)
892219820Sjeff{
893219820Sjeff	return unpack_string(p, buf, 64);
894219820Sjeff}
895219820Sjeff
896219820Sjeff#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \
897219820Sjeff	p = strstr(p, name); \
898219820Sjeff	if (!p) { \
899219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
900219820Sjeff			"PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \
901219820Sjeff			file_name, lineno, (name)); \
902219820Sjeff		ret = -2; \
903219820Sjeff		goto _error; \
904219820Sjeff	} \
905219820Sjeff	p += strlen(name); \
906219820Sjeff	_ret = unpack_##x(p, (val_ptr)); \
907219820Sjeff	if (_ret < 0) { \
908219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
909219820Sjeff			"PARSE ERROR: %s:%u: cannot parse "#x" value " \
910219820Sjeff			"after \"%s\"\n", file_name, lineno, (name)); \
911219820Sjeff		ret = _ret; \
912219820Sjeff		goto _error; \
913219820Sjeff	} \
914219820Sjeff	p += _ret; \
915219820Sjeff}
916219820Sjeff
917219820Sjeffint osm_sa_db_file_load(osm_opensm_t * p_osm)
918219820Sjeff{
919219820Sjeff	char line[1024];
920219820Sjeff	char *file_name;
921219820Sjeff	FILE *file;
922219820Sjeff	int ret = 0;
923219820Sjeff	osm_mgrp_t *p_mgrp = NULL;
924219820Sjeff	unsigned rereg_clients = 0;
925219820Sjeff	unsigned lineno;
926219820Sjeff
927219820Sjeff	file_name = p_osm->subn.opt.sa_db_file;
928219820Sjeff	if (!file_name) {
929219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
930219820Sjeff			"sa db file name is not specifed. Skip restore\n");
931219820Sjeff		return 0;
932219820Sjeff	}
933219820Sjeff
934219820Sjeff	file = fopen(file_name, "r");
935219820Sjeff	if (!file) {
936219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: "
937219820Sjeff			"cannot open sa db file \'%s\'. Skip restoring\n",
938219820Sjeff			file_name);
939219820Sjeff		return -1;
940219820Sjeff	}
941219820Sjeff
942219820Sjeff	lineno = 0;
943219820Sjeff
944219820Sjeff	while (fgets(line, sizeof(line) - 1, file) != NULL) {
945219820Sjeff		char *p;
946219820Sjeff		uint8_t val;
947219820Sjeff
948219820Sjeff		lineno++;
949219820Sjeff
950219820Sjeff		p = line;
951219820Sjeff		while (isspace(*p))
952219820Sjeff			p++;
953219820Sjeff
954219820Sjeff		if (*p == '#')
955219820Sjeff			continue;
956219820Sjeff
957219820Sjeff		if (!strncmp(p, "MC Group", 8)) {
958219820Sjeff			ib_member_rec_t mcm_rec;
959219820Sjeff			ib_net16_t mlid;
960219820Sjeff			unsigned well_known = 0;
961219820Sjeff
962219820Sjeff			p_mgrp = NULL;
963219820Sjeff			memset(&mcm_rec, 0, sizeof(mcm_rec));
964219820Sjeff
965219820Sjeff			PARSE_AHEAD(p, net16, " 0x", &mlid);
966219820Sjeff			if (strstr(p, "well known"))
967219820Sjeff				well_known = 1;
968219820Sjeff			PARSE_AHEAD(p, net64, " mgid=0x",
969219820Sjeff				    &mcm_rec.mgid.unicast.prefix);
970219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
971219820Sjeff				    &mcm_rec.mgid.unicast.interface_id);
972219820Sjeff			PARSE_AHEAD(p, net64, " port_gid=0x",
973219820Sjeff				    &mcm_rec.port_gid.unicast.prefix);
974219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
975219820Sjeff				    &mcm_rec.port_gid.unicast.interface_id);
976219820Sjeff			PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey);
977219820Sjeff			PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid);
978219820Sjeff			PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu);
979219820Sjeff			PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass);
980219820Sjeff			PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey);
981219820Sjeff			PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate);
982219820Sjeff			PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life);
983219820Sjeff			PARSE_AHEAD(p, net32, " sl_flow_hop=0x",
984219820Sjeff				    &mcm_rec.sl_flow_hop);
985219820Sjeff			PARSE_AHEAD(p, net8, " scope_state=0x",
986219820Sjeff				    &mcm_rec.scope_state);
987219820Sjeff			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
988219820Sjeff			mcm_rec.proxy_join = val;
989219820Sjeff
990219820Sjeff			p_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec,
991219820Sjeff					      well_known);
992219820Sjeff			if (!p_mgrp)
993219820Sjeff				rereg_clients = 1;
994219820Sjeff		} else if (p_mgrp && !strncmp(p, "mcm_port", 8)) {
995219820Sjeff			ib_gid_t port_gid;
996219820Sjeff			ib_net64_t guid;
997219820Sjeff			uint8_t scope_state;
998219820Sjeff			boolean_t proxy_join;
999219820Sjeff
1000219820Sjeff			PARSE_AHEAD(p, net64, " port_gid=0x",
1001219820Sjeff				    &port_gid.unicast.prefix);
1002219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1003219820Sjeff				    &port_gid.unicast.interface_id);
1004219820Sjeff			PARSE_AHEAD(p, net8, " scope_state=0x", &scope_state);
1005219820Sjeff			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1006219820Sjeff			proxy_join = val;
1007219820Sjeff
1008219820Sjeff			guid = port_gid.unicast.interface_id;
1009219820Sjeff			if (cl_qmap_get(&p_mgrp->mcm_port_tbl,
1010219820Sjeff					port_gid.unicast.interface_id) ==
1011219820Sjeff			    cl_qmap_end(&p_mgrp->mcm_port_tbl))
1012219820Sjeff				osm_mgrp_add_port(&p_osm->subn, &p_osm->log,
1013219820Sjeff						  p_mgrp, &port_gid,
1014219820Sjeff						  scope_state, proxy_join);
1015219820Sjeff		} else if (!strncmp(p, "Service Record:", 15)) {
1016219820Sjeff			ib_service_record_t s_rec;
1017219820Sjeff			uint32_t modified_time, lease_period;
1018219820Sjeff
1019219820Sjeff			p_mgrp = NULL;
1020219820Sjeff			memset(&s_rec, 0, sizeof(s_rec));
1021219820Sjeff
1022219820Sjeff			PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id);
1023219820Sjeff			PARSE_AHEAD(p, net64, " gid=0x",
1024219820Sjeff				    &s_rec.service_gid.unicast.prefix);
1025219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1026219820Sjeff				    &s_rec.service_gid.unicast.interface_id);
1027219820Sjeff			PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey);
1028219820Sjeff			PARSE_AHEAD(p, net32, " lease=0x",
1029219820Sjeff				    &s_rec.service_lease);
1030219820Sjeff			PARSE_AHEAD(p, net64, " key=0x",
1031219820Sjeff				    (ib_net64_t *) (&s_rec.service_key[0]));
1032219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1033219820Sjeff				    (ib_net64_t *) (&s_rec.service_key[8]));
1034219820Sjeff			PARSE_AHEAD(p, string64, " name=", s_rec.service_name);
1035219820Sjeff			PARSE_AHEAD(p, net64, " data8=0x",
1036219820Sjeff				    (ib_net64_t *) (&s_rec.service_data8[0]));
1037219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1038219820Sjeff				    (ib_net64_t *) (&s_rec.service_data8[8]));
1039219820Sjeff			PARSE_AHEAD(p, net64, " data16=0x",
1040219820Sjeff				    (ib_net64_t *) (&s_rec.service_data16[0]));
1041219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1042219820Sjeff				    (ib_net64_t *) (&s_rec.service_data16[4]));
1043219820Sjeff			PARSE_AHEAD(p, net64, " data32=0x",
1044219820Sjeff				    (ib_net64_t *) (&s_rec.service_data32[0]));
1045219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1046219820Sjeff				    (ib_net64_t *) (&s_rec.service_data32[2]));
1047219820Sjeff			PARSE_AHEAD(p, net64, " data64=0x",
1048219820Sjeff				    &s_rec.service_data64[0]);
1049219820Sjeff			PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]);
1050219820Sjeff			PARSE_AHEAD(p, net32, " modified_time=0x",
1051219820Sjeff				    &modified_time);
1052219820Sjeff			PARSE_AHEAD(p, net32, " lease_period=0x",
1053219820Sjeff				    &lease_period);
1054219820Sjeff
1055219820Sjeff			if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time),
1056219820Sjeff				      cl_ntoh32(lease_period)))
1057219820Sjeff				rereg_clients = 1;
1058219820Sjeff		} else if (!strncmp(p, "InformInfo Record:", 18)) {
1059219820Sjeff			ib_inform_info_record_t i_rec;
1060219820Sjeff			osm_mad_addr_t rep_addr;
1061219820Sjeff			ib_net16_t val16;
1062219820Sjeff
1063219820Sjeff			p_mgrp = NULL;
1064219820Sjeff			memset(&i_rec, 0, sizeof(i_rec));
1065219820Sjeff			memset(&rep_addr, 0, sizeof(rep_addr));
1066219820Sjeff
1067219820Sjeff			PARSE_AHEAD(p, net64, " subscriber_gid=0x",
1068219820Sjeff				    &i_rec.subscriber_gid.unicast.prefix);
1069219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1070219820Sjeff				    &i_rec.subscriber_gid.unicast.interface_id);
1071219820Sjeff			PARSE_AHEAD(p, net16, " subscriber_enum=0x",
1072219820Sjeff				    &i_rec.subscriber_enum);
1073219820Sjeff			PARSE_AHEAD(p, net64, " gid=0x",
1074219820Sjeff				    &i_rec.inform_info.gid.unicast.prefix);
1075219820Sjeff			PARSE_AHEAD(p, net64, ":0x",
1076219820Sjeff				    &i_rec.inform_info.gid.unicast.
1077219820Sjeff				    interface_id);
1078219820Sjeff			PARSE_AHEAD(p, net16, " lid_range_begin=0x",
1079219820Sjeff				    &i_rec.inform_info.lid_range_begin);
1080219820Sjeff			PARSE_AHEAD(p, net16, " lid_range_end=0x",
1081219820Sjeff				    &i_rec.inform_info.lid_range_end);
1082219820Sjeff			PARSE_AHEAD(p, net8, " is_generic=0x",
1083219820Sjeff				    &i_rec.inform_info.is_generic);
1084219820Sjeff			PARSE_AHEAD(p, net8, " subscribe=0x",
1085219820Sjeff				    &i_rec.inform_info.subscribe);
1086219820Sjeff			PARSE_AHEAD(p, net16, " trap_type=0x",
1087219820Sjeff				    &i_rec.inform_info.trap_type);
1088219820Sjeff			PARSE_AHEAD(p, net16, " trap_num=0x",
1089219820Sjeff				    &i_rec.inform_info.g_or_v.generic.trap_num);
1090219820Sjeff			PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x",
1091219820Sjeff				    &i_rec.inform_info.g_or_v.generic.
1092219820Sjeff				    qpn_resp_time_val);
1093219820Sjeff			PARSE_AHEAD(p, net32, " node_type=0x",
1094219820Sjeff				    (uint32_t *) & i_rec.inform_info.g_or_v.
1095219820Sjeff				    generic.reserved2);
1096219820Sjeff
1097219820Sjeff			PARSE_AHEAD(p, net16, " rep_addr: lid=0x",
1098219820Sjeff				    &rep_addr.dest_lid);
1099219820Sjeff			PARSE_AHEAD(p, net8, " path_bits=0x",
1100219820Sjeff				    &rep_addr.path_bits);
1101219820Sjeff			PARSE_AHEAD(p, net8, " static_rate=0x",
1102219820Sjeff				    &rep_addr.static_rate);
1103219820Sjeff			PARSE_AHEAD(p, net32, " remote_qp=0x",
1104219820Sjeff				    &rep_addr.addr_type.gsi.remote_qp);
1105219820Sjeff			PARSE_AHEAD(p, net32, " remote_qkey=0x",
1106219820Sjeff				    &rep_addr.addr_type.gsi.remote_qkey);
1107219820Sjeff			PARSE_AHEAD(p, net16, " pkey_ix=0x", &val16);
1108219820Sjeff			rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16);
1109219820Sjeff			PARSE_AHEAD(p, net8, " sl=0x",
1110219820Sjeff				    &rep_addr.addr_type.gsi.service_level);
1111219820Sjeff
1112219820Sjeff			if (load_infr(p_osm, &i_rec, &rep_addr))
1113219820Sjeff				rereg_clients = 1;
1114219820Sjeff		}
1115219820Sjeff	}
1116219820Sjeff
1117219820Sjeff	if (!rereg_clients)
1118219820Sjeff		p_osm->subn.opt.no_clients_rereg = TRUE;
1119219820Sjeff
1120219820Sjeff_error:
1121219820Sjeff	fclose(file);
1122219820Sjeff	return ret;
1123219820Sjeff}
1124