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