18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*******************************************************************************
38c2ecf20Sopenharmony_ci * This file contains the login functions used by the iSCSI Target driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci ******************************************************************************/
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <crypto/hash.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/kthread.h>
158c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
168c2ecf20Sopenharmony_ci#include <linux/idr.h>
178c2ecf20Sopenharmony_ci#include <linux/tcp.h>        /* TCP_NODELAY */
188c2ecf20Sopenharmony_ci#include <net/ip.h>
198c2ecf20Sopenharmony_ci#include <net/ipv6.h>         /* ipv6_addr_v4mapped() */
208c2ecf20Sopenharmony_ci#include <scsi/iscsi_proto.h>
218c2ecf20Sopenharmony_ci#include <target/target_core_base.h>
228c2ecf20Sopenharmony_ci#include <target/target_core_fabric.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h>
258c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_stat.h>
268c2ecf20Sopenharmony_ci#include "iscsi_target_device.h"
278c2ecf20Sopenharmony_ci#include "iscsi_target_nego.h"
288c2ecf20Sopenharmony_ci#include "iscsi_target_erl0.h"
298c2ecf20Sopenharmony_ci#include "iscsi_target_erl2.h"
308c2ecf20Sopenharmony_ci#include "iscsi_target_login.h"
318c2ecf20Sopenharmony_ci#include "iscsi_target_tpg.h"
328c2ecf20Sopenharmony_ci#include "iscsi_target_util.h"
338c2ecf20Sopenharmony_ci#include "iscsi_target.h"
348c2ecf20Sopenharmony_ci#include "iscsi_target_parameters.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_transport.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct iscsi_login *login;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
438c2ecf20Sopenharmony_ci	if (!login) {
448c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for struct iscsi_login.\n");
458c2ecf20Sopenharmony_ci		return NULL;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	conn->login = login;
488c2ecf20Sopenharmony_ci	login->conn = conn;
498c2ecf20Sopenharmony_ci	login->first_request = 1;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
528c2ecf20Sopenharmony_ci	if (!login->req_buf) {
538c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for response buffer.\n");
548c2ecf20Sopenharmony_ci		goto out_login;
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
588c2ecf20Sopenharmony_ci	if (!login->rsp_buf) {
598c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for request buffer.\n");
608c2ecf20Sopenharmony_ci		goto out_req_buf;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	conn->conn_login = login;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return login;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciout_req_buf:
688c2ecf20Sopenharmony_ci	kfree(login->req_buf);
698c2ecf20Sopenharmony_ciout_login:
708c2ecf20Sopenharmony_ci	kfree(login);
718c2ecf20Sopenharmony_ci	return NULL;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*
758c2ecf20Sopenharmony_ci * Used by iscsi_target_nego.c:iscsi_target_locate_portal() to setup
768c2ecf20Sopenharmony_ci * per struct iscsi_conn libcrypto contexts for crc32c and crc32-intel
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_ciint iscsi_login_setup_crypto(struct iscsi_conn *conn)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/*
838c2ecf20Sopenharmony_ci	 * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts
848c2ecf20Sopenharmony_ci	 * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback
858c2ecf20Sopenharmony_ci	 * to software 1x8 byte slicing from crc32c.ko
868c2ecf20Sopenharmony_ci	 */
878c2ecf20Sopenharmony_ci	tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
888c2ecf20Sopenharmony_ci	if (IS_ERR(tfm)) {
898c2ecf20Sopenharmony_ci		pr_err("crypto_alloc_ahash() failed\n");
908c2ecf20Sopenharmony_ci		return -ENOMEM;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	conn->conn_rx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
948c2ecf20Sopenharmony_ci	if (!conn->conn_rx_hash) {
958c2ecf20Sopenharmony_ci		pr_err("ahash_request_alloc() failed for conn_rx_hash\n");
968c2ecf20Sopenharmony_ci		crypto_free_ahash(tfm);
978c2ecf20Sopenharmony_ci		return -ENOMEM;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	ahash_request_set_callback(conn->conn_rx_hash, 0, NULL, NULL);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	conn->conn_tx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
1028c2ecf20Sopenharmony_ci	if (!conn->conn_tx_hash) {
1038c2ecf20Sopenharmony_ci		pr_err("ahash_request_alloc() failed for conn_tx_hash\n");
1048c2ecf20Sopenharmony_ci		ahash_request_free(conn->conn_rx_hash);
1058c2ecf20Sopenharmony_ci		conn->conn_rx_hash = NULL;
1068c2ecf20Sopenharmony_ci		crypto_free_ahash(tfm);
1078c2ecf20Sopenharmony_ci		return -ENOMEM;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci	ahash_request_set_callback(conn->conn_tx_hash, 0, NULL, NULL);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int iscsi_login_check_initiator_version(
1158c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
1168c2ecf20Sopenharmony_ci	u8 version_max,
1178c2ecf20Sopenharmony_ci	u8 version_min)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	if ((version_max != 0x00) || (version_min != 0x00)) {
1208c2ecf20Sopenharmony_ci		pr_err("Unsupported iSCSI IETF Pre-RFC Revision,"
1218c2ecf20Sopenharmony_ci			" version Min/Max 0x%02x/0x%02x, rejecting login.\n",
1228c2ecf20Sopenharmony_ci			version_min, version_max);
1238c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
1248c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_VERSION);
1258c2ecf20Sopenharmony_ci		return -1;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int sessiontype;
1348c2ecf20Sopenharmony_ci	struct iscsi_param *initiatorname_param = NULL, *sessiontype_param = NULL;
1358c2ecf20Sopenharmony_ci	struct iscsi_portal_group *tpg = conn->tpg;
1368c2ecf20Sopenharmony_ci	struct iscsi_session *sess = NULL, *sess_p = NULL;
1378c2ecf20Sopenharmony_ci	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
1388c2ecf20Sopenharmony_ci	struct se_session *se_sess, *se_sess_tmp;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	initiatorname_param = iscsi_find_param_from_key(
1418c2ecf20Sopenharmony_ci			INITIATORNAME, conn->param_list);
1428c2ecf20Sopenharmony_ci	sessiontype_param = iscsi_find_param_from_key(
1438c2ecf20Sopenharmony_ci			SESSIONTYPE, conn->param_list);
1448c2ecf20Sopenharmony_ci	if (!initiatorname_param || !sessiontype_param) {
1458c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
1468c2ecf20Sopenharmony_ci			ISCSI_LOGIN_STATUS_MISSING_FIELDS);
1478c2ecf20Sopenharmony_ci		return -1;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	spin_lock_bh(&se_tpg->session_lock);
1538c2ecf20Sopenharmony_ci	list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
1548c2ecf20Sopenharmony_ci			sess_list) {
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		sess_p = se_sess->fabric_sess_ptr;
1578c2ecf20Sopenharmony_ci		spin_lock(&sess_p->conn_lock);
1588c2ecf20Sopenharmony_ci		if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
1598c2ecf20Sopenharmony_ci		    atomic_read(&sess_p->session_logout) ||
1608c2ecf20Sopenharmony_ci		    atomic_read(&sess_p->session_close) ||
1618c2ecf20Sopenharmony_ci		    (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
1628c2ecf20Sopenharmony_ci			spin_unlock(&sess_p->conn_lock);
1638c2ecf20Sopenharmony_ci			continue;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci		if (!memcmp(sess_p->isid, conn->sess->isid, 6) &&
1668c2ecf20Sopenharmony_ci		   (!strcmp(sess_p->sess_ops->InitiatorName,
1678c2ecf20Sopenharmony_ci			    initiatorname_param->value) &&
1688c2ecf20Sopenharmony_ci		   (sess_p->sess_ops->SessionType == sessiontype))) {
1698c2ecf20Sopenharmony_ci			atomic_set(&sess_p->session_reinstatement, 1);
1708c2ecf20Sopenharmony_ci			atomic_set(&sess_p->session_fall_back_to_erl0, 1);
1718c2ecf20Sopenharmony_ci			atomic_set(&sess_p->session_close, 1);
1728c2ecf20Sopenharmony_ci			spin_unlock(&sess_p->conn_lock);
1738c2ecf20Sopenharmony_ci			iscsit_inc_session_usage_count(sess_p);
1748c2ecf20Sopenharmony_ci			iscsit_stop_time2retain_timer(sess_p);
1758c2ecf20Sopenharmony_ci			sess = sess_p;
1768c2ecf20Sopenharmony_ci			break;
1778c2ecf20Sopenharmony_ci		}
1788c2ecf20Sopenharmony_ci		spin_unlock(&sess_p->conn_lock);
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	spin_unlock_bh(&se_tpg->session_lock);
1818c2ecf20Sopenharmony_ci	/*
1828c2ecf20Sopenharmony_ci	 * If the Time2Retain handler has expired, the session is already gone.
1838c2ecf20Sopenharmony_ci	 */
1848c2ecf20Sopenharmony_ci	if (!sess)
1858c2ecf20Sopenharmony_ci		return 0;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	pr_debug("%s iSCSI Session SID %u is still active for %s,"
1888c2ecf20Sopenharmony_ci		" performing session reinstatement.\n", (sessiontype) ?
1898c2ecf20Sopenharmony_ci		"Discovery" : "Normal", sess->sid,
1908c2ecf20Sopenharmony_ci		sess->sess_ops->InitiatorName);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
1938c2ecf20Sopenharmony_ci	if (sess->session_state == TARG_SESS_STATE_FAILED) {
1948c2ecf20Sopenharmony_ci		spin_unlock_bh(&sess->conn_lock);
1958c2ecf20Sopenharmony_ci		iscsit_dec_session_usage_count(sess);
1968c2ecf20Sopenharmony_ci		return 0;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	iscsit_stop_session(sess, 1, 1);
2018c2ecf20Sopenharmony_ci	iscsit_dec_session_usage_count(sess);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int iscsi_login_set_conn_values(
2078c2ecf20Sopenharmony_ci	struct iscsi_session *sess,
2088c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
2098c2ecf20Sopenharmony_ci	__be16 cid)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	int ret;
2128c2ecf20Sopenharmony_ci	conn->sess		= sess;
2138c2ecf20Sopenharmony_ci	conn->cid		= be16_to_cpu(cid);
2148c2ecf20Sopenharmony_ci	/*
2158c2ecf20Sopenharmony_ci	 * Generate a random Status sequence number (statsn) for the new
2168c2ecf20Sopenharmony_ci	 * iSCSI connection.
2178c2ecf20Sopenharmony_ci	 */
2188c2ecf20Sopenharmony_ci	ret = get_random_bytes_wait(&conn->stat_sn, sizeof(u32));
2198c2ecf20Sopenharmony_ci	if (unlikely(ret))
2208c2ecf20Sopenharmony_ci		return ret;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	mutex_lock(&auth_id_lock);
2238c2ecf20Sopenharmony_ci	conn->auth_id		= iscsit_global->auth_id++;
2248c2ecf20Sopenharmony_ci	mutex_unlock(&auth_id_lock);
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci__printf(2, 3) int iscsi_change_param_sprintf(
2298c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
2308c2ecf20Sopenharmony_ci	const char *fmt, ...)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	va_list args;
2338c2ecf20Sopenharmony_ci	unsigned char buf[64];
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	memset(buf, 0, sizeof buf);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	va_start(args, fmt);
2388c2ecf20Sopenharmony_ci	vsnprintf(buf, sizeof buf, fmt, args);
2398c2ecf20Sopenharmony_ci	va_end(args);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
2428c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
2438c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
2448c2ecf20Sopenharmony_ci		return -1;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iscsi_change_param_sprintf);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/*
2528c2ecf20Sopenharmony_ci *	This is the leading connection of a new session,
2538c2ecf20Sopenharmony_ci *	or session reinstatement.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic int iscsi_login_zero_tsih_s1(
2568c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
2578c2ecf20Sopenharmony_ci	unsigned char *buf)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct iscsi_session *sess = NULL;
2608c2ecf20Sopenharmony_ci	struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
2618c2ecf20Sopenharmony_ci	int ret;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
2648c2ecf20Sopenharmony_ci	if (!sess) {
2658c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
2668c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
2678c2ecf20Sopenharmony_ci		pr_err("Could not allocate memory for session\n");
2688c2ecf20Sopenharmony_ci		return -ENOMEM;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (iscsi_login_set_conn_values(sess, conn, pdu->cid))
2728c2ecf20Sopenharmony_ci		goto free_sess;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	sess->init_task_tag	= pdu->itt;
2758c2ecf20Sopenharmony_ci	memcpy(&sess->isid, pdu->isid, 6);
2768c2ecf20Sopenharmony_ci	sess->exp_cmd_sn	= be32_to_cpu(pdu->cmdsn);
2778c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sess->sess_conn_list);
2788c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list);
2798c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sess->cr_active_list);
2808c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sess->cr_inactive_list);
2818c2ecf20Sopenharmony_ci	init_completion(&sess->async_msg_comp);
2828c2ecf20Sopenharmony_ci	init_completion(&sess->reinstatement_comp);
2838c2ecf20Sopenharmony_ci	init_completion(&sess->session_wait_comp);
2848c2ecf20Sopenharmony_ci	init_completion(&sess->session_waiting_on_uc_comp);
2858c2ecf20Sopenharmony_ci	mutex_init(&sess->cmdsn_mutex);
2868c2ecf20Sopenharmony_ci	spin_lock_init(&sess->conn_lock);
2878c2ecf20Sopenharmony_ci	spin_lock_init(&sess->cr_a_lock);
2888c2ecf20Sopenharmony_ci	spin_lock_init(&sess->cr_i_lock);
2898c2ecf20Sopenharmony_ci	spin_lock_init(&sess->session_usage_lock);
2908c2ecf20Sopenharmony_ci	spin_lock_init(&sess->ttt_lock);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	timer_setup(&sess->time2retain_timer,
2938c2ecf20Sopenharmony_ci		    iscsit_handle_time2retain_timeout, 0);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	ret = ida_alloc(&sess_ida, GFP_KERNEL);
2968c2ecf20Sopenharmony_ci	if (ret < 0) {
2978c2ecf20Sopenharmony_ci		pr_err("Session ID allocation failed %d\n", ret);
2988c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
2998c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
3008c2ecf20Sopenharmony_ci		goto free_sess;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	sess->session_index = ret;
3048c2ecf20Sopenharmony_ci	sess->creation_time = get_jiffies_64();
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	 * The FFP CmdSN window values will be allocated from the TPG's
3078c2ecf20Sopenharmony_ci	 * Initiator Node's ACL once the login has been successfully completed.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	atomic_set(&sess->max_cmd_sn, be32_to_cpu(pdu->cmdsn));
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
3128c2ecf20Sopenharmony_ci	if (!sess->sess_ops) {
3138c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
3148c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
3158c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for"
3168c2ecf20Sopenharmony_ci				" struct iscsi_sess_ops.\n");
3178c2ecf20Sopenharmony_ci		goto free_id;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	sess->se_sess = transport_alloc_session(TARGET_PROT_NORMAL);
3218c2ecf20Sopenharmony_ci	if (IS_ERR(sess->se_sess)) {
3228c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
3238c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
3248c2ecf20Sopenharmony_ci		goto free_ops;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return 0;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cifree_ops:
3308c2ecf20Sopenharmony_ci	kfree(sess->sess_ops);
3318c2ecf20Sopenharmony_cifree_id:
3328c2ecf20Sopenharmony_ci	ida_free(&sess_ida, sess->session_index);
3338c2ecf20Sopenharmony_cifree_sess:
3348c2ecf20Sopenharmony_ci	kfree(sess);
3358c2ecf20Sopenharmony_ci	conn->sess = NULL;
3368c2ecf20Sopenharmony_ci	return -ENOMEM;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int iscsi_login_zero_tsih_s2(
3408c2ecf20Sopenharmony_ci	struct iscsi_conn *conn)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct iscsi_node_attrib *na;
3438c2ecf20Sopenharmony_ci	struct iscsi_session *sess = conn->sess;
3448c2ecf20Sopenharmony_ci	bool iser = false;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	sess->tpg = conn->tpg;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/*
3498c2ecf20Sopenharmony_ci	 * Assign a new TPG Session Handle.  Note this is protected with
3508c2ecf20Sopenharmony_ci	 * struct iscsi_portal_group->np_login_sem from iscsit_access_np().
3518c2ecf20Sopenharmony_ci	 */
3528c2ecf20Sopenharmony_ci	sess->tsih = ++sess->tpg->ntsih;
3538c2ecf20Sopenharmony_ci	if (!sess->tsih)
3548c2ecf20Sopenharmony_ci		sess->tsih = ++sess->tpg->ntsih;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/*
3578c2ecf20Sopenharmony_ci	 * Create the default params from user defined values..
3588c2ecf20Sopenharmony_ci	 */
3598c2ecf20Sopenharmony_ci	if (iscsi_copy_param_list(&conn->param_list,
3608c2ecf20Sopenharmony_ci				conn->tpg->param_list, 1) < 0) {
3618c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
3628c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
3638c2ecf20Sopenharmony_ci		return -1;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
3678c2ecf20Sopenharmony_ci		iser = true;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	iscsi_set_keys_to_negotiate(conn->param_list, iser);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (sess->sess_ops->SessionType)
3728c2ecf20Sopenharmony_ci		return iscsi_set_keys_irrelevant_for_discovery(
3738c2ecf20Sopenharmony_ci				conn->param_list);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	na = iscsit_tpg_get_node_attrib(sess);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/*
3788c2ecf20Sopenharmony_ci	 * Need to send TargetPortalGroupTag back in first login response
3798c2ecf20Sopenharmony_ci	 * on any iSCSI connection where the Initiator provides TargetName.
3808c2ecf20Sopenharmony_ci	 * See 5.3.1.  Login Phase Start
3818c2ecf20Sopenharmony_ci	 *
3828c2ecf20Sopenharmony_ci	 * In our case, we have already located the struct iscsi_tiqn at this point.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt))
3858c2ecf20Sopenharmony_ci		return -1;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/*
3888c2ecf20Sopenharmony_ci	 * Workaround for Initiators that have broken connection recovery logic.
3898c2ecf20Sopenharmony_ci	 *
3908c2ecf20Sopenharmony_ci	 * "We would really like to get rid of this." Linux-iSCSI.org team
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	if (iscsi_change_param_sprintf(conn, "ErrorRecoveryLevel=%d", na->default_erl))
3938c2ecf20Sopenharmony_ci		return -1;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	/*
3968c2ecf20Sopenharmony_ci	 * Set RDMAExtensions=Yes by default for iSER enabled network portals
3978c2ecf20Sopenharmony_ci	 */
3988c2ecf20Sopenharmony_ci	if (iser) {
3998c2ecf20Sopenharmony_ci		struct iscsi_param *param;
4008c2ecf20Sopenharmony_ci		unsigned long mrdsl, off;
4018c2ecf20Sopenharmony_ci		int rc;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		if (iscsi_change_param_sprintf(conn, "RDMAExtensions=Yes"))
4048c2ecf20Sopenharmony_ci			return -1;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		/*
4078c2ecf20Sopenharmony_ci		 * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
4088c2ecf20Sopenharmony_ci		 * Immediate Data + Unsolicited Data-OUT if necessary..
4098c2ecf20Sopenharmony_ci		 */
4108c2ecf20Sopenharmony_ci		param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
4118c2ecf20Sopenharmony_ci						  conn->param_list);
4128c2ecf20Sopenharmony_ci		if (!param) {
4138c2ecf20Sopenharmony_ci			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
4148c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
4158c2ecf20Sopenharmony_ci			return -1;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci		rc = kstrtoul(param->value, 0, &mrdsl);
4188c2ecf20Sopenharmony_ci		if (rc < 0) {
4198c2ecf20Sopenharmony_ci			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
4208c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
4218c2ecf20Sopenharmony_ci			return -1;
4228c2ecf20Sopenharmony_ci		}
4238c2ecf20Sopenharmony_ci		off = mrdsl % PAGE_SIZE;
4248c2ecf20Sopenharmony_ci		if (!off)
4258c2ecf20Sopenharmony_ci			goto check_prot;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		if (mrdsl < PAGE_SIZE)
4288c2ecf20Sopenharmony_ci			mrdsl = PAGE_SIZE;
4298c2ecf20Sopenharmony_ci		else
4308c2ecf20Sopenharmony_ci			mrdsl -= off;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
4338c2ecf20Sopenharmony_ci			" to PAGE_SIZE\n", mrdsl);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		if (iscsi_change_param_sprintf(conn, "MaxRecvDataSegmentLength=%lu\n", mrdsl))
4368c2ecf20Sopenharmony_ci			return -1;
4378c2ecf20Sopenharmony_ci		/*
4388c2ecf20Sopenharmony_ci		 * ISER currently requires that ImmediateData + Unsolicited
4398c2ecf20Sopenharmony_ci		 * Data be disabled when protection / signature MRs are enabled.
4408c2ecf20Sopenharmony_ci		 */
4418c2ecf20Sopenharmony_cicheck_prot:
4428c2ecf20Sopenharmony_ci		if (sess->se_sess->sup_prot_ops &
4438c2ecf20Sopenharmony_ci		   (TARGET_PROT_DOUT_STRIP | TARGET_PROT_DOUT_PASS |
4448c2ecf20Sopenharmony_ci		    TARGET_PROT_DOUT_INSERT)) {
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			if (iscsi_change_param_sprintf(conn, "ImmediateData=No"))
4478c2ecf20Sopenharmony_ci				return -1;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci			if (iscsi_change_param_sprintf(conn, "InitialR2T=Yes"))
4508c2ecf20Sopenharmony_ci				return -1;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci			pr_debug("Forcing ImmediateData=No + InitialR2T=Yes for"
4538c2ecf20Sopenharmony_ci				 " T10-PI enabled ISER session\n");
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int iscsi_login_non_zero_tsih_s1(
4618c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
4628c2ecf20Sopenharmony_ci	unsigned char *buf)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return iscsi_login_set_conn_values(NULL, conn, pdu->cid);
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/*
4708c2ecf20Sopenharmony_ci *	Add a new connection to an existing session.
4718c2ecf20Sopenharmony_ci */
4728c2ecf20Sopenharmony_cistatic int iscsi_login_non_zero_tsih_s2(
4738c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
4748c2ecf20Sopenharmony_ci	unsigned char *buf)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct iscsi_portal_group *tpg = conn->tpg;
4778c2ecf20Sopenharmony_ci	struct iscsi_session *sess = NULL, *sess_p = NULL;
4788c2ecf20Sopenharmony_ci	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
4798c2ecf20Sopenharmony_ci	struct se_session *se_sess, *se_sess_tmp;
4808c2ecf20Sopenharmony_ci	struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
4818c2ecf20Sopenharmony_ci	bool iser = false;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	spin_lock_bh(&se_tpg->session_lock);
4848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
4858c2ecf20Sopenharmony_ci			sess_list) {
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr;
4888c2ecf20Sopenharmony_ci		if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
4898c2ecf20Sopenharmony_ci		    atomic_read(&sess_p->session_logout) ||
4908c2ecf20Sopenharmony_ci		    atomic_read(&sess_p->session_close) ||
4918c2ecf20Sopenharmony_ci		   (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
4928c2ecf20Sopenharmony_ci			continue;
4938c2ecf20Sopenharmony_ci		if (!memcmp(sess_p->isid, pdu->isid, 6) &&
4948c2ecf20Sopenharmony_ci		     (sess_p->tsih == be16_to_cpu(pdu->tsih))) {
4958c2ecf20Sopenharmony_ci			iscsit_inc_session_usage_count(sess_p);
4968c2ecf20Sopenharmony_ci			iscsit_stop_time2retain_timer(sess_p);
4978c2ecf20Sopenharmony_ci			sess = sess_p;
4988c2ecf20Sopenharmony_ci			break;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	spin_unlock_bh(&se_tpg->session_lock);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/*
5048c2ecf20Sopenharmony_ci	 * If the Time2Retain handler has expired, the session is already gone.
5058c2ecf20Sopenharmony_ci	 */
5068c2ecf20Sopenharmony_ci	if (!sess) {
5078c2ecf20Sopenharmony_ci		pr_err("Initiator attempting to add a connection to"
5088c2ecf20Sopenharmony_ci			" a non-existent session, rejecting iSCSI Login.\n");
5098c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
5108c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_SESSION);
5118c2ecf20Sopenharmony_ci		return -1;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/*
5158c2ecf20Sopenharmony_ci	 * Stop the Time2Retain timer if this is a failed session, we restart
5168c2ecf20Sopenharmony_ci	 * the timer if the login is not successful.
5178c2ecf20Sopenharmony_ci	 */
5188c2ecf20Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
5198c2ecf20Sopenharmony_ci	if (sess->session_state == TARG_SESS_STATE_FAILED)
5208c2ecf20Sopenharmony_ci		atomic_set(&sess->session_continuation, 1);
5218c2ecf20Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (iscsi_login_set_conn_values(sess, conn, pdu->cid) < 0 ||
5248c2ecf20Sopenharmony_ci	    iscsi_copy_param_list(&conn->param_list,
5258c2ecf20Sopenharmony_ci			conn->tpg->param_list, 0) < 0) {
5268c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
5278c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_NO_RESOURCES);
5288c2ecf20Sopenharmony_ci		return -1;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
5328c2ecf20Sopenharmony_ci		iser = true;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	iscsi_set_keys_to_negotiate(conn->param_list, iser);
5358c2ecf20Sopenharmony_ci	/*
5368c2ecf20Sopenharmony_ci	 * Need to send TargetPortalGroupTag back in first login response
5378c2ecf20Sopenharmony_ci	 * on any iSCSI connection where the Initiator provides TargetName.
5388c2ecf20Sopenharmony_ci	 * See 5.3.1.  Login Phase Start
5398c2ecf20Sopenharmony_ci	 *
5408c2ecf20Sopenharmony_ci	 * In our case, we have already located the struct iscsi_tiqn at this point.
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci	if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt))
5438c2ecf20Sopenharmony_ci		return -1;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return 0;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ciint iscsi_login_post_auth_non_zero_tsih(
5498c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
5508c2ecf20Sopenharmony_ci	u16 cid,
5518c2ecf20Sopenharmony_ci	u32 exp_statsn)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct iscsi_conn *conn_ptr = NULL;
5548c2ecf20Sopenharmony_ci	struct iscsi_conn_recovery *cr = NULL;
5558c2ecf20Sopenharmony_ci	struct iscsi_session *sess = conn->sess;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/*
5588c2ecf20Sopenharmony_ci	 * By following item 5 in the login table,  if we have found
5598c2ecf20Sopenharmony_ci	 * an existing ISID and a valid/existing TSIH and an existing
5608c2ecf20Sopenharmony_ci	 * CID we do connection reinstatement.  Currently we dont not
5618c2ecf20Sopenharmony_ci	 * support it so we send back an non-zero status class to the
5628c2ecf20Sopenharmony_ci	 * initiator and release the new connection.
5638c2ecf20Sopenharmony_ci	 */
5648c2ecf20Sopenharmony_ci	conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid);
5658c2ecf20Sopenharmony_ci	if (conn_ptr) {
5668c2ecf20Sopenharmony_ci		pr_err("Connection exists with CID %hu for %s,"
5678c2ecf20Sopenharmony_ci			" performing connection reinstatement.\n",
5688c2ecf20Sopenharmony_ci			conn_ptr->cid, sess->sess_ops->InitiatorName);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		iscsit_connection_reinstatement_rcfr(conn_ptr);
5718c2ecf20Sopenharmony_ci		iscsit_dec_conn_usage_count(conn_ptr);
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/*
5758c2ecf20Sopenharmony_ci	 * Check for any connection recovery entries containing CID.
5768c2ecf20Sopenharmony_ci	 * We use the original ExpStatSN sent in the first login request
5778c2ecf20Sopenharmony_ci	 * to acknowledge commands for the failed connection.
5788c2ecf20Sopenharmony_ci	 *
5798c2ecf20Sopenharmony_ci	 * Also note that an explict logout may have already been sent,
5808c2ecf20Sopenharmony_ci	 * but the response may not be sent due to additional connection
5818c2ecf20Sopenharmony_ci	 * loss.
5828c2ecf20Sopenharmony_ci	 */
5838c2ecf20Sopenharmony_ci	if (sess->sess_ops->ErrorRecoveryLevel == 2) {
5848c2ecf20Sopenharmony_ci		cr = iscsit_get_inactive_connection_recovery_entry(
5858c2ecf20Sopenharmony_ci				sess, cid);
5868c2ecf20Sopenharmony_ci		if (cr) {
5878c2ecf20Sopenharmony_ci			pr_debug("Performing implicit logout"
5888c2ecf20Sopenharmony_ci				" for connection recovery on CID: %hu\n",
5898c2ecf20Sopenharmony_ci					conn->cid);
5908c2ecf20Sopenharmony_ci			iscsit_discard_cr_cmds_by_expstatsn(cr, exp_statsn);
5918c2ecf20Sopenharmony_ci		}
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/*
5958c2ecf20Sopenharmony_ci	 * Else we follow item 4 from the login table in that we have
5968c2ecf20Sopenharmony_ci	 * found an existing ISID and a valid/existing TSIH and a new
5978c2ecf20Sopenharmony_ci	 * CID we go ahead and continue to add a new connection to the
5988c2ecf20Sopenharmony_ci	 * session.
5998c2ecf20Sopenharmony_ci	 */
6008c2ecf20Sopenharmony_ci	pr_debug("Adding CID %hu to existing session for %s.\n",
6018c2ecf20Sopenharmony_ci			cid, sess->sess_ops->InitiatorName);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if ((atomic_read(&sess->nconn) + 1) > sess->sess_ops->MaxConnections) {
6048c2ecf20Sopenharmony_ci		pr_err("Adding additional connection to this session"
6058c2ecf20Sopenharmony_ci			" would exceed MaxConnections %d, login failed.\n",
6068c2ecf20Sopenharmony_ci				sess->sess_ops->MaxConnections);
6078c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
6088c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_ISID_ERROR);
6098c2ecf20Sopenharmony_ci		return -1;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return 0;
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic void iscsi_post_login_start_timers(struct iscsi_conn *conn)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct iscsi_session *sess = conn->sess;
6188c2ecf20Sopenharmony_ci	/*
6198c2ecf20Sopenharmony_ci	 * FIXME: Unsolicited NopIN support for ISER
6208c2ecf20Sopenharmony_ci	 */
6218c2ecf20Sopenharmony_ci	if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
6228c2ecf20Sopenharmony_ci		return;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	if (!sess->sess_ops->SessionType)
6258c2ecf20Sopenharmony_ci		iscsit_start_nopin_timer(conn);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ciint iscsit_start_kthreads(struct iscsi_conn *conn)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	int ret = 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	spin_lock(&iscsit_global->ts_bitmap_lock);
6338c2ecf20Sopenharmony_ci	conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
6348c2ecf20Sopenharmony_ci					ISCSIT_BITMAP_BITS, get_order(1));
6358c2ecf20Sopenharmony_ci	spin_unlock(&iscsit_global->ts_bitmap_lock);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (conn->bitmap_id < 0) {
6388c2ecf20Sopenharmony_ci		pr_err("bitmap_find_free_region() failed for"
6398c2ecf20Sopenharmony_ci		       " iscsit_start_kthreads()\n");
6408c2ecf20Sopenharmony_ci		return -ENOMEM;
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn,
6448c2ecf20Sopenharmony_ci				      "%s", ISCSI_TX_THREAD_NAME);
6458c2ecf20Sopenharmony_ci	if (IS_ERR(conn->tx_thread)) {
6468c2ecf20Sopenharmony_ci		pr_err("Unable to start iscsi_target_tx_thread\n");
6478c2ecf20Sopenharmony_ci		ret = PTR_ERR(conn->tx_thread);
6488c2ecf20Sopenharmony_ci		goto out_bitmap;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci	conn->tx_thread_active = true;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn,
6538c2ecf20Sopenharmony_ci				      "%s", ISCSI_RX_THREAD_NAME);
6548c2ecf20Sopenharmony_ci	if (IS_ERR(conn->rx_thread)) {
6558c2ecf20Sopenharmony_ci		pr_err("Unable to start iscsi_target_rx_thread\n");
6568c2ecf20Sopenharmony_ci		ret = PTR_ERR(conn->rx_thread);
6578c2ecf20Sopenharmony_ci		goto out_tx;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci	conn->rx_thread_active = true;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	return 0;
6628c2ecf20Sopenharmony_ciout_tx:
6638c2ecf20Sopenharmony_ci	send_sig(SIGINT, conn->tx_thread, 1);
6648c2ecf20Sopenharmony_ci	kthread_stop(conn->tx_thread);
6658c2ecf20Sopenharmony_ci	conn->tx_thread_active = false;
6668c2ecf20Sopenharmony_ciout_bitmap:
6678c2ecf20Sopenharmony_ci	spin_lock(&iscsit_global->ts_bitmap_lock);
6688c2ecf20Sopenharmony_ci	bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
6698c2ecf20Sopenharmony_ci			      get_order(1));
6708c2ecf20Sopenharmony_ci	spin_unlock(&iscsit_global->ts_bitmap_lock);
6718c2ecf20Sopenharmony_ci	return ret;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_civoid iscsi_post_login_handler(
6758c2ecf20Sopenharmony_ci	struct iscsi_np *np,
6768c2ecf20Sopenharmony_ci	struct iscsi_conn *conn,
6778c2ecf20Sopenharmony_ci	u8 zero_tsih)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	int stop_timer = 0;
6808c2ecf20Sopenharmony_ci	struct iscsi_session *sess = conn->sess;
6818c2ecf20Sopenharmony_ci	struct se_session *se_sess = sess->se_sess;
6828c2ecf20Sopenharmony_ci	struct iscsi_portal_group *tpg = sess->tpg;
6838c2ecf20Sopenharmony_ci	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	iscsit_inc_conn_usage_count(conn);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_SUCCESS,
6888c2ecf20Sopenharmony_ci			ISCSI_LOGIN_STATUS_ACCEPT);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	pr_debug("Moving to TARG_CONN_STATE_LOGGED_IN.\n");
6918c2ecf20Sopenharmony_ci	conn->conn_state = TARG_CONN_STATE_LOGGED_IN;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	iscsi_set_connection_parameters(conn->conn_ops, conn->param_list);
6948c2ecf20Sopenharmony_ci	/*
6958c2ecf20Sopenharmony_ci	 * SCSI Initiator -> SCSI Target Port Mapping
6968c2ecf20Sopenharmony_ci	 */
6978c2ecf20Sopenharmony_ci	if (!zero_tsih) {
6988c2ecf20Sopenharmony_ci		iscsi_set_session_parameters(sess->sess_ops,
6998c2ecf20Sopenharmony_ci				conn->param_list, 0);
7008c2ecf20Sopenharmony_ci		iscsi_release_param_list(conn->param_list);
7018c2ecf20Sopenharmony_ci		conn->param_list = NULL;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		spin_lock_bh(&sess->conn_lock);
7048c2ecf20Sopenharmony_ci		atomic_set(&sess->session_continuation, 0);
7058c2ecf20Sopenharmony_ci		if (sess->session_state == TARG_SESS_STATE_FAILED) {
7068c2ecf20Sopenharmony_ci			pr_debug("Moving to"
7078c2ecf20Sopenharmony_ci					" TARG_SESS_STATE_LOGGED_IN.\n");
7088c2ecf20Sopenharmony_ci			sess->session_state = TARG_SESS_STATE_LOGGED_IN;
7098c2ecf20Sopenharmony_ci			stop_timer = 1;
7108c2ecf20Sopenharmony_ci		}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		pr_debug("iSCSI Login successful on CID: %hu from %pISpc to"
7138c2ecf20Sopenharmony_ci			" %pISpc,%hu\n", conn->cid, &conn->login_sockaddr,
7148c2ecf20Sopenharmony_ci			&conn->local_sockaddr, tpg->tpgt);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		list_add_tail(&conn->conn_list, &sess->sess_conn_list);
7178c2ecf20Sopenharmony_ci		atomic_inc(&sess->nconn);
7188c2ecf20Sopenharmony_ci		pr_debug("Incremented iSCSI Connection count to %hu"
7198c2ecf20Sopenharmony_ci			" from node: %s\n", atomic_read(&sess->nconn),
7208c2ecf20Sopenharmony_ci			sess->sess_ops->InitiatorName);
7218c2ecf20Sopenharmony_ci		spin_unlock_bh(&sess->conn_lock);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		iscsi_post_login_start_timers(conn);
7248c2ecf20Sopenharmony_ci		/*
7258c2ecf20Sopenharmony_ci		 * Determine CPU mask to ensure connection's RX and TX kthreads
7268c2ecf20Sopenharmony_ci		 * are scheduled on the same CPU.
7278c2ecf20Sopenharmony_ci		 */
7288c2ecf20Sopenharmony_ci		iscsit_thread_get_cpumask(conn);
7298c2ecf20Sopenharmony_ci		conn->conn_rx_reset_cpumask = 1;
7308c2ecf20Sopenharmony_ci		conn->conn_tx_reset_cpumask = 1;
7318c2ecf20Sopenharmony_ci		/*
7328c2ecf20Sopenharmony_ci		 * Wakeup the sleeping iscsi_target_rx_thread() now that
7338c2ecf20Sopenharmony_ci		 * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
7348c2ecf20Sopenharmony_ci		 */
7358c2ecf20Sopenharmony_ci		complete(&conn->rx_login_comp);
7368c2ecf20Sopenharmony_ci		iscsit_dec_conn_usage_count(conn);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		if (stop_timer) {
7398c2ecf20Sopenharmony_ci			spin_lock_bh(&se_tpg->session_lock);
7408c2ecf20Sopenharmony_ci			iscsit_stop_time2retain_timer(sess);
7418c2ecf20Sopenharmony_ci			spin_unlock_bh(&se_tpg->session_lock);
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci		iscsit_dec_session_usage_count(sess);
7448c2ecf20Sopenharmony_ci		return;
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
7488c2ecf20Sopenharmony_ci	iscsi_release_param_list(conn->param_list);
7498c2ecf20Sopenharmony_ci	conn->param_list = NULL;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	iscsit_determine_maxcmdsn(sess);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	spin_lock_bh(&se_tpg->session_lock);
7548c2ecf20Sopenharmony_ci	__transport_register_session(&sess->tpg->tpg_se_tpg,
7558c2ecf20Sopenharmony_ci			se_sess->se_node_acl, se_sess, sess);
7568c2ecf20Sopenharmony_ci	pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n");
7578c2ecf20Sopenharmony_ci	sess->session_state = TARG_SESS_STATE_LOGGED_IN;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	pr_debug("iSCSI Login successful on CID: %hu from %pISpc to %pISpc,%hu\n",
7608c2ecf20Sopenharmony_ci		conn->cid, &conn->login_sockaddr, &conn->local_sockaddr,
7618c2ecf20Sopenharmony_ci		tpg->tpgt);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
7648c2ecf20Sopenharmony_ci	list_add_tail(&conn->conn_list, &sess->sess_conn_list);
7658c2ecf20Sopenharmony_ci	atomic_inc(&sess->nconn);
7668c2ecf20Sopenharmony_ci	pr_debug("Incremented iSCSI Connection count to %hu from node:"
7678c2ecf20Sopenharmony_ci		" %s\n", atomic_read(&sess->nconn),
7688c2ecf20Sopenharmony_ci		sess->sess_ops->InitiatorName);
7698c2ecf20Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	sess->sid = tpg->sid++;
7728c2ecf20Sopenharmony_ci	if (!sess->sid)
7738c2ecf20Sopenharmony_ci		sess->sid = tpg->sid++;
7748c2ecf20Sopenharmony_ci	pr_debug("Established iSCSI session from node: %s\n",
7758c2ecf20Sopenharmony_ci			sess->sess_ops->InitiatorName);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	tpg->nsessions++;
7788c2ecf20Sopenharmony_ci	if (tpg->tpg_tiqn)
7798c2ecf20Sopenharmony_ci		tpg->tpg_tiqn->tiqn_nsessions++;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	pr_debug("Incremented number of active iSCSI sessions to %u on"
7828c2ecf20Sopenharmony_ci		" iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
7838c2ecf20Sopenharmony_ci	spin_unlock_bh(&se_tpg->session_lock);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	iscsi_post_login_start_timers(conn);
7868c2ecf20Sopenharmony_ci	/*
7878c2ecf20Sopenharmony_ci	 * Determine CPU mask to ensure connection's RX and TX kthreads
7888c2ecf20Sopenharmony_ci	 * are scheduled on the same CPU.
7898c2ecf20Sopenharmony_ci	 */
7908c2ecf20Sopenharmony_ci	iscsit_thread_get_cpumask(conn);
7918c2ecf20Sopenharmony_ci	conn->conn_rx_reset_cpumask = 1;
7928c2ecf20Sopenharmony_ci	conn->conn_tx_reset_cpumask = 1;
7938c2ecf20Sopenharmony_ci	/*
7948c2ecf20Sopenharmony_ci	 * Wakeup the sleeping iscsi_target_rx_thread() now that
7958c2ecf20Sopenharmony_ci	 * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
7968c2ecf20Sopenharmony_ci	 */
7978c2ecf20Sopenharmony_ci	complete(&conn->rx_login_comp);
7988c2ecf20Sopenharmony_ci	iscsit_dec_conn_usage_count(conn);
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_civoid iscsi_handle_login_thread_timeout(struct timer_list *t)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct iscsi_np *np = from_timer(np, t, np_login_timer);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
8068c2ecf20Sopenharmony_ci	pr_err("iSCSI Login timeout on Network Portal %pISpc\n",
8078c2ecf20Sopenharmony_ci			&np->np_sockaddr);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (np->np_login_timer_flags & ISCSI_TF_STOP) {
8108c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
8118c2ecf20Sopenharmony_ci		return;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (np->np_thread)
8158c2ecf20Sopenharmony_ci		send_sig(SIGINT, np->np_thread, 1);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
8188c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic void iscsi_start_login_thread_timer(struct iscsi_np *np)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	/*
8248c2ecf20Sopenharmony_ci	 * This used the TA_LOGIN_TIMEOUT constant because at this
8258c2ecf20Sopenharmony_ci	 * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout
8268c2ecf20Sopenharmony_ci	 */
8278c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
8288c2ecf20Sopenharmony_ci	np->np_login_timer_flags &= ~ISCSI_TF_STOP;
8298c2ecf20Sopenharmony_ci	np->np_login_timer_flags |= ISCSI_TF_RUNNING;
8308c2ecf20Sopenharmony_ci	mod_timer(&np->np_login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	pr_debug("Added timeout timer to iSCSI login request for"
8338c2ecf20Sopenharmony_ci			" %u seconds.\n", TA_LOGIN_TIMEOUT);
8348c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic void iscsi_stop_login_thread_timer(struct iscsi_np *np)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
8408c2ecf20Sopenharmony_ci	if (!(np->np_login_timer_flags & ISCSI_TF_RUNNING)) {
8418c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
8428c2ecf20Sopenharmony_ci		return;
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci	np->np_login_timer_flags |= ISCSI_TF_STOP;
8458c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	del_timer_sync(&np->np_login_timer);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
8508c2ecf20Sopenharmony_ci	np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
8518c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ciint iscsit_setup_np(
8558c2ecf20Sopenharmony_ci	struct iscsi_np *np,
8568c2ecf20Sopenharmony_ci	struct sockaddr_storage *sockaddr)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	struct socket *sock = NULL;
8598c2ecf20Sopenharmony_ci	int backlog = ISCSIT_TCP_BACKLOG, ret, len;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	switch (np->np_network_transport) {
8628c2ecf20Sopenharmony_ci	case ISCSI_TCP:
8638c2ecf20Sopenharmony_ci		np->np_ip_proto = IPPROTO_TCP;
8648c2ecf20Sopenharmony_ci		np->np_sock_type = SOCK_STREAM;
8658c2ecf20Sopenharmony_ci		break;
8668c2ecf20Sopenharmony_ci	case ISCSI_SCTP_TCP:
8678c2ecf20Sopenharmony_ci		np->np_ip_proto = IPPROTO_SCTP;
8688c2ecf20Sopenharmony_ci		np->np_sock_type = SOCK_STREAM;
8698c2ecf20Sopenharmony_ci		break;
8708c2ecf20Sopenharmony_ci	case ISCSI_SCTP_UDP:
8718c2ecf20Sopenharmony_ci		np->np_ip_proto = IPPROTO_SCTP;
8728c2ecf20Sopenharmony_ci		np->np_sock_type = SOCK_SEQPACKET;
8738c2ecf20Sopenharmony_ci		break;
8748c2ecf20Sopenharmony_ci	default:
8758c2ecf20Sopenharmony_ci		pr_err("Unsupported network_transport: %d\n",
8768c2ecf20Sopenharmony_ci				np->np_network_transport);
8778c2ecf20Sopenharmony_ci		return -EINVAL;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ret = sock_create(sockaddr->ss_family, np->np_sock_type,
8818c2ecf20Sopenharmony_ci			np->np_ip_proto, &sock);
8828c2ecf20Sopenharmony_ci	if (ret < 0) {
8838c2ecf20Sopenharmony_ci		pr_err("sock_create() failed.\n");
8848c2ecf20Sopenharmony_ci		return ret;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci	np->np_socket = sock;
8878c2ecf20Sopenharmony_ci	/*
8888c2ecf20Sopenharmony_ci	 * Setup the np->np_sockaddr from the passed sockaddr setup
8898c2ecf20Sopenharmony_ci	 * in iscsi_target_configfs.c code..
8908c2ecf20Sopenharmony_ci	 */
8918c2ecf20Sopenharmony_ci	memcpy(&np->np_sockaddr, sockaddr,
8928c2ecf20Sopenharmony_ci			sizeof(struct sockaddr_storage));
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	if (sockaddr->ss_family == AF_INET6)
8958c2ecf20Sopenharmony_ci		len = sizeof(struct sockaddr_in6);
8968c2ecf20Sopenharmony_ci	else
8978c2ecf20Sopenharmony_ci		len = sizeof(struct sockaddr_in);
8988c2ecf20Sopenharmony_ci	/*
8998c2ecf20Sopenharmony_ci	 * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY.
9008c2ecf20Sopenharmony_ci	 */
9018c2ecf20Sopenharmony_ci	if (np->np_network_transport == ISCSI_TCP)
9028c2ecf20Sopenharmony_ci		tcp_sock_set_nodelay(sock->sk);
9038c2ecf20Sopenharmony_ci	sock_set_reuseaddr(sock->sk);
9048c2ecf20Sopenharmony_ci	ip_sock_set_freebind(sock->sk);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	ret = kernel_bind(sock, (struct sockaddr *)&np->np_sockaddr, len);
9078c2ecf20Sopenharmony_ci	if (ret < 0) {
9088c2ecf20Sopenharmony_ci		pr_err("kernel_bind() failed: %d\n", ret);
9098c2ecf20Sopenharmony_ci		goto fail;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	ret = kernel_listen(sock, backlog);
9138c2ecf20Sopenharmony_ci	if (ret != 0) {
9148c2ecf20Sopenharmony_ci		pr_err("kernel_listen() failed: %d\n", ret);
9158c2ecf20Sopenharmony_ci		goto fail;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	return 0;
9198c2ecf20Sopenharmony_cifail:
9208c2ecf20Sopenharmony_ci	np->np_socket = NULL;
9218c2ecf20Sopenharmony_ci	sock_release(sock);
9228c2ecf20Sopenharmony_ci	return ret;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ciint iscsi_target_setup_login_socket(
9268c2ecf20Sopenharmony_ci	struct iscsi_np *np,
9278c2ecf20Sopenharmony_ci	struct sockaddr_storage *sockaddr)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct iscsit_transport *t;
9308c2ecf20Sopenharmony_ci	int rc;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	t = iscsit_get_transport(np->np_network_transport);
9338c2ecf20Sopenharmony_ci	if (!t)
9348c2ecf20Sopenharmony_ci		return -EINVAL;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	rc = t->iscsit_setup_np(np, sockaddr);
9378c2ecf20Sopenharmony_ci	if (rc < 0) {
9388c2ecf20Sopenharmony_ci		iscsit_put_transport(t);
9398c2ecf20Sopenharmony_ci		return rc;
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	np->np_transport = t;
9438c2ecf20Sopenharmony_ci	np->enabled = true;
9448c2ecf20Sopenharmony_ci	return 0;
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ciint iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	struct socket *new_sock, *sock = np->np_socket;
9508c2ecf20Sopenharmony_ci	struct sockaddr_in sock_in;
9518c2ecf20Sopenharmony_ci	struct sockaddr_in6 sock_in6;
9528c2ecf20Sopenharmony_ci	int rc;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	rc = kernel_accept(sock, &new_sock, 0);
9558c2ecf20Sopenharmony_ci	if (rc < 0)
9568c2ecf20Sopenharmony_ci		return rc;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	conn->sock = new_sock;
9598c2ecf20Sopenharmony_ci	conn->login_family = np->np_sockaddr.ss_family;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (np->np_sockaddr.ss_family == AF_INET6) {
9628c2ecf20Sopenharmony_ci		memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		rc = conn->sock->ops->getname(conn->sock,
9658c2ecf20Sopenharmony_ci				(struct sockaddr *)&sock_in6, 1);
9668c2ecf20Sopenharmony_ci		if (rc >= 0) {
9678c2ecf20Sopenharmony_ci			if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
9688c2ecf20Sopenharmony_ci				memcpy(&conn->login_sockaddr, &sock_in6, sizeof(sock_in6));
9698c2ecf20Sopenharmony_ci			} else {
9708c2ecf20Sopenharmony_ci				/* Pretend to be an ipv4 socket */
9718c2ecf20Sopenharmony_ci				sock_in.sin_family = AF_INET;
9728c2ecf20Sopenharmony_ci				sock_in.sin_port = sock_in6.sin6_port;
9738c2ecf20Sopenharmony_ci				memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4);
9748c2ecf20Sopenharmony_ci				memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in));
9758c2ecf20Sopenharmony_ci			}
9768c2ecf20Sopenharmony_ci		}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		rc = conn->sock->ops->getname(conn->sock,
9798c2ecf20Sopenharmony_ci				(struct sockaddr *)&sock_in6, 0);
9808c2ecf20Sopenharmony_ci		if (rc >= 0) {
9818c2ecf20Sopenharmony_ci			if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
9828c2ecf20Sopenharmony_ci				memcpy(&conn->local_sockaddr, &sock_in6, sizeof(sock_in6));
9838c2ecf20Sopenharmony_ci			} else {
9848c2ecf20Sopenharmony_ci				/* Pretend to be an ipv4 socket */
9858c2ecf20Sopenharmony_ci				sock_in.sin_family = AF_INET;
9868c2ecf20Sopenharmony_ci				sock_in.sin_port = sock_in6.sin6_port;
9878c2ecf20Sopenharmony_ci				memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4);
9888c2ecf20Sopenharmony_ci				memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in));
9898c2ecf20Sopenharmony_ci			}
9908c2ecf20Sopenharmony_ci		}
9918c2ecf20Sopenharmony_ci	} else {
9928c2ecf20Sopenharmony_ci		memset(&sock_in, 0, sizeof(struct sockaddr_in));
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		rc = conn->sock->ops->getname(conn->sock,
9958c2ecf20Sopenharmony_ci				(struct sockaddr *)&sock_in, 1);
9968c2ecf20Sopenharmony_ci		if (rc >= 0)
9978c2ecf20Sopenharmony_ci			memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in));
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		rc = conn->sock->ops->getname(conn->sock,
10008c2ecf20Sopenharmony_ci				(struct sockaddr *)&sock_in, 0);
10018c2ecf20Sopenharmony_ci		if (rc >= 0)
10028c2ecf20Sopenharmony_ci			memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in));
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	return 0;
10068c2ecf20Sopenharmony_ci}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ciint iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	struct iscsi_login_req *login_req;
10118c2ecf20Sopenharmony_ci	u32 padding = 0, payload_length;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
10148c2ecf20Sopenharmony_ci		return -1;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	login_req = (struct iscsi_login_req *)login->req;
10178c2ecf20Sopenharmony_ci	payload_length	= ntoh24(login_req->dlength);
10188c2ecf20Sopenharmony_ci	padding = ((-payload_length) & 3);
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
10218c2ecf20Sopenharmony_ci		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
10228c2ecf20Sopenharmony_ci		login_req->flags, login_req->itt, login_req->cmdsn,
10238c2ecf20Sopenharmony_ci		login_req->exp_statsn, login_req->cid, payload_length);
10248c2ecf20Sopenharmony_ci	/*
10258c2ecf20Sopenharmony_ci	 * Setup the initial iscsi_login values from the leading
10268c2ecf20Sopenharmony_ci	 * login request PDU.
10278c2ecf20Sopenharmony_ci	 */
10288c2ecf20Sopenharmony_ci	if (login->first_request) {
10298c2ecf20Sopenharmony_ci		login_req = (struct iscsi_login_req *)login->req;
10308c2ecf20Sopenharmony_ci		login->leading_connection = (!login_req->tsih) ? 1 : 0;
10318c2ecf20Sopenharmony_ci		login->current_stage	= ISCSI_LOGIN_CURRENT_STAGE(login_req->flags);
10328c2ecf20Sopenharmony_ci		login->version_min	= login_req->min_version;
10338c2ecf20Sopenharmony_ci		login->version_max	= login_req->max_version;
10348c2ecf20Sopenharmony_ci		memcpy(login->isid, login_req->isid, 6);
10358c2ecf20Sopenharmony_ci		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
10368c2ecf20Sopenharmony_ci		login->init_task_tag	= login_req->itt;
10378c2ecf20Sopenharmony_ci		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
10388c2ecf20Sopenharmony_ci		login->cid		= be16_to_cpu(login_req->cid);
10398c2ecf20Sopenharmony_ci		login->tsih		= be16_to_cpu(login_req->tsih);
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	if (iscsi_target_check_login_request(conn, login) < 0)
10438c2ecf20Sopenharmony_ci		return -1;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
10468c2ecf20Sopenharmony_ci	if (iscsi_login_rx_data(conn, login->req_buf,
10478c2ecf20Sopenharmony_ci				payload_length + padding) < 0)
10488c2ecf20Sopenharmony_ci		return -1;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	return 0;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ciint iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
10548c2ecf20Sopenharmony_ci			u32 length)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
10578c2ecf20Sopenharmony_ci		return -1;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic int
10638c2ecf20Sopenharmony_ciiscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	int rc;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (!t->owner) {
10688c2ecf20Sopenharmony_ci		conn->conn_transport = t;
10698c2ecf20Sopenharmony_ci		return 0;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	rc = try_module_get(t->owner);
10738c2ecf20Sopenharmony_ci	if (!rc) {
10748c2ecf20Sopenharmony_ci		pr_err("try_module_get() failed for %s\n", t->name);
10758c2ecf20Sopenharmony_ci		return -EINVAL;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	conn->conn_transport = t;
10798c2ecf20Sopenharmony_ci	return 0;
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic struct iscsi_conn *iscsit_alloc_conn(struct iscsi_np *np)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
10878c2ecf20Sopenharmony_ci	if (!conn) {
10888c2ecf20Sopenharmony_ci		pr_err("Could not allocate memory for new connection\n");
10898c2ecf20Sopenharmony_ci		return NULL;
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci	pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
10928c2ecf20Sopenharmony_ci	conn->conn_state = TARG_CONN_STATE_FREE;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	init_waitqueue_head(&conn->queues_wq);
10958c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->conn_list);
10968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->conn_cmd_list);
10978c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->immed_queue_list);
10988c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->response_queue_list);
10998c2ecf20Sopenharmony_ci	init_completion(&conn->conn_post_wait_comp);
11008c2ecf20Sopenharmony_ci	init_completion(&conn->conn_wait_comp);
11018c2ecf20Sopenharmony_ci	init_completion(&conn->conn_wait_rcfr_comp);
11028c2ecf20Sopenharmony_ci	init_completion(&conn->conn_waiting_on_uc_comp);
11038c2ecf20Sopenharmony_ci	init_completion(&conn->conn_logout_comp);
11048c2ecf20Sopenharmony_ci	init_completion(&conn->rx_half_close_comp);
11058c2ecf20Sopenharmony_ci	init_completion(&conn->tx_half_close_comp);
11068c2ecf20Sopenharmony_ci	init_completion(&conn->rx_login_comp);
11078c2ecf20Sopenharmony_ci	spin_lock_init(&conn->cmd_lock);
11088c2ecf20Sopenharmony_ci	spin_lock_init(&conn->conn_usage_lock);
11098c2ecf20Sopenharmony_ci	spin_lock_init(&conn->immed_queue_lock);
11108c2ecf20Sopenharmony_ci	spin_lock_init(&conn->nopin_timer_lock);
11118c2ecf20Sopenharmony_ci	spin_lock_init(&conn->response_queue_lock);
11128c2ecf20Sopenharmony_ci	spin_lock_init(&conn->state_lock);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	timer_setup(&conn->nopin_response_timer,
11158c2ecf20Sopenharmony_ci		    iscsit_handle_nopin_response_timeout, 0);
11168c2ecf20Sopenharmony_ci	timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (iscsit_conn_set_transport(conn, np->np_transport) < 0)
11198c2ecf20Sopenharmony_ci		goto free_conn;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
11228c2ecf20Sopenharmony_ci	if (!conn->conn_ops) {
11238c2ecf20Sopenharmony_ci		pr_err("Unable to allocate memory for struct iscsi_conn_ops.\n");
11248c2ecf20Sopenharmony_ci		goto put_transport;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
11288c2ecf20Sopenharmony_ci		pr_err("Unable to allocate conn->conn_cpumask\n");
11298c2ecf20Sopenharmony_ci		goto free_conn_ops;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	return conn;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cifree_conn_ops:
11358c2ecf20Sopenharmony_ci	kfree(conn->conn_ops);
11368c2ecf20Sopenharmony_ciput_transport:
11378c2ecf20Sopenharmony_ci	iscsit_put_transport(conn->conn_transport);
11388c2ecf20Sopenharmony_cifree_conn:
11398c2ecf20Sopenharmony_ci	kfree(conn);
11408c2ecf20Sopenharmony_ci	return NULL;
11418c2ecf20Sopenharmony_ci}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_civoid iscsit_free_conn(struct iscsi_conn *conn)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	free_cpumask_var(conn->conn_cpumask);
11468c2ecf20Sopenharmony_ci	kfree(conn->conn_ops);
11478c2ecf20Sopenharmony_ci	iscsit_put_transport(conn->conn_transport);
11488c2ecf20Sopenharmony_ci	kfree(conn);
11498c2ecf20Sopenharmony_ci}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_civoid iscsi_target_login_sess_out(struct iscsi_conn *conn,
11528c2ecf20Sopenharmony_ci				 bool zero_tsih, bool new_sess)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	if (!new_sess)
11558c2ecf20Sopenharmony_ci		goto old_sess_out;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	pr_err("iSCSI Login negotiation failed.\n");
11588c2ecf20Sopenharmony_ci	iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
11598c2ecf20Sopenharmony_ci				   ISCSI_LOGIN_STATUS_INIT_ERR);
11608c2ecf20Sopenharmony_ci	if (!zero_tsih || !conn->sess)
11618c2ecf20Sopenharmony_ci		goto old_sess_out;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	transport_free_session(conn->sess->se_sess);
11648c2ecf20Sopenharmony_ci	ida_free(&sess_ida, conn->sess->session_index);
11658c2ecf20Sopenharmony_ci	kfree(conn->sess->sess_ops);
11668c2ecf20Sopenharmony_ci	kfree(conn->sess);
11678c2ecf20Sopenharmony_ci	conn->sess = NULL;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ciold_sess_out:
11708c2ecf20Sopenharmony_ci	/*
11718c2ecf20Sopenharmony_ci	 * If login negotiation fails check if the Time2Retain timer
11728c2ecf20Sopenharmony_ci	 * needs to be restarted.
11738c2ecf20Sopenharmony_ci	 */
11748c2ecf20Sopenharmony_ci	if (!zero_tsih && conn->sess) {
11758c2ecf20Sopenharmony_ci		spin_lock_bh(&conn->sess->conn_lock);
11768c2ecf20Sopenharmony_ci		if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
11778c2ecf20Sopenharmony_ci			struct se_portal_group *se_tpg =
11788c2ecf20Sopenharmony_ci					&conn->tpg->tpg_se_tpg;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci			atomic_set(&conn->sess->session_continuation, 0);
11818c2ecf20Sopenharmony_ci			spin_unlock_bh(&conn->sess->conn_lock);
11828c2ecf20Sopenharmony_ci			spin_lock_bh(&se_tpg->session_lock);
11838c2ecf20Sopenharmony_ci			iscsit_start_time2retain_handler(conn->sess);
11848c2ecf20Sopenharmony_ci			spin_unlock_bh(&se_tpg->session_lock);
11858c2ecf20Sopenharmony_ci		} else
11868c2ecf20Sopenharmony_ci			spin_unlock_bh(&conn->sess->conn_lock);
11878c2ecf20Sopenharmony_ci		iscsit_dec_session_usage_count(conn->sess);
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	ahash_request_free(conn->conn_tx_hash);
11918c2ecf20Sopenharmony_ci	if (conn->conn_rx_hash) {
11928c2ecf20Sopenharmony_ci		struct crypto_ahash *tfm;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci		tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
11958c2ecf20Sopenharmony_ci		ahash_request_free(conn->conn_rx_hash);
11968c2ecf20Sopenharmony_ci		crypto_free_ahash(tfm);
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	if (conn->param_list) {
12008c2ecf20Sopenharmony_ci		iscsi_release_param_list(conn->param_list);
12018c2ecf20Sopenharmony_ci		conn->param_list = NULL;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci	iscsi_target_nego_release(conn);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (conn->sock) {
12068c2ecf20Sopenharmony_ci		sock_release(conn->sock);
12078c2ecf20Sopenharmony_ci		conn->sock = NULL;
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if (conn->conn_transport->iscsit_wait_conn)
12118c2ecf20Sopenharmony_ci		conn->conn_transport->iscsit_wait_conn(conn);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (conn->conn_transport->iscsit_free_conn)
12148c2ecf20Sopenharmony_ci		conn->conn_transport->iscsit_free_conn(conn);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	iscsit_free_conn(conn);
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_cistatic int __iscsi_target_login_thread(struct iscsi_np *np)
12208c2ecf20Sopenharmony_ci{
12218c2ecf20Sopenharmony_ci	u8 *buffer, zero_tsih = 0;
12228c2ecf20Sopenharmony_ci	int ret = 0, rc;
12238c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = NULL;
12248c2ecf20Sopenharmony_ci	struct iscsi_login *login;
12258c2ecf20Sopenharmony_ci	struct iscsi_portal_group *tpg = NULL;
12268c2ecf20Sopenharmony_ci	struct iscsi_login_req *pdu;
12278c2ecf20Sopenharmony_ci	struct iscsi_tpg_np *tpg_np;
12288c2ecf20Sopenharmony_ci	bool new_sess = false;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	flush_signals(current);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
12338c2ecf20Sopenharmony_ci	if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
12348c2ecf20Sopenharmony_ci		np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
12358c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
12368c2ecf20Sopenharmony_ci		complete(&np->np_restart_comp);
12378c2ecf20Sopenharmony_ci		return 1;
12388c2ecf20Sopenharmony_ci	} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
12398c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
12408c2ecf20Sopenharmony_ci		goto exit;
12418c2ecf20Sopenharmony_ci	} else {
12428c2ecf20Sopenharmony_ci		np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	conn = iscsit_alloc_conn(np);
12478c2ecf20Sopenharmony_ci	if (!conn) {
12488c2ecf20Sopenharmony_ci		/* Get another socket */
12498c2ecf20Sopenharmony_ci		return 1;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	rc = np->np_transport->iscsit_accept_np(np, conn);
12538c2ecf20Sopenharmony_ci	if (rc == -ENOSYS) {
12548c2ecf20Sopenharmony_ci		complete(&np->np_restart_comp);
12558c2ecf20Sopenharmony_ci		iscsit_free_conn(conn);
12568c2ecf20Sopenharmony_ci		goto exit;
12578c2ecf20Sopenharmony_ci	} else if (rc < 0) {
12588c2ecf20Sopenharmony_ci		spin_lock_bh(&np->np_thread_lock);
12598c2ecf20Sopenharmony_ci		if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
12608c2ecf20Sopenharmony_ci			np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
12618c2ecf20Sopenharmony_ci			spin_unlock_bh(&np->np_thread_lock);
12628c2ecf20Sopenharmony_ci			complete(&np->np_restart_comp);
12638c2ecf20Sopenharmony_ci			iscsit_free_conn(conn);
12648c2ecf20Sopenharmony_ci			/* Get another socket */
12658c2ecf20Sopenharmony_ci			return 1;
12668c2ecf20Sopenharmony_ci		}
12678c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
12688c2ecf20Sopenharmony_ci		iscsit_free_conn(conn);
12698c2ecf20Sopenharmony_ci		return 1;
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci	/*
12728c2ecf20Sopenharmony_ci	 * Perform the remaining iSCSI connection initialization items..
12738c2ecf20Sopenharmony_ci	 */
12748c2ecf20Sopenharmony_ci	login = iscsi_login_init_conn(conn);
12758c2ecf20Sopenharmony_ci	if (!login) {
12768c2ecf20Sopenharmony_ci		goto new_sess_out;
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	iscsi_start_login_thread_timer(np);
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
12828c2ecf20Sopenharmony_ci	conn->conn_state = TARG_CONN_STATE_XPT_UP;
12838c2ecf20Sopenharmony_ci	/*
12848c2ecf20Sopenharmony_ci	 * This will process the first login request + payload..
12858c2ecf20Sopenharmony_ci	 */
12868c2ecf20Sopenharmony_ci	rc = np->np_transport->iscsit_get_login_rx(conn, login);
12878c2ecf20Sopenharmony_ci	if (rc == 1)
12888c2ecf20Sopenharmony_ci		return 1;
12898c2ecf20Sopenharmony_ci	else if (rc < 0)
12908c2ecf20Sopenharmony_ci		goto new_sess_out;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	buffer = &login->req[0];
12938c2ecf20Sopenharmony_ci	pdu = (struct iscsi_login_req *)buffer;
12948c2ecf20Sopenharmony_ci	/*
12958c2ecf20Sopenharmony_ci	 * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
12968c2ecf20Sopenharmony_ci	 * when Status-Class != 0.
12978c2ecf20Sopenharmony_ci	*/
12988c2ecf20Sopenharmony_ci	conn->login_itt	= pdu->itt;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
13018c2ecf20Sopenharmony_ci	if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
13028c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
13038c2ecf20Sopenharmony_ci		pr_err("iSCSI Network Portal on %pISpc currently not"
13048c2ecf20Sopenharmony_ci			" active.\n", &np->np_sockaddr);
13058c2ecf20Sopenharmony_ci		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
13068c2ecf20Sopenharmony_ci				ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
13078c2ecf20Sopenharmony_ci		goto new_sess_out;
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	conn->network_transport = np->np_network_transport;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	pr_debug("Received iSCSI login request from %pISpc on %s Network"
13148c2ecf20Sopenharmony_ci		" Portal %pISpc\n", &conn->login_sockaddr, np->np_transport->name,
13158c2ecf20Sopenharmony_ci		&conn->local_sockaddr);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
13188c2ecf20Sopenharmony_ci	conn->conn_state	= TARG_CONN_STATE_IN_LOGIN;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	if (iscsi_login_check_initiator_version(conn, pdu->max_version,
13218c2ecf20Sopenharmony_ci			pdu->min_version) < 0)
13228c2ecf20Sopenharmony_ci		goto new_sess_out;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	zero_tsih = (pdu->tsih == 0x0000);
13258c2ecf20Sopenharmony_ci	if (zero_tsih) {
13268c2ecf20Sopenharmony_ci		/*
13278c2ecf20Sopenharmony_ci		 * This is the leading connection of a new session.
13288c2ecf20Sopenharmony_ci		 * We wait until after authentication to check for
13298c2ecf20Sopenharmony_ci		 * session reinstatement.
13308c2ecf20Sopenharmony_ci		 */
13318c2ecf20Sopenharmony_ci		if (iscsi_login_zero_tsih_s1(conn, buffer) < 0)
13328c2ecf20Sopenharmony_ci			goto new_sess_out;
13338c2ecf20Sopenharmony_ci	} else {
13348c2ecf20Sopenharmony_ci		/*
13358c2ecf20Sopenharmony_ci		 * Add a new connection to an existing session.
13368c2ecf20Sopenharmony_ci		 * We check for a non-existant session in
13378c2ecf20Sopenharmony_ci		 * iscsi_login_non_zero_tsih_s2() below based
13388c2ecf20Sopenharmony_ci		 * on ISID/TSIH, but wait until after authentication
13398c2ecf20Sopenharmony_ci		 * to check for connection reinstatement, etc.
13408c2ecf20Sopenharmony_ci		 */
13418c2ecf20Sopenharmony_ci		if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
13428c2ecf20Sopenharmony_ci			goto new_sess_out;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci	/*
13458c2ecf20Sopenharmony_ci	 * SessionType: Discovery
13468c2ecf20Sopenharmony_ci	 *
13478c2ecf20Sopenharmony_ci	 * 	Locates Default Portal
13488c2ecf20Sopenharmony_ci	 *
13498c2ecf20Sopenharmony_ci	 * SessionType: Normal
13508c2ecf20Sopenharmony_ci	 *
13518c2ecf20Sopenharmony_ci	 * 	Locates Target Portal from NP -> Target IQN
13528c2ecf20Sopenharmony_ci	 */
13538c2ecf20Sopenharmony_ci	rc = iscsi_target_locate_portal(np, conn, login);
13548c2ecf20Sopenharmony_ci	if (rc < 0) {
13558c2ecf20Sopenharmony_ci		tpg = conn->tpg;
13568c2ecf20Sopenharmony_ci		goto new_sess_out;
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci	login->zero_tsih = zero_tsih;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	if (conn->sess)
13618c2ecf20Sopenharmony_ci		conn->sess->se_sess->sup_prot_ops =
13628c2ecf20Sopenharmony_ci			conn->conn_transport->iscsit_get_sup_prot_ops(conn);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	tpg = conn->tpg;
13658c2ecf20Sopenharmony_ci	if (!tpg) {
13668c2ecf20Sopenharmony_ci		pr_err("Unable to locate struct iscsi_conn->tpg\n");
13678c2ecf20Sopenharmony_ci		goto new_sess_out;
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	if (zero_tsih) {
13718c2ecf20Sopenharmony_ci		if (iscsi_login_zero_tsih_s2(conn) < 0)
13728c2ecf20Sopenharmony_ci			goto new_sess_out;
13738c2ecf20Sopenharmony_ci	} else {
13748c2ecf20Sopenharmony_ci		if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
13758c2ecf20Sopenharmony_ci			goto old_sess_out;
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (conn->conn_transport->iscsit_validate_params) {
13798c2ecf20Sopenharmony_ci		ret = conn->conn_transport->iscsit_validate_params(conn);
13808c2ecf20Sopenharmony_ci		if (ret < 0) {
13818c2ecf20Sopenharmony_ci			if (zero_tsih)
13828c2ecf20Sopenharmony_ci				goto new_sess_out;
13838c2ecf20Sopenharmony_ci			else
13848c2ecf20Sopenharmony_ci				goto old_sess_out;
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	ret = iscsi_target_start_negotiation(login, conn);
13898c2ecf20Sopenharmony_ci	if (ret < 0)
13908c2ecf20Sopenharmony_ci		goto new_sess_out;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	iscsi_stop_login_thread_timer(np);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (ret == 1) {
13958c2ecf20Sopenharmony_ci		tpg_np = conn->tpg_np;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		iscsi_post_login_handler(np, conn, zero_tsih);
13988c2ecf20Sopenharmony_ci		iscsit_deaccess_np(np, tpg, tpg_np);
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	tpg = NULL;
14028c2ecf20Sopenharmony_ci	tpg_np = NULL;
14038c2ecf20Sopenharmony_ci	/* Get another socket */
14048c2ecf20Sopenharmony_ci	return 1;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_cinew_sess_out:
14078c2ecf20Sopenharmony_ci	new_sess = true;
14088c2ecf20Sopenharmony_ciold_sess_out:
14098c2ecf20Sopenharmony_ci	iscsi_stop_login_thread_timer(np);
14108c2ecf20Sopenharmony_ci	tpg_np = conn->tpg_np;
14118c2ecf20Sopenharmony_ci	iscsi_target_login_sess_out(conn, zero_tsih, new_sess);
14128c2ecf20Sopenharmony_ci	new_sess = false;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	if (tpg) {
14158c2ecf20Sopenharmony_ci		iscsit_deaccess_np(np, tpg, tpg_np);
14168c2ecf20Sopenharmony_ci		tpg = NULL;
14178c2ecf20Sopenharmony_ci		tpg_np = NULL;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	return 1;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ciexit:
14238c2ecf20Sopenharmony_ci	iscsi_stop_login_thread_timer(np);
14248c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
14258c2ecf20Sopenharmony_ci	np->np_thread_state = ISCSI_NP_THREAD_EXIT;
14268c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	return 0;
14298c2ecf20Sopenharmony_ci}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ciint iscsi_target_login_thread(void *arg)
14328c2ecf20Sopenharmony_ci{
14338c2ecf20Sopenharmony_ci	struct iscsi_np *np = arg;
14348c2ecf20Sopenharmony_ci	int ret;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	allow_signal(SIGINT);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	while (1) {
14398c2ecf20Sopenharmony_ci		ret = __iscsi_target_login_thread(np);
14408c2ecf20Sopenharmony_ci		/*
14418c2ecf20Sopenharmony_ci		 * We break and exit here unless another sock_accept() call
14428c2ecf20Sopenharmony_ci		 * is expected.
14438c2ecf20Sopenharmony_ci		 */
14448c2ecf20Sopenharmony_ci		if (ret != 1)
14458c2ecf20Sopenharmony_ci			break;
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
14498c2ecf20Sopenharmony_ci		msleep(100);
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	return 0;
14538c2ecf20Sopenharmony_ci}
1454