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