1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5d6b92ffaSHans Petter Selasky  *
6d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
7d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
8d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
9d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
10d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
11d6b92ffaSHans Petter Selasky  *
12d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
13d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
14d6b92ffaSHans Petter Selasky  *     conditions are met:
15d6b92ffaSHans Petter Selasky  *
16d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
17d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
18d6b92ffaSHans Petter Selasky  *        disclaimer.
19d6b92ffaSHans Petter Selasky  *
20d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
21d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
22d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
23d6b92ffaSHans Petter Selasky  *        provided with the distribution.
24d6b92ffaSHans Petter Selasky  *
25d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32d6b92ffaSHans Petter Selasky  * SOFTWARE.
33d6b92ffaSHans Petter Selasky  *
34d6b92ffaSHans Petter Selasky  */
35d6b92ffaSHans Petter Selasky 
36d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
37d6b92ffaSHans Petter Selasky #  include <config.h>
38d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
39d6b92ffaSHans Petter Selasky 
40d6b92ffaSHans Petter Selasky #include <string.h>
41d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_mlx.h>
42d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_mlx_defs.h>
43d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_mlx_svc.h>
44d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_mlx_transport.h>
45d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_mlx_sender.h>
46d6b92ffaSHans Petter Selasky #include <vendor/osm_pkt_randomizer.h>
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky typedef enum _osmv_disp_route {
49d6b92ffaSHans Petter Selasky 
50d6b92ffaSHans Petter Selasky 	OSMV_ROUTE_DROP,
51d6b92ffaSHans Petter Selasky 	OSMV_ROUTE_SIMPLE,
52d6b92ffaSHans Petter Selasky 	OSMV_ROUTE_RMPP,
53d6b92ffaSHans Petter Selasky 
54d6b92ffaSHans Petter Selasky } osmv_disp_route_t;
55d6b92ffaSHans Petter Selasky 
56d6b92ffaSHans Petter Selasky /**
57d6b92ffaSHans Petter Selasky  *   FORWARD REFERENCES TO PRIVATE FUNCTIONS
58d6b92ffaSHans Petter Selasky  */
59d6b92ffaSHans Petter Selasky 
60d6b92ffaSHans Petter Selasky static osmv_disp_route_t
61d6b92ffaSHans Petter Selasky __osmv_dispatch_route(IN osm_bind_handle_t h_bind,
62d6b92ffaSHans Petter Selasky 		      IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn);
63d6b92ffaSHans Petter Selasky 
64d6b92ffaSHans Petter Selasky static void
65d6b92ffaSHans Petter Selasky __osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind,
66d6b92ffaSHans Petter Selasky 			   IN const ib_mad_t * p_mad,
67d6b92ffaSHans Petter Selasky 			   IN osmv_txn_ctx_t * p_txn,
68d6b92ffaSHans Petter Selasky 			   IN const osm_mad_addr_t * p_mad_addr);
69d6b92ffaSHans Petter Selasky 
70d6b92ffaSHans Petter Selasky static void
71d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind,
72d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
73d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
74d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr);
75d6b92ffaSHans Petter Selasky 
76d6b92ffaSHans Petter Selasky static void
77d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind,
78d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
79d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
80d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr);
81d6b92ffaSHans Petter Selasky 
82d6b92ffaSHans Petter Selasky static ib_api_status_t
83d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind,
84d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
85d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
86d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr);
87d6b92ffaSHans Petter Selasky 
88d6b92ffaSHans Petter Selasky static ib_api_status_t
89d6b92ffaSHans Petter Selasky __osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind,
90d6b92ffaSHans Petter Selasky 			   IN osmv_txn_ctx_t * p_txn,
91d6b92ffaSHans Petter Selasky 			   IN const ib_mad_t * p_mad);
92d6b92ffaSHans Petter Selasky static void
93d6b92ffaSHans Petter Selasky __osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind,
94d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_req_mad,
95d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
96d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr);
97d6b92ffaSHans Petter Selasky 
98d6b92ffaSHans Petter Selasky /*
99d6b92ffaSHans Petter Selasky  * NAME
100d6b92ffaSHans Petter Selasky  *   osmv_dispatch_mad
101d6b92ffaSHans Petter Selasky  *
102d6b92ffaSHans Petter Selasky  * DESCRIPTION
103d6b92ffaSHans Petter Selasky  *   Lower-level MAD dispatcher.
104d6b92ffaSHans Petter Selasky  *   Implements a switch between the following MAD consumers:
105d6b92ffaSHans Petter Selasky  *   (1) Non-RMPP consumer (DATA)
106d6b92ffaSHans Petter Selasky  *   (2) RMPP receiver     (DATA/ABORT/STOP)
107d6b92ffaSHans Petter Selasky  *   (3) RMPP sender       (ACK/ABORT/STOP)
108d6b92ffaSHans Petter Selasky  *
109d6b92ffaSHans Petter Selasky  * PARAMETERS
110d6b92ffaSHans Petter Selasky  *   h_bind                The bind handle
111d6b92ffaSHans Petter Selasky  *   p_mad_buf             The 256 byte buffer of individual MAD
112d6b92ffaSHans Petter Selasky  *   p_mad_addr            The MAD originator's address
113d6b92ffaSHans Petter Selasky  */
114d6b92ffaSHans Petter Selasky 
115d6b92ffaSHans Petter Selasky ib_api_status_t
osmv_dispatch_mad(IN osm_bind_handle_t h_bind,IN const void * p_mad_buf,IN const osm_mad_addr_t * p_mad_addr)116d6b92ffaSHans Petter Selasky osmv_dispatch_mad(IN osm_bind_handle_t h_bind,
117d6b92ffaSHans Petter Selasky 		  IN const void *p_mad_buf,
118d6b92ffaSHans Petter Selasky 		  IN const osm_mad_addr_t * p_mad_addr)
119d6b92ffaSHans Petter Selasky {
120d6b92ffaSHans Petter Selasky 	ib_api_status_t ret = IB_SUCCESS;
121d6b92ffaSHans Petter Selasky 	const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf;
122d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
123d6b92ffaSHans Petter Selasky 	osmv_txn_ctx_t *p_txn = NULL;
124d6b92ffaSHans Petter Selasky 	osm_log_t *p_log = p_bo->p_vendor->p_log;
125d6b92ffaSHans Petter Selasky 
126d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
127d6b92ffaSHans Petter Selasky 
128d6b92ffaSHans Petter Selasky 	CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr);
129d6b92ffaSHans Petter Selasky 
130d6b92ffaSHans Petter Selasky 	osmv_txn_lock(p_bo);
131d6b92ffaSHans Petter Selasky 
132d6b92ffaSHans Petter Selasky 	if (TRUE == p_bo->is_closing) {
133d6b92ffaSHans Petter Selasky 
134d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
135d6b92ffaSHans Petter Selasky 			"The bind handle %p is being closed. "
136d6b92ffaSHans Petter Selasky 			"The MAD will not be dispatched.\n", p_bo);
137d6b92ffaSHans Petter Selasky 
138d6b92ffaSHans Petter Selasky 		ret = IB_INTERRUPTED;
139d6b92ffaSHans Petter Selasky 		goto dispatch_mad_done;
140d6b92ffaSHans Petter Selasky 	}
141d6b92ffaSHans Petter Selasky 
142d6b92ffaSHans Petter Selasky 	/*
143d6b92ffaSHans Petter Selasky 	   Add call for packet drop randomizer.
144d6b92ffaSHans Petter Selasky 	   This is a testing feature. If run_randomizer flag is set to TRUE,
145d6b92ffaSHans Petter Selasky 	   the randomizer will be called, and randomally will drop
146d6b92ffaSHans Petter Selasky 	   a packet. This is used for simulating unstable fabric.
147d6b92ffaSHans Petter Selasky 	 */
148d6b92ffaSHans Petter Selasky 	if (p_bo->p_vendor->run_randomizer == TRUE) {
149d6b92ffaSHans Petter Selasky 		/* Try the randomizer */
150d6b92ffaSHans Petter Selasky 		if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log,
151d6b92ffaSHans Petter Selasky 						p_bo->p_vendor->
152d6b92ffaSHans Petter Selasky 						p_pkt_randomizer,
153d6b92ffaSHans Petter Selasky 						p_mad) == TRUE) {
154d6b92ffaSHans Petter Selasky 			osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
155d6b92ffaSHans Petter Selasky 				"The MAD will not be dispatched.\n");
156d6b92ffaSHans Petter Selasky 			goto dispatch_mad_done;
157d6b92ffaSHans Petter Selasky 		}
158d6b92ffaSHans Petter Selasky 	}
159d6b92ffaSHans Petter Selasky 
160d6b92ffaSHans Petter Selasky 	switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) {
161d6b92ffaSHans Petter Selasky 
162d6b92ffaSHans Petter Selasky 	case OSMV_ROUTE_DROP:
163d6b92ffaSHans Petter Selasky 		break;		/* Do nothing */
164d6b92ffaSHans Petter Selasky 
165d6b92ffaSHans Petter Selasky 	case OSMV_ROUTE_SIMPLE:
166d6b92ffaSHans Petter Selasky 		__osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr);
167d6b92ffaSHans Petter Selasky 		break;
168d6b92ffaSHans Petter Selasky 
169d6b92ffaSHans Petter Selasky 	case OSMV_ROUTE_RMPP:
170d6b92ffaSHans Petter Selasky 		__osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr);
171d6b92ffaSHans Petter Selasky 		break;
172d6b92ffaSHans Petter Selasky 
173d6b92ffaSHans Petter Selasky 	default:
174d6b92ffaSHans Petter Selasky 		CL_ASSERT(FALSE);
175d6b92ffaSHans Petter Selasky 	}
176d6b92ffaSHans Petter Selasky 
177d6b92ffaSHans Petter Selasky dispatch_mad_done:
178d6b92ffaSHans Petter Selasky 	osmv_txn_unlock(p_bo);
179d6b92ffaSHans Petter Selasky 
180d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
181d6b92ffaSHans Petter Selasky 	return ret;
182d6b92ffaSHans Petter Selasky }
183d6b92ffaSHans Petter Selasky 
184d6b92ffaSHans Petter Selasky /*
185d6b92ffaSHans Petter Selasky  *  NAME            __osmv_dispatch_route()
186d6b92ffaSHans Petter Selasky  *
187d6b92ffaSHans Petter Selasky  *  DESCRIPTION     Decide which way to handle the received MAD: simple txn/RMPP/drop
188d6b92ffaSHans Petter Selasky  */
189d6b92ffaSHans Petter Selasky 
190d6b92ffaSHans Petter Selasky static osmv_disp_route_t
__osmv_dispatch_route(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_mad,OUT osmv_txn_ctx_t ** pp_txn)191d6b92ffaSHans Petter Selasky __osmv_dispatch_route(IN osm_bind_handle_t h_bind,
192d6b92ffaSHans Petter Selasky 		      IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn)
193d6b92ffaSHans Petter Selasky {
194d6b92ffaSHans Petter Selasky 	ib_api_status_t ret;
195d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
196d6b92ffaSHans Petter Selasky 	boolean_t is_resp = ib_mad_is_response(p_mad);
197d6b92ffaSHans Petter Selasky 	boolean_t is_txn;
198d6b92ffaSHans Petter Selasky 	uint64_t key = cl_ntoh64(p_mad->trans_id);
199d6b92ffaSHans Petter Selasky 
200d6b92ffaSHans Petter Selasky 	CL_ASSERT(NULL != pp_txn);
201d6b92ffaSHans Petter Selasky 
202d6b92ffaSHans Petter Selasky 	ret = osmv_txn_lookup(h_bind, key, pp_txn);
203d6b92ffaSHans Petter Selasky 	is_txn = (IB_SUCCESS == ret);
204d6b92ffaSHans Petter Selasky 
205d6b92ffaSHans Petter Selasky 	if (FALSE == is_txn && TRUE == is_resp) {
206d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
207d6b92ffaSHans Petter Selasky 			"Received a response to a non-started/aged-out transaction (tid=0x%" PRIx64 "). "
208d6b92ffaSHans Petter Selasky 			"Dropping the MAD.\n", key);
209d6b92ffaSHans Petter Selasky 		return OSMV_ROUTE_DROP;
210d6b92ffaSHans Petter Selasky 	}
211d6b92ffaSHans Petter Selasky 
212d6b92ffaSHans Petter Selasky 	if (TRUE == osmv_mad_is_rmpp(p_mad)) {
213d6b92ffaSHans Petter Selasky 		/* An RMPP transaction. The filtering is more delicate there */
214d6b92ffaSHans Petter Selasky 		return OSMV_ROUTE_RMPP;
215d6b92ffaSHans Petter Selasky 	}
216d6b92ffaSHans Petter Selasky 
217d6b92ffaSHans Petter Selasky 	if (TRUE == is_txn && FALSE == is_resp) {
218d6b92ffaSHans Petter Selasky 		/* Does this MAD try to start a transaction with duplicate tid? */
219d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
220d6b92ffaSHans Petter Selasky 			"Duplicate TID 0x%" PRIx64 " received (not a response). "
221d6b92ffaSHans Petter Selasky 			"Dropping the MAD.\n", key);
222d6b92ffaSHans Petter Selasky 
223d6b92ffaSHans Petter Selasky 		return OSMV_ROUTE_DROP;
224d6b92ffaSHans Petter Selasky 	}
225d6b92ffaSHans Petter Selasky 
226d6b92ffaSHans Petter Selasky 	return OSMV_ROUTE_SIMPLE;
227d6b92ffaSHans Petter Selasky }
228d6b92ffaSHans Petter Selasky 
229d6b92ffaSHans Petter Selasky /*
230d6b92ffaSHans Petter Selasky  *  NAME            __osmv_dispatch_simple_mad()
231d6b92ffaSHans Petter Selasky  *
232d6b92ffaSHans Petter Selasky  *  DESCRIPTION     Handle a MAD that is part of non-RMPP transfer
233d6b92ffaSHans Petter Selasky  */
234d6b92ffaSHans Petter Selasky 
235d6b92ffaSHans Petter Selasky static void
__osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_mad,IN osmv_txn_ctx_t * p_txn,IN const osm_mad_addr_t * p_mad_addr)236d6b92ffaSHans Petter Selasky __osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind,
237d6b92ffaSHans Petter Selasky 			   IN const ib_mad_t * p_mad,
238d6b92ffaSHans Petter Selasky 			   IN osmv_txn_ctx_t * p_txn,
239d6b92ffaSHans Petter Selasky 			   IN const osm_mad_addr_t * p_mad_addr)
240d6b92ffaSHans Petter Selasky {
241d6b92ffaSHans Petter Selasky 	osm_madw_t *p_madw;
242d6b92ffaSHans Petter Selasky 	ib_mad_t *p_mad_buf;
243d6b92ffaSHans Petter Selasky 	osm_madw_t *p_req_madw = NULL;
244d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
245d6b92ffaSHans Petter Selasky 
246d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
247d6b92ffaSHans Petter Selasky 
248d6b92ffaSHans Petter Selasky 	/* Build the MAD wrapper to be returned to the user.
249d6b92ffaSHans Petter Selasky 	 * The actual storage for the MAD is allocated there.
250d6b92ffaSHans Petter Selasky 	 */
251d6b92ffaSHans Petter Selasky 	p_madw =
252d6b92ffaSHans Petter Selasky 	    osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE,
253d6b92ffaSHans Petter Selasky 			     p_mad_addr);
254d6b92ffaSHans Petter Selasky 
255d6b92ffaSHans Petter Selasky 	if (NULL == p_madw) {
256d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
257d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_simple_mad: ERR 6501: "
258d6b92ffaSHans Petter Selasky 			"Out Of Memory - could not allocate a buffer of size %d\n",
259d6b92ffaSHans Petter Selasky 			MAD_BLOCK_SIZE);
260d6b92ffaSHans Petter Selasky 
261d6b92ffaSHans Petter Selasky 		goto dispatch_simple_mad_done;
262d6b92ffaSHans Petter Selasky 	}
263d6b92ffaSHans Petter Selasky 
264d6b92ffaSHans Petter Selasky 	p_mad_buf = osm_madw_get_mad_ptr(p_madw);
265d6b92ffaSHans Petter Selasky 	/* Copy the payload to the MAD buffer */
266d6b92ffaSHans Petter Selasky 	memcpy((void *)p_mad_buf, (void *)p_mad, MAD_BLOCK_SIZE);
267d6b92ffaSHans Petter Selasky 
268d6b92ffaSHans Petter Selasky 	if (NULL != p_txn) {
269d6b92ffaSHans Petter Selasky 		/* This is a RESPONSE MAD. Pair it with the REQUEST MAD, pass upstream */
270d6b92ffaSHans Petter Selasky 		p_req_madw = p_txn->p_madw;
271d6b92ffaSHans Petter Selasky 		CL_ASSERT(NULL != p_req_madw);
272d6b92ffaSHans Petter Selasky 
273d6b92ffaSHans Petter Selasky 		p_mad_buf->trans_id = cl_hton64(osmv_txn_get_tid(p_txn));
274d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
275d6b92ffaSHans Petter Selasky 			"Restoring the original TID to 0x%" PRIx64 "\n",
276d6b92ffaSHans Petter Selasky 			cl_ntoh64(p_mad_buf->trans_id));
277d6b92ffaSHans Petter Selasky 
278d6b92ffaSHans Petter Selasky 		/* Reply matched, transaction complete */
279d6b92ffaSHans Petter Selasky 		osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE);
280d6b92ffaSHans Petter Selasky 	} else {
281d6b92ffaSHans Petter Selasky 		/* This is a REQUEST  MAD. Don't create a context, pass upstream */
282d6b92ffaSHans Petter Selasky 	}
283d6b92ffaSHans Petter Selasky 
284d6b92ffaSHans Petter Selasky 	/* Do the job ! */
285d6b92ffaSHans Petter Selasky 	p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw);
286d6b92ffaSHans Petter Selasky 
287d6b92ffaSHans Petter Selasky dispatch_simple_mad_done:
288d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
289d6b92ffaSHans Petter Selasky }
290d6b92ffaSHans Petter Selasky 
291d6b92ffaSHans Petter Selasky /*
292d6b92ffaSHans Petter Selasky  *  NAME            __osmv_dispatch_rmpp_mad()
293d6b92ffaSHans Petter Selasky  *
294d6b92ffaSHans Petter Selasky  *  DESCRIPTION     Handle a MAD that is part of RMPP transfer
295d6b92ffaSHans Petter Selasky  */
296d6b92ffaSHans Petter Selasky 
297d6b92ffaSHans Petter Selasky static void
__osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_mad,IN osmv_txn_ctx_t * p_txn,IN const osm_mad_addr_t * p_mad_addr)298d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind,
299d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
300d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
301d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr)
302d6b92ffaSHans Petter Selasky {
303d6b92ffaSHans Petter Selasky 	ib_api_status_t status = IB_SUCCESS;
304d6b92ffaSHans Petter Selasky 	uint64_t key = cl_ntoh64(p_mad->trans_id);
305d6b92ffaSHans Petter Selasky 	boolean_t is_init_by_peer = FALSE;
306d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
307d6b92ffaSHans Petter Selasky 	osm_madw_t *p_madw;
308d6b92ffaSHans Petter Selasky 
309d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
310d6b92ffaSHans Petter Selasky 
311d6b92ffaSHans Petter Selasky 	if (NULL == p_txn) {
312d6b92ffaSHans Petter Selasky 		if (FALSE == osmv_rmpp_is_data(p_mad)
313d6b92ffaSHans Petter Selasky 		    || FALSE == osmv_rmpp_is_first(p_mad)) {
314d6b92ffaSHans Petter Selasky 			osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
315d6b92ffaSHans Petter Selasky 				"The MAD does not match any transaction "
316d6b92ffaSHans Petter Selasky 				"and does not start a sender-initiated RMPP transfer.\n");
317d6b92ffaSHans Petter Selasky 			goto dispatch_rmpp_mad_done;
318d6b92ffaSHans Petter Selasky 		}
319d6b92ffaSHans Petter Selasky 
320d6b92ffaSHans Petter Selasky 		/* IB Spec 13.6.2.2. This is a Sender Initiated Transfer.
321d6b92ffaSHans Petter Selasky 		   My peer is the requester and RMPP Sender. I am the RMPP Receiver.
322d6b92ffaSHans Petter Selasky 		 */
323d6b92ffaSHans Petter Selasky 		status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn);
324d6b92ffaSHans Petter Selasky 		if (IB_SUCCESS != status) {
325d6b92ffaSHans Petter Selasky 			goto dispatch_rmpp_mad_done;
326d6b92ffaSHans Petter Selasky 		}
327d6b92ffaSHans Petter Selasky 
328d6b92ffaSHans Petter Selasky 		is_init_by_peer = TRUE;
329d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
330d6b92ffaSHans Petter Selasky 			"A new sender-initiated transfer (TID=0x%" PRIx64 ") started\n",
331d6b92ffaSHans Petter Selasky 			key);
332d6b92ffaSHans Petter Selasky 	}
333d6b92ffaSHans Petter Selasky 
334d6b92ffaSHans Petter Selasky 	if (OSMV_TXN_RMPP_NONE == osmv_txn_get_rmpp_state(p_txn)) {
335d6b92ffaSHans Petter Selasky 		/* Case 1: Fall through from above.
336d6b92ffaSHans Petter Selasky 		 * Case 2: When the transaction was initiated by me
337d6b92ffaSHans Petter Selasky 		 *         (a single request MAD), there was an uncertainty
338d6b92ffaSHans Petter Selasky 		 *         whether the reply will be RMPP. Now it's resolved,
339d6b92ffaSHans Petter Selasky 		 *         since the reply is RMPP!
340d6b92ffaSHans Petter Selasky 		 */
341d6b92ffaSHans Petter Selasky 		status =
342d6b92ffaSHans Petter Selasky 		    osmv_txn_init_rmpp_receiver(h_bind, p_txn, is_init_by_peer);
343d6b92ffaSHans Petter Selasky 		if (IB_SUCCESS != status) {
344d6b92ffaSHans Petter Selasky 			goto dispatch_rmpp_mad_done;
345d6b92ffaSHans Petter Selasky 		}
346d6b92ffaSHans Petter Selasky 	}
347d6b92ffaSHans Petter Selasky 
348d6b92ffaSHans Petter Selasky 	switch (osmv_txn_get_rmpp_state(p_txn)) {
349d6b92ffaSHans Petter Selasky 
350d6b92ffaSHans Petter Selasky 	case OSMV_TXN_RMPP_RECEIVER:
351d6b92ffaSHans Petter Selasky 		status =
352d6b92ffaSHans Petter Selasky 		    __osmv_dispatch_rmpp_rcv(h_bind, p_mad, p_txn, p_mad_addr);
353d6b92ffaSHans Petter Selasky 		if (IB_SUCCESS != status) {
354d6b92ffaSHans Petter Selasky 			if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) {
355d6b92ffaSHans Petter Selasky 				/* This is a requester, still waiting for the reply. Apply the callback */
356d6b92ffaSHans Petter Selasky 				/* update the status of the p_madw */
357d6b92ffaSHans Petter Selasky 				p_madw = osmv_txn_get_madw(p_txn);
358d6b92ffaSHans Petter Selasky 				p_madw->status = status;
359d6b92ffaSHans Petter Selasky 				p_bo->send_err_cb(p_bo->cb_context, p_madw);
360d6b92ffaSHans Petter Selasky 			}
361d6b92ffaSHans Petter Selasky 
362d6b92ffaSHans Petter Selasky 			/* ABORT/STOP/LOCAL ERROR */
363d6b92ffaSHans Petter Selasky 			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE);
364d6b92ffaSHans Petter Selasky 		}
365d6b92ffaSHans Petter Selasky 		break;
366d6b92ffaSHans Petter Selasky 
367d6b92ffaSHans Petter Selasky 	case OSMV_TXN_RMPP_SENDER:
368d6b92ffaSHans Petter Selasky 		__osmv_dispatch_rmpp_snd(h_bind, p_mad, p_txn, p_mad_addr);
369d6b92ffaSHans Petter Selasky 		/* If an error happens here, it's the sender thread to cleanup the txn */
370d6b92ffaSHans Petter Selasky 		break;
371d6b92ffaSHans Petter Selasky 
372d6b92ffaSHans Petter Selasky 	default:
373d6b92ffaSHans Petter Selasky 		CL_ASSERT(FALSE);
374d6b92ffaSHans Petter Selasky 	}
375d6b92ffaSHans Petter Selasky 
376d6b92ffaSHans Petter Selasky dispatch_rmpp_mad_done:
377d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
378d6b92ffaSHans Petter Selasky }
379d6b92ffaSHans Petter Selasky 
380d6b92ffaSHans Petter Selasky /*
381d6b92ffaSHans Petter Selasky  *  NAME            __osmv_dispatch_rmpp_snd()
382d6b92ffaSHans Petter Selasky  *
383d6b92ffaSHans Petter Selasky  *  DESCRIPTION     MAD handling by an RMPP sender (ACK/ABORT/STOP)
384d6b92ffaSHans Petter Selasky  */
385d6b92ffaSHans Petter Selasky 
386d6b92ffaSHans Petter Selasky static void
__osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_mad,IN osmv_txn_ctx_t * p_txn,IN const osm_mad_addr_t * p_mad_addr)387d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind,
388d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
389d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
390d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr)
391d6b92ffaSHans Petter Selasky {
392d6b92ffaSHans Petter Selasky 	osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
393d6b92ffaSHans Petter Selasky 
394d6b92ffaSHans Petter Selasky 	uint32_t old_wl = p_send_ctx->window_last;
395d6b92ffaSHans Petter Selasky 	uint32_t total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx);
396d6b92ffaSHans Petter Selasky 	uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num);
397d6b92ffaSHans Petter Selasky 	uint32_t new_wl = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->paylen_newwin);
398d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
399d6b92ffaSHans Petter Selasky 
400d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
401d6b92ffaSHans Petter Selasky 
402d6b92ffaSHans Petter Selasky 	if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) {
403d6b92ffaSHans Petter Selasky 
404d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
405d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_snd: ERR 6502: "
406d6b92ffaSHans Petter Selasky 			"The remote side sent an ABORT/STOP indication.\n");
407d6b92ffaSHans Petter Selasky 		osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
408d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_snd_done;
409d6b92ffaSHans Petter Selasky 	}
410d6b92ffaSHans Petter Selasky 
411d6b92ffaSHans Petter Selasky 	if (FALSE == osmv_rmpp_is_ack(p_mad)) {
412d6b92ffaSHans Petter Selasky 
413d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
414d6b92ffaSHans Petter Selasky 			"Not supposed to receive DATA packets --> dropping the MAD\n");
415d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_snd_done;
416d6b92ffaSHans Petter Selasky 	}
417d6b92ffaSHans Petter Selasky 
418d6b92ffaSHans Petter Selasky 	/* Continue processing the ACK */
419d6b92ffaSHans Petter Selasky 	if (seg_num > old_wl) {
420d6b92ffaSHans Petter Selasky 
421d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
422d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_snd: ERR 6503: "
423d6b92ffaSHans Petter Selasky 			"ACK received for a non-sent segment %d\n", seg_num);
424d6b92ffaSHans Petter Selasky 
425d6b92ffaSHans Petter Selasky 		osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
426d6b92ffaSHans Petter Selasky 				   IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B);
427d6b92ffaSHans Petter Selasky 
428d6b92ffaSHans Petter Selasky 		osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
429d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_snd_done;
430d6b92ffaSHans Petter Selasky 	}
431d6b92ffaSHans Petter Selasky 
432d6b92ffaSHans Petter Selasky 	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
433d6b92ffaSHans Petter Selasky 		"__osmv_dispatch_rmpp_snd: "
434d6b92ffaSHans Petter Selasky 		"New WL = %u Old WL = %u Total Segs = %u\n",
435d6b92ffaSHans Petter Selasky 		new_wl, old_wl, total_segs);
436d6b92ffaSHans Petter Selasky 
437d6b92ffaSHans Petter Selasky 	if (new_wl < old_wl) {
438d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
439d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_snd: ERR 6508: "
440d6b92ffaSHans Petter Selasky 			"The receiver requests a smaller WL (%d) than before (%d)\n",
441d6b92ffaSHans Petter Selasky 			new_wl, old_wl);
442d6b92ffaSHans Petter Selasky 
443d6b92ffaSHans Petter Selasky 		osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
444d6b92ffaSHans Petter Selasky 				   IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S);
445d6b92ffaSHans Petter Selasky 
446d6b92ffaSHans Petter Selasky 		osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
447d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_snd_done;
448d6b92ffaSHans Petter Selasky 	}
449d6b92ffaSHans Petter Selasky 
450d6b92ffaSHans Petter Selasky 	/* Update the sender's window, and optionally wake up the sender thread
451d6b92ffaSHans Petter Selasky 	 * Note! A single ACK can acknowledge a whole range of segments: [WF..SEG_NUM]
452d6b92ffaSHans Petter Selasky 	 */
453d6b92ffaSHans Petter Selasky 	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
454d6b92ffaSHans Petter Selasky 		"ACK for seg_num #%d accepted.\n", seg_num);
455d6b92ffaSHans Petter Selasky 
456d6b92ffaSHans Petter Selasky 	if (seg_num == old_wl) {
457d6b92ffaSHans Petter Selasky 
458d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
459d6b92ffaSHans Petter Selasky 			"The send window [%d:%d] is totally acknowledged.\n",
460d6b92ffaSHans Petter Selasky 			p_send_ctx->window_first, old_wl);
461d6b92ffaSHans Petter Selasky 
462d6b92ffaSHans Petter Selasky 		p_send_ctx->window_first = seg_num + 1;
463d6b92ffaSHans Petter Selasky 		p_send_ctx->window_last =
464d6b92ffaSHans Petter Selasky 		    (new_wl < total_segs) ? new_wl : total_segs;
465d6b92ffaSHans Petter Selasky 
466d6b92ffaSHans Petter Selasky 		/* Remove the response timeout event for the window */
467d6b92ffaSHans Petter Selasky 		osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn));
468d6b92ffaSHans Petter Selasky 
469d6b92ffaSHans Petter Selasky 		/* Wake up the sending thread */
470d6b92ffaSHans Petter Selasky 		cl_event_signal(&p_send_ctx->event);
471d6b92ffaSHans Petter Selasky 	}
472d6b92ffaSHans Petter Selasky 
473d6b92ffaSHans Petter Selasky dispatch_rmpp_snd_done:
474d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
475d6b92ffaSHans Petter Selasky }
476d6b92ffaSHans Petter Selasky 
477d6b92ffaSHans Petter Selasky /*
478d6b92ffaSHans Petter Selasky  *  NAME           __osmv_dispatch_rmpp_rcv()
479d6b92ffaSHans Petter Selasky  *
480d6b92ffaSHans Petter Selasky  *  DESCRIPTION    MAD handling by an RMPP receiver (DATA/ABORT/STOP)
481d6b92ffaSHans Petter Selasky  */
482d6b92ffaSHans Petter Selasky 
483d6b92ffaSHans Petter Selasky static ib_api_status_t
__osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_mad,IN osmv_txn_ctx_t * p_txn,IN const osm_mad_addr_t * p_mad_addr)484d6b92ffaSHans Petter Selasky __osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind,
485d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_mad,
486d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
487d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr)
488d6b92ffaSHans Petter Selasky {
489d6b92ffaSHans Petter Selasky 	ib_api_status_t status = IB_SUCCESS;
490d6b92ffaSHans Petter Selasky 	osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
491d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
492d6b92ffaSHans Petter Selasky 	boolean_t is_last1 = FALSE, is_last2 = FALSE;
493d6b92ffaSHans Petter Selasky 	osm_madw_t *p_new_madw = NULL, *p_req_madw = NULL;
494d6b92ffaSHans Petter Selasky 	ib_mad_t *p_mad_buf;
495d6b92ffaSHans Petter Selasky 	uint32_t size = 0;
496d6b92ffaSHans Petter Selasky 	uint64_t key = osmv_txn_get_key(p_txn);
497d6b92ffaSHans Petter Selasky 	uint64_t tid = osmv_txn_get_tid(p_txn);
498d6b92ffaSHans Petter Selasky 
499d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
500d6b92ffaSHans Petter Selasky 
501d6b92ffaSHans Petter Selasky 	if (TRUE == osmv_rmpp_is_ack(p_mad)) {
502d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
503d6b92ffaSHans Petter Selasky 			"Not supposed to receive ACK's --> dropping the MAD\n");
504d6b92ffaSHans Petter Selasky 
505d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
506d6b92ffaSHans Petter Selasky 	}
507d6b92ffaSHans Petter Selasky 
508d6b92ffaSHans Petter Selasky 	if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) {
509d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
510d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_rcv: ERR 6504: "
511d6b92ffaSHans Petter Selasky 			"The Remote Side stopped sending\n");
512d6b92ffaSHans Petter Selasky 
513d6b92ffaSHans Petter Selasky 		status = IB_REMOTE_ERROR;
514d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
515d6b92ffaSHans Petter Selasky 	}
516d6b92ffaSHans Petter Selasky 
517d6b92ffaSHans Petter Selasky 	status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad);
518d6b92ffaSHans Petter Selasky 	switch (status) {
519d6b92ffaSHans Petter Selasky 
520d6b92ffaSHans Petter Selasky 	case IB_SUCCESS:
521d6b92ffaSHans Petter Selasky 
522d6b92ffaSHans Petter Selasky 		/* Check wheter this is the legal last MAD */
523d6b92ffaSHans Petter Selasky 		/* Criteria #1: the received MAD is marked last */
524d6b92ffaSHans Petter Selasky 		is_last1 = osmv_rmpp_is_last(p_mad);
525d6b92ffaSHans Petter Selasky 
526d6b92ffaSHans Petter Selasky 		/* Criteria #2: the total accumulated length hits the advertised one */
527d6b92ffaSHans Petter Selasky 		is_last2 = is_last1;
528d6b92ffaSHans Petter Selasky 
529d6b92ffaSHans Petter Selasky 		size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx);
530d6b92ffaSHans Petter Selasky 		if (size > 0) {
531d6b92ffaSHans Petter Selasky 			is_last2 =
532d6b92ffaSHans Petter Selasky 			    (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >=
533d6b92ffaSHans Petter Selasky 			     size);
534d6b92ffaSHans Petter Selasky 		}
535d6b92ffaSHans Petter Selasky 
536d6b92ffaSHans Petter Selasky 		if (is_last1 != is_last2) {
537d6b92ffaSHans Petter Selasky 
538d6b92ffaSHans Petter Selasky 			osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
539d6b92ffaSHans Petter Selasky 					   IB_RMPP_TYPE_ABORT,
540d6b92ffaSHans Petter Selasky 					   IB_RMPP_STATUS_BAD_LEN);
541d6b92ffaSHans Petter Selasky 
542d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
543d6b92ffaSHans Petter Selasky 			goto dispatch_rmpp_rcv_done;
544d6b92ffaSHans Petter Selasky 		}
545d6b92ffaSHans Petter Selasky 
546d6b92ffaSHans Petter Selasky 		/* TBD Consider an optimization - sending an ACK
547d6b92ffaSHans Petter Selasky 		 * only for the last segment in the window
548d6b92ffaSHans Petter Selasky 		 */
549d6b92ffaSHans Petter Selasky 		__osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr);
550d6b92ffaSHans Petter Selasky 		break;
551d6b92ffaSHans Petter Selasky 
552d6b92ffaSHans Petter Selasky 	case IB_INSUFFICIENT_RESOURCES:
553d6b92ffaSHans Petter Selasky 		/* An out-of-order segment received. Send the ACK anyway */
554d6b92ffaSHans Petter Selasky 		__osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr);
555d6b92ffaSHans Petter Selasky 		status = IB_SUCCESS;
556d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
557d6b92ffaSHans Petter Selasky 
558d6b92ffaSHans Petter Selasky 	case IB_INSUFFICIENT_MEMORY:
559d6b92ffaSHans Petter Selasky 		osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
560d6b92ffaSHans Petter Selasky 				   IB_RMPP_TYPE_STOP, IB_RMPP_STATUS_RESX);
561d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
562d6b92ffaSHans Petter Selasky 
563d6b92ffaSHans Petter Selasky 	default:
564d6b92ffaSHans Petter Selasky 		/* Illegal return code */
565d6b92ffaSHans Petter Selasky 		CL_ASSERT(FALSE);
566d6b92ffaSHans Petter Selasky 	}
567d6b92ffaSHans Petter Selasky 
568d6b92ffaSHans Petter Selasky 	if (TRUE != is_last1) {
569d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
570d6b92ffaSHans Petter Selasky 			"RMPP MADW assembly continues, TID=0x%" PRIx64 "\n", tid);
571d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
572d6b92ffaSHans Petter Selasky 	}
573d6b92ffaSHans Petter Selasky 
574d6b92ffaSHans Petter Selasky 	/* This is the last packet. */
575d6b92ffaSHans Petter Selasky 	if (0 == size) {
576d6b92ffaSHans Petter Selasky 		/* The total size was not advertised in the first packet */
577d6b92ffaSHans Petter Selasky 		size = osmv_rmpp_recv_ctx_get_byte_num_from_last(p_recv_ctx);
578d6b92ffaSHans Petter Selasky 	}
579d6b92ffaSHans Petter Selasky 
580d6b92ffaSHans Petter Selasky 	/*
581d6b92ffaSHans Petter Selasky 	   NOTE: the received mad might not be >= 256 bytes.
582d6b92ffaSHans Petter Selasky 	   some MADs might contain several SA records but still be
583d6b92ffaSHans Petter Selasky 	   less then a full MAD.
584d6b92ffaSHans Petter Selasky 	   We have to use RMPP to send them over since on a regular
585d6b92ffaSHans Petter Selasky 	   "simple" MAD there is no way to know how many records were sent
586d6b92ffaSHans Petter Selasky 	 */
587d6b92ffaSHans Petter Selasky 
588d6b92ffaSHans Petter Selasky 	/* Build the MAD wrapper to be returned to the user.
589d6b92ffaSHans Petter Selasky 	 * The actual storage for the MAD is allocated there.
590d6b92ffaSHans Petter Selasky 	 */
591d6b92ffaSHans Petter Selasky 	p_new_madw =
592d6b92ffaSHans Petter Selasky 	    osm_mad_pool_get(p_bo->p_osm_pool, h_bind, size, p_mad_addr);
593d6b92ffaSHans Petter Selasky 	if (NULL == p_new_madw) {
594d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
595d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_rcv: ERR 6506: "
596d6b92ffaSHans Petter Selasky 			"Out Of Memory - could not allocate %d bytes for the MADW\n",
597d6b92ffaSHans Petter Selasky 			size);
598d6b92ffaSHans Petter Selasky 
599d6b92ffaSHans Petter Selasky 		status = IB_INSUFFICIENT_MEMORY;
600d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;
601d6b92ffaSHans Petter Selasky 	}
602d6b92ffaSHans Petter Selasky 
603d6b92ffaSHans Petter Selasky 	p_req_madw = osmv_txn_get_madw(p_txn);
604d6b92ffaSHans Petter Selasky 	p_mad_buf = osm_madw_get_mad_ptr(p_new_madw);
605d6b92ffaSHans Petter Selasky 	status = osmv_rmpp_recv_ctx_reassemble_arbt_mad(p_recv_ctx, size,
606d6b92ffaSHans Petter Selasky 							(uint8_t *) p_mad_buf);
607d6b92ffaSHans Petter Selasky 	if (IB_SUCCESS != status) {
608d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
609d6b92ffaSHans Petter Selasky 			"__osmv_dispatch_rmpp_rcv: ERR 6507: "
610d6b92ffaSHans Petter Selasky 			"Internal error - could not reassemble the result MAD\n");
611d6b92ffaSHans Petter Selasky 		goto dispatch_rmpp_rcv_done;	/* What can happen here? */
612d6b92ffaSHans Petter Selasky 	}
613d6b92ffaSHans Petter Selasky 
614d6b92ffaSHans Petter Selasky 	/* The MAD is assembled, we are about to apply the callback.
615d6b92ffaSHans Petter Selasky 	 * Delete the transaction context, unless the transaction is double sided */
616d6b92ffaSHans Petter Selasky 	if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)
617d6b92ffaSHans Petter Selasky 	    || FALSE == osmv_mad_is_multi_resp(p_mad)) {
618d6b92ffaSHans Petter Selasky 
619d6b92ffaSHans Petter Selasky 		osmv_txn_done(h_bind, key, FALSE);
620d6b92ffaSHans Petter Selasky 	}
621d6b92ffaSHans Petter Selasky 
622d6b92ffaSHans Petter Selasky 	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
623d6b92ffaSHans Petter Selasky 		"RMPP MADW %p assembly complete, TID=0x%" PRIx64 "\n", p_new_madw,
624d6b92ffaSHans Petter Selasky 		tid);
625d6b92ffaSHans Petter Selasky 
626d6b92ffaSHans Petter Selasky 	p_mad_buf->trans_id = cl_hton64(tid);
627d6b92ffaSHans Petter Selasky 	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
628d6b92ffaSHans Petter Selasky 		"Restoring the original TID to 0x%" PRIx64 "\n",
629d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_mad_buf->trans_id));
630d6b92ffaSHans Petter Selasky 
631d6b92ffaSHans Petter Selasky 	/* Finally, do the job! */
632d6b92ffaSHans Petter Selasky 	p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw);
633d6b92ffaSHans Petter Selasky 
634d6b92ffaSHans Petter Selasky dispatch_rmpp_rcv_done:
635d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
636d6b92ffaSHans Petter Selasky 	return status;
637d6b92ffaSHans Petter Selasky }
638d6b92ffaSHans Petter Selasky 
639d6b92ffaSHans Petter Selasky /*
640d6b92ffaSHans Petter Selasky  *  NAME            __osmv_dispatch_accept_seg()
641d6b92ffaSHans Petter Selasky  *
642d6b92ffaSHans Petter Selasky  *  DESCRIPTION     Store a DATA segment at the RMPP receiver side,
643d6b92ffaSHans Petter Selasky  *                  if one is received in order.
644d6b92ffaSHans Petter Selasky  */
645d6b92ffaSHans Petter Selasky 
646d6b92ffaSHans Petter Selasky static ib_api_status_t
__osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind,IN osmv_txn_ctx_t * p_txn,IN const ib_mad_t * p_mad)647d6b92ffaSHans Petter Selasky __osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind,
648d6b92ffaSHans Petter Selasky 			   IN osmv_txn_ctx_t * p_txn, IN const ib_mad_t * p_mad)
649d6b92ffaSHans Petter Selasky {
650d6b92ffaSHans Petter Selasky 	ib_api_status_t ret = IB_SUCCESS;
651d6b92ffaSHans Petter Selasky 	uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num);
652d6b92ffaSHans Petter Selasky 	osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
653d6b92ffaSHans Petter Selasky 	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
654d6b92ffaSHans Petter Selasky 	uint64_t tid = osmv_txn_get_tid(p_txn);
655d6b92ffaSHans Petter Selasky 
656d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
657d6b92ffaSHans Petter Selasky 
658d6b92ffaSHans Petter Selasky 	if (seg_num != p_recv_ctx->expected_seg) {
659d6b92ffaSHans Petter Selasky 		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
660d6b92ffaSHans Petter Selasky 			"TID 0x%" PRIx64 ": can't accept this segment (%d) - "
661d6b92ffaSHans Petter Selasky 			"this is a Go-Back-N implementation\n", tid, seg_num);
662d6b92ffaSHans Petter Selasky 		return IB_INSUFFICIENT_RESOURCES;
663d6b92ffaSHans Petter Selasky 	}
664d6b92ffaSHans Petter Selasky 
665d6b92ffaSHans Petter Selasky 	/* Store the packet's copy in the reassembly list.
666d6b92ffaSHans Petter Selasky 	 * Promote the expected segment counter.
667d6b92ffaSHans Petter Selasky 	 */
668d6b92ffaSHans Petter Selasky 	ret = osmv_rmpp_recv_ctx_store_mad_seg(p_recv_ctx, (uint8_t *) p_mad);
669d6b92ffaSHans Petter Selasky 	if (IB_SUCCESS != ret) {
670d6b92ffaSHans Petter Selasky 		return ret;
671d6b92ffaSHans Petter Selasky 	}
672d6b92ffaSHans Petter Selasky 
673d6b92ffaSHans Petter Selasky 	osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
674d6b92ffaSHans Petter Selasky 		"TID 0x%" PRIx64 ": segment %d accepted\n", tid, seg_num);
675d6b92ffaSHans Petter Selasky 	p_recv_ctx->expected_seg = seg_num + 1;
676d6b92ffaSHans Petter Selasky 
677d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
678d6b92ffaSHans Petter Selasky 	return IB_SUCCESS;
679d6b92ffaSHans Petter Selasky }
680d6b92ffaSHans Petter Selasky 
681d6b92ffaSHans Petter Selasky /*
682d6b92ffaSHans Petter Selasky  *  NAME              __osmv_dispatch_send_ack()
683d6b92ffaSHans Petter Selasky  *
684d6b92ffaSHans Petter Selasky  *  DESCRIPTION
685d6b92ffaSHans Petter Selasky  *
686d6b92ffaSHans Petter Selasky  *  ISSUES
687d6b92ffaSHans Petter Selasky  *    Consider sending the ACK from an async thread
688d6b92ffaSHans Petter Selasky  *    if problems with the receiving side processing arise.
689d6b92ffaSHans Petter Selasky  */
690d6b92ffaSHans Petter Selasky 
691d6b92ffaSHans Petter Selasky static void
__osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind,IN const ib_mad_t * p_req_mad,IN osmv_txn_ctx_t * p_txn,IN const osm_mad_addr_t * p_mad_addr)692d6b92ffaSHans Petter Selasky __osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind,
693d6b92ffaSHans Petter Selasky 			 IN const ib_mad_t * p_req_mad,
694d6b92ffaSHans Petter Selasky 			 IN osmv_txn_ctx_t * p_txn,
695d6b92ffaSHans Petter Selasky 			 IN const osm_mad_addr_t * p_mad_addr)
696d6b92ffaSHans Petter Selasky {
697d6b92ffaSHans Petter Selasky 	osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
698d6b92ffaSHans Petter Selasky 
699d6b92ffaSHans Petter Selasky 	/* ACK the segment # that was accepted */
700d6b92ffaSHans Petter Selasky 	uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_req_mad)->seg_num);
701d6b92ffaSHans Petter Selasky 
702d6b92ffaSHans Petter Selasky 	/* NOTE! The receiver can publish the New Window Last (NWL) value
703d6b92ffaSHans Petter Selasky 	 * that is greater than the total number of segments to be sent.
704d6b92ffaSHans Petter Selasky 	 * It's the sender's responsibility to compute the correct number
705d6b92ffaSHans Petter Selasky 	 * of segments to send in the next burst.
706d6b92ffaSHans Petter Selasky 	 */
707d6b92ffaSHans Petter Selasky 	uint32_t nwl = p_recv_ctx->expected_seg + OSMV_RMPP_RECV_WIN - 1;
708d6b92ffaSHans Petter Selasky 
709d6b92ffaSHans Petter Selasky 	osmv_rmpp_send_ack(h_bind, p_req_mad, seg_num, nwl, p_mad_addr);
710d6b92ffaSHans Petter Selasky }
711