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