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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/cpuvar.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/modctl.h> 31 #include <sys/socket.h> 32 #include <sys/strsubr.h> 33 #include <sys/note.h> 34 #include <sys/sdt.h> 35 36 #define IDM_CONN_SM_STRINGS 37 #include <sys/idm/idm.h> 38 39 boolean_t idm_sm_logging = B_FALSE; 40 41 extern idm_global_t idm; /* Global state */ 42 43 static void 44 idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event, 45 uintptr_t event_info, idm_pdu_event_type_t pdu_event_type); 46 47 static void 48 idm_conn_event_handler(void *event_ctx_opaque); 49 50 static void 51 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 52 53 static void 54 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 55 56 static void 57 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 58 59 static void 60 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 61 62 static void 63 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 64 65 static void 66 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 67 68 static void 69 idm_logout_req_timeout(void *arg); 70 71 static void 72 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 73 74 static void 75 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 76 77 static void 78 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 79 80 static void 81 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 82 83 static void 84 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 85 86 static void 87 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 88 89 static void 90 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state, 91 idm_conn_event_ctx_t *event_ctx); 92 93 static void 94 idm_conn_unref(void *ic_void); 95 96 static idm_pdu_event_action_t 97 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx, 98 idm_pdu_t *pdu); 99 100 static idm_status_t 101 idm_ffp_enable(idm_conn_t *ic); 102 103 static void 104 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type); 105 106 static void 107 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 108 109 static void 110 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx); 111 112 idm_status_t 113 idm_conn_sm_init(idm_conn_t *ic) 114 { 115 char taskq_name[32]; 116 117 /* 118 * Caller should have assigned a unique connection ID. Use this 119 * connection ID to create a unique connection name string 120 */ 121 ASSERT(ic->ic_internal_cid != 0); 122 (void) snprintf(taskq_name, sizeof (taskq_name) - 1, "conn_sm%08x", 123 ic->ic_internal_cid); 124 125 ic->ic_state_taskq = taskq_create(taskq_name, 1, minclsyspri, 2, 2, 126 TASKQ_PREPOPULATE); 127 if (ic->ic_state_taskq == NULL) { 128 return (IDM_STATUS_FAIL); 129 } 130 131 idm_sm_audit_init(&ic->ic_state_audit); 132 mutex_init(&ic->ic_state_mutex, NULL, MUTEX_DEFAULT, NULL); 133 cv_init(&ic->ic_state_cv, NULL, CV_DEFAULT, NULL); 134 135 ic->ic_state = CS_S1_FREE; 136 ic->ic_last_state = CS_S1_FREE; 137 138 return (IDM_STATUS_SUCCESS); 139 } 140 141 void 142 idm_conn_sm_fini(idm_conn_t *ic) 143 { 144 taskq_destroy(ic->ic_state_taskq); 145 146 cv_destroy(&ic->ic_state_cv); 147 /* 148 * The thread that generated the event that got us here may still 149 * hold the ic_state_mutex. Once it is released we can safely 150 * destroy it since there is no way to locate the object now. 151 */ 152 mutex_enter(&ic->ic_state_mutex); 153 mutex_destroy(&ic->ic_state_mutex); 154 } 155 156 void 157 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info) 158 { 159 mutex_enter(&ic->ic_state_mutex); 160 idm_conn_event_locked(ic, event, event_info, CT_NONE); 161 mutex_exit(&ic->ic_state_mutex); 162 } 163 164 idm_status_t 165 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic) 166 { 167 int result; 168 169 mutex_enter(&old_ic->ic_state_mutex); 170 if (((old_ic->ic_conn_type == CONN_TYPE_INI) && 171 (old_ic->ic_state != CS_S8_CLEANUP)) || 172 ((old_ic->ic_conn_type == CONN_TYPE_TGT) && 173 (old_ic->ic_state < CS_S5_LOGGED_IN))) { 174 result = IDM_STATUS_FAIL; 175 } else { 176 result = IDM_STATUS_SUCCESS; 177 new_ic->ic_reinstate_conn = old_ic; 178 idm_conn_event_locked(new_ic->ic_reinstate_conn, 179 CE_CONN_REINSTATE, (uintptr_t)new_ic, CT_NONE); 180 } 181 mutex_exit(&old_ic->ic_state_mutex); 182 183 return (result); 184 } 185 186 void 187 idm_conn_tx_pdu_event(idm_conn_t *ic, idm_conn_event_t event, 188 uintptr_t event_info) 189 { 190 ASSERT(mutex_owned(&ic->ic_state_mutex)); 191 ic->ic_pdu_events++; 192 idm_conn_event_locked(ic, event, event_info, CT_TX_PDU); 193 } 194 195 void 196 idm_conn_rx_pdu_event(idm_conn_t *ic, idm_conn_event_t event, 197 uintptr_t event_info) 198 { 199 ASSERT(mutex_owned(&ic->ic_state_mutex)); 200 ic->ic_pdu_events++; 201 idm_conn_event_locked(ic, event, event_info, CT_RX_PDU); 202 } 203 204 static void 205 idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event, 206 uintptr_t event_info, idm_pdu_event_type_t pdu_event_type) 207 { 208 idm_conn_event_ctx_t *event_ctx; 209 210 idm_sm_audit_event(&ic->ic_state_audit, SAS_IDM_CONN, 211 (int)ic->ic_state, (int)event, event_info); 212 213 /* 214 * It's very difficult to prevent a few straggling events 215 * at the end. For example idm_sorx_thread will generate 216 * a CE_TRANSPORT_FAIL event when it exits. Rather than 217 * push complicated restrictions all over the code to 218 * prevent this we will simply drop the events (and in 219 * the case of PDU events release them appropriately) 220 * since they are irrelevant once we are in a terminal state. 221 * Of course those threads need to have appropriate holds on 222 * the connection otherwise it might disappear. 223 */ 224 if ((ic->ic_state == CS_S9_INIT_ERROR) || 225 (ic->ic_state == CS_S11_COMPLETE)) { 226 if ((pdu_event_type == CT_TX_PDU) || 227 (pdu_event_type == CT_RX_PDU)) { 228 ic->ic_pdu_events--; 229 idm_pdu_complete((idm_pdu_t *)event_info, 230 IDM_STATUS_SUCCESS); 231 } 232 IDM_SM_LOG(CE_NOTE, "*** Dropping event %s (%d) because of" 233 "state %s (%d)", 234 idm_ce_name[event], event, 235 idm_cs_name[ic->ic_state], ic->ic_state); 236 return; 237 } 238 239 /* 240 * Normal event handling 241 */ 242 idm_conn_hold(ic); 243 244 event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP); 245 event_ctx->iec_ic = ic; 246 event_ctx->iec_event = event; 247 event_ctx->iec_info = event_info; 248 event_ctx->iec_pdu_event_type = pdu_event_type; 249 250 (void) taskq_dispatch(ic->ic_state_taskq, &idm_conn_event_handler, 251 event_ctx, TQ_SLEEP); 252 } 253 254 static void 255 idm_conn_event_handler(void *event_ctx_opaque) 256 { 257 idm_conn_event_ctx_t *event_ctx = event_ctx_opaque; 258 idm_conn_t *ic = event_ctx->iec_ic; 259 idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info; 260 idm_pdu_event_action_t action; 261 262 IDM_SM_LOG(CE_NOTE, "idm_conn_event_handler: conn %p event %s(%d)", 263 (void *)ic, idm_ce_name[event_ctx->iec_event], 264 event_ctx->iec_event); 265 DTRACE_PROBE2(conn__event, 266 idm_conn_t *, ic, smb_event_ctx_t *, event_ctx); 267 268 /* 269 * Validate event 270 */ 271 ASSERT(event_ctx->iec_event != CE_UNDEFINED); 272 ASSERT3U(event_ctx->iec_event, <, CE_MAX_EVENT); 273 274 /* 275 * Validate current state 276 */ 277 ASSERT(ic->ic_state != CS_S0_UNDEFINED); 278 ASSERT3U(ic->ic_state, <, CS_MAX_STATE); 279 280 /* 281 * Validate PDU-related events against the current state. If a PDU 282 * is not allowed in the current state we change the event to a 283 * protocol error. This simplifies the state-specific event handlers. 284 * For example the CS_S2_XPT_WAIT state only needs to handle the 285 * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since 286 * no PDU's can be transmitted or received in that state. 287 */ 288 if (event_ctx->iec_pdu_event_type != CT_NONE) { 289 ASSERT(pdu != NULL); 290 action = idm_conn_sm_validate_pdu(ic, event_ctx, pdu); 291 292 switch (action) { 293 case CA_TX_PROTOCOL_ERROR: 294 /* 295 * Change event and forward the PDU 296 */ 297 event_ctx->iec_event = CE_TX_PROTOCOL_ERROR; 298 break; 299 case CA_RX_PROTOCOL_ERROR: 300 /* 301 * Change event and forward the PDU. 302 */ 303 event_ctx->iec_event = CE_RX_PROTOCOL_ERROR; 304 break; 305 case CA_FORWARD: 306 /* 307 * Let the state-specific event handlers take 308 * care of it. 309 */ 310 break; 311 case CA_DROP: 312 /* 313 * It never even happened 314 */ 315 IDM_SM_LOG(CE_NOTE, "*** drop PDU %p", (void *) pdu); 316 idm_pdu_complete(pdu, IDM_STATUS_FAIL); 317 break; 318 default: 319 ASSERT(0); 320 break; 321 } 322 } 323 324 switch (ic->ic_state) { 325 case CS_S1_FREE: 326 idm_state_s1_free(ic, event_ctx); 327 break; 328 case CS_S2_XPT_WAIT: 329 idm_state_s2_xpt_wait(ic, event_ctx); 330 break; 331 case CS_S3_XPT_UP: 332 idm_state_s3_xpt_up(ic, event_ctx); 333 break; 334 case CS_S4_IN_LOGIN: 335 idm_state_s4_in_login(ic, event_ctx); 336 break; 337 case CS_S5_LOGGED_IN: 338 idm_state_s5_logged_in(ic, event_ctx); 339 break; 340 case CS_S6_IN_LOGOUT: 341 idm_state_s6_in_logout(ic, event_ctx); 342 break; 343 case CS_S7_LOGOUT_REQ: 344 idm_state_s7_logout_req(ic, event_ctx); 345 break; 346 case CS_S8_CLEANUP: 347 idm_state_s8_cleanup(ic, event_ctx); 348 break; 349 case CS_S9_INIT_ERROR: 350 idm_state_s9_init_error(ic, event_ctx); 351 break; 352 case CS_S10_IN_CLEANUP: 353 idm_state_s10_in_cleanup(ic, event_ctx); 354 break; 355 case CS_S11_COMPLETE: 356 idm_state_s11_complete(ic, event_ctx); 357 break; 358 case CS_S12_ENABLE_DM: 359 idm_state_s12_enable_dm(ic, event_ctx); 360 break; 361 default: 362 ASSERT(0); 363 break; 364 } 365 366 /* 367 * Now that we've updated the state machine, if this was 368 * a PDU-related event take the appropriate action on the PDU 369 * (transmit it, forward it to the clients RX callback, drop 370 * it, etc). 371 */ 372 if (event_ctx->iec_pdu_event_type != CT_NONE) { 373 switch (action) { 374 case CA_TX_PROTOCOL_ERROR: 375 idm_pdu_tx_protocol_error(ic, pdu); 376 break; 377 case CA_RX_PROTOCOL_ERROR: 378 idm_pdu_rx_protocol_error(ic, pdu); 379 break; 380 case CA_FORWARD: 381 if (event_ctx->iec_pdu_event_type == CT_RX_PDU) { 382 idm_pdu_rx_forward(ic, pdu); 383 } else { 384 idm_pdu_tx_forward(ic, pdu); 385 } 386 break; 387 default: 388 ASSERT(0); 389 break; 390 } 391 } 392 393 /* 394 * Update outstanding PDU event count (see idm_pdu_tx for 395 * how this is used) 396 */ 397 if ((event_ctx->iec_pdu_event_type == CT_TX_PDU) || 398 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) { 399 mutex_enter(&ic->ic_state_mutex); 400 ic->ic_pdu_events--; 401 mutex_exit(&ic->ic_state_mutex); 402 } 403 404 idm_conn_rele(ic); 405 kmem_free(event_ctx, sizeof (*event_ctx)); 406 } 407 408 static void 409 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 410 { 411 switch (event_ctx->iec_event) { 412 case CE_CONNECT_REQ: 413 /* T1 */ 414 idm_update_state(ic, CS_S2_XPT_WAIT, event_ctx); 415 break; 416 case CE_CONNECT_ACCEPT: 417 /* T3 */ 418 idm_update_state(ic, CS_S3_XPT_UP, event_ctx); 419 break; 420 case CE_TX_PROTOCOL_ERROR: 421 case CE_RX_PROTOCOL_ERROR: 422 /* This should never happen */ 423 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 424 break; 425 default: 426 ASSERT(0); 427 /*NOTREACHED*/ 428 } 429 } 430 431 432 static void 433 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 434 { 435 switch (event_ctx->iec_event) { 436 case CE_CONNECT_SUCCESS: 437 /* T4 */ 438 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx); 439 break; 440 case CE_CONNECT_FAIL: 441 case CE_LOGOUT_OTHER_CONN_RCV: 442 case CE_TX_PROTOCOL_ERROR: 443 case CE_RX_PROTOCOL_ERROR: 444 /* T2 */ 445 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 446 break; 447 default: 448 ASSERT(0); 449 /*NOTREACHED*/ 450 } 451 } 452 453 454 static void 455 idm_login_timeout(void *arg) 456 { 457 idm_conn_t *ic = arg; 458 459 idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL); 460 } 461 462 static void 463 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 464 { 465 switch (event_ctx->iec_event) { 466 case CE_LOGIN_RCV: 467 /* T4 */ 468 idm_initial_login_actions(ic, event_ctx); 469 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx); 470 break; 471 case CE_LOGIN_TIMEOUT: 472 /* 473 * Don't need to cancel login timer since the timer is 474 * presumed to be the source of this event. 475 */ 476 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL); 477 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 478 break; 479 case CE_CONNECT_REJECT: 480 case CE_CONNECT_FAIL: 481 case CE_TRANSPORT_FAIL: 482 case CE_LOGOUT_OTHER_CONN_SND: 483 /* T6 */ 484 (void) untimeout(ic->ic_state_timeout); 485 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL); 486 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 487 break; 488 case CE_TX_PROTOCOL_ERROR: 489 case CE_RX_PROTOCOL_ERROR: 490 /* Don't care */ 491 break; 492 default: 493 ASSERT(0); 494 /*NOTREACHED*/ 495 } 496 } 497 498 static void 499 idm_state_s4_in_login_fail_snd_done(idm_pdu_t *pdu, idm_status_t status) 500 { 501 idm_conn_t *ic = pdu->isp_ic; 502 503 /* 504 * This pdu callback can be invoked by the tx thread, 505 * so run the disconnect code from another thread. 506 */ 507 pdu->isp_status = status; 508 idm_conn_event(ic, CE_LOGIN_FAIL_SND_DONE, (uintptr_t)pdu); 509 } 510 511 static void 512 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 513 { 514 idm_pdu_t *pdu; 515 516 /* 517 * Login timer should no longer be active after leaving this 518 * state. 519 */ 520 switch (event_ctx->iec_event) { 521 case CE_LOGIN_SUCCESS_RCV: 522 case CE_LOGIN_SUCCESS_SND: 523 (void) untimeout(ic->ic_state_timeout); 524 idm_login_success_actions(ic, event_ctx); 525 if (ic->ic_rdma_extensions) { 526 /* T19 */ 527 idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx); 528 } else { 529 /* T5 */ 530 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx); 531 } 532 break; 533 case CE_LOGIN_TIMEOUT: 534 /* T7 */ 535 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL); 536 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 537 break; 538 case CE_LOGIN_FAIL_SND_DONE: 539 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL); 540 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 541 break; 542 case CE_LOGIN_FAIL_SND: 543 /* 544 * Allow the logout response pdu to be sent and defer 545 * the state machine update until the completion callback. 546 * Only 1 level or callback interposition is allowed. 547 */ 548 (void) untimeout(ic->ic_state_timeout); 549 pdu = (idm_pdu_t *)event_ctx->iec_info; 550 ASSERT(ic->ic_client_callback == NULL); 551 ic->ic_client_callback = pdu->isp_callback; 552 pdu->isp_callback = 553 idm_state_s4_in_login_fail_snd_done; 554 break; 555 case CE_LOGIN_FAIL_RCV: 556 case CE_TRANSPORT_FAIL: 557 case CE_LOGOUT_OTHER_CONN_SND: 558 case CE_LOGOUT_OTHER_CONN_RCV: 559 /* T7 */ 560 (void) untimeout(ic->ic_state_timeout); 561 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL); 562 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 563 break; 564 case CE_LOGIN_SND: 565 /* 566 * Initiator connections will see initial login PDU 567 * in this state. Target connections see initial 568 * login PDU in "xpt up" state. 569 */ 570 mutex_enter(&ic->ic_state_mutex); 571 if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) { 572 idm_initial_login_actions(ic, event_ctx); 573 } 574 mutex_exit(&ic->ic_state_mutex); 575 break; 576 case CE_MISC_TX: 577 case CE_MISC_RX: 578 case CE_LOGIN_RCV: 579 case CE_TX_PROTOCOL_ERROR: 580 case CE_RX_PROTOCOL_ERROR: 581 /* Don't care */ 582 break; 583 default: 584 ASSERT(0); 585 /*NOTREACHED*/ 586 } 587 } 588 589 590 static void 591 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 592 { 593 switch (event_ctx->iec_event) { 594 case CE_LOGOUT_THIS_CONN_RCV: 595 case CE_LOGOUT_THIS_CONN_SND: 596 case CE_LOGOUT_OTHER_CONN_RCV: 597 case CE_LOGOUT_OTHER_CONN_SND: 598 /* T9 */ 599 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */ 600 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx); 601 break; 602 case CE_LOGOUT_SESSION_RCV: 603 case CE_LOGOUT_SESSION_SND: 604 /* T9 */ 605 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */ 606 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx); 607 break; 608 case CE_LOGOUT_SESSION_SUCCESS: 609 /* T8 */ 610 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */ 611 612 /* Close connection */ 613 if (IDM_CONN_ISTGT(ic)) { 614 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 615 } else { 616 ic->ic_transport_ops->it_ini_conn_disconnect(ic); 617 } 618 619 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 620 break; 621 case CE_ASYNC_LOGOUT_RCV: 622 case CE_ASYNC_LOGOUT_SND: 623 /* T11 */ 624 idm_update_state(ic, CS_S7_LOGOUT_REQ, event_ctx); 625 break; 626 case CE_TRANSPORT_FAIL: 627 case CE_ASYNC_DROP_CONN_RCV: 628 case CE_ASYNC_DROP_CONN_SND: 629 case CE_ASYNC_DROP_ALL_CONN_RCV: 630 case CE_ASYNC_DROP_ALL_CONN_SND: 631 /* T15 */ 632 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */ 633 idm_update_state(ic, CS_S8_CLEANUP, event_ctx); 634 break; 635 case CE_MISC_TX: 636 case CE_MISC_RX: 637 case CE_TX_PROTOCOL_ERROR: 638 case CE_RX_PROTOCOL_ERROR: 639 /* Don't care */ 640 break; 641 default: 642 ASSERT(0); 643 } 644 } 645 646 static void 647 idm_state_s6_in_logout_success_snd_done(idm_pdu_t *pdu, idm_status_t status) 648 { 649 idm_conn_t *ic = pdu->isp_ic; 650 651 /* 652 * This pdu callback can be invoked by the tx thread, 653 * so run the disconnect code from another thread. 654 */ 655 pdu->isp_status = status; 656 idm_conn_event(ic, CE_LOGOUT_SUCCESS_SND_DONE, (uintptr_t)pdu); 657 } 658 659 static void 660 idm_state_s6_in_logout_fail_snd_done(idm_pdu_t *pdu, idm_status_t status) 661 { 662 idm_conn_t *ic = pdu->isp_ic; 663 664 /* 665 * This pdu callback can be invoked by the tx thread, 666 * so run the disconnect code from another thread. 667 */ 668 pdu->isp_status = status; 669 idm_conn_event(ic, CE_LOGOUT_FAIL_SND_DONE, (uintptr_t)pdu); 670 } 671 672 static void 673 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 674 { 675 idm_pdu_t *pdu; 676 677 switch (event_ctx->iec_event) { 678 case CE_LOGOUT_SUCCESS_SND_DONE: 679 pdu = (idm_pdu_t *)event_ctx->iec_info; 680 681 /* Close connection (if it's not already closed) */ 682 ASSERT(IDM_CONN_ISTGT(ic)); 683 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 684 685 /* restore client callback */ 686 pdu->isp_callback = ic->ic_client_callback; 687 ic->ic_client_callback = NULL; 688 idm_pdu_complete(pdu, pdu->isp_status); 689 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 690 break; 691 case CE_LOGOUT_FAIL_SND_DONE: 692 pdu = (idm_pdu_t *)event_ctx->iec_info; 693 /* restore client callback */ 694 pdu->isp_callback = ic->ic_client_callback; 695 ic->ic_client_callback = NULL; 696 idm_pdu_complete(pdu, pdu->isp_status); 697 idm_update_state(ic, CS_S8_CLEANUP, event_ctx); 698 break; 699 case CE_LOGOUT_SUCCESS_SND: 700 case CE_LOGOUT_FAIL_SND: 701 /* 702 * Allow the logout response pdu to be sent and defer 703 * the state machine update until the completion callback. 704 * Only 1 level or callback interposition is allowed. 705 */ 706 pdu = (idm_pdu_t *)event_ctx->iec_info; 707 ASSERT(ic->ic_client_callback == NULL); 708 ic->ic_client_callback = pdu->isp_callback; 709 if (event_ctx->iec_event == CE_LOGOUT_SUCCESS_SND) { 710 pdu->isp_callback = 711 idm_state_s6_in_logout_success_snd_done; 712 } else { 713 pdu->isp_callback = 714 idm_state_s6_in_logout_fail_snd_done; 715 } 716 break; 717 case CE_LOGOUT_SUCCESS_RCV: 718 case CE_LOGOUT_SESSION_SUCCESS: 719 /* T13 */ 720 721 /* Close connection (if it's not already closed) */ 722 if (IDM_CONN_ISTGT(ic)) { 723 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 724 } else { 725 ic->ic_transport_ops->it_ini_conn_disconnect(ic); 726 } 727 728 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 729 break; 730 case CE_ASYNC_LOGOUT_RCV: 731 /* T14 Do nothing */ 732 break; 733 case CE_TRANSPORT_FAIL: 734 case CE_ASYNC_DROP_CONN_RCV: 735 case CE_ASYNC_DROP_CONN_SND: 736 case CE_ASYNC_DROP_ALL_CONN_RCV: 737 case CE_ASYNC_DROP_ALL_CONN_SND: 738 case CE_LOGOUT_FAIL_RCV: 739 idm_update_state(ic, CS_S8_CLEANUP, event_ctx); 740 break; 741 case CE_TX_PROTOCOL_ERROR: 742 case CE_RX_PROTOCOL_ERROR: 743 case CE_MISC_TX: 744 case CE_MISC_RX: 745 /* Don't care */ 746 break; 747 default: 748 ASSERT(0); 749 } 750 } 751 752 753 static void 754 idm_logout_req_timeout(void *arg) 755 { 756 idm_conn_t *ic = arg; 757 758 idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL); 759 } 760 761 static void 762 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 763 { 764 /* Must cancel logout timer before leaving this state */ 765 switch (event_ctx->iec_event) { 766 case CE_LOGOUT_THIS_CONN_RCV: 767 case CE_LOGOUT_THIS_CONN_SND: 768 case CE_LOGOUT_OTHER_CONN_RCV: 769 case CE_LOGOUT_OTHER_CONN_SND: 770 /* T10 */ 771 if (IDM_CONN_ISTGT(ic)) { 772 (void) untimeout(ic->ic_state_timeout); 773 } 774 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */ 775 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx); 776 break; 777 case CE_LOGOUT_SESSION_RCV: 778 case CE_LOGOUT_SESSION_SND: 779 /* T10 */ 780 if (IDM_CONN_ISTGT(ic)) { 781 (void) untimeout(ic->ic_state_timeout); 782 } 783 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */ 784 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx); 785 break; 786 case CE_ASYNC_LOGOUT_RCV: 787 case CE_ASYNC_LOGOUT_SND: 788 /* T12 Do nothing */ 789 break; 790 case CE_TRANSPORT_FAIL: 791 case CE_ASYNC_DROP_CONN_RCV: 792 case CE_ASYNC_DROP_CONN_SND: 793 case CE_ASYNC_DROP_ALL_CONN_RCV: 794 case CE_ASYNC_DROP_ALL_CONN_SND: 795 /* T16 */ 796 if (IDM_CONN_ISTGT(ic)) { 797 (void) untimeout(ic->ic_state_timeout); 798 } 799 /* FALLTHROUGH */ 800 case CE_LOGOUT_TIMEOUT: 801 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */ 802 idm_update_state(ic, CS_S8_CLEANUP, event_ctx); 803 break; 804 case CE_LOGOUT_SESSION_SUCCESS: 805 /* T18 */ 806 if (IDM_CONN_ISTGT(ic)) { 807 (void) untimeout(ic->ic_state_timeout); 808 } 809 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */ 810 811 /* Close connection (if it's not already closed) */ 812 if (IDM_CONN_ISTGT(ic)) { 813 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 814 } else { 815 ic->ic_transport_ops->it_ini_conn_disconnect(ic); 816 } 817 818 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 819 break; 820 case CE_TX_PROTOCOL_ERROR: 821 case CE_RX_PROTOCOL_ERROR: 822 case CE_MISC_TX: 823 case CE_MISC_RX: 824 /* Don't care */ 825 break; 826 default: 827 ASSERT(0); 828 } 829 } 830 831 832 static void 833 idm_cleanup_timeout(void *arg) 834 { 835 idm_conn_t *ic = arg; 836 837 idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL); 838 } 839 840 static void 841 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 842 { 843 idm_pdu_t *pdu; 844 845 /* 846 * Need to cancel the cleanup timeout before leaving this state 847 * if it hasn't already fired. 848 */ 849 switch (event_ctx->iec_event) { 850 case CE_LOGOUT_SUCCESS_RCV: 851 case CE_LOGOUT_SUCCESS_SND: 852 case CE_LOGOUT_SESSION_SUCCESS: 853 (void) untimeout(ic->ic_state_timeout); 854 /*FALLTHROUGH*/ 855 case CE_CLEANUP_TIMEOUT: 856 /* M1 */ 857 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 858 break; 859 case CE_LOGOUT_OTHER_CONN_RCV: 860 case CE_LOGOUT_OTHER_CONN_SND: 861 /* M2 */ 862 idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx); 863 break; 864 case CE_LOGOUT_SUCCESS_SND_DONE: 865 case CE_LOGOUT_FAIL_SND_DONE: 866 pdu = (idm_pdu_t *)event_ctx->iec_info; 867 /* restore client callback */ 868 pdu->isp_callback = ic->ic_client_callback; 869 ic->ic_client_callback = NULL; 870 idm_pdu_complete(pdu, pdu->isp_status); 871 break; 872 case CE_LOGOUT_SESSION_RCV: 873 case CE_LOGOUT_SESSION_SND: 874 case CE_TX_PROTOCOL_ERROR: 875 case CE_RX_PROTOCOL_ERROR: 876 case CE_MISC_TX: 877 case CE_MISC_RX: 878 case CE_TRANSPORT_FAIL: 879 case CE_LOGOUT_TIMEOUT: 880 /* Don't care */ 881 break; 882 default: 883 ASSERT(0); 884 } 885 } 886 887 /* ARGSUSED */ 888 static void 889 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 890 { 891 if (ic->ic_conn_type == CONN_TYPE_INI) { 892 mutex_enter(&ic->ic_state_mutex); 893 ic->ic_state_flags |= CF_ERROR; 894 ic->ic_conn_sm_status = IDM_STATUS_FAIL; 895 cv_signal(&ic->ic_state_cv); 896 mutex_exit(&ic->ic_state_mutex); 897 } 898 } 899 900 static void 901 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 902 { 903 idm_pdu_t *pdu; 904 905 /* 906 * Need to cancel the cleanup timeout before leaving this state 907 * if it hasn't already fired. 908 */ 909 switch (event_ctx->iec_event) { 910 case CE_LOGOUT_FAIL_RCV: 911 case CE_LOGOUT_FAIL_SND: 912 idm_update_state(ic, CS_S8_CLEANUP, event_ctx); 913 break; 914 case CE_LOGOUT_SUCCESS_SND: 915 case CE_LOGOUT_SUCCESS_RCV: 916 case CE_LOGOUT_SESSION_SUCCESS: 917 (void) untimeout(ic->ic_state_timeout); 918 /*FALLTHROUGH*/ 919 case CE_CLEANUP_TIMEOUT: 920 idm_update_state(ic, CS_S11_COMPLETE, event_ctx); 921 break; 922 case CE_LOGOUT_SUCCESS_SND_DONE: 923 case CE_LOGOUT_FAIL_SND_DONE: 924 pdu = (idm_pdu_t *)event_ctx->iec_info; 925 /* restore client callback */ 926 pdu->isp_callback = ic->ic_client_callback; 927 ic->ic_client_callback = NULL; 928 idm_pdu_complete(pdu, pdu->isp_status); 929 break; 930 case CE_TX_PROTOCOL_ERROR: 931 case CE_RX_PROTOCOL_ERROR: 932 case CE_MISC_TX: 933 case CE_MISC_RX: 934 case CE_LOGOUT_TIMEOUT: 935 /* Don't care */ 936 break; 937 default: 938 ASSERT(0); 939 } 940 } 941 942 /* ARGSUSED */ 943 static void 944 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 945 { 946 idm_pdu_t *pdu; 947 948 /* 949 * Cleanup logout success/fail completion if it's been delayed 950 * until now. 951 */ 952 switch (event_ctx->iec_event) { 953 case CE_LOGOUT_SUCCESS_SND_DONE: 954 case CE_LOGOUT_FAIL_SND_DONE: 955 pdu = (idm_pdu_t *)event_ctx->iec_info; 956 /* restore client callback */ 957 pdu->isp_callback = ic->ic_client_callback; 958 ic->ic_client_callback = NULL; 959 idm_pdu_complete(pdu, pdu->isp_status); 960 break; 961 } 962 } 963 964 static void 965 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 966 { 967 switch (event_ctx->iec_event) { 968 case CE_ENABLE_DM_SUCCESS: 969 /* T20 */ 970 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx); 971 break; 972 case CE_ENABLE_DM_FAIL: 973 /* T21 */ 974 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx); 975 break; 976 case CE_TRANSPORT_FAIL: 977 /* 978 * We expect to always hear back from the transport layer 979 * once we have an "enable data-mover" request outstanding. 980 * Therefore we'll ignore other events that may occur even 981 * when they clearly indicate a problem and wait for 982 * CE_ENABLE_DM_FAIL. On a related note this means the 983 * transport must ensure that it eventually completes the 984 * "enable data-mover" operation with either success or 985 * failure -- otherwise we'll be stuck here. 986 */ 987 break; 988 default: 989 ASSERT(0); 990 break; 991 } 992 } 993 994 static void 995 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state, 996 idm_conn_event_ctx_t *event_ctx) 997 { 998 int rc; 999 idm_status_t idm_status; 1000 1001 /* 1002 * Validate new state 1003 */ 1004 ASSERT(new_state != CS_S0_UNDEFINED); 1005 ASSERT3U(new_state, <, CS_MAX_STATE); 1006 1007 /* 1008 * Update state in context. We protect this with a mutex 1009 * even though the state machine code is single threaded so that 1010 * other threads can check the state value atomically. 1011 */ 1012 new_state = (new_state < CS_MAX_STATE) ? 1013 new_state : CS_S0_UNDEFINED; 1014 1015 IDM_SM_LOG(CE_NOTE, "idm_update_state: conn %p, evt %s(%d), " 1016 "%s(%d) --> %s(%d)", (void *)ic, 1017 idm_ce_name[event_ctx->iec_event], event_ctx->iec_event, 1018 idm_cs_name[ic->ic_state], ic->ic_state, 1019 idm_cs_name[new_state], new_state); 1020 1021 DTRACE_PROBE2(conn__state__change, 1022 idm_conn_t *, ic, idm_conn_state_t, new_state); 1023 1024 mutex_enter(&ic->ic_state_mutex); 1025 idm_sm_audit_state_change(&ic->ic_state_audit, SAS_IDM_CONN, 1026 (int)ic->ic_state, (int)new_state); 1027 ic->ic_last_state = ic->ic_state; 1028 ic->ic_state = new_state; 1029 cv_signal(&ic->ic_state_cv); 1030 mutex_exit(&ic->ic_state_mutex); 1031 1032 switch (ic->ic_state) { 1033 case CS_S1_FREE: 1034 ASSERT(0); /* Initial state, can't return */ 1035 break; 1036 case CS_S2_XPT_WAIT: 1037 if ((rc = idm_ini_conn_finish(ic)) != 0) { 1038 idm_conn_event(ic, CE_CONNECT_FAIL, NULL); 1039 } else { 1040 idm_conn_event(ic, CE_CONNECT_SUCCESS, NULL); 1041 } 1042 break; 1043 case CS_S3_XPT_UP: 1044 /* 1045 * Finish any connection related setup including 1046 * waking up the idm_tgt_conn_accept thread. 1047 * and starting the login timer. If the function 1048 * fails then we return to "free" state. 1049 */ 1050 if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) { 1051 switch (rc) { 1052 case IDM_STATUS_REJECT: 1053 idm_conn_event(ic, CE_CONNECT_REJECT, NULL); 1054 break; 1055 default: 1056 idm_conn_event(ic, CE_CONNECT_FAIL, NULL); 1057 break; 1058 } 1059 } 1060 1061 /* 1062 * First login received will cause a transition to 1063 * CS_S4_IN_LOGIN. Start login timer. 1064 */ 1065 ic->ic_state_timeout = timeout(idm_login_timeout, ic, 1066 drv_usectohz(IDM_LOGIN_SECONDS*1000000)); 1067 break; 1068 case CS_S4_IN_LOGIN: 1069 if (ic->ic_conn_type == CONN_TYPE_INI) { 1070 mutex_enter(&ic->ic_state_mutex); 1071 ic->ic_state_flags |= CF_LOGIN_READY; 1072 cv_signal(&ic->ic_state_cv); 1073 mutex_exit(&ic->ic_state_mutex); 1074 } 1075 break; 1076 case CS_S5_LOGGED_IN: 1077 ASSERT(!ic->ic_ffp); 1078 /* 1079 * IDM can go to FFP before the initiator but it 1080 * needs to go to FFP after the target (IDM target should 1081 * go to FFP after notify_ack). 1082 */ 1083 idm_status = idm_ffp_enable(ic); 1084 if (idm_status != IDM_STATUS_SUCCESS) { 1085 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL); 1086 } 1087 1088 if (ic->ic_reinstate_conn) { 1089 /* Connection reinstatement is complete */ 1090 idm_conn_event_locked(ic->ic_reinstate_conn, 1091 CE_CONN_REINSTATE_SUCCESS, NULL, CT_NONE); 1092 } 1093 break; 1094 case CS_S6_IN_LOGOUT: 1095 break; 1096 case CS_S7_LOGOUT_REQ: 1097 /* Start logout timer for target connections */ 1098 if (IDM_CONN_ISTGT(ic)) { 1099 ic->ic_state_timeout = timeout(idm_logout_req_timeout, 1100 ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000)); 1101 } 1102 break; 1103 case CS_S8_CLEANUP: 1104 /* Close connection (if it's not already closed) */ 1105 if (IDM_CONN_ISTGT(ic)) { 1106 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 1107 } else { 1108 ic->ic_transport_ops->it_ini_conn_disconnect(ic); 1109 } 1110 1111 /* Stop executing active tasks */ 1112 idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND); 1113 1114 /* Start logout timer */ 1115 ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic, 1116 drv_usectohz(IDM_CLEANUP_SECONDS*1000000)); 1117 break; 1118 case CS_S10_IN_CLEANUP: 1119 break; 1120 case CS_S9_INIT_ERROR: 1121 if (IDM_CONN_ISTGT(ic)) { 1122 ic->ic_transport_ops->it_tgt_conn_disconnect(ic); 1123 } else { 1124 mutex_enter(&ic->ic_state_mutex); 1125 ic->ic_state_flags |= CF_ERROR; 1126 ic->ic_conn_sm_status = IDM_STATUS_FAIL; 1127 cv_signal(&ic->ic_state_cv); 1128 mutex_exit(&ic->ic_state_mutex); 1129 ic->ic_transport_ops->it_ini_conn_disconnect(ic); 1130 } 1131 /*FALLTHROUGH*/ 1132 case CS_S11_COMPLETE: 1133 /* No more traffic on this connection */ 1134 (void) idm_notify_client(ic, CN_CONNECT_LOST, NULL); 1135 1136 /* Abort all tasks */ 1137 idm_task_abort(ic, NULL, AT_INTERNAL_ABORT); 1138 1139 /* 1140 * Handle terminal state actions on the global taskq so 1141 * we can clean up all the connection resources from 1142 * a separate thread context. 1143 */ 1144 idm_refcnt_async_wait_ref(&ic->ic_refcnt, &idm_conn_unref); 1145 break; 1146 case CS_S12_ENABLE_DM: 1147 1148 /* 1149 * The Enable DM state indicates the initiator to initiate 1150 * the hello sequence and the target to get ready to accept 1151 * the iSER Hello Message. 1152 */ 1153 idm_status = (IDM_CONN_ISINI(ic)) ? 1154 ic->ic_transport_ops->it_ini_enable_datamover(ic) : 1155 ic->ic_transport_ops->it_tgt_enable_datamover(ic); 1156 1157 if (idm_status == IDM_STATUS_SUCCESS) { 1158 idm_conn_event(ic, CE_ENABLE_DM_SUCCESS, NULL); 1159 } else { 1160 idm_conn_event(ic, CE_ENABLE_DM_FAIL, NULL); 1161 } 1162 1163 break; 1164 } 1165 } 1166 1167 1168 static void 1169 idm_conn_unref(void *ic_void) 1170 { 1171 idm_conn_t *ic = ic_void; 1172 1173 /* 1174 * Client should not be notified that the connection is destroyed 1175 * until all references on the idm connection have been removed. 1176 * Otherwise references on the associated client context would need 1177 * to be tracked separately which seems like a waste (at least when 1178 * there is a one for one correspondence with references on the 1179 * IDM connection). 1180 */ 1181 if (IDM_CONN_ISTGT(ic)) { 1182 (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL); 1183 idm_svc_conn_destroy(ic); 1184 } else { 1185 /* Initiator may destroy connection during this call */ 1186 (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL); 1187 } 1188 } 1189 1190 1191 static idm_pdu_event_action_t 1192 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx, 1193 idm_pdu_t *pdu) 1194 { 1195 char *reason_string; 1196 idm_pdu_event_action_t action; 1197 1198 ASSERT((event_ctx->iec_pdu_event_type == CT_RX_PDU) || 1199 (event_ctx->iec_pdu_event_type == CT_TX_PDU)); 1200 1201 /* 1202 * Let's check the simple stuff first. Make sure if this is a 1203 * target connection that the PDU is appropriate for a target 1204 * and if this is an initiator connection that the PDU is 1205 * appropriate for an initiator. This code is not in the data 1206 * path so organization is more important than performance. 1207 */ 1208 switch (IDM_PDU_OPCODE(pdu)) { 1209 case ISCSI_OP_NOOP_OUT: 1210 case ISCSI_OP_SCSI_CMD: 1211 case ISCSI_OP_SCSI_TASK_MGT_MSG: 1212 case ISCSI_OP_LOGIN_CMD: 1213 case ISCSI_OP_TEXT_CMD: 1214 case ISCSI_OP_SCSI_DATA: 1215 case ISCSI_OP_LOGOUT_CMD: 1216 case ISCSI_OP_SNACK_CMD: 1217 /* 1218 * Only the initiator should send these PDU's and 1219 * only the target should receive them. 1220 */ 1221 if (IDM_CONN_ISINI(ic) && 1222 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) { 1223 reason_string = "Invalid RX PDU for initiator"; 1224 action = CA_RX_PROTOCOL_ERROR; 1225 goto validate_pdu_done; 1226 } 1227 1228 if (IDM_CONN_ISTGT(ic) && 1229 (event_ctx->iec_pdu_event_type == CT_TX_PDU)) { 1230 reason_string = "Invalid TX PDU for target"; 1231 action = CA_TX_PROTOCOL_ERROR; 1232 goto validate_pdu_done; 1233 } 1234 break; 1235 case ISCSI_OP_NOOP_IN: 1236 case ISCSI_OP_SCSI_RSP: 1237 case ISCSI_OP_SCSI_TASK_MGT_RSP: 1238 case ISCSI_OP_LOGIN_RSP: 1239 case ISCSI_OP_TEXT_RSP: 1240 case ISCSI_OP_SCSI_DATA_RSP: 1241 case ISCSI_OP_LOGOUT_RSP: 1242 case ISCSI_OP_RTT_RSP: 1243 case ISCSI_OP_ASYNC_EVENT: 1244 case ISCSI_OP_REJECT_MSG: 1245 /* 1246 * Only the target should send these PDU's and 1247 * only the initiator should receive them. 1248 */ 1249 if (IDM_CONN_ISTGT(ic) && 1250 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) { 1251 reason_string = "Invalid RX PDU for target"; 1252 action = CA_RX_PROTOCOL_ERROR; 1253 goto validate_pdu_done; 1254 } 1255 1256 if (IDM_CONN_ISINI(ic) && 1257 (event_ctx->iec_pdu_event_type == CT_TX_PDU)) { 1258 reason_string = "Invalid TX PDU for initiator"; 1259 action = CA_TX_PROTOCOL_ERROR; 1260 goto validate_pdu_done; 1261 } 1262 break; 1263 default: 1264 reason_string = "Unknown PDU Type"; 1265 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1266 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1267 goto validate_pdu_done; 1268 } 1269 1270 /* 1271 * Now validate the opcodes against the current state. 1272 */ 1273 reason_string = "PDU not allowed in current state"; 1274 switch (IDM_PDU_OPCODE(pdu)) { 1275 case ISCSI_OP_NOOP_OUT: 1276 case ISCSI_OP_NOOP_IN: 1277 /* 1278 * Obviously S1-S3 are not allowed since login hasn't started. 1279 * S8 is probably out as well since the connection has been 1280 * dropped. 1281 */ 1282 switch (ic->ic_state) { 1283 case CS_S4_IN_LOGIN: 1284 case CS_S5_LOGGED_IN: 1285 case CS_S6_IN_LOGOUT: 1286 case CS_S7_LOGOUT_REQ: 1287 action = CA_FORWARD; 1288 goto validate_pdu_done; 1289 case CS_S8_CLEANUP: 1290 case CS_S10_IN_CLEANUP: 1291 action = CA_DROP; 1292 break; 1293 default: 1294 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1295 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1296 goto validate_pdu_done; 1297 } 1298 /*NOTREACHED*/ 1299 case ISCSI_OP_SCSI_CMD: 1300 case ISCSI_OP_SCSI_RSP: 1301 case ISCSI_OP_SCSI_TASK_MGT_MSG: 1302 case ISCSI_OP_SCSI_TASK_MGT_RSP: 1303 case ISCSI_OP_SCSI_DATA: 1304 case ISCSI_OP_SCSI_DATA_RSP: 1305 case ISCSI_OP_RTT_RSP: 1306 case ISCSI_OP_SNACK_CMD: 1307 case ISCSI_OP_TEXT_CMD: 1308 case ISCSI_OP_TEXT_RSP: 1309 switch (ic->ic_state) { 1310 case CS_S5_LOGGED_IN: 1311 case CS_S6_IN_LOGOUT: 1312 case CS_S7_LOGOUT_REQ: 1313 action = CA_FORWARD; 1314 goto validate_pdu_done; 1315 case CS_S8_CLEANUP: 1316 case CS_S10_IN_CLEANUP: 1317 action = CA_DROP; 1318 break; 1319 default: 1320 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1321 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1322 goto validate_pdu_done; 1323 } 1324 /*NOTREACHED*/ 1325 case ISCSI_OP_LOGOUT_CMD: 1326 case ISCSI_OP_LOGOUT_RSP: 1327 case ISCSI_OP_REJECT_MSG: 1328 case ISCSI_OP_ASYNC_EVENT: 1329 switch (ic->ic_state) { 1330 case CS_S5_LOGGED_IN: 1331 case CS_S6_IN_LOGOUT: 1332 case CS_S7_LOGOUT_REQ: 1333 action = CA_FORWARD; 1334 goto validate_pdu_done; 1335 case CS_S8_CLEANUP: 1336 case CS_S10_IN_CLEANUP: 1337 action = CA_DROP; 1338 break; 1339 default: 1340 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1341 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1342 goto validate_pdu_done; 1343 } 1344 /*NOTREACHED*/ 1345 case ISCSI_OP_LOGIN_CMD: 1346 case ISCSI_OP_LOGIN_RSP: 1347 switch (ic->ic_state) { 1348 case CS_S3_XPT_UP: 1349 case CS_S4_IN_LOGIN: 1350 action = CA_FORWARD; 1351 goto validate_pdu_done; 1352 default: 1353 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1354 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1355 goto validate_pdu_done; 1356 } 1357 /*NOTREACHED*/ 1358 default: 1359 /* This should never happen -- we already checked above */ 1360 ASSERT(0); 1361 /*NOTREACHED*/ 1362 } 1363 1364 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ? 1365 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR); 1366 1367 validate_pdu_done: 1368 if (action != CA_FORWARD) { 1369 DTRACE_PROBE2(idm__int__protocol__error, 1370 idm_conn_event_ctx_t *, event_ctx, 1371 char *, reason_string); 1372 } 1373 1374 return (action); 1375 } 1376 1377 /* ARGSUSED */ 1378 void 1379 idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu) 1380 { 1381 /* 1382 * Return the PDU to the caller indicating it was a protocol error. 1383 * Caller can take appropriate action. 1384 */ 1385 idm_pdu_complete(pdu, IDM_STATUS_PROTOCOL_ERROR); 1386 } 1387 1388 void 1389 idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu) 1390 { 1391 /* 1392 * Forward PDU to caller indicating it is a protocol error. 1393 * Caller should take appropriate action. 1394 */ 1395 (*ic->ic_conn_ops.icb_rx_error)(ic, pdu, IDM_STATUS_PROTOCOL_ERROR); 1396 } 1397 1398 idm_status_t 1399 idm_notify_client(idm_conn_t *ic, idm_client_notify_t cn, uintptr_t data) 1400 { 1401 /* 1402 * We may want to make this more complicated at some point but 1403 * for now lets just call the client's notify function and return 1404 * the status. 1405 */ 1406 return ((*ic->ic_conn_ops.icb_client_notify)(ic, cn, data)); 1407 } 1408 1409 static idm_status_t 1410 idm_ffp_enable(idm_conn_t *ic) 1411 { 1412 idm_status_t rc; 1413 1414 /* 1415 * On the initiator side the client will see this notification 1416 * before the actual login succes PDU. This shouldn't be a big 1417 * deal since the initiator drives the connection. It can simply 1418 * wait for the login response then start sending SCSI commands. 1419 * Kind ugly though compared with the way things work on target 1420 * connections. 1421 */ 1422 mutex_enter(&ic->ic_state_mutex); 1423 ic->ic_ffp = B_TRUE; 1424 mutex_exit(&ic->ic_state_mutex); 1425 1426 rc = idm_notify_client(ic, CN_FFP_ENABLED, NULL); 1427 if (rc != IDM_STATUS_SUCCESS) { 1428 mutex_enter(&ic->ic_state_mutex); 1429 ic->ic_ffp = B_FALSE; 1430 mutex_exit(&ic->ic_state_mutex); 1431 } 1432 return (rc); 1433 } 1434 1435 static void 1436 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type) 1437 { 1438 mutex_enter(&ic->ic_state_mutex); 1439 ic->ic_ffp = B_FALSE; 1440 mutex_exit(&ic->ic_state_mutex); 1441 1442 /* Client can't "fail" CN_FFP_DISABLED */ 1443 (void) idm_notify_client(ic, CN_FFP_DISABLED, 1444 (uintptr_t)disable_type); 1445 } 1446 1447 static void 1448 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 1449 { 1450 ASSERT((event_ctx->iec_event == CE_LOGIN_RCV) || 1451 (event_ctx->iec_event == CE_LOGIN_SND)); 1452 1453 /* 1454 * Currently it's not clear what we would do here -- since 1455 * we went to the trouble of coding an "initial login" hook 1456 * we'll leave it in for now. Remove before integration if 1457 * it's not used for anything. 1458 */ 1459 ic->ic_state_flags |= CF_INITIAL_LOGIN; 1460 } 1461 1462 static void 1463 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx) 1464 { 1465 idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info; 1466 iscsi_login_hdr_t *login_req = 1467 (iscsi_login_hdr_t *)pdu->isp_hdr; 1468 1469 ASSERT((event_ctx->iec_event == CE_LOGIN_SUCCESS_RCV) || 1470 (event_ctx->iec_event == CE_LOGIN_SUCCESS_SND)); 1471 1472 /* 1473 * Save off CID 1474 */ 1475 mutex_enter(&ic->ic_state_mutex); 1476 ic->ic_login_cid = ntohs(login_req->cid); 1477 ic->ic_login_info_valid = B_TRUE; 1478 1479 mutex_exit(&ic->ic_state_mutex); 1480 } 1481