/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 * or http://www.opensolaris.org/os/licensing. * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * This file implements the timer setup and timeout handling functions. */ #include extern int ibmf_trace_level; /* * ibmf_i_set_timer(): * Set the timer to the response or transaction time interval */ void ibmf_i_set_timer(void (*func)(void *), ibmf_msg_impl_t *msgimplp, ibmf_timer_t type) { clock_t interval; ibmf_rmpp_ctx_t *rmpp_ctx; ASSERT(MUTEX_HELD(&msgimplp->im_mutex)); IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_set_timer_start, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: msgp = %p, " "timer_type = 0x%x, func_cb = 0x%p\n", tnf_opaque, msgimplp, msgimplp, tnf_opaque, timer_type, type, tnf_opaque, func_cb, func); if (type == IBMF_RESP_TIMER) { /* * The response timer interval is the sum of the IBA * defined RespTimeValue (Vol. 1, Section 13.4.6.2.2), * and the round trip time value. Both values are determined * by the IBMF client and passed in the retrans_rtv and * retrans_rttv fields respectively, when calling * ibmf_msg_transport() */ ASSERT(msgimplp->im_rp_timeout_id == 0); interval = msgimplp->im_retrans.retrans_rtv + msgimplp->im_retrans.retrans_rttv; IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_set_timer, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, interval = %ld " "resp_time %x round trip time %x\n", tnf_string, msg, "setting response timer", tnf_long, interval, interval, tnf_uint, resp_time, msgimplp->im_retrans.retrans_rtv, tnf_uint, interval, msgimplp->im_retrans.retrans_rttv); msgimplp->im_rp_timeout_id = timeout(func, (void *)msgimplp, drv_usectohz(interval)); } else if (type == IBMF_TRANS_TIMER) { rmpp_ctx = &msgimplp->im_rmpp_ctx; ASSERT(msgimplp->im_tr_timeout_id == 0); if (rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) { /* * if payload was not specified use IB spec default * of 40 seconds */ interval = IBMF_RETRANS_DEF_TRANS_TO; IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2, ibmf_i_set_timer, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, interval = %ld\n", tnf_string, msg, "payload size unknown. Using default trans_to", tnf_long, interval, interval); } else { /* * if payload was specified, use a variation of IB * spec equation (13.6.3.2) that accounts for average * window size */ interval = (msgimplp->im_retrans.retrans_rtv + msgimplp->im_retrans.retrans_rttv) / IBMF_RMPP_DEFAULT_WIN_SZ * 4 * msgimplp->im_rmpp_ctx.rmpp_num_pkts; IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_set_timer, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, num_pkts = %d, rttv =" " %x, window_size = %d, interval = %ld\n", tnf_string, msg, "setting trans timer", tnf_uint, num_pkts, msgimplp->im_rmpp_ctx.rmpp_num_pkts, tnf_uint, rtv, msgimplp->im_retrans.retrans_rttv, tnf_uint, window_size, IBMF_RMPP_DEFAULT_WIN_SZ, tnf_long, interval, interval); } /* * Use the client specified transaction timeout value if * smaller than the calculated value */ if ((msgimplp->im_retrans.retrans_trans_to != 0) && (msgimplp->im_retrans.retrans_trans_to < interval)) { interval = msgimplp->im_retrans.retrans_trans_to; IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2, ibmf_i_set_timer, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, new_interval = %ld\n", tnf_string, msg, "user trans_to is smaller", tnf_long, new_interval, interval); } IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_set_timer, IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, interval = %ld" "\n", tnf_string, msg, "setting transaction timer", tnf_long, interval, interval); msgimplp->im_tr_timeout_id = timeout(func, (void *)msgimplp, drv_usectohz(interval)); } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_set_timer_end, IBMF_TNF_TRACE, "", "ibmf_i_set_timer() exit\n"); } /* * ibmf_i_unset_timer(): * Unset the timer */ void ibmf_i_unset_timer(ibmf_msg_impl_t *msgimplp, ibmf_timer_t type) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_unset_timer_start, IBMF_TNF_TRACE, "", "ibmf_i_unset_timer(): msgp = %p, \n", tnf_opaque, msgimplp, msgimplp); ASSERT(MUTEX_HELD(&msgimplp->im_mutex)); if (type == IBMF_RESP_TIMER) { if (msgimplp->im_rp_timeout_id != 0) { msgimplp->im_rp_unset_timeout_id = msgimplp->im_rp_timeout_id; msgimplp->im_rp_timeout_id = 0; } } else if (type == IBMF_TRANS_TIMER) { if (msgimplp->im_tr_timeout_id != 0) { msgimplp->im_tr_unset_timeout_id = msgimplp->im_tr_timeout_id; msgimplp->im_tr_timeout_id = 0; } } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_unset_timer_end, IBMF_TNF_TRACE, "", "ibmf_i_unset_timer() exit\n"); } /* * ibmf_i_recv_timeout: * * Perform "receive" timeout processing for the message. * This timeout handler is only used in RMPP processing. */ void ibmf_i_recv_timeout(void *argp) { ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp; ibmf_client_t *clientp = (ibmf_client_t *)msgimplp->im_client; ibmf_rmpp_ctx_t *rmpp_ctx; int msg_flags; uint_t ref_cnt; int status; IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_recv_timeout_start, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): msgp = 0x%p\n", tnf_opaque, msg, msgimplp); mutex_enter(&msgimplp->im_mutex); IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): resetting id time %llx\n", tnf_opaque, time, gethrtime()); /* * If the message has been marked unitialized or done * release the message mutex and return */ if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) || (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) { mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Message marked for removal, return without processing " "recv timeout", tnf_opaque, msgimplp, msgimplp); return; } /* * Unset the response and trans timers if they haven't fired (unlikely) */ ibmf_i_unset_timer(msgimplp, IBMF_RESP_TIMER); ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER); rmpp_ctx = &msgimplp->im_rmpp_ctx; /* Perform timeout processing for the RMPP transaction */ if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_RECEVR_ACTIVE) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): %s\n", tnf_string, msg, "RMPP context is Receiver Active, sending ABORT T2L"); status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_T2L, 0, 0, IBMF_NO_BLOCK); if (status != IBMF_SUCCESS) { IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_recv_timeout_err, IBMF_TNF_ERROR, "", "ibmf_i_recv_timeout(): %s\n", tnf_string, msg, "RMPP ABORT send failed"); msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_SEND_DONE; } mutex_enter(&clientp->ic_kstat_mutex); IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1); mutex_exit(&clientp->ic_kstat_mutex); rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT; IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_recv_timeout, IBMF_TNF_ERROR, "", "ibmf_i_recv_timeout(): %s\n", tnf_string, msg, "RMPP context is Receiver Active, terminating transaction"); ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp, IBMF_TRANS_TIMEOUT); } else if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_RECEVR_TERMINATE) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): %s\n", tnf_string, msg, "RMPP context is Receiver Terminate, " "terminating transaction"); rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_DONE; ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp, IBMF_SUCCESS); } /* * Save the transaction state flags and the timeout IDs * before releasing the mutex as they may be changed after that. */ msg_flags = msgimplp->im_trans_state_flags; mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): %s, msgp = 0x%p, refcnt = %d\n", tnf_string, msg, "recv timeout done. Dec ref count", tnf_opaque, msgimplp, msgimplp, tnf_uint, flags, msg_flags); /* * If the transaction flags indicate a completed transaction, * notify the client */ if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) { /* Remove the message from the client's message list */ ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt); /* * 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) { _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp)) if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) { /* * If the message is a termination message, * free it at this time. */ IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): freeing terminate " "message %p\n", tnf_opaque, msgp, msgimplp); /* free up the UD destination resource */ if (msgimplp->im_ibmf_ud_dest != NULL) { ibmf_i_free_ud_dest(clientp, msgimplp); ibmf_i_clean_ud_dest_list( clientp->ic_myci, B_FALSE); } /* Free the receive buffer */ kmem_free( msgimplp->im_msgbufs_recv.im_bufs_mad_hdr, IBMF_MAD_SIZE); /* destroy the message mutex */ mutex_destroy(&msgimplp->im_mutex); /* Free the termination message context */ kmem_free(msgimplp, sizeof (ibmf_msg_impl_t)); /* * Decrease the "messages allocated" count * so that an ibmf_unregister() can succeed * for this client. */ mutex_enter(&clientp->ic_mutex); clientp->ic_msgs_alloced--; mutex_exit(&clientp->ic_mutex); } else { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_recv_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): calling " "notify %p\n", tnf_opaque, msgp, msgimplp); ibmf_i_notify_client(msgimplp); } } } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_recv_timeout_end, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout() exit\n"); } /* * ibmf_i_send_timeout: * * Perform "send" timeout processing for the message. * This timeout handler is used in non-RMPP and RMPP processing. */ void ibmf_i_send_timeout(void *argp) { ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp; ibmf_client_t *clientp = (ibmf_client_t *)msgimplp->im_client; ibmf_rmpp_ctx_t *rmpp_ctx; int msg_flags; uint_t ref_cnt; int status; IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_timeout_start, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout_client(): msgp = 0x%p mgt_class = 0x%x " "local lid 0x%x remote lid 0x%x remote q# 0x%x\n", tnf_opaque, msg, msgimplp, tnf_uint, mgt_class, msgimplp->im_mgt_class, tnf_uint, local_lid, msgimplp->im_local_addr.ia_local_lid, tnf_uint, remote_lid, msgimplp->im_local_addr.ia_remote_lid, tnf_uint, qno, msgimplp->im_local_addr.ia_remote_qno); mutex_enter(&msgimplp->im_mutex); /* * If the message has been marked uninitialized or done, release the * message mutex and return */ if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) || (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) { mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Message is done, return without processing send timeout", tnf_opaque, msgimplp, msgimplp); return; } IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): resetting id %d\n", tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id); /* * If the timer fired, but the corresponding MAD was received before * we got to this point in the timeout code, then do nothing in the * timeout handler and return */ if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) && (msgimplp->im_rp_timeout_id == 0)) { mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Message not in undefined state, return without processing " "send timeout", tnf_opaque, msgimplp, msgimplp); return; } /* Clear the response timer */ if (msgimplp->im_rp_timeout_id != 0) ibmf_i_unset_timer(msgimplp, IBMF_RESP_TIMER); rmpp_ctx = &msgimplp->im_rmpp_ctx; /* * Non-RMPP send transaction timeout processing */ if ((msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP) == 0) { /* * We use the RMPP context to store the retry count even if * the response does not use RMPP */ if (rmpp_ctx->rmpp_retry_cnt < msgimplp->im_retrans.retrans_retries) { IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p, " "retry_cnt = %d, max_retries = %d\n", tnf_string, msg, "Non-RMPP send timed out", tnf_opaque, msgimplp, msgimplp, tnf_uint, retry_cnt, rmpp_ctx->rmpp_retry_cnt, tnf_uint, max_retries, msgimplp->im_retrans.retrans_retries); rmpp_ctx->rmpp_retry_cnt++; status = ibmf_i_send_single_pkt(msgimplp->im_client, msgimplp->im_qp_hdl, msgimplp, IBMF_NO_BLOCK); if (status == IBMF_SUCCESS) { mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Resent send", tnf_opaque, msgimplp, msgimplp); return; } IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_timeout, IBMF_TNF_ERROR, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p, " "status = %d\n", tnf_string, msg, "Retry send failed; terminating transaction", tnf_opaque, msgimplp, msgimplp, tnf_opaque, status, status); } else { IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_timeout, IBMF_TNF_ERROR, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "Not RMPP SEND, terminate transaction with " "IBMF_TRANS_TIMEOUT"); } /* * If we are in receive RMPP mode, then an ABORT should * be sent after the required number of retries. */ if (msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) { status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_TMR, 0, 0, IBMF_NO_BLOCK); if (status != IBMF_SUCCESS) { IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_timeout_err, IBMF_TNF_ERROR, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "RMPP ABORT send failed"); msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_SEND_DONE; } rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT; } ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp, IBMF_TRANS_TIMEOUT); msg_flags = msgimplp->im_trans_state_flags; mutex_exit(&msgimplp->im_mutex); /* Notify the client if the transaction is done */ if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) { IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "calling notify", tnf_opaque, msgimplp, msgimplp); /* Remove the message from the client's message list */ ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt); /* * 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 need to be sure the * reference count is zero before notifying the client. */ if (ref_cnt == 0) { ibmf_i_notify_client(msgimplp); } } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout() exit\n"); return; } IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p, retry_cnt = %d, " "max_retries = %d\n", tnf_string, msg, "RMPP send timed out", tnf_opaque, msgimplp, msgimplp, tnf_uint, retry_cnt, rmpp_ctx->rmpp_retry_cnt, tnf_uint, max_retries, msgimplp->im_retrans.retrans_retries); /* RMPP send transaction timeout processing */ if (rmpp_ctx->rmpp_retry_cnt == msgimplp->im_retrans.retrans_retries) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "Maximum retries done, sending ABORT TMR"); status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_TMR, 0, 0, IBMF_NO_BLOCK); if (status != IBMF_SUCCESS) { IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_timeout_err, IBMF_TNF_ERROR, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "RMPP ABORT send failed"); msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_SEND_DONE; } rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT; mutex_enter(&clientp->ic_kstat_mutex); IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1); mutex_exit(&clientp->ic_kstat_mutex); IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_timeout, IBMF_TNF_ERROR, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "Maximum retries done, terminate transaction with " "IBMF_TRANS_TIMEOUT"); ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp, IBMF_TRANS_TIMEOUT); } else { if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_SENDER_ACTIVE) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "RMPP context is Sender Active, Resending window"); /* * resend the window */ rmpp_ctx->rmpp_ns = rmpp_ctx->rmpp_wf; ibmf_i_send_rmpp_window(msgimplp, IBMF_NO_BLOCK); } else if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_SENDER_SWITCH) { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s\n", tnf_string, msg, "RMPP context is Sender Terminate, sending ACK"); /* send ACK */ (void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK, IBMF_RMPP_STATUS_NORMAL, 0, 1, IBMF_NO_BLOCK); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): setting timer %d %p\n", tnf_opaque, msgp, msgimplp, tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id); /* set response timer */ ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp, IBMF_RESP_TIMER); } rmpp_ctx->rmpp_retry_cnt++; } msg_flags = msgimplp->im_trans_state_flags; mutex_exit(&msgimplp->im_mutex); clientp = (ibmf_client_t *)msgimplp->im_client; IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Send timeout done", tnf_opaque, msgimplp, msgimplp); if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) { IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "calling notify", tnf_opaque, msgimplp, msgimplp); /* Remove the message from the client's message list */ ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt); /* * 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) { ibmf_i_notify_client(msgimplp); } } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_timeout_end, IBMF_TNF_TRACE, "", "ibmf_i_send_timeout() exit\n"); } void ibmf_i_err_terminate_timeout(void *argp) { ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp; ibmf_client_t *clientp = (ibmf_client_t *)msgimplp->im_client; int msg_flags; uint_t ref_cnt; IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_err_terminate_timeout_start, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout_client(): msgp = 0x%p\n", tnf_opaque, msg, msgimplp); mutex_enter(&msgimplp->im_mutex); /* * If the message has been marked uninitialized or done, release the * message mutex and return */ if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) || (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) { mutex_exit(&msgimplp->im_mutex); IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "Message is done, return without " "processing error terminate timeout", tnf_opaque, msgimplp, msgimplp); return; } IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): resetting " "id %d\n", tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id); /* Clear the response timer */ if (msgimplp->im_rp_timeout_id != 0) msgimplp->im_rp_timeout_id = 0; /* Mark the transaction as terminated */ ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp, IBMF_TRANS_FAILURE); msg_flags = msgimplp->im_trans_state_flags; mutex_exit(&msgimplp->im_mutex); clientp = (ibmf_client_t *)msgimplp->im_client; IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): %s, " "msgp = 0x%p\n", tnf_string, msg, "Error terminate timeout done", tnf_opaque, msgimplp, msgimplp); if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) { IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): %s, msgp = 0x%p\n", tnf_string, msg, "calling notify", tnf_opaque, msgimplp, msgimplp); /* Remove the message from the client's message list */ ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt); /* * 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) { _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp)) if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) { /* * If the message is a termination message, * free it at this time. */ IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): freeing terminate " "message %p\n", tnf_opaque, msgp, msgimplp); /* free up the UD destination resource */ if (msgimplp->im_ibmf_ud_dest != NULL) { ibmf_i_free_ud_dest(clientp, msgimplp); ibmf_i_clean_ud_dest_list( clientp->ic_myci, B_FALSE); } /* Free the receive buffer */ kmem_free( msgimplp->im_msgbufs_recv.im_bufs_mad_hdr, IBMF_MAD_SIZE); /* destroy the message mutex */ mutex_destroy(&msgimplp->im_mutex); /* Free the termination message context */ kmem_free(msgimplp, sizeof (ibmf_msg_impl_t)); /* * Decrease the "messages allocated" count * so that an ibmf_unregister() can succeed * for this client. */ mutex_enter(&clientp->ic_mutex); clientp->ic_msgs_alloced--; mutex_exit(&clientp->ic_mutex); } else { IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "", "ibmf_i_recv_timeout(): calling " "notify %p\n", tnf_opaque, msgp, msgimplp); ibmf_i_notify_client(msgimplp); } } } IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_err_terminate_timeout_end, IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout() exit\n"); }