1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte /* 22*fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*fcf3ce44SJohn Forte * Use is subject to license terms. 24*fcf3ce44SJohn Forte * 25*fcf3ce44SJohn Forte * iSCSI connection interfaces 26*fcf3ce44SJohn Forte */ 27*fcf3ce44SJohn Forte 28*fcf3ce44SJohn Forte #include "iscsi.h" 29*fcf3ce44SJohn Forte #include "persistent.h" 30*fcf3ce44SJohn Forte 31*fcf3ce44SJohn Forte /* interface connection interfaces */ 32*fcf3ce44SJohn Forte static iscsi_status_t iscsi_conn_state_free(iscsi_conn_t *icp, 33*fcf3ce44SJohn Forte iscsi_conn_event_t event); 34*fcf3ce44SJohn Forte static void iscsi_conn_state_in_login(iscsi_conn_t *icp, 35*fcf3ce44SJohn Forte iscsi_conn_event_t event); 36*fcf3ce44SJohn Forte static void iscsi_conn_state_logged_in(iscsi_conn_t *icp, 37*fcf3ce44SJohn Forte iscsi_conn_event_t event); 38*fcf3ce44SJohn Forte static void iscsi_conn_state_in_logout(iscsi_conn_t *icp, 39*fcf3ce44SJohn Forte iscsi_conn_event_t event); 40*fcf3ce44SJohn Forte static void iscsi_conn_state_failed(iscsi_conn_t *icp, 41*fcf3ce44SJohn Forte iscsi_conn_event_t event); 42*fcf3ce44SJohn Forte static void iscsi_conn_state_polling(iscsi_conn_t *icp, 43*fcf3ce44SJohn Forte iscsi_conn_event_t event); 44*fcf3ce44SJohn Forte static char *iscsi_conn_event_str(iscsi_conn_event_t event); 45*fcf3ce44SJohn Forte static void iscsi_conn_flush_active_cmds(iscsi_conn_t *icp); 46*fcf3ce44SJohn Forte 47*fcf3ce44SJohn Forte static void iscsi_conn_logged_in(iscsi_sess_t *isp, 48*fcf3ce44SJohn Forte iscsi_conn_t *icp); 49*fcf3ce44SJohn Forte static void iscsi_conn_retry(iscsi_sess_t *isp, 50*fcf3ce44SJohn Forte iscsi_conn_t *icp); 51*fcf3ce44SJohn Forte 52*fcf3ce44SJohn Forte #define SHUTDOWN_TIMEOUT 180 /* seconds */ 53*fcf3ce44SJohn Forte 54*fcf3ce44SJohn Forte /* 55*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 56*fcf3ce44SJohn Forte * | External Connection Interfaces | 57*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 58*fcf3ce44SJohn Forte */ 59*fcf3ce44SJohn Forte 60*fcf3ce44SJohn Forte /* 61*fcf3ce44SJohn Forte * iscsi_conn_create - This creates an iscsi connection structure and 62*fcf3ce44SJohn Forte * associates it with a session structure. The session's sess_conn_list_rwlock 63*fcf3ce44SJohn Forte * should be held as a writer before calling this function. 64*fcf3ce44SJohn Forte */ 65*fcf3ce44SJohn Forte iscsi_status_t 66*fcf3ce44SJohn Forte iscsi_conn_create(struct sockaddr *addr, iscsi_sess_t *isp, iscsi_conn_t **icpp) 67*fcf3ce44SJohn Forte { 68*fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 69*fcf3ce44SJohn Forte char th_name[ISCSI_TH_MAX_NAME_LEN]; 70*fcf3ce44SJohn Forte 71*fcf3ce44SJohn Forte /* See if this connection already exists */ 72*fcf3ce44SJohn Forte for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) { 73*fcf3ce44SJohn Forte 74*fcf3ce44SJohn Forte /* 75*fcf3ce44SJohn Forte * Compare the ioctl information to see if 76*fcf3ce44SJohn Forte * its a match for this connection. (This 77*fcf3ce44SJohn Forte * is done by making sure the IPs are of 78*fcf3ce44SJohn Forte * the same size and then they are the 79*fcf3ce44SJohn Forte * same value. 80*fcf3ce44SJohn Forte */ 81*fcf3ce44SJohn Forte if (bcmp(&icp->conn_base_addr, addr, 82*fcf3ce44SJohn Forte SIZEOF_SOCKADDR(addr)) == 0) { 83*fcf3ce44SJohn Forte /* It's a match, record this connection */ 84*fcf3ce44SJohn Forte break; 85*fcf3ce44SJohn Forte } 86*fcf3ce44SJohn Forte } 87*fcf3ce44SJohn Forte 88*fcf3ce44SJohn Forte /* If icp is found return it */ 89*fcf3ce44SJohn Forte if (icp != NULL) { 90*fcf3ce44SJohn Forte *icpp = icp; 91*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 92*fcf3ce44SJohn Forte } 93*fcf3ce44SJohn Forte 94*fcf3ce44SJohn Forte /* We are creating the connection, allocate, and setup */ 95*fcf3ce44SJohn Forte icp = (iscsi_conn_t *)kmem_zalloc(sizeof (iscsi_conn_t), KM_SLEEP); 96*fcf3ce44SJohn Forte 97*fcf3ce44SJohn Forte /* 98*fcf3ce44SJohn Forte * Setup connection 99*fcf3ce44SJohn Forte */ 100*fcf3ce44SJohn Forte icp->conn_sig = ISCSI_SIG_CONN; 101*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 102*fcf3ce44SJohn Forte mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL); 103*fcf3ce44SJohn Forte cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL); 104*fcf3ce44SJohn Forte icp->conn_state_destroy = B_FALSE; 105*fcf3ce44SJohn Forte icp->conn_sess = isp; 106*fcf3ce44SJohn Forte icp->conn_state_lbolt = ddi_get_lbolt(); 107*fcf3ce44SJohn Forte 108*fcf3ce44SJohn Forte mutex_enter(&iscsi_oid_mutex); 109*fcf3ce44SJohn Forte icp->conn_oid = iscsi_oid++; 110*fcf3ce44SJohn Forte mutex_exit(&iscsi_oid_mutex); 111*fcf3ce44SJohn Forte 112*fcf3ce44SJohn Forte /* Creation of the receive thread */ 113*fcf3ce44SJohn Forte if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_RXTH_NAME_FORMAT, 114*fcf3ce44SJohn Forte icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, 115*fcf3ce44SJohn Forte icp->conn_oid) >= sizeof (th_name)) { 116*fcf3ce44SJohn Forte cv_destroy(&icp->conn_state_change); 117*fcf3ce44SJohn Forte mutex_destroy(&icp->conn_state_mutex); 118*fcf3ce44SJohn Forte kmem_free(icp, sizeof (iscsi_conn_t)); 119*fcf3ce44SJohn Forte *icpp = NULL; 120*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 121*fcf3ce44SJohn Forte } 122*fcf3ce44SJohn Forte 123*fcf3ce44SJohn Forte icp->conn_rx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, 124*fcf3ce44SJohn Forte th_name, iscsi_rx_thread, icp); 125*fcf3ce44SJohn Forte 126*fcf3ce44SJohn Forte /* Creation of the transfer thread */ 127*fcf3ce44SJohn Forte if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT, 128*fcf3ce44SJohn Forte icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, 129*fcf3ce44SJohn Forte icp->conn_oid) >= sizeof (th_name)) { 130*fcf3ce44SJohn Forte iscsi_thread_destroy(icp->conn_rx_thread); 131*fcf3ce44SJohn Forte cv_destroy(&icp->conn_state_change); 132*fcf3ce44SJohn Forte mutex_destroy(&icp->conn_state_mutex); 133*fcf3ce44SJohn Forte kmem_free(icp, sizeof (iscsi_conn_t)); 134*fcf3ce44SJohn Forte *icpp = NULL; 135*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 136*fcf3ce44SJohn Forte } 137*fcf3ce44SJohn Forte 138*fcf3ce44SJohn Forte icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, 139*fcf3ce44SJohn Forte th_name, iscsi_tx_thread, icp); 140*fcf3ce44SJohn Forte 141*fcf3ce44SJohn Forte /* setup connection queues */ 142*fcf3ce44SJohn Forte iscsi_init_queue(&icp->conn_queue_active); 143*fcf3ce44SJohn Forte 144*fcf3ce44SJohn Forte bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr)); 145*fcf3ce44SJohn Forte 146*fcf3ce44SJohn Forte /* Add new connection to the session connection list */ 147*fcf3ce44SJohn Forte icp->conn_cid = isp->sess_conn_next_cid++; 148*fcf3ce44SJohn Forte if (isp->sess_conn_list == NULL) { 149*fcf3ce44SJohn Forte isp->sess_conn_list = isp->sess_conn_list_last_ptr = icp; 150*fcf3ce44SJohn Forte } else { 151*fcf3ce44SJohn Forte isp->sess_conn_list_last_ptr->conn_next = icp; 152*fcf3ce44SJohn Forte isp->sess_conn_list_last_ptr = icp; 153*fcf3ce44SJohn Forte } 154*fcf3ce44SJohn Forte 155*fcf3ce44SJohn Forte KSTAT_INC_SESS_CNTR_CONN(isp); 156*fcf3ce44SJohn Forte (void) iscsi_conn_kstat_init(icp); 157*fcf3ce44SJohn Forte 158*fcf3ce44SJohn Forte *icpp = icp; 159*fcf3ce44SJohn Forte 160*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 161*fcf3ce44SJohn Forte } 162*fcf3ce44SJohn Forte 163*fcf3ce44SJohn Forte 164*fcf3ce44SJohn Forte /* 165*fcf3ce44SJohn Forte * iscsi_conn_offline - This attempts to take a connection from 166*fcf3ce44SJohn Forte * any state to ISCSI_CONN_STATE_FREE. 167*fcf3ce44SJohn Forte */ 168*fcf3ce44SJohn Forte iscsi_status_t 169*fcf3ce44SJohn Forte iscsi_conn_offline(iscsi_conn_t *icp) 170*fcf3ce44SJohn Forte { 171*fcf3ce44SJohn Forte clock_t delay; 172*fcf3ce44SJohn Forte 173*fcf3ce44SJohn Forte ASSERT(icp != NULL); 174*fcf3ce44SJohn Forte 175*fcf3ce44SJohn Forte /* 176*fcf3ce44SJohn Forte * We can only destroy a connection if its either in 177*fcf3ce44SJohn Forte * a state of FREE or LOGGED. The other states are 178*fcf3ce44SJohn Forte * transitionary and its unsafe to perform actions 179*fcf3ce44SJohn Forte * on the connection in those states. Set a flag 180*fcf3ce44SJohn Forte * on the connection to influence the transitions 181*fcf3ce44SJohn Forte * to quickly complete. Then wait for a state 182*fcf3ce44SJohn Forte * transition. 183*fcf3ce44SJohn Forte */ 184*fcf3ce44SJohn Forte delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT); 185*fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 186*fcf3ce44SJohn Forte icp->conn_state_destroy = B_TRUE; 187*fcf3ce44SJohn Forte while ((icp->conn_state != ISCSI_CONN_STATE_FREE) && 188*fcf3ce44SJohn Forte (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN) && 189*fcf3ce44SJohn Forte (ddi_get_lbolt() < delay)) { 190*fcf3ce44SJohn Forte /* wait for transition */ 191*fcf3ce44SJohn Forte (void) cv_timedwait(&icp->conn_state_change, 192*fcf3ce44SJohn Forte &icp->conn_state_mutex, delay); 193*fcf3ce44SJohn Forte } 194*fcf3ce44SJohn Forte 195*fcf3ce44SJohn Forte /* Final check whether we can destroy the connection */ 196*fcf3ce44SJohn Forte switch (icp->conn_state) { 197*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FREE: 198*fcf3ce44SJohn Forte /* Easy case - Connection is dead */ 199*fcf3ce44SJohn Forte break; 200*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_LOGGED_IN: 201*fcf3ce44SJohn Forte /* Hard case - Force connection logout */ 202*fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, 203*fcf3ce44SJohn Forte ISCSI_CONN_EVENT_T9); 204*fcf3ce44SJohn Forte break; 205*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGIN: 206*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGOUT: 207*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FAILED: 208*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_POLLING: 209*fcf3ce44SJohn Forte default: 210*fcf3ce44SJohn Forte /* All other cases fail the destroy */ 211*fcf3ce44SJohn Forte icp->conn_state_destroy = B_FALSE; 212*fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 213*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 214*fcf3ce44SJohn Forte } 215*fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 216*fcf3ce44SJohn Forte 217*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 218*fcf3ce44SJohn Forte } 219*fcf3ce44SJohn Forte 220*fcf3ce44SJohn Forte /* 221*fcf3ce44SJohn Forte * iscsi_conn_destroy - This destroys an iscsi connection structure 222*fcf3ce44SJohn Forte * and de-associates it with the session. The connection should 223*fcf3ce44SJohn Forte * already been in the ISCSI_CONN_STATE_FREE when attempting this 224*fcf3ce44SJohn Forte * operation. 225*fcf3ce44SJohn Forte */ 226*fcf3ce44SJohn Forte iscsi_status_t 227*fcf3ce44SJohn Forte iscsi_conn_destroy(iscsi_conn_t *icp) 228*fcf3ce44SJohn Forte { 229*fcf3ce44SJohn Forte iscsi_sess_t *isp; 230*fcf3ce44SJohn Forte iscsi_conn_t *t_icp; 231*fcf3ce44SJohn Forte 232*fcf3ce44SJohn Forte ASSERT(icp != NULL); 233*fcf3ce44SJohn Forte isp = icp->conn_sess; 234*fcf3ce44SJohn Forte ASSERT(isp != NULL); 235*fcf3ce44SJohn Forte 236*fcf3ce44SJohn Forte if (icp->conn_state != ISCSI_CONN_STATE_FREE) { 237*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 238*fcf3ce44SJohn Forte } 239*fcf3ce44SJohn Forte 240*fcf3ce44SJohn Forte /* Destroy receive thread */ 241*fcf3ce44SJohn Forte iscsi_thread_destroy(icp->conn_rx_thread); 242*fcf3ce44SJohn Forte 243*fcf3ce44SJohn Forte /* Destroy transfer thread */ 244*fcf3ce44SJohn Forte iscsi_thread_destroy(icp->conn_tx_thread); 245*fcf3ce44SJohn Forte 246*fcf3ce44SJohn Forte /* Terminate connection queues */ 247*fcf3ce44SJohn Forte iscsi_destroy_queue(&icp->conn_queue_active); 248*fcf3ce44SJohn Forte 249*fcf3ce44SJohn Forte cv_destroy(&icp->conn_state_change); 250*fcf3ce44SJohn Forte mutex_destroy(&icp->conn_state_mutex); 251*fcf3ce44SJohn Forte 252*fcf3ce44SJohn Forte /* 253*fcf3ce44SJohn Forte * Remove connection from sessions linked list. 254*fcf3ce44SJohn Forte */ 255*fcf3ce44SJohn Forte if (isp->sess_conn_list == icp) { 256*fcf3ce44SJohn Forte /* connection first item in list */ 257*fcf3ce44SJohn Forte isp->sess_conn_list = icp->conn_next; 258*fcf3ce44SJohn Forte /* 259*fcf3ce44SJohn Forte * check if this is also the last item in the list 260*fcf3ce44SJohn Forte */ 261*fcf3ce44SJohn Forte if (isp->sess_conn_list_last_ptr == icp) { 262*fcf3ce44SJohn Forte isp->sess_conn_list_last_ptr = NULL; 263*fcf3ce44SJohn Forte } 264*fcf3ce44SJohn Forte } else { 265*fcf3ce44SJohn Forte /* 266*fcf3ce44SJohn Forte * search session list for icp pointing 267*fcf3ce44SJohn Forte * to connection being removed. Then 268*fcf3ce44SJohn Forte * update that connections next pointer. 269*fcf3ce44SJohn Forte */ 270*fcf3ce44SJohn Forte t_icp = isp->sess_conn_list; 271*fcf3ce44SJohn Forte while (t_icp->conn_next != NULL) { 272*fcf3ce44SJohn Forte if (t_icp->conn_next == icp) { 273*fcf3ce44SJohn Forte break; 274*fcf3ce44SJohn Forte } 275*fcf3ce44SJohn Forte t_icp = t_icp->conn_next; 276*fcf3ce44SJohn Forte } 277*fcf3ce44SJohn Forte if (t_icp->conn_next == icp) { 278*fcf3ce44SJohn Forte t_icp->conn_next = icp->conn_next; 279*fcf3ce44SJohn Forte /* 280*fcf3ce44SJohn Forte * if this is the last connection in the list 281*fcf3ce44SJohn Forte * update the last_ptr to point to t_icp 282*fcf3ce44SJohn Forte */ 283*fcf3ce44SJohn Forte if (isp->sess_conn_list_last_ptr == icp) { 284*fcf3ce44SJohn Forte isp->sess_conn_list_last_ptr = t_icp; 285*fcf3ce44SJohn Forte } 286*fcf3ce44SJohn Forte } else { 287*fcf3ce44SJohn Forte /* couldn't find session */ 288*fcf3ce44SJohn Forte ASSERT(FALSE); 289*fcf3ce44SJohn Forte } 290*fcf3ce44SJohn Forte } 291*fcf3ce44SJohn Forte 292*fcf3ce44SJohn Forte /* Free this Connections Data */ 293*fcf3ce44SJohn Forte iscsi_conn_kstat_term(icp); 294*fcf3ce44SJohn Forte kmem_free(icp, sizeof (iscsi_conn_t)); 295*fcf3ce44SJohn Forte 296*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 297*fcf3ce44SJohn Forte } 298*fcf3ce44SJohn Forte 299*fcf3ce44SJohn Forte 300*fcf3ce44SJohn Forte /* 301*fcf3ce44SJohn Forte * iscsi_conn_set_login_min_max - set min/max login window 302*fcf3ce44SJohn Forte * 303*fcf3ce44SJohn Forte * Used to set the min and max login window. Input values 304*fcf3ce44SJohn Forte * are in seconds. 305*fcf3ce44SJohn Forte */ 306*fcf3ce44SJohn Forte void 307*fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(iscsi_conn_t *icp, int min, int max) 308*fcf3ce44SJohn Forte { 309*fcf3ce44SJohn Forte ASSERT(icp != NULL); 310*fcf3ce44SJohn Forte 311*fcf3ce44SJohn Forte icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min); 312*fcf3ce44SJohn Forte icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max); 313*fcf3ce44SJohn Forte } 314*fcf3ce44SJohn Forte 315*fcf3ce44SJohn Forte 316*fcf3ce44SJohn Forte 317*fcf3ce44SJohn Forte /* 318*fcf3ce44SJohn Forte * iscsi_conn_state_machine - This function is used to drive the 319*fcf3ce44SJohn Forte * state machine of the iscsi connection. It takes in a connection 320*fcf3ce44SJohn Forte * and the associated event effecting the connection. 321*fcf3ce44SJohn Forte * 322*fcf3ce44SJohn Forte * 7.1.3 Connection State Diagram for an Initiator 323*fcf3ce44SJohn Forte * Symbolic Names for States: 324*fcf3ce44SJohn Forte * S1: FREE - State on instantiation, or after successful 325*fcf3ce44SJohn Forte * connection closure. 326*fcf3ce44SJohn Forte * S2: IN_LOGIN - Waiting for login process to conclude, 327*fcf3ce44SJohn Forte * possibly involving several PDU exchanges. 328*fcf3ce44SJohn Forte * S3: LOGGED_IN - In Full Feature Phase, waiting for all internal, 329*fcf3ce44SJohn Forte * iSCSI, and transport events 330*fcf3ce44SJohn Forte * S4: IN_LOGOUT - Waiting for the Logout repsonse. 331*fcf3ce44SJohn Forte * S5: FAILED - The connection has failed. Attempting 332*fcf3ce44SJohn Forte * to reconnect. 333*fcf3ce44SJohn Forte * S6: POLLING - The connection reconnect attempts have 334*fcf3ce44SJohn Forte * failed. Continue to poll at a lower 335*fcf3ce44SJohn Forte * frequency. 336*fcf3ce44SJohn Forte * 337*fcf3ce44SJohn Forte * States S3, S4 constitute the Full Feature Phase 338*fcf3ce44SJohn Forte * of the connection. 339*fcf3ce44SJohn Forte * 340*fcf3ce44SJohn Forte * The state diagram is as follows: 341*fcf3ce44SJohn Forte * ------- 342*fcf3ce44SJohn Forte * +-------->/ S1 \<------------------------------+ 343*fcf3ce44SJohn Forte * | +->\ /<---+ /---\ | 344*fcf3ce44SJohn Forte * | / ---+--- |T7/30 T7| | | 345*fcf3ce44SJohn Forte * | + | | \->------ | 346*fcf3ce44SJohn Forte * | T8| |T1 / T5 / S6 \--->| 347*fcf3ce44SJohn Forte * | | | / +----------\ /T30 | 348*fcf3ce44SJohn Forte * | | V / / ------ | 349*fcf3ce44SJohn Forte * | | ------- / / ^ | 350*fcf3ce44SJohn Forte * | | / S2 \ / T5 |T7 | 351*fcf3ce44SJohn Forte * | | \ / +-------------- --+--- | 352*fcf3ce44SJohn Forte * | | ---+--- / / S5 \--->| 353*fcf3ce44SJohn Forte * | | | / T14/T15 \ /T30 | 354*fcf3ce44SJohn Forte * | | |T5 / +-------------> ------ | 355*fcf3ce44SJohn Forte * | | | / / | 356*fcf3ce44SJohn Forte * | | | / / T11 | 357*fcf3ce44SJohn Forte * | | | / / +----+ | 358*fcf3ce44SJohn Forte * | | V V / | | | 359*fcf3ce44SJohn Forte * | | ------+ ----+-- | | 360*fcf3ce44SJohn Forte * | +-----/ S3 \T9/11/ S4 \<+ | 361*fcf3ce44SJohn Forte * +----------\ /---->\ /----------------+ 362*fcf3ce44SJohn Forte * ------- ------- T15/T17 363*fcf3ce44SJohn Forte * 364*fcf3ce44SJohn Forte * The state transition table is as follows: 365*fcf3ce44SJohn Forte * 366*fcf3ce44SJohn Forte * +-----+---+---+------+------+---+ 367*fcf3ce44SJohn Forte * |S1 |S2 |S3 |S4 |S5 |S6 | 368*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 369*fcf3ce44SJohn Forte * S1|T1 |T1 | - | - | - | | 370*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 371*fcf3ce44SJohn Forte * S2|T7/30|- |T5 | - | - | | 372*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 373*fcf3ce44SJohn Forte * S3|T8 |- | - |T9/11 |T14/15| | 374*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 375*fcf3ce44SJohn Forte * S4| |- | - |T11 |T15/17| | 376*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 377*fcf3ce44SJohn Forte * S5|T30 | |T5 | | |T7 | 378*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 379*fcf3ce44SJohn Forte * S6|T30 | |T5 | | |T7 | 380*fcf3ce44SJohn Forte * ---+-----+---+---+------+------+---+ 381*fcf3ce44SJohn Forte * 382*fcf3ce44SJohn Forte * Events definitions: 383*fcf3ce44SJohn Forte * 384*fcf3ce44SJohn Forte * -T1: Transport connection request was made (e.g., TCP SYN sent). 385*fcf3ce44SJohn Forte * -T5: The final iSCSI Login response with a Status-Class of zero was 386*fcf3ce44SJohn Forte * received. 387*fcf3ce44SJohn Forte * -T7: One of the following events caused the transition: 388*fcf3ce44SJohn Forte * - Login timed out. 389*fcf3ce44SJohn Forte * - A transport disconnect indication was received. 390*fcf3ce44SJohn Forte * - A transport reset was received. 391*fcf3ce44SJohn Forte * - An internal event indicating a transport timeout was 392*fcf3ce44SJohn Forte * received. 393*fcf3ce44SJohn Forte * - An internal event of receiving a Logout repsonse (success) 394*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout 395*fcf3ce44SJohn Forte * request was received. 396*fcf3ce44SJohn Forte * * In all these cases, the transport connection is closed. 397*fcf3ce44SJohn Forte * -T8: An internal event of receiving a Logout response (success) 398*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout request 399*fcf3ce44SJohn Forte * was received, thus closing this connection requiring no further 400*fcf3ce44SJohn Forte * cleanup. 401*fcf3ce44SJohn Forte * -T9: An internal event that indicates the readiness to start the 402*fcf3ce44SJohn Forte * Logout process was received, thus prompting an iSCSI Logout to 403*fcf3ce44SJohn Forte * be sent by the initiator. 404*fcf3ce44SJohn Forte * -T11: Async PDU with AsyncEvent "Request Logout" was received. 405*fcf3ce44SJohn Forte * -T13: An iSCSI Logout response (success) was received, or an internal 406*fcf3ce44SJohn Forte * event of receiving a Logout response (success) on another 407*fcf3ce44SJohn Forte * connection was received. 408*fcf3ce44SJohn Forte * -T14: One or more of the following events case this transition: 409*fcf3ce44SJohn Forte * - Header Digest Error 410*fcf3ce44SJohn Forte * - Protocol Error 411*fcf3ce44SJohn Forte * -T15: One or more of the following events caused this transition: 412*fcf3ce44SJohn Forte * - Internal event that indicates a transport connection timeout 413*fcf3ce44SJohn Forte * was received thus prompting transport RESET or transport 414*fcf3ce44SJohn Forte * connection closure. 415*fcf3ce44SJohn Forte * - A transport RESET 416*fcf3ce44SJohn Forte * - A transport disconnect indication. 417*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop connection" (for this CID) 418*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop all connections" 419*fcf3ce44SJohn Forte * -T17: One or more of the following events caused this transition: 420*fcf3ce44SJohn Forte * - Logout response, (failure i.e., a non-zero status) was 421*fcf3ce44SJohn Forte * received, or Logout timed out. 422*fcf3ce44SJohn Forte * - Any of the events specified for T15. 423*fcf3ce44SJohn Forte * -T30: One of the following event caused the transition: 424*fcf3ce44SJohn Forte * - Thefinal iSCSI Login response was received with a non-zero 425*fcf3ce44SJohn Forte * Status-Class. 426*fcf3ce44SJohn Forte */ 427*fcf3ce44SJohn Forte iscsi_status_t 428*fcf3ce44SJohn Forte iscsi_conn_state_machine(iscsi_conn_t *icp, iscsi_conn_event_t event) 429*fcf3ce44SJohn Forte { 430*fcf3ce44SJohn Forte iscsi_status_t status = ISCSI_STATUS_SUCCESS; 431*fcf3ce44SJohn Forte 432*fcf3ce44SJohn Forte ASSERT(icp != NULL); 433*fcf3ce44SJohn Forte ASSERT(mutex_owned(&icp->conn_state_mutex)); 434*fcf3ce44SJohn Forte 435*fcf3ce44SJohn Forte DTRACE_PROBE3(event, iscsi_conn_t *, icp, 436*fcf3ce44SJohn Forte char *, iscsi_conn_state_str(icp->conn_state), 437*fcf3ce44SJohn Forte char *, iscsi_conn_event_str(event)); 438*fcf3ce44SJohn Forte 439*fcf3ce44SJohn Forte icp->conn_prev_state = icp->conn_state; 440*fcf3ce44SJohn Forte icp->conn_state_lbolt = ddi_get_lbolt(); 441*fcf3ce44SJohn Forte 442*fcf3ce44SJohn Forte switch (icp->conn_state) { 443*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FREE: 444*fcf3ce44SJohn Forte status = iscsi_conn_state_free(icp, event); 445*fcf3ce44SJohn Forte break; 446*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGIN: 447*fcf3ce44SJohn Forte iscsi_conn_state_in_login(icp, event); 448*fcf3ce44SJohn Forte break; 449*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_LOGGED_IN: 450*fcf3ce44SJohn Forte iscsi_conn_state_logged_in(icp, event); 451*fcf3ce44SJohn Forte break; 452*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGOUT: 453*fcf3ce44SJohn Forte iscsi_conn_state_in_logout(icp, event); 454*fcf3ce44SJohn Forte break; 455*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FAILED: 456*fcf3ce44SJohn Forte iscsi_conn_state_failed(icp, event); 457*fcf3ce44SJohn Forte break; 458*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_POLLING: 459*fcf3ce44SJohn Forte iscsi_conn_state_polling(icp, event); 460*fcf3ce44SJohn Forte break; 461*fcf3ce44SJohn Forte default: 462*fcf3ce44SJohn Forte ASSERT(FALSE); 463*fcf3ce44SJohn Forte status = ISCSI_STATUS_INTERNAL_ERROR; 464*fcf3ce44SJohn Forte } 465*fcf3ce44SJohn Forte 466*fcf3ce44SJohn Forte cv_broadcast(&icp->conn_state_change); 467*fcf3ce44SJohn Forte return (status); 468*fcf3ce44SJohn Forte } 469*fcf3ce44SJohn Forte 470*fcf3ce44SJohn Forte 471*fcf3ce44SJohn Forte /* 472*fcf3ce44SJohn Forte * iscsi_conn_state_str - converts state enum to a string 473*fcf3ce44SJohn Forte */ 474*fcf3ce44SJohn Forte char * 475*fcf3ce44SJohn Forte iscsi_conn_state_str(iscsi_conn_state_t state) 476*fcf3ce44SJohn Forte { 477*fcf3ce44SJohn Forte switch (state) { 478*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FREE: 479*fcf3ce44SJohn Forte return ("free"); 480*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGIN: 481*fcf3ce44SJohn Forte return ("in_login"); 482*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_LOGGED_IN: 483*fcf3ce44SJohn Forte return ("logged_in"); 484*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_IN_LOGOUT: 485*fcf3ce44SJohn Forte return ("in_logout"); 486*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_FAILED: 487*fcf3ce44SJohn Forte return ("failed"); 488*fcf3ce44SJohn Forte case ISCSI_CONN_STATE_POLLING: 489*fcf3ce44SJohn Forte return ("polling"); 490*fcf3ce44SJohn Forte default: 491*fcf3ce44SJohn Forte return ("unknown"); 492*fcf3ce44SJohn Forte } 493*fcf3ce44SJohn Forte } 494*fcf3ce44SJohn Forte 495*fcf3ce44SJohn Forte 496*fcf3ce44SJohn Forte /* 497*fcf3ce44SJohn Forte * iscsi_conn_sync_params - used to update connection parameters 498*fcf3ce44SJohn Forte * 499*fcf3ce44SJohn Forte * Used to update connection parameters with current configured 500*fcf3ce44SJohn Forte * parameters in the persistent store. This should be called 501*fcf3ce44SJohn Forte * before starting to make a new iscsi connection in iscsi_login. 502*fcf3ce44SJohn Forte */ 503*fcf3ce44SJohn Forte iscsi_status_t 504*fcf3ce44SJohn Forte iscsi_conn_sync_params(iscsi_conn_t *icp) 505*fcf3ce44SJohn Forte { 506*fcf3ce44SJohn Forte iscsi_sess_t *isp; 507*fcf3ce44SJohn Forte iscsi_hba_t *ihp; 508*fcf3ce44SJohn Forte int param_id; 509*fcf3ce44SJohn Forte persistent_param_t pp; 510*fcf3ce44SJohn Forte iscsi_config_sess_t *ics; 511*fcf3ce44SJohn Forte int idx, size; 512*fcf3ce44SJohn Forte char *name; 513*fcf3ce44SJohn Forte 514*fcf3ce44SJohn Forte ASSERT(icp != NULL); 515*fcf3ce44SJohn Forte ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) || 516*fcf3ce44SJohn Forte (icp->conn_state == ISCSI_CONN_STATE_FAILED) || 517*fcf3ce44SJohn Forte (icp->conn_state == ISCSI_CONN_STATE_POLLING)); 518*fcf3ce44SJohn Forte isp = icp->conn_sess; 519*fcf3ce44SJohn Forte ASSERT(isp != NULL); 520*fcf3ce44SJohn Forte ihp = isp->sess_hba; 521*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 522*fcf3ce44SJohn Forte 523*fcf3ce44SJohn Forte /* 524*fcf3ce44SJohn Forte * Check if someone is trying to destroy this 525*fcf3ce44SJohn Forte * connection. If so fail the sync request, 526*fcf3ce44SJohn Forte * as a method of fast fail. 527*fcf3ce44SJohn Forte */ 528*fcf3ce44SJohn Forte if (icp->conn_state_destroy == B_TRUE) { 529*fcf3ce44SJohn Forte return (ISCSI_STATUS_SHUTDOWN); 530*fcf3ce44SJohn Forte } 531*fcf3ce44SJohn Forte 532*fcf3ce44SJohn Forte bzero(&pp, sizeof (pp)); 533*fcf3ce44SJohn Forte 534*fcf3ce44SJohn Forte /* First get a copy of the HBA params */ 535*fcf3ce44SJohn Forte bcopy(&ihp->hba_params, &icp->conn_params, 536*fcf3ce44SJohn Forte sizeof (iscsi_login_params_t)); 537*fcf3ce44SJohn Forte 538*fcf3ce44SJohn Forte /* 539*fcf3ce44SJohn Forte * Now we need to get the session configured 540*fcf3ce44SJohn Forte * values from the persistent store and apply 541*fcf3ce44SJohn Forte * them to our connection. 542*fcf3ce44SJohn Forte */ 543*fcf3ce44SJohn Forte (void) persistent_param_get((char *)isp->sess_name, &pp); 544*fcf3ce44SJohn Forte for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 545*fcf3ce44SJohn Forte param_id++) { 546*fcf3ce44SJohn Forte if (pp.p_bitmap & (1 << param_id)) { 547*fcf3ce44SJohn Forte 548*fcf3ce44SJohn Forte switch (param_id) { 549*fcf3ce44SJohn Forte /* 550*fcf3ce44SJohn Forte * Boolean parameters 551*fcf3ce44SJohn Forte */ 552*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 553*fcf3ce44SJohn Forte icp->conn_params.data_pdu_in_order = 554*fcf3ce44SJohn Forte pp.p_params.data_pdu_in_order; 555*fcf3ce44SJohn Forte break; 556*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 557*fcf3ce44SJohn Forte icp->conn_params.immediate_data = 558*fcf3ce44SJohn Forte pp.p_params.immediate_data; 559*fcf3ce44SJohn Forte break; 560*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_INITIAL_R2T: 561*fcf3ce44SJohn Forte icp->conn_params.initial_r2t = 562*fcf3ce44SJohn Forte pp.p_params.initial_r2t; 563*fcf3ce44SJohn Forte break; 564*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 565*fcf3ce44SJohn Forte icp->conn_params.data_pdu_in_order = 566*fcf3ce44SJohn Forte pp.p_params.data_pdu_in_order; 567*fcf3ce44SJohn Forte break; 568*fcf3ce44SJohn Forte /* 569*fcf3ce44SJohn Forte * Integer parameters 570*fcf3ce44SJohn Forte */ 571*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 572*fcf3ce44SJohn Forte icp->conn_params.header_digest = 573*fcf3ce44SJohn Forte pp.p_params.header_digest; 574*fcf3ce44SJohn Forte break; 575*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_DATA_DIGEST: 576*fcf3ce44SJohn Forte icp->conn_params.data_digest = 577*fcf3ce44SJohn Forte pp.p_params.data_digest; 578*fcf3ce44SJohn Forte break; 579*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 580*fcf3ce44SJohn Forte icp->conn_params.default_time_to_retain = 581*fcf3ce44SJohn Forte pp.p_params.default_time_to_retain; 582*fcf3ce44SJohn Forte break; 583*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 584*fcf3ce44SJohn Forte icp->conn_params.default_time_to_wait = 585*fcf3ce44SJohn Forte pp.p_params.default_time_to_wait; 586*fcf3ce44SJohn Forte break; 587*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 588*fcf3ce44SJohn Forte icp->conn_params.max_recv_data_seg_len = 589*fcf3ce44SJohn Forte pp.p_params.max_recv_data_seg_len; 590*fcf3ce44SJohn Forte break; 591*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 592*fcf3ce44SJohn Forte icp->conn_params.first_burst_length = 593*fcf3ce44SJohn Forte pp.p_params.first_burst_length; 594*fcf3ce44SJohn Forte break; 595*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 596*fcf3ce44SJohn Forte icp->conn_params.max_burst_length = 597*fcf3ce44SJohn Forte pp.p_params.max_burst_length; 598*fcf3ce44SJohn Forte break; 599*fcf3ce44SJohn Forte 600*fcf3ce44SJohn Forte /* 601*fcf3ce44SJohn Forte * Integer parameters which currently are unsettable 602*fcf3ce44SJohn Forte */ 603*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 604*fcf3ce44SJohn Forte /* FALLTHRU */ 605*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 606*fcf3ce44SJohn Forte /* FALLTHRU */ 607*fcf3ce44SJohn Forte case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 608*fcf3ce44SJohn Forte /* FALLTHRU */ 609*fcf3ce44SJohn Forte default: 610*fcf3ce44SJohn Forte break; 611*fcf3ce44SJohn Forte } 612*fcf3ce44SJohn Forte } 613*fcf3ce44SJohn Forte } 614*fcf3ce44SJohn Forte 615*fcf3ce44SJohn Forte /* Skip binding checks on discovery sessions */ 616*fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) { 617*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 618*fcf3ce44SJohn Forte } 619*fcf3ce44SJohn Forte 620*fcf3ce44SJohn Forte /* 621*fcf3ce44SJohn Forte * Now we need to get the current optional connection 622*fcf3ce44SJohn Forte * binding information. 623*fcf3ce44SJohn Forte */ 624*fcf3ce44SJohn Forte /* setup initial buffer for configured session information */ 625*fcf3ce44SJohn Forte size = sizeof (*ics); 626*fcf3ce44SJohn Forte ics = kmem_zalloc(size, KM_SLEEP); 627*fcf3ce44SJohn Forte ics->ics_in = 1; 628*fcf3ce44SJohn Forte 629*fcf3ce44SJohn Forte /* get configured sessions information */ 630*fcf3ce44SJohn Forte name = (char *)isp->sess_name; 631*fcf3ce44SJohn Forte if (persistent_get_config_session(name, ics) == B_FALSE) { 632*fcf3ce44SJohn Forte /* 633*fcf3ce44SJohn Forte * If we were unable to get target level information 634*fcf3ce44SJohn Forte * then check the initiator level information. 635*fcf3ce44SJohn Forte */ 636*fcf3ce44SJohn Forte name = (char *)isp->sess_hba->hba_name; 637*fcf3ce44SJohn Forte if (persistent_get_config_session(name, ics) == B_FALSE) { 638*fcf3ce44SJohn Forte /* 639*fcf3ce44SJohn Forte * No hba information is found. So assume default 640*fcf3ce44SJohn Forte * one session unbound behavior. 641*fcf3ce44SJohn Forte */ 642*fcf3ce44SJohn Forte ics->ics_out = 1; 643*fcf3ce44SJohn Forte ics->ics_bound = B_FALSE; 644*fcf3ce44SJohn Forte } 645*fcf3ce44SJohn Forte } 646*fcf3ce44SJohn Forte 647*fcf3ce44SJohn Forte /* 648*fcf3ce44SJohn Forte * Check to make sure this session is still a configured 649*fcf3ce44SJohn Forte * session. The user might have decreased the session 650*fcf3ce44SJohn Forte * count. (NOTE: byte 5 of the sess_isid is the session 651*fcf3ce44SJohn Forte * count (via MS/T). This counter starts at 0.) 652*fcf3ce44SJohn Forte */ 653*fcf3ce44SJohn Forte idx = isp->sess_isid[5]; 654*fcf3ce44SJohn Forte if (ics->ics_out <= idx) { 655*fcf3ce44SJohn Forte /* 656*fcf3ce44SJohn Forte * No longer a configured session. Return a 657*fcf3ce44SJohn Forte * failure so we don't attempt to relogin. 658*fcf3ce44SJohn Forte */ 659*fcf3ce44SJohn Forte return (ISCSI_STATUS_SHUTDOWN); 660*fcf3ce44SJohn Forte } 661*fcf3ce44SJohn Forte 662*fcf3ce44SJohn Forte /* 663*fcf3ce44SJohn Forte * If sessions are unbound set this information on 664*fcf3ce44SJohn Forte * the connection and return success. 665*fcf3ce44SJohn Forte */ 666*fcf3ce44SJohn Forte if (ics->ics_bound == B_FALSE) { 667*fcf3ce44SJohn Forte icp->conn_bound = B_FALSE; 668*fcf3ce44SJohn Forte kmem_free(ics, sizeof (iscsi_config_sess_t)); 669*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 670*fcf3ce44SJohn Forte } 671*fcf3ce44SJohn Forte 672*fcf3ce44SJohn Forte /* 673*fcf3ce44SJohn Forte * Since the sessions are bound we need to find the matching 674*fcf3ce44SJohn Forte * binding information for the session's isid. If this 675*fcf3ce44SJohn Forte * session's isid is > 0 then we need to get more configured 676*fcf3ce44SJohn Forte * session information to find the binding info. 677*fcf3ce44SJohn Forte */ 678*fcf3ce44SJohn Forte if (idx > 0) { 679*fcf3ce44SJohn Forte int ics_out; 680*fcf3ce44SJohn Forte 681*fcf3ce44SJohn Forte ics_out = ics->ics_out; 682*fcf3ce44SJohn Forte /* record new size and free last buffer */ 683*fcf3ce44SJohn Forte size = ISCSI_SESSION_CONFIG_SIZE(ics_out); 684*fcf3ce44SJohn Forte kmem_free(ics, sizeof (*ics)); 685*fcf3ce44SJohn Forte 686*fcf3ce44SJohn Forte /* allocate new buffer */ 687*fcf3ce44SJohn Forte ics = kmem_zalloc(size, KM_SLEEP); 688*fcf3ce44SJohn Forte ics->ics_in = ics_out; 689*fcf3ce44SJohn Forte 690*fcf3ce44SJohn Forte /* get configured sessions information */ 691*fcf3ce44SJohn Forte if (persistent_get_config_session(name, ics) != B_TRUE) { 692*fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi session(%d) - " 693*fcf3ce44SJohn Forte "unable to get configured session information\n", 694*fcf3ce44SJohn Forte isp->sess_oid); 695*fcf3ce44SJohn Forte kmem_free(ics, size); 696*fcf3ce44SJohn Forte return (ISCSI_STATUS_SHUTDOWN); 697*fcf3ce44SJohn Forte } 698*fcf3ce44SJohn Forte } 699*fcf3ce44SJohn Forte 700*fcf3ce44SJohn Forte /* Copy correct binding information to the connection */ 701*fcf3ce44SJohn Forte icp->conn_bound = B_TRUE; 702*fcf3ce44SJohn Forte if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) { 703*fcf3ce44SJohn Forte bcopy(&ics->ics_bindings[idx].i_addr.in4, 704*fcf3ce44SJohn Forte &icp->conn_bound_addr.sin4.sin_addr.s_addr, 705*fcf3ce44SJohn Forte sizeof (struct in_addr)); 706*fcf3ce44SJohn Forte } else { 707*fcf3ce44SJohn Forte bcopy(&ics->ics_bindings[idx].i_addr.in6, 708*fcf3ce44SJohn Forte &icp->conn_bound_addr.sin6.sin6_addr.s6_addr, 709*fcf3ce44SJohn Forte sizeof (struct in6_addr)); 710*fcf3ce44SJohn Forte } 711*fcf3ce44SJohn Forte 712*fcf3ce44SJohn Forte kmem_free(ics, size); 713*fcf3ce44SJohn Forte 714*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 715*fcf3ce44SJohn Forte } 716*fcf3ce44SJohn Forte 717*fcf3ce44SJohn Forte /* 718*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 719*fcf3ce44SJohn Forte * | Internal Connection Interfaces | 720*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 721*fcf3ce44SJohn Forte */ 722*fcf3ce44SJohn Forte 723*fcf3ce44SJohn Forte 724*fcf3ce44SJohn Forte /* 725*fcf3ce44SJohn Forte * iscsi_conn_state_free - 726*fcf3ce44SJohn Forte * 727*fcf3ce44SJohn Forte * S1: FREE - State on instantiation, or after successful 728*fcf3ce44SJohn Forte * connection closure. 729*fcf3ce44SJohn Forte */ 730*fcf3ce44SJohn Forte static iscsi_status_t 731*fcf3ce44SJohn Forte iscsi_conn_state_free(iscsi_conn_t *icp, iscsi_conn_event_t event) 732*fcf3ce44SJohn Forte { 733*fcf3ce44SJohn Forte iscsi_sess_t *isp; 734*fcf3ce44SJohn Forte iscsi_hba_t *ihp; 735*fcf3ce44SJohn Forte iscsi_task_t *itp; 736*fcf3ce44SJohn Forte iscsi_status_t status = ISCSI_STATUS_SUCCESS; 737*fcf3ce44SJohn Forte 738*fcf3ce44SJohn Forte ASSERT(icp != NULL); 739*fcf3ce44SJohn Forte isp = icp->conn_sess; 740*fcf3ce44SJohn Forte ASSERT(isp != NULL); 741*fcf3ce44SJohn Forte ihp = isp->sess_hba; 742*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 743*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE); 744*fcf3ce44SJohn Forte 745*fcf3ce44SJohn Forte /* switch on event change */ 746*fcf3ce44SJohn Forte switch (event) { 747*fcf3ce44SJohn Forte /* -T1: Transport connection request was request */ 748*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T1: 749*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_IN_LOGIN; 750*fcf3ce44SJohn Forte 751*fcf3ce44SJohn Forte /* 752*fcf3ce44SJohn Forte * Release the connection state mutex cross the 753*fcf3ce44SJohn Forte * the dispatch of the login task. The login task 754*fcf3ce44SJohn Forte * will reacquire the connection state mutex when 755*fcf3ce44SJohn Forte * it pushes the connection successful or failed. 756*fcf3ce44SJohn Forte */ 757*fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 758*fcf3ce44SJohn Forte 759*fcf3ce44SJohn Forte /* start login */ 760*fcf3ce44SJohn Forte itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 761*fcf3ce44SJohn Forte itp->t_arg = icp; 762*fcf3ce44SJohn Forte itp->t_blocking = B_TRUE; 763*fcf3ce44SJohn Forte 764*fcf3ce44SJohn Forte /* 765*fcf3ce44SJohn Forte * Sync base connection information before login 766*fcf3ce44SJohn Forte * A login redirection might have shifted the 767*fcf3ce44SJohn Forte * current information from the base. 768*fcf3ce44SJohn Forte */ 769*fcf3ce44SJohn Forte bcopy(&icp->conn_base_addr, &icp->conn_curr_addr, 770*fcf3ce44SJohn Forte sizeof (icp->conn_curr_addr)); 771*fcf3ce44SJohn Forte 772*fcf3ce44SJohn Forte status = iscsi_login_start(itp); 773*fcf3ce44SJohn Forte kmem_free(itp, sizeof (iscsi_task_t)); 774*fcf3ce44SJohn Forte 775*fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 776*fcf3ce44SJohn Forte break; 777*fcf3ce44SJohn Forte 778*fcf3ce44SJohn Forte /* All other events are invalid for this state */ 779*fcf3ce44SJohn Forte default: 780*fcf3ce44SJohn Forte ASSERT(FALSE); 781*fcf3ce44SJohn Forte status = ISCSI_STATUS_INTERNAL_ERROR; 782*fcf3ce44SJohn Forte } 783*fcf3ce44SJohn Forte return (status); 784*fcf3ce44SJohn Forte } 785*fcf3ce44SJohn Forte 786*fcf3ce44SJohn Forte /* 787*fcf3ce44SJohn Forte * iscsi_conn_state_in_login - During this state we are trying to 788*fcf3ce44SJohn Forte * connect the TCP connection and make a successful login to the 789*fcf3ce44SJohn Forte * target. To complete this we have a task queue item that is 790*fcf3ce44SJohn Forte * trying this processing at this point in time. When the task 791*fcf3ce44SJohn Forte * queue completed its processing it will issue either a T5/7 792*fcf3ce44SJohn Forte * event. 793*fcf3ce44SJohn Forte */ 794*fcf3ce44SJohn Forte static void 795*fcf3ce44SJohn Forte iscsi_conn_state_in_login(iscsi_conn_t *icp, iscsi_conn_event_t event) 796*fcf3ce44SJohn Forte { 797*fcf3ce44SJohn Forte iscsi_sess_t *isp; 798*fcf3ce44SJohn Forte 799*fcf3ce44SJohn Forte ASSERT(icp != NULL); 800*fcf3ce44SJohn Forte isp = icp->conn_sess; 801*fcf3ce44SJohn Forte ASSERT(isp != NULL); 802*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN); 803*fcf3ce44SJohn Forte 804*fcf3ce44SJohn Forte /* switch on event change */ 805*fcf3ce44SJohn Forte switch (event) { 806*fcf3ce44SJohn Forte /* 807*fcf3ce44SJohn Forte * -T5: The final iSCSI Login response with a Status-Class of zero 808*fcf3ce44SJohn Forte * was received. 809*fcf3ce44SJohn Forte */ 810*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T5: 811*fcf3ce44SJohn Forte iscsi_conn_logged_in(isp, icp); 812*fcf3ce44SJohn Forte break; 813*fcf3ce44SJohn Forte 814*fcf3ce44SJohn Forte /* 815*fcf3ce44SJohn Forte * -T30: One of the following event caused the transition: 816*fcf3ce44SJohn Forte * - Thefinal iSCSI Login response was received with a non-zero 817*fcf3ce44SJohn Forte * Status-Class. 818*fcf3ce44SJohn Forte */ 819*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T30: 820*fcf3ce44SJohn Forte /* FALLTHRU */ 821*fcf3ce44SJohn Forte 822*fcf3ce44SJohn Forte /* 823*fcf3ce44SJohn Forte * -T7: One of the following events caused the transition: 824*fcf3ce44SJohn Forte * - Login timed out. 825*fcf3ce44SJohn Forte * - A transport disconnect indication was received. 826*fcf3ce44SJohn Forte * - A transport reset was received. 827*fcf3ce44SJohn Forte * - An internal event indicating a transport timeout was 828*fcf3ce44SJohn Forte * received. 829*fcf3ce44SJohn Forte * - An internal event of receiving a Logout repsonse (success) 830*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout 831*fcf3ce44SJohn Forte * request was received. 832*fcf3ce44SJohn Forte * * In all these cases, the transport connection is closed. 833*fcf3ce44SJohn Forte */ 834*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T7: 835*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 836*fcf3ce44SJohn Forte break; 837*fcf3ce44SJohn Forte 838*fcf3ce44SJohn Forte /* All other events are invalid for this state */ 839*fcf3ce44SJohn Forte default: 840*fcf3ce44SJohn Forte ASSERT(FALSE); 841*fcf3ce44SJohn Forte } 842*fcf3ce44SJohn Forte } 843*fcf3ce44SJohn Forte 844*fcf3ce44SJohn Forte 845*fcf3ce44SJohn Forte /* 846*fcf3ce44SJohn Forte * iscsi_conn_state_logged_in - 847*fcf3ce44SJohn Forte * 848*fcf3ce44SJohn Forte */ 849*fcf3ce44SJohn Forte static void 850*fcf3ce44SJohn Forte iscsi_conn_state_logged_in(iscsi_conn_t *icp, iscsi_conn_event_t event) 851*fcf3ce44SJohn Forte { 852*fcf3ce44SJohn Forte iscsi_sess_t *isp; 853*fcf3ce44SJohn Forte iscsi_hba_t *ihp; 854*fcf3ce44SJohn Forte 855*fcf3ce44SJohn Forte ASSERT(icp != NULL); 856*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN); 857*fcf3ce44SJohn Forte isp = icp->conn_sess; 858*fcf3ce44SJohn Forte ASSERT(isp != NULL); 859*fcf3ce44SJohn Forte ihp = isp->sess_hba; 860*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 861*fcf3ce44SJohn Forte 862*fcf3ce44SJohn Forte /* switch on event change */ 863*fcf3ce44SJohn Forte switch (event) { 864*fcf3ce44SJohn Forte /* 865*fcf3ce44SJohn Forte * -T8: An internal event of receiving a Logout response (success) 866*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout request 867*fcf3ce44SJohn Forte * was received, thus closing this connection requiring no further 868*fcf3ce44SJohn Forte * cleanup. 869*fcf3ce44SJohn Forte */ 870*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T8: 871*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 872*fcf3ce44SJohn Forte 873*fcf3ce44SJohn Forte /* stop tx thread */ 874*fcf3ce44SJohn Forte (void) iscsi_thread_stop(icp->conn_tx_thread); 875*fcf3ce44SJohn Forte 876*fcf3ce44SJohn Forte /* Disconnect connection */ 877*fcf3ce44SJohn Forte iscsi_net->close(icp->conn_socket); 878*fcf3ce44SJohn Forte 879*fcf3ce44SJohn Forte /* Notify session that a connection logged out */ 880*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 881*fcf3ce44SJohn Forte iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3); 882*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 883*fcf3ce44SJohn Forte break; 884*fcf3ce44SJohn Forte 885*fcf3ce44SJohn Forte /* 886*fcf3ce44SJohn Forte * -T9: An internal event that indicates the readiness to start the 887*fcf3ce44SJohn Forte * Logout process was received, thus prompting an iSCSI Logout 888*fcf3ce44SJohn Forte * to be sent by the initiator. 889*fcf3ce44SJohn Forte */ 890*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T9: 891*fcf3ce44SJohn Forte /* FALLTHRU */ 892*fcf3ce44SJohn Forte 893*fcf3ce44SJohn Forte /* 894*fcf3ce44SJohn Forte * -T11: Aync PDU with AsyncEvent "Request Logout" was recevied 895*fcf3ce44SJohn Forte */ 896*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T11: 897*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT; 898*fcf3ce44SJohn Forte 899*fcf3ce44SJohn Forte (void) iscsi_handle_logout(icp); 900*fcf3ce44SJohn Forte break; 901*fcf3ce44SJohn Forte 902*fcf3ce44SJohn Forte /* 903*fcf3ce44SJohn Forte * -T14: One or more of the following events case this transition: 904*fcf3ce44SJohn Forte * - Header Digest Error 905*fcf3ce44SJohn Forte * - Protocol Error 906*fcf3ce44SJohn Forte */ 907*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T14: 908*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FAILED; 909*fcf3ce44SJohn Forte 910*fcf3ce44SJohn Forte /* stop tx thread */ 911*fcf3ce44SJohn Forte (void) iscsi_thread_stop(icp->conn_tx_thread); 912*fcf3ce44SJohn Forte 913*fcf3ce44SJohn Forte /* 914*fcf3ce44SJohn Forte * Error Recovery Level 0 states we should drop 915*fcf3ce44SJohn Forte * the connection here. Then we will fall through 916*fcf3ce44SJohn Forte * and treat this event like a T15. 917*fcf3ce44SJohn Forte */ 918*fcf3ce44SJohn Forte iscsi_net->close(icp->conn_socket); 919*fcf3ce44SJohn Forte 920*fcf3ce44SJohn Forte /* FALLTHRU */ 921*fcf3ce44SJohn Forte 922*fcf3ce44SJohn Forte /* 923*fcf3ce44SJohn Forte * -T15: One or more of the following events caused this transition 924*fcf3ce44SJohn Forte * - Internal event that indicates a transport connection timeout 925*fcf3ce44SJohn Forte * was received thus prompting transport RESET or transport 926*fcf3ce44SJohn Forte * connection closure. 927*fcf3ce44SJohn Forte * - A transport RESET 928*fcf3ce44SJohn Forte * - A transport disconnect indication. 929*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop connection" (for this CID) 930*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop all connections" 931*fcf3ce44SJohn Forte */ 932*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T15: 933*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FAILED; 934*fcf3ce44SJohn Forte 935*fcf3ce44SJohn Forte /* stop tx thread, no-op if already done for T14 */ 936*fcf3ce44SJohn Forte (void) iscsi_thread_stop(icp->conn_tx_thread); 937*fcf3ce44SJohn Forte 938*fcf3ce44SJohn Forte iscsi_conn_flush_active_cmds(icp); 939*fcf3ce44SJohn Forte 940*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 941*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N5); 942*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 943*fcf3ce44SJohn Forte 944*fcf3ce44SJohn Forte /* 945*fcf3ce44SJohn Forte * If session type is NORMAL, create a new login task 946*fcf3ce44SJohn Forte * to get this connection reestablished. 947*fcf3ce44SJohn Forte */ 948*fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 949*fcf3ce44SJohn Forte iscsi_conn_retry(isp, icp); 950*fcf3ce44SJohn Forte } else { 951*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 952*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 953*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); 954*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 955*fcf3ce44SJohn Forte } 956*fcf3ce44SJohn Forte break; 957*fcf3ce44SJohn Forte 958*fcf3ce44SJohn Forte /* All other events are invalid for this state */ 959*fcf3ce44SJohn Forte default: 960*fcf3ce44SJohn Forte ASSERT(FALSE); 961*fcf3ce44SJohn Forte } 962*fcf3ce44SJohn Forte } 963*fcf3ce44SJohn Forte 964*fcf3ce44SJohn Forte 965*fcf3ce44SJohn Forte /* 966*fcf3ce44SJohn Forte * iscsi_conn_state_in_logout - 967*fcf3ce44SJohn Forte * 968*fcf3ce44SJohn Forte */ 969*fcf3ce44SJohn Forte static void 970*fcf3ce44SJohn Forte iscsi_conn_state_in_logout(iscsi_conn_t *icp, iscsi_conn_event_t event) 971*fcf3ce44SJohn Forte { 972*fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 973*fcf3ce44SJohn Forte 974*fcf3ce44SJohn Forte ASSERT(icp != NULL); 975*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGOUT); 976*fcf3ce44SJohn Forte isp = icp->conn_sess; 977*fcf3ce44SJohn Forte ASSERT(isp != NULL); 978*fcf3ce44SJohn Forte 979*fcf3ce44SJohn Forte /* switch on event change */ 980*fcf3ce44SJohn Forte switch (event) { 981*fcf3ce44SJohn Forte /* 982*fcf3ce44SJohn Forte * -T11: Async PDU with AsyncEvent "Request Logout" was received again 983*fcf3ce44SJohn Forte */ 984*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T11: 985*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT; 986*fcf3ce44SJohn Forte 987*fcf3ce44SJohn Forte /* Already in LOGOUT ignore the request */ 988*fcf3ce44SJohn Forte break; 989*fcf3ce44SJohn Forte 990*fcf3ce44SJohn Forte /* 991*fcf3ce44SJohn Forte * -T17: One or more of the following events caused this transition: 992*fcf3ce44SJohn Forte * - Logout response, (failure i.e., a non-zero status) was 993*fcf3ce44SJohn Forte * received, or logout timed out. 994*fcf3ce44SJohn Forte * - Any of the events specified for T15 995*fcf3ce44SJohn Forte * 996*fcf3ce44SJohn Forte * -T14: One or more of the following events case this transition: 997*fcf3ce44SJohn Forte * - Header Digest Error 998*fcf3ce44SJohn Forte * - Protocol Error 999*fcf3ce44SJohn Forte * 1000*fcf3ce44SJohn Forte * -T15: One or more of the following events caused this transition 1001*fcf3ce44SJohn Forte * - Internal event that indicates a transport connection timeout 1002*fcf3ce44SJohn Forte * was received thus prompting transport RESET or transport 1003*fcf3ce44SJohn Forte * connection closure. 1004*fcf3ce44SJohn Forte * - A transport RESET 1005*fcf3ce44SJohn Forte * - A transport disconnect indication. 1006*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop connection" (for this CID) 1007*fcf3ce44SJohn Forte * - Async PDU with AsyncEvent "Drop all connections" 1008*fcf3ce44SJohn Forte */ 1009*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T17: 1010*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T14: 1011*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T15: 1012*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 1013*fcf3ce44SJohn Forte 1014*fcf3ce44SJohn Forte /* stop tx thread */ 1015*fcf3ce44SJohn Forte (void) iscsi_thread_stop(icp->conn_tx_thread); 1016*fcf3ce44SJohn Forte 1017*fcf3ce44SJohn Forte /* Disconnect Connection */ 1018*fcf3ce44SJohn Forte iscsi_net->close(icp->conn_socket); 1019*fcf3ce44SJohn Forte 1020*fcf3ce44SJohn Forte iscsi_conn_flush_active_cmds(icp); 1021*fcf3ce44SJohn Forte 1022*fcf3ce44SJohn Forte /* Notify session of a failed logout */ 1023*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1024*fcf3ce44SJohn Forte iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3); 1025*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1026*fcf3ce44SJohn Forte break; 1027*fcf3ce44SJohn Forte 1028*fcf3ce44SJohn Forte /* All other events are invalid for this state */ 1029*fcf3ce44SJohn Forte default: 1030*fcf3ce44SJohn Forte ASSERT(FALSE); 1031*fcf3ce44SJohn Forte } 1032*fcf3ce44SJohn Forte } 1033*fcf3ce44SJohn Forte 1034*fcf3ce44SJohn Forte 1035*fcf3ce44SJohn Forte /* 1036*fcf3ce44SJohn Forte * iscsi_conn_state_failed - 1037*fcf3ce44SJohn Forte * 1038*fcf3ce44SJohn Forte */ 1039*fcf3ce44SJohn Forte static void 1040*fcf3ce44SJohn Forte iscsi_conn_state_failed(iscsi_conn_t *icp, iscsi_conn_event_t event) 1041*fcf3ce44SJohn Forte { 1042*fcf3ce44SJohn Forte iscsi_sess_t *isp; 1043*fcf3ce44SJohn Forte 1044*fcf3ce44SJohn Forte ASSERT(icp != NULL); 1045*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_FAILED); 1046*fcf3ce44SJohn Forte isp = icp->conn_sess; 1047*fcf3ce44SJohn Forte ASSERT(isp != NULL); 1048*fcf3ce44SJohn Forte 1049*fcf3ce44SJohn Forte /* switch on event change */ 1050*fcf3ce44SJohn Forte switch (event) { 1051*fcf3ce44SJohn Forte 1052*fcf3ce44SJohn Forte /* 1053*fcf3ce44SJohn Forte * -T5: The final iSCSI Login response with a Status-Class of zero 1054*fcf3ce44SJohn Forte * was received. 1055*fcf3ce44SJohn Forte */ 1056*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T5: 1057*fcf3ce44SJohn Forte iscsi_conn_logged_in(isp, icp); 1058*fcf3ce44SJohn Forte break; 1059*fcf3ce44SJohn Forte 1060*fcf3ce44SJohn Forte /* 1061*fcf3ce44SJohn Forte * -T30: One of the following event caused the transition: 1062*fcf3ce44SJohn Forte * - Thefinal iSCSI Login response was received with a non-zero 1063*fcf3ce44SJohn Forte * Status-Class. 1064*fcf3ce44SJohn Forte */ 1065*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T30: 1066*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 1067*fcf3ce44SJohn Forte 1068*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1069*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); 1070*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1071*fcf3ce44SJohn Forte 1072*fcf3ce44SJohn Forte break; 1073*fcf3ce44SJohn Forte 1074*fcf3ce44SJohn Forte /* 1075*fcf3ce44SJohn Forte * -T7: One of the following events caused the transition: 1076*fcf3ce44SJohn Forte * - Login timed out. 1077*fcf3ce44SJohn Forte * - A transport disconnect indication was received. 1078*fcf3ce44SJohn Forte * - A transport reset was received. 1079*fcf3ce44SJohn Forte * - An internal event indicating a transport timeout was 1080*fcf3ce44SJohn Forte * received. 1081*fcf3ce44SJohn Forte * - An internal event of receiving a Logout repsonse (success) 1082*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout 1083*fcf3ce44SJohn Forte * request was received. 1084*fcf3ce44SJohn Forte * * In all these cases, the transport connection is closed. 1085*fcf3ce44SJohn Forte */ 1086*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T7: 1087*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_POLLING; 1088*fcf3ce44SJohn Forte 1089*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1090*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); 1091*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1092*fcf3ce44SJohn Forte 1093*fcf3ce44SJohn Forte iscsi_conn_retry(isp, icp); 1094*fcf3ce44SJohn Forte break; 1095*fcf3ce44SJohn Forte 1096*fcf3ce44SJohn Forte /* There are no valid transition out of this state. */ 1097*fcf3ce44SJohn Forte default: 1098*fcf3ce44SJohn Forte ASSERT(FALSE); 1099*fcf3ce44SJohn Forte } 1100*fcf3ce44SJohn Forte } 1101*fcf3ce44SJohn Forte 1102*fcf3ce44SJohn Forte /* 1103*fcf3ce44SJohn Forte * iscsi_conn_state_polling - 1104*fcf3ce44SJohn Forte * 1105*fcf3ce44SJohn Forte * S6: POLLING - State on instantiation, or after successful 1106*fcf3ce44SJohn Forte * connection closure. 1107*fcf3ce44SJohn Forte */ 1108*fcf3ce44SJohn Forte static void 1109*fcf3ce44SJohn Forte iscsi_conn_state_polling(iscsi_conn_t *icp, iscsi_conn_event_t event) 1110*fcf3ce44SJohn Forte { 1111*fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1112*fcf3ce44SJohn Forte 1113*fcf3ce44SJohn Forte ASSERT(icp != NULL); 1114*fcf3ce44SJohn Forte ASSERT(icp->conn_state == ISCSI_CONN_STATE_POLLING); 1115*fcf3ce44SJohn Forte isp = icp->conn_sess; 1116*fcf3ce44SJohn Forte ASSERT(isp != NULL); 1117*fcf3ce44SJohn Forte 1118*fcf3ce44SJohn Forte /* switch on event change */ 1119*fcf3ce44SJohn Forte switch (event) { 1120*fcf3ce44SJohn Forte /* 1121*fcf3ce44SJohn Forte * -T5: The final iSCSI Login response with a Status-Class of zero 1122*fcf3ce44SJohn Forte * was received. 1123*fcf3ce44SJohn Forte */ 1124*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T5: 1125*fcf3ce44SJohn Forte iscsi_conn_logged_in(isp, icp); 1126*fcf3ce44SJohn Forte break; 1127*fcf3ce44SJohn Forte 1128*fcf3ce44SJohn Forte /* 1129*fcf3ce44SJohn Forte * -T30: One of the following event caused the transition: 1130*fcf3ce44SJohn Forte * - Thefinal iSCSI Login response was received with a non-zero 1131*fcf3ce44SJohn Forte * Status-Class. 1132*fcf3ce44SJohn Forte */ 1133*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T30: 1134*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 1135*fcf3ce44SJohn Forte 1136*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1137*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); 1138*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1139*fcf3ce44SJohn Forte 1140*fcf3ce44SJohn Forte break; 1141*fcf3ce44SJohn Forte 1142*fcf3ce44SJohn Forte /* 1143*fcf3ce44SJohn Forte * -T7: One of the following events caused the transition: 1144*fcf3ce44SJohn Forte * - Login timed out. 1145*fcf3ce44SJohn Forte * - A transport disconnect indication was received. 1146*fcf3ce44SJohn Forte * - A transport reset was received. 1147*fcf3ce44SJohn Forte * - An internal event indicating a transport timeout was 1148*fcf3ce44SJohn Forte * received. 1149*fcf3ce44SJohn Forte * - An internal event of receiving a Logout repsonse (success) 1150*fcf3ce44SJohn Forte * on another connection for a "close the session" Logout 1151*fcf3ce44SJohn Forte * request was received. 1152*fcf3ce44SJohn Forte * * In all these cases, the transport connection is closed. 1153*fcf3ce44SJohn Forte */ 1154*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T7: 1155*fcf3ce44SJohn Forte /* 1156*fcf3ce44SJohn Forte * If session type is NORMAL, create a new login task 1157*fcf3ce44SJohn Forte * to get this connection reestablished. 1158*fcf3ce44SJohn Forte */ 1159*fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1160*fcf3ce44SJohn Forte iscsi_conn_retry(isp, icp); 1161*fcf3ce44SJohn Forte } else { 1162*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 1163*fcf3ce44SJohn Forte } 1164*fcf3ce44SJohn Forte break; 1165*fcf3ce44SJohn Forte 1166*fcf3ce44SJohn Forte /* All other events are invalid for this state */ 1167*fcf3ce44SJohn Forte default: 1168*fcf3ce44SJohn Forte ASSERT(FALSE); 1169*fcf3ce44SJohn Forte } 1170*fcf3ce44SJohn Forte } 1171*fcf3ce44SJohn Forte 1172*fcf3ce44SJohn Forte /* 1173*fcf3ce44SJohn Forte * iscsi_conn_event_str - converts event enum to a string 1174*fcf3ce44SJohn Forte */ 1175*fcf3ce44SJohn Forte static char * 1176*fcf3ce44SJohn Forte iscsi_conn_event_str(iscsi_conn_event_t event) 1177*fcf3ce44SJohn Forte { 1178*fcf3ce44SJohn Forte switch (event) { 1179*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T1: 1180*fcf3ce44SJohn Forte return ("T1"); 1181*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T5: 1182*fcf3ce44SJohn Forte return ("T5"); 1183*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T7: 1184*fcf3ce44SJohn Forte return ("T7"); 1185*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T8: 1186*fcf3ce44SJohn Forte return ("T8"); 1187*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T9: 1188*fcf3ce44SJohn Forte return ("T9"); 1189*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T11: 1190*fcf3ce44SJohn Forte return ("T11"); 1191*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T14: 1192*fcf3ce44SJohn Forte return ("T14"); 1193*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T15: 1194*fcf3ce44SJohn Forte return ("T15"); 1195*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T17: 1196*fcf3ce44SJohn Forte return ("T17"); 1197*fcf3ce44SJohn Forte case ISCSI_CONN_EVENT_T30: 1198*fcf3ce44SJohn Forte return ("T30"); 1199*fcf3ce44SJohn Forte 1200*fcf3ce44SJohn Forte default: 1201*fcf3ce44SJohn Forte return ("unknown"); 1202*fcf3ce44SJohn Forte } 1203*fcf3ce44SJohn Forte } 1204*fcf3ce44SJohn Forte 1205*fcf3ce44SJohn Forte /* 1206*fcf3ce44SJohn Forte * iscsi_conn_flush_active_cmds - flush all active icmdps 1207*fcf3ce44SJohn Forte * for a connection. 1208*fcf3ce44SJohn Forte */ 1209*fcf3ce44SJohn Forte static void 1210*fcf3ce44SJohn Forte iscsi_conn_flush_active_cmds(iscsi_conn_t *icp) 1211*fcf3ce44SJohn Forte { 1212*fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 1213*fcf3ce44SJohn Forte iscsi_sess_t *isp; 1214*fcf3ce44SJohn Forte boolean_t lock_held = B_FALSE; 1215*fcf3ce44SJohn Forte 1216*fcf3ce44SJohn Forte ASSERT(icp != NULL); 1217*fcf3ce44SJohn Forte isp = icp->conn_sess; 1218*fcf3ce44SJohn Forte ASSERT(isp != NULL); 1219*fcf3ce44SJohn Forte 1220*fcf3ce44SJohn Forte if (mutex_owned(&icp->conn_queue_active.mutex)) { 1221*fcf3ce44SJohn Forte lock_held = B_TRUE; 1222*fcf3ce44SJohn Forte } else { 1223*fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1224*fcf3ce44SJohn Forte } 1225*fcf3ce44SJohn Forte 1226*fcf3ce44SJohn Forte /* Flush active queue */ 1227*fcf3ce44SJohn Forte icmdp = icp->conn_queue_active.head; 1228*fcf3ce44SJohn Forte while (icmdp != NULL) { 1229*fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, 1230*fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E7, isp); 1231*fcf3ce44SJohn Forte icmdp = icp->conn_queue_active.head; 1232*fcf3ce44SJohn Forte } 1233*fcf3ce44SJohn Forte 1234*fcf3ce44SJohn Forte if (lock_held == B_FALSE) { 1235*fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1236*fcf3ce44SJohn Forte } 1237*fcf3ce44SJohn Forte } 1238*fcf3ce44SJohn Forte 1239*fcf3ce44SJohn Forte 1240*fcf3ce44SJohn Forte /* 1241*fcf3ce44SJohn Forte * iscsi_conn_logged_in - connection has successfully logged in 1242*fcf3ce44SJohn Forte */ 1243*fcf3ce44SJohn Forte static void 1244*fcf3ce44SJohn Forte iscsi_conn_logged_in(iscsi_sess_t *isp, iscsi_conn_t *icp) 1245*fcf3ce44SJohn Forte { 1246*fcf3ce44SJohn Forte ASSERT(isp != NULL); 1247*fcf3ce44SJohn Forte ASSERT(icp != NULL); 1248*fcf3ce44SJohn Forte 1249*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_LOGGED_IN; 1250*fcf3ce44SJohn Forte /* 1251*fcf3ce44SJohn Forte * We need to drop the connection state lock 1252*fcf3ce44SJohn Forte * before updating the session state. On update 1253*fcf3ce44SJohn Forte * of the session state it will enumerate the 1254*fcf3ce44SJohn Forte * target. If we hold the lock during enumeration 1255*fcf3ce44SJohn Forte * will block the watchdog thread from timing 1256*fcf3ce44SJohn Forte * a scsi_pkt, if required. This will lead to 1257*fcf3ce44SJohn Forte * a possible hang condition. 1258*fcf3ce44SJohn Forte * 1259*fcf3ce44SJohn Forte * Also the lock is no longer needed once the 1260*fcf3ce44SJohn Forte * connection state was updated. 1261*fcf3ce44SJohn Forte */ 1262*fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1263*fcf3ce44SJohn Forte 1264*fcf3ce44SJohn Forte /* startup threads */ 1265*fcf3ce44SJohn Forte (void) iscsi_thread_start(icp->conn_rx_thread); 1266*fcf3ce44SJohn Forte (void) iscsi_thread_start(icp->conn_tx_thread); 1267*fcf3ce44SJohn Forte 1268*fcf3ce44SJohn Forte /* Notify the session that a connection is logged in */ 1269*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1270*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1); 1271*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1272*fcf3ce44SJohn Forte 1273*fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1274*fcf3ce44SJohn Forte } 1275*fcf3ce44SJohn Forte 1276*fcf3ce44SJohn Forte /* 1277*fcf3ce44SJohn Forte * iscsi_conn_retry - retry connect/login 1278*fcf3ce44SJohn Forte */ 1279*fcf3ce44SJohn Forte static void 1280*fcf3ce44SJohn Forte iscsi_conn_retry(iscsi_sess_t *isp, iscsi_conn_t *icp) 1281*fcf3ce44SJohn Forte { 1282*fcf3ce44SJohn Forte iscsi_task_t *itp; 1283*fcf3ce44SJohn Forte 1284*fcf3ce44SJohn Forte ASSERT(isp != NULL); 1285*fcf3ce44SJohn Forte ASSERT(icp != NULL); 1286*fcf3ce44SJohn Forte 1287*fcf3ce44SJohn Forte /* set login min/max time values */ 1288*fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(icp, 1289*fcf3ce44SJohn Forte ISCSI_CONN_DEFAULT_LOGIN_MIN, 1290*fcf3ce44SJohn Forte ISCSI_CONN_DEFAULT_LOGIN_MAX); 1291*fcf3ce44SJohn Forte 1292*fcf3ce44SJohn Forte /* 1293*fcf3ce44SJohn Forte * Sync base connection information before login. 1294*fcf3ce44SJohn Forte * A login redirection might have shifted the 1295*fcf3ce44SJohn Forte * current information from the base. 1296*fcf3ce44SJohn Forte */ 1297*fcf3ce44SJohn Forte bcopy(&icp->conn_base_addr, &icp->conn_curr_addr, 1298*fcf3ce44SJohn Forte sizeof (icp->conn_curr_addr)); 1299*fcf3ce44SJohn Forte 1300*fcf3ce44SJohn Forte /* schedule login task */ 1301*fcf3ce44SJohn Forte itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 1302*fcf3ce44SJohn Forte itp->t_arg = icp; 1303*fcf3ce44SJohn Forte itp->t_blocking = B_FALSE; 1304*fcf3ce44SJohn Forte if (ddi_taskq_dispatch(isp->sess_taskq, 1305*fcf3ce44SJohn Forte (void(*)())iscsi_login_start, itp, DDI_SLEEP) != 1306*fcf3ce44SJohn Forte DDI_SUCCESS) { 1307*fcf3ce44SJohn Forte kmem_free(itp, sizeof (iscsi_task_t)); 1308*fcf3ce44SJohn Forte cmn_err(CE_WARN, 1309*fcf3ce44SJohn Forte "iscsi connection(%u) failure - " 1310*fcf3ce44SJohn Forte "unable to schedule login task", 1311*fcf3ce44SJohn Forte icp->conn_oid); 1312*fcf3ce44SJohn Forte 1313*fcf3ce44SJohn Forte icp->conn_state = ISCSI_CONN_STATE_FREE; 1314*fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 1315*fcf3ce44SJohn Forte iscsi_sess_state_machine(isp, 1316*fcf3ce44SJohn Forte ISCSI_SESS_EVENT_N6); 1317*fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 1318*fcf3ce44SJohn Forte } 1319*fcf3ce44SJohn Forte } 1320