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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * This file implements the timer setup and timeout handling functions.
28 */
29
30#include <sys/ib/mgt/ibmf/ibmf_impl.h>
31
32extern int ibmf_trace_level;
33
34/*
35 * ibmf_i_set_timer():
36 *	Set the timer to the response or transaction time interval
37 */
38void
39ibmf_i_set_timer(void (*func)(void *), ibmf_msg_impl_t *msgimplp,
40    ibmf_timer_t type)
41{
42	clock_t		interval;
43	ibmf_rmpp_ctx_t	*rmpp_ctx;
44
45	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
46
47	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_set_timer_start,
48	    IBMF_TNF_TRACE, "", "ibmf_i_set_timer: msgp = %p, "
49	    "timer_type = 0x%x, func_cb = 0x%p\n",
50	    tnf_opaque, msgimplp, msgimplp, tnf_opaque, timer_type, type,
51	    tnf_opaque, func_cb, func);
52
53	if (type == IBMF_RESP_TIMER) {
54
55		/*
56		 * The response timer interval is the sum of the IBA
57		 * defined RespTimeValue (Vol. 1, Section 13.4.6.2.2),
58		 * and the round trip time value. Both values are determined
59		 * by the IBMF client and passed in the retrans_rtv and
60		 * retrans_rttv fields respectively, when calling
61		 * ibmf_msg_transport()
62		 */
63		ASSERT(msgimplp->im_rp_timeout_id == 0);
64		interval = msgimplp->im_retrans.retrans_rtv +
65		    msgimplp->im_retrans.retrans_rttv;
66
67		IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_set_timer,
68		    IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, interval = %ld "
69		    "resp_time %x round trip time %x\n",
70		    tnf_string, msg, "setting response timer",
71		    tnf_long, interval, interval,
72		    tnf_uint, resp_time, msgimplp->im_retrans.retrans_rtv,
73		    tnf_uint, interval, msgimplp->im_retrans.retrans_rttv);
74
75		msgimplp->im_rp_timeout_id = timeout(func,
76		    (void *)msgimplp, drv_usectohz(interval));
77	} else if (type == IBMF_TRANS_TIMER) {
78		rmpp_ctx = &msgimplp->im_rmpp_ctx;
79
80		ASSERT(msgimplp->im_tr_timeout_id == 0);
81		if (rmpp_ctx->rmpp_flags & IBMF_CTX_RMPP_FLAGS_DYN_PYLD) {
82			/*
83			 * if payload was not specified use IB spec default
84			 * of 40 seconds
85			 */
86			interval = IBMF_RETRANS_DEF_TRANS_TO;
87
88			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
89			    ibmf_i_set_timer, IBMF_TNF_TRACE, "",
90			    "ibmf_i_set_timer: %s, interval = %ld\n",
91			    tnf_string, msg,
92			    "payload size unknown.  Using default trans_to",
93			    tnf_long, interval, interval);
94		} else {
95			/*
96			 * if payload was specified, use a variation of IB
97			 * spec equation (13.6.3.2) that accounts for average
98			 * window size
99			 */
100			interval = (msgimplp->im_retrans.retrans_rtv +
101			    msgimplp->im_retrans.retrans_rttv) /
102			    IBMF_RMPP_DEFAULT_WIN_SZ * 4 *
103			    msgimplp->im_rmpp_ctx.rmpp_num_pkts;
104
105			IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3,
106			    ibmf_i_set_timer, IBMF_TNF_TRACE, "",
107			    "ibmf_i_set_timer: %s, num_pkts = %d, rttv ="
108			    " %x, window_size = %d, interval = %ld\n",
109			    tnf_string, msg, "setting trans timer",
110			    tnf_uint, num_pkts,
111			    msgimplp->im_rmpp_ctx.rmpp_num_pkts, tnf_uint, rtv,
112			    msgimplp->im_retrans.retrans_rttv,
113			    tnf_uint, window_size, IBMF_RMPP_DEFAULT_WIN_SZ,
114			    tnf_long, interval, interval);
115		}
116
117		/*
118		 * Use the client specified transaction timeout value if
119		 * smaller than the calculated value
120		 */
121		if ((msgimplp->im_retrans.retrans_trans_to != 0) &&
122		    (msgimplp->im_retrans.retrans_trans_to < interval)) {
123
124			interval = msgimplp->im_retrans.retrans_trans_to;
125
126			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
127			    ibmf_i_set_timer, IBMF_TNF_TRACE, "",
128			    "ibmf_i_set_timer: %s, new_interval = %ld\n",
129			    tnf_string, msg, "user trans_to is smaller",
130			    tnf_long, new_interval, interval);
131		}
132
133		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_set_timer,
134		    IBMF_TNF_TRACE, "", "ibmf_i_set_timer: %s, interval = %ld"
135		    "\n", tnf_string, msg, "setting transaction timer",
136		    tnf_long, interval, interval);
137
138		msgimplp->im_tr_timeout_id = timeout(func,
139		    (void *)msgimplp, drv_usectohz(interval));
140	}
141
142	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_set_timer_end,
143	    IBMF_TNF_TRACE, "", "ibmf_i_set_timer() exit\n");
144}
145
146/*
147 * ibmf_i_unset_timer():
148 *	Unset the timer
149 */
150void
151ibmf_i_unset_timer(ibmf_msg_impl_t *msgimplp, ibmf_timer_t type)
152{
153	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_unset_timer_start,
154	    IBMF_TNF_TRACE, "", "ibmf_i_unset_timer(): msgp = %p, \n",
155	    tnf_opaque, msgimplp, msgimplp);
156
157	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
158
159	if (type == IBMF_RESP_TIMER) {
160		if (msgimplp->im_rp_timeout_id != 0) {
161			msgimplp->im_rp_unset_timeout_id =
162			    msgimplp->im_rp_timeout_id;
163			msgimplp->im_rp_timeout_id = 0;
164		}
165	} else if (type == IBMF_TRANS_TIMER) {
166		if (msgimplp->im_tr_timeout_id != 0) {
167			msgimplp->im_tr_unset_timeout_id =
168			    msgimplp->im_tr_timeout_id;
169			msgimplp->im_tr_timeout_id = 0;
170		}
171	}
172
173	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_unset_timer_end,
174	    IBMF_TNF_TRACE, "", "ibmf_i_unset_timer() exit\n");
175}
176
177/*
178 * ibmf_i_recv_timeout:
179 *
180 *	Perform "receive" timeout processing for the message.
181 *	This timeout handler is only used in RMPP processing.
182 */
183void
184ibmf_i_recv_timeout(void *argp)
185{
186	ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp;
187	ibmf_client_t	*clientp = (ibmf_client_t *)msgimplp->im_client;
188	ibmf_rmpp_ctx_t	*rmpp_ctx;
189	int		msg_flags;
190	uint_t		ref_cnt;
191	int		status;
192
193	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
194	    ibmf_i_recv_timeout_start, IBMF_TNF_TRACE, "",
195	    "ibmf_i_recv_timeout(): msgp = 0x%p\n", tnf_opaque, msg, msgimplp);
196
197	mutex_enter(&msgimplp->im_mutex);
198
199	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
200	    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
201	    "ibmf_i_recv_timeout(): resetting id time %llx\n",
202	    tnf_opaque, time, gethrtime());
203
204	/*
205	 * If the message has been marked unitialized or done
206	 * release the message mutex and return
207	 */
208	if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) ||
209	    (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) {
210
211		mutex_exit(&msgimplp->im_mutex);
212
213		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
214		    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
215		    "ibmf_i_recv_timeout(): %s, msgp = 0x%p\n", tnf_string, msg,
216		    "Message marked for removal, return without processing "
217		    "recv timeout",
218		    tnf_opaque, msgimplp, msgimplp);
219
220		return;
221	}
222
223	/*
224	 * Unset the response and trans timers if they haven't fired (unlikely)
225	 */
226	ibmf_i_unset_timer(msgimplp, IBMF_RESP_TIMER);
227	ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
228
229	rmpp_ctx = &msgimplp->im_rmpp_ctx;
230
231	/* Perform timeout processing for the RMPP transaction */
232	if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_RECEVR_ACTIVE) {
233
234		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
235		    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
236		    "ibmf_i_recv_timeout(): %s\n", tnf_string, msg,
237		    "RMPP context is Receiver Active, sending ABORT T2L");
238
239		status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
240		    IBMF_RMPP_STATUS_T2L, 0, 0, IBMF_NO_BLOCK);
241		if (status != IBMF_SUCCESS) {
242			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
243			    ibmf_i_recv_timeout_err, IBMF_TNF_ERROR, "",
244			    "ibmf_i_recv_timeout(): %s\n", tnf_string, msg,
245			    "RMPP ABORT send failed");
246			msgimplp->im_trans_state_flags |=
247			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
248		}
249
250		mutex_enter(&clientp->ic_kstat_mutex);
251		IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
252		mutex_exit(&clientp->ic_kstat_mutex);
253
254		rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
255
256		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
257		    ibmf_i_recv_timeout, IBMF_TNF_ERROR, "",
258		    "ibmf_i_recv_timeout(): %s\n", tnf_string, msg,
259		    "RMPP context is Receiver Active, terminating transaction");
260
261		ibmf_i_terminate_transaction(msgimplp->im_client,
262		    msgimplp, IBMF_TRANS_TIMEOUT);
263
264	} else if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_RECEVR_TERMINATE) {
265
266		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
267		    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
268		    "ibmf_i_recv_timeout(): %s\n", tnf_string, msg,
269		    "RMPP context is Receiver Terminate, "
270		    "terminating transaction");
271		rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_DONE;
272		ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp,
273		    IBMF_SUCCESS);
274	}
275
276	/*
277	 * Save the transaction state flags and the timeout IDs
278	 * before releasing the mutex as they may be changed after that.
279	 */
280	msg_flags = msgimplp->im_trans_state_flags;
281
282	mutex_exit(&msgimplp->im_mutex);
283
284	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
285	    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
286	    "ibmf_i_recv_timeout(): %s, msgp = 0x%p, refcnt = %d\n", tnf_string,
287	    msg, "recv timeout done.  Dec ref count", tnf_opaque, msgimplp,
288	    msgimplp, tnf_uint, flags, msg_flags);
289
290	/*
291	 * If the transaction flags indicate a completed transaction,
292	 * notify the client
293	 */
294	if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) {
295		/* Remove the message from the client's message list */
296		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
297
298		/*
299		 * Notify the client if the message reference count is zero.
300		 * At this point, we know that the transaction is done and
301		 * the message has been removed from the client's message list.
302		 * So, we only need to make sure the reference count is zero
303		 * before notifying the client.
304		 */
305		if (ref_cnt == 0) {
306			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
307			if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) {
308
309				/*
310				 * If the message is a termination message,
311				 * free it at this time.
312				 */
313				IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
314				    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
315				    "ibmf_i_recv_timeout(): freeing terminate "
316				    "message %p\n", tnf_opaque, msgp, msgimplp);
317
318				/* free up the UD destination resource */
319				if (msgimplp->im_ibmf_ud_dest != NULL) {
320					ibmf_i_free_ud_dest(clientp, msgimplp);
321					ibmf_i_clean_ud_dest_list(
322					    clientp->ic_myci, B_FALSE);
323				}
324
325				/* Free the receive buffer */
326				kmem_free(
327				    msgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
328				    IBMF_MAD_SIZE);
329
330				/* destroy the message mutex */
331				mutex_destroy(&msgimplp->im_mutex);
332
333				/* Free the termination message context */
334				kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
335
336				/*
337				 * Decrease the "messages allocated" count
338				 * so that an ibmf_unregister() can succeed
339				 * for this client.
340				 */
341				mutex_enter(&clientp->ic_mutex);
342				clientp->ic_msgs_alloced--;
343				mutex_exit(&clientp->ic_mutex);
344
345			} else {
346
347				IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
348				    ibmf_i_recv_timeout, IBMF_TNF_TRACE, "",
349				    "ibmf_i_recv_timeout(): calling "
350				    "notify %p\n", tnf_opaque, msgp, msgimplp);
351
352				ibmf_i_notify_client(msgimplp);
353			}
354		}
355	}
356
357	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
358	    ibmf_i_recv_timeout_end, IBMF_TNF_TRACE, "",
359	    "ibmf_i_recv_timeout() exit\n");
360}
361
362/*
363 * ibmf_i_send_timeout:
364 *
365 *	Perform "send" timeout processing for the message.
366 *	This timeout handler is used in non-RMPP and RMPP processing.
367 */
368void
369ibmf_i_send_timeout(void *argp)
370{
371	ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp;
372	ibmf_client_t	*clientp = (ibmf_client_t *)msgimplp->im_client;
373	ibmf_rmpp_ctx_t	*rmpp_ctx;
374	int		msg_flags;
375	uint_t		ref_cnt;
376	int		status;
377
378	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4,
379	    ibmf_i_send_timeout_start, IBMF_TNF_TRACE, "",
380	    "ibmf_i_send_timeout_client(): msgp = 0x%p mgt_class = 0x%x "
381	    "local lid 0x%x remote lid 0x%x remote q# 0x%x\n",
382	    tnf_opaque, msg, msgimplp,
383	    tnf_uint, mgt_class, msgimplp->im_mgt_class,
384	    tnf_uint, local_lid, msgimplp->im_local_addr.ia_local_lid,
385	    tnf_uint, remote_lid, msgimplp->im_local_addr.ia_remote_lid,
386	    tnf_uint, qno, msgimplp->im_local_addr.ia_remote_qno);
387
388	mutex_enter(&msgimplp->im_mutex);
389
390	/*
391	 * If the message has been marked uninitialized or done, release the
392	 * message mutex and return
393	 */
394	if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) ||
395	    (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) {
396
397		mutex_exit(&msgimplp->im_mutex);
398
399		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
400		    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
401		    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg,
402		    "Message is done, return without processing send timeout",
403		    tnf_opaque, msgimplp, msgimplp);
404
405		return;
406	}
407
408	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_send_timeout,
409	    IBMF_TNF_TRACE, "", "ibmf_i_send_timeout(): resetting id %d\n",
410	    tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
411
412	/*
413	 * If the timer fired, but the corresponding MAD was received before
414	 * we got to this point in the timeout code, then do nothing in the
415	 * timeout handler and return
416	 */
417	if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) &&
418	    (msgimplp->im_rp_timeout_id == 0)) {
419
420		mutex_exit(&msgimplp->im_mutex);
421
422		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
423		    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
424		    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg,
425		    "Message not in undefined state, return without processing "
426		    "send timeout",
427		    tnf_opaque, msgimplp, msgimplp);
428
429		return;
430	}
431
432	/* Clear the response timer */
433	if (msgimplp->im_rp_timeout_id != 0)
434		ibmf_i_unset_timer(msgimplp, IBMF_RESP_TIMER);
435
436	rmpp_ctx = &msgimplp->im_rmpp_ctx;
437
438	/*
439	 * Non-RMPP send transaction timeout processing
440	 */
441	if ((msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP) == 0) {
442
443		/*
444		 * We use the RMPP context to store the retry count even if
445		 * the response does not use RMPP
446		 */
447		if (rmpp_ctx->rmpp_retry_cnt <
448		    msgimplp->im_retrans.retrans_retries) {
449
450			IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
451			    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
452			    "ibmf_i_send_timeout(): %s, msgp = 0x%p, "
453			    "retry_cnt = %d, max_retries = %d\n",
454			    tnf_string, msg, "Non-RMPP send timed out",
455			    tnf_opaque, msgimplp, msgimplp,
456			    tnf_uint, retry_cnt, rmpp_ctx->rmpp_retry_cnt,
457			    tnf_uint, max_retries,
458			    msgimplp->im_retrans.retrans_retries);
459
460			rmpp_ctx->rmpp_retry_cnt++;
461
462			status = ibmf_i_send_single_pkt(msgimplp->im_client,
463			    msgimplp->im_qp_hdl, msgimplp, IBMF_NO_BLOCK);
464			if (status == IBMF_SUCCESS) {
465
466				mutex_exit(&msgimplp->im_mutex);
467
468				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
469				    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
470				    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n",
471				    tnf_string, msg, "Resent send",
472				    tnf_opaque, msgimplp, msgimplp);
473
474				return;
475			}
476
477			IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
478			    ibmf_i_send_timeout, IBMF_TNF_ERROR, "",
479			    "ibmf_i_send_timeout(): %s, msgp = 0x%p, "
480			    "status = %d\n", tnf_string, msg,
481			    "Retry send failed; terminating transaction",
482			    tnf_opaque, msgimplp, msgimplp,
483			    tnf_opaque, status, status);
484
485		} else {
486
487			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
488			    ibmf_i_send_timeout, IBMF_TNF_ERROR, "",
489			    "ibmf_i_send_timeout(): %s\n",  tnf_string, msg,
490			    "Not RMPP SEND, terminate transaction with "
491			    "IBMF_TRANS_TIMEOUT");
492		}
493
494		/*
495		 * If we are in receive RMPP mode, then an ABORT should
496		 * be sent after the required number of retries.
497		 */
498		if (msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) {
499			status = ibmf_i_send_rmpp(msgimplp,
500			    IBMF_RMPP_TYPE_ABORT, IBMF_RMPP_STATUS_TMR, 0, 0,
501			    IBMF_NO_BLOCK);
502			if (status != IBMF_SUCCESS) {
503				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
504				    ibmf_i_send_timeout_err, IBMF_TNF_ERROR, "",
505				    "ibmf_i_send_timeout(): %s\n", tnf_string,
506				    msg, "RMPP ABORT send failed");
507				msgimplp->im_trans_state_flags |=
508				    IBMF_TRANS_STATE_FLAG_SEND_DONE;
509			}
510			rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
511		}
512
513		ibmf_i_terminate_transaction(msgimplp->im_client,
514		    msgimplp, IBMF_TRANS_TIMEOUT);
515
516		msg_flags = msgimplp->im_trans_state_flags;
517
518		mutex_exit(&msgimplp->im_mutex);
519
520		/* Notify the client if the transaction is done */
521		if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) {
522
523			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
524			    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
525			    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n",
526			    tnf_string, msg, "calling notify",
527			    tnf_opaque, msgimplp, msgimplp);
528			/* Remove the message from the client's message list */
529			ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
530			/*
531			 * Notify the client if the message reference count is
532			 * zero. At this point, we know that the transaction is
533			 * done and the message has been removed from the
534			 * client's message list. So, we need to be sure the
535			 * reference count is zero before notifying the client.
536			 */
537			if (ref_cnt == 0) {
538				ibmf_i_notify_client(msgimplp);
539			}
540		}
541
542		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_timeout,
543		    IBMF_TNF_TRACE, "", "ibmf_i_send_timeout() exit\n");
544
545		return;
546	}
547
548	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
549	    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
550	    "ibmf_i_send_timeout(): %s, msgp = 0x%p, retry_cnt = %d, "
551	    "max_retries = %d\n", tnf_string, msg, "RMPP send timed out",
552	    tnf_opaque, msgimplp, msgimplp,
553	    tnf_uint, retry_cnt, rmpp_ctx->rmpp_retry_cnt,
554	    tnf_uint, max_retries, msgimplp->im_retrans.retrans_retries);
555
556	/* RMPP send transaction timeout processing */
557	if (rmpp_ctx->rmpp_retry_cnt == msgimplp->im_retrans.retrans_retries) {
558
559		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
560		    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
561		    "ibmf_i_send_timeout(): %s\n", tnf_string, msg,
562		    "Maximum retries done, sending ABORT TMR");
563
564		status = ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ABORT,
565		    IBMF_RMPP_STATUS_TMR, 0, 0, IBMF_NO_BLOCK);
566		if (status != IBMF_SUCCESS) {
567			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
568			    ibmf_i_send_timeout_err, IBMF_TNF_ERROR, "",
569			    "ibmf_i_send_timeout(): %s\n", tnf_string, msg,
570			    "RMPP ABORT send failed");
571			msgimplp->im_trans_state_flags |=
572			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
573		}
574
575		rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_ABORT;
576
577		mutex_enter(&clientp->ic_kstat_mutex);
578		IBMF_ADD32_KSTATS(clientp, rmpp_errors, 1);
579		mutex_exit(&clientp->ic_kstat_mutex);
580
581		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
582		    ibmf_i_send_timeout, IBMF_TNF_ERROR, "",
583		    "ibmf_i_send_timeout(): %s\n", tnf_string, msg,
584		    "Maximum retries done, terminate transaction with "
585		    "IBMF_TRANS_TIMEOUT");
586
587		ibmf_i_terminate_transaction(msgimplp->im_client,
588		    msgimplp, IBMF_TRANS_TIMEOUT);
589
590	} else {
591
592		if (rmpp_ctx->rmpp_state == IBMF_RMPP_STATE_SENDER_ACTIVE) {
593
594			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
595			    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
596			    "ibmf_i_send_timeout(): %s\n", tnf_string, msg,
597			    "RMPP context is Sender Active, Resending window");
598
599			/*
600			 * resend the window
601			 */
602			rmpp_ctx->rmpp_ns = rmpp_ctx->rmpp_wf;
603
604			ibmf_i_send_rmpp_window(msgimplp, IBMF_NO_BLOCK);
605		} else if (rmpp_ctx->rmpp_state ==
606		    IBMF_RMPP_STATE_SENDER_SWITCH) {
607
608			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
609			    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
610			    "ibmf_i_send_timeout(): %s\n", tnf_string, msg,
611			    "RMPP context is Sender Terminate, sending ACK");
612
613			/* send ACK */
614			(void) ibmf_i_send_rmpp(msgimplp, IBMF_RMPP_TYPE_ACK,
615			    IBMF_RMPP_STATUS_NORMAL, 0, 1, IBMF_NO_BLOCK);
616
617			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
618			    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
619			    "ibmf_i_send_timeout(): setting timer %d %p\n",
620			    tnf_opaque, msgp, msgimplp, tnf_opaque,
621			    timeout_id, msgimplp->im_rp_timeout_id);
622
623			/* set response timer */
624			ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
625			    IBMF_RESP_TIMER);
626		}
627
628		rmpp_ctx->rmpp_retry_cnt++;
629
630	}
631
632	msg_flags = msgimplp->im_trans_state_flags;
633
634	mutex_exit(&msgimplp->im_mutex);
635
636	clientp = (ibmf_client_t *)msgimplp->im_client;
637
638	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
639	    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
640	    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg,
641	    "Send timeout done", tnf_opaque, msgimplp, msgimplp);
642
643	if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) {
644		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
645		    ibmf_i_send_timeout, IBMF_TNF_TRACE, "",
646		    "ibmf_i_send_timeout(): %s, msgp = 0x%p\n", tnf_string, msg,
647		    "calling notify", tnf_opaque, msgimplp, msgimplp);
648		/* Remove the message from the client's message list */
649		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
650		/*
651		 * Notify the client if the message reference count is zero.
652		 * At this point, we know that the transaction is done and
653		 * the message has been removed from the client's message list.
654		 * So, we only need to make sure the reference count is zero
655		 * before notifying the client.
656		 */
657		if (ref_cnt == 0) {
658			ibmf_i_notify_client(msgimplp);
659		}
660	}
661
662	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_timeout_end,
663	    IBMF_TNF_TRACE, "", "ibmf_i_send_timeout() exit\n");
664}
665
666void
667ibmf_i_err_terminate_timeout(void *argp)
668{
669	ibmf_msg_impl_t *msgimplp = (ibmf_msg_impl_t *)argp;
670	ibmf_client_t	*clientp = (ibmf_client_t *)msgimplp->im_client;
671	int		msg_flags;
672	uint_t		ref_cnt;
673
674	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
675	    ibmf_i_err_terminate_timeout_start, IBMF_TNF_TRACE, "",
676	    "ibmf_i_err_terminate_timeout_client(): msgp = 0x%p\n",
677	    tnf_opaque, msg, msgimplp);
678
679	mutex_enter(&msgimplp->im_mutex);
680
681	/*
682	 * If the message has been marked uninitialized or done, release the
683	 * message mutex and return
684	 */
685	if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) ||
686	    (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) {
687
688		mutex_exit(&msgimplp->im_mutex);
689
690		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
691		    ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "",
692		    "ibmf_i_err_terminate_timeout(): %s, msgp = 0x%p\n",
693		    tnf_string, msg, "Message is done, return without "
694		    "processing error terminate timeout",
695		    tnf_opaque, msgimplp, msgimplp);
696
697		return;
698	}
699
700	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout,
701	    IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): resetting "
702	    "id %d\n", tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
703
704	/* Clear the response timer */
705	if (msgimplp->im_rp_timeout_id != 0)
706		msgimplp->im_rp_timeout_id = 0;
707
708	/* Mark the transaction as terminated */
709	ibmf_i_terminate_transaction(msgimplp->im_client, msgimplp,
710	    IBMF_TRANS_FAILURE);
711
712	msg_flags = msgimplp->im_trans_state_flags;
713
714	mutex_exit(&msgimplp->im_mutex);
715
716	clientp = (ibmf_client_t *)msgimplp->im_client;
717
718	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_err_terminate_timeout,
719	    IBMF_TNF_TRACE, "", "ibmf_i_err_terminate_timeout(): %s, "
720	    "msgp = 0x%p\n", tnf_string, msg,
721	    "Error terminate timeout done", tnf_opaque, msgimplp, msgimplp);
722
723	if (msg_flags & IBMF_TRANS_STATE_FLAG_DONE) {
724		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
725		    ibmf_i_err_terminate_timeout, IBMF_TNF_TRACE, "",
726		    "ibmf_i_err_terminate_timeout(): %s, msgp = 0x%p\n",
727		    tnf_string, msg,
728		    "calling notify", tnf_opaque, msgimplp, msgimplp);
729		/* Remove the message from the client's message list */
730		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
731		/*
732		 * Notify the client if the message reference count is zero.
733		 * At this point, we know that the transaction is done and
734		 * the message has been removed from the client's message list.
735		 * So, we only need to make sure the reference count is zero
736		 * before notifying the client.
737		 */
738		if (ref_cnt == 0) {
739			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
740			if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) {
741
742				/*
743				 * If the message is a termination message,
744				 * free it at this time.
745				 */
746
747				IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
748				    ibmf_i_err_terminate_timeout,
749				    IBMF_TNF_TRACE, "",
750				    "ibmf_i_recv_timeout(): freeing terminate "
751				    "message %p\n", tnf_opaque, msgp, msgimplp);
752
753				/* free up the UD destination resource */
754				if (msgimplp->im_ibmf_ud_dest != NULL) {
755					ibmf_i_free_ud_dest(clientp, msgimplp);
756					ibmf_i_clean_ud_dest_list(
757					    clientp->ic_myci, B_FALSE);
758				}
759
760				/* Free the receive buffer */
761				kmem_free(
762				    msgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
763				    IBMF_MAD_SIZE);
764
765				/* destroy the message mutex */
766				mutex_destroy(&msgimplp->im_mutex);
767
768				/* Free the termination message context */
769				kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
770
771				/*
772				 * Decrease the "messages allocated" count
773				 * so that an ibmf_unregister() can succeed
774				 * for this client.
775				 */
776				mutex_enter(&clientp->ic_mutex);
777				clientp->ic_msgs_alloced--;
778				mutex_exit(&clientp->ic_mutex);
779
780			} else {
781
782				IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
783				    ibmf_i_err_terminate_timeout,
784				    IBMF_TNF_TRACE, "",
785				    "ibmf_i_recv_timeout(): calling "
786				    "notify %p\n", tnf_opaque, msgp, msgimplp);
787
788				ibmf_i_notify_client(msgimplp);
789			}
790		}
791	}
792
793	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
794	    ibmf_i_err_terminate_timeout_end, IBMF_TNF_TRACE, "",
795	    "ibmf_i_err_terminate_timeout() exit\n");
796}
797