1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This file contains the routines to implement the RMPP protocol.
29 */
30
31 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
32
33 extern ibmf_state_t *ibmf_statep;
34 extern int ibmf_trace_level;
35
36 #define IBMF_BUF_PKTS 10
37
38 static void ibmf_i_rmpp_sender_active_flow(ibmf_client_t *clientp,
39 ibmf_qp_handle_t qp_hdl, ibmf_msg_impl_t *msgimplp, uchar_t *mad);
40 static void ibmf_i_rmpp_sender_switch_flow(ibmf_client_t *clientp,
41 ibmf_qp_handle_t qp_hdl, ibmf_msg_impl_t *msgimplp, uchar_t *mad);
42 static void ibmf_i_rmpp_recvr_flow_main(ibmf_client_t *clientp,
43 ibmf_qp_handle_t qp_hdl, ibmf_msg_impl_t *msgimplp, uchar_t *mad);
44 static void ibmf_i_rmpp_recvr_active_flow(ibmf_client_t *clientp,
45 ibmf_qp_handle_t qp_hdl, ibmf_msg_impl_t *msgimplp, uchar_t *mad);
46 static void ibmf_i_rmpp_recvr_term_flow(ibmf_client_t *clientp,
47 ibmf_qp_handle_t qp_hdl, ibmf_msg_impl_t *msgimplp, uchar_t *mad);
48 static boolean_t ibmf_i_is_valid_rmpp_status(ibmf_rmpp_hdr_t *rmpp_hdr);
49
50 /*
51 * ibmf_i_is_rmpp():
52 * Check if the client and QP context supports RMPP transfers
53 */
54 boolean_t
ibmf_i_is_rmpp(ibmf_client_t * clientp,ibmf_qp_handle_t ibmf_qp_handle)55 ibmf_i_is_rmpp(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle)
56 {
57 ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
58 boolean_t is_rmpp;
59
60 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_is_rmpp_start,
61 IBMF_TNF_TRACE, "", "ibmf_i_is_rmpp(): clientp = %p, "
62 "ibmf_qp_handle = 0x%p\n", tnf_opaque, clientp, clientp,
63 tnf_opaque, ibmf_qp_handle, ibmf_qp_handle);
64
65 if ((clientp->ic_reg_flags & IBMF_REG_FLAG_RMPP) == 0) {
66 is_rmpp = B_FALSE;
67 } else if ((ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT) &&
68 (qpp->isq_supports_rmpp == B_FALSE)) {
69 is_rmpp = B_FALSE;
70 } else {
71 is_rmpp = B_TRUE;
72 }
73
74 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_is_rmpp_end,
75 IBMF_TNF_TRACE, "", "ibmf_i_is_rmpp() exit, is_rmpp = %d\n",
76 tnf_uint, is_rmpp, is_rmpp);
77
78 return (is_rmpp);
79 }
80
81 /*
82 * ibmf_i_rmpp_sender_active_flow():
83 * Perform RMPP processing for the sender side transaction.
84 * Refer to figure 178 "RMPP Sender Main Flow Diagram" of
85 * the InfiniBand Architecture Specification Volume 1, Release 1.1
86 */
87 static void
ibmf_i_rmpp_sender_active_flow(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * mad)88 ibmf_i_rmpp_sender_active_flow(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
89 ibmf_msg_impl_t *msgimplp, uchar_t *mad)
90 {
91 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
92 ibmf_rmpp_hdr_t *rmpp_hdr;
93 uint32_t abort_status;
94 int status;
95
96 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
97 ibmf_i_rmpp_sender_active_flow_start, IBMF_TNF_TRACE, "",
98 "ibmf_i_rmpp_sender_active_flow(): clientp = 0x%p, qp_hdl = 0x%p, "
99 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
100 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
101 tnf_opaque, mad, mad);
102
103 /*
104 * RMPP header is located just after the MAD header for SA MADs
105 * If this changes for Vendor MADs, we will need some way for
106 * the client to specify the byte offset of the RMPP header
107 * within the MAD.
108 */
109 rmpp_hdr = (ibmf_rmpp_hdr_t *)(mad + sizeof (ib_mad_hdr_t));
110
111 if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) {
112
113 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
114 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
115 "ibmf_i_rmpp_sender_active_flow(): %s\n", tnf_string, msg,
116 "Data packet received, discarding it");
117
118 /*
119 * According to the IB spec, we discard the packet and resend
120 * packets next_seg->window_last. However, next_seg is equal to
121 * window_last so send_rmpp_window() will just reset the timer.
122 */
123 ibmf_i_send_rmpp_window(msgimplp, IBMF_NO_BLOCK);
124
125 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
126 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
127 "ibmf_i_rmpp_sender_active_flow() exit\n");
128
129 return;
130 }
131
132 if (rmpp_hdr->rmpp_type != IBMF_RMPP_TYPE_ACK) {
133
134 if ((rmpp_hdr->rmpp_type != IBMF_RMPP_TYPE_STOP) &&
135 (rmpp_hdr->rmpp_type != IBMF_RMPP_TYPE_ABORT)) {
136
137 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
138 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
139 "ibmf_i_rmpp_sender_active_flow(): %s\n",
140 tnf_string, msg,
141 "Unrecognized packet received, sending ABORT");
142
143 /* abort with status BadT */
144 status = ibmf_i_send_rmpp(msgimplp,
145 IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_BADT,
146 0, 0, IBMF_NO_BLOCK);
147 if (status != IBMF_SUCCESS) {
148 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
149 ibmf_i_rmpp_sender_active_flow,
150 IBMF_TNF_TRACE, "",
151 "ibmf_i_rmpp_sender_active_flow(): %s\n",
152 tnf_string, msg, "RMPP ABORT send failed");
153 msgimplp->im_trans_state_flags |=
154 IBMF_TRANS_STATE_FLAG_SEND_DONE;
155 }
156
157 mutex_enter(&clientp->ic_kstat_mutex);
158 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
159 mutex_exit(&clientp->ic_kstat_mutex);
160
161 } else {
162
163 abort_status = rmpp_hdr->rmpp_status;
164
165 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
166 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
167 "ibmf_i_rmpp_sender_active_flow(): %s, "
168 "status = %d\n", tnf_string, msg,
169 "STOP or ABORT packet received, terminating",
170 tnf_uint, abort_status, abort_status);
171 }
172
173 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
174 msgimplp->im_trans_state_flags |=
175 IBMF_TRANS_STATE_FLAG_SEND_DONE;
176
177 ibmf_i_set_timer(ibmf_i_err_terminate_timeout, msgimplp,
178 IBMF_RESP_TIMER);
179
180 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
181 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
182 "ibmf_i_rmpp_sender_active_flow() exit\n");
183
184 return;
185 }
186
187 IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_rmpp_sender_active_flow,
188 IBMF_TNF_TRACE, "", "ibmf_i_rmpp_sender_active_flow(): %s, "
189 "msgp = 0x%p, recvd seg = %d wl = %d wf = %d\n",
190 tnf_string, msg, "ACK packet received",
191 tnf_opaque, msgp, msgimplp, tnf_uint, recvd_seg,
192 b2h32(rmpp_hdr->rmpp_segnum), tnf_uint, wl, rmpp_ctx->rmpp_wl,
193 tnf_uint, wf, rmpp_ctx->rmpp_wf);
194
195
196 /* only ACK packets get here */
197 if (b2h32(rmpp_hdr->rmpp_segnum) > rmpp_ctx->rmpp_wl) {
198
199 /* abort with status S2B */
200 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
201 IBMF_RMPP_STATUS_S2B, 0, 0, IBMF_NO_BLOCK);
202 if (status != IBMF_SUCCESS) {
203 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
204 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
205 "ibmf_i_rmpp_sender_active_flow(): %s\n",
206 tnf_string, msg, "RMPP ABORT send failed");
207 msgimplp->im_trans_state_flags |=
208 IBMF_TRANS_STATE_FLAG_SEND_DONE;
209 }
210
211 mutex_enter(&clientp->ic_kstat_mutex);
212 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
213 mutex_exit(&clientp->ic_kstat_mutex);
214
215 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
216 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
217 "ibmf_i_rmpp_sender_active_flow(): %s\n",
218 tnf_string, msg, "Segnum > WL");
219
220 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
221
222 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
223 msgimplp, IBMF_RESP_TIMER);
224
225 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
226 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
227 "ibmf_i_rmpp_sender_active_flow() exit\n");
228
229 return;
230 }
231
232 if (b2h32(rmpp_hdr->rmpp_segnum) < rmpp_ctx->rmpp_wf) {
233
234 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
235 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
236 "ibmf_i_rmpp_sender_active_flow(): %s\n",
237 tnf_string, msg, "Segnum < WF");
238
239 /* discard the packet by not processing it here */
240
241 /* send the window */
242 ibmf_i_send_rmpp_window(msgimplp, IBMF_NO_BLOCK);
243
244 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
245 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
246 "ibmf_i_rmpp_sender_active_flow() exit\n");
247
248 return;
249 }
250
251 /* only ACK packets with valid segnum get here */
252 if (b2h32(rmpp_hdr->rmpp_pyldlen_nwl) < rmpp_ctx->rmpp_wl) {
253
254 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
255 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
256 "ibmf_i_rmpp_sender_active_flow(): %s\n",
257 tnf_string, msg, "NWL < WL");
258
259 /* abort with status W2S */
260 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
261 IBMF_RMPP_STATUS_W2S, 0, 0, IBMF_NO_BLOCK);
262 if (status != IBMF_SUCCESS) {
263 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
264 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
265 "ibmf_i_rmpp_sender_active_flow(): %s\n",
266 tnf_string, msg, "RMPP ABORT send failed");
267 msgimplp->im_trans_state_flags |=
268 IBMF_TRANS_STATE_FLAG_SEND_DONE;
269 }
270
271 mutex_enter(&clientp->ic_kstat_mutex);
272 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
273 mutex_exit(&clientp->ic_kstat_mutex);
274
275 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
276
277 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
278 msgimplp, IBMF_RESP_TIMER);
279
280 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
281 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
282 "ibmf_i_rmpp_sender_active_flow() exit\n");
283
284 return;
285 }
286
287 /* is ACK of last packet */
288
289 if (b2h32(rmpp_hdr->rmpp_segnum) == rmpp_ctx->rmpp_num_pkts) {
290
291 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
292 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
293 "ibmf_i_rmpp_sender_active_flow(): %s, msgp = 0x%p, "
294 "double-sided = %d\n", tnf_string, msg, "Last packet",
295 tnf_opaque, msgimplp, msgimplp,
296 tnf_opaque, double_sided, rmpp_ctx->rmpp_is_ds);
297
298 if (rmpp_ctx->rmpp_is_ds) {
299
300 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
301 ibmf_i_rmpp_sender_active_flow, IBMF_TNF_TRACE, "",
302 "ibmf_i_rmpp_sender_active_flow(): %s, "
303 "msgp = 0x%p\n", tnf_string, msg,
304 "Doublesided,sending ACK and switching to receiver",
305 tnf_opaque, msgimplp, msgimplp);
306
307 rmpp_ctx->rmpp_is_ds = B_FALSE;
308 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_SENDER_SWITCH;
309 rmpp_ctx->rmpp_wf = 1;
310 rmpp_ctx->rmpp_wl = 1;
311 rmpp_ctx->rmpp_es = 1;
312
313 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
314 IBMF_RMPP_STATUS_NORMAL, 0, 1, IBMF_NO_BLOCK);
315
316 /* set the response timer */
317 ibmf_i_set_timer(ibmf_i_send_timeout,
318 msgimplp, IBMF_RESP_TIMER);
319
320 /* proceed with sender switch to receiver */
321 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
322 ibmf_i_rmpp_sender_active_flow_end,
323 IBMF_TNF_TRACE, "",
324 "ibmf_i_rmpp_sender_active_flow() exit\n");
325 return;
326 }
327
328 /* successful termination */
329 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_DONE;
330 ibmf_i_terminate_transaction(clientp, msgimplp, IBMF_SUCCESS);
331
332 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
333 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
334 "ibmf_i_rmpp_sender_active_flow() exit\n");
335 return;
336 }
337
338 /* update RMPP context and send the next window */
339 rmpp_ctx->rmpp_wf = b2h32(rmpp_hdr->rmpp_segnum) + 1;
340 rmpp_ctx->rmpp_ns = b2h32(rmpp_hdr->rmpp_segnum) + 1;
341 rmpp_ctx->rmpp_wl =
342 (rmpp_ctx->rmpp_num_pkts < b2h32(rmpp_hdr->rmpp_pyldlen_nwl)) ?
343 rmpp_ctx->rmpp_num_pkts : b2h32(rmpp_hdr->rmpp_pyldlen_nwl);
344
345 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_rmpp_sender_active_flow,
346 IBMF_TNF_TRACE, "", "ibmf_i_rmpp_sender_active_flow(): %s, "
347 "wf = %d, wl = %d, ns = %d\n",
348 tnf_string, msg, "sending next window",
349 tnf_uint, wf, rmpp_ctx->rmpp_wf, tnf_uint, wl, rmpp_ctx->rmpp_wl,
350 tnf_uint, ns, rmpp_ctx->rmpp_ns);
351
352 /* send the window */
353 ibmf_i_send_rmpp_window(msgimplp, IBMF_NO_BLOCK);
354
355 /* carry on with the protocol */
356 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
357 ibmf_i_rmpp_sender_active_flow_end, IBMF_TNF_TRACE, "",
358 "ibmf_i_rmpp_sender_active_flow() exit\n");
359 }
360
361 /*
362 * ibmf_i_rmpp_sender_switch_flow():
363 * Perform sender to receiver flow processing switch.
364 * Refer to figure 179 "RMPP Sender Direction Switch Flow Diagram" of
365 * the InfiniBand Architecture Specification Volume 1, Release 1.1
366 */
367 static void
ibmf_i_rmpp_sender_switch_flow(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * mad)368 ibmf_i_rmpp_sender_switch_flow(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
369 ibmf_msg_impl_t *msgimplp, uchar_t *mad)
370 {
371 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
372 ibmf_rmpp_hdr_t *rmpp_hdr;
373 int status;
374
375 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
376 ibmf_i_rmpp_sender_switch_flow_start, IBMF_TNF_TRACE, "",
377 "ibmf_i_rmpp_sender_switch_flow(): clientp = 0x%p, qp_hdl = 0x%p, "
378 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
379 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
380 tnf_opaque, mad, mad);
381
382 rmpp_hdr = (ibmf_rmpp_hdr_t *)(mad + sizeof (ib_mad_hdr_t));
383
384 if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ACK) {
385
386 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
387 ibmf_i_rmpp_sender_switch_flow, IBMF_TNF_TRACE, "",
388 "ibmf_i_rmpp_sender_switch_flow(): %s\n", tnf_string, msg,
389 "ACK packet received, sending ACK");
390
391 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
392 IBMF_RMPP_STATUS_NORMAL, 0, 1, IBMF_NO_BLOCK);
393
394 /* set the response timer */
395 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
396 IBMF_RESP_TIMER);
397
398 } else if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) {
399
400 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
401 ibmf_i_rmpp_sender_switch_flow, IBMF_TNF_TRACE, "",
402 "ibmf_i_rmpp_sender_switch_flow(): %s\n", tnf_string, msg,
403 "DATA packet received, processing packet");
404
405 msgimplp->im_flags |= IBMF_MSG_FLAGS_RECV_RMPP;
406 ibmf_i_rmpp_recvr_flow_main(clientp, qp_hdl, msgimplp, mad);
407
408 } else {
409
410 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
411 ibmf_i_rmpp_sender_switch_flow, IBMF_TNF_TRACE, "",
412 "ibmf_i_rmpp_sender_switch_flow(): %s\n", tnf_string, msg,
413 "Unexpected packet received, sending ABORT BADT");
414
415 /* abort with status BadT */
416 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
417 IBMF_RMPP_STATUS_BADT, 0, 0, IBMF_NO_BLOCK);
418 if (status != IBMF_SUCCESS) {
419 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
420 ibmf_i_rmpp_sender_switch_flow, IBMF_TNF_TRACE, "",
421 "ibmf_i_rmpp_sender_switch_flow(): %s\n",
422 tnf_string, msg, "RMPP ABORT send failed");
423 msgimplp->im_trans_state_flags |=
424 IBMF_TRANS_STATE_FLAG_SEND_DONE;
425 }
426
427 mutex_enter(&clientp->ic_kstat_mutex);
428 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
429 mutex_exit(&clientp->ic_kstat_mutex);
430
431 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
432
433 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
434 msgimplp, IBMF_RESP_TIMER);
435 }
436
437 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
438 ibmf_i_rmpp_sender_switch_flow_end, IBMF_TNF_TRACE, "",
439 "ibmf_i_rmpp_sender_switch_flow() exit\n");
440 }
441
442 /*
443 * ibmf_i_rmpp_recvr_flow_main():
444 * Perform RMPP receiver flow processing.
445 * Refer to figure 176 "RMPP Receiver Main Flow Diagram" of
446 * the InfiniBand Architecture Specification Volume 1, Release 1.1
447 */
448 static void
ibmf_i_rmpp_recvr_flow_main(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * mad)449 ibmf_i_rmpp_recvr_flow_main(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
450 ibmf_msg_impl_t *msgimplp, uchar_t *mad)
451 {
452 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
453 ibmf_rmpp_hdr_t *rmpp_hdr;
454 ib_mad_hdr_t *mad_hdr;
455 uchar_t *msgbufp;
456 uchar_t *datap;
457 uint32_t data_sz, offset, num_pkts;
458 uint32_t cl_hdr_sz, cl_data_sz, cl_hdr_off, cl_hdrdata_sz;
459 size_t buf_sz;
460 int status;
461
462 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
463 ibmf_i_rmpp_recvr_flow_main_start, IBMF_TNF_TRACE, "",
464 "ibmf_i_rmpp_recvr_flow_main(): clientp = 0x%p, qp_hdl = 0x%p, "
465 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
466 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
467 tnf_opaque, mad, mad);
468
469 rmpp_hdr = (ibmf_rmpp_hdr_t *)(mad + sizeof (ib_mad_hdr_t));
470
471 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_rmpp_recvr_flow_main,
472 IBMF_TNF_TRACE, "", "ibmf_i_rmpp_recvr_flow_main(): "
473 "segnum = %d, es = %d, wl = %d\n", tnf_uint, segnum,
474 b2h32(rmpp_hdr->rmpp_segnum), tnf_uint, es, rmpp_ctx->rmpp_es,
475 tnf_uint, wl, rmpp_ctx->rmpp_wl);
476
477 /*
478 * check that this is the segment we expected;
479 * assume this check will succeed for the first segment since we cannot
480 * send an ACK if we haven't allocated the rmpp context yet
481 */
482 if (b2h32(rmpp_hdr->rmpp_segnum) != rmpp_ctx->rmpp_es) {
483
484 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
485 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
486 "ibmf_i_rmpp_recvr_flow_main(): %s\n", tnf_string, msg,
487 "Unexpected segment number, discarding packet");
488
489 /* discard this packet by not processing it here */
490
491 /*
492 * If the receive buffer is not yet allocated, this is
493 * probably the first MAD received for the receive context.
494 * We need to set up the receive buffer before calling
495 * ibmf_i_send_rmpp() to send an ACK packet.
496 */
497 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
498 status = ibmf_setup_recvbuf_on_error(msgimplp, mad);
499 if (status != IBMF_SUCCESS) {
500 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
501 ibmf_i_rmpp_recvr_flow_main_err,
502 IBMF_TNF_ERROR, "",
503 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
504 tnf_string, msg,
505 "ibmf_setup_recvbuf_on_error() failed");
506 return;
507 }
508 }
509
510 /* send an ACK of ES - 1 if ES is greater than 1 */
511 if (rmpp_ctx->rmpp_es > 1) {
512 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
513 IBMF_RMPP_STATUS_NORMAL, rmpp_ctx->rmpp_es - 1,
514 rmpp_ctx->rmpp_es - 1 + IBMF_RMPP_DEFAULT_WIN_SZ,
515 IBMF_NO_BLOCK);
516 }
517
518 /*
519 * reset the timer if we're still waiting for the first seg;
520 * this is the same timer that is normally set in send_compl
521 * NOTE: this should be in the IB spec's flowchart but isn't
522 */
523 if (rmpp_ctx->rmpp_es == 1) {
524 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
525 IBMF_RESP_TIMER);
526 }
527
528 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
529 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE, "",
530 "ibmf_i_rmpp_recvr_flow_main() exit\n");
531 return;
532 }
533
534 mad_hdr = (ib_mad_hdr_t *)mad;
535
536 ibmf_i_mgt_class_to_hdr_sz_off(mad_hdr->MgmtClass, &cl_hdr_sz,
537 &cl_hdr_off);
538
539 if ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_FIRST_PKT) ||
540 (b2h32(rmpp_hdr->rmpp_segnum) == 1)) {
541
542 /* first packet flag should be set and seg num should be 1 */
543 if (((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_FIRST_PKT) == 0) ||
544 (b2h32(rmpp_hdr->rmpp_segnum) != 1)) {
545
546 /*
547 * If the receive buffer is not yet allocated, this is
548 * probably the first MAD received for the receive ctx.
549 * We need to set up the receive buffer before calling
550 * ibmf_i_send_rmpp() to send an ABORT packet.
551 */
552 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
553 status = ibmf_setup_recvbuf_on_error(msgimplp,
554 mad);
555 if (status != IBMF_SUCCESS) {
556 IBMF_TRACE_1(IBMF_TNF_NODEBUG,
557 DPRINT_L2,
558 ibmf_i_rmpp_recvr_flow_main_err,
559 IBMF_TNF_ERROR, "",
560 "ibmf_i_rmpp_recvr_flow_main(): "
561 "%s\n", tnf_string, msg,
562 "ibmf_setup_recvbuf_on_error() "
563 "failed");
564 return;
565 }
566 }
567
568 /* abort with status BadT */
569 status = ibmf_i_send_rmpp(msgimplp,
570 IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_IFSN,
571 0, 0, IBMF_NO_BLOCK);
572 if (status != IBMF_SUCCESS) {
573 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
574 ibmf_i_rmpp_recvr_flow_main,
575 IBMF_TNF_TRACE, "",
576 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
577 tnf_string, msg, "RMPP ABORT send failed");
578 msgimplp->im_trans_state_flags |=
579 IBMF_TRANS_STATE_FLAG_SEND_DONE;
580 }
581
582 mutex_enter(&clientp->ic_kstat_mutex);
583 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
584 mutex_exit(&clientp->ic_kstat_mutex);
585
586 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
587 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
588 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
589 tnf_string, msg, "Inconsistent first and segment "
590 "number detected, sending ABORT IFSN");
591
592 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
593
594 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
595
596 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
597 msgimplp, IBMF_RESP_TIMER);
598
599 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
600 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE,
601 "", "ibmf_i_rmpp_recvr_flow_main() exit\n");
602 return;
603 }
604
605 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
606 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
607 "ibmf_i_rmpp_recvr_flow_main(): %s\n", tnf_string, msg,
608 "Segment number 1 received:", tnf_opaque, msgp, msgimplp);
609
610 cl_data_sz = MAD_SIZE_IN_BYTES -
611 sizeof (ib_mad_hdr_t) - cl_hdr_off - cl_hdr_sz;
612
613 cl_hdrdata_sz = MAD_SIZE_IN_BYTES -
614 sizeof (ib_mad_hdr_t) - cl_hdr_off;
615
616 /*
617 * Calculate the number of packets by dividing the payload
618 * length in the RMPP header by the payload size for
619 * a single packet of that management class (including the
620 * class header).
621 */
622 buf_sz = b2h32(rmpp_hdr->rmpp_pyldlen_nwl);
623 if ((buf_sz % cl_hdrdata_sz) != 0)
624 num_pkts = (buf_sz / cl_hdrdata_sz) + 1;
625 else {
626 if (buf_sz > 0)
627 num_pkts = buf_sz / cl_hdrdata_sz;
628 else
629 num_pkts = 1;
630 }
631
632 /*
633 * If the payload length of the message is not specified
634 * in the first packet's RMPP header, we create a
635 * temporary receive buffer with space for data payloads
636 * of IBMF_BUF_PKTS packets. If the number of packets
637 * received exceeds the capacity in the receive buffer,
638 * the temporary receive buffer will be freed up, and
639 * a larger temporary receive buffer will be allocated.
640 * When the last packet is received, the final receive
641 * buffer will be allocated with the real size of the message.
642 * The data will be copied from the old buffer to the new
643 * buffer.
644 */
645 if (b2h32(rmpp_hdr->rmpp_pyldlen_nwl) != 0) {
646 /*
647 * rmpp_pyld_len is the total length of just the
648 * class data. Class headers from each packet are
649 * not included in this calculation.
650 */
651 msgimplp->im_msgbufs_recv.im_bufs_cl_data_len =
652 rmpp_ctx->rmpp_pyld_len =
653 b2h32(rmpp_hdr->rmpp_pyldlen_nwl) -
654 (num_pkts * cl_hdr_sz);
655 } else {
656 msgimplp->im_msgbufs_recv.im_bufs_cl_data_len =
657 rmpp_ctx->rmpp_pyld_len =
658 IBMF_BUF_PKTS * cl_data_sz;
659 rmpp_ctx->rmpp_flags |= IBMF_CTX_RMPP_FLAGS_DYN_PYLD;
660 }
661
662 ASSERT(msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL);
663
664 /* allocate memory for the message data */
665 msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
666 (ib_mad_hdr_t *)kmem_zalloc(sizeof (ib_mad_hdr_t) +
667 cl_hdr_off + cl_hdr_sz + rmpp_ctx->rmpp_pyld_len,
668 KM_NOSLEEP);
669 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
670
671 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
672 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
673 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
674 tnf_string, msg,
675 "mem allocation failure (known rmpp payload)");
676
677 ibmf_i_terminate_transaction(
678 msgimplp->im_client, msgimplp,
679 IBMF_NO_MEMORY);
680
681 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
682 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE,
683 "", "ibmf_i_rmpp_recvr_flow_main() exit\n");
684 return;
685 }
686 mutex_enter(&clientp->ic_kstat_mutex);
687 IBMF_ADD32_KSTATS(clientp, recv_bufs_alloced, 1);
688 mutex_exit(&clientp->ic_kstat_mutex);
689
690 msgbufp = (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
691
692 /* copy the MAD and class header */
693 bcopy((const void *)mad, (void *)msgbufp,
694 sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz);
695
696 offset = sizeof (ib_mad_hdr_t) + cl_hdr_off;
697
698 /* initialize class header pointer */
699 if (cl_hdr_sz == 0) {
700 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr = NULL;
701 } else {
702 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
703 (void *)(msgbufp + offset);
704 }
705 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len = cl_hdr_sz;
706
707 offset += cl_hdr_sz;
708
709 /* initialize data area pointer */
710 msgimplp->im_msgbufs_recv.im_bufs_cl_data =
711 (void *)(msgbufp + offset);
712
713 rmpp_ctx->rmpp_data_offset = 0;
714
715 cl_data_sz = MAD_SIZE_IN_BYTES -
716 sizeof (ib_mad_hdr_t) - cl_hdr_off - cl_hdr_sz;
717
718 rmpp_ctx->rmpp_pkt_data_sz = cl_data_sz;
719
720 /*
721 * calculate number of expected packets for transaction
722 * timeout calculation
723 */
724 if (rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) {
725
726 /*
727 * if the payload length is not specified in
728 * the first packet, just guess how many packets
729 * might arrive
730 */
731 msgimplp->im_rmpp_ctx.rmpp_num_pkts = 100;
732 } else {
733 msgimplp->im_rmpp_ctx.rmpp_num_pkts =
734 rmpp_ctx->rmpp_pyld_len / cl_data_sz;
735
736 /* round up */
737 if ((rmpp_ctx->rmpp_pyld_len % cl_data_sz) != 0)
738 msgimplp->im_rmpp_ctx.rmpp_num_pkts++;
739 }
740
741 /* set the transaction timer if there are more packets */
742 if ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_LAST_PKT) == 0) {
743
744 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
745 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
746 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
747 tnf_string, msg,
748 "First pkt recvd; setting trans timer: ",
749 tnf_opaque, msg, msgimplp);
750
751 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
752 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
753 "ibmf_i_rmpp_recvr_flow_main(): setting trans"
754 " timer %p %d\n", tnf_opaque, msg, msgimplp,
755 tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
756
757 ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp,
758 IBMF_TRANS_TIMER);
759 }
760 }
761
762 offset = sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz;
763
764 /*
765 * copy the data from the packet into the data buffer in
766 * the message.
767 */
768
769 if (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_LAST_PKT)
770 data_sz = b2h32(rmpp_hdr->rmpp_pyldlen_nwl) - cl_hdr_sz;
771 else
772 data_sz = rmpp_ctx->rmpp_pkt_data_sz;
773
774 /* if a payload length was specified and we've met or exceeded it */
775 if (((data_sz + rmpp_ctx->rmpp_data_offset) >=
776 rmpp_ctx->rmpp_pyld_len) &&
777 ((rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) == 0)) {
778
779 /* last packet flag should be set */
780 if ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_LAST_PKT) == 0) {
781
782 /* abort with status Incon. last and payload length */
783 status = ibmf_i_send_rmpp(msgimplp,
784 IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_ILPL,
785 0, 0, IBMF_NO_BLOCK);
786 if (status != IBMF_SUCCESS) {
787 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
788 ibmf_i_rmpp_recvr_flow_main,
789 IBMF_TNF_TRACE, "",
790 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
791 tnf_string, msg, "RMPP ABORT send failed");
792 msgimplp->im_trans_state_flags |=
793 IBMF_TRANS_STATE_FLAG_SEND_DONE;
794 }
795
796 mutex_enter(&clientp->ic_kstat_mutex);
797 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
798 mutex_exit(&clientp->ic_kstat_mutex);
799
800 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
801 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
802 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
803 tnf_string, msg,
804 "Inconsistent last and payload length detected,"
805 " sending ABORT ILPL, unsetting trans timer");
806
807 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
808
809 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
810
811 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
812 msgimplp, IBMF_RESP_TIMER);
813
814 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
815 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE,
816 "", "ibmf_i_rmpp_recvr_flow_main() exit\n");
817
818 return;
819 }
820 } else if (((data_sz + rmpp_ctx->rmpp_data_offset) >=
821 rmpp_ctx->rmpp_pyld_len) &&
822 ((rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) != 0) &&
823 ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_LAST_PKT) == 0)) {
824
825 /*
826 * If the payload length was not specified in the first
827 * packet's RMPP header, we have a temporary receive buffer
828 * the size of which will be exceeded with this incoming
829 * packet. We need to allocate a new temporary receive buffer
830 * with an additional IBMF_BUF_PKTS data payloads.
831 */
832 ib_mad_hdr_t *old_buf;
833 size_t prev_pyld_len;
834
835 old_buf = msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
836 prev_pyld_len = rmpp_ctx->rmpp_pyld_len;
837
838 rmpp_ctx->rmpp_pyld_len +=
839 IBMF_BUF_PKTS * rmpp_ctx->rmpp_pkt_data_sz;
840 msgimplp->im_msgbufs_recv.im_bufs_cl_data_len =
841 rmpp_ctx->rmpp_pyld_len;
842 msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
843 (ib_mad_hdr_t *)kmem_zalloc(sizeof (ib_mad_hdr_t) +
844 cl_hdr_off + cl_hdr_sz + rmpp_ctx->rmpp_pyld_len,
845 KM_NOSLEEP);
846 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
847
848 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
849 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
850 "ibmf_i_rmpp_recvr_flow_main(): %s, allocsz = %d\n",
851 tnf_string, msg,
852 "mem allocation failure (unknown rmpp payload)",
853 tnf_uint, alloc_size,
854 sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz +
855 rmpp_ctx->rmpp_pyld_len);
856
857 ibmf_i_terminate_transaction(
858 msgimplp->im_client, msgimplp,
859 IBMF_NO_MEMORY);
860
861 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
862 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE,
863 "", "ibmf_i_rmpp_recvr_flow_main() exit\n");
864 return;
865 }
866 mutex_enter(&clientp->ic_kstat_mutex);
867 IBMF_ADD32_KSTATS(clientp, recv_bufs_alloced, 1);
868 mutex_exit(&clientp->ic_kstat_mutex);
869
870 msgbufp = (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
871
872 /* copy the MAD and class header */
873 bcopy((const void *)old_buf, (void *)msgbufp,
874 sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz +
875 prev_pyld_len);
876
877 kmem_free(old_buf, sizeof (ib_mad_hdr_t) + cl_hdr_off +
878 cl_hdr_sz + prev_pyld_len);
879 }
880
881 /* don't overflow buffer */
882 if (rmpp_ctx->rmpp_data_offset + data_sz >
883 rmpp_ctx->rmpp_pyld_len) {
884 data_sz = rmpp_ctx->rmpp_pyld_len -
885 rmpp_ctx->rmpp_data_offset;
886 }
887
888 datap = (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_cl_data;
889
890 bcopy((void *)&mad[offset],
891 (void *)(datap + rmpp_ctx->rmpp_data_offset), data_sz);
892
893 rmpp_ctx->rmpp_data_offset += data_sz;
894
895 rmpp_ctx->rmpp_es++;
896
897 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_rmpp_recvr_flow_main,
898 IBMF_TNF_TRACE, "", "ibmf_i_rmpp_recvr_flow_main(): es = %d\n",
899 tnf_uint, es, rmpp_ctx->rmpp_es);
900
901 if (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_LAST_PKT) {
902
903 /*
904 * Since this is the last packet, we finally know the
905 * size of the receive buffer we need to allocate.
906 * Allocate the needed size and free the temporary receive
907 * buffer.
908 */
909 if ((rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) !=
910 0) {
911 ib_mad_hdr_t *old_buf;
912 size_t prev_pyld_len;
913
914 rmpp_ctx->rmpp_flags &= ~IBMF_CTX_RMPP_FLAGS_DYN_PYLD;
915 old_buf = msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
916 prev_pyld_len = rmpp_ctx->rmpp_pyld_len;
917 rmpp_ctx->rmpp_pyld_len = rmpp_ctx->rmpp_data_offset;
918 msgimplp->im_msgbufs_recv.im_bufs_cl_data_len =
919 rmpp_ctx->rmpp_pyld_len;
920 msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
921 (ib_mad_hdr_t *)kmem_zalloc(sizeof (ib_mad_hdr_t) +
922 cl_hdr_off + cl_hdr_sz + rmpp_ctx->rmpp_pyld_len,
923 KM_NOSLEEP);
924 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
925 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
926 ibmf_i_rmpp_recvr_flow_main,
927 IBMF_TNF_TRACE, "",
928 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
929 tnf_string, msg,
930 "mem allocation failure (final payload)");
931 ibmf_i_terminate_transaction(
932 msgimplp->im_client, msgimplp,
933 IBMF_NO_MEMORY);
934 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
935 ibmf_i_rmpp_recvr_flow_main_end,
936 IBMF_TNF_TRACE, "",
937 "ibmf_i_rmpp_recvr_flow_main() exit\n");
938 return;
939 }
940 mutex_enter(&clientp->ic_kstat_mutex);
941 IBMF_ADD32_KSTATS(clientp, recv_bufs_alloced, 1);
942 mutex_exit(&clientp->ic_kstat_mutex);
943
944 msgbufp = (uchar_t *)
945 msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
946
947 /* copy the data to the new buffer */
948 bcopy((const void *)old_buf, (void *)msgbufp,
949 sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz +
950 rmpp_ctx->rmpp_pyld_len);
951
952 offset = sizeof (ib_mad_hdr_t) + cl_hdr_off;
953
954 /* initialize class header pointer */
955 if (cl_hdr_sz == 0) {
956 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr = NULL;
957 } else {
958 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
959 (void *)(msgbufp + offset);
960 }
961 msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len =
962 cl_hdr_sz;
963
964 offset += cl_hdr_sz;
965
966 /* initialize data area pointer */
967 msgimplp->im_msgbufs_recv.im_bufs_cl_data =
968 (void *)(msgbufp + offset);
969
970 kmem_free(old_buf, sizeof (ib_mad_hdr_t) + cl_hdr_off +
971 cl_hdr_sz + prev_pyld_len);
972 }
973
974 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
975 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
976 "ibmf_i_rmpp_recvr_flow_main(): %s, msgp = 0x%p\n",
977 tnf_string, msg,
978 "Last pkt rcvd; state to recv_term, sending ack",
979 tnf_opaque, msgp, msgimplp);
980
981 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_RECEVR_TERMINATE;
982
983 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
984 IBMF_RMPP_STATUS_NORMAL, rmpp_ctx->rmpp_es - 1,
985 rmpp_ctx->rmpp_es - 1 + IBMF_RMPP_DEFAULT_WIN_SZ,
986 IBMF_NO_BLOCK);
987 if (status != IBMF_SUCCESS) {
988 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
989 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
990 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
991 tnf_string, msg, "RMPP ACK send failed");
992 msgimplp->im_trans_state_flags |=
993 IBMF_TRANS_STATE_FLAG_SEND_DONE;
994 }
995
996 /* unset the transaction timer if it's not the first segment */
997 if ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_FIRST_PKT) == 0) {
998 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
999 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1000 "ibmf_i_rmpp_recvr_flow_main(): %s, msgp = 0x%p\n",
1001 tnf_string, msg, "Last, but not first segment",
1002 tnf_opaque, msgp, msgimplp);
1003 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1004 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1005 "ibmf_i_rmpp_recvr_flow_main(): unsetting timer "
1006 "%p %d\n", tnf_opaque, msgp, msgimplp,
1007 tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
1008
1009 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1010 }
1011
1012 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1013 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1014 "ibmf_i_rmpp_recvr_flow_main(): %s, msgp = 0x%p\n",
1015 tnf_string, msg,
1016 "Last pkt rcvd; setting resp timer",
1017 tnf_opaque, msgp, msgimplp);
1018
1019 /*
1020 * The RMPP receive transaction has been broken
1021 * up into two parts. At this point in the
1022 * transaction, all the data has been received.
1023 * From the perspective of the client, the transaction
1024 * is complete. So, control is returned to the client
1025 * at this point. However, the RMPP protocol requires
1026 * a wait after receiving the last data packet, so that,
1027 * duplicate packets may be absorbed. This wait is
1028 * implemented in the second part of the transaction under
1029 * a duplicate message context.
1030 * The regular message context is marked as done in
1031 * ibmf_i_terminate_transaction().
1032 * The IBMF_MSG_FLAGS_SET_TERMINATION flag indicates
1033 * that the duplicate message context needs to be created
1034 * to handle the termination loop.
1035 */
1036 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1037 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1038 "ibmf_i_rmpp_recvr_flow_main(): last packet, "
1039 " returning data to client for message %p\n",
1040 tnf_opaque, msgp, msgimplp);
1041
1042 ibmf_i_terminate_transaction(clientp, msgimplp, IBMF_SUCCESS);
1043
1044 /* Mark this message for early termination */
1045 msgimplp->im_flags |= IBMF_MSG_FLAGS_SET_TERMINATION;
1046
1047 return;
1048 }
1049
1050 if (b2h32(rmpp_hdr->rmpp_segnum) == rmpp_ctx->rmpp_wl) {
1051 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
1052 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1053 "ibmf_i_rmpp_recvr_flow_main(): %s, msgp = 0x%p"
1054 "segnum = %d, wl = %d\n", tnf_string, msg,
1055 "Last packet in window received", tnf_opaque, msgimplp,
1056 msgimplp, tnf_opaque, seg, b2h32(rmpp_hdr->rmpp_segnum),
1057 tnf_opaque, wl, rmpp_ctx->rmpp_wl);
1058
1059 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
1060 IBMF_RMPP_STATUS_NORMAL,
1061 rmpp_ctx->rmpp_es - 1,
1062 rmpp_ctx->rmpp_es - 1 +
1063 IBMF_RMPP_DEFAULT_WIN_SZ, IBMF_NO_BLOCK);
1064
1065 /* update the window */
1066 rmpp_ctx->rmpp_wl += IBMF_RMPP_DEFAULT_WIN_SZ;
1067
1068 } else {
1069
1070 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1071 ibmf_i_rmpp_recvr_flow_main, IBMF_TNF_TRACE, "",
1072 "ibmf_i_rmpp_recvr_flow_main(): %s\n",
1073 tnf_string, msg, "Packet in window received");
1074
1075 }
1076
1077 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1078 ibmf_i_rmpp_recvr_flow_main_end, IBMF_TNF_TRACE, "",
1079 "ibmf_i_rmpp_recvr_flow_main() exit\n");
1080 }
1081
1082 /*
1083 * ibmf_i_rmpp_recvr_active_flow():
1084 * Perform RMPP receiver flow initiation processing.
1085 * Refer to figure 176 "RMPP Receiver Main Flow Diagram" of
1086 * the InfiniBand Architecture Specification Volume 1, Release 1.1
1087 */
1088 static void
ibmf_i_rmpp_recvr_active_flow(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * mad)1089 ibmf_i_rmpp_recvr_active_flow(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
1090 ibmf_msg_impl_t *msgimplp, uchar_t *mad)
1091 {
1092 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1093 ibmf_rmpp_hdr_t *rmpp_hdr;
1094 uint32_t abort_status;
1095 int status;
1096
1097 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
1098 ibmf_i_rmpp_recvr_active_flow_start, IBMF_TNF_TRACE, "",
1099 "ibmf_i_rmpp_recvr_active_flow(): clientp = 0x%p, qp_hdl = 0x%p, "
1100 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
1101 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
1102 tnf_opaque, mad, mad);
1103
1104 rmpp_hdr = (ibmf_rmpp_hdr_t *)(mad + sizeof (ib_mad_hdr_t));
1105
1106 if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ACK) {
1107
1108 /* discard this packet by not processing it here */
1109
1110 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1111 ibmf_i_rmpp_recvr_active_flow, IBMF_TNF_TRACE, "",
1112 "ibmf_i_rmpp_recvr_active_flow(): %s\n", tnf_string, msg,
1113 "ACK packet received, discarding packet");
1114
1115 /*
1116 * reset the timer if we're still waiting for the first seg;
1117 * this is the same timer that is normally set in send_compl
1118 * NOTE: this should be in the IB spec's flowchart but isn't
1119 */
1120 if (rmpp_ctx->rmpp_es == 1) {
1121 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
1122 IBMF_RESP_TIMER);
1123 }
1124
1125 return;
1126 }
1127
1128 if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) {
1129
1130 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1131 ibmf_i_rmpp_recvr_active_flow, IBMF_TNF_TRACE, "",
1132 "ibmf_i_rmpp_recvr_active_flow(): %s\n", tnf_string, msg,
1133 "DATA packet received, processing packet");
1134
1135 ibmf_i_rmpp_recvr_flow_main(clientp, qp_hdl, msgimplp, mad);
1136
1137 } else if ((rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_STOP) ||
1138 (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ABORT)) {
1139
1140 abort_status = rmpp_hdr->rmpp_status;
1141
1142 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1143 ibmf_i_rmpp_recvr_active_flow, IBMF_TNF_TRACE, "",
1144 "ibmf_i_rmpp_recvr_active_flow(): %s, status = %d\n",
1145 tnf_string, msg,
1146 "STOP/ABORT packet received, terminating transaction",
1147 tnf_uint, abort_status, abort_status);
1148
1149 /* discard the packet and terminate the transaction */
1150 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1151 msgimplp->im_trans_state_flags |=
1152 IBMF_TRANS_STATE_FLAG_SEND_DONE;
1153
1154 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1155
1156 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1157 msgimplp, IBMF_RESP_TIMER);
1158
1159 } else {
1160
1161 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1162 ibmf_i_rmpp_recvr_active_flow, IBMF_TNF_TRACE, "",
1163 "ibmf_i_rmpp_recvr_active_flow(): %s\n", tnf_string, msg,
1164 "Unrecognized packet received, terminating transaction");
1165
1166 /* abort with status BadT */
1167 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
1168 IBMF_RMPP_STATUS_BADT, 0, 0, IBMF_NO_BLOCK);
1169 if (status != IBMF_SUCCESS) {
1170 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1171 ibmf_i_rmpp_recvr_active_flow, IBMF_TNF_TRACE, "",
1172 "ibmf_i_rmpp_recvr_active_flow(): %s\n",
1173 tnf_string, msg, "RMPP ABORT send failed");
1174 msgimplp->im_trans_state_flags |=
1175 IBMF_TRANS_STATE_FLAG_SEND_DONE;
1176 }
1177
1178 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1179
1180 mutex_enter(&clientp->ic_kstat_mutex);
1181 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
1182 mutex_exit(&clientp->ic_kstat_mutex);
1183
1184 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1185
1186 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1187 msgimplp, IBMF_RESP_TIMER);
1188 }
1189
1190 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1191 ibmf_i_rmpp_recvr_active_flow_end, IBMF_TNF_TRACE, "",
1192 "ibmf_i_rmpp_recvr_active_flow() exit\n");
1193 }
1194
1195 /*
1196 * ibmf_i_rmpp_recvr_term_flow():
1197 * Perform RMPP receiver termination flow processing.
1198 * Refer to figure 177 "RMPP Receiver Termination Flow Diagram" of
1199 * the InfiniBand Architecture Specification Volume 1, Release 1.1
1200 */
1201 static void
ibmf_i_rmpp_recvr_term_flow(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * mad)1202 ibmf_i_rmpp_recvr_term_flow(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
1203 ibmf_msg_impl_t *msgimplp, uchar_t *mad)
1204 {
1205 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1206 ibmf_rmpp_hdr_t *rmpp_hdr;
1207 int status;
1208
1209 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
1210 ibmf_i_rmpp_recvr_term_flow_start, IBMF_TNF_TRACE, "",
1211 "ibmf_i_rmpp_recvr_term_flow(): clientp = 0x%p, qp_hdl = 0x%p, "
1212 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
1213 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
1214 tnf_opaque, mad, mad);
1215
1216 rmpp_hdr = (ibmf_rmpp_hdr_t *)(mad + sizeof (ib_mad_hdr_t));
1217
1218 if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) {
1219
1220 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1221 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1222 "ibmf_i_rmpp_recvr_term_flow(): %s\n", tnf_string, msg,
1223 "Data packet received, resending ACK");
1224
1225 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
1226 IBMF_RMPP_STATUS_NORMAL, rmpp_ctx->rmpp_es - 1,
1227 rmpp_ctx->rmpp_es - 1 + IBMF_RMPP_DEFAULT_WIN_SZ,
1228 IBMF_NO_BLOCK);
1229
1230 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1231 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1232 "ibmf_i_rmpp_recvr_term_flow(): setting resp timer %d %p\n",
1233 tnf_opaque, msgimplp, msgimplp, tnf_opaque,
1234 timeout_id, msgimplp->im_rp_timeout_id);
1235
1236 /* set the response timer */
1237 ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp,
1238 IBMF_RESP_TIMER);
1239
1240 } else if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ACK) {
1241
1242 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1243 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1244 "ibmf_i_rmpp_recvr_term_flow(): %s, msgp = 0x%p\n",
1245 tnf_string, msg, "ACK packet received",
1246 tnf_opaque, msgimplp, msgimplp);
1247
1248 if (rmpp_ctx->rmpp_is_ds) {
1249 /*
1250 * received ACK from sender which is indication that
1251 * we can send response; notify client that data has
1252 * arrived; it will call msg_transport to send response
1253 */
1254 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1255 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1256 "ibmf_i_rmpp_recvr_term_flow(): %s, msgp = 0x%p\n",
1257 tnf_string, msg,
1258 "Received final ack for double-sided trans",
1259 tnf_opaque, msgimplp, msgimplp);
1260
1261 /*
1262 * successful termination
1263 */
1264 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_DONE;
1265 ibmf_i_terminate_transaction(clientp, msgimplp,
1266 IBMF_SUCCESS);
1267
1268 } else {
1269
1270 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1271 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1272 "ibmf_i_rmpp_recvr_term_flow(): %s, msgp = 0x%p\n",
1273 tnf_string, msg, "Received ACK while in recv_term "
1274 "state for single sided trans",
1275 tnf_opaque, msgimplp, msgimplp);
1276
1277 /* abort with status BadT */
1278 (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
1279 IBMF_RMPP_STATUS_BADT, 0, 0, IBMF_NO_BLOCK);
1280
1281 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1282
1283 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1284
1285 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1286 msgimplp, IBMF_RESP_TIMER);
1287 }
1288
1289 } else {
1290
1291 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1292 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1293 "ibmf_i_rmpp_recvr_term_flow(): %s\n", tnf_string, msg,
1294 "Unexpected packet received, sending ABORT BADT");
1295
1296 /* abort with status BadT */
1297 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
1298 IBMF_RMPP_STATUS_BADT, 0, 0, IBMF_NO_BLOCK);
1299 if (status != IBMF_SUCCESS) {
1300 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1301 ibmf_i_rmpp_recvr_term_flow, IBMF_TNF_TRACE, "",
1302 "ibmf_i_rmpp_recvr_term_flow(): %s\n",
1303 tnf_string, msg, "RMPP ABORT send failed");
1304 msgimplp->im_trans_state_flags |=
1305 IBMF_TRANS_STATE_FLAG_SEND_DONE;
1306 }
1307
1308 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1309
1310 mutex_enter(&clientp->ic_kstat_mutex);
1311 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
1312 mutex_exit(&clientp->ic_kstat_mutex);
1313
1314 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1315
1316 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1317 msgimplp, IBMF_RESP_TIMER);
1318
1319 }
1320
1321 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1322 ibmf_i_rmpp_recvr_term_flow_end, IBMF_TNF_TRACE, "",
1323 "ibmf_i_rmpp_recvr_term_flow() exit\n");
1324 }
1325
1326 /*
1327 * ibmf_i_is_valid_rmpp_status():
1328 * Check for a valid RMPP status
1329 */
1330 static boolean_t
ibmf_i_is_valid_rmpp_status(ibmf_rmpp_hdr_t * rmpp_hdr)1331 ibmf_i_is_valid_rmpp_status(ibmf_rmpp_hdr_t *rmpp_hdr)
1332 {
1333 boolean_t found = B_TRUE;
1334
1335 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
1336 ibmf_i_is_valid_rmpp_status_start, IBMF_TNF_TRACE, "",
1337 "ibmf_i_is_valid_rmpp_status(): rmpp_hdr = 0x%p\n",
1338 tnf_opaque, rmpp_hdr, rmpp_hdr);
1339
1340 if (((rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) ||
1341 (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ACK)) &&
1342 (rmpp_hdr->rmpp_status != IBMF_RMPP_STATUS_NORMAL))
1343 found = B_FALSE;
1344
1345 if ((rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_RESX) &&
1346 (rmpp_hdr->rmpp_type != IBMF_RMPP_TYPE_STOP))
1347 found = B_FALSE;
1348
1349 if (((rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_T2L) ||
1350 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_ILPL) ||
1351 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_IFSN) ||
1352 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_BADT) ||
1353 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_W2S) ||
1354 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_S2B) ||
1355 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_IS) ||
1356 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_UNV) ||
1357 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_TMR) ||
1358 (rmpp_hdr->rmpp_status == IBMF_RMPP_STATUS_USP)) &&
1359 (rmpp_hdr->rmpp_type != IBMF_RMPP_TYPE_ABORT))
1360 found = B_FALSE;
1361
1362 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1363 ibmf_i_is_valid_rmpp_status_end, IBMF_TNF_TRACE, "",
1364 "ibmf_i_is_valid_rmpp_status_flow() exit\n");
1365
1366 return (found);
1367 }
1368
1369 /*
1370 * ibmf_i_handle_rmpp():
1371 * Handle RMPP processing of an incoming IB packet
1372 */
1373 void
ibmf_i_handle_rmpp(ibmf_client_t * clientp,ibmf_qp_handle_t qp_hdl,ibmf_msg_impl_t * msgimplp,uchar_t * madp)1374 ibmf_i_handle_rmpp(ibmf_client_t *clientp, ibmf_qp_handle_t qp_hdl,
1375 ibmf_msg_impl_t *msgimplp, uchar_t *madp)
1376 {
1377 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1378 ibmf_rmpp_hdr_t *rmpp_hdr;
1379 int status;
1380
1381 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
1382 ibmf_i_handle_rmpp_start, IBMF_TNF_TRACE, "",
1383 "ibmf_i_handle_rmpp(): clientp = 0x%p, qp_hdl = 0x%p, "
1384 "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
1385 tnf_opaque, qp_hdl, qp_hdl, tnf_opaque, msg, msgimplp,
1386 tnf_opaque, mad, madp);
1387
1388 ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1389
1390 rmpp_hdr = (ibmf_rmpp_hdr_t *)(madp + sizeof (ib_mad_hdr_t));
1391
1392 /*
1393 * Check the version in the RMPP header
1394 */
1395 if (rmpp_hdr->rmpp_version != IBMF_RMPP_VERSION) {
1396
1397 /*
1398 * If the receive buffer is not yet allocated, this is
1399 * probably the first MAD received for the receive context.
1400 * We need to set up the receive buffer before calling
1401 * ibmf_i_send_rmpp() to send an ABORT packet.
1402 */
1403 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
1404 status = ibmf_setup_recvbuf_on_error(msgimplp, madp);
1405 if (status != IBMF_SUCCESS) {
1406 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
1407 ibmf_i_handle_rmpp_err, IBMF_TNF_ERROR, "",
1408 "ibmf_i_handle_rmpp(): %s\n", tnf_string,
1409 msg,
1410 "ibmf_setup_recvbuf_on_error() failed");
1411 return;
1412 }
1413 }
1414
1415 /*
1416 * Drop the message if the transaction has not yet
1417 * been identified as a send or receive RMPP transaction.
1418 * This is because the send completion of an abort packet
1419 * will hit the non-rmpp code which attempts to reset the
1420 * RESP timer set after sending the abort packet, causing
1421 * an assert.
1422 */
1423 if (((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) == 0) &&
1424 (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP) == 0) {
1425 /*
1426 * Reset the response timer since we're still
1427 * waiting for the first response MAD, provided
1428 * that the send completion has occured
1429 */
1430 if (msgimplp->im_trans_state_flags &
1431 IBMF_TRANS_STATE_FLAG_SEND_DONE) {
1432 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
1433 IBMF_RESP_TIMER);
1434 }
1435
1436 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1437 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1438 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1439 "BAD version detected, dropping MAD");
1440
1441 return;
1442 }
1443
1444 /* abort with status BadT */
1445 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
1446 IBMF_RMPP_STATUS_UNV, 0, 0, IBMF_NO_BLOCK);
1447 if (status != IBMF_SUCCESS) {
1448 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
1449 ibmf_i_handle_rmpp_err, IBMF_TNF_ERROR, "",
1450 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1451 "RMPP ABORT send failed");
1452 msgimplp->im_trans_state_flags |=
1453 IBMF_TRANS_STATE_FLAG_SEND_DONE;
1454 }
1455
1456 mutex_enter(&clientp->ic_kstat_mutex);
1457 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
1458 mutex_exit(&clientp->ic_kstat_mutex);
1459
1460 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1461 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1462 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1463 "Unsupported RMPP version detected, sending ABORT UNV");
1464
1465 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1466 ibmf_i_handle_rmpp_end, IBMF_TNF_TRACE, "",
1467 "ibmf_i_handle_rmpp() exit\n");
1468
1469 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1470
1471 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1472
1473 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1474 msgimplp, IBMF_RESP_TIMER);
1475
1476 return;
1477 }
1478
1479 /*
1480 * Check for a valid status in the RMPP header
1481 */
1482 if (ibmf_i_is_valid_rmpp_status(rmpp_hdr) != B_TRUE) {
1483
1484 /*
1485 * If the receive buffer is not yet allocated, this is
1486 * probably the first MAD received for the receive context.
1487 * We need to set up the receive buffer before calling
1488 * ibmf_i_send_rmpp() to send an ABORT packet.
1489 */
1490 if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
1491 status = ibmf_setup_recvbuf_on_error(msgimplp, madp);
1492 if (status != IBMF_SUCCESS) {
1493 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
1494 ibmf_i_handle_rmpp_err, IBMF_TNF_ERROR, "",
1495 "ibmf_i_handle_rmpp(): %s\n", tnf_string,
1496 msg,
1497 "ibmf_setup_recvbuf_on_error() failed");
1498 return;
1499 }
1500 }
1501
1502 /*
1503 * Drop the message if the transaction has not yet
1504 * been identified as a send or receive RMPP transaction.
1505 * This is because the send completion of an abort packet
1506 * will hit the non-rmpp code which attempts to reset the
1507 * RESP timer set after sending the abort packet, causing
1508 * an assert.
1509 */
1510 if (((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) == 0) &&
1511 (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP) == 0) {
1512 /*
1513 * Reset the response timer since we're still
1514 * waiting for the first response MAD, provided
1515 * that the send completion has occured
1516 */
1517 if (msgimplp->im_trans_state_flags &
1518 IBMF_TRANS_STATE_FLAG_SEND_DONE) {
1519 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
1520 IBMF_RESP_TIMER);
1521 }
1522
1523 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1524 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1525 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1526 "Invalid RMPP status detected, dropping MAD");
1527
1528 return;
1529 }
1530
1531 /* abort with status BadT */
1532 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
1533 IBMF_RMPP_STATUS_IS, 0, 0, IBMF_NO_BLOCK);
1534 if (status != IBMF_SUCCESS) {
1535 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
1536 ibmf_i_handle_rmpp_err, IBMF_TNF_ERROR, "",
1537 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1538 "RMPP ABORT send failed");
1539 msgimplp->im_trans_state_flags |=
1540 IBMF_TRANS_STATE_FLAG_SEND_DONE;
1541 }
1542
1543 mutex_enter(&clientp->ic_kstat_mutex);
1544 IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
1545 mutex_exit(&clientp->ic_kstat_mutex);
1546
1547 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
1548 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1549 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1550 "Invalid RMPP status detected, sending ABORT IS");
1551
1552 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1553 ibmf_i_handle_rmpp_end, IBMF_TNF_TRACE, "",
1554 "ibmf_i_handle_rmpp() exit\n");
1555
1556 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
1557
1558 ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
1559
1560 ibmf_i_set_timer(ibmf_i_err_terminate_timeout,
1561 msgimplp, IBMF_RESP_TIMER);
1562
1563 return;
1564 }
1565
1566 /*
1567 * We could check the MAD here and do an optional abort.
1568 * This abort if the MAD header is bad is not required by the spec.
1569 * Also, we should account for RRespTime here.
1570 */
1571
1572 /*
1573 * The RMPP engine has four execution flow paths corresponding
1574 * to the four states the RMPP state machine can be in at any
1575 * given time. The packet will be dropped if the context is not in any
1576 * of these four states.
1577 */
1578 switch (rmpp_ctx->rmpp_state) {
1579 case IBMF_RMPP_STATE_SENDER_ACTIVE :
1580 ibmf_i_rmpp_sender_active_flow(clientp, qp_hdl, msgimplp, madp);
1581 break;
1582 case IBMF_RMPP_STATE_SENDER_SWITCH :
1583 ibmf_i_rmpp_sender_switch_flow(clientp, qp_hdl, msgimplp, madp);
1584 break;
1585 case IBMF_RMPP_STATE_RECEVR_ACTIVE :
1586 ibmf_i_rmpp_recvr_active_flow(clientp, qp_hdl, msgimplp, madp);
1587 break;
1588 case IBMF_RMPP_STATE_RECEVR_TERMINATE :
1589 ibmf_i_rmpp_recvr_term_flow(clientp, qp_hdl, msgimplp, madp);
1590 break;
1591 default:
1592 /* Including IBMF_RMPP_STATE_ABORT */
1593 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1594 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1595 "ibmf_i_handle_rmpp(): %s, rmpp_state = 0x%x\n",
1596 tnf_string, msg, "Dropping packet",
1597 tnf_opaque, rmpp_state, rmpp_ctx->rmpp_state);
1598
1599 /* Reinitiate the resp timer if the state is ABORT */
1600 if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_ABORT) {
1601 ibmf_i_set_timer(ibmf_i_err_terminate_timeout, msgimplp,
1602 IBMF_RESP_TIMER);
1603
1604 return;
1605 }
1606
1607 /*
1608 * Drop the message if the transaction has not yet
1609 * been identified as a send or receive RMPP transaction.
1610 */
1611 if (((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) == 0) &&
1612 (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP) == 0) {
1613 /*
1614 * Reset the response timer since we're still
1615 * waiting for the first response MAD, provided
1616 * that the send completion has occured
1617 */
1618 if (msgimplp->im_trans_state_flags &
1619 IBMF_TRANS_STATE_FLAG_SEND_DONE) {
1620 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
1621 IBMF_RESP_TIMER);
1622 }
1623
1624 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1625 ibmf_i_handle_rmpp, IBMF_TNF_TRACE, "",
1626 "ibmf_i_handle_rmpp(): %s\n", tnf_string, msg,
1627 "BAD 1st RMPP packet, dropping MAD");
1628
1629 return;
1630 }
1631 }
1632
1633 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1634 ibmf_i_handle_rmpp_end, IBMF_TNF_TRACE, "",
1635 "ibmf_i_handle_rmpp() exit\n");
1636 }
1637
1638 /*
1639 * ibmf_i_send_rmpp():
1640 * ibmf_i_send_rmpp() is called to send any
1641 * type RMPP packet. The RMPP status is passed in as an argument.
1642 * In addition, the segment field and the payload length / new window last
1643 * field are passed in as arguments.
1644 */
1645 int
ibmf_i_send_rmpp(ibmf_msg_impl_t * msgimplp,uint8_t rmpp_type,uint8_t rmpp_status,uint32_t segno,uint32_t nwl,int block)1646 ibmf_i_send_rmpp(ibmf_msg_impl_t *msgimplp, uint8_t rmpp_type,
1647 uint8_t rmpp_status, uint32_t segno, uint32_t nwl, int block)
1648 {
1649 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1650 int status;
1651
1652 IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_start,
1653 IBMF_TNF_TRACE, "",
1654 "ibmf_i_send_rmpp(): msgp = 0x%p, rmpp_type = 0x%x, "
1655 "rmpp_status = %d, segno = %d, nwl = %d\n",
1656 tnf_opaque, msg, msgimplp,
1657 tnf_uint, rmpp_type, rmpp_type,
1658 tnf_uint, rmpp_status, rmpp_status,
1659 tnf_uint, segno, segno,
1660 tnf_uint, nwl, nwl);
1661
1662 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_rmpp,
1663 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp(): msgp = 0x%p, "
1664 "next_seg = 0x%x, num_pkts = %d\n",
1665 tnf_opaque, msg, msgimplp,
1666 tnf_uint, next_seg, msgimplp->im_rmpp_ctx.rmpp_ns,
1667 tnf_uint, num_pkts, msgimplp->im_rmpp_ctx.rmpp_num_pkts);
1668
1669 ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1670
1671 rmpp_ctx->rmpp_type = rmpp_type;
1672 rmpp_ctx->rmpp_status = rmpp_status;
1673 rmpp_ctx->rmpp_word3 = segno;
1674 rmpp_ctx->rmpp_word4 = nwl;
1675
1676 /*
1677 * send packet without blocking
1678 */
1679 status = ibmf_i_send_pkt(msgimplp->im_client, msgimplp->im_qp_hdl,
1680 msgimplp, block);
1681 if (status != IBMF_SUCCESS) {
1682 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1683 ibmf_i_send_rmpp_err, IBMF_TNF_ERROR, "",
1684 "ibmf_i_send_rmpp(): %s, status = %d\n", tnf_string, msg,
1685 "unable to send packet", tnf_uint, status, status);
1686 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_end,
1687 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp() exit\n");
1688 return (status);
1689 }
1690
1691 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_end,
1692 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp() exit\n");
1693
1694 return (IBMF_SUCCESS);
1695 }
1696
1697 /*
1698 * ibmf_i_send_rmpp_window():
1699 * Send an RMPP protocol window of packets
1700 */
1701 void
ibmf_i_send_rmpp_window(ibmf_msg_impl_t * msgimplp,int block)1702 ibmf_i_send_rmpp_window(ibmf_msg_impl_t *msgimplp, int block)
1703 {
1704 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1705 int status, i, numpkts = rmpp_ctx->rmpp_wl - rmpp_ctx->rmpp_ns + 1;
1706 uint32_t payload_length, cl_hdr_sz, cl_hdr_off;
1707
1708 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_window_start,
1709 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp_window(): msgp = 0x%p\n",
1710 tnf_opaque, msg, msgimplp);
1711
1712 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_rmpp_window,
1713 IBMF_TNF_TRACE, "", "ibmf_i_handle_rmpp(): wl = %d "
1714 "ns = %d, num_pkts = %d\n", tnf_uint, wl, rmpp_ctx->rmpp_wl,
1715 tnf_uint, ns, rmpp_ctx->rmpp_ns, tnf_uint, num_pkts,
1716 rmpp_ctx->rmpp_num_pkts);
1717
1718 ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1719
1720 ibmf_i_mgt_class_to_hdr_sz_off(
1721 msgimplp->im_msgbufs_send.im_bufs_mad_hdr->MgmtClass,
1722 &cl_hdr_sz, &cl_hdr_off);
1723
1724 for (i = 1; i <= numpkts; i++) {
1725
1726 if (rmpp_ctx->rmpp_ns == 1)
1727 payload_length = rmpp_ctx->rmpp_pyld_len +
1728 (rmpp_ctx->rmpp_num_pkts * cl_hdr_sz);
1729 else if (rmpp_ctx->rmpp_ns == rmpp_ctx->rmpp_num_pkts)
1730 payload_length = rmpp_ctx->rmpp_last_pkt_sz + cl_hdr_sz;
1731 else
1732 payload_length = rmpp_ctx->rmpp_pkt_data_sz;
1733
1734 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_rmpp_window,
1735 IBMF_TNF_TRACE, "", "ibmf_i_handle_rmpp(): ns = %d, "
1736 "pl = %d\n", tnf_uint, ns, rmpp_ctx->rmpp_ns,
1737 tnf_uint, pl, payload_length);
1738
1739 status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_DATA,
1740 IBMF_RMPP_STATUS_NORMAL, rmpp_ctx->rmpp_ns, payload_length,
1741 block);
1742 if (status != IBMF_SUCCESS) {
1743
1744 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1745 ibmf_i_send_rmpp_window_err, IBMF_TNF_ERROR, "",
1746 "ibmf_i_send_rmpp_window(): %s\n", tnf_string, msg,
1747 "Send rmpp window failed");
1748 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1749 ibmf_i_send_rmpp_window_end, IBMF_TNF_TRACE, "",
1750 "ibmf_i_send_rmpp_window() exit\n");
1751 return;
1752 }
1753
1754 rmpp_ctx->rmpp_ns++;
1755
1756 rmpp_ctx->rmpp_data_offset += rmpp_ctx->rmpp_pkt_data_sz;
1757 }
1758
1759 /* Set the response timer */
1760 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_rmpp_window,
1761 IBMF_TNF_TRACE, "", "ibmf_i_handle_rmpp(): setting timer %p %d\n",
1762 tnf_opaque, msgimplp, msgimplp, tnf_opaque, timeout_id,
1763 msgimplp->im_rp_timeout_id);
1764
1765 ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp, IBMF_RESP_TIMER);
1766
1767 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_window_end,
1768 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp_window() exit\n");
1769 }
1770
1771 /*
1772 * ibmf_i_send_rmpp_pkts():
1773 * Send a message using the RMPP protocol
1774 */
1775 int
ibmf_i_send_rmpp_pkts(ibmf_client_t * clientp,ibmf_qp_handle_t ibmf_qp_handle,ibmf_msg_impl_t * msgimplp,boolean_t isDS,int block)1776 ibmf_i_send_rmpp_pkts(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
1777 ibmf_msg_impl_t *msgimplp, boolean_t isDS, int block)
1778 {
1779 ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
1780 size_t buf_sz = msgimplp->im_msgbufs_send.im_bufs_cl_data_len;
1781 uint32_t num_pkts, resid;
1782 uint32_t cl_hdr_sz, cl_data_sz, cl_hdr_off;
1783
1784 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_pkts_start,
1785 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp_pkts(): clientp = 0x%p, "
1786 "qphdl = 0x%p, msgp = 0x%p, block = %d\n",
1787 tnf_opaque, clientp, clientp, tnf_opaque, qphdl, ibmf_qp_handle,
1788 tnf_opaque, msg, msgimplp, tnf_uint, block, block);
1789
1790 ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1791
1792 ibmf_i_mgt_class_to_hdr_sz_off(
1793 msgimplp->im_msgbufs_send.im_bufs_mad_hdr->MgmtClass,
1794 &cl_hdr_sz, &cl_hdr_off);
1795
1796 cl_data_sz = MAD_SIZE_IN_BYTES - sizeof (ib_mad_hdr_t) - cl_hdr_off -
1797 cl_hdr_sz;
1798
1799 if ((resid = (buf_sz % cl_data_sz)) != 0)
1800 num_pkts = (buf_sz / cl_data_sz) + 1;
1801 else {
1802 if (buf_sz > 0)
1803 num_pkts = buf_sz / cl_data_sz;
1804 else
1805 num_pkts = 1;
1806 }
1807
1808 rmpp_ctx->rmpp_wf = 1;
1809 rmpp_ctx->rmpp_wl = 1;
1810 rmpp_ctx->rmpp_ns = 1;
1811 rmpp_ctx->rmpp_is_ds = isDS;
1812 rmpp_ctx->rmpp_pyld_len = buf_sz;
1813 rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_SENDER_ACTIVE;
1814 rmpp_ctx->rmpp_type = IBMF_RMPP_TYPE_DATA;
1815 rmpp_ctx->rmpp_respt = IBMF_RMPP_TERM_RRESPT;
1816 rmpp_ctx->rmpp_status = IBMF_RMPP_STATUS_NORMAL;
1817 rmpp_ctx->rmpp_num_pkts = num_pkts;
1818 rmpp_ctx->rmpp_pkt_data_sz =
1819 (buf_sz < cl_data_sz) ? buf_sz : cl_data_sz;
1820 rmpp_ctx->rmpp_last_pkt_sz =
1821 (resid == 0) ? ((buf_sz == 0) ? 0 : cl_data_sz) : resid;
1822 rmpp_ctx->rmpp_data_offset = 0;
1823
1824 ibmf_i_send_rmpp_window(msgimplp, block);
1825
1826 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_rmpp_pkts_end,
1827 IBMF_TNF_TRACE, "", "ibmf_i_send_rmpp_pkts() exit\n");
1828
1829 return (IBMF_SUCCESS);
1830 }
1831