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 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 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 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 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 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