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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This file implements the MAD send logic in IBMF.
31 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
33 #define IBMF_SEND_WR_ID_TO_ADDR(id, ptr) \
34 (ptr) = (void *)(uintptr_t)(id)
36 extern int ibmf_trace_level
;
38 static void ibmf_i_do_send_cb(void *taskq_arg
);
39 static void ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle
,
40 ibmf_msg_impl_t
*msgimplp
, ibmf_send_wqe_t
*send_wqep
);
44 * Post an IB packet on the specified QP's send queue
47 ibmf_i_issue_pkt(ibmf_client_t
*clientp
, ibmf_msg_impl_t
*msgimplp
,
48 ibmf_qp_handle_t ibmf_qp_handle
, ibmf_send_wqe_t
*send_wqep
)
53 ibt_qp_hdl_t ibt_qp_handle
;
55 _NOTE(ASSUMING_PROTECTED(*send_wqep
))
56 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep
))
58 IBMF_TRACE_4(DPRINT_L4
,
59 "ibmf_i_issue_pkt() enter, clientp = %p, msg = %p, ""qp_hdl = %p, swqep = %p\n",
65 ASSERT(MUTEX_HELD(&msgimplp
->im_mutex
));
66 ASSERT(MUTEX_NOT_HELD(&clientp
->ic_mutex
));
69 * if the qp handle provided in ibmf_send_pkt()
70 * is not the default qp handle for this client,
71 * then the wqe must be sent on this qp,
72 * else use the default qp handle set up during ibmf_register()
74 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
75 ibt_qp_handle
= clientp
->ic_qp
->iq_qp_handle
;
78 ((ibmf_alt_qp_t
*)ibmf_qp_handle
)->isq_qp_handle
;
81 /* initialize the send WQE */
82 ibmf_i_init_send_wqe(clientp
, msgimplp
, sgl
, send_wqep
,
83 msgimplp
->im_ud_dest
, ibt_qp_handle
, ibmf_qp_handle
);
85 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep
))
88 * Issue the wqe to the transport.
89 * NOTE: ibt_post_send() will not block, so, it is ok
90 * to hold the msgimpl mutex across this call.
92 status
= ibt_post_send(send_wqep
->send_qp_handle
, &send_wqep
->send_wr
,
94 if (status
!= IBT_SUCCESS
) {
95 mutex_enter(&clientp
->ic_kstat_mutex
);
96 IBMF_ADD32_KSTATS(clientp
, send_pkt_failed
, 1);
97 mutex_exit(&clientp
->ic_kstat_mutex
);
98 IBMF_TRACE_2(DPRINT_L1
,
99 "ibmf_i_issue_pkt(): %s, status = %d\n",
102 return (IBMF_TRANSPORT_FAILURE
);
107 /* bump the number of active sends */
108 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
109 mutex_enter(&clientp
->ic_mutex
);
110 clientp
->ic_sends_active
++;
111 mutex_exit(&clientp
->ic_mutex
);
112 mutex_enter(&clientp
->ic_kstat_mutex
);
113 IBMF_ADD32_KSTATS(clientp
, sends_active
, 1);
114 mutex_exit(&clientp
->ic_kstat_mutex
);
116 ibmf_alt_qp_t
*qpp
= (ibmf_alt_qp_t
*)ibmf_qp_handle
;
117 mutex_enter(&qpp
->isq_mutex
);
118 qpp
->isq_sends_active
++;
119 mutex_exit(&qpp
->isq_mutex
);
120 mutex_enter(&clientp
->ic_kstat_mutex
);
121 IBMF_ADD32_KSTATS(clientp
, sends_active
, 1);
122 mutex_exit(&clientp
->ic_kstat_mutex
);
130 * Send an IB packet after allocating send resources
133 ibmf_i_send_pkt(ibmf_client_t
*clientp
, ibmf_qp_handle_t ibmf_qp_handle
,
134 ibmf_msg_impl_t
*msgimplp
, int block
)
136 ibmf_send_wqe_t
*send_wqep
;
139 IBMF_TRACE_4(DPRINT_L4
,
140 "ibmf_i_send_pkt(): clientp = 0x%p, qp_hdl = 0x%p, ""msgp = 0x%p, block = %d\n",
146 ASSERT(MUTEX_HELD(&msgimplp
->im_mutex
));
148 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep
))
151 * Reset send_done to indicate we have not received the completion
154 msgimplp
->im_trans_state_flags
&= ~IBMF_TRANS_STATE_FLAG_SEND_DONE
;
157 * Allocate resources needed to send a UD packet including the
160 status
= ibmf_i_alloc_send_resources(clientp
->ic_myci
,
161 msgimplp
, block
, &send_wqep
);
162 if (status
!= IBMF_SUCCESS
) {
163 IBMF_TRACE_2(DPRINT_L1
,
164 "ibmf_i_send_pkt(): %s, status = %d\n",
165 "unable to allocate send resources",
170 /* Set the segment number in the send WQE context */
171 if (msgimplp
->im_flags
& IBMF_MSG_FLAGS_SEND_RMPP
)
172 send_wqep
->send_rmpp_segment
= msgimplp
->im_rmpp_ctx
.rmpp_ns
;
174 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep
))
177 * Increment the count of pending send completions.
178 * Only when this count is zero should the client be notified
179 * of completion of the transaction.
181 msgimplp
->im_pending_send_compls
+= 1;
183 /* Send the packet */
184 status
= ibmf_i_issue_pkt(clientp
, msgimplp
, ibmf_qp_handle
, send_wqep
);
185 if (status
!= IBMF_SUCCESS
) {
186 ibmf_i_free_send_resources(clientp
->ic_myci
, msgimplp
,
188 IBMF_TRACE_2(DPRINT_L1
,
189 "ibmf_i_send_pkt(): %s, status = %d\n",
190 "unable to issue packet",
195 return (IBMF_SUCCESS
);
199 * ibmf_i_send_single_pkt():
200 * Send a single IB packet. Only used to send non-RMPP packets.
203 ibmf_i_send_single_pkt(ibmf_client_t
*clientp
, ibmf_qp_handle_t ibmf_qp_handle
,
204 ibmf_msg_impl_t
*msgimplp
, int block
)
208 IBMF_TRACE_4(DPRINT_L4
,
209 "ibmf_i_send_single_pkt(): clientp = 0x%p, qp_hdl = 0x%p, ""msgp = 0x%p, block = %d\n",
215 ASSERT(MUTEX_HELD(&msgimplp
->im_mutex
));
217 status
= ibmf_i_send_pkt(clientp
, ibmf_qp_handle
, msgimplp
, block
);
218 if (status
!= IBMF_SUCCESS
) {
219 IBMF_TRACE_2(DPRINT_L1
,
220 "ibmf_i_send_single_pkt(): %s, msgp = 0x%p\n",
221 "unable to send packet",
226 return (IBMF_SUCCESS
);
230 * ibmf_i_handle_send_completion():
231 * Process the WQE from the SQ identified in the work completion entry.
235 ibmf_i_handle_send_completion(ibmf_ci_t
*cip
, ibt_wc_t
*wcp
)
237 ibmf_client_t
*clientp
, *cclientp
;
238 ibmf_send_wqe_t
*send_wqep
;
239 ibmf_qp_handle_t ibmf_qp_handle
;
243 IBMF_TRACE_2(DPRINT_L4
,
244 "ibmf_i_handle_send_completion() enter, cip = %p, wcp = %p\n",
248 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep
))
250 ASSERT(wcp
->wc_id
!= (uintptr_t)NULL
);
252 ASSERT(IBMF_IS_SEND_WR_ID(wcp
->wc_id
));
254 /* get the IBMF send WQE context */
255 IBMF_SEND_WR_ID_TO_ADDR(wcp
->wc_id
, send_wqep
);
257 ASSERT(send_wqep
!= NULL
);
259 /* get the client context */
260 cclientp
= clientp
= send_wqep
->send_client
;
262 /* Check if this is a completion for a BUSY MAD sent by IBMF */
263 if (clientp
== NULL
) {
264 ibmf_msg_impl_t
*msgimplp
;
266 IBMF_TRACE_0(DPRINT_L3
,
267 "ibmf_i_handle_send_completion(): NULL client\n");
269 msgimplp
= send_wqep
->send_msg
;
272 * Deregister registered memory and free it, and
273 * free up the send WQE context
275 (void) ibt_deregister_mr(cip
->ci_ci_handle
,
276 send_wqep
->send_mem_hdl
);
277 kmem_free(send_wqep
->send_mem
, IBMF_MEM_PER_WQE
);
278 kmem_free(send_wqep
, sizeof (ibmf_send_wqe_t
));
280 /* Free up the message context */
281 ibmf_i_put_ud_dest(cip
, msgimplp
->im_ibmf_ud_dest
);
282 ibmf_i_clean_ud_dest_list(cip
, B_FALSE
);
283 kmem_free(msgimplp
, sizeof (ibmf_msg_impl_t
));
287 /* get the QP handle */
288 ibmf_qp_handle
= send_wqep
->send_ibmf_qp_handle
;
289 qpp
= (ibmf_alt_qp_t
*)ibmf_qp_handle
;
291 ASSERT(clientp
!= NULL
);
293 /* decrement the number of active sends */
294 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
295 mutex_enter(&clientp
->ic_mutex
);
296 clientp
->ic_sends_active
--;
297 mutex_exit(&clientp
->ic_mutex
);
299 mutex_enter(&qpp
->isq_mutex
);
300 qpp
->isq_sends_active
--;
301 mutex_exit(&qpp
->isq_mutex
);
304 mutex_enter(&clientp
->ic_kstat_mutex
);
305 IBMF_SUB32_KSTATS(clientp
, sends_active
, 1);
306 mutex_exit(&clientp
->ic_kstat_mutex
);
308 send_wqep
->send_status
= ibmf_i_ibt_wc_to_ibmf_status(wcp
->wc_status
);
311 * issue the callback using taskq. If no taskq or if the
312 * dispatch fails, we do the send processing in the callback context
313 * which is the interrupt context
315 if (cclientp
->ic_send_taskq
== NULL
) {
316 /* Do the processing in callback context */
317 mutex_enter(&clientp
->ic_kstat_mutex
);
318 IBMF_ADD32_KSTATS(clientp
, send_cb_active
, 1);
319 mutex_exit(&clientp
->ic_kstat_mutex
);
320 ibmf_i_do_send_cb((void *)send_wqep
);
321 mutex_enter(&clientp
->ic_kstat_mutex
);
322 IBMF_SUB32_KSTATS(clientp
, send_cb_active
, 1);
323 mutex_exit(&clientp
->ic_kstat_mutex
);
327 mutex_enter(&clientp
->ic_kstat_mutex
);
328 IBMF_ADD32_KSTATS(clientp
, send_cb_active
, 1);
329 mutex_exit(&clientp
->ic_kstat_mutex
);
331 /* Use taskq for processing if the IBMF_REG_FLAG_NO_OFFLOAD isn't set */
332 if ((clientp
->ic_reg_flags
& IBMF_REG_FLAG_NO_OFFLOAD
) == 0) {
333 ret
= taskq_dispatch(cclientp
->ic_send_taskq
, ibmf_i_do_send_cb
,
334 send_wqep
, TQ_NOSLEEP
);
336 IBMF_TRACE_1(DPRINT_L4
,
337 "ibmf_i_handle_send_completion(): %s\n",
338 "send: dispatch failed");
339 ibmf_i_do_send_cb((void *)send_wqep
);
342 ibmf_i_do_send_cb((void *)send_wqep
);
345 mutex_enter(&clientp
->ic_kstat_mutex
);
346 IBMF_SUB32_KSTATS(clientp
, send_cb_active
, 1);
347 mutex_exit(&clientp
->ic_kstat_mutex
);
349 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep
))
353 * ibmf_i_do_send_cb():
354 * Do the send completion processing
357 ibmf_i_do_send_cb(void *taskq_arg
)
360 ibmf_msg_impl_t
*msgimplp
;
361 ibmf_client_t
*clientp
;
362 ibmf_send_wqe_t
*send_wqep
;
364 int msg_trans_state_flags
, msg_flags
;
366 ibmf_qp_handle_t ibmf_qp_handle
;
367 struct kmem_cache
*kmem_cachep
;
368 timeout_id_t msg_rp_unset_id
, msg_tr_unset_id
;
369 timeout_id_t msg_rp_set_id
, msg_tr_set_id
;
370 ibmf_alt_qp_t
*altqp
;
371 boolean_t inc_refcnt
;
373 send_wqep
= taskq_arg
;
375 IBMF_TRACE_1(DPRINT_L4
,
376 "ibmf_i_do_send_cb() enter, send_wqep = %p\n", send_wqep
);
378 clientp
= send_wqep
->send_client
;
379 cip
= clientp
->ic_myci
;
380 msgimplp
= send_wqep
->send_msg
;
382 /* get the QP handle */
383 ibmf_qp_handle
= send_wqep
->send_ibmf_qp_handle
;
385 /* Get the WQE kmem cache pointer based on the QP type */
386 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
)
387 kmem_cachep
= cip
->ci_send_wqes_cache
;
389 altqp
= (ibmf_alt_qp_t
*)ibmf_qp_handle
;
390 kmem_cachep
= altqp
->isq_send_wqes_cache
;
393 /* Look for a message in the client's message list */
395 found
= ibmf_i_find_msg_client(clientp
, msgimplp
, inc_refcnt
);
398 * If the message context was not found, then it's likely
399 * been freed up. So, do nothing in this timeout handler
401 if (found
== B_FALSE
) {
402 kmem_cache_free(kmem_cachep
, send_wqep
);
403 mutex_enter(&cip
->ci_mutex
);
404 IBMF_SUB32_PORT_KSTATS(cip
, send_wqes_alloced
, 1);
405 mutex_exit(&cip
->ci_mutex
);
406 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
407 mutex_enter(&cip
->ci_mutex
);
408 cip
->ci_wqes_alloced
--;
409 if (cip
->ci_wqes_alloced
== 0)
410 cv_signal(&cip
->ci_wqes_cv
);
411 mutex_exit(&cip
->ci_mutex
);
413 mutex_enter(&altqp
->isq_mutex
);
414 altqp
->isq_wqes_alloced
--;
415 if (altqp
->isq_wqes_alloced
== 0)
416 cv_signal(&altqp
->isq_wqes_cv
);
417 mutex_exit(&altqp
->isq_mutex
);
419 IBMF_TRACE_1(DPRINT_L3
, "ibmf_i_do_send_cb(): %s\n",
420 "Message not found, return without processing send cb");
424 /* Grab the message context lock */
425 mutex_enter(&msgimplp
->im_mutex
);
428 * Decrement the count of pending send completions for
431 msgimplp
->im_pending_send_compls
-= 1;
434 * If the pending send completions is not zero, then we must
435 * not attempt to notify the client of a transaction completion
436 * in this instance of the send completion handler. Notification
437 * of transaction completion should be provided only by the
438 * last send completion so that all send completions are accounted
439 * for before the client is notified and subsequently attempts to
440 * reuse the message for an other transaction.
441 * If this is not done, the message may be reused while the
442 * send WR from the old transaction is still active in the QP's WQ.
443 * This could result in an attempt to modify the address handle with
444 * information for the new transaction which could be potentially
445 * incompatible, such as an incorrect port number. Such an
446 * incompatible modification of the address handle of the old
447 * transaction could result in a QP error.
449 if (msgimplp
->im_pending_send_compls
!= 0) {
450 IBMF_MSG_DECR_REFCNT(msgimplp
);
451 mutex_exit(&msgimplp
->im_mutex
);
452 kmem_cache_free(kmem_cachep
, send_wqep
);
453 mutex_enter(&cip
->ci_mutex
);
454 IBMF_SUB32_PORT_KSTATS(cip
, send_wqes_alloced
, 1);
455 mutex_exit(&cip
->ci_mutex
);
456 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
457 mutex_enter(&cip
->ci_mutex
);
458 cip
->ci_wqes_alloced
--;
459 if (cip
->ci_wqes_alloced
== 0)
460 cv_signal(&cip
->ci_wqes_cv
);
461 mutex_exit(&cip
->ci_mutex
);
463 mutex_enter(&altqp
->isq_mutex
);
464 altqp
->isq_wqes_alloced
--;
465 if (altqp
->isq_wqes_alloced
== 0)
466 cv_signal(&altqp
->isq_wqes_cv
);
467 mutex_exit(&altqp
->isq_mutex
);
469 IBMF_TRACE_1(DPRINT_L3
, "ibmf_i_do_send_cb(): %s\n",
470 "Message found with pending send completions, ""return without processing send cb");
475 * If the message has been marked unitialized or done
476 * release the message mutex and return
478 if ((msgimplp
->im_trans_state_flags
& IBMF_TRANS_STATE_FLAG_UNINIT
) ||
479 (msgimplp
->im_trans_state_flags
& IBMF_TRANS_STATE_FLAG_DONE
)) {
480 IBMF_MSG_DECR_REFCNT(msgimplp
);
481 msg_trans_state_flags
= msgimplp
->im_trans_state_flags
;
482 msg_flags
= msgimplp
->im_flags
;
483 ref_cnt
= msgimplp
->im_ref_count
;
484 mutex_exit(&msgimplp
->im_mutex
);
486 * This thread may notify the client only if the
487 * transaction is done, the message has been removed
488 * from the client's message list, and the message
489 * reference count is 0.
490 * If the transaction is done, and the message reference
491 * count = 0, there is still a possibility that a
492 * packet could arrive for the message and its reference
493 * count increased if the message is still on the list.
494 * If the message is still on the list, it will be
495 * removed by a call to ibmf_i_client_rem_msg() at
496 * the completion point of the transaction.
497 * So, the reference count should be checked after the
498 * message has been removed.
500 if ((msg_trans_state_flags
& IBMF_TRANS_STATE_FLAG_DONE
) &&
501 !(msg_flags
& IBMF_MSG_FLAGS_ON_LIST
) &&
504 ibmf_i_notify_sequence(clientp
, msgimplp
, msg_flags
);
507 kmem_cache_free(kmem_cachep
, send_wqep
);
508 mutex_enter(&cip
->ci_mutex
);
509 IBMF_SUB32_PORT_KSTATS(cip
, send_wqes_alloced
, 1);
510 mutex_exit(&cip
->ci_mutex
);
511 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
512 mutex_enter(&cip
->ci_mutex
);
513 cip
->ci_wqes_alloced
--;
514 if (cip
->ci_wqes_alloced
== 0)
515 cv_signal(&cip
->ci_wqes_cv
);
516 mutex_exit(&cip
->ci_mutex
);
518 mutex_enter(&altqp
->isq_mutex
);
519 altqp
->isq_wqes_alloced
--;
520 if (altqp
->isq_wqes_alloced
== 0)
521 cv_signal(&altqp
->isq_wqes_cv
);
522 mutex_exit(&altqp
->isq_mutex
);
524 IBMF_TRACE_2(DPRINT_L3
,
525 "ibmf_i_do_send_cb(): %s, msg = %p\n",
526 "Message marked for removal, return without processing ""send cb",
531 /* Perform send completion processing of the message context */
532 ibmf_i_do_send_compl((ibmf_handle_t
)clientp
, msgimplp
, send_wqep
);
534 msg_rp_unset_id
= msg_tr_unset_id
= msg_rp_set_id
= msg_tr_set_id
= 0;
536 /* Save the message flags before releasing the mutex */
537 msg_trans_state_flags
= msgimplp
->im_trans_state_flags
;
538 msg_flags
= msgimplp
->im_flags
;
539 msg_rp_unset_id
= msgimplp
->im_rp_unset_timeout_id
;
540 msg_tr_unset_id
= msgimplp
->im_tr_unset_timeout_id
;
541 msgimplp
->im_rp_unset_timeout_id
= 0;
542 msgimplp
->im_tr_unset_timeout_id
= 0;
545 * Decrement the message reference count
546 * This count was inceremented when the message was found on the
547 * client's message list
549 IBMF_MSG_DECR_REFCNT(msgimplp
);
551 if (msg_trans_state_flags
& IBMF_TRANS_STATE_FLAG_DONE
) {
552 if (msgimplp
->im_rp_timeout_id
!= 0) {
553 msg_rp_set_id
= msgimplp
->im_rp_timeout_id
;
554 msgimplp
->im_rp_timeout_id
= 0;
556 if (msgimplp
->im_tr_timeout_id
!= 0) {
557 msg_tr_set_id
= msgimplp
->im_tr_timeout_id
;
558 msgimplp
->im_tr_timeout_id
= 0;
562 mutex_exit(&msgimplp
->im_mutex
);
564 if (msg_rp_unset_id
!= 0) {
565 (void) untimeout(msg_rp_unset_id
);
568 if (msg_tr_unset_id
!= 0) {
569 (void) untimeout(msg_tr_unset_id
);
572 if (msg_rp_set_id
!= 0) {
573 (void) untimeout(msg_rp_set_id
);
576 if (msg_tr_set_id
!= 0) {
577 (void) untimeout(msg_tr_set_id
);
580 IBMF_TRACE_2(DPRINT_L3
, "ibmf_i_do_send_cb(): %s, msg = %p\n",
581 "Send callback done. Dec ref count", msgimplp
);
584 * If the transaction is done, signal the block thread if the
585 * transaction is blocking, or call the client's transaction done
586 * notification callback
588 if (msg_trans_state_flags
& IBMF_TRANS_STATE_FLAG_DONE
) {
590 /* Remove the message from the client's message list */
591 ibmf_i_client_rem_msg(clientp
, msgimplp
, &ref_cnt
);
594 * Notify the client if the message reference count is zero.
595 * At this point, we know that the transaction is done and
596 * the message has been removed from the client's message list.
597 * So, we only need to make sure the reference count is zero
598 * before notifying the client.
602 ibmf_i_notify_sequence(clientp
, msgimplp
, msg_flags
);
607 kmem_cache_free(kmem_cachep
, send_wqep
);
608 mutex_enter(&cip
->ci_mutex
);
609 IBMF_SUB32_PORT_KSTATS(cip
, send_wqes_alloced
, 1);
610 mutex_exit(&cip
->ci_mutex
);
611 if (ibmf_qp_handle
== IBMF_QP_HANDLE_DEFAULT
) {
612 mutex_enter(&cip
->ci_mutex
);
613 cip
->ci_wqes_alloced
--;
614 if (cip
->ci_wqes_alloced
== 0)
615 cv_signal(&cip
->ci_wqes_cv
);
616 mutex_exit(&cip
->ci_mutex
);
618 mutex_enter(&altqp
->isq_mutex
);
619 altqp
->isq_wqes_alloced
--;
620 if (altqp
->isq_wqes_alloced
== 0)
621 cv_signal(&altqp
->isq_wqes_cv
);
622 mutex_exit(&altqp
->isq_mutex
);
627 * ibmf_i_do_send_compl():
628 * Determine if the transaction is complete
632 ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle
, ibmf_msg_impl_t
*msgimplp
,
633 ibmf_send_wqe_t
*send_wqep
)
635 IBMF_TRACE_4(DPRINT_L4
,
636 "ibmf_i_do_send_compl(): ibmf_hdl = 0x%p ""msgp = %p, send_wqep = 0x%p, msg_flags = 0x%x\n",
642 ASSERT(MUTEX_HELD(&msgimplp
->im_mutex
));
645 * For RMPP transactions, we only care about the final packet of the
646 * transaction. For others, the code does not need to wait for the send
647 * completion (although bad things can happen if it never occurs).
648 * The final packets of a transaction are sent when the state is either
649 * ABORT or RECEVR_TERMINATE.
650 * Don't mark the transaction as send_done if there are still more
651 * packets to be sent, including doing the second part of a double-sided
654 if ((msgimplp
->im_flags
& IBMF_MSG_FLAGS_RECV_RMPP
) ||
655 (msgimplp
->im_flags
& IBMF_MSG_FLAGS_SEND_RMPP
)) {
657 IBMF_TRACE_3(DPRINT_L3
,
658 "ibmf_i_do_send_compl(): %s msgp = %p, rmpp_state = 0x%x\n",
659 "Received send callback for RMPP trans",
661 msgimplp
->im_rmpp_ctx
.rmpp_state
);
664 * For ABORT state, we should not return control to
665 * the client from the send completion handler.
666 * Control should be returned in the error timeout handler.
668 * The exception is when the IBMF_TRANS_STATE_FLAG_RECV_DONE
669 * flag has already been set. This flag is set when
670 * ibmf_i_terminate_transaction is called from one of the
671 * three timeout handlers. In this case return control from
674 if (msgimplp
->im_rmpp_ctx
.rmpp_state
== IBMF_RMPP_STATE_ABORT
) {
675 msgimplp
->im_trans_state_flags
|=
676 IBMF_TRANS_STATE_FLAG_SEND_DONE
;
677 if (msgimplp
->im_trans_state_flags
&
678 IBMF_TRANS_STATE_FLAG_RECV_DONE
) {
679 msgimplp
->im_trans_state_flags
|=
680 IBMF_TRANS_STATE_FLAG_DONE
;
684 if ((msgimplp
->im_rmpp_ctx
.rmpp_state
==
685 IBMF_RMPP_STATE_RECEVR_TERMINATE
) ||
686 (msgimplp
->im_rmpp_ctx
.rmpp_state
==
687 IBMF_RMPP_STATE_DONE
)) {
688 msgimplp
->im_trans_state_flags
|=
689 IBMF_TRANS_STATE_FLAG_SEND_DONE
;
690 if (msgimplp
->im_trans_state_flags
&
691 IBMF_TRANS_STATE_FLAG_RECV_DONE
) {
692 msgimplp
->im_trans_state_flags
|=
693 IBMF_TRANS_STATE_FLAG_DONE
;
698 * If the transaction is a send-only RMPP, then
699 * set the SEND_DONE flag on every send completion
700 * as long as there are no outstanding ones.
701 * This is needed so that the transaction can return
702 * in the receive path, where ibmf_i_terminate_transaction
703 * is called from ibmf_i_rmpp_sender_active_flow,
704 * after checking if the SEND_DONE flag is set.
705 * When a new MAD is sent as part of the RMPP transaction,
706 * the SEND_DONE flag will get reset.
707 * The RECV_DONE indicates that the last ACK was received.
709 if ((msgimplp
->im_flags
& IBMF_MSG_FLAGS_SEQUENCED
) == 0) {
710 if (msgimplp
->im_pending_send_compls
== 0) {
711 msgimplp
->im_trans_state_flags
|=
712 IBMF_TRANS_STATE_FLAG_SEND_DONE
;
713 if (msgimplp
->im_trans_state_flags
&
714 IBMF_TRANS_STATE_FLAG_RECV_DONE
) {
715 msgimplp
->im_trans_state_flags
|=
716 IBMF_TRANS_STATE_FLAG_DONE
;
725 * Only non-RMPP send completion gets here.
726 * If the send is a single-packet send that does not use RMPP, and if
727 * the transaction is not a sequenced transaction, call the transaction
728 * callback handler after flagging the transaction as done. If the
729 * message is sequenced, start a timer to bound the wait for the first
730 * data packet of the response.
732 if (msgimplp
->im_flags
& IBMF_MSG_FLAGS_SEQUENCED
) {
734 IBMF_TRACE_2(DPRINT_L3
,
735 "ibmf_i_do_send_compl(): %s msgp = %p\n",
736 "Sequenced transaction, setting response timer",
740 * Check if the send completion already occured,
741 * which could imply that this is a send completion
742 * for some previous transaction that has come in very late.
743 * In this case exit here.
745 if (msgimplp
->im_trans_state_flags
&
746 IBMF_TRANS_STATE_FLAG_SEND_DONE
) {
750 /* mark as send_compl happened */
751 msgimplp
->im_trans_state_flags
|=
752 IBMF_TRANS_STATE_FLAG_SEND_DONE
;
754 if (msgimplp
->im_trans_state_flags
&
755 IBMF_TRANS_STATE_FLAG_RECV_DONE
) {
756 msgimplp
->im_trans_state_flags
|=
757 IBMF_TRANS_STATE_FLAG_DONE
;
762 * check if response was received before send
765 if (((msgimplp
->im_trans_state_flags
&
766 IBMF_TRANS_STATE_FLAG_DONE
) == 0) &&
767 ((msgimplp
->im_trans_state_flags
&
768 IBMF_TRANS_STATE_FLAG_RECV_ACTIVE
) == 0)) {
769 /* set timer for first packet of response */
770 ibmf_i_set_timer(ibmf_i_send_timeout
, msgimplp
,
774 msgimplp
->im_msg_status
= IBMF_SUCCESS
;
775 msgimplp
->im_trans_state_flags
|=
776 IBMF_TRANS_STATE_FLAG_SEND_DONE
;
777 msgimplp
->im_trans_state_flags
|= IBMF_TRANS_STATE_FLAG_DONE
;