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