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/*
37 * Abstract:
38 *    Implementation of osm_req_t.
39 * This object represents the generic attribute requester.
40 * This object is part of the opensm family of objects.
41 *
42 */
43
44/*
45  Next available error code: 0x300
46*/
47
48#if HAVE_CONFIG_H
49#  include <config.h>
50#endif				/* HAVE_CONFIG_H */
51
52#ifdef OSM_VENDOR_INTF_UMADT
53
54#include <stdlib.h>
55#include <stdio.h>
56#include <dlfcn.h>
57#include <string.h>
58
59#include <complib/cl_qlist.h>
60#include <complib/cl_thread.h>
61#include <complib/cl_timer.h>
62#include <iba/ib_types.h>
63#include <opensm/osm_madw.h>
64#include <opensm/osm_log.h>
65#include <opensm/osm_mad_pool.h>
66
67#include <vendor/osm_vendor_umadt.h>
68#include <vendor/osm_umadt.h>
69
70/*  GEN1 includes */
71#include "umadt_so.h"
72#include "ibt.h"
73#include "statustext.h"
74
75/* //////////////////////////////////////////////////////////////////////// */
76/* //////////////////////////////////////////////////////////////////////// */
77/* //////////////////////////////////////////////////////////////////////// */
78/* //////////////////////////////////////////////////////////////////////// */
79/* //////////////////////////////////////////////////////////////////////// */
80/*  */
81/*      VENDOR_MAD_INTF */
82/*  */
83/* //////////////////////////////////////////////////////////////////////// */
84/* //////////////////////////////////////////////////////////////////////// */
85/* //////////////////////////////////////////////////////////////////////// */
86/* //////////////////////////////////////////////////////////////////////// */
87/* //////////////////////////////////////////////////////////////////////// */
88
89/* //////////////////// */
90/*  Globals        // */
91/* //////////////////// */
92typedef struct _ib_sa_mad_vM3 {
93	uint8_t base_ver;
94	uint8_t mgmt_class;
95	uint8_t class_ver;
96	uint8_t method;
97	ib_net16_t status;
98	ib_net16_t resv;
99	ib_net64_t trans_id;
100	ib_net16_t attr_id;
101	ib_net16_t resv1;
102	ib_net32_t attr_mod;
103	ib_net64_t resv2;
104	ib_net64_t sm_key;
105
106	ib_net32_t seg_num;
107	ib_net32_t payload_len;
108	uint8_t frag_flag;
109	uint8_t edit_mod;
110	ib_net16_t window;
111	ib_net16_t attr_offset;
112	ib_net16_t resv3;
113
114	ib_net64_t comp_mask;
115
116	uint8_t data[IB_SA_DATA_SIZE];
117} ib_sa_mad_t_vM3;
118#define  DEFAULT_TIMER_INTERVAL_MSEC   500	/*  500msec timer interval */
119
120void __mad_recv_processor(void *context);
121
122boolean_t __valid_mad_handle(IN mad_bind_info_t * p_mad_bind_info);
123
124cl_status_t
125__match_tid_context(const cl_list_item_t * const p_list_item, void *context);
126void __osm_vendor_timer_callback(IN void *context);
127
128osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
129			     IN const uint32_t timeout)
130{
131	ib_api_status_t status;
132	umadt_obj_t *p_umadt_obj;
133
134	OSM_LOG_ENTER(p_log);
135
136	p_umadt_obj = malloc(sizeof(umadt_obj_t));
137	if (p_umadt_obj) {
138		memset(p_umadt_obj, 0, sizeof(umadt_obj_t));
139
140		status = osm_vendor_init((osm_vendor_t *) p_umadt_obj, p_log,
141					 timeout);
142		if (status != IB_SUCCESS) {
143			osm_vendor_delete((osm_vendor_t **) & p_umadt_obj);
144		}
145	} else {
146		printf
147		    ("osm_vendor_construct: ERROR! Unable to create Umadt object!\n");
148	}
149
150	OSM_LOG_EXIT(p_log);
151
152	return ((osm_vendor_t *) p_umadt_obj);
153}
154
155void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
156{
157	umadt_obj_t *p_umadt_obj = (umadt_obj_t *) * pp_vend;
158	cl_list_item_t *p_list_item;
159	uint32_t count, i;
160	mad_bind_info_t *p_mad_bind_info;
161
162	OSM_LOG_ENTER(p_umadt_obj->p_log);
163
164	cl_spinlock_acquire(&p_umadt_obj->register_lock);
165	p_mad_bind_info =
166	    (mad_bind_info_t *) cl_qlist_head(&p_umadt_obj->register_list);
167	count = cl_qlist_count(&p_umadt_obj->register_list);
168	cl_spinlock_release(&p_umadt_obj->register_lock);
169	for (i = 0; i < count; i++) {
170		cl_spinlock_acquire(&p_umadt_obj->register_lock);
171		p_list_item = cl_qlist_next(&p_mad_bind_info->list_item);
172		cl_spinlock_release(&p_umadt_obj->register_lock);
173		/*  Unbind this handle */
174		/*  osm_vendor_ubind also removesd the item from the list */
175		/*  osm_vendor_unbind takes the list lock so release it here */
176		osm_vendor_unbind((osm_bind_handle_t) p_mad_bind_info);
177		p_mad_bind_info = (mad_bind_info_t *) p_list_item;
178	}
179	dlclose(p_umadt_obj->umadt_handle);
180	free(p_umadt_obj);
181	*pp_vend = NULL;
182
183	OSM_LOG_EXIT(p_umadt_obj->p_log);
184}
185
186/* //////////////////////////////////////////////////////////////////////// */
187/*  See VendorAbstractMadIntf.h for info */
188/* //////////////////////////////////////////////////////////////////////// */
189/*  */
190ib_api_status_t
191osm_vendor_init(IN osm_vendor_t * const p_vend,
192		IN osm_log_t * const p_log, IN const uint32_t timeout)
193{
194	FSTATUS Status;
195	PUMADT_GET_INTERFACE uMadtGetInterface;
196	char *error;
197	umadt_obj_t *p_umadt_obj = (umadt_obj_t *) p_vend;
198
199	OSM_LOG_ENTER(p_log);
200
201	p_umadt_obj->p_log = p_log;
202	p_umadt_obj->timeout = timeout;
203
204	p_umadt_obj->umadt_handle = dlopen("libibt.so", RTLD_NOW);
205
206	if (!p_umadt_obj->umadt_handle) {
207		printf("Could not load libibt.so <%s>\n", dlerror());
208		return IB_ERROR;
209	}
210	uMadtGetInterface =
211	    dlsym(p_umadt_obj->umadt_handle, "uMadtGetInterface");
212	if ((error = dlerror()) != NULL) {
213		printf("Could not resolve symbol uMadtGetInterface ERROR<%s>\n",
214		       error);
215		return IB_ERROR;
216	}
217
218	Status = (*uMadtGetInterface) (&p_umadt_obj->uMadtInterface);
219	if (Status != FSUCCESS) {
220		printf(" Error in getting uMADT interface ERROR<%d>\n", Status);
221		return IB_ERROR;
222	}
223
224	/*  Initialize the register list and register list lock */
225	cl_qlist_init(&p_umadt_obj->register_list);
226
227	cl_spinlock_construct(&p_umadt_obj->register_lock);
228	CL_ASSERT(cl_spinlock_init(&p_umadt_obj->register_lock) == CL_SUCCESS);
229	p_umadt_obj->init_done = TRUE;
230	printf("*****SUCCESS*****\n");
231
232	OSM_LOG_EXIT(p_log);
233	return IB_SUCCESS;
234
235}
236
237/* //////////////////////////////////////////////////////////////////////// */
238/*  See VendorAbstractMadIntf.h for info */
239/* //////////////////////////////////////////////////////////////////////// */
240ib_api_status_t
241osm_vendor_get_ports(IN osm_vendor_t * const p_vend,
242		     IN ib_net64_t * const p_guids,
243		     IN uint32_t * const p_num_guids)
244{
245	char *error = NULL;
246	PIBT_GET_INTERFACE pfnIbtGetInterface;
247	PIBT_INIT pfnIbtInitFunc;
248
249	FSTATUS Status;
250	uint32_t caCount, caGuidCount;
251	IB_CA_ATTRIBUTES caAttributes;
252	IB_HANDLE caHandle;
253	uint32_t i;
254	IB_PORT_ATTRIBUTES *pPortAttributesList;
255	EUI64 CaGuidArray[8];
256	void *context;
257	uint64_t *p_port_guid;
258	uint32_t free_guids;
259
260	umadt_obj_t *p_umadt_obj = (umadt_obj_t *) p_vend;
261
262	OSM_LOG_ENTER(p_umadt_obj->p_log);
263
264	CL_ASSERT(p_guids);
265	CL_ASSERT(p_num_guids);
266
267	pfnIbtInitFunc =
268	    (PIBT_INIT) dlsym(p_umadt_obj->umadt_handle, "IbtInit");
269
270	if (!pfnIbtInitFunc) {
271		printf("Error getting IbtInit function address.\n");
272		return IB_ERROR;
273	}
274
275	(*pfnIbtInitFunc) ();
276
277	pfnIbtGetInterface =
278	    (PIBT_GET_INTERFACE) dlsym(p_umadt_obj->umadt_handle,
279				       "IbtGetInterface");
280
281	if (!pfnIbtGetInterface || (error = dlerror()) != NULL) {
282		printf("Error getting IbtGetInterface function address.<%s>\n",
283		       error);
284		return FALSE;
285	}
286	(*pfnIbtGetInterface) (&p_umadt_obj->IbtInterface);
287
288	caGuidCount = 8;
289	Status =
290	    p_umadt_obj->IbtInterface.GetCaGuidArray(&caGuidCount,
291						     &CaGuidArray[0]);
292
293	if ((Status != FSUCCESS) || (caGuidCount == 0)) {
294		return FALSE;
295	}
296
297	free_guids = *p_num_guids;
298	p_port_guid = p_guids;
299
300	/* query each ca & copy its info into callers buffer */
301	for (caCount = 0; caCount < caGuidCount; caCount++) {
302		memset(&caAttributes, 0, sizeof(IB_CA_ATTRIBUTES));
303
304		/* Open the CA */
305		Status = p_umadt_obj->IbtInterface.Vpi.OpenCA(CaGuidArray[caCount], NULL,	/*  CACompletionCallback */
306							      NULL,	/*  AsyncEventCallback */
307							      NULL, &caHandle);
308		if (Status != FSUCCESS) {
309			return IB_ERROR;
310		}
311
312		Status = p_umadt_obj->IbtInterface.Vpi.QueryCA(caHandle,
313							       &caAttributes,
314							       &context);
315
316		if (Status != FSUCCESS) {
317			p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle);
318			return IB_ERROR;
319		}
320
321		if (caAttributes.Ports > free_guids) {
322			*p_num_guids = 0;
323			memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t));
324			return IB_INSUFFICIENT_MEMORY;
325		}
326
327		pPortAttributesList =
328		    (IB_PORT_ATTRIBUTES *) malloc(caAttributes.
329						  PortAttributesListSize);
330
331		if (pPortAttributesList == NULL) {
332			p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle);
333			*p_num_guids = 0;
334			memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t));
335			return IB_INSUFFICIENT_MEMORY;
336		}
337
338		memset(pPortAttributesList, 0,
339		       caAttributes.PortAttributesListSize);
340
341		caAttributes.PortAttributesList = pPortAttributesList;
342
343		Status = p_umadt_obj->IbtInterface.Vpi.QueryCA(caHandle,
344							       &caAttributes,
345							       &context);
346
347		if (Status != FSUCCESS) {
348			p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle);
349			*p_num_guids = 0;
350			memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t));
351			return IB_ERROR;
352		}
353
354		pPortAttributesList = caAttributes.PortAttributesList;
355
356		for (i = 0; i < caAttributes.Ports; i++) {
357			*(p_port_guid) =
358			    cl_hton64((uint64_t) pPortAttributesList->GUID);
359			pPortAttributesList = pPortAttributesList->Next;
360			p_port_guid++;
361		}
362		free(caAttributes.PortAttributesList);
363		p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle);
364
365		free_guids = free_guids - caAttributes.Ports;
366
367	}
368	*p_num_guids = *p_num_guids - free_guids;
369	return IB_SUCCESS;
370}
371
372/* //////////////////////////////////////////////////////////////////////// */
373/*  See VendorAbstractMadIntf.h for info */
374/* //////////////////////////////////////////////////////////////////////// */
375ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
376			 IN const uint32_t mad_size,
377			 IN osm_vend_wrap_t * p_vend_wrap)
378{
379	/* FSTATUS Status; */
380	/* uint32_t mad_count = 0; */
381	/* MadtStruct *p_madt_struct; */
382	mad_bind_info_t *p_mad_bind_info = (mad_bind_info_t *) h_bind;
383	umadt_obj_t *p_umadt_obj = p_mad_bind_info->p_umadt_obj;
384	ib_mad_t *p_mad;
385	OSM_LOG_ENTER(p_umadt_obj->p_log);
386
387	CL_ASSERT(h_bind);
388
389	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
390
391	/*  Sanity check */
392	CL_ASSERT(p_umadt_obj->init_done);
393	CL_ASSERT(p_vend_wrap);
394	CL_ASSERT(__valid_mad_handle(p_mad_bind_info));
395
396#if 0
397	mad_count = 1;
398	Status =
399	    p_umadt_obj->uMadtInterface.uMadtGetSendMad(p_mad_bind_info->
400							umadt_handle,
401							&mad_count,
402							&p_madt_struct);
403
404	if (Status != FSUCCESS || p_madt_struct == NULL) {
405		p_vend_wrap->p_madt_struct = NULL;
406		return NULL;
407	}
408	p_vend_wrap->p_madt_struct = p_madt_struct;
409	p_vend_wrap->direction = SEND;
410	return ((ib_mad_t *) & p_madt_struct->IBMad);
411#endif				/*  0 */
412	p_mad = (ib_mad_t *) malloc(mad_size);
413	if (!p_mad) {
414		p_vend_wrap->p_madt_struct = NULL;
415		return NULL;
416	}
417
418	memset(p_mad, 0, mad_size);
419
420	p_vend_wrap->p_madt_struct = NULL;
421	p_vend_wrap->direction = SEND;
422	p_vend_wrap->size = mad_size;
423	return (p_mad);
424
425}
426
427/* //////////////////////////////////////////////////////////////////////// */
428/*  See VendorAbstractMadIntf.h for info */
429/* //////////////////////////////////////////////////////////////////////// */
430void
431osm_vendor_put(IN osm_bind_handle_t h_bind,
432	       IN osm_vend_wrap_t * const p_vend_wrap,
433	       IN ib_mad_t * const p_mad)
434{
435
436	FSTATUS Status;
437
438	mad_bind_info_t *p_mad_bind_info;
439	umadt_obj_t *p_umadt_obj;
440
441	/*  */
442	/*  Validate the vendor mad transport handle */
443	/*  */
444	CL_ASSERT(h_bind);
445	p_mad_bind_info = (mad_bind_info_t *) h_bind;
446	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
447
448	/*  sanity check */
449	CL_ASSERT(p_umadt_obj->init_done);
450	CL_ASSERT(h_bind);
451	CL_ASSERT(__valid_mad_handle(p_mad_bind_info));
452	CL_ASSERT(p_vend_wrap);
453	/* CL_ASSERT( (ib_mad_t*)&p_vend_wrap->p_madt_struct->IBMad == p_mad ); */
454
455	/*  Release the MAD based on the direction of the MAD */
456	if (p_vend_wrap->direction == SEND) {
457		/*  */
458		/* For a send the PostSend released the MAD with Umadt. Simply dealloacte the */
459		/* local memory that was allocated on the osm_vendor_get() call. */
460		/*  */
461		free(p_mad);
462#if 0
463		Status =
464		    p_umadt_obj->uMadtInterface.
465		    uMadtReleaseSendMad(p_mad_bind_info->umadt_handle,
466					p_vend_wrap->p_madt_struct);
467		if (Status != FSUCCESS) {
468			/* printf("uMadtReleaseSendMad: Status  = <%d>\n", Status); */
469			return;
470		}
471#endif
472	} else if (p_vend_wrap->direction == RECEIVE) {
473		CL_ASSERT((ib_mad_t *) & p_vend_wrap->p_madt_struct->IBMad ==
474			  p_mad);
475		Status =
476		    p_umadt_obj->uMadtInterface.
477		    uMadtReleaseRecvMad(p_mad_bind_info->umadt_handle,
478					p_vend_wrap->p_madt_struct);
479		if (Status != FSUCCESS) {
480			/* printf("uMadtReleaseRecvMad Status=<%d>\n", Status); */
481			return;
482		}
483	} else {
484		return;
485	}
486	return;
487}
488
489/* //////////////////////////////////////////////////////////////////////// */
490/*  See VendorAbstractMadIntf.h for info */
491/* //////////////////////////////////////////////////////////////////////// */
492ib_api_status_t
493osm_vendor_send(IN osm_bind_handle_t h_bind,
494		IN osm_vend_wrap_t * const p_vend_wrap,
495		IN osm_mad_addr_t * const p_mad_addr,
496		IN ib_mad_t * const p_mad,
497		IN void *transaction_context, IN boolean_t const resp_expected)
498{
499	FSTATUS Status;
500
501	MadAddrStruct destAddr = { 0 };
502
503	mad_bind_info_t *p_mad_bind_info;
504	trans_context_t *p_trans_context;
505
506	umadt_obj_t *p_umadt_obj = NULL;
507
508	uint32_t mad_count = 0;
509	MadtStruct *p_madt_struct = NULL;
510	uint32_t i;
511	uint32_t num_mads = 0;
512	uint32_t seg_num = 0;
513	uint8_t *p_frag_data = NULL;
514	ib_sa_mad_t_vM3 *p_sa_mad = NULL;
515
516	CL_ASSERT(h_bind);
517	p_mad_bind_info = (mad_bind_info_t *) h_bind;
518	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
519
520	/*  sanity check */
521	CL_ASSERT(p_umadt_obj);
522	CL_ASSERT(p_umadt_obj->init_done);
523	CL_ASSERT(__valid_mad_handle(p_mad_bind_info));
524	CL_ASSERT(p_vend_wrap);
525	CL_ASSERT(p_mad_addr);
526	CL_ASSERT(p_mad);
527	/* CL_ASSERT( (ib_mad_t*)&p_vend_wrap->p_madt_struct->IBMad == p_mad ); */
528
529	/*  */
530	/*  based on the class, fill out the address info */
531	/*  */
532	destAddr.DestLid = p_mad_addr->dest_lid;
533	destAddr.PathBits = p_mad_addr->path_bits;
534	destAddr.StaticRate = p_mad_addr->static_rate;
535
536	if (p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_LID ||
537	    p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_DIR) {
538		CL_ASSERT(p_mad_addr->addr_type.smi.source_lid);
539		destAddr.AddrType.Smi.SourceLid =
540		    p_mad_addr->addr_type.smi.source_lid;
541	} else {
542		destAddr.AddrType.Gsi.RemoteQpNumber =
543		    p_mad_addr->addr_type.gsi.remote_qp;
544		destAddr.AddrType.Gsi.RemoteQkey =
545		    p_mad_addr->addr_type.gsi.remote_qkey;
546		destAddr.AddrType.Gsi.PKey = OSM_DEFAULT_PKEY;
547		destAddr.AddrType.Gsi.ServiceLevel =
548		    p_mad_addr->addr_type.gsi.service_level;
549		destAddr.AddrType.Gsi.GlobalRoute =
550		    p_mad_addr->addr_type.gsi.global_route;
551		/* destAddr.AddrType.Gsi.GRHInfo = p_mad_addr->addr_type.gsi.grh_info; */
552	}
553	p_mad->trans_id = cl_ntoh64(p_mad->trans_id) << 24;
554
555	/*  */
556	/*  Create a transaction context for this send and save the TID and client context. */
557	/*  */
558
559	if (resp_expected) {
560		p_trans_context = malloc(sizeof(trans_context_t));
561		CL_ASSERT(p_trans_context);
562
563		memset(p_trans_context, 0, sizeof(trans_context_t));
564		p_trans_context->trans_id = p_mad->trans_id;
565		p_trans_context->context = transaction_context;
566		p_trans_context->sent_time = cl_get_time_stamp();
567
568		cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
569		cl_qlist_insert_tail(&p_mad_bind_info->trans_ctxt_list,
570				     &p_trans_context->list_item);
571		cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
572	}
573
574	if (p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_LID ||
575	    p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_DIR) {
576		/*  Get one mad from uMadt */
577		mad_count = 1;
578		Status =
579		    p_umadt_obj->uMadtInterface.
580		    uMadtGetSendMad(p_mad_bind_info->umadt_handle, &mad_count,
581				    &p_madt_struct);
582
583		if (Status != FSUCCESS || p_madt_struct == NULL) {
584			return IB_ERROR;
585		}
586
587		/*  No Segmentation required */
588		memcpy(&p_madt_struct->IBMad, p_mad, MAD_BLOCK_SIZE);
589
590		/*  Post the MAD */
591
592		Status =
593		    p_umadt_obj->uMadtInterface.uMadtPostSend(p_mad_bind_info->
594							      umadt_handle,
595							      p_madt_struct,
596							      &destAddr);
597		if (Status != FSUCCESS) {
598			printf("uMadtPostSendMad: Status  = <%d>\n", Status);
599			return IB_ERROR;
600		}
601
602		/*  Release send MAD */
603		Status =
604		    p_umadt_obj->uMadtInterface.
605		    uMadtReleaseSendMad(p_mad_bind_info->umadt_handle,
606					p_madt_struct);
607		if (Status != FSUCCESS) {
608			printf("uMadtReleaseSendMad: Status  = <%d>\n", Status);
609			return IB_ERROR;
610		}
611	} else {
612
613		/*  */
614		/*  Segment the MAD, get the required send mads from uMadt and post the MADs. */
615		/*  */
616		uint32_t payload_len;
617
618		payload_len =
619		    cl_ntoh32(((ib_sa_mad_t_vM3 *) p_mad)->payload_len);
620		num_mads = payload_len / IB_SA_DATA_SIZE;
621		if (payload_len % IB_SA_DATA_SIZE != 0) {
622			num_mads++;	/*  Get one additional mad for the remainder */
623		}
624		for (i = 0; i < num_mads; i++) {
625			/*  Get one mad from uMadt */
626			mad_count = 1;
627			Status =
628			    p_umadt_obj->uMadtInterface.
629			    uMadtGetSendMad(p_mad_bind_info->umadt_handle,
630					    &mad_count, &p_madt_struct);
631
632			if (Status != FSUCCESS || p_madt_struct == NULL) {
633				return IB_ERROR;
634			}
635			/*  Copy client MAD into uMadt's MAD. */
636			if (i == 0) {	/*  First Packet */
637				/*  Since this is the first MAD, copy the entire MAD_SIZE */
638				memcpy(&p_madt_struct->IBMad, p_mad,
639				       MAD_BLOCK_SIZE);
640
641				p_frag_data =
642				    (uint8_t *) p_mad + MAD_BLOCK_SIZE;
643
644				p_sa_mad =
645				    (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad;
646				if (num_mads == 1) {	/*  Only one Packet */
647					p_sa_mad->seg_num = 0;
648					p_sa_mad->frag_flag = 5;	/*  Set bit 0 for first pkt and b4 for last pkt */
649					/*  the payload length gets copied with the mad header above */
650				} else {	/*  More than one packet in this response */
651
652					seg_num = 1;
653					p_sa_mad->seg_num =
654					    cl_ntoh32(seg_num++);
655					p_sa_mad->frag_flag = 1;	/*  Set bit 0 for first pkt */
656					/*  the payload length gets copied with the mad header above */
657				}
658
659			} else if (i < num_mads - 1) {	/*  Not last packet */
660				/*  First copy only the header */
661				memcpy(&p_madt_struct->IBMad, p_mad,
662				       IB_SA_MAD_HDR_SIZE);
663				/*  Set the relevant fields in the SA_MAD_HEADER */
664				p_sa_mad =
665				    (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad;
666				p_sa_mad->payload_len =
667				    cl_ntoh32(IB_SA_DATA_SIZE);
668				p_sa_mad->seg_num = cl_ntoh32(seg_num++);
669				p_sa_mad->frag_flag = 0;
670				/*  Now copy the fragmented data */
671				memcpy(((uint8_t *) & p_madt_struct->IBMad) +
672				       IB_SA_MAD_HDR_SIZE, p_frag_data,
673				       IB_SA_DATA_SIZE);
674				p_frag_data = p_frag_data + IB_SA_DATA_SIZE;
675
676			} else if (i == num_mads - 1) {	/*  Last packet */
677				/*  First copy only the header */
678				memcpy(&p_madt_struct->IBMad, p_mad,
679				       IB_SA_MAD_HDR_SIZE);
680				/*  Set the relevant fields in the SA_MAD_HEADER */
681				p_sa_mad =
682				    (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad;
683				p_sa_mad->seg_num = cl_ntoh32(seg_num++);
684				p_sa_mad->frag_flag = 4;	/*  Set Bit 2 for last pkt */
685				p_sa_mad->payload_len =
686				    cl_ntoh32(cl_ntoh32
687					      (((ib_sa_mad_t_vM3 *) p_mad)->
688					       payload_len) % IB_SA_DATA_SIZE);
689				/*  Now copy the fragmented data */
690				memcpy((((uint8_t *) & p_madt_struct->IBMad)) +
691				       IB_SA_MAD_HDR_SIZE, p_frag_data,
692				       cl_ntoh32(p_sa_mad->payload_len));
693				p_frag_data = p_frag_data + IB_SA_DATA_SIZE;
694
695			}
696			/*  Post the MAD */
697			Status =
698			    p_umadt_obj->uMadtInterface.
699			    uMadtPostSend(p_mad_bind_info->umadt_handle,
700					  p_madt_struct, &destAddr);
701			if (Status != FSUCCESS) {
702				printf("uMadtPostSendMad: Status  = <%d>\n",
703				       Status);
704				return IB_ERROR;
705			}
706
707			/*  Release send MAD */
708			Status =
709			    p_umadt_obj->uMadtInterface.
710			    uMadtReleaseSendMad(p_mad_bind_info->umadt_handle,
711						p_madt_struct);
712			if (Status != FSUCCESS) {
713				printf("uMadtReleaseSendMad: Status  = <%d>\n",
714				       Status);
715				return IB_ERROR;
716			}
717		}
718	}
719	return (IB_SUCCESS);
720}
721
722/* //////////////////////////////////////////////////////////////////////// */
723/*  See VendorAbstractMadIntf.h for info */
724/* //////////////////////////////////////////////////////////////////////// */
725
726osm_bind_handle_t
727osm_vendor_bind(IN osm_vendor_t * const p_vend,
728		IN osm_bind_info_t * const p_osm_bind_info,
729		IN osm_mad_pool_t * const p_mad_pool,
730		IN osm_vend_mad_recv_callback_t mad_recv_callback,
731		IN void *context)
732{
733	cl_status_t cl_status;
734	FSTATUS Status;		/*  GEN1 Status for Umadt */
735
736	mad_bind_info_t *p_mad_bind_info;
737	RegisterClassStruct *p_umadt_reg_class;
738
739	umadt_obj_t *p_umadt_obj;
740	OSM_LOG_ENTER(((umadt_obj_t *) p_vend)->p_log);
741
742	CL_ASSERT(p_vend);
743
744	p_umadt_obj = (umadt_obj_t *) p_vend;
745
746	/*  Sanity check */
747	CL_ASSERT(p_umadt_obj->init_done);
748	CL_ASSERT(p_osm_bind_info);
749	CL_ASSERT(p_mad_pool);
750	CL_ASSERT(mad_recv_callback);
751
752	/*  Allocate memory for registering the handle. */
753	p_mad_bind_info = (mad_bind_info_t *) malloc(sizeof(*p_mad_bind_info));
754	if (p_mad_bind_info) {
755		memset(p_mad_bind_info, 0, sizeof(*p_mad_bind_info));
756		p_umadt_reg_class = &p_mad_bind_info->umadt_reg_class;
757	}
758	p_umadt_reg_class->PortGuid = cl_ntoh64(p_osm_bind_info->port_guid);
759	p_umadt_reg_class->ClassId = p_osm_bind_info->mad_class;
760	p_umadt_reg_class->ClassVersion = p_osm_bind_info->class_version;
761	p_umadt_reg_class->isResponder = p_osm_bind_info->is_responder;
762	p_umadt_reg_class->isTrapProcessor = p_osm_bind_info->is_trap_processor;
763	p_umadt_reg_class->isReportProcessor =
764	    p_osm_bind_info->is_report_processor;
765	p_umadt_reg_class->SendQueueSize = p_osm_bind_info->send_q_size;
766	p_umadt_reg_class->RecvQueueSize = p_osm_bind_info->recv_q_size;
767	p_umadt_reg_class->NotifySendCompletion = TRUE;
768
769	p_mad_bind_info->p_umadt_obj = p_umadt_obj;
770	p_mad_bind_info->p_mad_pool = p_mad_pool;
771	p_mad_bind_info->mad_recv_callback = mad_recv_callback;
772	p_mad_bind_info->client_context = context;
773
774	/*  register with Umadt for MAD interface */
775	Status = p_umadt_obj->uMadtInterface.uMadtRegister(p_umadt_reg_class,
776							   &p_mad_bind_info->
777							   umadt_handle);
778	if (Status != FSUCCESS) {
779		free(p_mad_bind_info);
780		OSM_LOG_EXIT(p_umadt_obj->p_log);
781		return (OSM_BIND_INVALID_HANDLE);
782	}
783	CL_ASSERT(p_mad_bind_info->umadt_handle);
784	/*  */
785	/*  Start a worker thread to process receives. */
786	/*  */
787	cl_thread_construct(&p_mad_bind_info->recv_processor_thread);
788	cl_status = cl_thread_init(&p_mad_bind_info->recv_processor_thread,
789				   __mad_recv_processor,
790				   (void *)p_mad_bind_info, "mad_recv_worker");
791	CL_ASSERT(cl_status == CL_SUCCESS);
792
793	cl_qlist_init(&p_mad_bind_info->trans_ctxt_list);
794	cl_spinlock_construct(&p_mad_bind_info->trans_ctxt_lock);
795	cl_spinlock_init(&p_mad_bind_info->trans_ctxt_lock);
796	cl_spinlock_construct(&p_mad_bind_info->timeout_list_lock);
797	cl_spinlock_init(&p_mad_bind_info->timeout_list_lock);
798
799	cl_status = cl_timer_init(&p_mad_bind_info->timeout_timer,
800				  __osm_vendor_timer_callback,
801				  (void *)p_mad_bind_info);
802	CL_ASSERT(cl_status == CL_SUCCESS);
803	cl_qlist_init(&p_mad_bind_info->timeout_list);
804	/*  */
805	/*  Insert the mad_reg_struct in list and return pointer to it as the handle */
806	/*  */
807	cl_spinlock_acquire(&p_umadt_obj->register_lock);
808
809	cl_qlist_insert_head(&p_umadt_obj->register_list,
810			     &p_mad_bind_info->list_item);
811
812	cl_spinlock_release(&p_umadt_obj->register_lock);
813
814	/*
815	   A timeout value of 0 means disable timeouts.
816	 */
817	if (p_umadt_obj->timeout) {
818		cl_timer_start(&p_mad_bind_info->timeout_timer,
819			       DEFAULT_TIMER_INTERVAL_MSEC);
820	}
821
822	OSM_LOG_EXIT(p_umadt_obj->p_log);
823	return ((osm_bind_handle_t) p_mad_bind_info);
824}
825
826/**********************************************************************
827 **********************************************************************/
828void osm_vendor_unbind(IN osm_bind_handle_t h_bind)
829{
830	mad_bind_info_t *p_mad_bind_info;
831	umadt_obj_t *p_umadt_obj;
832	cl_list_item_t *p_list_item, *p_next_list_item;
833
834	CL_ASSERT(h_bind);
835	p_mad_bind_info = (mad_bind_info_t *) h_bind;
836	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
837
838	/*  sanity check */
839	CL_ASSERT(p_umadt_obj);
840	CL_ASSERT(p_umadt_obj->init_done);
841	CL_ASSERT(__valid_mad_handle(p_mad_bind_info));
842
843	p_umadt_obj->uMadtInterface.uMadtDestroy(&p_mad_bind_info->
844						 umadt_handle);
845	cl_timer_destroy(&p_mad_bind_info->timeout_timer);
846	cl_thread_destroy(&p_mad_bind_info->recv_processor_thread);
847
848	cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
849	p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list);
850	while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
851		p_next_list_item = cl_qlist_next(p_list_item);
852		cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
853				     p_list_item);
854		free(p_list_item);
855		p_list_item = p_next_list_item;
856	}
857	cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
858
859	cl_spinlock_acquire(&p_mad_bind_info->timeout_list_lock);
860	p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list);
861	while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) {
862		p_next_list_item = cl_qlist_next(p_list_item);
863		cl_qlist_remove_item(&p_mad_bind_info->timeout_list,
864				     p_list_item);
865		free(p_list_item);
866		p_list_item = p_next_list_item;
867	}
868	cl_spinlock_release(&p_mad_bind_info->timeout_list_lock);
869
870	free(p_mad_bind_info);
871}
872
873/**********************************************************************
874 **********************************************************************/
875void __mad_recv_processor(IN void *context)
876{
877	mad_bind_info_t *p_mad_bind_info = (mad_bind_info_t *) context;
878	umadt_obj_t *p_umadt_obj;
879	osm_madw_t *p_osm_madw = NULL;
880	osm_vend_wrap_t *p_vend_wrap = NULL;
881	osm_mad_addr_t osm_mad_addr = { 0 };
882	cl_list_item_t *p_list_item;
883	void *transaction_context;
884
885	FSTATUS Status;
886	MadtStruct *pRecvMad = NULL;
887	MadWorkCompletion *pRecvCmp = NULL;
888
889	CL_ASSERT(context);
890
891	p_mad_bind_info = (mad_bind_info_t *) context;
892	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
893	/*  PollFor a completion */
894	/*  if FNOTFOND, then wait for a completion then again poll and return the MAD */
895	while (1) {
896		Status =
897		    p_umadt_obj->uMadtInterface.
898		    uMadtPollForRecvCompletion(p_mad_bind_info->umadt_handle,
899					       &pRecvMad, &pRecvCmp);
900		if (Status != FSUCCESS) {
901			if (Status == FNOT_FOUND) {
902				/* Wait for a completion */
903				Status = p_umadt_obj->uMadtInterface.uMadtWaitForAnyCompletion(p_mad_bind_info->umadt_handle, RECV_COMPLETION, 0x5000);	/* 5 sec timeout */
904
905				if (Status == FTIMEOUT) {
906					continue;
907				}
908				CL_ASSERT(Status == FSUCCESS);
909
910				Status =
911				    p_umadt_obj->uMadtInterface.
912				    uMadtPollForRecvCompletion(p_mad_bind_info->
913							       umadt_handle,
914							       &pRecvMad,
915							       &pRecvCmp);
916				if (Status != FSUCCESS) {
917					printf
918					    (" mad_recv_worker: Error in PollForRecv returning <%x>\n",
919					     Status);
920					CL_ASSERT(0);
921				}
922			} else {
923				printf
924				    ("uMadtPollForRecvCompletion Status=<%x>\n",
925				     Status);
926				CL_ASSERT(0);
927			}
928		}
929		CL_ASSERT(pRecvMad);
930		CL_ASSERT(pRecvCmp);
931
932		if (((ib_sa_mad_t_vM3 *) (&pRecvMad->IBMad))->frag_flag & 0x20) {
933			/*  Ignore the ACK packet */
934			Status =
935			    p_umadt_obj->uMadtInterface.
936			    uMadtReleaseRecvMad(p_mad_bind_info->umadt_handle,
937						pRecvMad);
938			continue;
939		}
940		/*  */
941		/*  Extract the return address to pass it on to the client */
942		/*  */
943		osm_mad_addr.dest_lid = pRecvCmp->AddressInfo.DestLid;
944		osm_mad_addr.path_bits = pRecvCmp->AddressInfo.PathBits;
945		osm_mad_addr.static_rate = pRecvCmp->AddressInfo.StaticRate;
946
947		if (p_mad_bind_info->umadt_reg_class.ClassId ==
948		    IB_MCLASS_SUBN_LID
949		    || p_mad_bind_info->umadt_reg_class.ClassId ==
950		    IB_MCLASS_SUBN_DIR) {
951			osm_mad_addr.addr_type.smi.source_lid =
952			    pRecvCmp->AddressInfo.AddrType.Smi.SourceLid;
953			/* osm_mad_addr.addr_type.smi.port_num = pRecvCmp->AddressInfo.AddrType.Smi.PortNumber; */
954		} else {
955			osm_mad_addr.addr_type.gsi.remote_qp =
956			    pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQpNumber;
957			osm_mad_addr.addr_type.gsi.remote_qkey =
958			    pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQkey;
959			osm_mad_addr.addr_type.gsi.pkey_ix = 0;
960			osm_mad_addr.addr_type.gsi.service_level =
961			    pRecvCmp->AddressInfo.AddrType.Gsi.ServiceLevel;
962			osm_mad_addr.addr_type.gsi.global_route =
963			    pRecvCmp->AddressInfo.AddrType.Gsi.GlobalRoute;
964			/* osm_mad_addr.addr_type.gsi.grh_info = pRecvCmp->AddressInfo.AddrType.Gsi.GRHInfo; */
965		}
966		p_osm_madw =
967		    osm_mad_pool_get_wrapper(p_mad_bind_info->p_mad_pool,
968					     p_mad_bind_info, MAD_BLOCK_SIZE,
969					     (ib_mad_t *) & pRecvMad->IBMad,
970					     &osm_mad_addr);
971		CL_ASSERT(p_osm_madw);
972		p_vend_wrap = osm_madw_get_vend_ptr(p_osm_madw);
973		CL_ASSERT(p_vend_wrap);
974		p_vend_wrap->p_madt_struct = pRecvMad;
975		p_vend_wrap->direction = RECEIVE;
976
977		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
978			"__mad_recv_processor: "
979			"Received data p_osm_madw[0x%p].\n", p_osm_madw);
980
981		/*  */
982		/*  Do TID Processing. */
983		/*  */
984		/*  If R bit is set swap the TID */
985
986		cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
987		p_list_item =
988		    cl_qlist_find_from_head(&p_mad_bind_info->trans_ctxt_list,
989					    __match_tid_context,
990					    &p_osm_madw->p_mad->trans_id);
991
992		if (p_list_item ==
993		    cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
994			transaction_context = NULL;
995		} else {
996			transaction_context =
997			    ((trans_context_t *) p_list_item)->context;
998			cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
999					     p_list_item);
1000			free(p_list_item);
1001		}
1002		cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
1003		((ib_mad_t *) p_osm_madw->p_mad)->trans_id =
1004		    cl_ntoh64(p_osm_madw->p_mad->trans_id >> 24);
1005		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
1006			"__mad_recv_processor: "
1007			"Received data p_osm_madw [0x%p]" "\n\t\t\t\tTID[0x%"
1008			PRIx64 ", context[%p]. \n", p_osm_madw,
1009			((ib_mad_t *) p_osm_madw->p_mad)->trans_id,
1010			transaction_context);
1011
1012		(*(p_mad_bind_info->mad_recv_callback)) (p_osm_madw,
1013							 p_mad_bind_info->
1014							 client_context,
1015							 transaction_context);
1016
1017	}
1018}
1019
1020/**********************************************************************
1021 **********************************************************************/
1022
1023cl_status_t
1024__match_tid_context(const cl_list_item_t * const p_list_item, void *context)
1025{
1026	if (((trans_context_t *) p_list_item)->trans_id ==
1027	    *((uint64_t *) context))
1028		return CL_SUCCESS;
1029	return CL_NOT_FOUND;
1030}
1031
1032/**********************************************************************
1033 **********************************************************************/
1034
1035boolean_t __valid_mad_handle(IN mad_bind_info_t * p_mad_bind_info)
1036{
1037
1038	umadt_obj_t *p_umadt_obj;
1039
1040	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
1041
1042	cl_spinlock_acquire(&p_umadt_obj->register_lock);
1043	if (!cl_is_item_in_qlist(&p_umadt_obj->register_list,
1044				 &p_mad_bind_info->list_item)) {
1045		cl_spinlock_release(&p_umadt_obj->register_lock);
1046		return FALSE;
1047	}
1048	cl_spinlock_release(&p_umadt_obj->register_lock);
1049	return TRUE;
1050}
1051
1052void __osm_vendor_timer_callback(IN void *context)
1053{
1054	uint64_t current_time;
1055	mad_bind_info_t *p_mad_bind_info;
1056	umadt_obj_t *p_umadt_obj;
1057	uint32_t timeout;
1058
1059	cl_list_item_t *p_list_item, *p_next_list_item;
1060
1061	CL_ASSERT(context);
1062
1063	p_mad_bind_info = (mad_bind_info_t *) context;
1064	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
1065	timeout = p_umadt_obj->timeout * 1000;
1066
1067	current_time = cl_get_time_stamp();
1068
1069	cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
1070
1071	p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list);
1072	while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
1073
1074		p_next_list_item = cl_qlist_next(p_list_item);
1075
1076		/*  DEFAULT_PKT_TIMEOUT is in milli seconds */
1077		if (current_time - ((trans_context_t *) p_list_item)->sent_time
1078		    > timeout) {
1079			/*  Add this transaction to the timeout_list */
1080			cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
1081					     p_list_item);
1082			cl_qlist_insert_tail(&p_mad_bind_info->timeout_list,
1083					     p_list_item);
1084		}
1085
1086		p_list_item = p_next_list_item;
1087	}
1088
1089	cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
1090
1091	p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list);
1092	while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) {
1093		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
1094			"__osm_vendor_timer_callback: "
1095			"Timing out transaction context [0x%p].\n",
1096			((trans_context_t *) p_list_item)->context);
1097
1098		(*(p_mad_bind_info->mad_recv_callback)) (NULL,
1099							 p_mad_bind_info->
1100							 client_context,
1101							 ((trans_context_t *)
1102							  p_list_item)->
1103							 context);
1104
1105		p_next_list_item = cl_qlist_next(p_list_item);
1106		cl_qlist_remove_item(&p_mad_bind_info->timeout_list,
1107				     p_list_item);
1108		free(p_list_item);
1109		p_list_item = p_next_list_item;
1110	}
1111
1112	cl_timer_start(&p_mad_bind_info->timeout_timer,
1113		       DEFAULT_TIMER_INTERVAL_MSEC);
1114
1115}
1116
1117#endif				/* OSM_VENDOR_INTF_UMADT */
1118