]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/libvendor/osm_vendor_ibumad.c
Upgrade to version 3.1.6
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / libvendor / osm_vendor_ibumad.c
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  * Copyright (c) 2009 HNR Consulting. All rights reserved.
6  * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  */
37
38 /*
39  * Abstract:
40  *    Implementation of osm_vendor_t (for umad).
41  * This object represents the OpenIB vendor layer.
42  * This object is part of the opensm family of objects.
43  *
44  * Environment:
45  *    Linux User Mode
46  *
47  */
48
49 #if HAVE_CONFIG_H
50 #  include <config.h>
51 #endif                          /* HAVE_CONFIG_H */
52
53 #ifdef OSM_VENDOR_INTF_OPENIB
54
55 #include <unistd.h>
56 #include <stdlib.h>
57 #include <fcntl.h>
58 #include <errno.h>
59
60 #include <iba/ib_types.h>
61 #include <complib/cl_qlist.h>
62 #include <complib/cl_math.h>
63 #include <complib/cl_debug.h>
64 #include <opensm/osm_file_ids.h>
65 #define FILE_ID OSM_FILE_VENDOR_IBUMAD_C
66 #include <opensm/osm_madw.h>
67 #include <opensm/osm_log.h>
68 #include <opensm/osm_mad_pool.h>
69 #include <opensm/osm_helper.h>
70 #include <vendor/osm_vendor_api.h>
71
72 /****s* OpenSM: Vendor UMAD/osm_umad_bind_info_t
73  * NAME
74  *   osm_umad_bind_info_t
75  *
76  * DESCRIPTION
77  *    Structure containing bind information.
78  *
79  * SYNOPSIS
80  */
81 typedef struct _osm_umad_bind_info {
82         osm_vendor_t *p_vend;
83         void *client_context;
84         osm_mad_pool_t *p_mad_pool;
85         osm_vend_mad_recv_callback_t mad_recv_callback;
86         osm_vend_mad_send_err_callback_t send_err_callback;
87         ib_net64_t port_guid;
88         int port_id;
89         int agent_id;
90         int agent_id1;          /* SMI requires two agents */
91         int timeout;
92         int max_retries;
93 } osm_umad_bind_info_t;
94
95 typedef struct _umad_receiver {
96         pthread_t tid;
97         osm_vendor_t *p_vend;
98         osm_log_t *p_log;
99 } umad_receiver_t;
100
101 static void osm_vendor_close_port(osm_vendor_t * const p_vend);
102
103 static void log_send_error(osm_vendor_t * const p_vend, osm_madw_t *p_madw)
104 {
105         if (p_madw->p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
106                 /* LID routed */
107                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5410: "
108                         "Send completed with error (%s) -- dropping\n"
109                         "\t\t\tClass 0x%x, Method 0x%X, Attr 0x%X, "
110                         "TID 0x%" PRIx64 ", LID %u\n",
111                         ib_get_err_str(p_madw->status),
112                         p_madw->p_mad->mgmt_class, p_madw->p_mad->method,
113                         cl_ntoh16(p_madw->p_mad->attr_id),
114                         cl_ntoh64(p_madw->p_mad->trans_id),
115                         cl_ntoh16(p_madw->mad_addr.dest_lid));
116         } else {
117                 ib_smp_t *p_smp;
118
119                 /* Direct routed SMP */
120                 p_smp = osm_madw_get_smp_ptr(p_madw);
121                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5411: "
122                         "DR SMP Send completed with error (%s) -- dropping\n"
123                         "\t\t\tMethod 0x%X, Attr 0x%X, TID 0x%" PRIx64 "\n",
124                         ib_get_err_str(p_madw->status),
125                         p_madw->p_mad->method,
126                         cl_ntoh16(p_madw->p_mad->attr_id),
127                         cl_ntoh64(p_madw->p_mad->trans_id));
128                 osm_dump_smp_dr_path(p_vend->p_log, p_smp, OSM_LOG_ERROR);
129         }
130 }
131
132 static void clear_madw(osm_vendor_t * p_vend)
133 {
134         umad_match_t *m, *e, *old_m;
135         ib_net64_t old_tid;
136         uint8_t old_mgmt_class;
137
138         OSM_LOG_ENTER(p_vend->p_log);
139         pthread_mutex_lock(&p_vend->match_tbl_mutex);
140         for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
141                 if (m->tid) {
142                         old_m = m;
143                         old_tid = m->tid;
144                         old_mgmt_class = m->mgmt_class;
145                         m->tid = 0;
146                         osm_mad_pool_put(((osm_umad_bind_info_t
147                                            *) ((osm_madw_t *) m->v)->h_bind)->
148                                          p_mad_pool, m->v);
149                         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
150                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5401: "
151                                 "evicting entry %p (tid was 0x%" PRIx64
152                                 " mgmt class 0x%x)\n",
153                                 old_m, cl_ntoh64(old_tid), old_mgmt_class);
154                         goto Exit;
155                 }
156         }
157         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
158
159 Exit:
160         OSM_LOG_EXIT(p_vend->p_log);
161 }
162
163 static osm_madw_t *get_madw(osm_vendor_t * p_vend, ib_net64_t * tid,
164                             uint8_t mgmt_class)
165 {
166         umad_match_t *m, *e;
167         ib_net64_t mtid = (*tid & CL_HTON64(0x00000000ffffffffULL));
168         osm_madw_t *res;
169
170         /*
171          * Since mtid == 0 is the empty key, we should not
172          * waste time looking for it
173          */
174         if (mtid == 0 || mgmt_class == 0)
175                 return 0;
176
177         pthread_mutex_lock(&p_vend->match_tbl_mutex);
178         for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
179                 if (m->tid == mtid && m->mgmt_class == mgmt_class) {
180                         m->tid = 0;
181                         m->mgmt_class = 0;
182                         *tid = mtid;
183                         res = m->v;
184                         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
185                         return res;
186                 }
187         }
188
189         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
190         return 0;
191 }
192
193 /*
194  * If match table full, evict LRU (least recently used) transaction.
195  * Maintain 2 LRUs: one for SMPs, and one for others (GS).
196  * Evict LRU GS transaction if one is available and only evict LRU SMP
197  * transaction if no other choice.
198  */
199 static void
200 put_madw(osm_vendor_t * p_vend, osm_madw_t * p_madw, ib_net64_t tid,
201          uint8_t mgmt_class)
202 {
203         umad_match_t *m, *e, *old_lru, *lru = 0, *lru_smp = 0;
204         osm_madw_t *p_req_madw;
205         osm_umad_bind_info_t *p_bind;
206         ib_net64_t old_tid;
207         uint32_t oldest = ~0, oldest_smp = ~0;
208         uint8_t old_mgmt_class;
209
210         pthread_mutex_lock(&p_vend->match_tbl_mutex);
211         for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
212                 if (m->tid == 0 && m->mgmt_class == 0) {
213                         m->tid = tid;
214                         m->mgmt_class = mgmt_class;
215                         m->v = p_madw;
216                         m->version =
217                             cl_atomic_inc((atomic32_t *) & p_vend->mtbl.
218                                           last_version);
219                         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
220                         return;
221                 }
222                 if (m->mgmt_class == IB_MCLASS_SUBN_DIR ||
223                     m->mgmt_class == IB_MCLASS_SUBN_LID) {
224                         if (oldest_smp >= m->version) {
225                                 oldest_smp = m->version;
226                                 lru_smp = m;
227                         }
228                 } else {
229                         if (oldest >= m->version) {
230                                 oldest = m->version;
231                                 lru = m;
232                         }
233                 }
234         }
235
236         if (oldest != ~0) {
237                 old_lru = lru;
238                 old_tid = lru->tid;
239                 old_mgmt_class = lru->mgmt_class;
240         } else {
241                 CL_ASSERT(oldest_smp != ~0);
242                 old_lru = lru_smp;
243                 old_tid = lru_smp->tid;
244                 old_mgmt_class = lru_smp->mgmt_class;
245         }
246         p_req_madw = old_lru->v;
247         p_bind = p_req_madw->h_bind;
248         p_req_madw->status = IB_CANCELED;
249         log_send_error(p_vend, p_req_madw);
250         pthread_mutex_lock(&p_vend->cb_mutex);
251         (*p_bind->send_err_callback) (p_bind->client_context, p_req_madw);
252         pthread_mutex_unlock(&p_vend->cb_mutex);
253         if (mgmt_class == IB_MCLASS_SUBN_DIR ||
254             mgmt_class == IB_MCLASS_SUBN_LID) {
255                 lru_smp->tid = tid;
256                 lru_smp->mgmt_class = mgmt_class;
257                 lru_smp->v = p_madw;
258                 lru_smp->version =
259                     cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version);
260         } else {
261                 lru->tid = tid;
262                 lru->mgmt_class = mgmt_class;
263                 lru->v = p_madw;
264                 lru->version =
265                     cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version);
266         }
267         pthread_mutex_unlock(&p_vend->match_tbl_mutex);
268         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5402: "
269                 "evicting entry %p (tid was 0x%" PRIx64
270                 " mgmt class 0x%x)\n", old_lru,
271                 cl_ntoh64(old_tid), old_mgmt_class);
272 }
273
274 static void
275 ib_mad_addr_conv(ib_user_mad_t * umad, osm_mad_addr_t * osm_mad_addr,
276                  int is_smi)
277 {
278         ib_mad_addr_t *ib_mad_addr = umad_get_mad_addr(umad);
279
280         memset(osm_mad_addr, 0, sizeof(osm_mad_addr_t));
281         osm_mad_addr->dest_lid = ib_mad_addr->lid;
282         osm_mad_addr->path_bits = ib_mad_addr->path_bits;
283
284         if (is_smi) {
285                 osm_mad_addr->addr_type.smi.source_lid = osm_mad_addr->dest_lid;
286                 osm_mad_addr->addr_type.smi.port_num = 255;     /* not used */
287                 return;
288         }
289
290         osm_mad_addr->addr_type.gsi.remote_qp = ib_mad_addr->qpn;
291         osm_mad_addr->addr_type.gsi.remote_qkey = ib_mad_addr->qkey;
292         osm_mad_addr->addr_type.gsi.pkey_ix = umad_get_pkey(umad);
293         osm_mad_addr->addr_type.gsi.service_level = ib_mad_addr->sl;
294         if (ib_mad_addr->grh_present) {
295                 osm_mad_addr->addr_type.gsi.global_route = 1;
296                 osm_mad_addr->addr_type.gsi.grh_info.hop_limit = ib_mad_addr->hop_limit;
297                 osm_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
298                         ib_grh_set_ver_class_flow(6,    /* GRH version */
299                                                   ib_mad_addr->traffic_class,
300                                                   ib_mad_addr->flow_label);
301                 memcpy(&osm_mad_addr->addr_type.gsi.grh_info.dest_gid,
302                        &ib_mad_addr->gid, 16);
303         }
304 }
305
306 static void *swap_mad_bufs(osm_madw_t * p_madw, void *umad)
307 {
308         void *old;
309
310         old = p_madw->vend_wrap.umad;
311         p_madw->vend_wrap.umad = umad;
312         p_madw->p_mad = umad_get_mad(umad);
313
314         return old;
315 }
316
317 static void unlock_mutex(void *arg)
318 {
319         pthread_mutex_unlock(arg);
320 }
321
322 static void *umad_receiver(void *p_ptr)
323 {
324         umad_receiver_t *const p_ur = (umad_receiver_t *) p_ptr;
325         osm_vendor_t *p_vend = p_ur->p_vend;
326         osm_umad_bind_info_t *p_bind;
327         osm_mad_addr_t osm_addr;
328         osm_madw_t *p_madw, *p_req_madw;
329         ib_mad_t *p_mad, *p_req_mad;
330         void *umad = 0;
331         int mad_agent, length;
332
333         OSM_LOG_ENTER(p_ur->p_log);
334
335         for (;;) {
336                 if (!umad &&
337                     !(umad = umad_alloc(1, umad_size() + MAD_BLOCK_SIZE))) {
338                         OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5403: "
339                                 "can't alloc MAD sized umad\n");
340                         break;
341                 }
342
343                 length = MAD_BLOCK_SIZE;
344                 if ((mad_agent = umad_recv(p_vend->umad_port_id, umad,
345                                            &length, -1)) < 0) {
346                         if (length <= MAD_BLOCK_SIZE) {
347                                 OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5404: "
348                                         "recv error on MAD sized umad (%m)\n");
349                                 continue;
350                         } else {
351                                 umad_free(umad);
352                                 /* Need a larger buffer for RMPP */
353                                 umad = umad_alloc(1, umad_size() + length);
354                                 if (!umad) {
355                                         OSM_LOG(p_ur->p_log, OSM_LOG_ERROR,
356                                                 "ERR 5405: "
357                                                 "can't alloc umad length %d\n",
358                                                 length);
359                                         continue;
360                                 }
361
362                                 if ((mad_agent = umad_recv(p_vend->umad_port_id,
363                                                            umad, &length,
364                                                            -1)) < 0) {
365                                         OSM_LOG(p_ur->p_log, OSM_LOG_ERROR,
366                                                 "ERR 5406: "
367                                                 "recv error on umad length %d (%m)\n",
368                                                 length);
369                                         continue;
370                                 }
371                         }
372                 }
373
374                 if (mad_agent >= OSM_UMAD_MAX_AGENTS ||
375                     !(p_bind = p_vend->agents[mad_agent])) {
376                         OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5407: "
377                                 "invalid mad agent %d - dropping\n", mad_agent);
378                         continue;
379                 }
380
381                 p_mad = (ib_mad_t *) umad_get_mad(umad);
382
383                 ib_mad_addr_conv(umad, &osm_addr,
384                                  p_mad->mgmt_class == IB_MCLASS_SUBN_LID ||
385                                  p_mad->mgmt_class == IB_MCLASS_SUBN_DIR);
386
387                 if (!(p_madw = osm_mad_pool_get(p_bind->p_mad_pool,
388                                                 (osm_bind_handle_t) p_bind,
389                                                 MAX(length, MAD_BLOCK_SIZE),
390                                                 &osm_addr))) {
391                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5408: "
392                                 "request for a new madw failed -- dropping packet\n");
393                         continue;
394                 }
395
396                 /* Need to fix up MAD size if short RMPP packet */
397                 if (length < MAD_BLOCK_SIZE)
398                         p_madw->mad_size = length;
399
400                 /*
401                  * Avoid copying by swapping mad buf pointers.
402                  * Do not use umad after this line of code.
403                  */
404                 umad = swap_mad_bufs(p_madw, umad);
405
406                 /* if status != 0 then we are handling recv timeout on send */
407                 if (umad_status(p_madw->vend_wrap.umad)) {
408                         if (!(p_req_madw = get_madw(p_vend, &p_mad->trans_id,
409                                                     p_mad->mgmt_class))) {
410                                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
411                                         "ERR 5412: "
412                                         "Failed to obtain request madw for timed out MAD"
413                                         " (class=0x%X method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n",
414                                         p_mad->mgmt_class, p_mad->method,
415                                         cl_ntoh16(p_mad->attr_id),
416                                         cl_ntoh64(p_mad->trans_id));
417                         } else {
418                                 p_req_madw->status = IB_TIMEOUT;
419                                 log_send_error(p_vend, p_req_madw);
420                                 /* cb frees req_madw */
421                                 pthread_mutex_lock(&p_vend->cb_mutex);
422                                 pthread_cleanup_push(unlock_mutex,
423                                                      &p_vend->cb_mutex);
424                                 (*p_bind->send_err_callback) (p_bind->
425                                                               client_context,
426                                                               p_req_madw);
427                                 pthread_cleanup_pop(1);
428                         }
429
430                         osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
431                         continue;
432                 }
433
434                 p_req_madw = 0;
435                 if (ib_mad_is_response(p_mad)) {
436                         p_req_madw = get_madw(p_vend, &p_mad->trans_id,
437                                               p_mad->mgmt_class);
438                         if (PF(!p_req_madw)) {
439                                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
440                                         "ERR 5413: Failed to obtain request "
441                                         "madw for received MAD "
442                                         "(class=0x%X method=0x%X attr=0x%X "
443                                         "tid=0x%"PRIx64") -- dropping\n",
444                                         p_mad->mgmt_class, p_mad->method,
445                                         cl_ntoh16(p_mad->attr_id),
446                                         cl_ntoh64(p_mad->trans_id));
447                                 osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
448                                 continue;
449                         }
450
451                         /*
452                          * Check that request MAD was really a request,
453                          * and make sure that attribute ID, attribute
454                          * modifier and transaction ID are the same in
455                          * request and response.
456                          *
457                          * Exception for o15-0.2-1.11:
458                          * SA response to a SubnAdmGetMulti() containing a
459                          * MultiPathRecord shall have PathRecord attribute ID.
460                          */
461                         p_req_mad = osm_madw_get_mad_ptr(p_req_madw);
462                         if (PF(ib_mad_is_response(p_req_mad) ||
463                                (p_mad->attr_id != p_req_mad->attr_id &&
464                                 !(p_mad->mgmt_class == IB_MCLASS_SUBN_ADM &&
465                                   p_req_mad->attr_id ==
466                                         IB_MAD_ATTR_MULTIPATH_RECORD &&
467                                   p_mad->attr_id == IB_MAD_ATTR_PATH_RECORD)) ||
468                                p_mad->attr_mod != p_req_mad->attr_mod ||
469                                p_mad->trans_id != p_req_mad->trans_id)) {
470                                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
471                                         "ERR 541A: "
472                                         "Response MAD validation failed "
473                                         "(request attr=0x%X modif=0x%X "
474                                         "tid=0x%"PRIx64", "
475                                         "response attr=0x%X modif=0x%X "
476                                         "tid=0x%"PRIx64") -- dropping\n",
477                                         cl_ntoh16(p_req_mad->attr_id),
478                                         cl_ntoh32(p_req_mad->attr_mod),
479                                         cl_ntoh64(p_req_mad->trans_id),
480                                         cl_ntoh16(p_mad->attr_id),
481                                         cl_ntoh32(p_mad->attr_mod),
482                                         cl_ntoh64(p_mad->trans_id));
483                                 osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
484                                 continue;
485                         }
486                 }
487
488 #ifndef VENDOR_RMPP_SUPPORT
489                 if ((p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) &&
490                     (p_mad->mgmt_class != IB_MCLASS_SUBN_LID) &&
491                     (ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_mad,
492                                          IB_RMPP_FLAG_ACTIVE))) {
493                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5414: "
494                                 "class 0x%x method 0x%x RMPP version %d type "
495                                 "%d flags 0x%x received -- dropping\n",
496                                 p_mad->mgmt_class, p_mad->method,
497                                 ((ib_rmpp_mad_t *) p_mad)->rmpp_version,
498                                 ((ib_rmpp_mad_t *) p_mad)->rmpp_type,
499                                 ((ib_rmpp_mad_t *) p_mad)->rmpp_flags);
500                         osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
501                         continue;
502                 }
503 #endif
504
505                 /* call the CB */
506                 pthread_mutex_lock(&p_vend->cb_mutex);
507                 pthread_cleanup_push(unlock_mutex, &p_vend->cb_mutex);
508                 (*p_bind->mad_recv_callback) (p_madw, p_bind->client_context,
509                                               p_req_madw);
510                 pthread_cleanup_pop(1);
511         }
512
513         OSM_LOG_EXIT(p_vend->p_log);
514         return NULL;
515 }
516
517 static int umad_receiver_start(osm_vendor_t * p_vend)
518 {
519         umad_receiver_t *p_ur = p_vend->receiver;
520
521         p_ur->p_vend = p_vend;
522         p_ur->p_log = p_vend->p_log;
523
524         if (pthread_create(&p_ur->tid, NULL, umad_receiver, p_ur) != 0)
525                 return -1;
526
527         return 0;
528 }
529
530 static void umad_receiver_stop(umad_receiver_t * p_ur)
531 {
532         pthread_cancel(p_ur->tid);
533         pthread_join(p_ur->tid, NULL);
534         p_ur->tid = 0;
535         p_ur->p_vend = NULL;
536         p_ur->p_log = NULL;
537 }
538
539 ib_api_status_t
540 osm_vendor_init(IN osm_vendor_t * const p_vend,
541                 IN osm_log_t * const p_log, IN const uint32_t timeout)
542 {
543         char *max = NULL;
544         int r, n_cas;
545
546         OSM_LOG_ENTER(p_log);
547
548         p_vend->p_log = p_log;
549         p_vend->timeout = timeout;
550         p_vend->max_retries = OSM_DEFAULT_RETRY_COUNT;
551         pthread_mutex_init(&p_vend->cb_mutex, NULL);
552         pthread_mutex_init(&p_vend->match_tbl_mutex, NULL);
553         p_vend->umad_port_id = -1;
554         p_vend->issmfd = -1;
555
556         /*
557          * Open our instance of UMAD.
558          */
559         if ((r = umad_init()) < 0) {
560                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
561                         "ERR 5415: Error opening UMAD\n");
562         }
563
564         if ((n_cas = umad_get_cas_names(p_vend->ca_names,
565                                         OSM_UMAD_MAX_CAS)) < 0) {
566                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
567                         "ERR 5416: umad_get_cas_names failed\n");
568                 r = n_cas;
569                 goto Exit;
570         }
571
572         p_vend->ca_count = n_cas;
573         p_vend->mtbl.max = DEFAULT_OSM_UMAD_MAX_PENDING;
574
575         if ((max = getenv("OSM_UMAD_MAX_PENDING")) != NULL) {
576                 int tmp = strtol(max, NULL, 0);
577                 if (tmp > 0)
578                         p_vend->mtbl.max = tmp;
579                 else
580                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:"
581                                 "OSM_UMAD_MAX_PENDING=%d is invalid\n",
582                                 tmp);
583         }
584
585         OSM_LOG(p_vend->p_log, OSM_LOG_INFO, "%d pending umads specified\n",
586                 p_vend->mtbl.max);
587
588         p_vend->mtbl.tbl = calloc(p_vend->mtbl.max, sizeof(*(p_vend->mtbl.tbl)));
589         if (!p_vend->mtbl.tbl) {
590                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:"
591                         "failed to allocate vendor match table\n");
592                 r = IB_INSUFFICIENT_MEMORY;
593                 goto Exit;
594         }
595
596 Exit:
597         OSM_LOG_EXIT(p_log);
598         return (r);
599 }
600
601 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
602                              IN const uint32_t timeout)
603 {
604         osm_vendor_t *p_vend = NULL;
605
606         OSM_LOG_ENTER(p_log);
607
608         if (!timeout) {
609                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5433: "
610                         "transaction timeout cannot be 0\n");
611                 goto Exit;
612         }
613
614         p_vend = malloc(sizeof(*p_vend));
615         if (p_vend == NULL) {
616                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5417: "
617                         "Unable to allocate vendor object\n");
618                 goto Exit;
619         }
620
621         memset(p_vend, 0, sizeof(*p_vend));
622
623         if (osm_vendor_init(p_vend, p_log, timeout) != IB_SUCCESS) {
624                 free(p_vend);
625                 p_vend = NULL;
626         }
627
628 Exit:
629         OSM_LOG_EXIT(p_log);
630         return (p_vend);
631 }
632
633 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
634 {
635         osm_vendor_close_port(*pp_vend);
636
637         clear_madw(*pp_vend);
638         /* make sure all ports are closed */
639         umad_done();
640
641         pthread_mutex_destroy(&(*pp_vend)->cb_mutex);
642         pthread_mutex_destroy(&(*pp_vend)->match_tbl_mutex);
643         free((*pp_vend)->mtbl.tbl);
644         free(*pp_vend);
645         *pp_vend = NULL;
646 }
647
648 ib_api_status_t
649 osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend,
650                              IN ib_port_attr_t * const p_attr_array,
651                              IN uint32_t * const p_num_ports)
652 {
653         umad_ca_t ca;
654         ib_port_attr_t *attr = p_attr_array;
655         unsigned done = 0;
656         int r = 0, i, j, k;
657
658         OSM_LOG_ENTER(p_vend->p_log);
659
660         CL_ASSERT(p_vend && p_num_ports);
661
662         if (!*p_num_ports) {
663                 r = IB_INVALID_PARAMETER;
664                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5418: "
665                         "Ports in should be > 0\n");
666                 goto Exit;
667         }
668
669         if (!p_attr_array) {
670                 r = IB_INSUFFICIENT_MEMORY;
671                 *p_num_ports = 0;
672                 goto Exit;
673         }
674
675         for (i = 0; i < p_vend->ca_count && !done; i++) {
676                 /* For each CA, retrieve the port attributes */
677                 if (umad_get_ca(p_vend->ca_names[i], &ca) == 0) {
678                         if (ca.node_type < 1 || ca.node_type > 3)
679                                 continue;
680                         for (j = 0; j <= ca.numports; j++) {
681                                 if (!ca.ports[j])
682                                         continue;
683                                 attr->port_guid = ca.ports[j]->port_guid;
684                                 attr->lid = ca.ports[j]->base_lid;
685                                 attr->port_num = ca.ports[j]->portnum;
686                                 attr->sm_lid = ca.ports[j]->sm_lid;
687                                 attr->sm_sl = ca.ports[j]->sm_sl;
688                                 attr->link_state = ca.ports[j]->state;
689                                 if (attr->num_pkeys && attr->p_pkey_table) {
690                                         if (attr->num_pkeys > ca.ports[j]->pkeys_size)
691                                                 attr->num_pkeys = ca.ports[j]->pkeys_size;
692                                         for (k = 0; k < attr->num_pkeys; k++)
693                                                 attr->p_pkey_table[k] =
694                                                         cl_hton16(ca.ports[j]->pkeys[k]);
695                                 }
696                                 attr->num_pkeys = ca.ports[j]->pkeys_size;
697                                 if (attr->num_gids && attr->p_gid_table) {
698                                         attr->p_gid_table[0].unicast.prefix = cl_hton64(ca.ports[j]->gid_prefix);
699                                         attr->p_gid_table[0].unicast.interface_id = cl_hton64(ca.ports[j]->port_guid);
700                                         attr->num_gids = 1;
701                                 }
702                                 attr++;
703                                 if (attr - p_attr_array > *p_num_ports) {
704                                         done = 1;
705                                         break;
706                                 }
707                         }
708                         umad_release_ca(&ca);
709                 }
710         }
711
712         *p_num_ports = attr - p_attr_array;
713
714 Exit:
715         OSM_LOG_EXIT(p_vend->p_log);
716         return r;
717 }
718
719 static int
720 osm_vendor_open_port(IN osm_vendor_t * const p_vend,
721                      IN const ib_net64_t port_guid)
722 {
723         ib_net64_t portguids[OSM_UMAD_MAX_PORTS_PER_CA + 1];
724         umad_ca_t umad_ca;
725         int i = 0, umad_port_id = -1;
726         char *name;
727         int ca, r;
728
729         CL_ASSERT(p_vend);
730
731         OSM_LOG_ENTER(p_vend->p_log);
732
733         if (p_vend->umad_port_id >= 0) {
734                 umad_port_id = p_vend->umad_port_id;
735                 goto Exit;
736         }
737
738         if (!port_guid) {
739                 name = NULL;
740                 i = 0;
741                 goto _found;
742         }
743
744         for (ca = 0; ca < p_vend->ca_count; ca++) {
745                 if ((r = umad_get_ca_portguids(p_vend->ca_names[ca], portguids,
746                                                OSM_UMAD_MAX_PORTS_PER_CA + 1)) < 0) {
747 #ifdef __WIN__
748                         OSM_LOG(p_vend->p_log, OSM_LOG_VERBOSE,
749 #else
750                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5421: "
751 #endif
752                                 "Unable to get CA %s port guids (%s)\n",
753                                 p_vend->ca_names[ca], strerror(r));
754                         continue;
755                 }
756                 for (i = 0; i < r; i++)
757                         if (port_guid == portguids[i]) {
758                                 name = p_vend->ca_names[ca];
759                                 goto _found;
760                         }
761         }
762
763         /*
764          * No local CA owns this guid!
765          */
766         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5422: "
767                 "Unable to find requested CA guid 0x%" PRIx64 "\n",
768                 cl_ntoh64(port_guid));
769         goto Exit;
770
771 _found:
772         /* Validate that node is an IB node type (not iWARP) */
773         if (umad_get_ca(name, &umad_ca) < 0) {
774                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542A: "
775                         "umad_get_ca() failed\n");
776                 goto Exit;
777         }
778
779         if (umad_ca.node_type < 1 || umad_ca.node_type > 3) {
780                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542D: "
781                         "Type %d of node \'%s\' is not an IB node type\n",
782                         umad_ca.node_type, umad_ca.ca_name);
783                 fprintf(stderr,
784                         "Type %d of node \'%s\' is not an IB node type\n",
785                         umad_ca.node_type, umad_ca.ca_name);
786                 umad_release_ca(&umad_ca);
787                 goto Exit;
788         }
789         umad_release_ca(&umad_ca);
790
791         /* Port found, try to open it */
792         if (umad_get_port(name, i, &p_vend->umad_port) < 0) {
793                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542B: "
794                         "umad_get_port() failed\n");
795                 goto Exit;
796         }
797
798         if ((umad_port_id = umad_open_port(p_vend->umad_port.ca_name,
799                                            p_vend->umad_port.portnum)) < 0) {
800                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542C: "
801                         "umad_open_port() failed\n");
802                 goto Exit;
803         }
804
805         p_vend->umad_port_id = umad_port_id;
806
807         /* start receiver thread */
808         if (!(p_vend->receiver = calloc(1, sizeof(umad_receiver_t)))) {
809                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5423: "
810                         "Unable to alloc receiver struct\n");
811                 umad_close_port(umad_port_id);
812                 umad_release_port(&p_vend->umad_port);
813                 p_vend->umad_port.port_guid = 0;
814                 p_vend->umad_port_id = umad_port_id = -1;
815                 goto Exit;
816         }
817         if (umad_receiver_start(p_vend) != 0) {
818                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5420: "
819                         "umad_receiver_init failed\n");
820                 umad_close_port(umad_port_id);
821                 umad_release_port(&p_vend->umad_port);
822                 p_vend->umad_port.port_guid = 0;
823                 p_vend->umad_port_id = umad_port_id = -1;
824         }
825
826 Exit:
827         OSM_LOG_EXIT(p_vend->p_log);
828         return umad_port_id;
829 }
830
831 static void osm_vendor_close_port(osm_vendor_t * const p_vend)
832 {
833         umad_receiver_t *p_ur;
834         int i;
835
836         p_ur = p_vend->receiver;
837         p_vend->receiver = NULL;
838         if (p_ur) {
839                 umad_receiver_stop(p_ur);
840                 free(p_ur);
841         }
842
843         if (p_vend->umad_port_id >= 0) {
844                 for (i = 0; i < OSM_UMAD_MAX_AGENTS; i++)
845                         if (p_vend->agents[i])
846                                 umad_unregister(p_vend->umad_port_id, i);
847                 umad_close_port(p_vend->umad_port_id);
848                 umad_release_port(&p_vend->umad_port);
849                 p_vend->umad_port.port_guid = 0;
850                 p_vend->umad_port_id = -1;
851         }
852 }
853
854 static int set_bit(int nr, void *method_mask)
855 {
856         long mask, *addr = method_mask;
857         int retval;
858
859         addr += nr / (8 * sizeof(long));
860         mask = 1L << (nr % (8 * sizeof(long)));
861         retval = (mask & *addr) != 0;
862         *addr |= mask;
863         return retval;
864 }
865
866 osm_bind_handle_t
867 osm_vendor_bind(IN osm_vendor_t * const p_vend,
868                 IN osm_bind_info_t * const p_user_bind,
869                 IN osm_mad_pool_t * const p_mad_pool,
870                 IN osm_vend_mad_recv_callback_t mad_recv_callback,
871                 IN osm_vend_mad_send_err_callback_t send_err_callback,
872                 IN void *context)
873 {
874         ib_net64_t port_guid;
875         osm_umad_bind_info_t *p_bind = 0;
876         long method_mask[16 / sizeof(long)];
877         int umad_port_id;
878         uint8_t rmpp_version;
879
880         OSM_LOG_ENTER(p_vend->p_log);
881
882         CL_ASSERT(p_user_bind);
883         CL_ASSERT(p_mad_pool);
884         CL_ASSERT(mad_recv_callback);
885         CL_ASSERT(send_err_callback);
886
887         port_guid = p_user_bind->port_guid;
888
889         OSM_LOG(p_vend->p_log, OSM_LOG_INFO,
890                 "Mgmt class 0x%02x binding to port GUID 0x%" PRIx64 "\n",
891                 p_user_bind->mad_class, cl_ntoh64(port_guid));
892
893         if ((umad_port_id = osm_vendor_open_port(p_vend, port_guid)) < 0) {
894                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5424: "
895                         "Unable to open port 0x%" PRIx64 "\n",
896                         cl_ntoh64(port_guid));
897                 goto Exit;
898         }
899
900         if (umad_get_issm_path(p_vend->umad_port.ca_name,
901                                p_vend->umad_port.portnum,
902                                p_vend->issm_path,
903                                sizeof(p_vend->issm_path)) < 0) {
904                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542E: "
905                         "Cannot resolve issm path for port %s:%u\n",
906                         p_vend->umad_port.ca_name, p_vend->umad_port.portnum);
907                 goto Exit;
908         }
909
910         if (!(p_bind = malloc(sizeof(*p_bind)))) {
911                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5425: "
912                         "Unable to allocate internal bind object\n");
913                 goto Exit;
914         }
915
916         memset(p_bind, 0, sizeof(*p_bind));
917         p_bind->p_vend = p_vend;
918         p_bind->port_id = umad_port_id;
919         p_bind->client_context = context;
920         p_bind->mad_recv_callback = mad_recv_callback;
921         p_bind->send_err_callback = send_err_callback;
922         p_bind->p_mad_pool = p_mad_pool;
923         p_bind->port_guid = port_guid;
924         p_bind->timeout = p_user_bind->timeout ? p_user_bind->timeout :
925                           p_vend->timeout;
926         p_bind->max_retries = p_user_bind->retries ? p_user_bind->retries :
927                               p_vend->max_retries;
928
929         memset(method_mask, 0, sizeof method_mask);
930         if (p_user_bind->is_responder) {
931                 set_bit(IB_MAD_METHOD_GET, &method_mask);
932                 set_bit(IB_MAD_METHOD_SET, &method_mask);
933                 if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) {
934                         set_bit(IB_MAD_METHOD_GETTABLE, &method_mask);
935                         set_bit(IB_MAD_METHOD_DELETE, &method_mask);
936 #ifdef DUAL_SIDED_RMPP
937                         set_bit(IB_MAD_METHOD_GETMULTI, &method_mask);
938 #endif
939                         /* Add in IB_MAD_METHOD_GETTRACETABLE */
940                         /* when supported by OpenSM */
941                 }
942         }
943         if (p_user_bind->is_report_processor)
944                 set_bit(IB_MAD_METHOD_REPORT, &method_mask);
945         if (p_user_bind->is_trap_processor) {
946                 set_bit(IB_MAD_METHOD_TRAP, &method_mask);
947                 set_bit(IB_MAD_METHOD_TRAP_REPRESS, &method_mask);
948         }
949 #ifndef VENDOR_RMPP_SUPPORT
950         rmpp_version = 0;
951 #else
952         /* If SA class, set rmpp_version */
953         if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM)
954                 rmpp_version = 1;
955         else
956                 rmpp_version = 0;
957 #endif
958
959         if ((p_bind->agent_id = umad_register(p_vend->umad_port_id,
960                                               p_user_bind->mad_class,
961                                               p_user_bind->class_version,
962                                               rmpp_version, method_mask)) < 0) {
963                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5426: "
964                         "Unable to register class %u version %u\n",
965                         p_user_bind->mad_class, p_user_bind->class_version);
966                 free(p_bind);
967                 p_bind = 0;
968                 goto Exit;
969         }
970
971         if (p_bind->agent_id >= OSM_UMAD_MAX_AGENTS ||
972             p_vend->agents[p_bind->agent_id]) {
973                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5427: "
974                         "bad agent id %u or duplicate agent for class %u vers %u\n",
975                         p_bind->agent_id, p_user_bind->mad_class,
976                         p_user_bind->class_version);
977                 free(p_bind);
978                 p_bind = 0;
979                 goto Exit;
980         }
981
982         p_vend->agents[p_bind->agent_id] = p_bind;
983
984         /* If Subn Directed Route class, register Subn LID routed class */
985         if (p_user_bind->mad_class == IB_MCLASS_SUBN_DIR) {
986                 if ((p_bind->agent_id1 = umad_register(p_vend->umad_port_id,
987                                                        IB_MCLASS_SUBN_LID,
988                                                        p_user_bind->
989                                                        class_version, 0,
990                                                        method_mask)) < 0) {
991                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5428: "
992                                 "Unable to register class 1 version %u\n",
993                                 p_user_bind->class_version);
994                         free(p_bind);
995                         p_bind = 0;
996                         goto Exit;
997                 }
998
999                 if (p_bind->agent_id1 >= OSM_UMAD_MAX_AGENTS ||
1000                     p_vend->agents[p_bind->agent_id1]) {
1001                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5429: "
1002                                 "bad agent id %u or duplicate agent for class 1 vers %u\n",
1003                                 p_bind->agent_id1, p_user_bind->class_version);
1004                         free(p_bind);
1005                         p_bind = 0;
1006                         goto Exit;
1007                 }
1008
1009                 p_vend->agents[p_bind->agent_id1] = p_bind;
1010         }
1011
1012 Exit:
1013         OSM_LOG_EXIT(p_vend->p_log);
1014         return ((osm_bind_handle_t) p_bind);
1015 }
1016
1017 static void
1018 __osm_vendor_recv_dummy_cb(IN osm_madw_t * p_madw,
1019                            IN void *bind_context, IN osm_madw_t * p_req_madw)
1020 {
1021 #ifdef _DEBUG_
1022         fprintf(stderr,
1023                 "__osm_vendor_recv_dummy_cb: Ignoring received MAD after osm_vendor_unbind\n");
1024 #endif
1025 }
1026
1027 static void
1028 __osm_vendor_send_err_dummy_cb(IN void *bind_context,
1029                                IN osm_madw_t * p_req_madw)
1030 {
1031 #ifdef _DEBUG_
1032         fprintf(stderr,
1033                 "__osm_vendor_send_err_dummy_cb: Ignoring send error after osm_vendor_unbind\n");
1034 #endif
1035 }
1036
1037 void osm_vendor_unbind(IN osm_bind_handle_t h_bind)
1038 {
1039         osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
1040         osm_vendor_t *p_vend = p_bind->p_vend;
1041
1042         OSM_LOG_ENTER(p_vend->p_log);
1043
1044         pthread_mutex_lock(&p_vend->cb_mutex);
1045         p_bind->mad_recv_callback = __osm_vendor_recv_dummy_cb;
1046         p_bind->send_err_callback = __osm_vendor_send_err_dummy_cb;
1047         pthread_mutex_unlock(&p_vend->cb_mutex);
1048
1049         OSM_LOG_EXIT(p_vend->p_log);
1050 }
1051
1052 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
1053                          IN const uint32_t mad_size,
1054                          IN osm_vend_wrap_t * const p_vw)
1055 {
1056         osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
1057         osm_vendor_t *p_vend = p_bind->p_vend;
1058
1059         OSM_LOG_ENTER(p_vend->p_log);
1060
1061         OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
1062                 "Acquiring UMAD for p_madw = %p, size = %u\n", p_vw, mad_size);
1063         CL_ASSERT(p_vw);
1064         p_vw->size = mad_size;
1065         p_vw->umad = umad_alloc(1, mad_size + umad_size());
1066
1067         /* track locally */
1068         p_vw->h_bind = h_bind;
1069
1070         OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
1071                 "Acquired UMAD %p, size = %u\n", p_vw->umad, p_vw->size);
1072
1073         OSM_LOG_EXIT(p_vend->p_log);
1074         return (p_vw->umad ? umad_get_mad(p_vw->umad) : NULL);
1075 }
1076
1077 void
1078 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
1079 {
1080         osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
1081         osm_vendor_t *p_vend = p_bind->p_vend;
1082         osm_madw_t *p_madw;
1083
1084         OSM_LOG_ENTER(p_vend->p_log);
1085
1086         CL_ASSERT(p_vw);
1087
1088         OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Retiring UMAD %p\n", p_vw->umad);
1089
1090         /*
1091          * We moved the removal of the transaction to immediately after
1092          * it was looked up.
1093          */
1094
1095         /* free the mad but the wrapper is part of the madw object */
1096         umad_free(p_vw->umad);
1097         p_vw->umad = 0;
1098         p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
1099         p_madw->p_mad = NULL;
1100
1101         OSM_LOG_EXIT(p_vend->p_log);
1102 }
1103
1104 ib_api_status_t
1105 osm_vendor_send(IN osm_bind_handle_t h_bind,
1106                 IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
1107 {
1108         osm_umad_bind_info_t *const p_bind = h_bind;
1109         osm_vendor_t *const p_vend = p_bind->p_vend;
1110         osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
1111         osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
1112         ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
1113         ib_sa_mad_t *const p_sa = (ib_sa_mad_t *) p_mad;
1114         ib_mad_addr_t mad_addr;
1115         int ret = -1;
1116         int __attribute__((__unused__)) is_rmpp = 0;
1117         uint32_t sent_mad_size;
1118         uint64_t tid;
1119 #ifndef VENDOR_RMPP_SUPPORT
1120         uint32_t paylen = 0;
1121 #endif
1122
1123         OSM_LOG_ENTER(p_vend->p_log);
1124
1125         CL_ASSERT(p_vw->h_bind == h_bind);
1126         CL_ASSERT(p_mad == umad_get_mad(p_vw->umad));
1127
1128         if (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) {
1129                 umad_set_addr_net(p_vw->umad, 0xffff, 0, 0, 0);
1130                 umad_set_grh(p_vw->umad, NULL);
1131                 goto Resp;
1132         }
1133         if (p_mad->mgmt_class == IB_MCLASS_SUBN_LID) {
1134                 umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, 0, 0, 0);
1135                 umad_set_grh(p_vw->umad, NULL);
1136                 goto Resp;
1137         }
1138         /* GS classes */
1139         umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid,
1140                           p_mad_addr->addr_type.gsi.remote_qp,
1141                           p_mad_addr->addr_type.gsi.service_level,
1142                           IB_QP1_WELL_KNOWN_Q_KEY);
1143         if (p_mad_addr->addr_type.gsi.global_route) {
1144                 mad_addr.grh_present = 1;
1145                 mad_addr.gid_index = 0;
1146                 mad_addr.hop_limit = p_mad_addr->addr_type.gsi.grh_info.hop_limit;
1147                 ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi.grh_info.ver_class_flow,
1148                                           NULL, &mad_addr.traffic_class,
1149                                           &mad_addr.flow_label);
1150                 memcpy(&mad_addr.gid, &p_mad_addr->addr_type.gsi.grh_info.dest_gid, 16);
1151                 umad_set_grh(p_vw->umad, &mad_addr);
1152         } else
1153                 umad_set_grh(p_vw->umad, NULL);
1154         umad_set_pkey(p_vw->umad, p_mad_addr->addr_type.gsi.pkey_ix);
1155         if (ib_class_is_rmpp(p_mad->mgmt_class)) {      /* RMPP GS classes */
1156                 if (!ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa,
1157                                          IB_RMPP_FLAG_ACTIVE)) {
1158                         /* Clear RMPP header when RMPP not ACTIVE */
1159                         p_sa->rmpp_version = 0;
1160                         p_sa->rmpp_type = 0;
1161                         p_sa->rmpp_flags = 0;
1162                         p_sa->rmpp_status = 0;
1163 #ifdef VENDOR_RMPP_SUPPORT
1164                 } else
1165                         is_rmpp = 1;
1166                 OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "RMPP %d length %d\n",
1167                         ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa,
1168                                             IB_RMPP_FLAG_ACTIVE),
1169                         p_madw->mad_size);
1170 #else
1171                 } else {
1172                         p_sa->rmpp_version = 1;
1173                         p_sa->seg_num = cl_ntoh32(1);   /* first DATA is seg 1 */
1174                         p_sa->rmpp_flags |= (uint8_t) 0x70;     /* RRespTime of 14 (high 5 bits) */
1175                         p_sa->rmpp_status = 0;
1176                         paylen = p_madw->mad_size - IB_SA_MAD_HDR_SIZE;
1177                         paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE);
1178                         p_sa->paylen_newwin = cl_ntoh32(paylen);
1179                 }
1180 #endif
1181         }
1182
1183 Resp:
1184         if (resp_expected)
1185                 put_madw(p_vend, p_madw, p_mad->trans_id, p_mad->mgmt_class);
1186
1187 #ifdef VENDOR_RMPP_SUPPORT
1188         sent_mad_size = p_madw->mad_size;
1189 #else
1190         sent_mad_size = is_rmpp ? p_madw->mad_size - IB_SA_MAD_HDR_SIZE :
1191             p_madw->mad_size;
1192 #endif
1193         tid = cl_ntoh64(p_mad->trans_id);
1194         if ((ret = umad_send(p_bind->port_id, p_bind->agent_id, p_vw->umad,
1195                              sent_mad_size,
1196                              resp_expected ? p_bind->timeout : 0,
1197                              p_bind->max_retries)) < 0) {
1198                 OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5430: "
1199                         "Send p_madw = %p of size %d, Class 0x%x, Method 0x%X, "
1200                         "Attr 0x%X, TID 0x%" PRIx64 " failed %d (%m)\n",
1201                         p_madw, sent_mad_size, p_mad->mgmt_class,
1202                         p_mad->method, cl_ntoh16(p_mad->attr_id), tid, ret);
1203                 if (resp_expected) {
1204                         get_madw(p_vend, &p_mad->trans_id,
1205                                  p_mad->mgmt_class);    /* remove from aging table */
1206                         p_madw->status = IB_ERROR;
1207                         pthread_mutex_lock(&p_vend->cb_mutex);
1208                         (*p_bind->send_err_callback) (p_bind->client_context, p_madw);  /* cb frees madw */
1209                         pthread_mutex_unlock(&p_vend->cb_mutex);
1210                 } else
1211                         osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
1212                 goto Exit;
1213         }
1214
1215         if (!resp_expected)
1216                 osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
1217
1218         OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Completed sending %s TID 0x%" PRIx64 "\n",
1219                 resp_expected ? "request" : "response or unsolicited", tid);
1220 Exit:
1221         OSM_LOG_EXIT(p_vend->p_log);
1222         return (ret);
1223 }
1224
1225 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
1226 {
1227         osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
1228         osm_vendor_t *p_vend = p_bind->p_vend;
1229
1230         OSM_LOG_ENTER(p_vend->p_log);
1231         ;
1232         OSM_LOG_EXIT(p_vend->p_log);
1233         return (0);
1234 }
1235
1236 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
1237 {
1238         osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
1239         osm_vendor_t *p_vend = p_bind->p_vend;
1240
1241         OSM_LOG_ENTER(p_vend->p_log);
1242         if (TRUE == is_sm_val) {
1243                 p_vend->issmfd = open(p_vend->issm_path, O_NONBLOCK);
1244                 if (p_vend->issmfd < 0) {
1245                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5431: "
1246                                 "setting IS_SM capmask: cannot open file "
1247                                 "\'%s\': %s\n",
1248                                 p_vend->issm_path, strerror(errno));
1249                         p_vend->issmfd = -1;
1250                 }
1251         } else if (p_vend->issmfd != -1) {
1252                 if (0 != close(p_vend->issmfd))
1253                         OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5432: "
1254                                 "clearing IS_SM capmask: cannot close: %s\n",
1255                                 strerror(errno));
1256                 p_vend->issmfd = -1;
1257         }
1258         OSM_LOG_EXIT(p_vend->p_log);
1259 }
1260
1261 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
1262 {
1263         umad_debug(level);
1264 }
1265
1266 #endif                          /* OSM_VENDOR_INTF_OPENIB */