1/*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2014 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37/*
38 * Abstract:
39 *    Implementation of osm_sa_t.
40 * This object represents the Subnet Administration object.
41 * This object is part of the opensm family of objects.
42 */
43
44#if HAVE_CONFIG_H
45#  include <config.h>
46#endif				/* HAVE_CONFIG_H */
47
48#include <string.h>
49#include <ctype.h>
50#include <errno.h>
51#include <stdlib.h>
52#include <unistd.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <complib/cl_qmap.h>
56#include <complib/cl_passivelock.h>
57#include <complib/cl_debug.h>
58#include <iba/ib_types.h>
59#include <opensm/osm_file_ids.h>
60#define FILE_ID OSM_FILE_SA_C
61#include <opensm/osm_sa.h>
62#include <opensm/osm_madw.h>
63#include <opensm/osm_log.h>
64#include <opensm/osm_subnet.h>
65#include <opensm/osm_mad_pool.h>
66#include <opensm/osm_msgdef.h>
67#include <opensm/osm_opensm.h>
68#include <opensm/osm_multicast.h>
69#include <opensm/osm_inform.h>
70#include <opensm/osm_service.h>
71#include <opensm/osm_guid.h>
72#include <opensm/osm_helper.h>
73#include <vendor/osm_vendor_api.h>
74
75#define  OSM_SA_INITIAL_TID_VALUE 0xabc
76
77extern void osm_cpi_rcv_process(IN void *context, IN void *data);
78extern void osm_gir_rcv_process(IN void *context, IN void *data);
79extern void osm_infr_rcv_process(IN void *context, IN void *data);
80extern void osm_infir_rcv_process(IN void *context, IN void *data);
81extern void osm_lftr_rcv_process(IN void *context, IN void *data);
82extern void osm_lr_rcv_process(IN void *context, IN void *data);
83extern void osm_mcmr_rcv_process(IN void *context, IN void *data);
84extern void osm_mftr_rcv_process(IN void *context, IN void *data);
85extern void osm_mpr_rcv_process(IN void *context, IN void *data);
86extern void osm_nr_rcv_process(IN void *context, IN void *data);
87extern void osm_pr_rcv_process(IN void *context, IN void *data);
88extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
89extern void osm_pir_rcv_process(IN void *context, IN void *data);
90extern void osm_sr_rcv_process(IN void *context, IN void *data);
91extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
92extern void osm_smir_rcv_process(IN void *context, IN void *data);
93extern void osm_sir_rcv_process(IN void *context, IN void *data);
94extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
95extern void osm_sr_rcv_lease_cb(IN void *context);
96
97void osm_sa_construct(IN osm_sa_t * p_sa)
98{
99	memset(p_sa, 0, sizeof(*p_sa));
100	p_sa->state = OSM_SA_STATE_INIT;
101	p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE;
102
103	cl_timer_construct(&p_sa->sr_timer);
104}
105
106void osm_sa_shutdown(IN osm_sa_t * p_sa)
107{
108	OSM_LOG_ENTER(p_sa->p_log);
109
110	cl_timer_stop(&p_sa->sr_timer);
111
112	/* unbind from the mad service */
113	osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl);
114
115	/* remove any registered dispatcher message */
116	cl_disp_unregister(p_sa->nr_disp_h);
117	cl_disp_unregister(p_sa->pir_disp_h);
118	cl_disp_unregister(p_sa->gir_disp_h);
119	cl_disp_unregister(p_sa->lr_disp_h);
120	cl_disp_unregister(p_sa->pr_disp_h);
121#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
122	cl_disp_unregister(p_sa->mpr_disp_h);
123#endif
124	cl_disp_unregister(p_sa->smir_disp_h);
125	cl_disp_unregister(p_sa->mcmr_disp_h);
126	cl_disp_unregister(p_sa->sr_disp_h);
127	cl_disp_unregister(p_sa->infr_disp_h);
128	cl_disp_unregister(p_sa->infir_disp_h);
129	cl_disp_unregister(p_sa->vlarb_disp_h);
130	cl_disp_unregister(p_sa->slvl_disp_h);
131	cl_disp_unregister(p_sa->pkey_disp_h);
132	cl_disp_unregister(p_sa->lft_disp_h);
133	cl_disp_unregister(p_sa->sir_disp_h);
134	cl_disp_unregister(p_sa->mft_disp_h);
135
136	if (p_sa->p_set_disp) {
137		cl_disp_unregister(p_sa->mcmr_set_disp_h);
138		cl_disp_unregister(p_sa->infr_set_disp_h);
139		cl_disp_unregister(p_sa->sr_set_disp_h);
140		cl_disp_unregister(p_sa->gir_set_disp_h);
141	}
142
143	osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl);
144
145	OSM_LOG_EXIT(p_sa->p_log);
146}
147
148void osm_sa_destroy(IN osm_sa_t * p_sa)
149{
150	OSM_LOG_ENTER(p_sa->p_log);
151
152	p_sa->state = OSM_SA_STATE_INIT;
153
154	cl_timer_destroy(&p_sa->sr_timer);
155
156	OSM_LOG_EXIT(p_sa->p_log);
157}
158
159ib_api_status_t osm_sa_init(IN osm_sm_t * p_sm, IN osm_sa_t * p_sa,
160			    IN osm_subn_t * p_subn, IN osm_vendor_t * p_vendor,
161			    IN osm_mad_pool_t * p_mad_pool,
162			    IN osm_log_t * p_log, IN osm_stats_t * p_stats,
163			    IN cl_dispatcher_t * p_disp,
164			    IN cl_dispatcher_t * p_set_disp,
165			    IN cl_plock_t * p_lock)
166{
167	ib_api_status_t status;
168
169	OSM_LOG_ENTER(p_log);
170
171	p_sa->sm = p_sm;
172	p_sa->p_subn = p_subn;
173	p_sa->p_vendor = p_vendor;
174	p_sa->p_mad_pool = p_mad_pool;
175	p_sa->p_log = p_log;
176	p_sa->p_disp = p_disp;
177	p_sa->p_set_disp = p_set_disp;
178	p_sa->p_lock = p_lock;
179
180	p_sa->state = OSM_SA_STATE_READY;
181
182	status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl, p_sa, p_sa->p_mad_pool,
183				      p_sa->p_vendor, p_subn, p_log, p_stats,
184				      p_disp, p_set_disp);
185	if (status != IB_SUCCESS)
186		goto Exit;
187
188	status = cl_timer_init(&p_sa->sr_timer, osm_sr_rcv_lease_cb, p_sa);
189	if (status != IB_SUCCESS)
190		goto Exit;
191
192	status = IB_INSUFFICIENT_RESOURCES;
193	p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO,
194					    osm_cpi_rcv_process, p_sa);
195	if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE)
196		goto Exit;
197
198	p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD,
199					   osm_nr_rcv_process, p_sa);
200	if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE)
201		goto Exit;
202
203	p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD,
204					    osm_pir_rcv_process, p_sa);
205	if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE)
206		goto Exit;
207
208	p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
209					    osm_gir_rcv_process, p_sa);
210	if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE)
211		goto Exit;
212
213	p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD,
214					   osm_lr_rcv_process, p_sa);
215	if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE)
216		goto Exit;
217
218	p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD,
219					   osm_pr_rcv_process, p_sa);
220	if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE)
221		goto Exit;
222
223#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
224	p_sa->mpr_disp_h =
225	    cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD,
226			     osm_mpr_rcv_process, p_sa);
227	if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE)
228		goto Exit;
229#endif
230
231	p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD,
232					     osm_smir_rcv_process, p_sa);
233	if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE)
234		goto Exit;
235
236	p_sa->mcmr_disp_h =
237	    cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
238			     osm_mcmr_rcv_process, p_sa);
239	if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE)
240		goto Exit;
241
242	p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD,
243					   osm_sr_rcv_process, p_sa);
244	if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE)
245		goto Exit;
246
247	p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO,
248					     osm_infr_rcv_process, p_sa);
249	if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE)
250		goto Exit;
251
252	p_sa->infir_disp_h =
253	    cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD,
254			     osm_infir_rcv_process, p_sa);
255	if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE)
256		goto Exit;
257
258	p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD,
259					      osm_vlarb_rec_rcv_process, p_sa);
260	if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE)
261		goto Exit;
262
263	p_sa->slvl_disp_h =
264	    cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD,
265			     osm_slvl_rec_rcv_process, p_sa);
266	if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE)
267		goto Exit;
268
269	p_sa->pkey_disp_h =
270	    cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD,
271			     osm_pkey_rec_rcv_process, p_sa);
272	if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE)
273		goto Exit;
274
275	p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD,
276					    osm_lftr_rcv_process, p_sa);
277	if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE)
278		goto Exit;
279
280	p_sa->sir_disp_h =
281	    cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD,
282			     osm_sir_rcv_process, p_sa);
283	if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE)
284		goto Exit;
285
286	p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD,
287					    osm_mftr_rcv_process, p_sa);
288	if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE)
289		goto Exit;
290
291	/*
292	 * When p_set_disp is defined, it means that we use different dispatcher
293	 * for SA Set requests, and we need to register handlers for it.
294	 */
295	if (p_set_disp) {
296		p_sa->gir_set_disp_h =
297		    cl_disp_register(p_set_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
298				     osm_gir_rcv_process, p_sa);
299		if (p_sa->gir_set_disp_h == CL_DISP_INVALID_HANDLE)
300			goto Exit;
301
302		p_sa->mcmr_set_disp_h =
303		    cl_disp_register(p_set_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
304				     osm_mcmr_rcv_process, p_sa);
305		if (p_sa->mcmr_set_disp_h == CL_DISP_INVALID_HANDLE)
306			goto Exit;
307
308		p_sa->sr_set_disp_h =
309		    cl_disp_register(p_set_disp, OSM_MSG_MAD_SERVICE_RECORD,
310				     osm_sr_rcv_process, p_sa);
311		if (p_sa->sr_set_disp_h == CL_DISP_INVALID_HANDLE)
312			goto Exit;
313
314		p_sa->infr_set_disp_h =
315		    cl_disp_register(p_set_disp, OSM_MSG_MAD_INFORM_INFO,
316				     osm_infr_rcv_process, p_sa);
317		if (p_sa->infr_set_disp_h == CL_DISP_INVALID_HANDLE)
318			goto Exit;
319	}
320
321	status = IB_SUCCESS;
322Exit:
323	OSM_LOG_EXIT(p_log);
324	return status;
325}
326
327ib_api_status_t osm_sa_bind(IN osm_sa_t * p_sa, IN ib_net64_t port_guid)
328{
329	ib_api_status_t status;
330
331	OSM_LOG_ENTER(p_sa->p_log);
332
333	status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid);
334
335	if (status != IB_SUCCESS) {
336		OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: "
337			"SA MAD Controller bind failed (%s)\n",
338			ib_get_err_str(status));
339		goto Exit;
340	}
341
342Exit:
343	OSM_LOG_EXIT(p_sa->p_log);
344	return status;
345}
346
347ib_api_status_t osm_sa_send(osm_sa_t *sa, IN osm_madw_t * p_madw,
348			    IN boolean_t resp_expected)
349{
350	ib_api_status_t status;
351
352	cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent);
353	status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected);
354	if (status != IB_SUCCESS) {
355		cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent);
356		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: "
357			"osm_vendor_send failed, status = %s\n",
358			ib_get_err_str(status));
359	}
360	return status;
361}
362
363void osm_sa_send_error(IN osm_sa_t * sa, IN const osm_madw_t * p_madw,
364		       IN ib_net16_t sa_status)
365{
366	osm_madw_t *p_resp_madw;
367	ib_sa_mad_t *p_resp_sa_mad;
368	ib_sa_mad_t *p_sa_mad;
369
370	OSM_LOG_ENTER(sa->p_log);
371
372	/* avoid races - if we are exiting - exit */
373	if (osm_exit_flag) {
374		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
375			"Ignoring requested send after exit\n");
376		goto Exit;
377	}
378
379	p_resp_madw = osm_mad_pool_get(sa->p_mad_pool,
380				       p_madw->h_bind, MAD_BLOCK_SIZE,
381				       &p_madw->mad_addr);
382
383	if (p_resp_madw == NULL) {
384		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: "
385			"Unable to acquire response MAD\n");
386		goto Exit;
387	}
388
389	p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
390	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
391
392	/*  Copy the MAD header back into the response mad */
393	*p_resp_sa_mad = *p_sa_mad;
394	p_resp_sa_mad->status = sa_status;
395
396	if (p_resp_sa_mad->method == IB_MAD_METHOD_SET)
397		p_resp_sa_mad->method = IB_MAD_METHOD_GET;
398	else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE)
399		p_resp_sa_mad->attr_offset = 0;
400
401	p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
402
403	/*
404	 * C15-0.1.5 - always return SM_Key = 0 (table 185 p 884)
405	 */
406	p_resp_sa_mad->sm_key = 0;
407
408	/*
409	 * o15-0.2.7 - The PathRecord Attribute ID shall be used in
410	 * the response (to a SubnAdmGetMulti(MultiPathRecord)
411	 */
412	if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD)
413		p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
414
415	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_FRAMES))
416		osm_dump_sa_mad_v2(sa->p_log, p_resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
417
418	osm_sa_send(sa, p_resp_madw, FALSE);
419
420Exit:
421	OSM_LOG_EXIT(sa->p_log);
422}
423
424void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size,
425		    cl_qlist_t *list)
426{
427	cl_list_item_t *item;
428	osm_madw_t *resp_madw;
429	ib_sa_mad_t *sa_mad, *resp_sa_mad;
430	unsigned num_rec, i;
431#ifndef VENDOR_RMPP_SUPPORT
432	unsigned trim_num_rec;
433#endif
434	unsigned char *p;
435
436	sa_mad = osm_madw_get_sa_mad_ptr(madw);
437	num_rec = cl_qlist_count(list);
438
439	/*
440	 * C15-0.1.30:
441	 * If we do a SubnAdmGet and got more than one record it is an error!
442	 */
443	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) {
444		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: "
445			"Got %u records for SubnAdmGet(%s) comp_mask 0x%016" PRIx64
446			"from requester LID %u\n",
447			num_rec, ib_get_sa_attr_str(sa_mad->attr_id),
448			cl_ntoh64(sa_mad->comp_mask),
449			cl_ntoh16(madw->mad_addr.dest_lid));
450		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS);
451		goto Exit;
452	}
453
454#ifndef VENDOR_RMPP_SUPPORT
455	trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size;
456	if (trim_num_rec < num_rec) {
457		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
458			"Number of records:%u trimmed to:%u to fit in one MAD\n",
459			num_rec, trim_num_rec);
460		num_rec = trim_num_rec;
461	}
462#endif
463
464	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec);
465
466	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) {
467		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS);
468		goto Exit;
469	}
470
471	/*
472	 * Get a MAD to reply. Address of Mad is in the received mad_wrapper
473	 */
474	resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind,
475				     num_rec * attr_size + IB_SA_MAD_HDR_SIZE,
476				     &madw->mad_addr);
477	if (!resp_madw) {
478		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: "
479			"osm_mad_pool_get failed\n");
480		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES);
481		goto Exit;
482	}
483
484	resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw);
485
486	/*
487	   Copy the MAD header back into the response mad.
488	   Set the 'R' bit and the payload length,
489	   Then copy all records from the list into the response payload.
490	 */
491
492	memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE);
493	if (resp_sa_mad->method == IB_MAD_METHOD_SET)
494		resp_sa_mad->method = IB_MAD_METHOD_GET;
495	resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
496	/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
497	resp_sa_mad->sm_key = 0;
498
499	/* Fill in the offset (paylen will be done by the rmpp SAR) */
500	resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0;
501
502	p = ib_sa_mad_get_payload_ptr(resp_sa_mad);
503
504#ifndef VENDOR_RMPP_SUPPORT
505	/* we support only one packet RMPP - so we will set the first and
506	   last flags for gettable */
507	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) {
508		resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
509		resp_sa_mad->rmpp_flags =
510		    IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST |
511		    IB_RMPP_FLAG_ACTIVE;
512	}
513#else
514	/* forcefully define the packet as RMPP one */
515	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
516		resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
517#endif
518
519	for (i = 0; i < num_rec; i++) {
520		item = cl_qlist_remove_head(list);
521		memcpy(p, ((osm_sa_item_t *)item)->resp.data, attr_size);
522		p += attr_size;
523		free(item);
524	}
525
526	osm_dump_sa_mad_v2(sa->p_log, resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
527	osm_sa_send(sa, resp_madw, FALSE);
528
529Exit:
530	/* need to set the mem free ... */
531	item = cl_qlist_remove_head(list);
532	while (item != cl_qlist_end(list)) {
533		free(item);
534		item = cl_qlist_remove_head(list);
535	}
536}
537
538/*
539 *  SA DB Dumper
540 *
541 */
542
543struct opensm_dump_context {
544	osm_opensm_t *p_osm;
545	FILE *file;
546};
547
548static int
549opensm_dump_to_file(osm_opensm_t * p_osm, const char *file_name,
550		    void (*dump_func) (osm_opensm_t * p_osm, FILE * file))
551{
552	char path[1024];
553	char path_tmp[1032];
554	FILE *file;
555	int fd, status = 0;
556
557	snprintf(path, sizeof(path), "%s/%s",
558		 p_osm->subn.opt.dump_files_dir, file_name);
559
560	snprintf(path_tmp, sizeof(path_tmp), "%s.tmp", path);
561
562	file = fopen(path_tmp, "w");
563	if (!file) {
564		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: "
565			"cannot open file \'%s\': %s\n",
566			path_tmp, strerror(errno));
567		return -1;
568	}
569
570	if (chmod(path_tmp, S_IRUSR | S_IWUSR)) {
571		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0C: "
572			"cannot change access permissions of file "
573			"\'%s\' : %s\n",
574			path_tmp, strerror(errno));
575		fclose(file);
576		return -1;
577	}
578
579	dump_func(p_osm, file);
580
581	if (p_osm->subn.opt.fsync_high_avail_files) {
582		if (fflush(file) == 0) {
583			fd = fileno(file);
584			if (fd != -1) {
585				if (fsync(fd) == -1)
586					OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
587						"ERR 4C08: fsync() failed (%s) for %s\n",
588						strerror(errno), path_tmp);
589			} else
590				OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C09: "
591					"fileno() failed for %s\n", path_tmp);
592		} else
593			OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0A: "
594				"fflush() failed (%s) for %s\n",
595				strerror(errno), path_tmp);
596	}
597
598	fclose(file);
599
600	status = rename(path_tmp, path);
601	if (status) {
602		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0B: "
603			"Failed to rename file:%s (err:%s)\n",
604			path_tmp, strerror(errno));
605	}
606
607	return status;
608}
609
610static void mcast_mgr_dump_one_port(cl_map_item_t * p_map_item, void *cxt)
611{
612	FILE *file = ((struct opensm_dump_context *)cxt)->file;
613	osm_mcm_alias_guid_t *p_mcm_alias_guid = (osm_mcm_alias_guid_t *) p_map_item;
614
615	fprintf(file, "mcm_port: "
616		"port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " "
617		"scope_state=0x%02x proxy_join=0x%x" "\n\n",
618		cl_ntoh64(p_mcm_alias_guid->port_gid.unicast.prefix),
619		cl_ntoh64(p_mcm_alias_guid->port_gid.unicast.interface_id),
620		p_mcm_alias_guid->scope_state, p_mcm_alias_guid->proxy_join);
621}
622
623static void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, void *cxt)
624{
625	struct opensm_dump_context dump_context;
626	osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm;
627	FILE *file = ((struct opensm_dump_context *)cxt)->file;
628
629	fprintf(file, "MC Group 0x%04x %s:"
630		" mgid=0x%016" PRIx64 ":0x%016" PRIx64
631		" port_gid=0x%016" PRIx64 ":0x%016" PRIx64
632		" qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x"
633		" pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x"
634		" scope_state=0x%02x proxy_join=0x%x" "\n\n",
635		cl_ntoh16(p_mgrp->mlid),
636		p_mgrp->well_known ? " (well known)" : "",
637		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
638		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id),
639		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix),
640		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id),
641		cl_ntoh32(p_mgrp->mcmember_rec.qkey),
642		cl_ntoh16(p_mgrp->mcmember_rec.mlid),
643		p_mgrp->mcmember_rec.mtu,
644		p_mgrp->mcmember_rec.tclass,
645		cl_ntoh16(p_mgrp->mcmember_rec.pkey),
646		p_mgrp->mcmember_rec.rate,
647		p_mgrp->mcmember_rec.pkt_life,
648		cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop),
649		p_mgrp->mcmember_rec.scope_state,
650		p_mgrp->mcmember_rec.proxy_join);
651
652	dump_context.p_osm = p_osm;
653	dump_context.file = file;
654
655	cl_qmap_apply_func(&p_mgrp->mcm_alias_port_tbl,
656			   mcast_mgr_dump_one_port, &dump_context);
657}
658
659static void sa_dump_one_inform(cl_list_item_t * p_list_item, void *cxt)
660{
661	FILE *file = ((struct opensm_dump_context *)cxt)->file;
662	osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
663	ib_inform_info_record_t *p_iir = &p_infr->inform_record;
664
665	fprintf(file, "InformInfo Record:"
666		" subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64
667		" subscriber_enum=0x%x"
668		" InformInfo:"
669		" gid=0x%016" PRIx64 ":0x%016" PRIx64
670		" lid_range_begin=0x%x"
671		" lid_range_end=0x%x"
672		" is_generic=0x%x"
673		" subscribe=0x%x"
674		" trap_type=0x%x"
675		" trap_num=0x%x"
676		" qpn_resp_time_val=0x%x"
677		" node_type=0x%06x"
678		" rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x"
679		" remote_qp=0x%08x remote_qkey=0x%08x pkey_ix=0x%04x sl=0x%02x"
680		"\n\n",
681		cl_ntoh64(p_iir->subscriber_gid.unicast.prefix),
682		cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id),
683		cl_ntoh16(p_iir->subscriber_enum),
684		cl_ntoh64(p_iir->inform_info.gid.unicast.prefix),
685		cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id),
686		cl_ntoh16(p_iir->inform_info.lid_range_begin),
687		cl_ntoh16(p_iir->inform_info.lid_range_end),
688		p_iir->inform_info.is_generic,
689		p_iir->inform_info.subscribe,
690		cl_ntoh16(p_iir->inform_info.trap_type),
691		cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num),
692		cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val),
693		cl_ntoh32(ib_inform_info_get_prod_type(&p_iir->inform_info)),
694		cl_ntoh16(p_infr->report_addr.dest_lid),
695		p_infr->report_addr.path_bits,
696		p_infr->report_addr.static_rate,
697		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp),
698		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey),
699		p_infr->report_addr.addr_type.gsi.pkey_ix,
700		p_infr->report_addr.addr_type.gsi.service_level);
701}
702
703static void sa_dump_one_service(cl_list_item_t * p_list_item, void *cxt)
704{
705	FILE *file = ((struct opensm_dump_context *)cxt)->file;
706	osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item;
707	ib_service_record_t *p_sr = &p_svcr->service_record;
708
709	fprintf(file, "Service Record: id=0x%016" PRIx64
710		" gid=0x%016" PRIx64 ":0x%016" PRIx64
711		" pkey=0x%x"
712		" lease=0x%x"
713		" key=0x%02x%02x%02x%02x%02x%02x%02x%02x"
714		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
715		" name=\'%s\'"
716		" data8=0x%02x%02x%02x%02x%02x%02x%02x%02x"
717		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
718		" data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x"
719		" data32=0x%08x%08x:0x%08x%08x"
720		" data64=0x%016" PRIx64 ":0x%016" PRIx64
721		" modified_time=0x%x lease_period=0x%x\n\n",
722		cl_ntoh64(p_sr->service_id),
723		cl_ntoh64(p_sr->service_gid.unicast.prefix),
724		cl_ntoh64(p_sr->service_gid.unicast.interface_id),
725		cl_ntoh16(p_sr->service_pkey),
726		cl_ntoh32(p_sr->service_lease),
727		p_sr->service_key[0], p_sr->service_key[1],
728		p_sr->service_key[2], p_sr->service_key[3],
729		p_sr->service_key[4], p_sr->service_key[5],
730		p_sr->service_key[6], p_sr->service_key[7],
731		p_sr->service_key[8], p_sr->service_key[9],
732		p_sr->service_key[10], p_sr->service_key[11],
733		p_sr->service_key[12], p_sr->service_key[13],
734		p_sr->service_key[14], p_sr->service_key[15],
735		p_sr->service_name,
736		p_sr->service_data8[0], p_sr->service_data8[1],
737		p_sr->service_data8[2], p_sr->service_data8[3],
738		p_sr->service_data8[4], p_sr->service_data8[5],
739		p_sr->service_data8[6], p_sr->service_data8[7],
740		p_sr->service_data8[8], p_sr->service_data8[9],
741		p_sr->service_data8[10], p_sr->service_data8[11],
742		p_sr->service_data8[12], p_sr->service_data8[13],
743		p_sr->service_data8[14], p_sr->service_data8[15],
744		cl_ntoh16(p_sr->service_data16[0]),
745		cl_ntoh16(p_sr->service_data16[1]),
746		cl_ntoh16(p_sr->service_data16[2]),
747		cl_ntoh16(p_sr->service_data16[3]),
748		cl_ntoh16(p_sr->service_data16[4]),
749		cl_ntoh16(p_sr->service_data16[5]),
750		cl_ntoh16(p_sr->service_data16[6]),
751		cl_ntoh16(p_sr->service_data16[7]),
752		cl_ntoh32(p_sr->service_data32[0]),
753		cl_ntoh32(p_sr->service_data32[1]),
754		cl_ntoh32(p_sr->service_data32[2]),
755		cl_ntoh32(p_sr->service_data32[3]),
756		cl_ntoh64(p_sr->service_data64[0]),
757		cl_ntoh64(p_sr->service_data64[1]),
758		p_svcr->modified_time, p_svcr->lease_period);
759}
760
761static void sa_dump_one_port_guidinfo(cl_map_item_t * p_map_item, void *cxt)
762{
763	FILE *file = ((struct opensm_dump_context *)cxt)->file;
764	osm_port_t *p_port = (osm_port_t *) p_map_item;
765	uint32_t max_block;
766	int block_num;
767
768	if (!p_port->p_physp->p_guids)
769		return;
770
771	max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
772		     GUID_TABLE_MAX_ENTRIES;
773
774	for (block_num = 0; block_num < max_block; block_num++) {
775		fprintf(file, "GUIDInfo Record:"
776			" base_guid=0x%016" PRIx64 " lid=0x%04x block_num=0x%x"
777			" guid0=0x%016" PRIx64 " guid1=0x%016" PRIx64
778			" guid2=0x%016" PRIx64 " guid3=0x%016" PRIx64
779			" guid4=0x%016" PRIx64 " guid5=0x%016" PRIx64
780			" guid6=0x%016" PRIx64 " guid7=0x%016" PRIx64
781			"\n\n",
782			cl_ntoh64((*p_port->p_physp->p_guids)[0]),
783			cl_ntoh16(osm_port_get_base_lid(p_port)), block_num,
784			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES]),
785			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 1]),
786			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 2]),
787			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 3]),
788			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 4]),
789			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 5]),
790			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 6]),
791			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 7]));
792	}
793}
794
795static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
796{
797	struct opensm_dump_context dump_context;
798	osm_mgrp_t *p_mgrp;
799
800	dump_context.p_osm = p_osm;
801	dump_context.file = file;
802	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump guidinfo\n");
803	cl_qmap_apply_func(&p_osm->subn.port_guid_tbl,
804			   sa_dump_one_port_guidinfo, &dump_context);
805	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast\n");
806	for (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&p_osm->subn.mgrp_mgid_tbl);
807	     p_mgrp != (osm_mgrp_t *) cl_fmap_end(&p_osm->subn.mgrp_mgid_tbl);
808	     p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item))
809		sa_dump_one_mgrp(p_mgrp, &dump_context);
810	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform\n");
811	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
812			    sa_dump_one_inform, &dump_context);
813	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump services\n");
814	cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
815			    sa_dump_one_service, &dump_context);
816}
817
818int osm_sa_db_file_dump(osm_opensm_t * p_osm)
819{
820	int res = 1;
821
822	cl_plock_acquire(&p_osm->lock);
823	if (p_osm->sa.dirty) {
824		res = opensm_dump_to_file(
825			p_osm, "opensm-sa.dump", sa_dump_all_sa);
826		if (!res)
827			p_osm->sa.dirty = FALSE;
828	}
829	cl_plock_release(&p_osm->lock);
830
831	return res;
832}
833
834/*
835 *  SA DB Loader
836 */
837static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
838				ib_member_rec_t * p_mcm_rec)
839{
840	ib_net64_t comp_mask;
841	osm_mgrp_t *p_mgrp;
842
843	cl_plock_excl_acquire(&p_osm->lock);
844
845	p_mgrp = osm_get_mgrp_by_mgid(&p_osm->subn, &p_mcm_rec->mgid);
846	if (p_mgrp) {
847		if (p_mgrp->mlid == mlid) {
848			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
849				"mgrp %04x is already here.", cl_ntoh16(mlid));
850			goto _out;
851		}
852		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
853			"mlid %04x is already used by another MC group. Will "
854			"request clients reregistration.\n", cl_ntoh16(mlid));
855		p_mgrp = NULL;
856		goto _out;
857	}
858
859	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
860	    | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
861	if (!(p_mgrp = osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
862							    comp_mask,
863							    p_mcm_rec)) ||
864	    p_mgrp->mlid != mlid) {
865		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
866			"cannot create MC group with mlid 0x%04x and mgid "
867			"0x%016" PRIx64 ":0x%016" PRIx64 "\n", cl_ntoh16(mlid),
868			cl_ntoh64(p_mcm_rec->mgid.unicast.prefix),
869			cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id));
870		p_mgrp = NULL;
871	}
872
873_out:
874	cl_plock_release(&p_osm->lock);
875
876	return p_mgrp;
877}
878
879static int load_svcr(osm_opensm_t * p_osm, ib_service_record_t * sr,
880		     uint32_t modified_time, uint32_t lease_period)
881{
882	osm_svcr_t *p_svcr;
883	int ret = 0;
884
885	cl_plock_excl_acquire(&p_osm->lock);
886
887	if (osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) {
888		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
889			"ServiceRecord already exists\n");
890		goto _out;
891	}
892
893	if (!(p_svcr = osm_svcr_new(sr))) {
894		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
895			"cannot allocate new service struct\n");
896		ret = -1;
897		goto _out;
898	}
899
900	p_svcr->modified_time = modified_time;
901	p_svcr->lease_period = lease_period;
902
903	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding ServiceRecord...\n");
904
905	osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr);
906
907	if (lease_period != 0xffffffff)
908		cl_timer_trim(&p_osm->sa.sr_timer, 1000);
909
910_out:
911	cl_plock_release(&p_osm->lock);
912
913	return ret;
914}
915
916static int load_infr(osm_opensm_t * p_osm, ib_inform_info_record_t * iir,
917		     osm_mad_addr_t * addr)
918{
919	osm_infr_t infr, *p_infr;
920	int ret = 0;
921
922	infr.h_bind = p_osm->sa.mad_ctrl.h_bind;
923	infr.sa = &p_osm->sa;
924	/* other possible way to restore mad_addr partially is
925	   to extract qpn from InformInfo and to find lid by gid */
926	infr.report_addr = *addr;
927	infr.inform_record = *iir;
928
929	cl_plock_excl_acquire(&p_osm->lock);
930	if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) {
931		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
932			"InformInfo Record already exists\n");
933		goto _out;
934	}
935
936	if (!(p_infr = osm_infr_new(&infr))) {
937		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
938			"cannot allocate new infr struct\n");
939		ret = -1;
940		goto _out;
941	}
942
943	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding InformInfo Record...\n");
944
945	osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr);
946
947_out:
948	cl_plock_release(&p_osm->lock);
949
950	return ret;
951}
952
953static int load_guidinfo(osm_opensm_t * p_osm, ib_net64_t base_guid,
954			 ib_guidinfo_record_t *gir)
955{
956	osm_port_t *p_port;
957	uint32_t max_block;
958	int i, ret = 0;
959	osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;
960
961	cl_plock_excl_acquire(&p_osm->lock);
962
963	p_port = osm_get_port_by_guid(&p_osm->subn, base_guid);
964	if (!p_port)
965		goto _out;
966
967	if (!p_port->p_physp->p_guids) {
968		max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
969			     GUID_TABLE_MAX_ENTRIES;
970		p_port->p_physp->p_guids = calloc(max_block * GUID_TABLE_MAX_ENTRIES,
971						  sizeof(ib_net64_t));
972		if (!p_port->p_physp->p_guids) {
973			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
974				"cannot allocate GUID table for port "
975				"GUID 0x%" PRIx64 "\n",
976				cl_ntoh64(p_port->p_physp->port_guid));
977			goto _out;
978		}
979	}
980
981	for (i = 0; i < GUID_TABLE_MAX_ENTRIES; i++) {
982		if (!gir->guid_info.guid[i])
983			continue;
984		/* skip block 0 index 0 */
985		if (gir->block_num == 0 && i == 0)
986			continue;
987		if (gir->block_num * GUID_TABLE_MAX_ENTRIES + i >
988		    p_port->p_physp->port_info.guid_cap)
989			break;
990
991		p_alias_guid = osm_alias_guid_new(gir->guid_info.guid[i],
992						  p_port);
993		if (!p_alias_guid) {
994			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
995				"Alias guid %d memory allocation failed"
996				" for port GUID 0x%" PRIx64 "\n",
997				gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
998				cl_ntoh64(p_port->p_physp->port_guid));
999			goto _out;
1000		}
1001
1002		p_alias_guid_check =
1003			(osm_alias_guid_t *) cl_qmap_insert(&p_osm->subn.alias_port_guid_tbl,
1004							    p_alias_guid->alias_guid,
1005							    &p_alias_guid->map_item);
1006		if (p_alias_guid_check != p_alias_guid) {
1007			/* alias GUID is a duplicate */
1008			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
1009				"Duplicate alias port GUID 0x%" PRIx64
1010				" index %d base port GUID 0x%" PRIx64 "\n",
1011				cl_ntoh64(p_alias_guid->alias_guid),
1012				gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
1013				cl_ntoh64(p_alias_guid->p_base_port->guid));
1014			osm_alias_guid_delete(&p_alias_guid);
1015			goto _out;
1016		}
1017	}
1018
1019	memcpy(&(*p_port->p_physp->p_guids)[gir->block_num * GUID_TABLE_MAX_ENTRIES],
1020	       &gir->guid_info, sizeof(ib_guid_info_t));
1021
1022	osm_queue_guidinfo(&p_osm->sa, p_port, gir->block_num);
1023
1024_out:
1025	cl_plock_release(&p_osm->lock);
1026
1027	return ret;
1028}
1029
1030#define UNPACK_FUNC(name,x) \
1031static int unpack_##name##x(char *p, uint##x##_t *val_ptr) \
1032{ \
1033	char *q; \
1034	unsigned long long num; \
1035	num = strtoull(p, &q, 16); \
1036	if (num > ~((uint##x##_t)0x0) \
1037	    || q == p || (!isspace(*q) && *q != ':')) { \
1038		*val_ptr = 0; \
1039		return -1; \
1040	} \
1041	*val_ptr = cl_hton##x((uint##x##_t)num); \
1042	return (int)(q - p); \
1043}
1044
1045#define cl_hton8(x) (x)
1046
1047UNPACK_FUNC(net, 8);
1048UNPACK_FUNC(net, 16);
1049UNPACK_FUNC(net, 32);
1050UNPACK_FUNC(net, 64);
1051
1052static int unpack_string(char *p, uint8_t * buf, unsigned len)
1053{
1054	char *q = p;
1055	char delim = ' ';
1056
1057	if (*q == '\'' || *q == '\"')
1058		delim = *q++;
1059	while (--len && *q && *q != delim)
1060		*buf++ = *q++;
1061	*buf = '\0';
1062	if (*q == delim && delim != ' ')
1063		q++;
1064	return (int)(q - p);
1065}
1066
1067static int unpack_string64(char *p, uint8_t * buf)
1068{
1069	return unpack_string(p, buf, 64);
1070}
1071
1072#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \
1073	p = strstr(p, name); \
1074	if (!p) { \
1075		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
1076			"PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \
1077			file_name, lineno, (name)); \
1078		ret = -2; \
1079		goto _error; \
1080	} \
1081	p += strlen(name); \
1082	_ret = unpack_##x(p, (val_ptr)); \
1083	if (_ret < 0) { \
1084		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
1085			"PARSE ERROR: %s:%u: cannot parse "#x" value " \
1086			"after \"%s\"\n", file_name, lineno, (name)); \
1087		ret = _ret; \
1088		goto _error; \
1089	} \
1090	p += _ret; \
1091}
1092
1093static void sa_db_file_load_handle_mgrp(osm_opensm_t * p_osm,
1094					osm_mgrp_t * p_mgrp)
1095{
1096	/* decide whether to delete the mgrp object or not */
1097	if (p_mgrp->full_members == 0 && !p_mgrp->well_known) {
1098		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1099			"Closing MC group 0x%016" PRIx64 ":0x%016" PRIx64
1100			" - no full members were added to not well known "
1101			"group\n",
1102			cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
1103			cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id));
1104		osm_mgrp_cleanup(&p_osm->subn, p_mgrp);
1105	}
1106}
1107
1108int osm_sa_db_file_load(osm_opensm_t * p_osm)
1109{
1110	char line[1024];
1111	char *file_name;
1112	FILE *file;
1113	int ret = 0;
1114	osm_mgrp_t *p_next_mgrp = NULL;
1115	osm_mgrp_t *p_prev_mgrp = NULL;
1116	unsigned rereg_clients = 0;
1117	unsigned lineno;
1118
1119	if (!p_osm->subn.first_time_master_sweep) {
1120		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1121			"Not first sweep - skip SA DB restore\n");
1122		return 0;
1123	}
1124
1125	file_name = p_osm->subn.opt.sa_db_file;
1126	if (!file_name) {
1127		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1128			"sa db file name is not specified. Skip restore\n");
1129		return 0;
1130	}
1131
1132	file = fopen(file_name, "r");
1133	if (!file) {
1134		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: "
1135			"Can't open sa db file \'%s\'. Skip restoring\n",
1136			file_name);
1137		return -1;
1138	}
1139
1140	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1141		"Restoring SA DB from file \'%s\'\n",
1142		file_name);
1143
1144	lineno = 0;
1145
1146	while (fgets(line, sizeof(line) - 1, file) != NULL) {
1147		char *p;
1148		uint8_t val;
1149
1150		lineno++;
1151
1152		p = line;
1153		while (isspace(*p))
1154			p++;
1155
1156		if (*p == '#')
1157			continue;
1158
1159		if (!strncmp(p, "MC Group", 8)) {
1160			ib_member_rec_t mcm_rec;
1161			ib_net16_t mlid;
1162
1163			p_next_mgrp = NULL;
1164			memset(&mcm_rec, 0, sizeof(mcm_rec));
1165
1166			PARSE_AHEAD(p, net16, " 0x", &mlid);
1167			PARSE_AHEAD(p, net64, " mgid=0x",
1168				    &mcm_rec.mgid.unicast.prefix);
1169			PARSE_AHEAD(p, net64, ":0x",
1170				    &mcm_rec.mgid.unicast.interface_id);
1171			PARSE_AHEAD(p, net64, " port_gid=0x",
1172				    &mcm_rec.port_gid.unicast.prefix);
1173			PARSE_AHEAD(p, net64, ":0x",
1174				    &mcm_rec.port_gid.unicast.interface_id);
1175			PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey);
1176			PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid);
1177			PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu);
1178			PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass);
1179			PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey);
1180			PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate);
1181			PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life);
1182			PARSE_AHEAD(p, net32, " sl_flow_hop=0x",
1183				    &mcm_rec.sl_flow_hop);
1184			PARSE_AHEAD(p, net8, " scope_state=0x",
1185				    &mcm_rec.scope_state);
1186			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1187			mcm_rec.proxy_join = val;
1188
1189			p_next_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec);
1190			if (!p_next_mgrp)
1191				rereg_clients = 1;
1192			if (cl_ntoh16(mlid) > p_osm->sm.mlids_init_max)
1193				p_osm->sm.mlids_init_max = cl_ntoh16(mlid);
1194		} else if (p_next_mgrp && !strncmp(p, "mcm_port", 8)) {
1195			ib_member_rec_t mcmr;
1196			ib_net64_t guid;
1197			osm_port_t *port;
1198			boolean_t proxy;
1199
1200			PARSE_AHEAD(p, net64, " port_gid=0x",
1201				    &mcmr.port_gid.unicast.prefix);
1202			PARSE_AHEAD(p, net64, ":0x",
1203				    &mcmr.port_gid.unicast.interface_id);
1204			PARSE_AHEAD(p, net8, " scope_state=0x", &mcmr.scope_state);
1205			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1206			proxy = val;
1207
1208			guid = mcmr.port_gid.unicast.interface_id;
1209			port = osm_get_port_by_alias_guid(&p_osm->subn, guid);
1210			if (port &&
1211			    cl_qmap_get(&p_next_mgrp->mcm_port_tbl, guid) ==
1212			    cl_qmap_end(&p_next_mgrp->mcm_port_tbl) &&
1213			    !osm_mgrp_add_port(&p_osm->subn, &p_osm->log,
1214						p_next_mgrp, port, &mcmr, proxy))
1215				rereg_clients = 1;
1216		} else if (!strncmp(p, "Service Record:", 15)) {
1217			ib_service_record_t s_rec;
1218			uint32_t modified_time, lease_period;
1219
1220			p_next_mgrp = NULL;
1221			memset(&s_rec, 0, sizeof(s_rec));
1222
1223			PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id);
1224			PARSE_AHEAD(p, net64, " gid=0x",
1225				    &s_rec.service_gid.unicast.prefix);
1226			PARSE_AHEAD(p, net64, ":0x",
1227				    &s_rec.service_gid.unicast.interface_id);
1228			PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey);
1229			PARSE_AHEAD(p, net32, " lease=0x",
1230				    &s_rec.service_lease);
1231			PARSE_AHEAD(p, net64, " key=0x",
1232				    (ib_net64_t *) (&s_rec.service_key[0]));
1233			PARSE_AHEAD(p, net64, ":0x",
1234				    (ib_net64_t *) (&s_rec.service_key[8]));
1235			PARSE_AHEAD(p, string64, " name=", s_rec.service_name);
1236			PARSE_AHEAD(p, net64, " data8=0x",
1237				    (ib_net64_t *) (&s_rec.service_data8[0]));
1238			PARSE_AHEAD(p, net64, ":0x",
1239				    (ib_net64_t *) (&s_rec.service_data8[8]));
1240			PARSE_AHEAD(p, net64, " data16=0x",
1241				    (ib_net64_t *) (&s_rec.service_data16[0]));
1242			PARSE_AHEAD(p, net64, ":0x",
1243				    (ib_net64_t *) (&s_rec.service_data16[4]));
1244			PARSE_AHEAD(p, net64, " data32=0x",
1245				    (ib_net64_t *) (&s_rec.service_data32[0]));
1246			PARSE_AHEAD(p, net64, ":0x",
1247				    (ib_net64_t *) (&s_rec.service_data32[2]));
1248			PARSE_AHEAD(p, net64, " data64=0x",
1249				    &s_rec.service_data64[0]);
1250			PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]);
1251			PARSE_AHEAD(p, net32, " modified_time=0x",
1252				    &modified_time);
1253			PARSE_AHEAD(p, net32, " lease_period=0x",
1254				    &lease_period);
1255
1256			if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time),
1257				      cl_ntoh32(lease_period)))
1258				rereg_clients = 1;
1259		} else if (!strncmp(p, "InformInfo Record:", 18)) {
1260			ib_inform_info_record_t i_rec;
1261			osm_mad_addr_t rep_addr;
1262			ib_net16_t val16;
1263
1264			p_next_mgrp = NULL;
1265			memset(&i_rec, 0, sizeof(i_rec));
1266			memset(&rep_addr, 0, sizeof(rep_addr));
1267
1268			PARSE_AHEAD(p, net64, " subscriber_gid=0x",
1269				    &i_rec.subscriber_gid.unicast.prefix);
1270			PARSE_AHEAD(p, net64, ":0x",
1271				    &i_rec.subscriber_gid.unicast.interface_id);
1272			PARSE_AHEAD(p, net16, " subscriber_enum=0x",
1273				    &i_rec.subscriber_enum);
1274			PARSE_AHEAD(p, net64, " gid=0x",
1275				    &i_rec.inform_info.gid.unicast.prefix);
1276			PARSE_AHEAD(p, net64, ":0x",
1277				    &i_rec.inform_info.gid.unicast.
1278				    interface_id);
1279			PARSE_AHEAD(p, net16, " lid_range_begin=0x",
1280				    &i_rec.inform_info.lid_range_begin);
1281			PARSE_AHEAD(p, net16, " lid_range_end=0x",
1282				    &i_rec.inform_info.lid_range_end);
1283			PARSE_AHEAD(p, net8, " is_generic=0x",
1284				    &i_rec.inform_info.is_generic);
1285			PARSE_AHEAD(p, net8, " subscribe=0x",
1286				    &i_rec.inform_info.subscribe);
1287			PARSE_AHEAD(p, net16, " trap_type=0x",
1288				    &i_rec.inform_info.trap_type);
1289			PARSE_AHEAD(p, net16, " trap_num=0x",
1290				    &i_rec.inform_info.g_or_v.generic.trap_num);
1291			PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x",
1292				    &i_rec.inform_info.g_or_v.generic.
1293				    qpn_resp_time_val);
1294			PARSE_AHEAD(p, net32, " node_type=0x",
1295				    (uint32_t *) & i_rec.inform_info.g_or_v.
1296				    generic.reserved2);
1297
1298			PARSE_AHEAD(p, net16, " rep_addr: lid=0x",
1299				    &rep_addr.dest_lid);
1300			PARSE_AHEAD(p, net8, " path_bits=0x",
1301				    &rep_addr.path_bits);
1302			PARSE_AHEAD(p, net8, " static_rate=0x",
1303				    &rep_addr.static_rate);
1304			PARSE_AHEAD(p, net32, " remote_qp=0x",
1305				    &rep_addr.addr_type.gsi.remote_qp);
1306			PARSE_AHEAD(p, net32, " remote_qkey=0x",
1307				    &rep_addr.addr_type.gsi.remote_qkey);
1308			PARSE_AHEAD(p, net16, " pkey_ix=0x", &val16);
1309			rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16);
1310			PARSE_AHEAD(p, net8, " sl=0x",
1311				    &rep_addr.addr_type.gsi.service_level);
1312
1313			if (load_infr(p_osm, &i_rec, &rep_addr))
1314				rereg_clients = 1;
1315		} else if (!strncmp(p, "GUIDInfo Record:", 16)) {
1316			ib_guidinfo_record_t gi_rec;
1317			ib_net64_t base_guid;
1318
1319			p_next_mgrp = NULL;
1320			memset(&gi_rec, 0, sizeof(gi_rec));
1321
1322			PARSE_AHEAD(p, net64, " base_guid=0x", &base_guid);
1323			PARSE_AHEAD(p, net16, " lid=0x", &gi_rec.lid);
1324			PARSE_AHEAD(p, net8, " block_num=0x",
1325				    &gi_rec.block_num);
1326			PARSE_AHEAD(p, net64, " guid0=0x",
1327				    &gi_rec.guid_info.guid[0]);
1328			PARSE_AHEAD(p, net64, " guid1=0x",
1329				    &gi_rec.guid_info.guid[1]);
1330			PARSE_AHEAD(p, net64, " guid2=0x",
1331				    &gi_rec.guid_info.guid[2]);
1332			PARSE_AHEAD(p, net64, " guid3=0x",
1333				    &gi_rec.guid_info.guid[3]);
1334			PARSE_AHEAD(p, net64, " guid4=0x",
1335				    &gi_rec.guid_info.guid[4]);
1336			PARSE_AHEAD(p, net64, " guid5=0x",
1337				    &gi_rec.guid_info.guid[5]);
1338			PARSE_AHEAD(p, net64, " guid6=0x",
1339				    &gi_rec.guid_info.guid[6]);
1340			PARSE_AHEAD(p, net64, " guid7=0x",
1341				    &gi_rec.guid_info.guid[7]);
1342
1343			if (load_guidinfo(p_osm, base_guid, &gi_rec))
1344				rereg_clients = 1;
1345		}
1346
1347		/*
1348		 * p_next_mgrp points to the multicast group now being parsed.
1349		 * p_prev_mgrp points to the last multicast group we parsed.
1350		 * We decide whether to keep or delete each multicast group
1351		 * only when we finish parsing it's member records. if the
1352		 * group has full members, or it is a "well known group" we
1353		 * keep it.
1354		 */
1355		if (p_prev_mgrp != p_next_mgrp) {
1356			if (p_prev_mgrp)
1357				sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
1358			p_prev_mgrp = p_next_mgrp;
1359		}
1360	}
1361
1362	if (p_next_mgrp)
1363		sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
1364
1365	/*
1366	 * If loading succeeded, do whatever 'no_clients_rereg' says.
1367	 * If loading failed at some point, turn off the 'no_clients_rereg'
1368	 * option (turn on re-registration requests).
1369	 */
1370	if (rereg_clients)
1371		p_osm->subn.opt.no_clients_rereg = FALSE;
1372
1373	/* We've just finished loading SA DB file - clear the "dirty" flag */
1374	p_osm->sa.dirty = FALSE;
1375
1376_error:
1377	fclose(file);
1378	return ret;
1379}
1380