Print this page
    
NEX-3622 COMSTAR should have per remote port kstats for I/O and latency
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c
          +++ new/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.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.
  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   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  24   24   */
  25   25  
  26   26  #include <sys/cpuvar.h>
  27   27  #include <sys/types.h>
  28   28  #include <sys/conf.h>
  29   29  #include <sys/file.h>
  
    | 
      ↓ open down ↓ | 
    29 lines elided | 
    
      ↑ open up ↑ | 
  
  30   30  #include <sys/ddi.h>
  31   31  #include <sys/sunddi.h>
  32   32  #include <sys/modctl.h>
  33   33  #include <sys/sysmacros.h>
  34   34  #include <sys/scsi/generic/persist.h>
  35   35  
  36   36  #include <sys/socket.h>
  37   37  #include <sys/strsubr.h>
  38   38  #include <sys/note.h>
  39   39  #include <sys/sdt.h>
       40 +#include <sys/kstat.h>
  40   41  
  41   42  #include <sys/stmf.h>
  42   43  #include <sys/stmf_ioctl.h>
  43   44  #include <sys/portif.h>
  44   45  #include <sys/idm/idm.h>
  45   46  
  46   47  #define ISCSIT_SESS_SM_STRINGS
  47   48  #include "iscsit.h"
  48   49  
  49   50  typedef struct {
  50   51          list_node_t             se_ctx_node;
  51   52          iscsit_session_event_t  se_ctx_event;
  52   53          iscsit_conn_t           *se_event_data;
  53   54  } sess_event_ctx_t;
  54   55  
  55   56  static void
  56   57  sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event,
  57   58  iscsit_conn_t *ict);
  58   59  
  59   60  static void
  60   61  sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  61   62  
  62   63  static void
  63   64  sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  64   65  
  65   66  static void
  66   67  sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  67   68  
  68   69  static void
  69   70  sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  70   71  
  71   72  static void
  72   73  sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  73   74  
  74   75  static void
  75   76  sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  76   77  
  77   78  static void
  78   79  sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  79   80  
  80   81  static void
  81   82  sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx);
  82   83  
  83   84  static void
  84   85  sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx,
  85   86      iscsit_session_state_t new_state);
  86   87  
  87   88  static int
  88   89  iscsit_task_itt_compare(const void *void_task1, const void *void_task2);
  89   90  
  90   91  static uint16_t
  91   92  iscsit_tsih_alloc(void)
  92   93  {
  93   94          uintptr_t result;
  94   95  
  95   96          result = (uintptr_t)vmem_alloc(iscsit_global.global_tsih_pool,
  96   97              1, VM_NOSLEEP | VM_NEXTFIT);
  97   98  
  98   99          /* ISCSI_UNSPEC_TSIH (0) indicates failure */
  99  100          if (result > ISCSI_MAX_TSIH) {
 100  101                  vmem_free(iscsit_global.global_tsih_pool, (void *)result, 1);
 101  102                  result = ISCSI_UNSPEC_TSIH;
 102  103          }
 103  104  
 104  105          return ((uint16_t)result);
 105  106  }
 106  107  
 107  108  static void
 108  109  iscsit_tsih_free(uint16_t tsih)
 109  110  {
 110  111          vmem_free(iscsit_global.global_tsih_pool, (void *)(uintptr_t)tsih, 1);
 111  112  }
 112  113  
 113  114  
 114  115  iscsit_sess_t *
 115  116  iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict,
 116  117      uint32_t cmdsn, uint8_t *isid, uint16_t tag,
 117  118      char *initiator_name, char *target_name,
 118  119      uint8_t *error_class, uint8_t *error_detail)
 119  120  {
 120  121          iscsit_sess_t *result;
 121  122  
 122  123          *error_class = ISCSI_STATUS_CLASS_SUCCESS;
 123  124  
 124  125          /*
 125  126           * Even if this session create "fails" for some reason we still need
 126  127           * to return a valid session pointer so that we can send the failed
 127  128           * login response.
 128  129           */
 129  130          result = kmem_zalloc(sizeof (*result), KM_SLEEP);
 130  131  
 131  132          /* Allocate TSIH */
 132  133          if ((result->ist_tsih = iscsit_tsih_alloc()) == ISCSI_UNSPEC_TSIH) {
 133  134                  /* Out of TSIH's */
 134  135                  *error_class = ISCSI_STATUS_CLASS_TARGET_ERR;
 135  136                  *error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
 136  137                  /*
 137  138                   * Continue initializing this session so we can use it
 138  139                   * to complete the login process.
 139  140                   */
 140  141          }
 141  142  
 142  143          idm_sm_audit_init(&result->ist_state_audit);
 143  144          mutex_init(&result->ist_sn_mutex, NULL, MUTEX_DEFAULT, NULL);
 144  145          mutex_init(&result->ist_mutex, NULL, MUTEX_DEFAULT, NULL);
 145  146          cv_init(&result->ist_cv, NULL, CV_DEFAULT, NULL);
 146  147          list_create(&result->ist_events, sizeof (sess_event_ctx_t),
 147  148              offsetof(sess_event_ctx_t, se_ctx_node));
 148  149          list_create(&result->ist_conn_list, sizeof (iscsit_conn_t),
 149  150              offsetof(iscsit_conn_t, ict_sess_ln));
 150  151          avl_create(&result->ist_task_list, iscsit_task_itt_compare,
 151  152              sizeof (iscsit_task_t), offsetof(iscsit_task_t, it_sess_ln));
 152  153          result->ist_rxpdu_queue = kmem_zalloc(sizeof (iscsit_cbuf_t), KM_SLEEP);
 153  154          result->ist_state = SS_Q1_FREE;
 154  155          result->ist_last_state = SS_Q1_FREE;
 155  156          bcopy(isid, result->ist_isid, ISCSI_ISID_LEN);
 156  157          result->ist_tpgt_tag = tag;
 157  158  
 158  159          result->ist_tgt = tgt;
 159  160          /*
 160  161           * cmdsn/expcmdsn do not advance during login phase.
 161  162           */
 162  163          result->ist_expcmdsn = cmdsn;
 163  164          result->ist_maxcmdsn = result->ist_expcmdsn + 1;
 164  165  
 165  166          result->ist_initiator_name =
 166  167              kmem_alloc(strlen(initiator_name) + 1, KM_SLEEP);
 167  168          (void) strcpy(result->ist_initiator_name, initiator_name);
 168  169          if (target_name) {
 169  170                  /* A discovery session might not have a target name */
 170  171                  result->ist_target_name =
 171  172                      kmem_alloc(strlen(target_name) + 1, KM_SLEEP);
 172  173                  (void) strcpy(result->ist_target_name, target_name);
 173  174          }
 174  175          idm_refcnt_init(&result->ist_refcnt, result);
 175  176  
 176  177          /* Login code will fill in ist_stmf_sess if necessary */
 177  178  
 178  179          if (*error_class == ISCSI_STATUS_CLASS_SUCCESS) {
 179  180                  /*
 180  181                   * Make sure the service is still enabled and if so get a global
 181  182                   * hold to represent this session.
 182  183                   */
 183  184                  mutex_enter(&iscsit_global.global_state_mutex);
 184  185                  if (iscsit_global.global_svc_state == ISE_ENABLED) {
 185  186                          iscsit_global_hold();
 186  187                          mutex_exit(&iscsit_global.global_state_mutex);
 187  188  
 188  189                          /*
 189  190                           * Kick session state machine (also binds connection
 190  191                           * to session)
 191  192                           */
 192  193                          iscsit_sess_sm_event(result, SE_CONN_IN_LOGIN, ict);
 193  194  
 194  195                          *error_class = ISCSI_STATUS_CLASS_SUCCESS;
 195  196                  } else {
 196  197                          mutex_exit(&iscsit_global.global_state_mutex);
 197  198                          *error_class = ISCSI_STATUS_CLASS_TARGET_ERR;
 198  199                          *error_detail = ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE;
 199  200                  }
 200  201          }
 201  202  
 202  203          /*
 203  204           * As noted above we must return a session pointer even if something
  
    | 
      ↓ open down ↓ | 
    154 lines elided | 
    
      ↑ open up ↑ | 
  
 204  205           * failed.  The resources will get freed later.
 205  206           */
 206  207          return (result);
 207  208  }
 208  209  
 209  210  static void
 210  211  iscsit_sess_unref(void *ist_void)
 211  212  {
 212  213          iscsit_sess_t *ist = ist_void;
 213  214          stmf_scsi_session_t *iss;
      215 +        char prop_buf[KSTAT_STRLEN + 1];
 214  216  
 215  217          /*
 216  218           * State machine has run to completion, destroy session
 217  219           *
 218  220           * If we have an associated STMF session we should clean it
 219  221           * up now.
 220  222           *
 221  223           * This session is no longer associated with a target at this
 222  224           * point so don't touch the target.
 223  225           */
 224  226          mutex_enter(&ist->ist_mutex);
 225  227          ASSERT(ist->ist_conn_count == 0);
 226  228          iss = ist->ist_stmf_sess;
 227  229          if (iss != NULL) {
      230 +                (void) snprintf(prop_buf, sizeof (prop_buf),
      231 +                    "peername_%"PRIxPTR"", (uintptr_t)ist);
      232 +                stmf_remove_rport_info(iss, prop_buf);
 228  233                  stmf_deregister_scsi_session(ist->ist_lport, iss);
 229  234                  kmem_free(iss->ss_rport_id, sizeof (scsi_devid_desc_t) +
 230  235                      strlen(ist->ist_initiator_name) + 1);
 231  236                  stmf_remote_port_free(iss->ss_rport);
 232  237                  if (iss->ss_rport_alias)
 233  238                          strfree(iss->ss_rport_alias);
 234  239                  stmf_free(iss);
 235  240          }
 236  241          mutex_exit(&ist->ist_mutex);
 237  242  
 238  243          iscsit_sess_destroy(ist);
 239  244          iscsit_global_rele();
 240  245  }
 241  246  
 242  247  void
 243  248  iscsit_sess_destroy(iscsit_sess_t *ist)
 244  249  {
 245  250          idm_refcnt_destroy(&ist->ist_refcnt);
 246  251          if (ist->ist_initiator_name)
 247  252                  kmem_free(ist->ist_initiator_name,
 248  253                      strlen(ist->ist_initiator_name) + 1);
 249  254          if (ist->ist_initiator_alias)
 250  255                  kmem_free(ist->ist_initiator_alias,
 251  256                      strlen(ist->ist_initiator_alias) + 1);
 252  257          if (ist->ist_target_name)
 253  258                  kmem_free(ist->ist_target_name,
 254  259                      strlen(ist->ist_target_name) + 1);
 255  260          if (ist->ist_target_alias)
 256  261                  kmem_free(ist->ist_target_alias,
 257  262                      strlen(ist->ist_target_alias) + 1);
 258  263          avl_destroy(&ist->ist_task_list);
 259  264          kmem_free(ist->ist_rxpdu_queue, sizeof (iscsit_cbuf_t));
 260  265          list_destroy(&ist->ist_conn_list);
 261  266          list_destroy(&ist->ist_events);
 262  267          cv_destroy(&ist->ist_cv);
 263  268          mutex_destroy(&ist->ist_mutex);
 264  269          mutex_destroy(&ist->ist_sn_mutex);
 265  270          kmem_free(ist, sizeof (*ist));
 266  271  }
 267  272  
 268  273  void
 269  274  iscsit_sess_close(iscsit_sess_t *ist)
 270  275  {
 271  276          iscsit_conn_t *ict;
 272  277  
 273  278          mutex_enter(&ist->ist_mutex);
 274  279          /*
 275  280           * Note in the session state that we are forcing this session
 276  281           * to close so that the session state machine can avoid
 277  282           * pointless delays like transitions to SS_Q4_FAILED state.
 278  283           */
 279  284          ist->ist_admin_close = B_TRUE;
 280  285          if (ist->ist_state == SS_Q3_LOGGED_IN) {
 281  286                  for (ict = list_head(&ist->ist_conn_list);
 282  287                      ict != NULL;
 283  288                      ict = list_next(&ist->ist_conn_list, ict)) {
 284  289                          iscsit_send_async_event(ict,
 285  290                              ISCSI_ASYNC_EVENT_REQUEST_LOGOUT);
 286  291                  }
 287  292          }
 288  293          mutex_exit(&ist->ist_mutex);
 289  294  }
 290  295  
 291  296  
 292  297  void
 293  298  iscsit_sess_bind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict)
 294  299  {
 295  300          iscsit_conn_hold(ict);
 296  301          iscsit_sess_hold(ist);
 297  302          ict->ict_sess = ist;
 298  303          mutex_enter(&ist->ist_mutex);
 299  304          ist->ist_conn_count++;
 300  305          list_insert_tail(&ist->ist_conn_list, ict);
 301  306          mutex_exit(&ist->ist_mutex);
 302  307  }
 303  308  
 304  309  void
 305  310  iscsit_sess_unbind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict)
 306  311  {
 307  312          mutex_enter(&ist->ist_mutex);
 308  313          list_remove(&ist->ist_conn_list, ict);
 309  314          ist->ist_conn_count--;
 310  315          mutex_exit(&ist->ist_mutex);
 311  316          iscsit_sess_rele(ist);
 312  317          iscsit_conn_rele(ict);
 313  318  }
 314  319  
 315  320  void
 316  321  iscsit_sess_hold(iscsit_sess_t *ist)
 317  322  {
 318  323          idm_refcnt_hold(&ist->ist_refcnt);
 319  324  }
 320  325  
 321  326  void
 322  327  iscsit_sess_rele(iscsit_sess_t *ist)
 323  328  {
 324  329          idm_refcnt_rele(&ist->ist_refcnt);
 325  330  }
 326  331  
 327  332  idm_status_t
 328  333  iscsit_sess_check_hold(iscsit_sess_t *ist)
 329  334  {
 330  335          mutex_enter(&ist->ist_mutex);
 331  336          if (ist->ist_state != SS_Q6_DONE &&
 332  337              ist->ist_state != SS_Q7_ERROR) {
 333  338                  idm_refcnt_hold(&ist->ist_refcnt);
 334  339                  mutex_exit(&ist->ist_mutex);
 335  340                  return (IDM_STATUS_SUCCESS);
 336  341          }
 337  342          mutex_exit(&ist->ist_mutex);
 338  343          return (IDM_STATUS_FAIL);
 339  344  }
 340  345  
 341  346  iscsit_conn_t *
 342  347  iscsit_sess_lookup_conn(iscsit_sess_t *ist, uint16_t cid)
 343  348  {
 344  349          iscsit_conn_t *result;
 345  350  
 346  351          mutex_enter(&ist->ist_mutex);
 347  352          for (result = list_head(&ist->ist_conn_list);
 348  353              result != NULL;
 349  354              result = list_next(&ist->ist_conn_list, result)) {
 350  355                  if (result->ict_cid == cid) {
 351  356                          iscsit_conn_hold(result);
 352  357                          mutex_exit(&ist->ist_mutex);
 353  358                          return (result);
 354  359                  }
 355  360          }
 356  361          mutex_exit(&ist->ist_mutex);
 357  362  
 358  363          return (NULL);
 359  364  }
 360  365  
 361  366  iscsit_sess_t *
 362  367  iscsit_sess_reinstate(iscsit_tgt_t *tgt, iscsit_sess_t *ist, iscsit_conn_t *ict,
 363  368      uint8_t *error_class, uint8_t *error_detail)
 364  369  {
 365  370          iscsit_sess_t *new_sess;
 366  371  
 367  372          mutex_enter(&ist->ist_mutex);
 368  373  
 369  374          /*
 370  375           * Session reinstatement replaces a current session with a new session.
 371  376           * The new session will have the same ISID as the existing session.
 372  377           */
 373  378          new_sess = iscsit_sess_create(tgt, ict, 0,
 374  379              ist->ist_isid, ist->ist_tpgt_tag,
 375  380              ist->ist_initiator_name, ist->ist_target_name,
 376  381              error_class, error_detail);
 377  382          ASSERT(new_sess != NULL);
 378  383  
 379  384          /* Copy additional fields from original session */
 380  385          new_sess->ist_expcmdsn = ist->ist_expcmdsn;
 381  386          new_sess->ist_maxcmdsn = ist->ist_expcmdsn + 1;
 382  387  
 383  388          if (ist->ist_state != SS_Q6_DONE &&
 384  389              ist->ist_state != SS_Q7_ERROR) {
 385  390                  /*
 386  391                   * Generate reinstate event
 387  392                   */
 388  393                  sess_sm_event_locked(ist, SE_SESSION_REINSTATE, NULL);
 389  394          }
 390  395          mutex_exit(&ist->ist_mutex);
 391  396  
 392  397          return (new_sess);
 393  398  }
 394  399  
 395  400  int
 396  401  iscsit_sess_avl_compare(const void *void_sess1, const void *void_sess2)
 397  402  {
 398  403          const iscsit_sess_t     *sess1 = void_sess1;
 399  404          const iscsit_sess_t     *sess2 = void_sess2;
 400  405          int                     result;
 401  406  
 402  407          /*
 403  408           * Sort by initiator name, then ISID then portal group tag
 404  409           */
 405  410          result = strcmp(sess1->ist_initiator_name, sess2->ist_initiator_name);
 406  411          if (result < 0) {
 407  412                  return (-1);
 408  413          } else if (result > 0) {
 409  414                  return (1);
 410  415          }
 411  416  
 412  417          /*
 413  418           * Initiator names match, compare ISIDs
 414  419           */
 415  420          result = memcmp(sess1->ist_isid, sess2->ist_isid, ISCSI_ISID_LEN);
 416  421          if (result < 0) {
 417  422                  return (-1);
 418  423          } else if (result > 0) {
 419  424                  return (1);
 420  425          }
 421  426  
 422  427          /*
 423  428           * ISIDs match, compare portal group tags
 424  429           */
 425  430          if (sess1->ist_tpgt_tag < sess2->ist_tpgt_tag) {
 426  431                  return (-1);
 427  432          } else if (sess1->ist_tpgt_tag > sess2->ist_tpgt_tag) {
 428  433                  return (1);
 429  434          }
 430  435  
 431  436          /*
 432  437           * Portal group tags match, compare TSIHs
 433  438           */
 434  439          if (sess1->ist_tsih < sess2->ist_tsih) {
 435  440                  return (-1);
 436  441          } else if (sess1->ist_tsih > sess2->ist_tsih) {
 437  442                  return (1);
 438  443          }
 439  444  
 440  445          /*
 441  446           * Sessions match
 442  447           */
 443  448          return (0);
 444  449  }
 445  450  
 446  451  int
 447  452  iscsit_task_itt_compare(const void *void_task1, const void *void_task2)
 448  453  {
 449  454          const iscsit_task_t     *task1 = void_task1;
 450  455          const iscsit_task_t     *task2 = void_task2;
 451  456  
 452  457          if (task1->it_itt < task2->it_itt)
 453  458                  return (-1);
 454  459          else if (task1->it_itt > task2->it_itt)
 455  460                  return (1);
 456  461  
 457  462          return (0);
 458  463  }
 459  464  
 460  465  /*
 461  466   * State machine
 462  467   */
 463  468  
 464  469  void
 465  470  iscsit_sess_sm_event(iscsit_sess_t *ist, iscsit_session_event_t event,
 466  471      iscsit_conn_t *ict)
 467  472  {
 468  473          mutex_enter(&ist->ist_mutex);
 469  474          sess_sm_event_locked(ist, event, ict);
 470  475          mutex_exit(&ist->ist_mutex);
 471  476  }
 472  477  
 473  478  static void
 474  479  sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event,
 475  480      iscsit_conn_t *ict)
 476  481  {
 477  482          sess_event_ctx_t *ctx;
 478  483  
 479  484          iscsit_sess_hold(ist);
 480  485  
 481  486          ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
 482  487  
 483  488          ctx->se_ctx_event = event;
 484  489          ctx->se_event_data = ict;
 485  490  
 486  491          list_insert_tail(&ist->ist_events, ctx);
 487  492          /*
 488  493           * Use the ist_sm_busy to keep the state machine single threaded.
 489  494           * This also serves as recursion avoidance since this flag will
 490  495           * always be set if we call login_sm_event from within the
 491  496           * state machine code.
 492  497           */
 493  498          if (!ist->ist_sm_busy) {
 494  499                  ist->ist_sm_busy = B_TRUE;
 495  500                  while (!list_is_empty(&ist->ist_events)) {
 496  501                          ctx = list_head(&ist->ist_events);
 497  502                          list_remove(&ist->ist_events, ctx);
 498  503                          idm_sm_audit_event(&ist->ist_state_audit,
 499  504                              SAS_ISCSIT_SESS, (int)ist->ist_state,
 500  505                              (int)ctx->se_ctx_event, (uintptr_t)ict);
 501  506                          mutex_exit(&ist->ist_mutex);
 502  507                          sess_sm_event_dispatch(ist, ctx);
 503  508                          mutex_enter(&ist->ist_mutex);
 504  509                  }
 505  510                  ist->ist_sm_busy = B_FALSE;
 506  511  
 507  512          }
 508  513  
 509  514          iscsit_sess_rele(ist);
 510  515  }
 511  516  
 512  517  static void
 513  518  sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 514  519  {
 515  520          iscsit_conn_t   *ict;
 516  521  
 517  522          DTRACE_PROBE2(session__event, iscsit_sess_t *, ist,
 518  523              sess_event_ctx_t *, ctx);
 519  524  
 520  525          IDM_SM_LOG(CE_NOTE, "sess_sm_event_dispatch: sess %p event %s(%d)",
 521  526              (void *)ist, iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event);
 522  527  
 523  528          /* State independent actions */
 524  529          switch (ctx->se_ctx_event) {
 525  530          case SE_CONN_IN_LOGIN:
 526  531                  ict = ctx->se_event_data;
 527  532                  iscsit_sess_bind_conn(ist, ict);
 528  533                  break;
 529  534          case SE_CONN_FAIL:
 530  535                  ict = ctx->se_event_data;
 531  536                  iscsit_sess_unbind_conn(ist, ict);
 532  537                  break;
 533  538          }
 534  539  
 535  540          /* State dependent actions */
 536  541          switch (ist->ist_state) {
 537  542          case SS_Q1_FREE:
 538  543                  sess_sm_q1_free(ist, ctx);
 539  544                  break;
 540  545          case SS_Q2_ACTIVE:
 541  546                  sess_sm_q2_active(ist, ctx);
 542  547                  break;
 543  548          case SS_Q3_LOGGED_IN:
 544  549                  sess_sm_q3_logged_in(ist, ctx);
 545  550                  break;
 546  551          case SS_Q4_FAILED:
 547  552                  sess_sm_q4_failed(ist, ctx);
 548  553                  break;
 549  554          case SS_Q5_CONTINUE:
 550  555                  sess_sm_q5_continue(ist, ctx);
 551  556                  break;
 552  557          case SS_Q6_DONE:
 553  558                  sess_sm_q6_done(ist, ctx);
 554  559                  break;
 555  560          case SS_Q7_ERROR:
 556  561                  sess_sm_q7_error(ist, ctx);
 557  562                  break;
 558  563          default:
 559  564                  ASSERT(0);
 560  565                  break;
 561  566          }
 562  567  
 563  568          kmem_free(ctx, sizeof (*ctx));
 564  569  }
 565  570  
 566  571  static void
 567  572  sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 568  573  {
 569  574          switch (ctx->se_ctx_event) {
 570  575          case SE_CONN_IN_LOGIN:
 571  576                  /* N1 */
 572  577                  sess_sm_new_state(ist, ctx, SS_Q2_ACTIVE);
 573  578                  break;
 574  579          default:
 575  580                  ASSERT(0);
 576  581                  break;
 577  582          }
 578  583  }
 579  584  
 580  585  
 581  586  static void
 582  587  sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 583  588  {
 584  589          iscsit_conn_t   *ict;
 585  590  
 586  591          switch (ctx->se_ctx_event) {
 587  592          case SE_CONN_LOGGED_IN:
 588  593                  /* N2 track FFP connections */
 589  594                  ist->ist_ffp_conn_count++;
 590  595                  sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN);
 591  596                  break;
 592  597          case SE_CONN_IN_LOGIN:
 593  598                  /* N2.1, don't care stay in this state */
 594  599                  break;
 595  600          case SE_CONN_FAIL:
 596  601                  /* N9 */
 597  602                  sess_sm_new_state(ist, ctx, SS_Q7_ERROR);
 598  603                  break;
 599  604          case SE_SESSION_REINSTATE:
 600  605                  /* N11 */
 601  606                  /*
 602  607                   * Shutdown the iSCSI connections by
 603  608                   * sending an implicit logout to all
 604  609                   * the IDM connections and transition
 605  610                   * the session to SS_Q6_DONE state.
 606  611                   */
 607  612                  mutex_enter(&ist->ist_mutex);
 608  613                  for (ict = list_head(&ist->ist_conn_list);
 609  614                      ict != NULL;
 610  615                      ict = list_next(&ist->ist_conn_list, ict)) {
 611  616                          iscsit_conn_logout(ict);
 612  617                  }
 613  618                  mutex_exit(&ist->ist_mutex);
 614  619                  sess_sm_new_state(ist, ctx, SS_Q6_DONE);
 615  620                  break;
 616  621          default:
 617  622                  ASSERT(0);
 618  623                  break;
 619  624          }
 620  625  }
 621  626  
 622  627  static void
 623  628  sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 624  629  {
 625  630          iscsit_conn_t   *ict;
 626  631  
 627  632          switch (ctx->se_ctx_event) {
 628  633          case SE_CONN_IN_LOGIN:
 629  634          case SE_CONN_FAIL:
 630  635                  /* N2.2, don't care */
 631  636                  break;
 632  637          case SE_CONN_LOGGED_IN:
 633  638                  /* N2.2, track FFP connections */
 634  639                  ist->ist_ffp_conn_count++;
 635  640                  break;
 636  641          case SE_CONN_FFP_FAIL:
 637  642          case SE_CONN_FFP_DISABLE:
 638  643                  /*
 639  644                   * Event data from event context is the associated connection
 640  645                   * which in this case happens to be the last FFP connection
 641  646                   * for the session.  In certain cases we need to refer
 642  647                   * to this last valid connection (i.e. RFC3720 section 12.16)
 643  648                   * so we'll save off a pointer here for later use.
 644  649                   */
 645  650                  ASSERT(ist->ist_ffp_conn_count >= 1);
 646  651                  ist->ist_failed_conn = (iscsit_conn_t *)ctx->se_event_data;
 647  652                  ist->ist_ffp_conn_count--;
 648  653                  if (ist->ist_ffp_conn_count == 0) {
 649  654                          /*
 650  655                           * N5(fail) or N3(disable)
 651  656                           *
 652  657                           * If the event is SE_CONN_FFP_FAIL but we are
 653  658                           * in the midst of an administrative session close
 654  659                           * because of a service or target offline then
 655  660                           * there is no need to go to "failed" state.
 656  661                           */
 657  662                          sess_sm_new_state(ist, ctx,
 658  663                              ((ctx->se_ctx_event == SE_CONN_FFP_DISABLE) ||
 659  664                              (ist->ist_admin_close)) ?
 660  665                              SS_Q6_DONE : SS_Q4_FAILED);
 661  666                  }
 662  667                  break;
 663  668          case SE_SESSION_CLOSE:
 664  669          case SE_SESSION_REINSTATE:
 665  670                  /* N3 */
 666  671                  mutex_enter(&ist->ist_mutex);
 667  672                  if (ctx->se_ctx_event == SE_SESSION_CLOSE) {
 668  673                          ASSERT(ist->ist_ffp_conn_count >= 1);
 669  674                          ist->ist_ffp_conn_count--;
 670  675                  }
 671  676                  for (ict = list_head(&ist->ist_conn_list);
 672  677                      ict != NULL;
 673  678                      ict = list_next(&ist->ist_conn_list, ict)) {
 674  679                          if ((ctx->se_ctx_event == SE_SESSION_CLOSE) &&
 675  680                              ((iscsit_conn_t *)ctx->se_event_data == ict)) {
 676  681                                  /*
 677  682                                   * Skip this connection since it will
 678  683                                   * see the logout response
 679  684                                   */
 680  685                                  continue;
 681  686                          }
 682  687                          iscsit_conn_logout(ict);
 683  688                  }
 684  689                  mutex_exit(&ist->ist_mutex);
 685  690  
 686  691                  sess_sm_new_state(ist, ctx, SS_Q6_DONE);
 687  692                  break;
 688  693          default:
 689  694                  ASSERT(0);
 690  695                  break;
 691  696          }
 692  697  }
 693  698  
 694  699  static void
 695  700  sess_sm_timeout(void *arg)
 696  701  {
 697  702          iscsit_sess_t *ist = arg;
 698  703  
 699  704          iscsit_sess_sm_event(ist, SE_SESSION_TIMEOUT, NULL);
 700  705  }
 701  706  
 702  707  static void
 703  708  sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 704  709  {
 705  710          /* Session timer must not be running when we leave this event */
 706  711          switch (ctx->se_ctx_event) {
 707  712          case SE_CONN_IN_LOGIN:
 708  713                  /* N7 */
 709  714                  sess_sm_new_state(ist, ctx, SS_Q5_CONTINUE);
 710  715                  break;
 711  716          case SE_SESSION_REINSTATE:
 712  717                  /* N6 */
 713  718                  (void) untimeout(ist->ist_state_timeout);
 714  719                  /*FALLTHROUGH*/
 715  720          case SE_SESSION_TIMEOUT:
 716  721                  /* N6 */
 717  722                  sess_sm_new_state(ist, ctx, SS_Q6_DONE);
 718  723                  break;
 719  724          case SE_CONN_FAIL:
 720  725                  /* Don't care */
 721  726                  break;
 722  727          default:
 723  728                  ASSERT(0);
 724  729                  break;
 725  730          }
 726  731  }
 727  732  
 728  733  static void
 729  734  sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 730  735  {
 731  736          switch (ctx->se_ctx_event) {
 732  737          case SE_CONN_FAIL:
 733  738                  /* N5 */
 734  739                  sess_sm_new_state(ist, ctx, SS_Q4_FAILED);
 735  740                  break;
 736  741          case SE_CONN_LOGGED_IN:
 737  742                  /* N10 */
 738  743                  sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN);
 739  744                  break;
 740  745          case SE_SESSION_REINSTATE:
 741  746                  /* N11 */
 742  747                  sess_sm_new_state(ist, ctx, SS_Q6_DONE);
 743  748                  break;
 744  749          default:
 745  750                  ASSERT(0);
 746  751                  break;
 747  752          }
 748  753  }
 749  754  
 750  755  static void
 751  756  sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 752  757  {
 753  758          /* Terminal state */
 754  759          switch (ctx->se_ctx_event) {
 755  760          case SE_CONN_LOGGED_IN:
 756  761                  /*
 757  762                   * It's possible to get this event if we encountered
 758  763                   * an SE_SESSION_REINSTATE_EVENT while we were in
 759  764                   * SS_Q2_ACTIVE state.  If so we want to update
 760  765                   * ist->ist_ffp_conn_count because we know an
 761  766                   * SE_CONN_FFP_FAIL or SE_CONN_FFP_DISABLE is on the
 762  767                   * way.
 763  768                   */
 764  769                  ist->ist_ffp_conn_count++;
 765  770                  break;
 766  771          case SE_CONN_FFP_FAIL:
 767  772          case SE_CONN_FFP_DISABLE:
 768  773                  ASSERT(ist->ist_ffp_conn_count >= 1);
 769  774                  ist->ist_ffp_conn_count--;
 770  775                  break;
 771  776          case SE_CONN_FAIL:
 772  777                  if (ist->ist_conn_count == 0) {
 773  778                          idm_refcnt_async_wait_ref(&ist->ist_refcnt,
 774  779                              &iscsit_sess_unref);
 775  780                  }
 776  781                  break;
 777  782          default:
 778  783                  break;
 779  784          }
 780  785  }
 781  786  
 782  787  static void
 783  788  sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx)
 784  789  {
 785  790          /* Terminal state */
 786  791          switch (ctx->se_ctx_event) {
 787  792          case SE_CONN_FAIL:
 788  793                  if (ist->ist_conn_count == 0) {
 789  794                          idm_refcnt_async_wait_ref(&ist->ist_refcnt,
 790  795                              &iscsit_sess_unref);
 791  796                  }
 792  797                  break;
 793  798          default:
 794  799                  break;
 795  800          }
 796  801  }
 797  802  
 798  803  static void
 799  804  sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx,
 800  805      iscsit_session_state_t new_state)
 801  806  {
 802  807          int t2r_secs;
 803  808  
 804  809          /*
 805  810           * Validate new state
 806  811           */
 807  812          ASSERT(new_state != SS_UNDEFINED);
 808  813          ASSERT3U(new_state, <, SS_MAX_STATE);
 809  814  
 810  815          new_state = (new_state < SS_MAX_STATE) ?
 811  816              new_state : SS_UNDEFINED;
 812  817  
 813  818          IDM_SM_LOG(CE_NOTE, "sess_sm_new_state: sess %p, evt %s(%d), "
 814  819              "%s(%d) --> %s(%d)\n", (void *) ist,
 815  820              iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event,
 816  821              iscsit_ss_name[ist->ist_state], ist->ist_state,
 817  822              iscsit_ss_name[new_state], new_state);
 818  823  
 819  824          DTRACE_PROBE3(sess__state__change,
 820  825              iscsit_sess_t *, ist, sess_event_ctx_t *, ctx,
 821  826              iscsit_session_state_t, new_state);
 822  827  
 823  828          mutex_enter(&ist->ist_mutex);
 824  829          idm_sm_audit_state_change(&ist->ist_state_audit, SAS_ISCSIT_SESS,
 825  830              (int)ist->ist_state, (int)new_state);
 826  831          ist->ist_last_state = ist->ist_state;
 827  832          ist->ist_state = new_state;
 828  833          mutex_exit(&ist->ist_mutex);
 829  834  
 830  835          switch (ist->ist_state) {
 831  836          case SS_Q1_FREE:
 832  837                  break;
 833  838          case SS_Q2_ACTIVE:
 834  839                  iscsit_tgt_bind_sess(ist->ist_tgt, ist);
 835  840                  break;
 836  841          case SS_Q3_LOGGED_IN:
 837  842                  break;
 838  843          case SS_Q4_FAILED:
 839  844                  t2r_secs =
 840  845                      ist->ist_failed_conn->ict_op.op_default_time_2_retain;
 841  846                  ist->ist_state_timeout = timeout(sess_sm_timeout, ist,
 842  847                      drv_usectohz(t2r_secs*1000000));
 843  848                  break;
 844  849          case SS_Q5_CONTINUE:
 845  850                  break;
 846  851          case SS_Q6_DONE:
 847  852          case SS_Q7_ERROR:
 848  853                  /*
 849  854                   * We won't need our TSIH anymore and it represents an
 850  855                   * implicit reference to the global TSIH pool.  Get rid
 851  856                   * of it.
 852  857                   */
 853  858                  if (ist->ist_tsih != ISCSI_UNSPEC_TSIH) {
 854  859                          iscsit_tsih_free(ist->ist_tsih);
 855  860                  }
 856  861  
 857  862                  /*
 858  863                   * We don't want this session to show up anymore so unbind
 859  864                   * it now.  After this call this session cannot have any
 860  865                   * references outside itself (implicit or explicit).
 861  866                   */
 862  867                  iscsit_tgt_unbind_sess(ist->ist_tgt, ist);
 863  868  
 864  869                  /*
 865  870                   * If we have more connections bound then more events
 866  871                   * are comming so don't wait for idle yet.
 867  872                   */
 868  873                  if (ist->ist_conn_count == 0) {
 869  874                          idm_refcnt_async_wait_ref(&ist->ist_refcnt,
 870  875                              &iscsit_sess_unref);
 871  876                  }
 872  877                  break;
 873  878          default:
 874  879                  ASSERT(0);
 875  880                  /*NOTREACHED*/
 876  881          }
 877  882  }
  
    | 
      ↓ open down ↓ | 
    640 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX