]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sender.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / libvendor / osm_vendor_mlx_sender.c
1 /*
2  * Copyright (c) 2004-2006 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 #if HAVE_CONFIG_H
37 #  include <config.h>
38 #endif                          /* HAVE_CONFIG_H */
39
40 #include <string.h>
41 #include <vendor/osm_vendor_mlx_sender.h>
42 #include <vendor/osm_vendor_mlx_transport.h>
43 #include <vendor/osm_vendor_mlx_svc.h>
44 #include <vendor/osm_pkt_randomizer.h>
45
46 static ib_api_status_t
47 __osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind,
48                          IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num);
49
50 /****d* OSM Vendor/osmv_simple_send_madw
51  * NAME
52  *   osmv_simple_send_madw
53  *
54  * DESCRIPTION
55  *   Send a single MAD (256 bytes).
56  *
57  *   If this MAD requires a response, set the timeout event.
58  *   The function call returns when the MAD's send completion is received.
59  *
60  */
61
62 ib_api_status_t
63 osmv_simple_send_madw(IN osm_bind_handle_t h_bind,
64                       IN osm_madw_t * const p_madw,
65                       IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry)
66 {
67         ib_api_status_t ret;
68         osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
69         osm_mad_addr_t *p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
70         uint8_t mad_buf[MAD_BLOCK_SIZE];
71         ib_mad_t *p_mad = (ib_mad_t *) mad_buf;
72         uint64_t key = 0;
73
74         OSM_LOG_ENTER(p_bo->p_vendor->p_log);
75
76         CL_ASSERT(p_madw->mad_size <= MAD_BLOCK_SIZE);
77
78         memset(p_mad, 0, MAD_BLOCK_SIZE);
79         memcpy(p_mad, osm_madw_get_mad_ptr(p_madw), p_madw->mad_size);
80
81         if (NULL != p_txn) {
82                 /* Push a fake txn id to the MAD */
83                 key = osmv_txn_get_key(p_txn);
84                 p_mad->trans_id = cl_hton64(key);
85         }
86
87         /*
88            Add call for packet drop randomizer.
89            This is a testing feature. If run_randomizer flag is set to TRUE,
90            the randomizer will be called, and randomally will drop
91            a packet. This is used for simulating unstable fabric.
92          */
93         if (p_bo->p_vendor->run_randomizer == TRUE) {
94                 /* Try the randomizer */
95                 if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log,
96                                                 p_bo->p_vendor->
97                                                 p_pkt_randomizer,
98                                                 p_mad) == TRUE) {
99                         osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
100                                 "The MAD will not be sent. \n");
101                         ret = IB_SUCCESS;
102                 } else {
103                         ret =
104                             osmv_transport_mad_send(h_bind, p_mad, p_mad_addr);
105                 }
106         } else {
107                 ret = osmv_transport_mad_send(h_bind, p_mad, p_mad_addr);
108         }
109
110         if ((IB_SUCCESS == ret) && (NULL != p_txn) && (!is_retry)) {
111                 /* Set the timeout for receiving the response MAD */
112                 ret = osmv_txn_set_timeout_ev(h_bind, key,
113                                               p_bo->p_vendor->resp_timeout);
114         }
115
116         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
117         return ret;
118 }
119
120 /***** OSM Vendor/osmv_rmpp_send_madw
121  * NAME
122  *   osmv_rmpp_send_madw
123  *
124  * DESCRIPTION
125  * Send a single message (MAD wrapper of arbitrary length).
126  *      Follow the RMPP semantics
127  *      (segmentation, send window, timeouts etc).
128  *
129  *      The function call returns either when the whole message
130  *      has been acknowledged, or upon error.
131  *
132  *  ASSUMPTIONS
133  *      The RMPP sender context is set up
134  */
135
136 ib_api_status_t
137 osmv_rmpp_send_madw(IN osm_bind_handle_t h_bind,
138                     IN osm_madw_t * const p_madw,
139                     IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds)
140 {
141         ib_api_status_t ret = IB_SUCCESS;
142         uint32_t i, total_segs;
143
144         osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
145         osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
146
147         OSM_LOG_ENTER(p_bo->p_vendor->p_log);
148
149         total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx);
150         CL_ASSERT(total_segs >= 1);
151
152         /* In the double-sided transfer, wait for ACK 0 */
153
154         for (;;) {
155
156                 if (p_send_ctx->window_first > total_segs) {
157
158                         /* Every segment is acknowledged */
159                         break;
160                 }
161
162                 /* Send the next burst. */
163                 for (i = p_send_ctx->window_first; i <= p_send_ctx->window_last;
164                      i++) {
165
166                         /* Send a segment and setup a timeout timer */
167                         ret = __osmv_rmpp_send_segment(h_bind, p_txn, i);
168                         if (IB_SUCCESS != ret) {
169                                 goto send_done;
170                         }
171                 }
172
173                 /* Set the Response Timeout for the ACK on the last DATA segment */
174                 ret = osmv_txn_set_timeout_ev(h_bind, osmv_txn_get_key(p_txn),
175                                               p_bo->p_vendor->resp_timeout);
176                 if (IB_SUCCESS != ret) {
177                         goto send_done;
178                 }
179
180                 /* Going to sleep. Let the others access the transaction DB */
181                 osmv_txn_unlock(p_bo);
182
183                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
184                         "RMPP Sender thread (madw=%p) going to sleep ...\n",
185                         p_madw);
186
187                 /* Await the next event to happen */
188                 cl_event_wait_on(&p_send_ctx->event,
189                                  EVENT_NO_TIMEOUT, TRUE /* interruptible */ );
190
191                 /* Got a signal from the MAD dispatcher/timeout handler */
192                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
193                         "RMPP Sender thread (madw=%p) waking up on a signal ...\n",
194                         p_madw);
195
196                 /* Let's see what changed... Make this atomic - re-acquire the lock. */
197                 osmv_txn_lock(p_bo);
198
199                 if (TRUE == p_bo->is_closing) {
200                         osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
201                                 "osmv_rmpp_send_madw: ERR 6601: "
202                                 "The bind handle %p is being closed. "
203                                 "Stopping the RMPP Send of MADW %p\n",
204                                 h_bind, p_madw);
205
206                         ret = IB_TIMEOUT;
207                         return IB_INTERRUPTED;
208                 }
209
210                 /* STOP? ABORT? TIMEOUT? */
211                 if (IB_SUCCESS != p_send_ctx->status) {
212                         osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
213                                 "osmv_rmpp_send_madw: ERR 6602: "
214                                 "An error (%s) happened during the RMPP send of %p. Bailing out.\n",
215                                 ib_get_err_str(p_send_ctx->status), p_madw);
216                         ret = p_send_ctx->status;
217                         goto send_done;
218                 }
219         }
220
221         if (TRUE == is_rmpp_ds) {
222                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
223                         "Double-sided RMPP - switching to be the receiver.\n");
224
225                 ret = osmv_txn_init_rmpp_receiver(h_bind, p_txn, FALSE
226                                                   /*Send was initiated by me */
227                                                   );
228
229                 if (IB_SUCCESS == ret) {
230                         /* Send ACK on the 0 segment */
231                         ret = __osmv_rmpp_send_segment(h_bind, p_txn, 0);
232                 }
233         }
234
235 send_done:
236         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
237         return ret;
238 }
239
240 /*
241  *  NAME                osmv_rmpp_send_ack
242  *
243  *  DESCRIPTION
244  *
245  */
246
247 ib_api_status_t
248 osmv_rmpp_send_ack(IN osm_bind_handle_t h_bind,
249                    IN const ib_mad_t * p_req_mad,
250                    IN uint32_t seg_num,
251                    IN uint32_t nwl, IN const osm_mad_addr_t * p_mad_addr)
252 {
253         uint8_t resp_mad[MAD_BLOCK_SIZE];
254         ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad;
255
256 #ifdef OSMV_RANDOM_DROP
257         if (TRUE == osmv_random_drop()) {
258                 osm_log(((osmv_bind_obj_t *) h_bind)->p_vendor->p_log,
259                         OSM_LOG_DEBUG,
260                         "Error injection - dropping the RMPP ACK\n");
261                 return IB_SUCCESS;
262         }
263 #endif
264
265         memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE);
266
267         p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method);
268         p_resp_mad->rmpp_type = IB_RMPP_TYPE_ACK;
269         p_resp_mad->seg_num = cl_hton32(seg_num);
270         p_resp_mad->paylen_newwin = cl_hton32(nwl);
271         p_resp_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
272
273         return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr);
274 }
275
276 /*
277  *  NAME            osmv_rmpp_send_nak
278  *
279  *  DESCRIPTION     Send the RMPP ABORT or STOP packet
280  */
281
282 ib_api_status_t
283 osmv_rmpp_send_nak(IN osm_bind_handle_t h_bind,
284                    IN const ib_mad_t * p_req_mad,
285                    IN const osm_mad_addr_t * p_mad_addr,
286                    IN uint8_t nak_type, IN uint8_t status)
287 {
288         uint8_t resp_mad[MAD_BLOCK_SIZE];
289         ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad;
290
291         memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE);
292
293         p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method);
294         p_resp_mad->rmpp_type = nak_type;
295         p_resp_mad->rmpp_status = status;
296
297         return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr);
298 }
299
300 /*
301  *  NAME              __osmv_rmpp_send_segment
302  *
303  *  DESCRIPTION       Build a MAD for a specific segment and send it
304  */
305
306 static ib_api_status_t
307 __osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind,
308                          IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num)
309 {
310         ib_api_status_t ret;
311         osmv_rmpp_send_ctx_t *p_send_ctx;
312         uint8_t mad_buf[MAD_BLOCK_SIZE];
313         ib_mad_t *p_mad = (ib_mad_t *) mad_buf;
314         osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
315         osm_mad_addr_t *p_mad_addr =
316             osm_madw_get_mad_addr_ptr(osmv_txn_get_madw(p_txn));
317         uint32_t timeout = p_bo->p_vendor->resp_timeout;
318         uint64_t key;
319
320         OSM_LOG_ENTER(p_bo->p_vendor->p_log);
321
322 #ifdef OSMV_RANDOM_DROP
323         if (TRUE == osmv_random_drop()) {
324
325                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
326                         "Error injection - simulating the RMPP segment drop\n");
327                 return IB_SUCCESS;
328         }
329 #endif
330
331         p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
332         key = osmv_txn_get_key(p_txn);
333
334         if (0 != seg_num) {
335                 ret =
336                     osmv_rmpp_send_ctx_get_seg(p_send_ctx, seg_num, timeout,
337                                                p_mad);
338                 CL_ASSERT(IB_SUCCESS == ret);
339
340                 /* Put the segment to the wire ! */
341                 p_mad->trans_id = cl_hton64(key);
342
343                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
344                         "Sending RMPP segment #%d, on-wire TID=0x%llX\n",
345                         seg_num, p_mad->trans_id);
346
347                 /*
348                    Add call for packet drop randomizer.
349                    This is a testing feature. If run_randomizer flag is set to TRUE,
350                    the randomizer will be called, and randomally will drop
351                    a packet. This is used for simulating unstable fabric.
352                  */
353                 if (p_bo->p_vendor->run_randomizer == TRUE) {
354                         /* Try the randomizer */
355                         if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log,
356                                                         p_bo->p_vendor->
357                                                         p_pkt_randomizer,
358                                                         p_mad) == TRUE) {
359                                 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
360                                         "The MAD will not be sent. \n");
361                                 ret = IB_SUCCESS;
362                         } else {
363                                 ret =
364                                     osmv_transport_mad_send((osm_bind_handle_t)
365                                                             p_bo, p_mad,
366                                                             p_mad_addr);
367                         }
368                 } else {
369                         ret =
370                             osmv_transport_mad_send((osm_bind_handle_t) p_bo,
371                                                     p_mad, p_mad_addr);
372                 }
373         } else {
374                 /* This is an ACK for double-sided handshake. Give it a special treatment. */
375
376                 /* It doesn't really matter which data to put. Only the header matters. */
377                 ret = osmv_rmpp_send_ctx_get_seg(p_send_ctx, 1, timeout, p_mad);
378                 CL_ASSERT(IB_SUCCESS == ret);
379
380                 p_mad->trans_id = cl_hton64(key);
381                 ret =
382                     osmv_rmpp_send_ack((osm_bind_handle_t) p_bo, p_mad,
383                                        0 /* segnum */ ,
384                                        OSMV_RMPP_RECV_WIN /* NWL */ ,
385                                        p_mad_addr);
386         }
387
388         OSM_LOG_EXIT(p_bo->p_vendor->p_log);
389         return ret;
390 }