162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * This file contains the login functions used by the iSCSI Target driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci ******************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/hash.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/kthread.h> 1562306a36Sopenharmony_ci#include <linux/sched/signal.h> 1662306a36Sopenharmony_ci#include <linux/idr.h> 1762306a36Sopenharmony_ci#include <linux/tcp.h> /* TCP_NODELAY */ 1862306a36Sopenharmony_ci#include <net/ip.h> 1962306a36Sopenharmony_ci#include <net/ipv6.h> /* ipv6_addr_v4mapped() */ 2062306a36Sopenharmony_ci#include <scsi/iscsi_proto.h> 2162306a36Sopenharmony_ci#include <target/target_core_base.h> 2262306a36Sopenharmony_ci#include <target/target_core_fabric.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h> 2562306a36Sopenharmony_ci#include <target/iscsi/iscsi_target_stat.h> 2662306a36Sopenharmony_ci#include "iscsi_target_device.h" 2762306a36Sopenharmony_ci#include "iscsi_target_nego.h" 2862306a36Sopenharmony_ci#include "iscsi_target_erl0.h" 2962306a36Sopenharmony_ci#include "iscsi_target_erl2.h" 3062306a36Sopenharmony_ci#include "iscsi_target_login.h" 3162306a36Sopenharmony_ci#include "iscsi_target_tpg.h" 3262306a36Sopenharmony_ci#include "iscsi_target_util.h" 3362306a36Sopenharmony_ci#include "iscsi_target.h" 3462306a36Sopenharmony_ci#include "iscsi_target_parameters.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <target/iscsi/iscsi_transport.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct iscsi_login *iscsi_login_init_conn(struct iscsit_conn *conn) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct iscsi_login *login; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL); 4362306a36Sopenharmony_ci if (!login) { 4462306a36Sopenharmony_ci pr_err("Unable to allocate memory for struct iscsi_login.\n"); 4562306a36Sopenharmony_ci return NULL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci conn->login = login; 4862306a36Sopenharmony_ci login->conn = conn; 4962306a36Sopenharmony_ci login->first_request = 1; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); 5262306a36Sopenharmony_ci if (!login->req_buf) { 5362306a36Sopenharmony_ci pr_err("Unable to allocate memory for response buffer.\n"); 5462306a36Sopenharmony_ci goto out_login; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); 5862306a36Sopenharmony_ci if (!login->rsp_buf) { 5962306a36Sopenharmony_ci pr_err("Unable to allocate memory for request buffer.\n"); 6062306a36Sopenharmony_ci goto out_req_buf; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci conn->conn_login = login; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return login; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciout_req_buf: 6862306a36Sopenharmony_ci kfree(login->req_buf); 6962306a36Sopenharmony_ciout_login: 7062306a36Sopenharmony_ci kfree(login); 7162306a36Sopenharmony_ci return NULL; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Used by iscsi_target_nego.c:iscsi_target_locate_portal() to setup 7662306a36Sopenharmony_ci * per struct iscsit_conn libcrypto contexts for crc32c and crc32-intel 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ciint iscsi_login_setup_crypto(struct iscsit_conn *conn) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct crypto_ahash *tfm; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts 8462306a36Sopenharmony_ci * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback 8562306a36Sopenharmony_ci * to software 1x8 byte slicing from crc32c.ko 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); 8862306a36Sopenharmony_ci if (IS_ERR(tfm)) { 8962306a36Sopenharmony_ci pr_err("crypto_alloc_ahash() failed\n"); 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci conn->conn_rx_hash = ahash_request_alloc(tfm, GFP_KERNEL); 9462306a36Sopenharmony_ci if (!conn->conn_rx_hash) { 9562306a36Sopenharmony_ci pr_err("ahash_request_alloc() failed for conn_rx_hash\n"); 9662306a36Sopenharmony_ci crypto_free_ahash(tfm); 9762306a36Sopenharmony_ci return -ENOMEM; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci ahash_request_set_callback(conn->conn_rx_hash, 0, NULL, NULL); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci conn->conn_tx_hash = ahash_request_alloc(tfm, GFP_KERNEL); 10262306a36Sopenharmony_ci if (!conn->conn_tx_hash) { 10362306a36Sopenharmony_ci pr_err("ahash_request_alloc() failed for conn_tx_hash\n"); 10462306a36Sopenharmony_ci ahash_request_free(conn->conn_rx_hash); 10562306a36Sopenharmony_ci conn->conn_rx_hash = NULL; 10662306a36Sopenharmony_ci crypto_free_ahash(tfm); 10762306a36Sopenharmony_ci return -ENOMEM; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci ahash_request_set_callback(conn->conn_tx_hash, 0, NULL, NULL); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int iscsi_login_check_initiator_version( 11562306a36Sopenharmony_ci struct iscsit_conn *conn, 11662306a36Sopenharmony_ci u8 version_max, 11762306a36Sopenharmony_ci u8 version_min) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci if ((version_max != 0x00) || (version_min != 0x00)) { 12062306a36Sopenharmony_ci pr_err("Unsupported iSCSI IETF Pre-RFC Revision," 12162306a36Sopenharmony_ci " version Min/Max 0x%02x/0x%02x, rejecting login.\n", 12262306a36Sopenharmony_ci version_min, version_max); 12362306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 12462306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_VERSION); 12562306a36Sopenharmony_ci return -1; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciint iscsi_check_for_session_reinstatement(struct iscsit_conn *conn) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci int sessiontype; 13462306a36Sopenharmony_ci struct iscsi_param *initiatorname_param = NULL, *sessiontype_param = NULL; 13562306a36Sopenharmony_ci struct iscsi_portal_group *tpg = conn->tpg; 13662306a36Sopenharmony_ci struct iscsit_session *sess = NULL, *sess_p = NULL; 13762306a36Sopenharmony_ci struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; 13862306a36Sopenharmony_ci struct se_session *se_sess, *se_sess_tmp; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci initiatorname_param = iscsi_find_param_from_key( 14162306a36Sopenharmony_ci INITIATORNAME, conn->param_list); 14262306a36Sopenharmony_ci sessiontype_param = iscsi_find_param_from_key( 14362306a36Sopenharmony_ci SESSIONTYPE, conn->param_list); 14462306a36Sopenharmony_ci if (!initiatorname_param || !sessiontype_param) { 14562306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 14662306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 14762306a36Sopenharmony_ci return -1; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci spin_lock_bh(&se_tpg->session_lock); 15362306a36Sopenharmony_ci list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, 15462306a36Sopenharmony_ci sess_list) { 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci sess_p = se_sess->fabric_sess_ptr; 15762306a36Sopenharmony_ci spin_lock(&sess_p->conn_lock); 15862306a36Sopenharmony_ci if (atomic_read(&sess_p->session_fall_back_to_erl0) || 15962306a36Sopenharmony_ci atomic_read(&sess_p->session_logout) || 16062306a36Sopenharmony_ci atomic_read(&sess_p->session_close) || 16162306a36Sopenharmony_ci (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { 16262306a36Sopenharmony_ci spin_unlock(&sess_p->conn_lock); 16362306a36Sopenharmony_ci continue; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (!memcmp(sess_p->isid, conn->sess->isid, 6) && 16662306a36Sopenharmony_ci (!strcmp(sess_p->sess_ops->InitiatorName, 16762306a36Sopenharmony_ci initiatorname_param->value) && 16862306a36Sopenharmony_ci (sess_p->sess_ops->SessionType == sessiontype))) { 16962306a36Sopenharmony_ci atomic_set(&sess_p->session_reinstatement, 1); 17062306a36Sopenharmony_ci atomic_set(&sess_p->session_fall_back_to_erl0, 1); 17162306a36Sopenharmony_ci atomic_set(&sess_p->session_close, 1); 17262306a36Sopenharmony_ci spin_unlock(&sess_p->conn_lock); 17362306a36Sopenharmony_ci iscsit_inc_session_usage_count(sess_p); 17462306a36Sopenharmony_ci iscsit_stop_time2retain_timer(sess_p); 17562306a36Sopenharmony_ci sess = sess_p; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci spin_unlock(&sess_p->conn_lock); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci spin_unlock_bh(&se_tpg->session_lock); 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * If the Time2Retain handler has expired, the session is already gone. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci if (!sess) 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci pr_debug("%s iSCSI Session SID %u is still active for %s," 18862306a36Sopenharmony_ci " performing session reinstatement.\n", (sessiontype) ? 18962306a36Sopenharmony_ci "Discovery" : "Normal", sess->sid, 19062306a36Sopenharmony_ci sess->sess_ops->InitiatorName); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci spin_lock_bh(&sess->conn_lock); 19362306a36Sopenharmony_ci if (sess->session_state == TARG_SESS_STATE_FAILED) { 19462306a36Sopenharmony_ci spin_unlock_bh(&sess->conn_lock); 19562306a36Sopenharmony_ci iscsit_dec_session_usage_count(sess); 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci spin_unlock_bh(&sess->conn_lock); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci iscsit_stop_session(sess, 1, 1); 20162306a36Sopenharmony_ci iscsit_dec_session_usage_count(sess); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int iscsi_login_set_conn_values( 20762306a36Sopenharmony_ci struct iscsit_session *sess, 20862306a36Sopenharmony_ci struct iscsit_conn *conn, 20962306a36Sopenharmony_ci __be16 cid) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int ret; 21262306a36Sopenharmony_ci conn->sess = sess; 21362306a36Sopenharmony_ci conn->cid = be16_to_cpu(cid); 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Generate a random Status sequence number (statsn) for the new 21662306a36Sopenharmony_ci * iSCSI connection. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci ret = get_random_bytes_wait(&conn->stat_sn, sizeof(u32)); 21962306a36Sopenharmony_ci if (unlikely(ret)) 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mutex_lock(&auth_id_lock); 22362306a36Sopenharmony_ci conn->auth_id = iscsit_global->auth_id++; 22462306a36Sopenharmony_ci mutex_unlock(&auth_id_lock); 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci__printf(2, 3) int iscsi_change_param_sprintf( 22962306a36Sopenharmony_ci struct iscsit_conn *conn, 23062306a36Sopenharmony_ci const char *fmt, ...) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci va_list args; 23362306a36Sopenharmony_ci unsigned char buf[64]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci memset(buf, 0, sizeof buf); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci va_start(args, fmt); 23862306a36Sopenharmony_ci vsnprintf(buf, sizeof buf, fmt, args); 23962306a36Sopenharmony_ci va_end(args); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { 24262306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 24362306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 24462306a36Sopenharmony_ci return -1; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ciEXPORT_SYMBOL(iscsi_change_param_sprintf); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * This is the leading connection of a new session, 25362306a36Sopenharmony_ci * or session reinstatement. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_cistatic int iscsi_login_zero_tsih_s1( 25662306a36Sopenharmony_ci struct iscsit_conn *conn, 25762306a36Sopenharmony_ci unsigned char *buf) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct iscsit_session *sess = NULL; 26062306a36Sopenharmony_ci struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci sess = kzalloc(sizeof(struct iscsit_session), GFP_KERNEL); 26462306a36Sopenharmony_ci if (!sess) { 26562306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 26662306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 26762306a36Sopenharmony_ci pr_err("Could not allocate memory for session\n"); 26862306a36Sopenharmony_ci return -ENOMEM; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (iscsi_login_set_conn_values(sess, conn, pdu->cid)) 27262306a36Sopenharmony_ci goto free_sess; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci sess->init_task_tag = pdu->itt; 27562306a36Sopenharmony_ci memcpy(&sess->isid, pdu->isid, 6); 27662306a36Sopenharmony_ci sess->exp_cmd_sn = be32_to_cpu(pdu->cmdsn); 27762306a36Sopenharmony_ci INIT_LIST_HEAD(&sess->sess_conn_list); 27862306a36Sopenharmony_ci INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list); 27962306a36Sopenharmony_ci INIT_LIST_HEAD(&sess->cr_active_list); 28062306a36Sopenharmony_ci INIT_LIST_HEAD(&sess->cr_inactive_list); 28162306a36Sopenharmony_ci init_completion(&sess->async_msg_comp); 28262306a36Sopenharmony_ci init_completion(&sess->reinstatement_comp); 28362306a36Sopenharmony_ci init_completion(&sess->session_wait_comp); 28462306a36Sopenharmony_ci init_completion(&sess->session_waiting_on_uc_comp); 28562306a36Sopenharmony_ci mutex_init(&sess->cmdsn_mutex); 28662306a36Sopenharmony_ci spin_lock_init(&sess->conn_lock); 28762306a36Sopenharmony_ci spin_lock_init(&sess->cr_a_lock); 28862306a36Sopenharmony_ci spin_lock_init(&sess->cr_i_lock); 28962306a36Sopenharmony_ci spin_lock_init(&sess->session_usage_lock); 29062306a36Sopenharmony_ci spin_lock_init(&sess->ttt_lock); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci timer_setup(&sess->time2retain_timer, 29362306a36Sopenharmony_ci iscsit_handle_time2retain_timeout, 0); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ret = ida_alloc(&sess_ida, GFP_KERNEL); 29662306a36Sopenharmony_ci if (ret < 0) { 29762306a36Sopenharmony_ci pr_err("Session ID allocation failed %d\n", ret); 29862306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 29962306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 30062306a36Sopenharmony_ci goto free_sess; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci sess->session_index = ret; 30462306a36Sopenharmony_ci sess->creation_time = get_jiffies_64(); 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci * The FFP CmdSN window values will be allocated from the TPG's 30762306a36Sopenharmony_ci * Initiator Node's ACL once the login has been successfully completed. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci atomic_set(&sess->max_cmd_sn, be32_to_cpu(pdu->cmdsn)); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL); 31262306a36Sopenharmony_ci if (!sess->sess_ops) { 31362306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 31462306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 31562306a36Sopenharmony_ci pr_err("Unable to allocate memory for" 31662306a36Sopenharmony_ci " struct iscsi_sess_ops.\n"); 31762306a36Sopenharmony_ci goto free_id; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci sess->se_sess = transport_alloc_session(TARGET_PROT_NORMAL); 32162306a36Sopenharmony_ci if (IS_ERR(sess->se_sess)) { 32262306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 32362306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 32462306a36Sopenharmony_ci goto free_ops; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cifree_ops: 33062306a36Sopenharmony_ci kfree(sess->sess_ops); 33162306a36Sopenharmony_cifree_id: 33262306a36Sopenharmony_ci ida_free(&sess_ida, sess->session_index); 33362306a36Sopenharmony_cifree_sess: 33462306a36Sopenharmony_ci kfree(sess); 33562306a36Sopenharmony_ci conn->sess = NULL; 33662306a36Sopenharmony_ci return -ENOMEM; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int iscsi_login_zero_tsih_s2( 34062306a36Sopenharmony_ci struct iscsit_conn *conn) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct iscsi_node_attrib *na; 34362306a36Sopenharmony_ci struct iscsit_session *sess = conn->sess; 34462306a36Sopenharmony_ci struct iscsi_param *param; 34562306a36Sopenharmony_ci bool iser = false; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci sess->tpg = conn->tpg; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * Assign a new TPG Session Handle. Note this is protected with 35162306a36Sopenharmony_ci * struct iscsi_portal_group->np_login_sem from iscsit_access_np(). 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci sess->tsih = ++sess->tpg->ntsih; 35462306a36Sopenharmony_ci if (!sess->tsih) 35562306a36Sopenharmony_ci sess->tsih = ++sess->tpg->ntsih; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * Create the default params from user defined values.. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci if (iscsi_copy_param_list(&conn->param_list, 36162306a36Sopenharmony_ci conn->tpg->param_list, 1) < 0) { 36262306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 36362306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 36462306a36Sopenharmony_ci return -1; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) 36862306a36Sopenharmony_ci iser = true; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci iscsi_set_keys_to_negotiate(conn->param_list, iser); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (sess->sess_ops->SessionType) 37362306a36Sopenharmony_ci return iscsi_set_keys_irrelevant_for_discovery( 37462306a36Sopenharmony_ci conn->param_list); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci na = iscsit_tpg_get_node_attrib(sess); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * If ACL allows non-authorized access in TPG with CHAP, 38062306a36Sopenharmony_ci * then set None to AuthMethod. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); 38362306a36Sopenharmony_ci if (param && !strstr(param->value, NONE)) { 38462306a36Sopenharmony_ci if (!iscsi_conn_auth_required(conn)) 38562306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "AuthMethod=%s", 38662306a36Sopenharmony_ci NONE)) 38762306a36Sopenharmony_ci return -1; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * Need to send TargetPortalGroupTag back in first login response 39262306a36Sopenharmony_ci * on any iSCSI connection where the Initiator provides TargetName. 39362306a36Sopenharmony_ci * See 5.3.1. Login Phase Start 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * In our case, we have already located the struct iscsi_tiqn at this point. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt)) 39862306a36Sopenharmony_ci return -1; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * Workaround for Initiators that have broken connection recovery logic. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * "We would really like to get rid of this." Linux-iSCSI.org team 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "ErrorRecoveryLevel=%d", na->default_erl)) 40662306a36Sopenharmony_ci return -1; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* 40962306a36Sopenharmony_ci * Set RDMAExtensions=Yes by default for iSER enabled network portals 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci if (iser) { 41262306a36Sopenharmony_ci struct iscsi_param *param; 41362306a36Sopenharmony_ci unsigned long mrdsl, off; 41462306a36Sopenharmony_ci int rc; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "RDMAExtensions=Yes")) 41762306a36Sopenharmony_ci return -1; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for 42162306a36Sopenharmony_ci * Immediate Data + Unsolicited Data-OUT if necessary.. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci param = iscsi_find_param_from_key("MaxRecvDataSegmentLength", 42462306a36Sopenharmony_ci conn->param_list); 42562306a36Sopenharmony_ci if (!param) { 42662306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 42762306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 42862306a36Sopenharmony_ci return -1; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci rc = kstrtoul(param->value, 0, &mrdsl); 43162306a36Sopenharmony_ci if (rc < 0) { 43262306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 43362306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 43462306a36Sopenharmony_ci return -1; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci off = mrdsl % PAGE_SIZE; 43762306a36Sopenharmony_ci if (!off) 43862306a36Sopenharmony_ci goto check_prot; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (mrdsl < PAGE_SIZE) 44162306a36Sopenharmony_ci mrdsl = PAGE_SIZE; 44262306a36Sopenharmony_ci else 44362306a36Sopenharmony_ci mrdsl -= off; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down" 44662306a36Sopenharmony_ci " to PAGE_SIZE\n", mrdsl); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "MaxRecvDataSegmentLength=%lu\n", mrdsl)) 44962306a36Sopenharmony_ci return -1; 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * ISER currently requires that ImmediateData + Unsolicited 45262306a36Sopenharmony_ci * Data be disabled when protection / signature MRs are enabled. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_cicheck_prot: 45562306a36Sopenharmony_ci if (sess->se_sess->sup_prot_ops & 45662306a36Sopenharmony_ci (TARGET_PROT_DOUT_STRIP | TARGET_PROT_DOUT_PASS | 45762306a36Sopenharmony_ci TARGET_PROT_DOUT_INSERT)) { 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "ImmediateData=No")) 46062306a36Sopenharmony_ci return -1; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "InitialR2T=Yes")) 46362306a36Sopenharmony_ci return -1; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci pr_debug("Forcing ImmediateData=No + InitialR2T=Yes for" 46662306a36Sopenharmony_ci " T10-PI enabled ISER session\n"); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int iscsi_login_non_zero_tsih_s1( 47462306a36Sopenharmony_ci struct iscsit_conn *conn, 47562306a36Sopenharmony_ci unsigned char *buf) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return iscsi_login_set_conn_values(NULL, conn, pdu->cid); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci/* 48362306a36Sopenharmony_ci * Add a new connection to an existing session. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic int iscsi_login_non_zero_tsih_s2( 48662306a36Sopenharmony_ci struct iscsit_conn *conn, 48762306a36Sopenharmony_ci unsigned char *buf) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct iscsi_portal_group *tpg = conn->tpg; 49062306a36Sopenharmony_ci struct iscsit_session *sess = NULL, *sess_p = NULL; 49162306a36Sopenharmony_ci struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; 49262306a36Sopenharmony_ci struct se_session *se_sess, *se_sess_tmp; 49362306a36Sopenharmony_ci struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; 49462306a36Sopenharmony_ci bool iser = false; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci spin_lock_bh(&se_tpg->session_lock); 49762306a36Sopenharmony_ci list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, 49862306a36Sopenharmony_ci sess_list) { 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci sess_p = (struct iscsit_session *)se_sess->fabric_sess_ptr; 50162306a36Sopenharmony_ci if (atomic_read(&sess_p->session_fall_back_to_erl0) || 50262306a36Sopenharmony_ci atomic_read(&sess_p->session_logout) || 50362306a36Sopenharmony_ci atomic_read(&sess_p->session_close) || 50462306a36Sopenharmony_ci (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) 50562306a36Sopenharmony_ci continue; 50662306a36Sopenharmony_ci if (!memcmp(sess_p->isid, pdu->isid, 6) && 50762306a36Sopenharmony_ci (sess_p->tsih == be16_to_cpu(pdu->tsih))) { 50862306a36Sopenharmony_ci iscsit_inc_session_usage_count(sess_p); 50962306a36Sopenharmony_ci iscsit_stop_time2retain_timer(sess_p); 51062306a36Sopenharmony_ci sess = sess_p; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci spin_unlock_bh(&se_tpg->session_lock); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * If the Time2Retain handler has expired, the session is already gone. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci if (!sess) { 52062306a36Sopenharmony_ci pr_err("Initiator attempting to add a connection to" 52162306a36Sopenharmony_ci " a non-existent session, rejecting iSCSI Login.\n"); 52262306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 52362306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_SESSION); 52462306a36Sopenharmony_ci return -1; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* 52862306a36Sopenharmony_ci * Stop the Time2Retain timer if this is a failed session, we restart 52962306a36Sopenharmony_ci * the timer if the login is not successful. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci spin_lock_bh(&sess->conn_lock); 53262306a36Sopenharmony_ci if (sess->session_state == TARG_SESS_STATE_FAILED) 53362306a36Sopenharmony_ci atomic_set(&sess->session_continuation, 1); 53462306a36Sopenharmony_ci spin_unlock_bh(&sess->conn_lock); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (iscsi_login_set_conn_values(sess, conn, pdu->cid) < 0 || 53762306a36Sopenharmony_ci iscsi_copy_param_list(&conn->param_list, 53862306a36Sopenharmony_ci conn->tpg->param_list, 0) < 0) { 53962306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 54062306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 54162306a36Sopenharmony_ci return -1; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) 54562306a36Sopenharmony_ci iser = true; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci iscsi_set_keys_to_negotiate(conn->param_list, iser); 54862306a36Sopenharmony_ci /* 54962306a36Sopenharmony_ci * Need to send TargetPortalGroupTag back in first login response 55062306a36Sopenharmony_ci * on any iSCSI connection where the Initiator provides TargetName. 55162306a36Sopenharmony_ci * See 5.3.1. Login Phase Start 55262306a36Sopenharmony_ci * 55362306a36Sopenharmony_ci * In our case, we have already located the struct iscsi_tiqn at this point. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt)) 55662306a36Sopenharmony_ci return -1; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ciint iscsi_login_post_auth_non_zero_tsih( 56262306a36Sopenharmony_ci struct iscsit_conn *conn, 56362306a36Sopenharmony_ci u16 cid, 56462306a36Sopenharmony_ci u32 exp_statsn) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct iscsit_conn *conn_ptr = NULL; 56762306a36Sopenharmony_ci struct iscsi_conn_recovery *cr = NULL; 56862306a36Sopenharmony_ci struct iscsit_session *sess = conn->sess; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* 57162306a36Sopenharmony_ci * By following item 5 in the login table, if we have found 57262306a36Sopenharmony_ci * an existing ISID and a valid/existing TSIH and an existing 57362306a36Sopenharmony_ci * CID we do connection reinstatement. Currently we dont not 57462306a36Sopenharmony_ci * support it so we send back an non-zero status class to the 57562306a36Sopenharmony_ci * initiator and release the new connection. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid); 57862306a36Sopenharmony_ci if (conn_ptr) { 57962306a36Sopenharmony_ci pr_err("Connection exists with CID %hu for %s," 58062306a36Sopenharmony_ci " performing connection reinstatement.\n", 58162306a36Sopenharmony_ci conn_ptr->cid, sess->sess_ops->InitiatorName); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci iscsit_connection_reinstatement_rcfr(conn_ptr); 58462306a36Sopenharmony_ci iscsit_dec_conn_usage_count(conn_ptr); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* 58862306a36Sopenharmony_ci * Check for any connection recovery entries containing CID. 58962306a36Sopenharmony_ci * We use the original ExpStatSN sent in the first login request 59062306a36Sopenharmony_ci * to acknowledge commands for the failed connection. 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * Also note that an explict logout may have already been sent, 59362306a36Sopenharmony_ci * but the response may not be sent due to additional connection 59462306a36Sopenharmony_ci * loss. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci if (sess->sess_ops->ErrorRecoveryLevel == 2) { 59762306a36Sopenharmony_ci cr = iscsit_get_inactive_connection_recovery_entry( 59862306a36Sopenharmony_ci sess, cid); 59962306a36Sopenharmony_ci if (cr) { 60062306a36Sopenharmony_ci pr_debug("Performing implicit logout" 60162306a36Sopenharmony_ci " for connection recovery on CID: %hu\n", 60262306a36Sopenharmony_ci conn->cid); 60362306a36Sopenharmony_ci iscsit_discard_cr_cmds_by_expstatsn(cr, exp_statsn); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* 60862306a36Sopenharmony_ci * Else we follow item 4 from the login table in that we have 60962306a36Sopenharmony_ci * found an existing ISID and a valid/existing TSIH and a new 61062306a36Sopenharmony_ci * CID we go ahead and continue to add a new connection to the 61162306a36Sopenharmony_ci * session. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci pr_debug("Adding CID %hu to existing session for %s.\n", 61462306a36Sopenharmony_ci cid, sess->sess_ops->InitiatorName); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if ((atomic_read(&sess->nconn) + 1) > sess->sess_ops->MaxConnections) { 61762306a36Sopenharmony_ci pr_err("Adding additional connection to this session" 61862306a36Sopenharmony_ci " would exceed MaxConnections %d, login failed.\n", 61962306a36Sopenharmony_ci sess->sess_ops->MaxConnections); 62062306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 62162306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_ISID_ERROR); 62262306a36Sopenharmony_ci return -1; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic void iscsi_post_login_start_timers(struct iscsit_conn *conn) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct iscsit_session *sess = conn->sess; 63162306a36Sopenharmony_ci /* 63262306a36Sopenharmony_ci * FIXME: Unsolicited NopIN support for ISER 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) 63562306a36Sopenharmony_ci return; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (!sess->sess_ops->SessionType) 63862306a36Sopenharmony_ci iscsit_start_nopin_timer(conn); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ciint iscsit_start_kthreads(struct iscsit_conn *conn) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci int ret = 0; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci spin_lock(&iscsit_global->ts_bitmap_lock); 64662306a36Sopenharmony_ci conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap, 64762306a36Sopenharmony_ci ISCSIT_BITMAP_BITS, get_order(1)); 64862306a36Sopenharmony_ci spin_unlock(&iscsit_global->ts_bitmap_lock); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (conn->bitmap_id < 0) { 65162306a36Sopenharmony_ci pr_err("bitmap_find_free_region() failed for" 65262306a36Sopenharmony_ci " iscsit_start_kthreads()\n"); 65362306a36Sopenharmony_ci return -ENOMEM; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn, 65762306a36Sopenharmony_ci "%s", ISCSI_TX_THREAD_NAME); 65862306a36Sopenharmony_ci if (IS_ERR(conn->tx_thread)) { 65962306a36Sopenharmony_ci pr_err("Unable to start iscsi_target_tx_thread\n"); 66062306a36Sopenharmony_ci ret = PTR_ERR(conn->tx_thread); 66162306a36Sopenharmony_ci goto out_bitmap; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci conn->tx_thread_active = true; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, 66662306a36Sopenharmony_ci "%s", ISCSI_RX_THREAD_NAME); 66762306a36Sopenharmony_ci if (IS_ERR(conn->rx_thread)) { 66862306a36Sopenharmony_ci pr_err("Unable to start iscsi_target_rx_thread\n"); 66962306a36Sopenharmony_ci ret = PTR_ERR(conn->rx_thread); 67062306a36Sopenharmony_ci goto out_tx; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci conn->rx_thread_active = true; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ciout_tx: 67662306a36Sopenharmony_ci send_sig(SIGINT, conn->tx_thread, 1); 67762306a36Sopenharmony_ci kthread_stop(conn->tx_thread); 67862306a36Sopenharmony_ci conn->tx_thread_active = false; 67962306a36Sopenharmony_ciout_bitmap: 68062306a36Sopenharmony_ci spin_lock(&iscsit_global->ts_bitmap_lock); 68162306a36Sopenharmony_ci bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, 68262306a36Sopenharmony_ci get_order(1)); 68362306a36Sopenharmony_ci spin_unlock(&iscsit_global->ts_bitmap_lock); 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_civoid iscsi_post_login_handler( 68862306a36Sopenharmony_ci struct iscsi_np *np, 68962306a36Sopenharmony_ci struct iscsit_conn *conn, 69062306a36Sopenharmony_ci u8 zero_tsih) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci int stop_timer = 0; 69362306a36Sopenharmony_ci struct iscsit_session *sess = conn->sess; 69462306a36Sopenharmony_ci struct se_session *se_sess = sess->se_sess; 69562306a36Sopenharmony_ci struct iscsi_portal_group *tpg = sess->tpg; 69662306a36Sopenharmony_ci struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci iscsit_inc_conn_usage_count(conn); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_SUCCESS, 70162306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_ACCEPT); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci pr_debug("Moving to TARG_CONN_STATE_LOGGED_IN.\n"); 70462306a36Sopenharmony_ci conn->conn_state = TARG_CONN_STATE_LOGGED_IN; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci iscsi_set_connection_parameters(conn->conn_ops, conn->param_list); 70762306a36Sopenharmony_ci /* 70862306a36Sopenharmony_ci * SCSI Initiator -> SCSI Target Port Mapping 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (!zero_tsih) { 71162306a36Sopenharmony_ci iscsi_set_session_parameters(sess->sess_ops, 71262306a36Sopenharmony_ci conn->param_list, 0); 71362306a36Sopenharmony_ci iscsi_release_param_list(conn->param_list); 71462306a36Sopenharmony_ci conn->param_list = NULL; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci spin_lock_bh(&sess->conn_lock); 71762306a36Sopenharmony_ci atomic_set(&sess->session_continuation, 0); 71862306a36Sopenharmony_ci if (sess->session_state == TARG_SESS_STATE_FAILED) { 71962306a36Sopenharmony_ci pr_debug("Moving to" 72062306a36Sopenharmony_ci " TARG_SESS_STATE_LOGGED_IN.\n"); 72162306a36Sopenharmony_ci sess->session_state = TARG_SESS_STATE_LOGGED_IN; 72262306a36Sopenharmony_ci stop_timer = 1; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci pr_debug("iSCSI Login successful on CID: %hu from %pISpc to" 72662306a36Sopenharmony_ci " %pISpc,%hu\n", conn->cid, &conn->login_sockaddr, 72762306a36Sopenharmony_ci &conn->local_sockaddr, tpg->tpgt); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci list_add_tail(&conn->conn_list, &sess->sess_conn_list); 73062306a36Sopenharmony_ci atomic_inc(&sess->nconn); 73162306a36Sopenharmony_ci pr_debug("Incremented iSCSI Connection count to %d" 73262306a36Sopenharmony_ci " from node: %s\n", atomic_read(&sess->nconn), 73362306a36Sopenharmony_ci sess->sess_ops->InitiatorName); 73462306a36Sopenharmony_ci spin_unlock_bh(&sess->conn_lock); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci iscsi_post_login_start_timers(conn); 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * Determine CPU mask to ensure connection's RX and TX kthreads 73962306a36Sopenharmony_ci * are scheduled on the same CPU. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci iscsit_thread_get_cpumask(conn); 74262306a36Sopenharmony_ci conn->conn_rx_reset_cpumask = 1; 74362306a36Sopenharmony_ci conn->conn_tx_reset_cpumask = 1; 74462306a36Sopenharmony_ci /* 74562306a36Sopenharmony_ci * Wakeup the sleeping iscsi_target_rx_thread() now that 74662306a36Sopenharmony_ci * iscsit_conn is in TARG_CONN_STATE_LOGGED_IN state. 74762306a36Sopenharmony_ci */ 74862306a36Sopenharmony_ci complete(&conn->rx_login_comp); 74962306a36Sopenharmony_ci iscsit_dec_conn_usage_count(conn); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (stop_timer) { 75262306a36Sopenharmony_ci spin_lock_bh(&se_tpg->session_lock); 75362306a36Sopenharmony_ci iscsit_stop_time2retain_timer(sess); 75462306a36Sopenharmony_ci spin_unlock_bh(&se_tpg->session_lock); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci iscsit_dec_session_usage_count(sess); 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); 76162306a36Sopenharmony_ci iscsi_release_param_list(conn->param_list); 76262306a36Sopenharmony_ci conn->param_list = NULL; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci iscsit_determine_maxcmdsn(sess); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci spin_lock_bh(&se_tpg->session_lock); 76762306a36Sopenharmony_ci __transport_register_session(&sess->tpg->tpg_se_tpg, 76862306a36Sopenharmony_ci se_sess->se_node_acl, se_sess, sess); 76962306a36Sopenharmony_ci pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); 77062306a36Sopenharmony_ci sess->session_state = TARG_SESS_STATE_LOGGED_IN; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci pr_debug("iSCSI Login successful on CID: %hu from %pISpc to %pISpc,%hu\n", 77362306a36Sopenharmony_ci conn->cid, &conn->login_sockaddr, &conn->local_sockaddr, 77462306a36Sopenharmony_ci tpg->tpgt); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_lock_bh(&sess->conn_lock); 77762306a36Sopenharmony_ci list_add_tail(&conn->conn_list, &sess->sess_conn_list); 77862306a36Sopenharmony_ci atomic_inc(&sess->nconn); 77962306a36Sopenharmony_ci pr_debug("Incremented iSCSI Connection count to %d from node:" 78062306a36Sopenharmony_ci " %s\n", atomic_read(&sess->nconn), 78162306a36Sopenharmony_ci sess->sess_ops->InitiatorName); 78262306a36Sopenharmony_ci spin_unlock_bh(&sess->conn_lock); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci sess->sid = tpg->sid++; 78562306a36Sopenharmony_ci if (!sess->sid) 78662306a36Sopenharmony_ci sess->sid = tpg->sid++; 78762306a36Sopenharmony_ci pr_debug("Established iSCSI session from node: %s\n", 78862306a36Sopenharmony_ci sess->sess_ops->InitiatorName); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci tpg->nsessions++; 79162306a36Sopenharmony_ci if (tpg->tpg_tiqn) 79262306a36Sopenharmony_ci tpg->tpg_tiqn->tiqn_nsessions++; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci pr_debug("Incremented number of active iSCSI sessions to %u on" 79562306a36Sopenharmony_ci " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); 79662306a36Sopenharmony_ci spin_unlock_bh(&se_tpg->session_lock); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci iscsi_post_login_start_timers(conn); 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * Determine CPU mask to ensure connection's RX and TX kthreads 80162306a36Sopenharmony_ci * are scheduled on the same CPU. 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci iscsit_thread_get_cpumask(conn); 80462306a36Sopenharmony_ci conn->conn_rx_reset_cpumask = 1; 80562306a36Sopenharmony_ci conn->conn_tx_reset_cpumask = 1; 80662306a36Sopenharmony_ci /* 80762306a36Sopenharmony_ci * Wakeup the sleeping iscsi_target_rx_thread() now that 80862306a36Sopenharmony_ci * iscsit_conn is in TARG_CONN_STATE_LOGGED_IN state. 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci complete(&conn->rx_login_comp); 81162306a36Sopenharmony_ci iscsit_dec_conn_usage_count(conn); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ciint iscsit_setup_np( 81562306a36Sopenharmony_ci struct iscsi_np *np, 81662306a36Sopenharmony_ci struct sockaddr_storage *sockaddr) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct socket *sock = NULL; 81962306a36Sopenharmony_ci int backlog = ISCSIT_TCP_BACKLOG, ret, len; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci switch (np->np_network_transport) { 82262306a36Sopenharmony_ci case ISCSI_TCP: 82362306a36Sopenharmony_ci np->np_ip_proto = IPPROTO_TCP; 82462306a36Sopenharmony_ci np->np_sock_type = SOCK_STREAM; 82562306a36Sopenharmony_ci break; 82662306a36Sopenharmony_ci case ISCSI_SCTP_TCP: 82762306a36Sopenharmony_ci np->np_ip_proto = IPPROTO_SCTP; 82862306a36Sopenharmony_ci np->np_sock_type = SOCK_STREAM; 82962306a36Sopenharmony_ci break; 83062306a36Sopenharmony_ci case ISCSI_SCTP_UDP: 83162306a36Sopenharmony_ci np->np_ip_proto = IPPROTO_SCTP; 83262306a36Sopenharmony_ci np->np_sock_type = SOCK_SEQPACKET; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci default: 83562306a36Sopenharmony_ci pr_err("Unsupported network_transport: %d\n", 83662306a36Sopenharmony_ci np->np_network_transport); 83762306a36Sopenharmony_ci return -EINVAL; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci ret = sock_create(sockaddr->ss_family, np->np_sock_type, 84162306a36Sopenharmony_ci np->np_ip_proto, &sock); 84262306a36Sopenharmony_ci if (ret < 0) { 84362306a36Sopenharmony_ci pr_err("sock_create() failed.\n"); 84462306a36Sopenharmony_ci return ret; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci np->np_socket = sock; 84762306a36Sopenharmony_ci /* 84862306a36Sopenharmony_ci * Setup the np->np_sockaddr from the passed sockaddr setup 84962306a36Sopenharmony_ci * in iscsi_target_configfs.c code.. 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci memcpy(&np->np_sockaddr, sockaddr, 85262306a36Sopenharmony_ci sizeof(struct sockaddr_storage)); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (sockaddr->ss_family == AF_INET6) 85562306a36Sopenharmony_ci len = sizeof(struct sockaddr_in6); 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci len = sizeof(struct sockaddr_in); 85862306a36Sopenharmony_ci /* 85962306a36Sopenharmony_ci * Set SO_REUSEADDR, and disable Nagle Algorithm with TCP_NODELAY. 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ci if (np->np_network_transport == ISCSI_TCP) 86262306a36Sopenharmony_ci tcp_sock_set_nodelay(sock->sk); 86362306a36Sopenharmony_ci sock_set_reuseaddr(sock->sk); 86462306a36Sopenharmony_ci ip_sock_set_freebind(sock->sk); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ret = kernel_bind(sock, (struct sockaddr *)&np->np_sockaddr, len); 86762306a36Sopenharmony_ci if (ret < 0) { 86862306a36Sopenharmony_ci pr_err("kernel_bind() failed: %d\n", ret); 86962306a36Sopenharmony_ci goto fail; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ret = kernel_listen(sock, backlog); 87362306a36Sopenharmony_ci if (ret != 0) { 87462306a36Sopenharmony_ci pr_err("kernel_listen() failed: %d\n", ret); 87562306a36Sopenharmony_ci goto fail; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_cifail: 88062306a36Sopenharmony_ci np->np_socket = NULL; 88162306a36Sopenharmony_ci sock_release(sock); 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ciint iscsi_target_setup_login_socket( 88662306a36Sopenharmony_ci struct iscsi_np *np, 88762306a36Sopenharmony_ci struct sockaddr_storage *sockaddr) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct iscsit_transport *t; 89062306a36Sopenharmony_ci int rc; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci t = iscsit_get_transport(np->np_network_transport); 89362306a36Sopenharmony_ci if (!t) 89462306a36Sopenharmony_ci return -EINVAL; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci rc = t->iscsit_setup_np(np, sockaddr); 89762306a36Sopenharmony_ci if (rc < 0) { 89862306a36Sopenharmony_ci iscsit_put_transport(t); 89962306a36Sopenharmony_ci return rc; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci np->np_transport = t; 90362306a36Sopenharmony_ci np->enabled = true; 90462306a36Sopenharmony_ci return 0; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ciint iscsit_accept_np(struct iscsi_np *np, struct iscsit_conn *conn) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct socket *new_sock, *sock = np->np_socket; 91062306a36Sopenharmony_ci struct sockaddr_in sock_in; 91162306a36Sopenharmony_ci struct sockaddr_in6 sock_in6; 91262306a36Sopenharmony_ci int rc; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci rc = kernel_accept(sock, &new_sock, 0); 91562306a36Sopenharmony_ci if (rc < 0) 91662306a36Sopenharmony_ci return rc; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci conn->sock = new_sock; 91962306a36Sopenharmony_ci conn->login_family = np->np_sockaddr.ss_family; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (np->np_sockaddr.ss_family == AF_INET6) { 92262306a36Sopenharmony_ci memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci rc = conn->sock->ops->getname(conn->sock, 92562306a36Sopenharmony_ci (struct sockaddr *)&sock_in6, 1); 92662306a36Sopenharmony_ci if (rc >= 0) { 92762306a36Sopenharmony_ci if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) { 92862306a36Sopenharmony_ci memcpy(&conn->login_sockaddr, &sock_in6, sizeof(sock_in6)); 92962306a36Sopenharmony_ci } else { 93062306a36Sopenharmony_ci /* Pretend to be an ipv4 socket */ 93162306a36Sopenharmony_ci sock_in.sin_family = AF_INET; 93262306a36Sopenharmony_ci sock_in.sin_port = sock_in6.sin6_port; 93362306a36Sopenharmony_ci memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4); 93462306a36Sopenharmony_ci memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in)); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci rc = conn->sock->ops->getname(conn->sock, 93962306a36Sopenharmony_ci (struct sockaddr *)&sock_in6, 0); 94062306a36Sopenharmony_ci if (rc >= 0) { 94162306a36Sopenharmony_ci if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) { 94262306a36Sopenharmony_ci memcpy(&conn->local_sockaddr, &sock_in6, sizeof(sock_in6)); 94362306a36Sopenharmony_ci } else { 94462306a36Sopenharmony_ci /* Pretend to be an ipv4 socket */ 94562306a36Sopenharmony_ci sock_in.sin_family = AF_INET; 94662306a36Sopenharmony_ci sock_in.sin_port = sock_in6.sin6_port; 94762306a36Sopenharmony_ci memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4); 94862306a36Sopenharmony_ci memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in)); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci } else { 95262306a36Sopenharmony_ci memset(&sock_in, 0, sizeof(struct sockaddr_in)); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci rc = conn->sock->ops->getname(conn->sock, 95562306a36Sopenharmony_ci (struct sockaddr *)&sock_in, 1); 95662306a36Sopenharmony_ci if (rc >= 0) 95762306a36Sopenharmony_ci memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in)); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci rc = conn->sock->ops->getname(conn->sock, 96062306a36Sopenharmony_ci (struct sockaddr *)&sock_in, 0); 96162306a36Sopenharmony_ci if (rc >= 0) 96262306a36Sopenharmony_ci memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in)); 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ciint iscsit_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct iscsi_login_req *login_req; 97162306a36Sopenharmony_ci u32 padding = 0, payload_length; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0) 97462306a36Sopenharmony_ci return -1; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci login_req = (struct iscsi_login_req *)login->req; 97762306a36Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 97862306a36Sopenharmony_ci padding = ((-payload_length) & 3); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," 98162306a36Sopenharmony_ci " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n", 98262306a36Sopenharmony_ci login_req->flags, login_req->itt, login_req->cmdsn, 98362306a36Sopenharmony_ci login_req->exp_statsn, login_req->cid, payload_length); 98462306a36Sopenharmony_ci /* 98562306a36Sopenharmony_ci * Setup the initial iscsi_login values from the leading 98662306a36Sopenharmony_ci * login request PDU. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci if (login->first_request) { 98962306a36Sopenharmony_ci login_req = (struct iscsi_login_req *)login->req; 99062306a36Sopenharmony_ci login->leading_connection = (!login_req->tsih) ? 1 : 0; 99162306a36Sopenharmony_ci login->current_stage = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags); 99262306a36Sopenharmony_ci login->version_min = login_req->min_version; 99362306a36Sopenharmony_ci login->version_max = login_req->max_version; 99462306a36Sopenharmony_ci memcpy(login->isid, login_req->isid, 6); 99562306a36Sopenharmony_ci login->cmd_sn = be32_to_cpu(login_req->cmdsn); 99662306a36Sopenharmony_ci login->init_task_tag = login_req->itt; 99762306a36Sopenharmony_ci login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn); 99862306a36Sopenharmony_ci login->cid = be16_to_cpu(login_req->cid); 99962306a36Sopenharmony_ci login->tsih = be16_to_cpu(login_req->tsih); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (iscsi_target_check_login_request(conn, login) < 0) 100362306a36Sopenharmony_ci return -1; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS); 100662306a36Sopenharmony_ci if (iscsi_login_rx_data(conn, login->req_buf, 100762306a36Sopenharmony_ci payload_length + padding) < 0) 100862306a36Sopenharmony_ci return -1; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ciint iscsit_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login, 101462306a36Sopenharmony_ci u32 length) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0) 101762306a36Sopenharmony_ci return -1; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return 0; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int 102362306a36Sopenharmony_ciiscsit_conn_set_transport(struct iscsit_conn *conn, struct iscsit_transport *t) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci int rc; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (!t->owner) { 102862306a36Sopenharmony_ci conn->conn_transport = t; 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci rc = try_module_get(t->owner); 103362306a36Sopenharmony_ci if (!rc) { 103462306a36Sopenharmony_ci pr_err("try_module_get() failed for %s\n", t->name); 103562306a36Sopenharmony_ci return -EINVAL; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci conn->conn_transport = t; 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct iscsit_conn *conn; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci conn = kzalloc(sizeof(struct iscsit_conn), GFP_KERNEL); 104762306a36Sopenharmony_ci if (!conn) { 104862306a36Sopenharmony_ci pr_err("Could not allocate memory for new connection\n"); 104962306a36Sopenharmony_ci return NULL; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); 105262306a36Sopenharmony_ci conn->conn_state = TARG_CONN_STATE_FREE; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci init_waitqueue_head(&conn->queues_wq); 105562306a36Sopenharmony_ci INIT_LIST_HEAD(&conn->conn_list); 105662306a36Sopenharmony_ci INIT_LIST_HEAD(&conn->conn_cmd_list); 105762306a36Sopenharmony_ci INIT_LIST_HEAD(&conn->immed_queue_list); 105862306a36Sopenharmony_ci INIT_LIST_HEAD(&conn->response_queue_list); 105962306a36Sopenharmony_ci init_completion(&conn->conn_post_wait_comp); 106062306a36Sopenharmony_ci init_completion(&conn->conn_wait_comp); 106162306a36Sopenharmony_ci init_completion(&conn->conn_wait_rcfr_comp); 106262306a36Sopenharmony_ci init_completion(&conn->conn_waiting_on_uc_comp); 106362306a36Sopenharmony_ci init_completion(&conn->conn_logout_comp); 106462306a36Sopenharmony_ci init_completion(&conn->rx_half_close_comp); 106562306a36Sopenharmony_ci init_completion(&conn->tx_half_close_comp); 106662306a36Sopenharmony_ci init_completion(&conn->rx_login_comp); 106762306a36Sopenharmony_ci spin_lock_init(&conn->cmd_lock); 106862306a36Sopenharmony_ci spin_lock_init(&conn->conn_usage_lock); 106962306a36Sopenharmony_ci spin_lock_init(&conn->immed_queue_lock); 107062306a36Sopenharmony_ci spin_lock_init(&conn->nopin_timer_lock); 107162306a36Sopenharmony_ci spin_lock_init(&conn->response_queue_lock); 107262306a36Sopenharmony_ci spin_lock_init(&conn->state_lock); 107362306a36Sopenharmony_ci spin_lock_init(&conn->login_worker_lock); 107462306a36Sopenharmony_ci spin_lock_init(&conn->login_timer_lock); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci timer_setup(&conn->nopin_response_timer, 107762306a36Sopenharmony_ci iscsit_handle_nopin_response_timeout, 0); 107862306a36Sopenharmony_ci timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0); 107962306a36Sopenharmony_ci timer_setup(&conn->login_timer, iscsit_login_timeout, 0); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (iscsit_conn_set_transport(conn, np->np_transport) < 0) 108262306a36Sopenharmony_ci goto free_conn; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); 108562306a36Sopenharmony_ci if (!conn->conn_ops) { 108662306a36Sopenharmony_ci pr_err("Unable to allocate memory for struct iscsi_conn_ops.\n"); 108762306a36Sopenharmony_ci goto put_transport; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { 109162306a36Sopenharmony_ci pr_err("Unable to allocate conn->conn_cpumask\n"); 109262306a36Sopenharmony_ci goto free_conn_ops; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (!zalloc_cpumask_var(&conn->allowed_cpumask, GFP_KERNEL)) { 109662306a36Sopenharmony_ci pr_err("Unable to allocate conn->allowed_cpumask\n"); 109762306a36Sopenharmony_ci goto free_conn_cpumask; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci conn->cmd_cnt = target_alloc_cmd_counter(); 110162306a36Sopenharmony_ci if (!conn->cmd_cnt) 110262306a36Sopenharmony_ci goto free_conn_allowed_cpumask; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci return conn; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cifree_conn_allowed_cpumask: 110762306a36Sopenharmony_ci free_cpumask_var(conn->allowed_cpumask); 110862306a36Sopenharmony_cifree_conn_cpumask: 110962306a36Sopenharmony_ci free_cpumask_var(conn->conn_cpumask); 111062306a36Sopenharmony_cifree_conn_ops: 111162306a36Sopenharmony_ci kfree(conn->conn_ops); 111262306a36Sopenharmony_ciput_transport: 111362306a36Sopenharmony_ci iscsit_put_transport(conn->conn_transport); 111462306a36Sopenharmony_cifree_conn: 111562306a36Sopenharmony_ci kfree(conn); 111662306a36Sopenharmony_ci return NULL; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_civoid iscsit_free_conn(struct iscsit_conn *conn) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci target_free_cmd_counter(conn->cmd_cnt); 112262306a36Sopenharmony_ci free_cpumask_var(conn->allowed_cpumask); 112362306a36Sopenharmony_ci free_cpumask_var(conn->conn_cpumask); 112462306a36Sopenharmony_ci kfree(conn->conn_ops); 112562306a36Sopenharmony_ci iscsit_put_transport(conn->conn_transport); 112662306a36Sopenharmony_ci kfree(conn); 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_civoid iscsi_target_login_sess_out(struct iscsit_conn *conn, 113062306a36Sopenharmony_ci bool zero_tsih, bool new_sess) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci if (!new_sess) 113362306a36Sopenharmony_ci goto old_sess_out; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci pr_err("iSCSI Login negotiation failed.\n"); 113662306a36Sopenharmony_ci iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 113762306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 113862306a36Sopenharmony_ci if (!zero_tsih || !conn->sess) 113962306a36Sopenharmony_ci goto old_sess_out; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci transport_free_session(conn->sess->se_sess); 114262306a36Sopenharmony_ci ida_free(&sess_ida, conn->sess->session_index); 114362306a36Sopenharmony_ci kfree(conn->sess->sess_ops); 114462306a36Sopenharmony_ci kfree(conn->sess); 114562306a36Sopenharmony_ci conn->sess = NULL; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ciold_sess_out: 114862306a36Sopenharmony_ci /* 114962306a36Sopenharmony_ci * If login negotiation fails check if the Time2Retain timer 115062306a36Sopenharmony_ci * needs to be restarted. 115162306a36Sopenharmony_ci */ 115262306a36Sopenharmony_ci if (!zero_tsih && conn->sess) { 115362306a36Sopenharmony_ci spin_lock_bh(&conn->sess->conn_lock); 115462306a36Sopenharmony_ci if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { 115562306a36Sopenharmony_ci struct se_portal_group *se_tpg = 115662306a36Sopenharmony_ci &conn->tpg->tpg_se_tpg; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci atomic_set(&conn->sess->session_continuation, 0); 115962306a36Sopenharmony_ci spin_unlock_bh(&conn->sess->conn_lock); 116062306a36Sopenharmony_ci spin_lock_bh(&se_tpg->session_lock); 116162306a36Sopenharmony_ci iscsit_start_time2retain_handler(conn->sess); 116262306a36Sopenharmony_ci spin_unlock_bh(&se_tpg->session_lock); 116362306a36Sopenharmony_ci } else 116462306a36Sopenharmony_ci spin_unlock_bh(&conn->sess->conn_lock); 116562306a36Sopenharmony_ci iscsit_dec_session_usage_count(conn->sess); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci ahash_request_free(conn->conn_tx_hash); 116962306a36Sopenharmony_ci if (conn->conn_rx_hash) { 117062306a36Sopenharmony_ci struct crypto_ahash *tfm; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci tfm = crypto_ahash_reqtfm(conn->conn_rx_hash); 117362306a36Sopenharmony_ci ahash_request_free(conn->conn_rx_hash); 117462306a36Sopenharmony_ci crypto_free_ahash(tfm); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (conn->param_list) { 117862306a36Sopenharmony_ci iscsi_release_param_list(conn->param_list); 117962306a36Sopenharmony_ci conn->param_list = NULL; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci iscsi_target_nego_release(conn); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (conn->sock) { 118462306a36Sopenharmony_ci sock_release(conn->sock); 118562306a36Sopenharmony_ci conn->sock = NULL; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (conn->conn_transport->iscsit_wait_conn) 118962306a36Sopenharmony_ci conn->conn_transport->iscsit_wait_conn(conn); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (conn->conn_transport->iscsit_free_conn) 119262306a36Sopenharmony_ci conn->conn_transport->iscsit_free_conn(conn); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci iscsit_free_conn(conn); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic int __iscsi_target_login_thread(struct iscsi_np *np) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci u8 *buffer, zero_tsih = 0; 120062306a36Sopenharmony_ci int ret = 0, rc; 120162306a36Sopenharmony_ci struct iscsit_conn *conn = NULL; 120262306a36Sopenharmony_ci struct iscsi_login *login; 120362306a36Sopenharmony_ci struct iscsi_portal_group *tpg = NULL; 120462306a36Sopenharmony_ci struct iscsi_login_req *pdu; 120562306a36Sopenharmony_ci struct iscsi_tpg_np *tpg_np; 120662306a36Sopenharmony_ci bool new_sess = false; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci flush_signals(current); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 121162306a36Sopenharmony_ci if (atomic_dec_if_positive(&np->np_reset_count) >= 0) { 121262306a36Sopenharmony_ci np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; 121362306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 121462306a36Sopenharmony_ci complete(&np->np_restart_comp); 121562306a36Sopenharmony_ci return 1; 121662306a36Sopenharmony_ci } else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) { 121762306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 121862306a36Sopenharmony_ci goto exit; 121962306a36Sopenharmony_ci } else { 122062306a36Sopenharmony_ci np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci conn = iscsit_alloc_conn(np); 122562306a36Sopenharmony_ci if (!conn) { 122662306a36Sopenharmony_ci /* Get another socket */ 122762306a36Sopenharmony_ci return 1; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci rc = np->np_transport->iscsit_accept_np(np, conn); 123162306a36Sopenharmony_ci if (rc == -ENOSYS) { 123262306a36Sopenharmony_ci complete(&np->np_restart_comp); 123362306a36Sopenharmony_ci iscsit_free_conn(conn); 123462306a36Sopenharmony_ci goto exit; 123562306a36Sopenharmony_ci } else if (rc < 0) { 123662306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 123762306a36Sopenharmony_ci if (atomic_dec_if_positive(&np->np_reset_count) >= 0) { 123862306a36Sopenharmony_ci np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; 123962306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 124062306a36Sopenharmony_ci complete(&np->np_restart_comp); 124162306a36Sopenharmony_ci iscsit_free_conn(conn); 124262306a36Sopenharmony_ci /* Get another socket */ 124362306a36Sopenharmony_ci return 1; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 124662306a36Sopenharmony_ci iscsit_free_conn(conn); 124762306a36Sopenharmony_ci return 1; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci /* 125062306a36Sopenharmony_ci * Perform the remaining iSCSI connection initialization items.. 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_ci login = iscsi_login_init_conn(conn); 125362306a36Sopenharmony_ci if (!login) { 125462306a36Sopenharmony_ci goto new_sess_out; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci iscsit_start_login_timer(conn, current); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); 126062306a36Sopenharmony_ci conn->conn_state = TARG_CONN_STATE_XPT_UP; 126162306a36Sopenharmony_ci /* 126262306a36Sopenharmony_ci * This will process the first login request + payload.. 126362306a36Sopenharmony_ci */ 126462306a36Sopenharmony_ci rc = np->np_transport->iscsit_get_login_rx(conn, login); 126562306a36Sopenharmony_ci if (rc == 1) 126662306a36Sopenharmony_ci return 1; 126762306a36Sopenharmony_ci else if (rc < 0) 126862306a36Sopenharmony_ci goto new_sess_out; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci buffer = &login->req[0]; 127162306a36Sopenharmony_ci pdu = (struct iscsi_login_req *)buffer; 127262306a36Sopenharmony_ci /* 127362306a36Sopenharmony_ci * Used by iscsit_tx_login_rsp() for Login Resonses PDUs 127462306a36Sopenharmony_ci * when Status-Class != 0. 127562306a36Sopenharmony_ci */ 127662306a36Sopenharmony_ci conn->login_itt = pdu->itt; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 127962306a36Sopenharmony_ci if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { 128062306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 128162306a36Sopenharmony_ci pr_err("iSCSI Network Portal on %pISpc currently not" 128262306a36Sopenharmony_ci " active.\n", &np->np_sockaddr); 128362306a36Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 128462306a36Sopenharmony_ci ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 128562306a36Sopenharmony_ci goto new_sess_out; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci conn->network_transport = np->np_network_transport; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci pr_debug("Received iSCSI login request from %pISpc on %s Network" 129262306a36Sopenharmony_ci " Portal %pISpc\n", &conn->login_sockaddr, np->np_transport->name, 129362306a36Sopenharmony_ci &conn->local_sockaddr); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); 129662306a36Sopenharmony_ci conn->conn_state = TARG_CONN_STATE_IN_LOGIN; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (iscsi_login_check_initiator_version(conn, pdu->max_version, 129962306a36Sopenharmony_ci pdu->min_version) < 0) 130062306a36Sopenharmony_ci goto new_sess_out; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci zero_tsih = (pdu->tsih == 0x0000); 130362306a36Sopenharmony_ci if (zero_tsih) { 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * This is the leading connection of a new session. 130662306a36Sopenharmony_ci * We wait until after authentication to check for 130762306a36Sopenharmony_ci * session reinstatement. 130862306a36Sopenharmony_ci */ 130962306a36Sopenharmony_ci if (iscsi_login_zero_tsih_s1(conn, buffer) < 0) 131062306a36Sopenharmony_ci goto new_sess_out; 131162306a36Sopenharmony_ci } else { 131262306a36Sopenharmony_ci /* 131362306a36Sopenharmony_ci * Add a new connection to an existing session. 131462306a36Sopenharmony_ci * We check for a non-existant session in 131562306a36Sopenharmony_ci * iscsi_login_non_zero_tsih_s2() below based 131662306a36Sopenharmony_ci * on ISID/TSIH, but wait until after authentication 131762306a36Sopenharmony_ci * to check for connection reinstatement, etc. 131862306a36Sopenharmony_ci */ 131962306a36Sopenharmony_ci if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0) 132062306a36Sopenharmony_ci goto new_sess_out; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci /* 132362306a36Sopenharmony_ci * SessionType: Discovery 132462306a36Sopenharmony_ci * 132562306a36Sopenharmony_ci * Locates Default Portal 132662306a36Sopenharmony_ci * 132762306a36Sopenharmony_ci * SessionType: Normal 132862306a36Sopenharmony_ci * 132962306a36Sopenharmony_ci * Locates Target Portal from NP -> Target IQN 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_ci rc = iscsi_target_locate_portal(np, conn, login); 133262306a36Sopenharmony_ci if (rc < 0) { 133362306a36Sopenharmony_ci tpg = conn->tpg; 133462306a36Sopenharmony_ci goto new_sess_out; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci login->zero_tsih = zero_tsih; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (conn->sess) 133962306a36Sopenharmony_ci conn->sess->se_sess->sup_prot_ops = 134062306a36Sopenharmony_ci conn->conn_transport->iscsit_get_sup_prot_ops(conn); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci tpg = conn->tpg; 134362306a36Sopenharmony_ci if (!tpg) { 134462306a36Sopenharmony_ci pr_err("Unable to locate struct iscsit_conn->tpg\n"); 134562306a36Sopenharmony_ci goto new_sess_out; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (zero_tsih) { 134962306a36Sopenharmony_ci if (iscsi_login_zero_tsih_s2(conn) < 0) 135062306a36Sopenharmony_ci goto new_sess_out; 135162306a36Sopenharmony_ci } else { 135262306a36Sopenharmony_ci if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) 135362306a36Sopenharmony_ci goto old_sess_out; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (conn->conn_transport->iscsit_validate_params) { 135762306a36Sopenharmony_ci ret = conn->conn_transport->iscsit_validate_params(conn); 135862306a36Sopenharmony_ci if (ret < 0) { 135962306a36Sopenharmony_ci if (zero_tsih) 136062306a36Sopenharmony_ci goto new_sess_out; 136162306a36Sopenharmony_ci else 136262306a36Sopenharmony_ci goto old_sess_out; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci ret = iscsi_target_start_negotiation(login, conn); 136762306a36Sopenharmony_ci if (ret < 0) 136862306a36Sopenharmony_ci goto new_sess_out; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (ret == 1) { 137162306a36Sopenharmony_ci tpg_np = conn->tpg_np; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci iscsi_post_login_handler(np, conn, zero_tsih); 137462306a36Sopenharmony_ci iscsit_deaccess_np(np, tpg, tpg_np); 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci tpg = NULL; 137862306a36Sopenharmony_ci tpg_np = NULL; 137962306a36Sopenharmony_ci /* Get another socket */ 138062306a36Sopenharmony_ci return 1; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cinew_sess_out: 138362306a36Sopenharmony_ci new_sess = true; 138462306a36Sopenharmony_ciold_sess_out: 138562306a36Sopenharmony_ci iscsit_stop_login_timer(conn); 138662306a36Sopenharmony_ci tpg_np = conn->tpg_np; 138762306a36Sopenharmony_ci iscsi_target_login_sess_out(conn, zero_tsih, new_sess); 138862306a36Sopenharmony_ci new_sess = false; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (tpg) { 139162306a36Sopenharmony_ci iscsit_deaccess_np(np, tpg, tpg_np); 139262306a36Sopenharmony_ci tpg = NULL; 139362306a36Sopenharmony_ci tpg_np = NULL; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci return 1; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ciexit: 139962306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 140062306a36Sopenharmony_ci np->np_thread_state = ISCSI_NP_THREAD_EXIT; 140162306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return 0; 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ciint iscsi_target_login_thread(void *arg) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci struct iscsi_np *np = arg; 140962306a36Sopenharmony_ci int ret; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci allow_signal(SIGINT); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci while (1) { 141462306a36Sopenharmony_ci ret = __iscsi_target_login_thread(np); 141562306a36Sopenharmony_ci /* 141662306a36Sopenharmony_ci * We break and exit here unless another sock_accept() call 141762306a36Sopenharmony_ci * is expected. 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_ci if (ret != 1) 142062306a36Sopenharmony_ci break; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci while (!kthread_should_stop()) { 142462306a36Sopenharmony_ci msleep(100); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci return 0; 142862306a36Sopenharmony_ci} 1429