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