162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci * This file contains the iSCSI Target specific utility functions.
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 <linux/list.h>
1262306a36Sopenharmony_ci#include <linux/sched/signal.h>
1362306a36Sopenharmony_ci#include <net/ipv6.h>         /* ipv6_addr_equal() */
1462306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1562306a36Sopenharmony_ci#include <scsi/iscsi_proto.h>
1662306a36Sopenharmony_ci#include <target/target_core_base.h>
1762306a36Sopenharmony_ci#include <target/target_core_fabric.h>
1862306a36Sopenharmony_ci#include <target/iscsi/iscsi_transport.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h>
2162306a36Sopenharmony_ci#include "iscsi_target_parameters.h"
2262306a36Sopenharmony_ci#include "iscsi_target_seq_pdu_list.h"
2362306a36Sopenharmony_ci#include "iscsi_target_datain_values.h"
2462306a36Sopenharmony_ci#include "iscsi_target_erl0.h"
2562306a36Sopenharmony_ci#include "iscsi_target_erl1.h"
2662306a36Sopenharmony_ci#include "iscsi_target_erl2.h"
2762306a36Sopenharmony_ci#include "iscsi_target_tpg.h"
2862306a36Sopenharmony_ci#include "iscsi_target_util.h"
2962306a36Sopenharmony_ci#include "iscsi_target.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciextern struct list_head g_tiqn_list;
3262306a36Sopenharmony_ciextern spinlock_t tiqn_lock;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciint iscsit_add_r2t_to_list(
3562306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
3662306a36Sopenharmony_ci	u32 offset,
3762306a36Sopenharmony_ci	u32 xfer_len,
3862306a36Sopenharmony_ci	int recovery,
3962306a36Sopenharmony_ci	u32 r2t_sn)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct iscsi_r2t *r2t;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	lockdep_assert_held(&cmd->r2t_lock);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	WARN_ON_ONCE((s32)xfer_len < 0);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC);
4862306a36Sopenharmony_ci	if (!r2t) {
4962306a36Sopenharmony_ci		pr_err("Unable to allocate memory for struct iscsi_r2t.\n");
5062306a36Sopenharmony_ci		return -1;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	INIT_LIST_HEAD(&r2t->r2t_list);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	r2t->recovery_r2t = recovery;
5562306a36Sopenharmony_ci	r2t->r2t_sn = (!r2t_sn) ? cmd->r2t_sn++ : r2t_sn;
5662306a36Sopenharmony_ci	r2t->offset = offset;
5762306a36Sopenharmony_ci	r2t->xfer_len = xfer_len;
5862306a36Sopenharmony_ci	list_add_tail(&r2t->r2t_list, &cmd->cmd_r2t_list);
5962306a36Sopenharmony_ci	spin_unlock_bh(&cmd->r2t_lock);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	spin_lock_bh(&cmd->r2t_lock);
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct iscsi_r2t *iscsit_get_r2t_for_eos(
6862306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
6962306a36Sopenharmony_ci	u32 offset,
7062306a36Sopenharmony_ci	u32 length)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct iscsi_r2t *r2t;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	spin_lock_bh(&cmd->r2t_lock);
7562306a36Sopenharmony_ci	list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
7662306a36Sopenharmony_ci		if ((r2t->offset <= offset) &&
7762306a36Sopenharmony_ci		    (r2t->offset + r2t->xfer_len) >= (offset + length)) {
7862306a36Sopenharmony_ci			spin_unlock_bh(&cmd->r2t_lock);
7962306a36Sopenharmony_ci			return r2t;
8062306a36Sopenharmony_ci		}
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci	spin_unlock_bh(&cmd->r2t_lock);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	pr_err("Unable to locate R2T for Offset: %u, Length:"
8562306a36Sopenharmony_ci			" %u\n", offset, length);
8662306a36Sopenharmony_ci	return NULL;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistruct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsit_cmd *cmd)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct iscsi_r2t *r2t;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	spin_lock_bh(&cmd->r2t_lock);
9462306a36Sopenharmony_ci	list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
9562306a36Sopenharmony_ci		if (!r2t->sent_r2t) {
9662306a36Sopenharmony_ci			spin_unlock_bh(&cmd->r2t_lock);
9762306a36Sopenharmony_ci			return r2t;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	spin_unlock_bh(&cmd->r2t_lock);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	pr_err("Unable to locate next R2T to send for ITT:"
10362306a36Sopenharmony_ci			" 0x%08x.\n", cmd->init_task_tag);
10462306a36Sopenharmony_ci	return NULL;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_civoid iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsit_cmd *cmd)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	lockdep_assert_held(&cmd->r2t_lock);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	list_del(&r2t->r2t_list);
11262306a36Sopenharmony_ci	kmem_cache_free(lio_r2t_cache, r2t);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civoid iscsit_free_r2ts_from_list(struct iscsit_cmd *cmd)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct iscsi_r2t *r2t, *r2t_tmp;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	spin_lock_bh(&cmd->r2t_lock);
12062306a36Sopenharmony_ci	list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list)
12162306a36Sopenharmony_ci		iscsit_free_r2t(r2t, cmd);
12262306a36Sopenharmony_ci	spin_unlock_bh(&cmd->r2t_lock);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int iscsit_wait_for_tag(struct se_session *se_sess, int state, int *cpup)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int tag = -1;
12862306a36Sopenharmony_ci	DEFINE_SBQ_WAIT(wait);
12962306a36Sopenharmony_ci	struct sbq_wait_state *ws;
13062306a36Sopenharmony_ci	struct sbitmap_queue *sbq;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (state == TASK_RUNNING)
13362306a36Sopenharmony_ci		return tag;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	sbq = &se_sess->sess_tag_pool;
13662306a36Sopenharmony_ci	ws = &sbq->ws[0];
13762306a36Sopenharmony_ci	for (;;) {
13862306a36Sopenharmony_ci		sbitmap_prepare_to_wait(sbq, ws, &wait, state);
13962306a36Sopenharmony_ci		if (signal_pending_state(state, current))
14062306a36Sopenharmony_ci			break;
14162306a36Sopenharmony_ci		tag = sbitmap_queue_get(sbq, cpup);
14262306a36Sopenharmony_ci		if (tag >= 0)
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci		schedule();
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	sbitmap_finish_wait(sbq, ws, &wait);
14862306a36Sopenharmony_ci	return tag;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/*
15262306a36Sopenharmony_ci * May be called from software interrupt (timer) context for allocating
15362306a36Sopenharmony_ci * iSCSI NopINs.
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistruct iscsit_cmd *iscsit_allocate_cmd(struct iscsit_conn *conn, int state)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct iscsit_cmd *cmd;
15862306a36Sopenharmony_ci	struct se_session *se_sess = conn->sess->se_sess;
15962306a36Sopenharmony_ci	int size, tag, cpu;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
16262306a36Sopenharmony_ci	if (tag < 0)
16362306a36Sopenharmony_ci		tag = iscsit_wait_for_tag(se_sess, state, &cpu);
16462306a36Sopenharmony_ci	if (tag < 0)
16562306a36Sopenharmony_ci		return NULL;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	size = sizeof(struct iscsit_cmd) + conn->conn_transport->priv_size;
16862306a36Sopenharmony_ci	cmd = (struct iscsit_cmd *)(se_sess->sess_cmd_map + (tag * size));
16962306a36Sopenharmony_ci	memset(cmd, 0, size);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	cmd->se_cmd.map_tag = tag;
17262306a36Sopenharmony_ci	cmd->se_cmd.map_cpu = cpu;
17362306a36Sopenharmony_ci	cmd->conn = conn;
17462306a36Sopenharmony_ci	cmd->data_direction = DMA_NONE;
17562306a36Sopenharmony_ci	INIT_LIST_HEAD(&cmd->i_conn_node);
17662306a36Sopenharmony_ci	INIT_LIST_HEAD(&cmd->datain_list);
17762306a36Sopenharmony_ci	INIT_LIST_HEAD(&cmd->cmd_r2t_list);
17862306a36Sopenharmony_ci	spin_lock_init(&cmd->datain_lock);
17962306a36Sopenharmony_ci	spin_lock_init(&cmd->dataout_timeout_lock);
18062306a36Sopenharmony_ci	spin_lock_init(&cmd->istate_lock);
18162306a36Sopenharmony_ci	spin_lock_init(&cmd->error_lock);
18262306a36Sopenharmony_ci	spin_lock_init(&cmd->r2t_lock);
18362306a36Sopenharmony_ci	timer_setup(&cmd->dataout_timer, iscsit_handle_dataout_timeout, 0);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return cmd;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_allocate_cmd);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistruct iscsi_seq *iscsit_get_seq_holder_for_datain(
19062306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
19162306a36Sopenharmony_ci	u32 seq_send_order)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	u32 i;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	for (i = 0; i < cmd->seq_count; i++)
19662306a36Sopenharmony_ci		if (cmd->seq_list[i].seq_send_order == seq_send_order)
19762306a36Sopenharmony_ci			return &cmd->seq_list[i];
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return NULL;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistruct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsit_cmd *cmd)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	u32 i;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (!cmd->seq_list) {
20762306a36Sopenharmony_ci		pr_err("struct iscsit_cmd->seq_list is NULL!\n");
20862306a36Sopenharmony_ci		return NULL;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < cmd->seq_count; i++) {
21262306a36Sopenharmony_ci		if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
21362306a36Sopenharmony_ci			continue;
21462306a36Sopenharmony_ci		if (cmd->seq_list[i].seq_send_order == cmd->seq_send_order) {
21562306a36Sopenharmony_ci			cmd->seq_send_order++;
21662306a36Sopenharmony_ci			return &cmd->seq_list[i];
21762306a36Sopenharmony_ci		}
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return NULL;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistruct iscsi_r2t *iscsit_get_holder_for_r2tsn(
22462306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
22562306a36Sopenharmony_ci	u32 r2t_sn)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct iscsi_r2t *r2t;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	spin_lock_bh(&cmd->r2t_lock);
23062306a36Sopenharmony_ci	list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
23162306a36Sopenharmony_ci		if (r2t->r2t_sn == r2t_sn) {
23262306a36Sopenharmony_ci			spin_unlock_bh(&cmd->r2t_lock);
23362306a36Sopenharmony_ci			return r2t;
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci	spin_unlock_bh(&cmd->r2t_lock);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return NULL;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic inline int iscsit_check_received_cmdsn(struct iscsit_session *sess, u32 cmdsn)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	u32 max_cmdsn;
24462306a36Sopenharmony_ci	int ret;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/*
24762306a36Sopenharmony_ci	 * This is the proper method of checking received CmdSN against
24862306a36Sopenharmony_ci	 * ExpCmdSN and MaxCmdSN values, as well as accounting for out
24962306a36Sopenharmony_ci	 * or order CmdSNs due to multiple connection sessions and/or
25062306a36Sopenharmony_ci	 * CRC failures.
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci	max_cmdsn = atomic_read(&sess->max_cmd_sn);
25362306a36Sopenharmony_ci	if (iscsi_sna_gt(cmdsn, max_cmdsn)) {
25462306a36Sopenharmony_ci		pr_err("Received CmdSN: 0x%08x is greater than"
25562306a36Sopenharmony_ci		       " MaxCmdSN: 0x%08x, ignoring.\n", cmdsn, max_cmdsn);
25662306a36Sopenharmony_ci		ret = CMDSN_MAXCMDSN_OVERRUN;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	} else if (cmdsn == sess->exp_cmd_sn) {
25962306a36Sopenharmony_ci		sess->exp_cmd_sn++;
26062306a36Sopenharmony_ci		pr_debug("Received CmdSN matches ExpCmdSN,"
26162306a36Sopenharmony_ci		      " incremented ExpCmdSN to: 0x%08x\n",
26262306a36Sopenharmony_ci		      sess->exp_cmd_sn);
26362306a36Sopenharmony_ci		ret = CMDSN_NORMAL_OPERATION;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	} else if (iscsi_sna_gt(cmdsn, sess->exp_cmd_sn)) {
26662306a36Sopenharmony_ci		pr_debug("Received CmdSN: 0x%08x is greater"
26762306a36Sopenharmony_ci		      " than ExpCmdSN: 0x%08x, not acknowledging.\n",
26862306a36Sopenharmony_ci		      cmdsn, sess->exp_cmd_sn);
26962306a36Sopenharmony_ci		ret = CMDSN_HIGHER_THAN_EXP;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	} else {
27262306a36Sopenharmony_ci		pr_err("Received CmdSN: 0x%08x is less than"
27362306a36Sopenharmony_ci		       " ExpCmdSN: 0x%08x, ignoring.\n", cmdsn,
27462306a36Sopenharmony_ci		       sess->exp_cmd_sn);
27562306a36Sopenharmony_ci		ret = CMDSN_LOWER_THAN_EXP;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ret;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * Commands may be received out of order if MC/S is in use.
28362306a36Sopenharmony_ci * Ensure they are executed in CmdSN order.
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_ciint iscsit_sequence_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
28662306a36Sopenharmony_ci			unsigned char *buf, __be32 cmdsn)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	int ret, cmdsn_ret;
28962306a36Sopenharmony_ci	bool reject = false;
29062306a36Sopenharmony_ci	u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	mutex_lock(&conn->sess->cmdsn_mutex);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, be32_to_cpu(cmdsn));
29562306a36Sopenharmony_ci	switch (cmdsn_ret) {
29662306a36Sopenharmony_ci	case CMDSN_NORMAL_OPERATION:
29762306a36Sopenharmony_ci		ret = iscsit_execute_cmd(cmd, 0);
29862306a36Sopenharmony_ci		if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
29962306a36Sopenharmony_ci			iscsit_execute_ooo_cmdsns(conn->sess);
30062306a36Sopenharmony_ci		else if (ret < 0) {
30162306a36Sopenharmony_ci			reject = true;
30262306a36Sopenharmony_ci			ret = CMDSN_ERROR_CANNOT_RECOVER;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci	case CMDSN_HIGHER_THAN_EXP:
30662306a36Sopenharmony_ci		ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
30762306a36Sopenharmony_ci		if (ret < 0) {
30862306a36Sopenharmony_ci			reject = true;
30962306a36Sopenharmony_ci			ret = CMDSN_ERROR_CANNOT_RECOVER;
31062306a36Sopenharmony_ci			break;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci		ret = CMDSN_HIGHER_THAN_EXP;
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	case CMDSN_LOWER_THAN_EXP:
31562306a36Sopenharmony_ci	case CMDSN_MAXCMDSN_OVERRUN:
31662306a36Sopenharmony_ci	default:
31762306a36Sopenharmony_ci		cmd->i_state = ISTATE_REMOVE;
31862306a36Sopenharmony_ci		iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
31962306a36Sopenharmony_ci		/*
32062306a36Sopenharmony_ci		 * Existing callers for iscsit_sequence_cmd() will silently
32162306a36Sopenharmony_ci		 * ignore commands with CMDSN_LOWER_THAN_EXP, so force this
32262306a36Sopenharmony_ci		 * return for CMDSN_MAXCMDSN_OVERRUN as well..
32362306a36Sopenharmony_ci		 */
32462306a36Sopenharmony_ci		ret = CMDSN_LOWER_THAN_EXP;
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	mutex_unlock(&conn->sess->cmdsn_mutex);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (reject)
33062306a36Sopenharmony_ci		iscsit_reject_cmd(cmd, reason, buf);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return ret;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_sequence_cmd);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciint iscsit_check_unsolicited_dataout(struct iscsit_cmd *cmd, unsigned char *buf)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct iscsit_conn *conn = cmd->conn;
33962306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
34062306a36Sopenharmony_ci	struct iscsi_data *hdr = (struct iscsi_data *) buf;
34162306a36Sopenharmony_ci	u32 payload_length = ntoh24(hdr->dlength);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (conn->sess->sess_ops->InitialR2T) {
34462306a36Sopenharmony_ci		pr_err("Received unexpected unsolicited data"
34562306a36Sopenharmony_ci			" while InitialR2T=Yes, protocol error.\n");
34662306a36Sopenharmony_ci		transport_send_check_condition_and_sense(se_cmd,
34762306a36Sopenharmony_ci				TCM_UNEXPECTED_UNSOLICITED_DATA, 0);
34862306a36Sopenharmony_ci		return -1;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if ((cmd->first_burst_len + payload_length) >
35262306a36Sopenharmony_ci	     conn->sess->sess_ops->FirstBurstLength) {
35362306a36Sopenharmony_ci		pr_err("Total %u bytes exceeds FirstBurstLength: %u"
35462306a36Sopenharmony_ci			" for this Unsolicited DataOut Burst.\n",
35562306a36Sopenharmony_ci			(cmd->first_burst_len + payload_length),
35662306a36Sopenharmony_ci				conn->sess->sess_ops->FirstBurstLength);
35762306a36Sopenharmony_ci		transport_send_check_condition_and_sense(se_cmd,
35862306a36Sopenharmony_ci				TCM_INCORRECT_AMOUNT_OF_DATA, 0);
35962306a36Sopenharmony_ci		return -1;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))
36362306a36Sopenharmony_ci		return 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) &&
36662306a36Sopenharmony_ci	    ((cmd->first_burst_len + payload_length) !=
36762306a36Sopenharmony_ci	      conn->sess->sess_ops->FirstBurstLength)) {
36862306a36Sopenharmony_ci		pr_err("Unsolicited non-immediate data received %u"
36962306a36Sopenharmony_ci			" does not equal FirstBurstLength: %u, and does"
37062306a36Sopenharmony_ci			" not equal ExpXferLen %u.\n",
37162306a36Sopenharmony_ci			(cmd->first_burst_len + payload_length),
37262306a36Sopenharmony_ci			conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length);
37362306a36Sopenharmony_ci		transport_send_check_condition_and_sense(se_cmd,
37462306a36Sopenharmony_ci				TCM_INCORRECT_AMOUNT_OF_DATA, 0);
37562306a36Sopenharmony_ci		return -1;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistruct iscsit_cmd *iscsit_find_cmd_from_itt(
38162306a36Sopenharmony_ci	struct iscsit_conn *conn,
38262306a36Sopenharmony_ci	itt_t init_task_tag)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct iscsit_cmd *cmd;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	spin_lock_bh(&conn->cmd_lock);
38762306a36Sopenharmony_ci	list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
38862306a36Sopenharmony_ci		if (cmd->init_task_tag == init_task_tag) {
38962306a36Sopenharmony_ci			spin_unlock_bh(&conn->cmd_lock);
39062306a36Sopenharmony_ci			return cmd;
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	spin_unlock_bh(&conn->cmd_lock);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	pr_err("Unable to locate ITT: 0x%08x on CID: %hu",
39662306a36Sopenharmony_ci			init_task_tag, conn->cid);
39762306a36Sopenharmony_ci	return NULL;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_find_cmd_from_itt);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistruct iscsit_cmd *iscsit_find_cmd_from_itt_or_dump(
40262306a36Sopenharmony_ci	struct iscsit_conn *conn,
40362306a36Sopenharmony_ci	itt_t init_task_tag,
40462306a36Sopenharmony_ci	u32 length)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct iscsit_cmd *cmd;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	spin_lock_bh(&conn->cmd_lock);
40962306a36Sopenharmony_ci	list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
41062306a36Sopenharmony_ci		if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT)
41162306a36Sopenharmony_ci			continue;
41262306a36Sopenharmony_ci		if (cmd->init_task_tag == init_task_tag) {
41362306a36Sopenharmony_ci			spin_unlock_bh(&conn->cmd_lock);
41462306a36Sopenharmony_ci			return cmd;
41562306a36Sopenharmony_ci		}
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	spin_unlock_bh(&conn->cmd_lock);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	pr_err("Unable to locate ITT: 0x%08x on CID: %hu,"
42062306a36Sopenharmony_ci			" dumping payload\n", init_task_tag, conn->cid);
42162306a36Sopenharmony_ci	if (length)
42262306a36Sopenharmony_ci		iscsit_dump_data_payload(conn, length, 1);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return NULL;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_find_cmd_from_itt_or_dump);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistruct iscsit_cmd *iscsit_find_cmd_from_ttt(
42962306a36Sopenharmony_ci	struct iscsit_conn *conn,
43062306a36Sopenharmony_ci	u32 targ_xfer_tag)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct iscsit_cmd *cmd = NULL;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	spin_lock_bh(&conn->cmd_lock);
43562306a36Sopenharmony_ci	list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
43662306a36Sopenharmony_ci		if (cmd->targ_xfer_tag == targ_xfer_tag) {
43762306a36Sopenharmony_ci			spin_unlock_bh(&conn->cmd_lock);
43862306a36Sopenharmony_ci			return cmd;
43962306a36Sopenharmony_ci		}
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci	spin_unlock_bh(&conn->cmd_lock);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	pr_err("Unable to locate TTT: 0x%08x on CID: %hu\n",
44462306a36Sopenharmony_ci			targ_xfer_tag, conn->cid);
44562306a36Sopenharmony_ci	return NULL;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ciint iscsit_find_cmd_for_recovery(
44962306a36Sopenharmony_ci	struct iscsit_session *sess,
45062306a36Sopenharmony_ci	struct iscsit_cmd **cmd_ptr,
45162306a36Sopenharmony_ci	struct iscsi_conn_recovery **cr_ptr,
45262306a36Sopenharmony_ci	itt_t init_task_tag)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct iscsit_cmd *cmd = NULL;
45562306a36Sopenharmony_ci	struct iscsi_conn_recovery *cr;
45662306a36Sopenharmony_ci	/*
45762306a36Sopenharmony_ci	 * Scan through the inactive connection recovery list's command list.
45862306a36Sopenharmony_ci	 * If init_task_tag matches the command is still alligent.
45962306a36Sopenharmony_ci	 */
46062306a36Sopenharmony_ci	spin_lock(&sess->cr_i_lock);
46162306a36Sopenharmony_ci	list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) {
46262306a36Sopenharmony_ci		spin_lock(&cr->conn_recovery_cmd_lock);
46362306a36Sopenharmony_ci		list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) {
46462306a36Sopenharmony_ci			if (cmd->init_task_tag == init_task_tag) {
46562306a36Sopenharmony_ci				spin_unlock(&cr->conn_recovery_cmd_lock);
46662306a36Sopenharmony_ci				spin_unlock(&sess->cr_i_lock);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci				*cr_ptr = cr;
46962306a36Sopenharmony_ci				*cmd_ptr = cmd;
47062306a36Sopenharmony_ci				return -2;
47162306a36Sopenharmony_ci			}
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci		spin_unlock(&cr->conn_recovery_cmd_lock);
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	spin_unlock(&sess->cr_i_lock);
47662306a36Sopenharmony_ci	/*
47762306a36Sopenharmony_ci	 * Scan through the active connection recovery list's command list.
47862306a36Sopenharmony_ci	 * If init_task_tag matches the command is ready to be reassigned.
47962306a36Sopenharmony_ci	 */
48062306a36Sopenharmony_ci	spin_lock(&sess->cr_a_lock);
48162306a36Sopenharmony_ci	list_for_each_entry(cr, &sess->cr_active_list, cr_list) {
48262306a36Sopenharmony_ci		spin_lock(&cr->conn_recovery_cmd_lock);
48362306a36Sopenharmony_ci		list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) {
48462306a36Sopenharmony_ci			if (cmd->init_task_tag == init_task_tag) {
48562306a36Sopenharmony_ci				spin_unlock(&cr->conn_recovery_cmd_lock);
48662306a36Sopenharmony_ci				spin_unlock(&sess->cr_a_lock);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci				*cr_ptr = cr;
48962306a36Sopenharmony_ci				*cmd_ptr = cmd;
49062306a36Sopenharmony_ci				return 0;
49162306a36Sopenharmony_ci			}
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci		spin_unlock(&cr->conn_recovery_cmd_lock);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci	spin_unlock(&sess->cr_a_lock);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return -1;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_civoid iscsit_add_cmd_to_immediate_queue(
50162306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
50262306a36Sopenharmony_ci	struct iscsit_conn *conn,
50362306a36Sopenharmony_ci	u8 state)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct iscsi_queue_req *qr;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC);
50862306a36Sopenharmony_ci	if (!qr) {
50962306a36Sopenharmony_ci		pr_err("Unable to allocate memory for"
51062306a36Sopenharmony_ci				" struct iscsi_queue_req\n");
51162306a36Sopenharmony_ci		return;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci	INIT_LIST_HEAD(&qr->qr_list);
51462306a36Sopenharmony_ci	qr->cmd = cmd;
51562306a36Sopenharmony_ci	qr->state = state;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	spin_lock_bh(&conn->immed_queue_lock);
51862306a36Sopenharmony_ci	list_add_tail(&qr->qr_list, &conn->immed_queue_list);
51962306a36Sopenharmony_ci	atomic_inc(&cmd->immed_queue_count);
52062306a36Sopenharmony_ci	atomic_set(&conn->check_immediate_queue, 1);
52162306a36Sopenharmony_ci	spin_unlock_bh(&conn->immed_queue_lock);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	wake_up(&conn->queues_wq);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_add_cmd_to_immediate_queue);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistruct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsit_conn *conn)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct iscsi_queue_req *qr;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	spin_lock_bh(&conn->immed_queue_lock);
53262306a36Sopenharmony_ci	if (list_empty(&conn->immed_queue_list)) {
53362306a36Sopenharmony_ci		spin_unlock_bh(&conn->immed_queue_lock);
53462306a36Sopenharmony_ci		return NULL;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	qr = list_first_entry(&conn->immed_queue_list,
53762306a36Sopenharmony_ci			      struct iscsi_queue_req, qr_list);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	list_del(&qr->qr_list);
54062306a36Sopenharmony_ci	if (qr->cmd)
54162306a36Sopenharmony_ci		atomic_dec(&qr->cmd->immed_queue_count);
54262306a36Sopenharmony_ci	spin_unlock_bh(&conn->immed_queue_lock);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return qr;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic void iscsit_remove_cmd_from_immediate_queue(
54862306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
54962306a36Sopenharmony_ci	struct iscsit_conn *conn)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct iscsi_queue_req *qr, *qr_tmp;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	spin_lock_bh(&conn->immed_queue_lock);
55462306a36Sopenharmony_ci	if (!atomic_read(&cmd->immed_queue_count)) {
55562306a36Sopenharmony_ci		spin_unlock_bh(&conn->immed_queue_lock);
55662306a36Sopenharmony_ci		return;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) {
56062306a36Sopenharmony_ci		if (qr->cmd != cmd)
56162306a36Sopenharmony_ci			continue;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		atomic_dec(&qr->cmd->immed_queue_count);
56462306a36Sopenharmony_ci		list_del(&qr->qr_list);
56562306a36Sopenharmony_ci		kmem_cache_free(lio_qr_cache, qr);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	spin_unlock_bh(&conn->immed_queue_lock);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (atomic_read(&cmd->immed_queue_count)) {
57062306a36Sopenharmony_ci		pr_err("ITT: 0x%08x immed_queue_count: %d\n",
57162306a36Sopenharmony_ci			cmd->init_task_tag,
57262306a36Sopenharmony_ci			atomic_read(&cmd->immed_queue_count));
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ciint iscsit_add_cmd_to_response_queue(
57762306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
57862306a36Sopenharmony_ci	struct iscsit_conn *conn,
57962306a36Sopenharmony_ci	u8 state)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct iscsi_queue_req *qr;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC);
58462306a36Sopenharmony_ci	if (!qr) {
58562306a36Sopenharmony_ci		pr_err("Unable to allocate memory for"
58662306a36Sopenharmony_ci			" struct iscsi_queue_req\n");
58762306a36Sopenharmony_ci		return -ENOMEM;
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci	INIT_LIST_HEAD(&qr->qr_list);
59062306a36Sopenharmony_ci	qr->cmd = cmd;
59162306a36Sopenharmony_ci	qr->state = state;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	spin_lock_bh(&conn->response_queue_lock);
59462306a36Sopenharmony_ci	list_add_tail(&qr->qr_list, &conn->response_queue_list);
59562306a36Sopenharmony_ci	atomic_inc(&cmd->response_queue_count);
59662306a36Sopenharmony_ci	spin_unlock_bh(&conn->response_queue_lock);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	wake_up(&conn->queues_wq);
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistruct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsit_conn *conn)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct iscsi_queue_req *qr;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	spin_lock_bh(&conn->response_queue_lock);
60762306a36Sopenharmony_ci	if (list_empty(&conn->response_queue_list)) {
60862306a36Sopenharmony_ci		spin_unlock_bh(&conn->response_queue_lock);
60962306a36Sopenharmony_ci		return NULL;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	qr = list_first_entry(&conn->response_queue_list,
61362306a36Sopenharmony_ci			      struct iscsi_queue_req, qr_list);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	list_del(&qr->qr_list);
61662306a36Sopenharmony_ci	if (qr->cmd)
61762306a36Sopenharmony_ci		atomic_dec(&qr->cmd->response_queue_count);
61862306a36Sopenharmony_ci	spin_unlock_bh(&conn->response_queue_lock);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return qr;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void iscsit_remove_cmd_from_response_queue(
62462306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
62562306a36Sopenharmony_ci	struct iscsit_conn *conn)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct iscsi_queue_req *qr, *qr_tmp;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	spin_lock_bh(&conn->response_queue_lock);
63062306a36Sopenharmony_ci	if (!atomic_read(&cmd->response_queue_count)) {
63162306a36Sopenharmony_ci		spin_unlock_bh(&conn->response_queue_lock);
63262306a36Sopenharmony_ci		return;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list,
63662306a36Sopenharmony_ci				qr_list) {
63762306a36Sopenharmony_ci		if (qr->cmd != cmd)
63862306a36Sopenharmony_ci			continue;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		atomic_dec(&qr->cmd->response_queue_count);
64162306a36Sopenharmony_ci		list_del(&qr->qr_list);
64262306a36Sopenharmony_ci		kmem_cache_free(lio_qr_cache, qr);
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci	spin_unlock_bh(&conn->response_queue_lock);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (atomic_read(&cmd->response_queue_count)) {
64762306a36Sopenharmony_ci		pr_err("ITT: 0x%08x response_queue_count: %d\n",
64862306a36Sopenharmony_ci			cmd->init_task_tag,
64962306a36Sopenharmony_ci			atomic_read(&cmd->response_queue_count));
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cibool iscsit_conn_all_queues_empty(struct iscsit_conn *conn)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	bool empty;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	spin_lock_bh(&conn->immed_queue_lock);
65862306a36Sopenharmony_ci	empty = list_empty(&conn->immed_queue_list);
65962306a36Sopenharmony_ci	spin_unlock_bh(&conn->immed_queue_lock);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (!empty)
66262306a36Sopenharmony_ci		return empty;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	spin_lock_bh(&conn->response_queue_lock);
66562306a36Sopenharmony_ci	empty = list_empty(&conn->response_queue_list);
66662306a36Sopenharmony_ci	spin_unlock_bh(&conn->response_queue_lock);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return empty;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_civoid iscsit_free_queue_reqs_for_conn(struct iscsit_conn *conn)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct iscsi_queue_req *qr, *qr_tmp;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	spin_lock_bh(&conn->immed_queue_lock);
67662306a36Sopenharmony_ci	list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) {
67762306a36Sopenharmony_ci		list_del(&qr->qr_list);
67862306a36Sopenharmony_ci		if (qr->cmd)
67962306a36Sopenharmony_ci			atomic_dec(&qr->cmd->immed_queue_count);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		kmem_cache_free(lio_qr_cache, qr);
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci	spin_unlock_bh(&conn->immed_queue_lock);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	spin_lock_bh(&conn->response_queue_lock);
68662306a36Sopenharmony_ci	list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list,
68762306a36Sopenharmony_ci			qr_list) {
68862306a36Sopenharmony_ci		list_del(&qr->qr_list);
68962306a36Sopenharmony_ci		if (qr->cmd)
69062306a36Sopenharmony_ci			atomic_dec(&qr->cmd->response_queue_count);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		kmem_cache_free(lio_qr_cache, qr);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	spin_unlock_bh(&conn->response_queue_lock);
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_civoid iscsit_release_cmd(struct iscsit_cmd *cmd)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct iscsit_session *sess;
70062306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	WARN_ON(!list_empty(&cmd->i_conn_node));
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (cmd->conn)
70562306a36Sopenharmony_ci		sess = cmd->conn->sess;
70662306a36Sopenharmony_ci	else
70762306a36Sopenharmony_ci		sess = cmd->sess;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	BUG_ON(!sess || !sess->se_sess);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	kfree(cmd->buf_ptr);
71262306a36Sopenharmony_ci	kfree(cmd->pdu_list);
71362306a36Sopenharmony_ci	kfree(cmd->seq_list);
71462306a36Sopenharmony_ci	kfree(cmd->tmr_req);
71562306a36Sopenharmony_ci	kfree(cmd->overflow_buf);
71662306a36Sopenharmony_ci	kfree(cmd->iov_data);
71762306a36Sopenharmony_ci	kfree(cmd->text_in_ptr);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	target_free_tag(sess->se_sess, se_cmd);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_release_cmd);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_civoid __iscsit_free_cmd(struct iscsit_cmd *cmd, bool check_queues)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct iscsit_conn *conn = cmd->conn;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	WARN_ON(!list_empty(&cmd->i_conn_node));
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (cmd->data_direction == DMA_TO_DEVICE) {
73062306a36Sopenharmony_ci		iscsit_stop_dataout_timer(cmd);
73162306a36Sopenharmony_ci		iscsit_free_r2ts_from_list(cmd);
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci	if (cmd->data_direction == DMA_FROM_DEVICE)
73462306a36Sopenharmony_ci		iscsit_free_all_datain_reqs(cmd);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (conn && check_queues) {
73762306a36Sopenharmony_ci		iscsit_remove_cmd_from_immediate_queue(cmd, conn);
73862306a36Sopenharmony_ci		iscsit_remove_cmd_from_response_queue(cmd, conn);
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (conn && conn->conn_transport->iscsit_unmap_cmd)
74262306a36Sopenharmony_ci		conn->conn_transport->iscsit_unmap_cmd(conn, cmd);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_civoid iscsit_free_cmd(struct iscsit_cmd *cmd, bool shutdown)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct se_cmd *se_cmd = cmd->se_cmd.se_tfo ? &cmd->se_cmd : NULL;
74862306a36Sopenharmony_ci	int rc;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	WARN_ON(!list_empty(&cmd->i_conn_node));
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	__iscsit_free_cmd(cmd, shutdown);
75362306a36Sopenharmony_ci	if (se_cmd) {
75462306a36Sopenharmony_ci		rc = transport_generic_free_cmd(se_cmd, shutdown);
75562306a36Sopenharmony_ci		if (!rc && shutdown && se_cmd->se_sess) {
75662306a36Sopenharmony_ci			__iscsit_free_cmd(cmd, shutdown);
75762306a36Sopenharmony_ci			target_put_sess_cmd(se_cmd);
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci	} else {
76062306a36Sopenharmony_ci		iscsit_release_cmd(cmd);
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ciEXPORT_SYMBOL(iscsit_free_cmd);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cibool iscsit_check_session_usage_count(struct iscsit_session *sess,
76662306a36Sopenharmony_ci				      bool can_sleep)
76762306a36Sopenharmony_ci{
76862306a36Sopenharmony_ci	spin_lock_bh(&sess->session_usage_lock);
76962306a36Sopenharmony_ci	if (sess->session_usage_count != 0) {
77062306a36Sopenharmony_ci		sess->session_waiting_on_uc = 1;
77162306a36Sopenharmony_ci		spin_unlock_bh(&sess->session_usage_lock);
77262306a36Sopenharmony_ci		if (!can_sleep)
77362306a36Sopenharmony_ci			return true;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		wait_for_completion(&sess->session_waiting_on_uc_comp);
77662306a36Sopenharmony_ci		return false;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci	spin_unlock_bh(&sess->session_usage_lock);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return false;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_civoid iscsit_dec_session_usage_count(struct iscsit_session *sess)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	spin_lock_bh(&sess->session_usage_lock);
78662306a36Sopenharmony_ci	sess->session_usage_count--;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!sess->session_usage_count && sess->session_waiting_on_uc)
78962306a36Sopenharmony_ci		complete(&sess->session_waiting_on_uc_comp);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	spin_unlock_bh(&sess->session_usage_lock);
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_civoid iscsit_inc_session_usage_count(struct iscsit_session *sess)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	spin_lock_bh(&sess->session_usage_lock);
79762306a36Sopenharmony_ci	sess->session_usage_count++;
79862306a36Sopenharmony_ci	spin_unlock_bh(&sess->session_usage_lock);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistruct iscsit_conn *iscsit_get_conn_from_cid(struct iscsit_session *sess, u16 cid)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct iscsit_conn *conn;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
80662306a36Sopenharmony_ci	list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
80762306a36Sopenharmony_ci		if ((conn->cid == cid) &&
80862306a36Sopenharmony_ci		    (conn->conn_state == TARG_CONN_STATE_LOGGED_IN)) {
80962306a36Sopenharmony_ci			iscsit_inc_conn_usage_count(conn);
81062306a36Sopenharmony_ci			spin_unlock_bh(&sess->conn_lock);
81162306a36Sopenharmony_ci			return conn;
81262306a36Sopenharmony_ci		}
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	return NULL;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistruct iscsit_conn *iscsit_get_conn_from_cid_rcfr(struct iscsit_session *sess, u16 cid)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	struct iscsit_conn *conn;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
82462306a36Sopenharmony_ci	list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
82562306a36Sopenharmony_ci		if (conn->cid == cid) {
82662306a36Sopenharmony_ci			iscsit_inc_conn_usage_count(conn);
82762306a36Sopenharmony_ci			spin_lock(&conn->state_lock);
82862306a36Sopenharmony_ci			atomic_set(&conn->connection_wait_rcfr, 1);
82962306a36Sopenharmony_ci			spin_unlock(&conn->state_lock);
83062306a36Sopenharmony_ci			spin_unlock_bh(&sess->conn_lock);
83162306a36Sopenharmony_ci			return conn;
83262306a36Sopenharmony_ci		}
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return NULL;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_civoid iscsit_check_conn_usage_count(struct iscsit_conn *conn)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	spin_lock_bh(&conn->conn_usage_lock);
84262306a36Sopenharmony_ci	if (conn->conn_usage_count != 0) {
84362306a36Sopenharmony_ci		conn->conn_waiting_on_uc = 1;
84462306a36Sopenharmony_ci		spin_unlock_bh(&conn->conn_usage_lock);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		wait_for_completion(&conn->conn_waiting_on_uc_comp);
84762306a36Sopenharmony_ci		return;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci	spin_unlock_bh(&conn->conn_usage_lock);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_civoid iscsit_dec_conn_usage_count(struct iscsit_conn *conn)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	spin_lock_bh(&conn->conn_usage_lock);
85562306a36Sopenharmony_ci	conn->conn_usage_count--;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (!conn->conn_usage_count && conn->conn_waiting_on_uc)
85862306a36Sopenharmony_ci		complete(&conn->conn_waiting_on_uc_comp);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	spin_unlock_bh(&conn->conn_usage_lock);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_civoid iscsit_inc_conn_usage_count(struct iscsit_conn *conn)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	spin_lock_bh(&conn->conn_usage_lock);
86662306a36Sopenharmony_ci	conn->conn_usage_count++;
86762306a36Sopenharmony_ci	spin_unlock_bh(&conn->conn_usage_lock);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int iscsit_add_nopin(struct iscsit_conn *conn, int want_response)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	u8 state;
87362306a36Sopenharmony_ci	struct iscsit_cmd *cmd;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	cmd = iscsit_allocate_cmd(conn, TASK_RUNNING);
87662306a36Sopenharmony_ci	if (!cmd)
87762306a36Sopenharmony_ci		return -1;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	cmd->iscsi_opcode = ISCSI_OP_NOOP_IN;
88062306a36Sopenharmony_ci	state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
88162306a36Sopenharmony_ci				ISTATE_SEND_NOPIN_NO_RESPONSE;
88262306a36Sopenharmony_ci	cmd->init_task_tag = RESERVED_ITT;
88362306a36Sopenharmony_ci	cmd->targ_xfer_tag = (want_response) ?
88462306a36Sopenharmony_ci			     session_get_next_ttt(conn->sess) : 0xFFFFFFFF;
88562306a36Sopenharmony_ci	spin_lock_bh(&conn->cmd_lock);
88662306a36Sopenharmony_ci	list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
88762306a36Sopenharmony_ci	spin_unlock_bh(&conn->cmd_lock);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (want_response)
89062306a36Sopenharmony_ci		iscsit_start_nopin_response_timer(conn);
89162306a36Sopenharmony_ci	iscsit_add_cmd_to_immediate_queue(cmd, conn, state);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return 0;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_civoid iscsit_handle_nopin_response_timeout(struct timer_list *t)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct iscsit_conn *conn = from_timer(conn, t, nopin_response_timer);
89962306a36Sopenharmony_ci	struct iscsit_session *sess = conn->sess;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	iscsit_inc_conn_usage_count(conn);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
90462306a36Sopenharmony_ci	if (conn->nopin_response_timer_flags & ISCSI_TF_STOP) {
90562306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
90662306a36Sopenharmony_ci		iscsit_dec_conn_usage_count(conn);
90762306a36Sopenharmony_ci		return;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	pr_err("Did not receive response to NOPIN on CID: %hu, failing"
91162306a36Sopenharmony_ci		" connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n",
91262306a36Sopenharmony_ci		conn->cid, sess->sess_ops->InitiatorName, sess->isid,
91362306a36Sopenharmony_ci		sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt);
91462306a36Sopenharmony_ci	conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
91562306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	iscsit_fill_cxn_timeout_err_stats(sess);
91862306a36Sopenharmony_ci	iscsit_cause_connection_reinstatement(conn, 0);
91962306a36Sopenharmony_ci	iscsit_dec_conn_usage_count(conn);
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_civoid iscsit_mod_nopin_response_timer(struct iscsit_conn *conn)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	struct iscsit_session *sess = conn->sess;
92562306a36Sopenharmony_ci	struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
92862306a36Sopenharmony_ci	if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) {
92962306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
93062306a36Sopenharmony_ci		return;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	mod_timer(&conn->nopin_response_timer,
93462306a36Sopenharmony_ci		(get_jiffies_64() + na->nopin_response_timeout * HZ));
93562306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_civoid iscsit_start_nopin_response_timer(struct iscsit_conn *conn)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct iscsit_session *sess = conn->sess;
94162306a36Sopenharmony_ci	struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
94462306a36Sopenharmony_ci	if (conn->nopin_response_timer_flags & ISCSI_TF_RUNNING) {
94562306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
94662306a36Sopenharmony_ci		return;
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP;
95062306a36Sopenharmony_ci	conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING;
95162306a36Sopenharmony_ci	mod_timer(&conn->nopin_response_timer,
95262306a36Sopenharmony_ci		  jiffies + na->nopin_response_timeout * HZ);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	pr_debug("Started NOPIN Response Timer on CID: %d to %u"
95562306a36Sopenharmony_ci		" seconds\n", conn->cid, na->nopin_response_timeout);
95662306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_civoid iscsit_stop_nopin_response_timer(struct iscsit_conn *conn)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
96262306a36Sopenharmony_ci	if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) {
96362306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
96462306a36Sopenharmony_ci		return;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci	conn->nopin_response_timer_flags |= ISCSI_TF_STOP;
96762306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	del_timer_sync(&conn->nopin_response_timer);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
97262306a36Sopenharmony_ci	conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
97362306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_civoid iscsit_handle_nopin_timeout(struct timer_list *t)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	struct iscsit_conn *conn = from_timer(conn, t, nopin_timer);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	iscsit_inc_conn_usage_count(conn);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
98362306a36Sopenharmony_ci	if (conn->nopin_timer_flags & ISCSI_TF_STOP) {
98462306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
98562306a36Sopenharmony_ci		iscsit_dec_conn_usage_count(conn);
98662306a36Sopenharmony_ci		return;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci	conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING;
98962306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	iscsit_add_nopin(conn, 1);
99262306a36Sopenharmony_ci	iscsit_dec_conn_usage_count(conn);
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_civoid __iscsit_start_nopin_timer(struct iscsit_conn *conn)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct iscsit_session *sess = conn->sess;
99862306a36Sopenharmony_ci	struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	lockdep_assert_held(&conn->nopin_timer_lock);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/*
100362306a36Sopenharmony_ci	* NOPIN timeout is disabled.
100462306a36Sopenharmony_ci	 */
100562306a36Sopenharmony_ci	if (!na->nopin_timeout)
100662306a36Sopenharmony_ci		return;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (conn->nopin_timer_flags & ISCSI_TF_RUNNING)
100962306a36Sopenharmony_ci		return;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
101262306a36Sopenharmony_ci	conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
101362306a36Sopenharmony_ci	mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	pr_debug("Started NOPIN Timer on CID: %d at %u second"
101662306a36Sopenharmony_ci		" interval\n", conn->cid, na->nopin_timeout);
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_civoid iscsit_start_nopin_timer(struct iscsit_conn *conn)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
102262306a36Sopenharmony_ci	__iscsit_start_nopin_timer(conn);
102362306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_civoid iscsit_stop_nopin_timer(struct iscsit_conn *conn)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
102962306a36Sopenharmony_ci	if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) {
103062306a36Sopenharmony_ci		spin_unlock_bh(&conn->nopin_timer_lock);
103162306a36Sopenharmony_ci		return;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci	conn->nopin_timer_flags |= ISCSI_TF_STOP;
103462306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	del_timer_sync(&conn->nopin_timer);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	spin_lock_bh(&conn->nopin_timer_lock);
103962306a36Sopenharmony_ci	conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING;
104062306a36Sopenharmony_ci	spin_unlock_bh(&conn->nopin_timer_lock);
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_civoid iscsit_login_timeout(struct timer_list *t)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct iscsit_conn *conn = from_timer(conn, t, login_timer);
104662306a36Sopenharmony_ci	struct iscsi_login *login = conn->login;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	spin_lock_bh(&conn->login_timer_lock);
105162306a36Sopenharmony_ci	login->login_failed = 1;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	if (conn->login_kworker) {
105462306a36Sopenharmony_ci		pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n",
105562306a36Sopenharmony_ci			 conn->login_kworker->comm, conn->login_kworker->pid);
105662306a36Sopenharmony_ci		send_sig(SIGINT, conn->login_kworker, 1);
105762306a36Sopenharmony_ci	} else {
105862306a36Sopenharmony_ci		schedule_delayed_work(&conn->login_work, 0);
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci	spin_unlock_bh(&conn->login_timer_lock);
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_civoid iscsit_start_login_timer(struct iscsit_conn *conn, struct task_struct *kthr)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	pr_debug("Login timer started\n");
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	conn->login_kworker = kthr;
106862306a36Sopenharmony_ci	mod_timer(&conn->login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ciint iscsit_set_login_timer_kworker(struct iscsit_conn *conn, struct task_struct *kthr)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	struct iscsi_login *login = conn->login;
107462306a36Sopenharmony_ci	int ret = 0;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	spin_lock_bh(&conn->login_timer_lock);
107762306a36Sopenharmony_ci	if (login->login_failed) {
107862306a36Sopenharmony_ci		/* The timer has already expired */
107962306a36Sopenharmony_ci		ret = -1;
108062306a36Sopenharmony_ci	} else {
108162306a36Sopenharmony_ci		conn->login_kworker = kthr;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci	spin_unlock_bh(&conn->login_timer_lock);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return ret;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_civoid iscsit_stop_login_timer(struct iscsit_conn *conn)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	pr_debug("Login timer stopped\n");
109162306a36Sopenharmony_ci	timer_delete_sync(&conn->login_timer);
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ciint iscsit_send_tx_data(
109562306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
109662306a36Sopenharmony_ci	struct iscsit_conn *conn,
109762306a36Sopenharmony_ci	int use_misc)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	int tx_sent, tx_size;
110062306a36Sopenharmony_ci	u32 iov_count;
110162306a36Sopenharmony_ci	struct kvec *iov;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cisend_data:
110462306a36Sopenharmony_ci	tx_size = cmd->tx_size;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (!use_misc) {
110762306a36Sopenharmony_ci		iov = &cmd->iov_data[0];
110862306a36Sopenharmony_ci		iov_count = cmd->iov_data_count;
110962306a36Sopenharmony_ci	} else {
111062306a36Sopenharmony_ci		iov = &cmd->iov_misc[0];
111162306a36Sopenharmony_ci		iov_count = cmd->iov_misc_count;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	tx_sent = tx_data(conn, &iov[0], iov_count, tx_size);
111562306a36Sopenharmony_ci	if (tx_size != tx_sent) {
111662306a36Sopenharmony_ci		if (tx_sent == -EAGAIN) {
111762306a36Sopenharmony_ci			pr_err("tx_data() returned -EAGAIN\n");
111862306a36Sopenharmony_ci			goto send_data;
111962306a36Sopenharmony_ci		} else
112062306a36Sopenharmony_ci			return -1;
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci	cmd->tx_size = 0;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	return 0;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ciint iscsit_fe_sendpage_sg(
112862306a36Sopenharmony_ci	struct iscsit_cmd *cmd,
112962306a36Sopenharmony_ci	struct iscsit_conn *conn)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	struct scatterlist *sg = cmd->first_data_sg;
113262306a36Sopenharmony_ci	struct bio_vec bvec;
113362306a36Sopenharmony_ci	struct msghdr msghdr = { .msg_flags = MSG_SPLICE_PAGES,	};
113462306a36Sopenharmony_ci	struct kvec iov;
113562306a36Sopenharmony_ci	u32 tx_hdr_size, data_len;
113662306a36Sopenharmony_ci	u32 offset = cmd->first_data_sg_off;
113762306a36Sopenharmony_ci	int tx_sent, iov_off;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cisend_hdr:
114062306a36Sopenharmony_ci	tx_hdr_size = ISCSI_HDR_LEN;
114162306a36Sopenharmony_ci	if (conn->conn_ops->HeaderDigest)
114262306a36Sopenharmony_ci		tx_hdr_size += ISCSI_CRC_LEN;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	iov.iov_base = cmd->pdu;
114562306a36Sopenharmony_ci	iov.iov_len = tx_hdr_size;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	tx_sent = tx_data(conn, &iov, 1, tx_hdr_size);
114862306a36Sopenharmony_ci	if (tx_hdr_size != tx_sent) {
114962306a36Sopenharmony_ci		if (tx_sent == -EAGAIN) {
115062306a36Sopenharmony_ci			pr_err("tx_data() returned -EAGAIN\n");
115162306a36Sopenharmony_ci			goto send_hdr;
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci		return -1;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	data_len = cmd->tx_size - tx_hdr_size - cmd->padding;
115762306a36Sopenharmony_ci	/*
115862306a36Sopenharmony_ci	 * Set iov_off used by padding and data digest tx_data() calls below
115962306a36Sopenharmony_ci	 * in order to determine proper offset into cmd->iov_data[]
116062306a36Sopenharmony_ci	 */
116162306a36Sopenharmony_ci	if (conn->conn_ops->DataDigest) {
116262306a36Sopenharmony_ci		data_len -= ISCSI_CRC_LEN;
116362306a36Sopenharmony_ci		if (cmd->padding)
116462306a36Sopenharmony_ci			iov_off = (cmd->iov_data_count - 2);
116562306a36Sopenharmony_ci		else
116662306a36Sopenharmony_ci			iov_off = (cmd->iov_data_count - 1);
116762306a36Sopenharmony_ci	} else {
116862306a36Sopenharmony_ci		iov_off = (cmd->iov_data_count - 1);
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci	/*
117162306a36Sopenharmony_ci	 * Perform sendpage() for each page in the scatterlist
117262306a36Sopenharmony_ci	 */
117362306a36Sopenharmony_ci	while (data_len) {
117462306a36Sopenharmony_ci		u32 space = (sg->length - offset);
117562306a36Sopenharmony_ci		u32 sub_len = min_t(u32, data_len, space);
117662306a36Sopenharmony_cisend_pg:
117762306a36Sopenharmony_ci		bvec_set_page(&bvec, sg_page(sg), sub_len, sg->offset + offset);
117862306a36Sopenharmony_ci		iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, sub_len);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci		tx_sent = conn->sock->ops->sendmsg(conn->sock, &msghdr,
118162306a36Sopenharmony_ci						   sub_len);
118262306a36Sopenharmony_ci		if (tx_sent != sub_len) {
118362306a36Sopenharmony_ci			if (tx_sent == -EAGAIN) {
118462306a36Sopenharmony_ci				pr_err("sendmsg/splice returned -EAGAIN\n");
118562306a36Sopenharmony_ci				goto send_pg;
118662306a36Sopenharmony_ci			}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci			pr_err("sendmsg/splice failure: %d\n", tx_sent);
118962306a36Sopenharmony_ci			return -1;
119062306a36Sopenharmony_ci		}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		data_len -= sub_len;
119362306a36Sopenharmony_ci		offset = 0;
119462306a36Sopenharmony_ci		sg = sg_next(sg);
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_cisend_padding:
119862306a36Sopenharmony_ci	if (cmd->padding) {
119962306a36Sopenharmony_ci		struct kvec *iov_p = &cmd->iov_data[iov_off++];
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci		tx_sent = tx_data(conn, iov_p, 1, cmd->padding);
120262306a36Sopenharmony_ci		if (cmd->padding != tx_sent) {
120362306a36Sopenharmony_ci			if (tx_sent == -EAGAIN) {
120462306a36Sopenharmony_ci				pr_err("tx_data() returned -EAGAIN\n");
120562306a36Sopenharmony_ci				goto send_padding;
120662306a36Sopenharmony_ci			}
120762306a36Sopenharmony_ci			return -1;
120862306a36Sopenharmony_ci		}
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cisend_datacrc:
121262306a36Sopenharmony_ci	if (conn->conn_ops->DataDigest) {
121362306a36Sopenharmony_ci		struct kvec *iov_d = &cmd->iov_data[iov_off];
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci		tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN);
121662306a36Sopenharmony_ci		if (ISCSI_CRC_LEN != tx_sent) {
121762306a36Sopenharmony_ci			if (tx_sent == -EAGAIN) {
121862306a36Sopenharmony_ci				pr_err("tx_data() returned -EAGAIN\n");
121962306a36Sopenharmony_ci				goto send_datacrc;
122062306a36Sopenharmony_ci			}
122162306a36Sopenharmony_ci			return -1;
122262306a36Sopenharmony_ci		}
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return 0;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci/*
122962306a36Sopenharmony_ci *      This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU
123062306a36Sopenharmony_ci *      back to the Initiator when an expection condition occurs with the
123162306a36Sopenharmony_ci *      errors set in status_class and status_detail.
123262306a36Sopenharmony_ci *
123362306a36Sopenharmony_ci *      Parameters:     iSCSI Connection, Status Class, Status Detail.
123462306a36Sopenharmony_ci *      Returns:        0 on success, -1 on error.
123562306a36Sopenharmony_ci */
123662306a36Sopenharmony_ciint iscsit_tx_login_rsp(struct iscsit_conn *conn, u8 status_class, u8 status_detail)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct iscsi_login_rsp *hdr;
123962306a36Sopenharmony_ci	struct iscsi_login *login = conn->conn_login;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	login->login_failed = 1;
124262306a36Sopenharmony_ci	iscsit_collect_login_stats(conn, status_class, status_detail);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	memset(&login->rsp[0], 0, ISCSI_HDR_LEN);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	hdr	= (struct iscsi_login_rsp *)&login->rsp[0];
124762306a36Sopenharmony_ci	hdr->opcode		= ISCSI_OP_LOGIN_RSP;
124862306a36Sopenharmony_ci	hdr->status_class	= status_class;
124962306a36Sopenharmony_ci	hdr->status_detail	= status_detail;
125062306a36Sopenharmony_ci	hdr->itt		= conn->login_itt;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_civoid iscsit_print_session_params(struct iscsit_session *sess)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct iscsit_conn *conn;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	pr_debug("-----------------------------[Session Params for"
126062306a36Sopenharmony_ci		" SID: %u]-----------------------------\n", sess->sid);
126162306a36Sopenharmony_ci	spin_lock_bh(&sess->conn_lock);
126262306a36Sopenharmony_ci	list_for_each_entry(conn, &sess->sess_conn_list, conn_list)
126362306a36Sopenharmony_ci		iscsi_dump_conn_ops(conn->conn_ops);
126462306a36Sopenharmony_ci	spin_unlock_bh(&sess->conn_lock);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	iscsi_dump_sess_ops(sess->sess_ops);
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ciint rx_data(
127062306a36Sopenharmony_ci	struct iscsit_conn *conn,
127162306a36Sopenharmony_ci	struct kvec *iov,
127262306a36Sopenharmony_ci	int iov_count,
127362306a36Sopenharmony_ci	int data)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	int rx_loop = 0, total_rx = 0;
127662306a36Sopenharmony_ci	struct msghdr msg;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (!conn || !conn->sock || !conn->conn_ops)
127962306a36Sopenharmony_ci		return -1;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct msghdr));
128262306a36Sopenharmony_ci	iov_iter_kvec(&msg.msg_iter, ITER_DEST, iov, iov_count, data);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	while (msg_data_left(&msg)) {
128562306a36Sopenharmony_ci		rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
128662306a36Sopenharmony_ci		if (rx_loop <= 0) {
128762306a36Sopenharmony_ci			pr_debug("rx_loop: %d total_rx: %d\n",
128862306a36Sopenharmony_ci				rx_loop, total_rx);
128962306a36Sopenharmony_ci			return rx_loop;
129062306a36Sopenharmony_ci		}
129162306a36Sopenharmony_ci		total_rx += rx_loop;
129262306a36Sopenharmony_ci		pr_debug("rx_loop: %d, total_rx: %d, data: %d\n",
129362306a36Sopenharmony_ci				rx_loop, total_rx, data);
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return total_rx;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ciint tx_data(
130062306a36Sopenharmony_ci	struct iscsit_conn *conn,
130162306a36Sopenharmony_ci	struct kvec *iov,
130262306a36Sopenharmony_ci	int iov_count,
130362306a36Sopenharmony_ci	int data)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct msghdr msg;
130662306a36Sopenharmony_ci	int total_tx = 0;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!conn || !conn->sock || !conn->conn_ops)
130962306a36Sopenharmony_ci		return -1;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (data <= 0) {
131262306a36Sopenharmony_ci		pr_err("Data length is: %d\n", data);
131362306a36Sopenharmony_ci		return -1;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct msghdr));
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, iov_count, data);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	while (msg_data_left(&msg)) {
132162306a36Sopenharmony_ci		int tx_loop = sock_sendmsg(conn->sock, &msg);
132262306a36Sopenharmony_ci		if (tx_loop <= 0) {
132362306a36Sopenharmony_ci			pr_debug("tx_loop: %d total_tx %d\n",
132462306a36Sopenharmony_ci				tx_loop, total_tx);
132562306a36Sopenharmony_ci			return tx_loop;
132662306a36Sopenharmony_ci		}
132762306a36Sopenharmony_ci		total_tx += tx_loop;
132862306a36Sopenharmony_ci		pr_debug("tx_loop: %d, total_tx: %d, data: %d\n",
132962306a36Sopenharmony_ci					tx_loop, total_tx, data);
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	return total_tx;
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_civoid iscsit_collect_login_stats(
133662306a36Sopenharmony_ci	struct iscsit_conn *conn,
133762306a36Sopenharmony_ci	u8 status_class,
133862306a36Sopenharmony_ci	u8 status_detail)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct iscsi_param *intrname = NULL;
134162306a36Sopenharmony_ci	struct iscsi_tiqn *tiqn;
134262306a36Sopenharmony_ci	struct iscsi_login_stats *ls;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	tiqn = iscsit_snmp_get_tiqn(conn);
134562306a36Sopenharmony_ci	if (!tiqn)
134662306a36Sopenharmony_ci		return;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	ls = &tiqn->login_stats;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	spin_lock(&ls->lock);
135162306a36Sopenharmony_ci	if (status_class == ISCSI_STATUS_CLS_SUCCESS)
135262306a36Sopenharmony_ci		ls->accepts++;
135362306a36Sopenharmony_ci	else if (status_class == ISCSI_STATUS_CLS_REDIRECT) {
135462306a36Sopenharmony_ci		ls->redirects++;
135562306a36Sopenharmony_ci		ls->last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT;
135662306a36Sopenharmony_ci	} else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR)  &&
135762306a36Sopenharmony_ci		 (status_detail == ISCSI_LOGIN_STATUS_AUTH_FAILED)) {
135862306a36Sopenharmony_ci		ls->authenticate_fails++;
135962306a36Sopenharmony_ci		ls->last_fail_type =  ISCSI_LOGIN_FAIL_AUTHENTICATE;
136062306a36Sopenharmony_ci	} else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR)  &&
136162306a36Sopenharmony_ci		 (status_detail == ISCSI_LOGIN_STATUS_TGT_FORBIDDEN)) {
136262306a36Sopenharmony_ci		ls->authorize_fails++;
136362306a36Sopenharmony_ci		ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE;
136462306a36Sopenharmony_ci	} else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) &&
136562306a36Sopenharmony_ci		 (status_detail == ISCSI_LOGIN_STATUS_INIT_ERR)) {
136662306a36Sopenharmony_ci		ls->negotiate_fails++;
136762306a36Sopenharmony_ci		ls->last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE;
136862306a36Sopenharmony_ci	} else {
136962306a36Sopenharmony_ci		ls->other_fails++;
137062306a36Sopenharmony_ci		ls->last_fail_type = ISCSI_LOGIN_FAIL_OTHER;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	/* Save initiator name, ip address and time, if it is a failed login */
137462306a36Sopenharmony_ci	if (status_class != ISCSI_STATUS_CLS_SUCCESS) {
137562306a36Sopenharmony_ci		if (conn->param_list)
137662306a36Sopenharmony_ci			intrname = iscsi_find_param_from_key(INITIATORNAME,
137762306a36Sopenharmony_ci							     conn->param_list);
137862306a36Sopenharmony_ci		strscpy(ls->last_intr_fail_name,
137962306a36Sopenharmony_ci		       (intrname ? intrname->value : "Unknown"),
138062306a36Sopenharmony_ci		       sizeof(ls->last_intr_fail_name));
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci		ls->last_intr_fail_ip_family = conn->login_family;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci		ls->last_intr_fail_sockaddr = conn->login_sockaddr;
138562306a36Sopenharmony_ci		ls->last_fail_time = get_jiffies_64();
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	spin_unlock(&ls->lock);
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistruct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsit_conn *conn)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct iscsi_portal_group *tpg;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (!conn)
139662306a36Sopenharmony_ci		return NULL;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	tpg = conn->tpg;
139962306a36Sopenharmony_ci	if (!tpg)
140062306a36Sopenharmony_ci		return NULL;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (!tpg->tpg_tiqn)
140362306a36Sopenharmony_ci		return NULL;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	return tpg->tpg_tiqn;
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_civoid iscsit_fill_cxn_timeout_err_stats(struct iscsit_session *sess)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	struct iscsi_portal_group *tpg = sess->tpg;
141162306a36Sopenharmony_ci	struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (!tiqn)
141462306a36Sopenharmony_ci		return;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	spin_lock_bh(&tiqn->sess_err_stats.lock);
141762306a36Sopenharmony_ci	strscpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
141862306a36Sopenharmony_ci			sess->sess_ops->InitiatorName,
141962306a36Sopenharmony_ci			sizeof(tiqn->sess_err_stats.last_sess_fail_rem_name));
142062306a36Sopenharmony_ci	tiqn->sess_err_stats.last_sess_failure_type =
142162306a36Sopenharmony_ci			ISCSI_SESS_ERR_CXN_TIMEOUT;
142262306a36Sopenharmony_ci	tiqn->sess_err_stats.cxn_timeout_errors++;
142362306a36Sopenharmony_ci	atomic_long_inc(&sess->conn_timeout_errors);
142462306a36Sopenharmony_ci	spin_unlock_bh(&tiqn->sess_err_stats.lock);
142562306a36Sopenharmony_ci}
1426