1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff#if HAVE_CONFIG_H
37219820Sjeff#  include <config.h>
38219820Sjeff#endif				/* HAVE_CONFIG_H */
39219820Sjeff
40219820Sjeff#include <stdlib.h>
41219820Sjeff#include <string.h>
42219820Sjeff#include <iba/ib_types.h>
43219820Sjeff#include <complib/cl_qlist.h>
44219820Sjeff
45219820Sjeff#include <vendor/osm_vendor_mlx_rmpp_ctx.h>
46219820Sjeff#include <vendor/osm_vendor_mlx_svc.h>
47219820Sjeff
48219820Sjeffib_api_status_t
49219820Sjeffosmv_rmpp_send_ctx_init(osmv_rmpp_send_ctx_t * p_ctx, void *p_arbt_mad,
50219820Sjeff			uint32_t mad_sz, osm_log_t * p_log)
51219820Sjeff{
52219820Sjeff	ib_api_status_t st = IB_SUCCESS;
53219820Sjeff	cl_status_t cl_st;
54219820Sjeff
55219820Sjeff	CL_ASSERT(p_ctx);
56219820Sjeff	if (NULL == p_arbt_mad) {
57219820Sjeff		return IB_INVALID_PARAMETER;
58219820Sjeff	}
59219820Sjeff
60219820Sjeff	if (osmv_mad_is_sa((ib_mad_t *) p_arbt_mad)) {
61219820Sjeff		p_ctx->is_sa_mad = TRUE;
62219820Sjeff	} else
63219820Sjeff		p_ctx->is_sa_mad = FALSE;
64219820Sjeff
65219820Sjeff	p_ctx->mad_sz = mad_sz;
66219820Sjeff
67219820Sjeff	cl_event_construct(&p_ctx->event);
68219820Sjeff	cl_st = cl_event_init(&p_ctx->event, FALSE);
69219820Sjeff	if (cl_st != CL_SUCCESS) {
70219820Sjeff		return IB_ERROR;
71219820Sjeff	}
72219820Sjeff
73219820Sjeff	st = osmv_rmpp_sar_init(&p_ctx->sar, p_arbt_mad, p_ctx->mad_sz,
74219820Sjeff				p_ctx->is_sa_mad);
75219820Sjeff	if (st == IB_SUCCESS) {
76219820Sjeff		p_ctx->window_first = 1;
77219820Sjeff		p_ctx->window_last = 1;
78219820Sjeff	}
79219820Sjeff
80219820Sjeff	p_ctx->p_log = p_log;
81219820Sjeff	return st;
82219820Sjeff}
83219820Sjeff
84219820Sjeffvoid osmv_rmpp_send_ctx_done(IN osmv_rmpp_send_ctx_t * p_ctx)
85219820Sjeff{
86219820Sjeff	CL_ASSERT(p_ctx);
87219820Sjeff	cl_event_destroy(&p_ctx->event);
88219820Sjeff	osmv_rmpp_sar_done(&p_ctx->sar);
89219820Sjeff	free(p_ctx);
90219820Sjeff}
91219820Sjeff
92219820Sjeffuint32_t osmv_rmpp_send_ctx_get_num_segs(IN osmv_rmpp_send_ctx_t * p_send_ctx)
93219820Sjeff{
94219820Sjeff	uint32_t data_len, data_sz, num;
95219820Sjeff
96219820Sjeff	CL_ASSERT(p_send_ctx);
97219820Sjeff
98219820Sjeff	if (p_send_ctx->is_sa_mad) {
99219820Sjeff		data_len = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE;
100219820Sjeff		data_sz = IB_SA_DATA_SIZE;
101219820Sjeff	} else {
102219820Sjeff		data_len = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE;
103219820Sjeff		data_sz = MAD_RMPP_DATA_SIZE;
104219820Sjeff	}
105219820Sjeff
106219820Sjeff	num = data_len / data_sz;
107219820Sjeff	if (0 == data_len || (data_len % data_sz) > 0) {
108219820Sjeff		num++;
109219820Sjeff	}
110219820Sjeff
111219820Sjeff	return num;
112219820Sjeff}
113219820Sjeff
114219820Sjeffib_api_status_t
115219820Sjeffosmv_rmpp_send_ctx_get_seg(IN osmv_rmpp_send_ctx_t * p_send_ctx,
116219820Sjeff			   IN uint32_t seg_idx,
117219820Sjeff			   IN uint32_t resp_timeout, OUT void *p_buf)
118219820Sjeff{
119219820Sjeff	ib_api_status_t st = IB_SUCCESS;
120219820Sjeff	uint32_t num_segs, paylen = 0;
121219820Sjeff	ib_rmpp_mad_t *p_rmpp_mad;
122219820Sjeff
123219820Sjeff	OSM_LOG_ENTER(p_send_ctx->p_log);
124219820Sjeff	CL_ASSERT(p_send_ctx);
125219820Sjeff
126219820Sjeff	st = osmv_rmpp_sar_get_mad_seg(&p_send_ctx->sar, seg_idx, p_buf);
127219820Sjeff	if (st != IB_SUCCESS) {
128219820Sjeff		goto Exit;
129219820Sjeff	}
130219820Sjeff
131219820Sjeff	p_rmpp_mad = (ib_rmpp_mad_t *) p_buf;
132219820Sjeff	/* Set the relevant bits in the RMPP hdr */
133219820Sjeff	p_rmpp_mad->rmpp_status = IB_RMPP_STATUS_SUCCESS;
134219820Sjeff	p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_ACTIVE;
135219820Sjeff	p_rmpp_mad->rmpp_flags |= resp_timeout << 3;
136219820Sjeff
137219820Sjeff	num_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx);
138219820Sjeff
139219820Sjeff	if (1 == seg_idx) {
140219820Sjeff		p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_FIRST;
141219820Sjeff
142219820Sjeff		/* This is the first segment -
143219820Sjeff		   the reported paylen is the total amount of data.
144219820Sjeff		 */
145219820Sjeff		if (p_send_ctx->is_sa_mad) {
146219820Sjeff			/* sa mad hdr sz */
147219820Sjeff			paylen = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE;
148219820Sjeff			paylen +=
149219820Sjeff			    num_segs * (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE);
150219820Sjeff		} else {
151219820Sjeff			/* mad hdr sz */
152219820Sjeff			paylen = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE;
153219820Sjeff		}
154219820Sjeff	}
155219820Sjeff
156219820Sjeff	if (seg_idx == num_segs) {
157219820Sjeff		p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_LAST;
158219820Sjeff
159219820Sjeff		/*
160219820Sjeff		   This is the last segment -
161219820Sjeff		   the reported paylen is only the amount of data left on this segment.
162219820Sjeff		 */
163219820Sjeff		if (p_send_ctx->is_sa_mad) {
164219820Sjeff			paylen = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE;
165219820Sjeff			paylen -= (num_segs - 1) * IB_SA_DATA_SIZE;
166219820Sjeff			paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE);
167219820Sjeff		} else {
168219820Sjeff			paylen = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE;
169219820Sjeff			paylen -=
170219820Sjeff			    (num_segs - 1) * (MAD_BLOCK_SIZE -
171219820Sjeff					      MAD_RMPP_HDR_SIZE);
172219820Sjeff		}
173219820Sjeff	}
174219820Sjeff
175219820Sjeff	p_rmpp_mad->rmpp_type = IB_RMPP_TYPE_DATA;
176219820Sjeff	p_rmpp_mad->rmpp_version = 1;
177219820Sjeff	p_rmpp_mad->paylen_newwin = cl_ntoh32(paylen);
178219820Sjeff	p_rmpp_mad->seg_num = cl_ntoh32(seg_idx);
179219820Sjeff
180219820SjeffExit:
181219820Sjeff	OSM_LOG_EXIT(p_send_ctx->p_log);
182219820Sjeff	return st;
183219820Sjeff}
184219820Sjeff
185219820Sjeffib_api_status_t
186219820Sjeffosmv_rmpp_recv_ctx_init(osmv_rmpp_recv_ctx_t * p_ctx, osm_log_t * p_log)
187219820Sjeff{
188219820Sjeff	ib_api_status_t st = IB_SUCCESS;
189219820Sjeff
190219820Sjeff	CL_ASSERT(p_ctx);
191219820Sjeff
192219820Sjeff	p_ctx->is_sa_mad = FALSE;
193219820Sjeff
194219820Sjeff	p_ctx->p_rbuf = malloc(sizeof(cl_qlist_t));
195219820Sjeff	if (p_ctx->p_rbuf) {
196219820Sjeff		memset(p_ctx->p_rbuf, 0, sizeof(cl_qlist_t));
197219820Sjeff		cl_qlist_init(p_ctx->p_rbuf);
198219820Sjeff		p_ctx->expected_seg = 1;
199219820Sjeff	} else
200219820Sjeff		st = IB_INSUFFICIENT_MEMORY;
201219820Sjeff
202219820Sjeff	p_ctx->p_log = p_log;
203219820Sjeff
204219820Sjeff	return st;
205219820Sjeff}
206219820Sjeff
207219820Sjeffvoid osmv_rmpp_recv_ctx_done(IN osmv_rmpp_recv_ctx_t * p_ctx)
208219820Sjeff{
209219820Sjeff	cl_list_item_t *p_list_item;
210219820Sjeff	cl_list_obj_t *p_obj;
211219820Sjeff
212219820Sjeff	CL_ASSERT(p_ctx);
213219820Sjeff
214219820Sjeff	/* go over all the items in the list and remove them */
215219820Sjeff	p_list_item = cl_qlist_remove_head(p_ctx->p_rbuf);
216219820Sjeff	while (p_list_item != cl_qlist_end(p_ctx->p_rbuf)) {
217219820Sjeff
218219820Sjeff		p_obj = PARENT_STRUCT(p_list_item, cl_list_obj_t, list_item);
219219820Sjeff
220219820Sjeff		free(cl_qlist_obj(p_obj));
221219820Sjeff		free(p_obj);
222219820Sjeff
223219820Sjeff		p_list_item = cl_qlist_remove_head(p_ctx->p_rbuf);
224219820Sjeff	}
225219820Sjeff
226219820Sjeff	osmv_rmpp_sar_done(&p_ctx->sar);
227219820Sjeff
228219820Sjeff	free(p_ctx->p_rbuf);
229219820Sjeff	free(p_ctx);
230219820Sjeff}
231219820Sjeff
232219820Sjeffib_api_status_t
233219820Sjeffosmv_rmpp_recv_ctx_store_mad_seg(IN osmv_rmpp_recv_ctx_t * p_recv_ctx,
234219820Sjeff				 IN void *p_mad)
235219820Sjeff{
236219820Sjeff	cl_list_obj_t *p_obj = NULL;
237219820Sjeff	void *p_list_mad;
238219820Sjeff
239219820Sjeff	OSM_LOG_ENTER(p_recv_ctx->p_log);
240219820Sjeff
241219820Sjeff	CL_ASSERT(p_recv_ctx);
242219820Sjeff	p_list_mad = malloc(MAD_BLOCK_SIZE);
243219820Sjeff	if (NULL == p_list_mad) {
244219820Sjeff		return IB_INSUFFICIENT_MEMORY;
245219820Sjeff	}
246219820Sjeff	memset(p_list_mad, 0, MAD_BLOCK_SIZE);
247219820Sjeff	memcpy(p_list_mad, p_mad, MAD_BLOCK_SIZE);
248219820Sjeff
249219820Sjeff	p_obj = malloc(sizeof(cl_list_obj_t));
250219820Sjeff	if (NULL == p_obj) {
251219820Sjeff		free(p_list_mad);
252219820Sjeff		return IB_INSUFFICIENT_MEMORY;
253219820Sjeff	}
254219820Sjeff	memset(p_obj, 0, sizeof(cl_list_obj_t));
255219820Sjeff	cl_qlist_set_obj(p_obj, p_list_mad);
256219820Sjeff
257219820Sjeff	cl_qlist_insert_tail(p_recv_ctx->p_rbuf, &p_obj->list_item);
258219820Sjeff
259219820Sjeff	if (osmv_mad_is_sa((ib_mad_t *) p_mad)) {
260219820Sjeff		p_recv_ctx->is_sa_mad = TRUE;
261219820Sjeff	}
262219820Sjeff
263219820Sjeff	return IB_SUCCESS;
264219820Sjeff
265219820Sjeff}
266219820Sjeff
267219820Sjeffuint32_t
268219820Sjeffosmv_rmpp_recv_ctx_get_cur_byte_num(IN osmv_rmpp_recv_ctx_t * p_recv_ctx)
269219820Sjeff{
270219820Sjeff	uint32_t num_segs;
271219820Sjeff
272219820Sjeff	num_segs = cl_qlist_count(p_recv_ctx->p_rbuf);
273219820Sjeff	if (p_recv_ctx->is_sa_mad)
274219820Sjeff		return ((num_segs * IB_SA_DATA_SIZE) + IB_SA_MAD_HDR_SIZE);
275219820Sjeff	else
276219820Sjeff		return ((num_segs * MAD_RMPP_DATA_SIZE) + MAD_RMPP_HDR_SIZE);
277219820Sjeff}
278219820Sjeff
279219820Sjeffuint32_t
280219820Sjeffosmv_rmpp_recv_ctx_get_byte_num_from_first(IN osmv_rmpp_recv_ctx_t * p_recv_ctx)
281219820Sjeff{
282219820Sjeff	cl_list_item_t *p_item;
283219820Sjeff	cl_list_obj_t *p_obj;
284219820Sjeff	void *p_list_mad;
285219820Sjeff	uint32_t num_bytes, num_segs;
286219820Sjeff
287219820Sjeff	p_item = cl_qlist_head(p_recv_ctx->p_rbuf);
288219820Sjeff	p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
289219820Sjeff	p_list_mad = cl_qlist_obj(p_obj);
290219820Sjeff
291219820Sjeff	/* mad data sz */
292219820Sjeff	num_bytes = cl_ntoh32(((ib_rmpp_mad_t *) p_list_mad)->paylen_newwin);
293219820Sjeff	if (0 != num_bytes) {
294219820Sjeff		if (p_recv_ctx->is_sa_mad) {
295219820Sjeff			/* sa mad hdr sz */
296219820Sjeff			num_segs = cl_qlist_count(p_recv_ctx->p_rbuf);
297219820Sjeff			num_bytes -=
298219820Sjeff			    num_segs * (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE);
299219820Sjeff			num_bytes += IB_SA_MAD_HDR_SIZE;
300219820Sjeff		} else {
301219820Sjeff			/* mad hdr sz */
302219820Sjeff			num_bytes += MAD_RMPP_HDR_SIZE;
303219820Sjeff		}
304219820Sjeff	}
305219820Sjeff
306219820Sjeff	return num_bytes;
307219820Sjeff}
308219820Sjeff
309219820Sjeffuint32_t
310219820Sjeffosmv_rmpp_recv_ctx_get_byte_num_from_last(IN osmv_rmpp_recv_ctx_t * p_recv_ctx)
311219820Sjeff{
312219820Sjeff	cl_list_item_t *p_item;
313219820Sjeff	cl_list_obj_t *p_obj;
314219820Sjeff	void *p_list_mad;
315219820Sjeff	uint32_t num_bytes, num_segs;
316219820Sjeff
317219820Sjeff	p_item = cl_qlist_tail(p_recv_ctx->p_rbuf);
318219820Sjeff	p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item);
319219820Sjeff	p_list_mad = cl_qlist_obj(p_obj);
320219820Sjeff
321219820Sjeff	/* mad data sz */
322219820Sjeff	num_segs = cl_qlist_count(p_recv_ctx->p_rbuf);
323219820Sjeff	num_bytes = cl_ntoh32(((ib_rmpp_mad_t *) p_list_mad)->paylen_newwin);
324219820Sjeff
325219820Sjeff	if (0 != num_bytes) {
326219820Sjeff		if (p_recv_ctx->is_sa_mad) {
327219820Sjeff			/* sa mad hdr sz */
328219820Sjeff			num_bytes += MAD_RMPP_HDR_SIZE;
329219820Sjeff			num_bytes += (num_segs - 1) * IB_SA_DATA_SIZE;
330219820Sjeff		} else {
331219820Sjeff			/* mad hdr sz */
332219820Sjeff			num_bytes += MAD_RMPP_HDR_SIZE;
333219820Sjeff			num_bytes += (num_segs - 1) * MAD_RMPP_DATA_SIZE;
334219820Sjeff		}
335219820Sjeff	}
336219820Sjeff
337219820Sjeff	return num_bytes;
338219820Sjeff}
339219820Sjeff
340219820Sjeff/* assuming that the last rmpp pkt arrived so that data member: total_bytes has the right value */
341219820Sjeffib_api_status_t
342219820Sjeffosmv_rmpp_recv_ctx_reassemble_arbt_mad(IN osmv_rmpp_recv_ctx_t * p_recv_ctx,
343219820Sjeff				       IN uint32_t size, IN void *p_arbt_mad)
344219820Sjeff{
345219820Sjeff	ib_api_status_t st = IB_SUCCESS;
346219820Sjeff
347219820Sjeff	CL_ASSERT(p_recv_ctx);
348219820Sjeff
349219820Sjeff	st = osmv_rmpp_sar_init(&p_recv_ctx->sar, p_arbt_mad, size,
350219820Sjeff				p_recv_ctx->is_sa_mad);
351219820Sjeff	if (st != IB_SUCCESS) {
352219820Sjeff		return st;
353219820Sjeff	}
354219820Sjeff
355219820Sjeff	st = osmv_rmpp_sar_reassemble_arbt_mad(&p_recv_ctx->sar,
356219820Sjeff					       p_recv_ctx->p_rbuf);
357219820Sjeff
358219820Sjeff	osmv_rmpp_sar_done(&p_recv_ctx->sar);
359219820Sjeff
360219820Sjeff	return st;
361219820Sjeff}
362