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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
39 #endif /* HAVE_CONFIG_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>
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
56 uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw)
60 CL_ASSERT(p_madw->p_mad);
62 memcpy(&wrid, &p_madw, sizeof(osm_madw_t *));
64 ib_mad_is_response(p_madw->p_mad);
69 __osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid,
70 OUT uint8_t * is_resp,
71 OUT osm_madw_t ** pp_madw)
73 *is_resp = wrid & 0x0000000000000001;
75 memcpy(pp_madw, &wrid, sizeof(osm_madw_t *));
78 /**********************************************************************
79 * TS MAD to OSM ADDRESS VECTOR
80 **********************************************************************/
82 __osm_ts_conv_mad_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend,
83 IN struct ib_mad *p_mad,
85 OUT osm_mad_addr_t * p_mad_addr)
87 p_mad_addr->dest_lid = cl_hton16(p_mad->slid);
88 p_mad_addr->static_rate = 0; /* HACK - we do not know the rate ! */
89 p_mad_addr->path_bits = 0; /* HACK - no way to know in TS */
92 p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid);
93 p_mad_addr->addr_type.smi.port_num = p_mad->port;
96 p_mad_addr->addr_type.gsi.remote_qp = p_mad->sqpn;
97 p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
98 p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index;
99 p_mad_addr->addr_type.gsi.service_level = 0; /* HACK no way to know */
101 p_mad_addr->addr_type.gsi.global_route = FALSE; /* HACK no way to know */
102 /* copy the GRH data if relevant */
104 if (p_mad_addr->addr_type.gsi.global_route)
106 p_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
107 ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version,
108 p_rcv_desc->grh.traffic_class,
109 p_rcv_desc->grh.flow_label);
110 p_mad_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit;
111 memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw,
112 &p_rcv_desc->grh.sgid, sizeof(ib_net64_t));
113 memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw,
114 p_rcv_desc->grh.dgid, sizeof(ib_net64_t));
120 /**********************************************************************
121 * OSM ADDR VECTOR TO TS MAD:
122 **********************************************************************/
124 __osm_ts_conv_osm_addr_to_ts_addr(IN osm_mad_addr_t * p_mad_addr,
125 IN uint8_t is_smi, OUT struct ib_mad *p_mad)
128 /* For global destination or Multicast address: */
129 p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid);
136 p_mad->dqpn = p_mad_addr->addr_type.gsi.remote_qp;
140 void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind)
142 osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
143 osm_vendor_t *p_vend = p_bind->p_vend;
145 VAPI_hca_attr_t attr_mod;
146 VAPI_hca_attr_mask_t attr_mask;
148 OSM_LOG_ENTER(p_vend->p_log);
150 memset(&attr_mod, 0, sizeof(attr_mod));
151 memset(&attr_mask, 0, sizeof(attr_mask));
153 attr_mod.is_sm = FALSE;
154 attr_mask = HCA_ATTR_IS_SM;
157 VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
159 if (status != VAPI_OK) {
160 osm_log(p_vend->p_log, OSM_LOG_ERROR,
161 "__osm_vendor_clear_sm: ERR 5021: "
162 "Unable set 'IS_SM' bit in port attributes (%d).\n",
166 OSM_LOG_EXIT(p_vend->p_log);
169 /**********************************************************************
170 * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT
171 **********************************************************************/
172 void osm_vendor_construct(IN osm_vendor_t * const p_vend)
174 memset(p_vend, 0, sizeof(*p_vend));
175 cl_thread_construct(&(p_vend->smi_bind.poller));
176 cl_thread_construct(&(p_vend->gsi_bind.poller));
179 /**********************************************************************
180 * DEALOCATE osm_vendor_t
181 **********************************************************************/
182 void osm_vendor_destroy(IN osm_vendor_t * const p_vend)
184 OSM_LOG_ENTER(p_vend->p_log);
185 osm_transaction_mgr_destroy(p_vend);
187 /* Destroy the poller threads */
188 /* HACK: can you destroy an un-initialized thread ? */
189 pthread_cancel(p_vend->smi_bind.poller.osd.id);
190 pthread_cancel(p_vend->gsi_bind.poller.osd.id);
191 cl_thread_destroy(&(p_vend->smi_bind.poller));
192 cl_thread_destroy(&(p_vend->gsi_bind.poller));
193 OSM_LOG_EXIT(p_vend->p_log);
196 /**********************************************************************
197 DEALLOCATE A POINTER TO osm_vendor_t
198 **********************************************************************/
199 void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
203 osm_vendor_destroy(*pp_vend);
208 /**********************************************************************
209 Initializes the vendor:
210 **********************************************************************/
213 osm_vendor_init(IN osm_vendor_t * const p_vend,
214 IN osm_log_t * const p_log, IN const uint32_t timeout)
216 ib_api_status_t status = IB_SUCCESS;
218 OSM_LOG_ENTER(p_log);
220 p_vend->p_log = p_log;
221 p_vend->p_transaction_mgr = NULL;
222 osm_transaction_mgr_init(p_vend);
223 p_vend->timeout = timeout;
225 /* we use the file handle to track the binding */
226 p_vend->smi_bind.ul_dev_fd = -1;
227 p_vend->gsi_bind.ul_dev_fd = -1;
233 /**********************************************************************
234 * Create and Initialize osm_vendor_t Object
235 **********************************************************************/
236 osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
237 IN const uint32_t timeout)
239 ib_api_status_t status;
240 osm_vendor_t *p_vend;
242 OSM_LOG_ENTER(p_log);
246 p_vend = malloc(sizeof(*p_vend));
247 if (p_vend != NULL) {
248 memset(p_vend, 0, sizeof(*p_vend));
250 status = osm_vendor_init(p_vend, p_log, timeout);
251 if (status != IB_SUCCESS) {
252 osm_vendor_delete(&p_vend);
255 osm_log(p_vend->p_log, OSM_LOG_ERROR,
256 "osm_vendor_new: ERR 5007: "
257 "Fail to allocate vendor object.\n");
264 /**********************************************************************
265 * TS RCV Thread callback
266 * HACK: - we need to make this support arbitrary size mads.
267 **********************************************************************/
269 __osm_ts_rcv_callback(IN osm_ts_bind_info_t * p_bind,
270 IN osm_mad_addr_t * p_mad_addr,
271 IN uint32_t mad_size, IN void *p_mad)
273 ib_api_status_t status;
274 osm_madw_t *p_req_madw = NULL;
276 osm_vend_wrap_t *p_new_vw;
278 osm_log_t *const p_log = p_bind->p_vend->p_log;
280 OSM_LOG_ENTER(p_log);
282 /* if it is a response MAD we mustbe able to get the request */
283 if (ib_mad_is_response((ib_mad_t *) p_mad)) {
284 /* can we find a matching madw by this payload TID */
286 osm_transaction_mgr_get_madw_for_tid(p_bind->p_vend,
289 if (status != IB_SUCCESS) {
290 osm_log(p_log, OSM_LOG_ERROR,
291 "__osm_ts_rcv_callback: ERR 5008: "
292 "Error obtaining request madw by TID (%d).\n",
297 if (p_req_madw == NULL) {
298 osm_log(p_log, OSM_LOG_ERROR,
299 "__osm_ts_rcv_callback: ERR 5009: "
300 "Fail to obtain request madw for receined MAD. Aborting CB.\n");
305 /* do we have a request ??? */
306 if (p_req_madw == NULL) {
308 /* if not - get new osm_madw and arrange it. */
309 /* create the new madw in the pool */
310 p_madw = osm_mad_pool_get(p_bind->p_osm_pool,
311 (osm_bind_handle_t) p_bind,
312 mad_size, p_mad_addr);
313 if (p_madw == NULL) {
314 osm_log(p_log, OSM_LOG_ERROR,
315 "__osm_ts_rcv_callback: ERR 5010: "
316 "Error request for a new madw.\n");
319 /* HACK: we cust to avoid the const ??? */
320 p_mad_buf = (void *)p_madw->p_mad;
322 /* we have the madw defined during the send and stored in the vend_wrap */
323 /* we need to make sure the wrapper is correctly init there */
324 CL_ASSERT(p_req_madw->vend_wrap.p_resp_madw != 0);
325 p_madw = p_req_madw->vend_wrap.p_resp_madw;
327 CL_ASSERT(p_madw->h_bind);
329 osm_vendor_get(p_madw->h_bind, mad_size,
332 if (p_mad_buf == NULL) {
333 osm_log(p_log, OSM_LOG_ERROR,
334 "__osm_ts_rcv_callback: ERR 5011: "
335 "Unable to acquire wire MAD.\n");
341 Finally, attach the wire MAD to this wrapper.
343 osm_madw_set_mad(p_madw, p_mad_buf);
346 /* init some fields of the vendor wrapper */
347 p_new_vw = osm_madw_get_vend_ptr(p_madw);
348 p_new_vw->h_bind = p_bind;
349 p_new_vw->size = mad_size;
350 p_new_vw->p_resp_madw = NULL;
351 p_new_vw->p_mad_buf = p_mad_buf;
353 memcpy(p_new_vw->p_mad_buf, p_mad, mad_size);
355 /* attach the buffer to the wrapper */
356 p_madw->p_mad = p_mad_buf;
358 /* we can also make sure we marked the size and bind on the returned madw */
359 p_madw->h_bind = p_new_vw->h_bind;
362 (*(osm_vend_mad_recv_callback_t) p_bind->rcv_callback)
363 (p_madw, p_bind->client_context, p_req_madw);
369 /**********************************************************************
370 * TS Send callback : invoked after each send
372 **********************************************************************/
374 __osm_ts_send_callback(IN osm_ts_bind_info_t * bind_info_p,
375 IN boolean_t is_resp,
376 IN osm_madw_t * madw_p, IN IB_comp_status_t status)
378 osm_log_t *const p_log = bind_info_p->p_vend->p_log;
379 osm_vend_wrap_t *p_vw;
381 OSM_LOG_ENTER(p_log);
383 osm_log(p_log, OSM_LOG_DEBUG,
384 "__osm_ts_send_callback: INFO 1008: "
385 "Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp);
387 /* we need to handle requests and responses differently */
389 if (status != IB_COMP_SUCCESS) {
390 osm_log(p_log, OSM_LOG_ERROR,
391 "__osm_ts_send_callback: ERR 5012: "
392 "Error Sending Response MADW:%p.\n", madw_p);
394 osm_log(p_log, OSM_LOG_DEBUG,
395 "__osm_ts_send_callback: DBG 1008: "
396 "Completed Sending Response MADW:%p.\n",
400 /* if we are a response - we need to clean it up */
401 osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p);
404 /* this call back is invoked on completion of send - error or not */
405 if (status != IB_COMP_SUCCESS) {
407 osm_log(p_log, OSM_LOG_ERROR,
408 "__osm_ts_send_callback: ERR 5013: "
409 "Received an Error from IB_MGT Send (%d).\n",
412 p_vw = osm_madw_get_vend_ptr(madw_p);
416 Return any wrappers to the pool that may have been
417 pre-emptively allocated to handle a receive.
419 if (p_vw->p_resp_madw) {
420 osm_mad_pool_put(bind_info_p->p_osm_pool,
422 p_vw->p_resp_madw = NULL;
426 (*(osm_vend_mad_send_err_callback_t) bind_info_p->
428 (bind_info_p->client_context, madw_p);
430 /* successful request send - do nothing - the response will need the
432 osm_log(p_log, OSM_LOG_DEBUG,
433 "__osm_ts_send_callback: DBG 1008: "
434 "Completed Sending Request MADW:%p.\n", madw_p);
441 /**********************************************************************
443 * Always receive 256byte mads from the devcie file
444 **********************************************************************/
445 void __osm_vendor_ts_poller(IN void *p_ptr)
449 osm_mad_addr_t mad_addr;
450 osm_ts_bind_info_t *const p_bind = (osm_ts_bind_info_t *) p_ptr;
452 OSM_LOG_ENTER(p_bind->p_vend->p_log);
453 /* we set the type of cancelation for this thread */
454 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
457 /* we read one mad at a time and pass it to the read callback function */
458 ts_ret_code = read(p_bind->ul_dev_fd, &mad, sizeof(mad));
459 if (ts_ret_code != sizeof(mad)) {
460 osm_log(p_bind->p_vend->p_log, OSM_LOG_ERROR,
461 "__osm_vendor_ts_poller: ERR 5003: "
462 "error with read, bytes = %d, errno = %d\n",
465 osm_log(p_bind->p_vend->p_log, OSM_LOG_DEBUG,
466 "__osm_vendor_ts_poller: "
467 "MAD QPN:%d SLID:0x%04x class:0x%02x "
468 "__osm_vendor_ts_poller:0x%02x attr:0x%04x status:0x%04x "
469 "__osm_vendor_ts_poller:0x%016" PRIx64 "\n",
474 cl_ntoh16(mad.attribute_id),
475 cl_ntoh16(mad.status),
476 cl_ntoh64(mad.transaction_id));
478 /* first arrange an address */
479 __osm_ts_conv_mad_rcv_desc_to_osm_addr(p_bind->p_vend,
492 /* call the receiver callback */
493 /* HACK: this should be replaced with a call to the RMPP Assembly ... */
494 __osm_ts_rcv_callback(p_bind, &mad_addr, 256, &mad);
498 OSM_LOG_EXIT(p_bind->p_vend->p_log);
501 /**********************************************************************
502 * BINDs a callback (rcv and send error) for a given class and method
503 * defined by the given: osm_bind_info_t
504 **********************************************************************/
506 osm_vendor_bind(IN osm_vendor_t * const p_vend,
507 IN osm_bind_info_t * const p_user_bind,
508 IN osm_mad_pool_t * const p_mad_pool,
509 IN osm_vend_mad_recv_callback_t mad_recv_callback,
510 IN osm_vend_mad_send_err_callback_t send_err_callback,
513 ib_net64_t port_guid;
514 osm_ts_bind_info_t *p_bind = NULL;
515 VAPI_hca_hndl_t hca_hndl;
516 VAPI_hca_id_t hca_id;
518 ib_api_status_t status;
520 char device_file[16];
521 osm_ts_user_mad_filter filter;
525 OSM_LOG_ENTER(p_vend->p_log);
527 CL_ASSERT(p_mad_pool);
529 port_guid = p_user_bind->port_guid;
531 osm_log(p_vend->p_log, OSM_LOG_INFO,
533 "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid));
535 switch (p_user_bind->mad_class) {
536 case IB_MCLASS_SUBN_LID:
537 case IB_MCLASS_SUBN_DIR:
538 p_bind = &(p_vend->smi_bind);
542 case IB_MCLASS_SUBN_ADM:
544 p_bind = &(p_vend->gsi_bind);
549 /* Make sure we did not previously opened the file */
550 if (p_bind->ul_dev_fd >= 0) {
551 osm_log(p_vend->p_log, OSM_LOG_ERROR,
552 "osm_vendor_bind: ERR 5004: "
553 "Already binded to port %u\n", p_bind->port_num);
558 We need to figure out what is the TS file name to attach to.
559 I guess it is following the index of the port in the table of
563 /* obtain the hca name and port num from the guid */
564 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
566 "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n",
567 cl_ntoh64(port_guid));
569 osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl,
571 if (status != IB_SUCCESS) {
572 osm_log(p_vend->p_log, OSM_LOG_ERROR,
573 "osm_vendor_bind: ERR 5005: "
574 "Fail to find port number of port guid:0x%016" PRIx64
579 /* the file name is just /dev/ts_ua0: */
580 strcpy(device_file, "/dev/ts_ua0");
582 osm_log(p_vend->p_log, OSM_LOG_ERROR,
583 "osm_vendor_bind: " "Opening TS UL dev file:%s\n", device_file);
585 /* Open the file ... */
586 device_fd = open(device_file, O_RDWR);
588 osm_log(p_vend->p_log, OSM_LOG_ERROR,
589 "osm_vendor_bind: ERR 5006: "
590 "Fail to open TS UL dev file:%s\n", device_file);
594 /* track this bind request info */
595 p_bind->ul_dev_fd = device_fd;
596 p_bind->port_num = port_num;
597 p_bind->p_vend = p_vend;
598 p_bind->client_context = context;
599 p_bind->rcv_callback = mad_recv_callback;
600 p_bind->send_err_callback = send_err_callback;
601 p_bind->p_osm_pool = p_mad_pool;
602 p_bind->hca_hndl = hca_hndl;
605 * Create the MAD filter on this file handle.
607 filter.port = port_num;
610 filter.mgmt_class = p_user_bind->mad_class;
611 filter.direction = TS_IB_MAD_DIRECTION_IN;
613 TS_IB_MAD_FILTER_DIRECTION |
614 TS_IB_MAD_FILTER_PORT |
615 TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS;
617 ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter);
618 if (ts_ioctl_ret < 0) {
619 osm_log(p_vend->p_log, OSM_LOG_ERROR,
620 "osm_vendor_bind: ERR 5014: "
621 "Fail to register MAD filter with err:%u\n",
626 /* Initialize the listener thread for this port */
627 status = cl_thread_init(&p_bind->poller,
628 __osm_vendor_ts_poller, p_bind,
630 if (status != IB_SUCCESS)
634 OSM_LOG_EXIT(p_vend->p_log);
635 return ((osm_bind_handle_t) p_bind);
638 /**********************************************************************
639 Get a mad from the lower level.
640 The osm_vend_wrap_t is a wrapper used to connect the mad to the response.
641 **********************************************************************/
642 ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
643 IN const uint32_t mad_size,
644 IN osm_vend_wrap_t * const p_vw)
647 osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
648 osm_vendor_t *p_vend = p_bind->p_vend;
650 OSM_LOG_ENTER(p_vend->p_log);
654 p_vw->size = mad_size;
657 p_mad = (ib_mad_t *) malloc(p_vw->size);
659 osm_log(p_vend->p_log, OSM_LOG_ERROR,
660 "osm_vendor_get: ERR 5022: "
661 "Error Obtaining MAD buffer.\n");
665 memset(p_mad, 0, p_vw->size);
668 p_vw->p_mad_buf = p_mad;
669 p_vw->h_bind = h_bind;
670 p_vw->p_resp_madw = NULL;
672 if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
673 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
675 "Acquired MAD %p, size = %u.\n", p_mad, p_vw->size);
679 OSM_LOG_EXIT(p_vend->p_log);
683 /**********************************************************************
684 * Return a MAD by providing it's wrapper object.
685 **********************************************************************/
687 osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
689 osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
690 osm_vendor_t *p_vend = p_bind->p_vend;
693 OSM_LOG_ENTER(p_vend->p_log);
696 CL_ASSERT(p_vw->p_mad_buf);
698 if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
699 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
700 "osm_vendor_put: " "Retiring MAD %p.\n",
705 * We moved the removal of the transaction to immediatly after
709 /* free the mad but the wrapper is part of the madw object */
710 free(p_vw->p_mad_buf);
711 p_vw->p_mad_buf = NULL;
712 p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
713 p_madw->p_mad = NULL;
715 OSM_LOG_EXIT(p_vend->p_log);
718 /**********************************************************************
721 MADs are buffers of type: struct ib_mad - so they are limited by size.
722 This is for internal use by osm_vendor_send and the transaction mgr
724 **********************************************************************/
726 osm_ts_send_mad(IN osm_ts_bind_info_t * p_bind, IN osm_madw_t * const p_madw)
728 osm_vendor_t *const p_vend = p_bind->p_vend;
729 osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
730 ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
731 struct ib_mad ts_mad;
733 ib_api_status_t status;
735 OSM_LOG_ENTER(p_vend->p_log);
738 * Copy the MAD over to the sent mad
740 memcpy(&ts_mad, p_mad, 256);
743 * For all sends other than directed route SM MADs,
744 * acquire an address vector for the destination.
746 if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
747 __osm_ts_conv_osm_addr_to_ts_addr(p_mad_addr,
749 IB_MCLASS_SUBN_LID, &ts_mad);
751 /* is a directed route - we need to construct a permissive address */
752 /* we do not need port number since it is part of the mad_hndl */
753 ts_mad.dlid = IB_LID_PERMISSIVE;
754 ts_mad.slid = IB_LID_PERMISSIVE;
756 if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) ||
757 (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) {
764 ts_mad.port = p_bind->port_num;
767 ret = write(p_bind->ul_dev_fd, &ts_mad, sizeof(ts_mad));
769 if (ret != sizeof(ts_mad)) {
770 osm_log(p_vend->p_log, OSM_LOG_ERROR,
771 "osm_ts_send_mad: ERR 5026: "
772 "Error sending mad (%d).\n", ret);
780 OSM_LOG_EXIT(p_vend->p_log);
784 /**********************************************************************
787 What is unclear to me is the need for the setting of all the MAD Wrapper
788 fields. Seems like the OSM uses these values during it's processing...
789 **********************************************************************/
791 osm_vendor_send(IN osm_bind_handle_t h_bind,
792 IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
794 osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
795 osm_vendor_t *const p_vend = p_bind->p_vend;
796 osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
797 ib_api_status_t status;
799 OSM_LOG_ENTER(p_vend->p_log);
802 * If a response is expected to this MAD, then preallocate
803 * a mad wrapper to contain the wire MAD received in the
804 * response. Allocating a wrapper here allows for easier
805 * failure paths than after we already received the wire mad.
807 if (resp_expected == TRUE) {
808 /* we track it in the vendor wrapper */
810 osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool);
811 if (p_vw->p_resp_madw == NULL) {
812 osm_log(p_vend->p_log, OSM_LOG_ERROR,
813 "osm_vendor_send: ERR 5024: "
814 "Unable to allocate MAD wrapper.\n");
815 status = IB_INSUFFICIENT_RESOURCES;
819 /* put some minimal info on that wrapper */
820 ((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind;
822 /* we also want to track it in the TID based map */
823 status = osm_transaction_mgr_insert_madw((osm_bind_handle_t *)
825 if (status != IB_SUCCESS) {
826 osm_log(p_vend->p_log, OSM_LOG_ERROR,
827 "osm_vendor_send: ERR 5025: "
828 "Error inserting request madw by TID (%d).\n",
832 p_vw->p_resp_madw = NULL;
834 /* do the actual send */
835 /* HACK: to be replaced by call to RMPP Segmentation */
836 status = osm_ts_send_mad(p_bind, p_madw);
838 /* we do not get an asycn callback so call it ourselves */
839 /* this will handle all cleanup if neccessary */
840 __osm_ts_send_callback(p_bind, !resp_expected, p_madw, status);
843 OSM_LOG_EXIT(p_vend->p_log);
847 /**********************************************************************
848 * the idea here is to change the content of the bind such that it
849 * will hold the local address used for sending directed route by the SMA.
850 **********************************************************************/
851 ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
853 osm_vendor_t *p_vend = ((osm_ts_bind_info_t *) h_bind)->p_vend;
855 OSM_LOG_ENTER(p_vend->p_log);
857 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
858 "osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n");
860 OSM_LOG_EXIT(p_vend->p_log);
865 void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
867 osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind;
868 osm_vendor_t *p_vend = p_bind->p_vend;
870 VAPI_hca_attr_t attr_mod;
871 VAPI_hca_attr_mask_t attr_mask;
873 OSM_LOG_ENTER(p_vend->p_log);
875 memset(&attr_mod, 0, sizeof(attr_mod));
876 memset(&attr_mask, 0, sizeof(attr_mask));
878 attr_mod.is_sm = is_sm_val;
879 attr_mask = HCA_ATTR_IS_SM;
882 VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod,
884 if (status != VAPI_OK) {
885 osm_log(p_vend->p_log, OSM_LOG_ERROR,
886 "osm_vendor_set_sm: ERR 5027: "
887 "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n",
891 OSM_LOG_EXIT(p_vend->p_log);
894 void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)