Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ib / mgt / ibmf / ibmf_send.c
blob2c893cdaced01d0814f2cb9f5d7d79f4b49c5abb
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
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);
43 * ibmf_i_issue_pkt():
44 * Post an IB packet on the specified QP's send queue
46 int
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)
50 int ret;
51 ibt_status_t status;
52 ibt_wr_ds_t sgl[1];
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",
60 clientp,
61 msgimplp,
62 ibmf_qp_handle,
63 send_wqep);
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;
76 } else {
77 ibt_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,
93 1, NULL);
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",
100 "post send failure",
101 status);
102 return (IBMF_TRANSPORT_FAILURE);
105 ret = IBMF_SUCCESS;
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);
115 } else {
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);
125 return (ret);
129 * ibmf_i_send_pkt()
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;
137 int status;
139 IBMF_TRACE_4(DPRINT_L4,
140 "ibmf_i_send_pkt(): clientp = 0x%p, qp_hdl = 0x%p, ""msgp = 0x%p, block = %d\n",
141 clientp,
142 ibmf_qp_handle,
143 msgimplp,
144 block);
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
152 * for this send yet.
154 msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_SEND_DONE;
157 * Allocate resources needed to send a UD packet including the
158 * send WQE context
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",
166 status);
167 return (status);
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,
187 send_wqep);
188 IBMF_TRACE_2(DPRINT_L1,
189 "ibmf_i_send_pkt(): %s, status = %d\n",
190 "unable to issue packet",
191 status);
192 return (status);
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)
206 int status;
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",
210 clientp,
211 ibmf_qp_handle,
212 msgimplp,
213 block);
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",
222 status);
223 return (status);
226 return (IBMF_SUCCESS);
230 * ibmf_i_handle_send_completion():
231 * Process the WQE from the SQ identified in the work completion entry.
233 /* ARGSUSED */
234 void
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;
240 ibmf_alt_qp_t *qpp;
241 int ret;
243 IBMF_TRACE_2(DPRINT_L4,
244 "ibmf_i_handle_send_completion() enter, cip = %p, wcp = %p\n",
245 cip,
246 wcp);
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));
284 return;
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);
298 } else {
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);
324 return;
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);
335 if (ret == 0) {
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);
341 } else {
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
356 static void
357 ibmf_i_do_send_cb(void *taskq_arg)
359 ibmf_ci_t *cip;
360 ibmf_msg_impl_t *msgimplp;
361 ibmf_client_t *clientp;
362 ibmf_send_wqe_t *send_wqep;
363 boolean_t found;
364 int msg_trans_state_flags, msg_flags;
365 uint_t ref_cnt;
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;
388 else {
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 */
394 inc_refcnt = B_TRUE;
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);
412 } else {
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");
421 return;
424 /* Grab the message context lock */
425 mutex_enter(&msgimplp->im_mutex);
428 * Decrement the count of pending send completions for
429 * this transaction
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);
462 } else {
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");
471 return;
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) &&
502 (ref_cnt == 0)) {
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);
517 } else {
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",
527 msgimplp);
528 return;
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.
600 if (ref_cnt == 0) {
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);
617 } else {
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
630 /* ARGSUSED */
631 static void
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",
637 ibmf_handle,
638 msgimplp,
639 send_wqep,
640 msgimplp->im_flags);
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
652 * transaction.
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",
660 msgimplp,
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
672 * here.
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;
721 return;
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",
737 msgimplp);
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) {
747 return;
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;
758 return;
762 * check if response was received before send
763 * completion
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,
771 IBMF_RESP_TIMER);
773 } else {
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;