]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_sa.c
MFV r353623: 10473 zfs(1M) missing cross-reference to zfs-program(1M)
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_sa.c
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
77 extern void osm_cpi_rcv_process(IN void *context, IN void *data);
78 extern void osm_gir_rcv_process(IN void *context, IN void *data);
79 extern void osm_infr_rcv_process(IN void *context, IN void *data);
80 extern void osm_infir_rcv_process(IN void *context, IN void *data);
81 extern void osm_lftr_rcv_process(IN void *context, IN void *data);
82 extern void osm_lr_rcv_process(IN void *context, IN void *data);
83 extern void osm_mcmr_rcv_process(IN void *context, IN void *data);
84 extern void osm_mftr_rcv_process(IN void *context, IN void *data);
85 extern void osm_mpr_rcv_process(IN void *context, IN void *data);
86 extern void osm_nr_rcv_process(IN void *context, IN void *data);
87 extern void osm_pr_rcv_process(IN void *context, IN void *data);
88 extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
89 extern void osm_pir_rcv_process(IN void *context, IN void *data);
90 extern void osm_sr_rcv_process(IN void *context, IN void *data);
91 extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
92 extern void osm_smir_rcv_process(IN void *context, IN void *data);
93 extern void osm_sir_rcv_process(IN void *context, IN void *data);
94 extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
95 extern void osm_sr_rcv_lease_cb(IN void *context);
96
97 void 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
106 void 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
148 void 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
159 ib_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;
322 Exit:
323         OSM_LOG_EXIT(p_log);
324         return status;
325 }
326
327 ib_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
342 Exit:
343         OSM_LOG_EXIT(p_sa->p_log);
344         return status;
345 }
346
347 ib_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
363 void 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
420 Exit:
421         OSM_LOG_EXIT(sa->p_log);
422 }
423
424 void 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
529 Exit:
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
543 struct opensm_dump_context {
544         osm_opensm_t *p_osm;
545         FILE *file;
546 };
547
548 static int
549 opensm_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
610 static 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
623 static 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
659 static 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
703 static 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
761 static 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
795 static 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
818 int 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  */
837 static 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
879 static 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
916 static 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
953 static 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) \
1031 static 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
1047 UNPACK_FUNC(net, 8);
1048 UNPACK_FUNC(net, 16);
1049 UNPACK_FUNC(net, 32);
1050 UNPACK_FUNC(net, 64);
1051
1052 static 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
1067 static 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
1093 static 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
1108 int 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 }