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
32 extern int ibmf_trace_level;
33
34 /*
35 * ibmf_i_set_timer():
36 * Set the timer to the response or transaction time interval
37 */
38 void
ibmf_i_set_timer(void (* func)(void *),ibmf_msg_impl_t * msgimplp,ibmf_timer_t type)39 ibmf_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 */
150 void
ibmf_i_unset_timer(ibmf_msg_impl_t * msgimplp,ibmf_timer_t type)151 ibmf_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 */
183 void
ibmf_i_recv_timeout(void * argp)184 ibmf_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 */
368 void
ibmf_i_send_timeout(void * argp)369 ibmf_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
666 void
ibmf_i_err_terminate_timeout(void * argp)667 ibmf_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