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