The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/common/io/comstar/port/iscsit/iscsit_sess.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7b1cfe603a8ad422cb02d080edbc412e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.