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