ibmf_send.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file implements the MAD send logic in IBMF.
*/
extern int ibmf_trace_level;
static void ibmf_i_do_send_cb(void *taskq_arg);
/*
* ibmf_i_issue_pkt():
* Post an IB packet on the specified QP's send queue
*/
int
{
int ret;
"ibmf_i_issue_pkt() enter, clientp = %p, msg = %p, "
/*
* if the qp handle provided in ibmf_send_pkt()
* is not the default qp handle for this client,
* then the wqe must be sent on this qp,
* else use the default qp handle set up during ibmf_register()
*/
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
} else {
}
/* initialize the send WQE */
/*
* Issue the wqe to the transport.
* NOTE: ibt_post_send() will not block, so, it is ok
* to hold the msgimpl mutex across this call.
*/
1, NULL);
if (status != IBT_SUCCESS) {
"ibmf_i_issue_pkt(): %s, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
ret = IBMF_SUCCESS;
/* bump the number of active sends */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
} else {
qpp->isq_sends_active++;
}
return (ret);
}
/*
* ibmf_i_send_pkt()
* Send an IB packet after allocating send resources
*/
int
{
int status;
IBMF_TNF_TRACE, "",
"ibmf_i_send_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
/*
* Reset send_done to indicate we have not received the completion
* for this send yet.
*/
/*
* Allocate resources needed to send a UD packet including the
* send WQE context
*/
if (status != IBMF_SUCCESS) {
return (status);
}
/* Set the segment number in the send WQE context */
/*
* Increment the count of pending send completions.
* Only when this count is zero should the client be notified
* of completion of the transaction.
*/
/* Send the packet */
if (status != IBMF_SUCCESS) {
return (status);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_send_single_pkt():
* Send a single IB packet. Only used to send non-RMPP packets.
*/
int
{
int status;
IBMF_TNF_TRACE, "",
"ibmf_i_send_single_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
if (status != IBMF_SUCCESS) {
"ibmf_i_send_single_pkt(): %s, msgp = 0x%p\n",
"ibmf_i_send_single_pkt() exit\n");
return (status);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_handle_send_completion():
* Process the WQE from the SQ identified in the work completion entry.
*/
/* ARGSUSED */
void
{
int ret;
"ibmf_i_handle_send_completion() enter, cip = %p, wcp = %p\n",
/* get the IBMF send WQE context */
/* get the client context */
/* Check if this is a completion for a BUSY MAD sent by IBMF */
"ibmf_i_handle_send_completion(): NULL client\n");
/*
* Deregister registered memory and free it, and
* free up the send WQE context
*/
/* Free up the message context */
"ibmf_i_handle_send_completion() exit\n");
return;
}
/* get the QP handle */
/* decrement the number of active sends */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
} else {
qpp->isq_sends_active--;
}
/*
* issue the callback using taskq. If no taskq or if the
* dispatch fails, we do the send processing in the callback context
* which is the interrupt context
*/
/* Do the processing in callback context */
ibmf_i_do_send_cb((void *)send_wqep);
"ibmf_i_handle_send_completion(): %s\n",
"ibmf_i_handle_send_completion() exit\n");
return;
}
/* Use taskq for processing if the IBMF_REG_FLAG_NO_OFFLOAD isn't set */
if (ret == 0) {
"ibmf_i_handle_send_completion(): %s\n",
ibmf_i_do_send_cb((void *)send_wqep);
}
} else {
ibmf_i_do_send_cb((void *)send_wqep);
}
"ibmf_i_handle_send_completion() exit\n");
}
/*
* ibmf_i_do_send_cb():
* Do the send completion processing
*/
static void
ibmf_i_do_send_cb(void *taskq_arg)
{
struct kmem_cache *kmem_cachep;
"ibmf_i_do_send_cb() enter, send_wqep = %p\n",
/* get the QP handle */
/* Get the WQE kmem cache pointer based on the QP type */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
else {
}
/* Look for a message in the client's message list */
inc_refcnt = B_TRUE;
/*
* If the message context was not found, then it's likely
* been freed up. So, do nothing in this timeout handler
*/
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
cip->ci_wqes_alloced--;
if (cip->ci_wqes_alloced == 0)
} else {
if (altqp->isq_wqes_alloced == 0)
}
"Message not found, return without processing send cb");
return;
}
/* Grab the message context lock */
/*
* Decrement the count of pending send completions for
* this transaction
*/
/*
* If the pending send completions is not zero, then we must
* not attempt to notify the client of a transaction completion
* in this instance of the send completion handler. Notification
* of transaction completion should be provided only by the
* last send completion so that all send completions are accounted
* for before the client is notified and subsequently attempts to
* reuse the message for an other transaction.
* If this is not done, the message may be reused while the
* send WR from the old transaction is still active in the QP's WQ.
* This could result in an attempt to modify the address handle with
* information for the new transaction which could be potentially
* incompatible, such as an incorrect port number. Such an
* incompatible modification of the address handle of the old
* transaction could result in a QP error.
*/
if (msgimplp->im_pending_send_compls != 0) {
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
cip->ci_wqes_alloced--;
if (cip->ci_wqes_alloced == 0)
} else {
if (altqp->isq_wqes_alloced == 0)
}
"Message found with pending send completions, "
"return without processing send cb");
return;
}
/*
* If the message has been marked unitialized or done
* release the message mutex and return
*/
/*
* This thread may notify the client only if the
* transaction is done, the message has been removed
* from the client's message list, and the message
* reference count is 0.
* If the transaction is done, and the message reference
* count = 0, there is still a possibility that a
* packet could arrive for the message and its reference
* count increased if the message is still on the list.
* If the message is still on the list, it will be
* removed by a call to ibmf_i_client_rem_msg() at
* the completion point of the transaction.
* So, the reference count should be checked after the
* message has been removed.
*/
if ((msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) &&
!(msg_flags & IBMF_MSG_FLAGS_ON_LIST) &&
(ref_cnt == 0)) {
}
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
cip->ci_wqes_alloced--;
if (cip->ci_wqes_alloced == 0)
} else {
if (altqp->isq_wqes_alloced == 0)
}
"Message marked for removal, return without processing "
return;
}
/* Perform send completion processing of the message context */
/* Save the message flags before releasing the mutex */
/*
* Decrement the message reference count
* This count was inceremented when the message was found on the
* client's message list
*/
if (msgimplp->im_rp_timeout_id != 0) {
msgimplp->im_rp_timeout_id = 0;
}
if (msgimplp->im_tr_timeout_id != 0) {
msgimplp->im_tr_timeout_id = 0;
}
}
if (msg_rp_unset_id != 0) {
(void) untimeout(msg_rp_unset_id);
}
if (msg_tr_unset_id != 0) {
(void) untimeout(msg_tr_unset_id);
}
if (msg_rp_set_id != 0) {
(void) untimeout(msg_rp_set_id);
}
if (msg_tr_set_id != 0) {
(void) untimeout(msg_tr_set_id);
}
"ibmf_i_do_send_cb(): %s, msg = %p\n",
/*
* If the transaction is done, signal the block thread if the
* transaction is blocking, or call the client's transaction done
* notification callback
*/
/* Remove the message from the client's message list */
/*
* Notify the client if the message reference count is zero.
* At this point, we know that the transaction is done and
* the message has been removed from the client's message list.
* So, we only need to make sure the reference count is zero
* before notifying the client.
*/
if (ref_cnt == 0) {
}
}
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
cip->ci_wqes_alloced--;
if (cip->ci_wqes_alloced == 0)
} else {
if (altqp->isq_wqes_alloced == 0)
}
"ibmf_i_do_send_cb() exit\n");
}
/*
* ibmf_i_do_send_compl():
* Determine if the transaction is complete
*/
/* ARGSUSED */
static void
{
"msgp = %p, send_wqep = 0x%p, msg_flags = 0x%x\n",
/*
* For RMPP transactions, we only care about the final packet of the
* transaction. For others, the code does not need to wait for the send
* completion (although bad things can happen if it never occurs).
* The final packets of a transaction are sent when the state is either
* ABORT or RECEVR_TERMINATE.
* Don't mark the transaction as send_done if there are still more
* packets to be sent, including doing the second part of a double-sided
* transaction.
*/
"ibmf_i_do_send_compl(): %s msgp = %p, rmpp_state = 0x%x\n",
/*
* For ABORT state, we should not return control to
* the client from the send completion handler.
* Control should be returned in the error timeout handler.
*
* The exception is when the IBMF_TRANS_STATE_FLAG_RECV_DONE
* flag has already been set. This flag is set when
* ibmf_i_terminate_transaction is called from one of the
* three timeout handlers. In this case return control from
* here.
*/
if (msgimplp->im_trans_state_flags &
}
}
if (msgimplp->im_trans_state_flags &
}
}
"ibmf_i_do_send_compl() exit\n");
return;
}
/*
* Only non-RMPP send completion gets here.
* If the send is a single-packet send that does not use RMPP, and if
* the transaction is not a sequenced transaction, call the transaction
* callback handler after flagging the transaction as done. If the
* message is sequenced, start a timer to bound the wait for the first
* data packet of the response.
*/
"Sequenced transaction, setting response timer",
/*
* Check if the send completion already occured,
* which could imply that this is a send completion
* for some previous transaction that has come in very late.
* In this case exit here.
*/
if (msgimplp->im_trans_state_flags &
"ibmf_i_do_send_compl() exit, "
"Duplicate SEND completion\n");
return;
}
/* mark as send_compl happened */
if (msgimplp->im_trans_state_flags &
"ibmf_i_do_send_compl() exit, RECV_DONE\n");
return;
}
/*
* check if response was received before send
* completion
*/
if (((msgimplp->im_trans_state_flags &
IBMF_TRANS_STATE_FLAG_DONE) == 0) &&
IBMF_TRANS_STATE_FLAG_RECV_ACTIVE) == 0)) {
/* set timer for first packet of response */
}
} else {
}
}