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