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
826void osm_vendor_unbind(IN osm_bind_handle_t h_bind)
827{
828	mad_bind_info_t *p_mad_bind_info;
829	umadt_obj_t *p_umadt_obj;
830	cl_list_item_t *p_list_item, *p_next_list_item;
831
832	CL_ASSERT(h_bind);
833	p_mad_bind_info = (mad_bind_info_t *) h_bind;
834	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
835
836	/*  sanity check */
837	CL_ASSERT(p_umadt_obj);
838	CL_ASSERT(p_umadt_obj->init_done);
839	CL_ASSERT(__valid_mad_handle(p_mad_bind_info));
840
841	p_umadt_obj->uMadtInterface.uMadtDestroy(&p_mad_bind_info->
842						 umadt_handle);
843	cl_timer_destroy(&p_mad_bind_info->timeout_timer);
844	cl_thread_destroy(&p_mad_bind_info->recv_processor_thread);
845
846	cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
847	p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list);
848	while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
849		p_next_list_item = cl_qlist_next(p_list_item);
850		cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
851				     p_list_item);
852		free(p_list_item);
853		p_list_item = p_next_list_item;
854	}
855	cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
856
857	cl_spinlock_acquire(&p_mad_bind_info->timeout_list_lock);
858	p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list);
859	while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) {
860		p_next_list_item = cl_qlist_next(p_list_item);
861		cl_qlist_remove_item(&p_mad_bind_info->timeout_list,
862				     p_list_item);
863		free(p_list_item);
864		p_list_item = p_next_list_item;
865	}
866	cl_spinlock_release(&p_mad_bind_info->timeout_list_lock);
867
868	free(p_mad_bind_info);
869}
870
871void __mad_recv_processor(IN void *context)
872{
873	mad_bind_info_t *p_mad_bind_info = (mad_bind_info_t *) context;
874	umadt_obj_t *p_umadt_obj;
875	osm_madw_t *p_osm_madw = NULL;
876	osm_vend_wrap_t *p_vend_wrap = NULL;
877	osm_mad_addr_t osm_mad_addr = { 0 };
878	cl_list_item_t *p_list_item;
879	void *transaction_context;
880
881	FSTATUS Status;
882	MadtStruct *pRecvMad = NULL;
883	MadWorkCompletion *pRecvCmp = NULL;
884
885	CL_ASSERT(context);
886
887	p_mad_bind_info = (mad_bind_info_t *) context;
888	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
889	/*  PollFor a completion */
890	/*  if FNOTFOND, then wait for a completion then again poll and return the MAD */
891	while (1) {
892		Status =
893		    p_umadt_obj->uMadtInterface.
894		    uMadtPollForRecvCompletion(p_mad_bind_info->umadt_handle,
895					       &pRecvMad, &pRecvCmp);
896		if (Status != FSUCCESS) {
897			if (Status == FNOT_FOUND) {
898				/* Wait for a completion */
899				Status = p_umadt_obj->uMadtInterface.uMadtWaitForAnyCompletion(p_mad_bind_info->umadt_handle, RECV_COMPLETION, 0x5000);	/* 5 sec timeout */
900
901				if (Status == FTIMEOUT) {
902					continue;
903				}
904				CL_ASSERT(Status == FSUCCESS);
905
906				Status =
907				    p_umadt_obj->uMadtInterface.
908				    uMadtPollForRecvCompletion(p_mad_bind_info->
909							       umadt_handle,
910							       &pRecvMad,
911							       &pRecvCmp);
912				if (Status != FSUCCESS) {
913					printf
914					    (" mad_recv_worker: Error in PollForRecv returning <%x>\n",
915					     Status);
916					CL_ASSERT(0);
917				}
918			} else {
919				printf
920				    ("uMadtPollForRecvCompletion Status=<%x>\n",
921				     Status);
922				CL_ASSERT(0);
923			}
924		}
925		CL_ASSERT(pRecvMad);
926		CL_ASSERT(pRecvCmp);
927
928		if (((ib_sa_mad_t_vM3 *) (&pRecvMad->IBMad))->frag_flag & 0x20) {
929			/*  Ignore the ACK packet */
930			Status =
931			    p_umadt_obj->uMadtInterface.
932			    uMadtReleaseRecvMad(p_mad_bind_info->umadt_handle,
933						pRecvMad);
934			continue;
935		}
936		/*  */
937		/*  Extract the return address to pass it on to the client */
938		/*  */
939		osm_mad_addr.dest_lid = pRecvCmp->AddressInfo.DestLid;
940		osm_mad_addr.path_bits = pRecvCmp->AddressInfo.PathBits;
941		osm_mad_addr.static_rate = pRecvCmp->AddressInfo.StaticRate;
942
943		if (p_mad_bind_info->umadt_reg_class.ClassId ==
944		    IB_MCLASS_SUBN_LID
945		    || p_mad_bind_info->umadt_reg_class.ClassId ==
946		    IB_MCLASS_SUBN_DIR) {
947			osm_mad_addr.addr_type.smi.source_lid =
948			    pRecvCmp->AddressInfo.AddrType.Smi.SourceLid;
949			/* osm_mad_addr.addr_type.smi.port_num = pRecvCmp->AddressInfo.AddrType.Smi.PortNumber; */
950		} else {
951			osm_mad_addr.addr_type.gsi.remote_qp =
952			    pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQpNumber;
953			osm_mad_addr.addr_type.gsi.remote_qkey =
954			    pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQkey;
955			osm_mad_addr.addr_type.gsi.pkey_ix = 0;
956			osm_mad_addr.addr_type.gsi.service_level =
957			    pRecvCmp->AddressInfo.AddrType.Gsi.ServiceLevel;
958			osm_mad_addr.addr_type.gsi.global_route =
959			    pRecvCmp->AddressInfo.AddrType.Gsi.GlobalRoute;
960			/* osm_mad_addr.addr_type.gsi.grh_info = pRecvCmp->AddressInfo.AddrType.Gsi.GRHInfo; */
961		}
962		p_osm_madw =
963		    osm_mad_pool_get_wrapper(p_mad_bind_info->p_mad_pool,
964					     p_mad_bind_info, MAD_BLOCK_SIZE,
965					     (ib_mad_t *) & pRecvMad->IBMad,
966					     &osm_mad_addr);
967		CL_ASSERT(p_osm_madw);
968		p_vend_wrap = osm_madw_get_vend_ptr(p_osm_madw);
969		CL_ASSERT(p_vend_wrap);
970		p_vend_wrap->p_madt_struct = pRecvMad;
971		p_vend_wrap->direction = RECEIVE;
972
973		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
974			"__mad_recv_processor: "
975			"Received data p_osm_madw[0x%p].\n", p_osm_madw);
976
977		/*  */
978		/*  Do TID Processing. */
979		/*  */
980		/*  If R bit is set swap the TID */
981
982		cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
983		p_list_item =
984		    cl_qlist_find_from_head(&p_mad_bind_info->trans_ctxt_list,
985					    __match_tid_context,
986					    &p_osm_madw->p_mad->trans_id);
987
988		if (p_list_item ==
989		    cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
990			transaction_context = NULL;
991		} else {
992			transaction_context =
993			    ((trans_context_t *) p_list_item)->context;
994			cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
995					     p_list_item);
996			free(p_list_item);
997		}
998		cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
999		((ib_mad_t *) p_osm_madw->p_mad)->trans_id =
1000		    cl_ntoh64(p_osm_madw->p_mad->trans_id >> 24);
1001		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
1002			"__mad_recv_processor: "
1003			"Received data p_osm_madw [0x%p]" "\n\t\t\t\tTID[0x%"
1004			PRIx64 ", context[%p]. \n", p_osm_madw,
1005			((ib_mad_t *) p_osm_madw->p_mad)->trans_id,
1006			transaction_context);
1007
1008		(*(p_mad_bind_info->mad_recv_callback)) (p_osm_madw,
1009							 p_mad_bind_info->
1010							 client_context,
1011							 transaction_context);
1012
1013	}
1014}
1015
1016cl_status_t
1017__match_tid_context(const cl_list_item_t * const p_list_item, void *context)
1018{
1019	if (((trans_context_t *) p_list_item)->trans_id ==
1020	    *((uint64_t *) context))
1021		return CL_SUCCESS;
1022	return CL_NOT_FOUND;
1023}
1024
1025boolean_t __valid_mad_handle(IN mad_bind_info_t * p_mad_bind_info)
1026{
1027
1028	umadt_obj_t *p_umadt_obj;
1029
1030	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
1031
1032	cl_spinlock_acquire(&p_umadt_obj->register_lock);
1033	if (!cl_is_item_in_qlist(&p_umadt_obj->register_list,
1034				 &p_mad_bind_info->list_item)) {
1035		cl_spinlock_release(&p_umadt_obj->register_lock);
1036		return FALSE;
1037	}
1038	cl_spinlock_release(&p_umadt_obj->register_lock);
1039	return TRUE;
1040}
1041
1042void __osm_vendor_timer_callback(IN void *context)
1043{
1044	uint64_t current_time;
1045	mad_bind_info_t *p_mad_bind_info;
1046	umadt_obj_t *p_umadt_obj;
1047	uint32_t timeout;
1048
1049	cl_list_item_t *p_list_item, *p_next_list_item;
1050
1051	CL_ASSERT(context);
1052
1053	p_mad_bind_info = (mad_bind_info_t *) context;
1054	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
1055	timeout = p_umadt_obj->timeout * 1000;
1056
1057	current_time = cl_get_time_stamp();
1058
1059	cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);
1060
1061	p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list);
1062	while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {
1063
1064		p_next_list_item = cl_qlist_next(p_list_item);
1065
1066		/*  DEFAULT_PKT_TIMEOUT is in milli seconds */
1067		if (current_time - ((trans_context_t *) p_list_item)->sent_time
1068		    > timeout) {
1069			/*  Add this transaction to the timeout_list */
1070			cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
1071					     p_list_item);
1072			cl_qlist_insert_tail(&p_mad_bind_info->timeout_list,
1073					     p_list_item);
1074		}
1075
1076		p_list_item = p_next_list_item;
1077	}
1078
1079	cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);
1080
1081	p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list);
1082	while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) {
1083		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
1084			"__osm_vendor_timer_callback: "
1085			"Timing out transaction context [0x%p].\n",
1086			((trans_context_t *) p_list_item)->context);
1087
1088		(*(p_mad_bind_info->mad_recv_callback)) (NULL,
1089							 p_mad_bind_info->
1090							 client_context,
1091							 ((trans_context_t *)
1092							  p_list_item)->
1093							 context);
1094
1095		p_next_list_item = cl_qlist_next(p_list_item);
1096		cl_qlist_remove_item(&p_mad_bind_info->timeout_list,
1097				     p_list_item);
1098		free(p_list_item);
1099		p_list_item = p_next_list_item;
1100	}
1101
1102	cl_timer_start(&p_mad_bind_info->timeout_timer,
1103		       DEFAULT_TIMER_INTERVAL_MSEC);
1104
1105}
1106
1107#endif				/* OSM_VENDOR_INTF_UMADT */
1108