]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/libvendor/osm_vendor_ts.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / libvendor / osm_vendor_ts.c
1 /*
2  * Copyright (c) 2004-2008 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  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 #undef __init
37 #if HAVE_CONFIG_H
38 #  include <config.h>
39 #endif                          /* HAVE_CONFIG_H */
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <vendor/osm_vendor_ts.h>
44 #include <vendor/osm_vendor_api.h>
45 #include <vendor/osm_ts_useraccess.h>
46 #include <opensm/osm_subnet.h>
47 #include <opensm/osm_opensm.h>
48
49 /*
50   Since a race can accure on requests. Meaning - a response is received before
51   the send_callback is called - we will save both the madw_p and the fact
52   whether or not it is a response. A race can occure only on requests that did
53   not fail, and then the madw_p will be put back in the pool before the
54   callback.
55 */
56 uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw)
57 {
58         uint64_t wrid = 0;
59
60         CL_ASSERT(p_madw->p_mad);
61
62         memcpy(&wrid, &p_madw, sizeof(osm_madw_t *));
63         wrid = (wrid << 1) |
64             ib_mad_is_response(p_madw->p_mad) |
65             (p_madw->p_mad->method == IB_MAD_METHOD_TRAP_REPRESS);
66         return wrid;
67 }
68
69 void
70 __osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid,
71                                   OUT uint8_t * is_resp,
72                                   OUT osm_madw_t ** pp_madw)
73 {
74         *is_resp = wrid & 0x0000000000000001;
75         wrid = wrid >> 1;
76         memcpy(pp_madw, &wrid, sizeof(osm_madw_t *));
77 }
78
79 /**********************************************************************
80  * TS MAD to OSM ADDRESS VECTOR
81  **********************************************************************/
82 void
83 __osm_ts_conv_mad_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend,
84                                        IN struct ib_mad *p_mad,
85                                        IN uint8_t is_smi,
86                                        OUT osm_mad_addr_t * p_mad_addr)
87 {
88         p_mad_addr->dest_lid = cl_hton16(p_mad->slid);
89         p_mad_addr->static_rate = 0;    /*  HACK - we do not know the rate ! */
90         p_mad_addr->path_bits = 0;      /*  HACK - no way to know in TS */
91         if (is_smi) {
92                 /* SMI */
93                 p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid);
94                 p_mad_addr->addr_type.smi.port_num = p_mad->port;
95         } else {
96                 /* GSI */
97                 p_mad_addr->addr_type.gsi.remote_qp = p_mad->sqpn;
98                 p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
99                 p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index;
100                 p_mad_addr->addr_type.gsi.service_level = 0;    /*  HACK no way to know */
101
102                 p_mad_addr->addr_type.gsi.global_route = FALSE; /*  HACK no way to know */
103                 /* copy the GRH data if relevant */
104                 /*
105                    if (p_mad_addr->addr_type.gsi.global_route)
106                    {
107                    p_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
108                    ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version,
109                    p_rcv_desc->grh.traffic_class,
110                    p_rcv_desc->grh.flow_label);
111                    p_mad_addr->addr_type.gsi.grh_info.hop_limit =  p_rcv_desc->grh.hop_limit;
112                    memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw,
113                    &p_rcv_desc->grh.sgid, sizeof(ib_net64_t));
114                    memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw,
115                    p_rcv_desc->grh.dgid,  sizeof(ib_net64_t));
116                    }
117                  */
118         }
119 }
120
121 /**********************************************************************
122  * OSM ADDR VECTOR TO TS MAD:
123  **********************************************************************/
124 void
125 __osm_ts_conv_osm_addr_to_ts_addr(IN osm_mad_addr_t * p_mad_addr,
126                                   IN uint8_t is_smi, OUT struct ib_mad *p_mad)
127 {
128
129         /* For global destination or Multicast address: */
130         p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid);
131         p_mad->sl = 0;
132         if (is_smi) {
133                 p_mad->sqpn = 0;
134                 p_mad->dqpn = 0;
135         } else {
136                 p_mad->sqpn = 1;
137                 p_mad->dqpn = p_mad_addr->addr_type.gsi.remote_qp;
138         }
139 }
140
141 /**********************************************************************
142  **********************************************************************/
143 void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind)
144 {
145         osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
146         osm_vendor_t *p_vend = p_bind->p_vend;
147         VAPI_ret_t status;
148         VAPI_hca_attr_t attr_mod;
149         VAPI_hca_attr_mask_t attr_mask;
150
151         OSM_LOG_ENTER(p_vend->p_log);
152
153         memset(&attr_mod, 0, sizeof(attr_mod));
154         memset(&attr_mask, 0, sizeof(attr_mask));
155
156         attr_mod.is_sm = FALSE;
157         attr_mask = HCA_ATTR_IS_SM;
158
159         status =
160             VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
161                                  &attr_mask);
162         if (status != VAPI_OK) {
163                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
164                         "__osm_vendor_clear_sm: ERR 5021: "
165                         "Unable set 'IS_SM' bit in port attributes (%d).\n",
166                         status);
167         }
168
169         OSM_LOG_EXIT(p_vend->p_log);
170 }
171
172 /**********************************************************************
173  * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT
174  **********************************************************************/
175 void osm_vendor_construct(IN osm_vendor_t * const p_vend)
176 {
177         memset(p_vend, 0, sizeof(*p_vend));
178         cl_thread_construct(&(p_vend->smi_bind.poller));
179         cl_thread_construct(&(p_vend->gsi_bind.poller));
180 }
181
182 /**********************************************************************
183  * DEALOCATE osm_vendor_t
184  **********************************************************************/
185 void osm_vendor_destroy(IN osm_vendor_t * const p_vend)
186 {
187         OSM_LOG_ENTER(p_vend->p_log);
188         osm_transaction_mgr_destroy(p_vend);
189
190         /* Destroy the poller threads */
191         /* HACK: can you destroy an un-initialized thread ? */
192         pthread_cancel(p_vend->smi_bind.poller.osd.id);
193         pthread_cancel(p_vend->gsi_bind.poller.osd.id);
194         cl_thread_destroy(&(p_vend->smi_bind.poller));
195         cl_thread_destroy(&(p_vend->gsi_bind.poller));
196         OSM_LOG_EXIT(p_vend->p_log);
197 }
198
199 /**********************************************************************
200 DEALLOCATE A POINTER TO osm_vendor_t
201 **********************************************************************/
202 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
203 {
204         CL_ASSERT(pp_vend);
205
206         osm_vendor_destroy(*pp_vend);
207         free(*pp_vend);
208         *pp_vend = NULL;
209 }
210
211 /**********************************************************************
212  Initializes the vendor:
213 **********************************************************************/
214
215 ib_api_status_t
216 osm_vendor_init(IN osm_vendor_t * const p_vend,
217                 IN osm_log_t * const p_log, IN const uint32_t timeout)
218 {
219         ib_api_status_t status = IB_SUCCESS;
220
221         OSM_LOG_ENTER(p_log);
222
223         p_vend->p_log = p_log;
224         p_vend->p_transaction_mgr = NULL;
225         osm_transaction_mgr_init(p_vend);
226         p_vend->timeout = timeout;
227
228         /* we use the file handle to track the binding */
229         p_vend->smi_bind.ul_dev_fd = -1;
230         p_vend->gsi_bind.ul_dev_fd = -1;
231
232         OSM_LOG_EXIT(p_log);
233         return (status);
234 }
235
236 /**********************************************************************
237  *  Create and Initialize osm_vendor_t Object
238  **********************************************************************/
239 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
240                              IN const uint32_t timeout)
241 {
242         ib_api_status_t status;
243         osm_vendor_t *p_vend;
244
245         OSM_LOG_ENTER(p_log);
246
247         CL_ASSERT(p_log);
248
249         p_vend = malloc(sizeof(*p_vend));
250         if (p_vend != NULL) {
251                 memset(p_vend, 0, sizeof(*p_vend));
252
253                 status = osm_vendor_init(p_vend, p_log, timeout);
254                 if (status != IB_SUCCESS) {
255                         osm_vendor_delete(&p_vend);
256                 }
257         } else {
258                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
259                         "osm_vendor_new: ERR 5007: "
260                         "Fail to allocate vendor object.\n");
261         }
262
263         OSM_LOG_EXIT(p_log);
264         return (p_vend);
265 }
266
267 /**********************************************************************
268  * TS RCV Thread callback
269  * HACK: - we need to make this support arbitrary size mads.
270  **********************************************************************/
271 void
272 __osm_ts_rcv_callback(IN osm_ts_bind_info_t * p_bind,
273                       IN osm_mad_addr_t * p_mad_addr,
274                       IN uint32_t mad_size, IN void *p_mad)
275 {
276         ib_api_status_t status;
277         osm_madw_t *p_req_madw = NULL;
278         osm_madw_t *p_madw;
279         osm_vend_wrap_t *p_new_vw;
280         ib_mad_t *p_mad_buf;
281         osm_log_t *const p_log = p_bind->p_vend->p_log;
282
283         OSM_LOG_ENTER(p_log);
284
285         /* if it is a response MAD we mustbe able to get the request */
286         if (ib_mad_is_response((ib_mad_t *) p_mad)) {
287                 /* can we find a matching madw by this payload TID */
288                 status =
289                     osm_transaction_mgr_get_madw_for_tid(p_bind->p_vend,
290                                                          (ib_mad_t *) p_mad,
291                                                          &p_req_madw);
292                 if (status != IB_SUCCESS) {
293                         osm_log(p_log, OSM_LOG_ERROR,
294                                 "__osm_ts_rcv_callback: ERR 5008: "
295                                 "Error obtaining request madw by TID (%d).\n",
296                                 status);
297                         p_req_madw = NULL;
298                 }
299
300                 if (p_req_madw == NULL) {
301                         osm_log(p_log, OSM_LOG_ERROR,
302                                 "__osm_ts_rcv_callback: ERR 5009:  "
303                                 "Fail to obtain request madw for receined MAD. Aborting CB.\n");
304                         goto Exit;
305                 }
306         }
307
308         /* do we have a request ??? */
309         if (p_req_madw == NULL) {
310
311                 /* if not - get new osm_madw and arrange it. */
312                 /* create the new madw in the pool */
313                 p_madw = osm_mad_pool_get(p_bind->p_osm_pool,
314                                           (osm_bind_handle_t) p_bind,
315                                           mad_size, p_mad_addr);
316                 if (p_madw == NULL) {
317                         osm_log(p_log, OSM_LOG_ERROR,
318                                 "__osm_ts_rcv_callback: ERR 5010: "
319                                 "Error request for a new madw.\n");
320                         goto Exit;
321                 }
322                 /* HACK: we cust to avoid the const ??? */
323                 p_mad_buf = (void *)p_madw->p_mad;
324         } else {
325                 /* we have the madw defined during the send and stored in the vend_wrap */
326                 /* we need to make sure the wrapper is correctly init there */
327                 CL_ASSERT(p_req_madw->vend_wrap.p_resp_madw != 0);
328                 p_madw = p_req_madw->vend_wrap.p_resp_madw;
329
330                 CL_ASSERT(p_madw->h_bind);
331                 p_mad_buf =
332                     osm_vendor_get(p_madw->h_bind, mad_size,
333                                    &p_madw->vend_wrap);
334
335                 if (p_mad_buf == NULL) {
336                         osm_log(p_log, OSM_LOG_ERROR,
337                                 "__osm_ts_rcv_callback: ERR 5011: "
338                                 "Unable to acquire wire MAD.\n");
339
340                         goto Exit;
341                 }
342
343                 /*
344                    Finally, attach the wire MAD to this wrapper.
345                  */
346                 osm_madw_set_mad(p_madw, p_mad_buf);
347         }
348
349         /* init some fields of the vendor wrapper */
350         p_new_vw = osm_madw_get_vend_ptr(p_madw);
351         p_new_vw->h_bind = p_bind;
352         p_new_vw->size = mad_size;
353         p_new_vw->p_resp_madw = NULL;
354         p_new_vw->p_mad_buf = p_mad_buf;
355
356         memcpy(p_new_vw->p_mad_buf, p_mad, mad_size);
357
358         /* attach the buffer to the wrapper */
359         p_madw->p_mad = p_mad_buf;
360
361         /* we can also make sure we marked the size and bind on the returned madw */
362         p_madw->h_bind = p_new_vw->h_bind;
363
364         /* call the CB */
365         (*(osm_vend_mad_recv_callback_t) p_bind->rcv_callback)
366             (p_madw, p_bind->client_context, p_req_madw);
367
368 Exit:
369         OSM_LOG_EXIT(p_log);
370 }
371
372 /**********************************************************************
373  * TS Send callback : invoked after each send
374  *
375  **********************************************************************/
376 void
377 __osm_ts_send_callback(IN osm_ts_bind_info_t * bind_info_p,
378                        IN boolean_t is_resp,
379                        IN osm_madw_t * madw_p, IN IB_comp_status_t status)
380 {
381         osm_log_t *const p_log = bind_info_p->p_vend->p_log;
382         osm_vend_wrap_t *p_vw;
383
384         OSM_LOG_ENTER(p_log);
385
386         osm_log(p_log, OSM_LOG_DEBUG,
387                 "__osm_ts_send_callback: INFO 1008: "
388                 "Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp);
389
390         /* we need to handle requests and responses differently */
391         if (is_resp) {
392                 if (status != IB_COMP_SUCCESS) {
393                         osm_log(p_log, OSM_LOG_ERROR,
394                                 "__osm_ts_send_callback: ERR 5012: "
395                                 "Error Sending Response MADW:%p.\n", madw_p);
396                 } else {
397                         osm_log(p_log, OSM_LOG_DEBUG,
398                                 "__osm_ts_send_callback: DBG 1008: "
399                                 "Completed Sending Response MADW:%p.\n",
400                                 madw_p);
401                 }
402
403                 /* if we are a response - we need to clean it up */
404                 osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p);
405         } else {
406
407                 /* this call back is invoked on completion of send - error or not */
408                 if (status != IB_COMP_SUCCESS) {
409
410                         osm_log(p_log, OSM_LOG_ERROR,
411                                 "__osm_ts_send_callback: ERR 5013: "
412                                 "Received an Error from IB_MGT Send (%d).\n",
413                                 status);
414
415                         p_vw = osm_madw_get_vend_ptr(madw_p);
416                         CL_ASSERT(p_vw);
417
418                         /*
419                            Return any wrappers to the pool that may have been
420                            pre-emptively allocated to handle a receive.
421                          */
422                         if (p_vw->p_resp_madw) {
423                                 osm_mad_pool_put(bind_info_p->p_osm_pool,
424                                                  p_vw->p_resp_madw);
425                                 p_vw->p_resp_madw = NULL;
426                         }
427
428                         /* invoke the CB */
429                         (*(osm_vend_mad_send_err_callback_t) bind_info_p->
430                          send_err_callback)
431                             (bind_info_p->client_context, madw_p);
432                 } else {
433                         /* successful request send - do nothing - the response will need the
434                            out mad */
435                         osm_log(p_log, OSM_LOG_DEBUG,
436                                 "__osm_ts_send_callback: DBG 1008: "
437                                 "Completed Sending Request MADW:%p.\n", madw_p);
438                 }
439         }
440
441         OSM_LOG_EXIT(p_log);
442 }
443
444 /**********************************************************************
445  * Poller thread:
446  * Always receive 256byte mads from the devcie file
447  **********************************************************************/
448 void __osm_vendor_ts_poller(IN void *p_ptr)
449 {
450         int ts_ret_code;
451         struct ib_mad mad;
452         osm_mad_addr_t mad_addr;
453         osm_ts_bind_info_t *const p_bind = (osm_ts_bind_info_t *) p_ptr;
454
455         OSM_LOG_ENTER(p_bind->p_vend->p_log);
456         /* we set the type of cancelation for this thread */
457         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
458
459         while (1) {
460                 /* we read one mad at a time and pass it to the read callback function */
461                 ts_ret_code = read(p_bind->ul_dev_fd, &mad, sizeof(mad));
462                 if (ts_ret_code != sizeof(mad)) {
463                         osm_log(p_bind->p_vend->p_log, OSM_LOG_ERROR,
464                                 "__osm_vendor_ts_poller: ERR 5003: "
465                                 "error with read, bytes = %d, errno = %d\n",
466                                 ts_ret_code, errno);
467                 } else {
468                         osm_log(p_bind->p_vend->p_log, OSM_LOG_DEBUG,
469                                 "__osm_vendor_ts_poller: "
470                                 "MAD QPN:%d SLID:0x%04x class:0x%02x "
471                                 "__osm_vendor_ts_poller:0x%02x attr:0x%04x status:0x%04x "
472                                 "__osm_vendor_ts_poller:0x%016" PRIx64 "\n",
473                                 cl_ntoh32(mad.dqpn),
474                                 cl_ntoh16(mad.slid),
475                                 mad.mgmt_class,
476                                 mad.r_method,
477                                 cl_ntoh16(mad.attribute_id),
478                                 cl_ntoh16(mad.status),
479                                 cl_ntoh64(mad.transaction_id));
480
481                         /* first arrange an address */
482                         __osm_ts_conv_mad_rcv_desc_to_osm_addr(p_bind->p_vend,
483                                                                &mad,
484                                                                (((ib_mad_t *) &
485                                                                  mad)->
486                                                                 mgmt_class ==
487                                                                 IB_MCLASS_SUBN_LID)
488                                                                ||
489                                                                (((ib_mad_t *) &
490                                                                  mad)->
491                                                                 mgmt_class ==
492                                                                 IB_MCLASS_SUBN_DIR),
493                                                                &mad_addr);
494
495                         /* call the receiver callback */
496                         /* HACK: this should be replaced with a call to the RMPP Assembly ... */
497                         __osm_ts_rcv_callback(p_bind, &mad_addr, 256, &mad);
498                 }
499         }
500
501         OSM_LOG_EXIT(p_bind->p_vend->p_log);
502 }
503
504 /**********************************************************************
505  * BINDs a callback (rcv and send error) for a given class and method
506  * defined by the given:  osm_bind_info_t
507  **********************************************************************/
508 osm_bind_handle_t
509 osm_vendor_bind(IN osm_vendor_t * const p_vend,
510                 IN osm_bind_info_t * const p_user_bind,
511                 IN osm_mad_pool_t * const p_mad_pool,
512                 IN osm_vend_mad_recv_callback_t mad_recv_callback,
513                 IN osm_vend_mad_send_err_callback_t send_err_callback,
514                 IN void *context)
515 {
516         ib_net64_t port_guid;
517         osm_ts_bind_info_t *p_bind = NULL;
518         VAPI_hca_hndl_t hca_hndl;
519         VAPI_hca_id_t hca_id;
520         uint32_t port_num;
521         ib_api_status_t status;
522         int device_fd;
523         char device_file[16];
524         osm_ts_user_mad_filter filter;
525         int ts_ioctl_ret;
526         int qpn;
527
528         OSM_LOG_ENTER(p_vend->p_log);
529
530         CL_ASSERT(p_mad_pool);
531
532         port_guid = p_user_bind->port_guid;
533
534         osm_log(p_vend->p_log, OSM_LOG_INFO,
535                 "osm_vendor_bind: "
536                 "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid));
537
538         switch (p_user_bind->mad_class) {
539         case IB_MCLASS_SUBN_LID:
540         case IB_MCLASS_SUBN_DIR:
541                 p_bind = &(p_vend->smi_bind);
542                 qpn = 0;
543                 break;
544
545         case IB_MCLASS_SUBN_ADM:
546         default:
547                 p_bind = &(p_vend->gsi_bind);
548                 qpn = 1;
549                 break;
550         }
551
552         /* Make sure we did not previously opened the file */
553         if (p_bind->ul_dev_fd >= 0) {
554                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
555                         "osm_vendor_bind: ERR 5004: "
556                         "Already binded to port %u\n", p_bind->port_num);
557                 goto Exit;
558         }
559
560         /*
561            We need to figure out what is the TS file name to attach to.
562            I guess it is following the index of the port in the table of
563            ports.
564          */
565
566         /* obtain the hca name and port num from the guid */
567         osm_log(p_vend->p_log, OSM_LOG_DEBUG,
568                 "osm_vendor_bind: "
569                 "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
570                 cl_ntoh64(port_guid));
571         status =
572             osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl,
573                                             &hca_id, &port_num);
574         if (status != IB_SUCCESS) {
575                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
576                         "osm_vendor_bind: ERR 5005: "
577                         "Fail to find port number of port guid:0x%016" PRIx64
578                         "\n", port_guid);
579                 goto Exit;
580         }
581
582         /* the file name is just /dev/ts_ua0: */
583         strcpy(device_file, "/dev/ts_ua0");
584
585         osm_log(p_vend->p_log, OSM_LOG_ERROR,
586                 "osm_vendor_bind: " "Opening TS UL dev file:%s\n", device_file);
587
588         /* Open the file ... */
589         device_fd = open(device_file, O_RDWR);
590         if (device_fd < 0) {
591                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
592                         "osm_vendor_bind: ERR 5006: "
593                         "Fail to open TS UL dev file:%s\n", device_file);
594                 goto Exit;
595         }
596
597         /* track this bind request info */
598         p_bind->ul_dev_fd = device_fd;
599         p_bind->port_num = port_num;
600         p_bind->p_vend = p_vend;
601         p_bind->client_context = context;
602         p_bind->rcv_callback = mad_recv_callback;
603         p_bind->send_err_callback = send_err_callback;
604         p_bind->p_osm_pool = p_mad_pool;
605         p_bind->hca_hndl = hca_hndl;
606
607         /*
608          * Create the MAD filter on this file handle.
609          */
610         filter.port = port_num;
611
612         filter.qpn = qpn;
613         filter.mgmt_class = p_user_bind->mad_class;
614         filter.direction = TS_IB_MAD_DIRECTION_IN;
615         filter.mask =
616             TS_IB_MAD_FILTER_DIRECTION |
617             TS_IB_MAD_FILTER_PORT |
618             TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS;
619
620         ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter);
621         if (ts_ioctl_ret < 0) {
622                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
623                         "osm_vendor_bind: ERR 5014: "
624                         "Fail to register MAD filter with err:%u\n",
625                         ts_ioctl_ret);
626                 goto Exit;
627         }
628
629         /* Initialize the listener thread for this port */
630         status = cl_thread_init(&p_bind->poller,
631                                 __osm_vendor_ts_poller, p_bind,
632                                 "osm ts poller");
633         if (status != IB_SUCCESS)
634                 goto Exit;
635
636 Exit:
637         OSM_LOG_EXIT(p_vend->p_log);
638         return ((osm_bind_handle_t) p_bind);
639 }
640
641 /**********************************************************************
642 Get a mad from the lower level.
643 The osm_vend_wrap_t is a wrapper used to connect the mad to the response.
644 **********************************************************************/
645 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
646                          IN const uint32_t mad_size,
647                          IN osm_vend_wrap_t * const p_vw)
648 {
649         ib_mad_t *p_mad;
650         osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
651         osm_vendor_t *p_vend = p_bind->p_vend;
652
653         OSM_LOG_ENTER(p_vend->p_log);
654
655         CL_ASSERT(p_vw);
656
657         p_vw->size = mad_size;
658
659         /* allocate it */
660         p_mad = (ib_mad_t *) malloc(p_vw->size);
661         if (p_mad == NULL) {
662                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
663                         "osm_vendor_get: ERR 5022: "
664                         "Error Obtaining MAD buffer.\n");
665                 goto Exit;
666         }
667
668         memset(p_mad, 0, p_vw->size);
669
670         /* track locally */
671         p_vw->p_mad_buf = p_mad;
672         p_vw->h_bind = h_bind;
673         p_vw->p_resp_madw = NULL;
674
675         if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
676                 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
677                         "osm_vendor_get: "
678                         "Acquired MAD %p, size = %u.\n", p_mad, p_vw->size);
679         }
680
681 Exit:
682         OSM_LOG_EXIT(p_vend->p_log);
683         return (p_mad);
684 }
685
686 /**********************************************************************
687  * Return a MAD by providing it's wrapper object.
688  **********************************************************************/
689 void
690 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
691 {
692         osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
693         osm_vendor_t *p_vend = p_bind->p_vend;
694         osm_madw_t *p_madw;
695
696         OSM_LOG_ENTER(p_vend->p_log);
697
698         CL_ASSERT(p_vw);
699         CL_ASSERT(p_vw->p_mad_buf);
700
701         if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
702                 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
703                         "osm_vendor_put: " "Retiring MAD %p.\n",
704                         p_vw->p_mad_buf);
705         }
706
707         /*
708          * We moved the removal of the transaction to immediatly after
709          * it was looked up.
710          */
711
712         /* free the mad but the wrapper is part of the madw object */
713         free(p_vw->p_mad_buf);
714         p_vw->p_mad_buf = NULL;
715         p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
716         p_madw->p_mad = NULL;
717
718         OSM_LOG_EXIT(p_vend->p_log);
719 }
720
721 /**********************************************************************
722 Actually Send a MAD
723
724 MADs are buffers of type: struct ib_mad - so they are limited by size.
725 This is for internal use by osm_vendor_send and the transaction mgr
726 retry too.
727 **********************************************************************/
728 ib_api_status_t
729 osm_ts_send_mad(IN osm_ts_bind_info_t * p_bind, IN osm_madw_t * const p_madw)
730 {
731         osm_vendor_t *const p_vend = p_bind->p_vend;
732         osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
733         ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
734         struct ib_mad ts_mad;
735         int ret;
736         ib_api_status_t status;
737
738         OSM_LOG_ENTER(p_vend->p_log);
739
740         /*
741          * Copy the MAD over to the sent mad
742          */
743         memcpy(&ts_mad, p_mad, 256);
744
745         /*
746          * For all sends other than directed route SM MADs,
747          * acquire an address vector for the destination.
748          */
749         if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
750                 __osm_ts_conv_osm_addr_to_ts_addr(p_mad_addr,
751                                                   p_mad->mgmt_class ==
752                                                   IB_MCLASS_SUBN_LID, &ts_mad);
753         } else {
754                 /* is a directed route - we need to construct a permissive address */
755                 /* we do not need port number since it is part of the mad_hndl */
756                 ts_mad.dlid = IB_LID_PERMISSIVE;
757                 ts_mad.slid = IB_LID_PERMISSIVE;
758         }
759         if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) ||
760             (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) {
761                 ts_mad.sqpn = 0;
762                 ts_mad.dqpn = 0;
763         } else {
764                 ts_mad.sqpn = 1;
765                 ts_mad.dqpn = 1;
766         }
767         ts_mad.port = p_bind->port_num;
768
769         /* send it */
770         ret = write(p_bind->ul_dev_fd, &ts_mad, sizeof(ts_mad));
771
772         if (ret != sizeof(ts_mad)) {
773                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
774                         "osm_ts_send_mad: ERR 5026: "
775                         "Error sending mad (%d).\n", ret);
776                 status = IB_ERROR;
777                 goto Exit;
778         }
779
780         status = IB_SUCCESS;
781
782 Exit:
783         OSM_LOG_EXIT(p_vend->p_log);
784         return (status);
785 }
786
787 /**********************************************************************
788 Send a MAD through.
789
790 What is unclear to me is the need for the setting of all the MAD Wrapper
791 fields. Seems like the OSM uses these values during it's processing...
792 **********************************************************************/
793 ib_api_status_t
794 osm_vendor_send(IN osm_bind_handle_t h_bind,
795                 IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
796 {
797         osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
798         osm_vendor_t *const p_vend = p_bind->p_vend;
799         osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
800         ib_api_status_t status;
801
802         OSM_LOG_ENTER(p_vend->p_log);
803
804         /*
805          * If a response is expected to this MAD, then preallocate
806          * a mad wrapper to contain the wire MAD received in the
807          * response.  Allocating a wrapper here allows for easier
808          * failure paths than after we already received the wire mad.
809          */
810         if (resp_expected == TRUE) {
811                 /* we track it in the vendor wrapper */
812                 p_vw->p_resp_madw =
813                     osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool);
814                 if (p_vw->p_resp_madw == NULL) {
815                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
816                                 "osm_vendor_send: ERR 5024: "
817                                 "Unable to allocate MAD wrapper.\n");
818                         status = IB_INSUFFICIENT_RESOURCES;
819                         goto Exit;
820                 }
821
822                 /* put some minimal info on that wrapper */
823                 ((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind;
824
825                 /* we also want to track it in the TID based map */
826                 status = osm_transaction_mgr_insert_madw((osm_bind_handle_t *)
827                                                          p_bind, p_madw);
828                 if (status != IB_SUCCESS) {
829                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
830                                 "osm_vendor_send: ERR 5025: "
831                                 "Error inserting request madw by TID (%d).\n",
832                                 status);
833                 }
834         } else
835                 p_vw->p_resp_madw = NULL;
836
837         /* do the actual send */
838         /* HACK: to be replaced by call to RMPP Segmentation */
839         status = osm_ts_send_mad(p_bind, p_madw);
840
841         /* we do not get an asycn callback so call it ourselves */
842         /* this will handle all cleanup if neccessary */
843         __osm_ts_send_callback(p_bind, !resp_expected, p_madw, status);
844
845 Exit:
846         OSM_LOG_EXIT(p_vend->p_log);
847         return (status);
848 }
849
850 /**********************************************************************
851  * the idea here is to change the content of the bind such that it
852  * will hold the local address used for sending directed route by the SMA.
853  **********************************************************************/
854 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
855 {
856         osm_vendor_t *p_vend = ((osm_ts_bind_info_t *) h_bind)->p_vend;
857
858         OSM_LOG_ENTER(p_vend->p_log);
859
860         osm_log(p_vend->p_log, OSM_LOG_DEBUG,
861                 "osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n");
862
863         OSM_LOG_EXIT(p_vend->p_log);
864
865         return (IB_SUCCESS);
866 }
867
868 /**********************************************************************
869  **********************************************************************/
870 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
871 {
872         osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
873         osm_vendor_t *p_vend = p_bind->p_vend;
874         VAPI_ret_t status;
875         VAPI_hca_attr_t attr_mod;
876         VAPI_hca_attr_mask_t attr_mask;
877
878         OSM_LOG_ENTER(p_vend->p_log);
879
880         memset(&attr_mod, 0, sizeof(attr_mod));
881         memset(&attr_mask, 0, sizeof(attr_mask));
882
883         attr_mod.is_sm = is_sm_val;
884         attr_mask = HCA_ATTR_IS_SM;
885
886         status =
887             VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
888                                  &attr_mask);
889         if (status != VAPI_OK) {
890                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
891                         "osm_vendor_set_sm: ERR 5027: "
892                         "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n",
893                         is_sm_val, status);
894         }
895
896         OSM_LOG_EXIT(p_vend->p_log);
897 }
898
899 /**********************************************************************
900  **********************************************************************/
901 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
902 {
903
904 }