cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iscsi_target_datain_values.c (14151B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*******************************************************************************
      3 * This file contains the iSCSI Target DataIN value generation functions.
      4 *
      5 * (c) Copyright 2007-2013 Datera, Inc.
      6 *
      7 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
      8 *
      9 ******************************************************************************/
     10
     11#include <linux/slab.h>
     12#include <scsi/iscsi_proto.h>
     13#include <target/iscsi/iscsi_target_core.h>
     14#include "iscsi_target_seq_pdu_list.h"
     15#include "iscsi_target_erl1.h"
     16#include "iscsi_target_util.h"
     17#include "iscsi_target.h"
     18#include "iscsi_target_datain_values.h"
     19
     20struct iscsi_datain_req *iscsit_allocate_datain_req(void)
     21{
     22	struct iscsi_datain_req *dr;
     23
     24	dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
     25	if (!dr) {
     26		pr_err("Unable to allocate memory for"
     27				" struct iscsi_datain_req\n");
     28		return NULL;
     29	}
     30	INIT_LIST_HEAD(&dr->cmd_datain_node);
     31
     32	return dr;
     33}
     34
     35void iscsit_attach_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)
     36{
     37	spin_lock(&cmd->datain_lock);
     38	list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
     39	spin_unlock(&cmd->datain_lock);
     40}
     41
     42void iscsit_free_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)
     43{
     44	spin_lock(&cmd->datain_lock);
     45	list_del(&dr->cmd_datain_node);
     46	spin_unlock(&cmd->datain_lock);
     47
     48	kmem_cache_free(lio_dr_cache, dr);
     49}
     50
     51void iscsit_free_all_datain_reqs(struct iscsit_cmd *cmd)
     52{
     53	struct iscsi_datain_req *dr, *dr_tmp;
     54
     55	spin_lock(&cmd->datain_lock);
     56	list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
     57		list_del(&dr->cmd_datain_node);
     58		kmem_cache_free(lio_dr_cache, dr);
     59	}
     60	spin_unlock(&cmd->datain_lock);
     61}
     62
     63struct iscsi_datain_req *iscsit_get_datain_req(struct iscsit_cmd *cmd)
     64{
     65	if (list_empty(&cmd->datain_list)) {
     66		pr_err("cmd->datain_list is empty for ITT:"
     67			" 0x%08x\n", cmd->init_task_tag);
     68		return NULL;
     69	}
     70
     71	return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
     72				cmd_datain_node);
     73}
     74
     75/*
     76 *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
     77 */
     78static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
     79	struct iscsit_cmd *cmd,
     80	struct iscsi_datain *datain)
     81{
     82	u32 next_burst_len, read_data_done, read_data_left;
     83	struct iscsit_conn *conn = cmd->conn;
     84	struct iscsi_datain_req *dr;
     85
     86	dr = iscsit_get_datain_req(cmd);
     87	if (!dr)
     88		return NULL;
     89
     90	if (dr->recovery && dr->generate_recovery_values) {
     91		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
     92					cmd, dr) < 0)
     93			return NULL;
     94
     95		dr->generate_recovery_values = 0;
     96	}
     97
     98	next_burst_len = (!dr->recovery) ?
     99			cmd->next_burst_len : dr->next_burst_len;
    100	read_data_done = (!dr->recovery) ?
    101			cmd->read_data_done : dr->read_data_done;
    102
    103	read_data_left = (cmd->se_cmd.data_length - read_data_done);
    104	if (!read_data_left) {
    105		pr_err("ITT: 0x%08x read_data_left is zero!\n",
    106				cmd->init_task_tag);
    107		return NULL;
    108	}
    109
    110	if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
    111	    (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
    112	     next_burst_len))) {
    113		datain->length = read_data_left;
    114
    115		datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
    116		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    117			datain->flags |= ISCSI_FLAG_DATA_ACK;
    118	} else {
    119		if ((next_burst_len +
    120		     conn->conn_ops->MaxRecvDataSegmentLength) <
    121		     conn->sess->sess_ops->MaxBurstLength) {
    122			datain->length =
    123				conn->conn_ops->MaxRecvDataSegmentLength;
    124			next_burst_len += datain->length;
    125		} else {
    126			datain->length = (conn->sess->sess_ops->MaxBurstLength -
    127					  next_burst_len);
    128			next_burst_len = 0;
    129
    130			datain->flags |= ISCSI_FLAG_CMD_FINAL;
    131			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    132				datain->flags |= ISCSI_FLAG_DATA_ACK;
    133		}
    134	}
    135
    136	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
    137	datain->offset = read_data_done;
    138
    139	if (!dr->recovery) {
    140		cmd->next_burst_len = next_burst_len;
    141		cmd->read_data_done += datain->length;
    142	} else {
    143		dr->next_burst_len = next_burst_len;
    144		dr->read_data_done += datain->length;
    145	}
    146
    147	if (!dr->recovery) {
    148		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
    149			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
    150
    151		return dr;
    152	}
    153
    154	if (!dr->runlength) {
    155		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
    156			dr->dr_complete =
    157			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    158				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    159				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    160		}
    161	} else {
    162		if ((dr->begrun + dr->runlength) == dr->data_sn) {
    163			dr->dr_complete =
    164			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    165				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    166				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    167		}
    168	}
    169
    170	return dr;
    171}
    172
    173/*
    174 *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
    175 */
    176static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
    177	struct iscsit_cmd *cmd,
    178	struct iscsi_datain *datain)
    179{
    180	u32 offset, read_data_done, read_data_left, seq_send_order;
    181	struct iscsit_conn *conn = cmd->conn;
    182	struct iscsi_datain_req *dr;
    183	struct iscsi_seq *seq;
    184
    185	dr = iscsit_get_datain_req(cmd);
    186	if (!dr)
    187		return NULL;
    188
    189	if (dr->recovery && dr->generate_recovery_values) {
    190		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
    191					cmd, dr) < 0)
    192			return NULL;
    193
    194		dr->generate_recovery_values = 0;
    195	}
    196
    197	read_data_done = (!dr->recovery) ?
    198			cmd->read_data_done : dr->read_data_done;
    199	seq_send_order = (!dr->recovery) ?
    200			cmd->seq_send_order : dr->seq_send_order;
    201
    202	read_data_left = (cmd->se_cmd.data_length - read_data_done);
    203	if (!read_data_left) {
    204		pr_err("ITT: 0x%08x read_data_left is zero!\n",
    205				cmd->init_task_tag);
    206		return NULL;
    207	}
    208
    209	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
    210	if (!seq)
    211		return NULL;
    212
    213	seq->sent = 1;
    214
    215	if (!dr->recovery && !seq->next_burst_len)
    216		seq->first_datasn = cmd->data_sn;
    217
    218	offset = (seq->offset + seq->next_burst_len);
    219
    220	if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
    221	     cmd->se_cmd.data_length) {
    222		datain->length = (cmd->se_cmd.data_length - offset);
    223		datain->offset = offset;
    224
    225		datain->flags |= ISCSI_FLAG_CMD_FINAL;
    226		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    227			datain->flags |= ISCSI_FLAG_DATA_ACK;
    228
    229		seq->next_burst_len = 0;
    230		seq_send_order++;
    231	} else {
    232		if ((seq->next_burst_len +
    233		     conn->conn_ops->MaxRecvDataSegmentLength) <
    234		     conn->sess->sess_ops->MaxBurstLength) {
    235			datain->length =
    236				conn->conn_ops->MaxRecvDataSegmentLength;
    237			datain->offset = (seq->offset + seq->next_burst_len);
    238
    239			seq->next_burst_len += datain->length;
    240		} else {
    241			datain->length = (conn->sess->sess_ops->MaxBurstLength -
    242					  seq->next_burst_len);
    243			datain->offset = (seq->offset + seq->next_burst_len);
    244
    245			datain->flags |= ISCSI_FLAG_CMD_FINAL;
    246			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    247				datain->flags |= ISCSI_FLAG_DATA_ACK;
    248
    249			seq->next_burst_len = 0;
    250			seq_send_order++;
    251		}
    252	}
    253
    254	if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
    255		datain->flags |= ISCSI_FLAG_DATA_STATUS;
    256
    257	datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
    258	if (!dr->recovery) {
    259		cmd->seq_send_order = seq_send_order;
    260		cmd->read_data_done += datain->length;
    261	} else {
    262		dr->seq_send_order = seq_send_order;
    263		dr->read_data_done += datain->length;
    264	}
    265
    266	if (!dr->recovery) {
    267		if (datain->flags & ISCSI_FLAG_CMD_FINAL)
    268			seq->last_datasn = datain->data_sn;
    269		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
    270			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
    271
    272		return dr;
    273	}
    274
    275	if (!dr->runlength) {
    276		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
    277			dr->dr_complete =
    278			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    279				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    280				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    281		}
    282	} else {
    283		if ((dr->begrun + dr->runlength) == dr->data_sn) {
    284			dr->dr_complete =
    285			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    286				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    287				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    288		}
    289	}
    290
    291	return dr;
    292}
    293
    294/*
    295 *	For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
    296 */
    297static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
    298	struct iscsit_cmd *cmd,
    299	struct iscsi_datain *datain)
    300{
    301	u32 next_burst_len, read_data_done, read_data_left;
    302	struct iscsit_conn *conn = cmd->conn;
    303	struct iscsi_datain_req *dr;
    304	struct iscsi_pdu *pdu;
    305
    306	dr = iscsit_get_datain_req(cmd);
    307	if (!dr)
    308		return NULL;
    309
    310	if (dr->recovery && dr->generate_recovery_values) {
    311		if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
    312					cmd, dr) < 0)
    313			return NULL;
    314
    315		dr->generate_recovery_values = 0;
    316	}
    317
    318	next_burst_len = (!dr->recovery) ?
    319			cmd->next_burst_len : dr->next_burst_len;
    320	read_data_done = (!dr->recovery) ?
    321			cmd->read_data_done : dr->read_data_done;
    322
    323	read_data_left = (cmd->se_cmd.data_length - read_data_done);
    324	if (!read_data_left) {
    325		pr_err("ITT: 0x%08x read_data_left is zero!\n",
    326				cmd->init_task_tag);
    327		return dr;
    328	}
    329
    330	pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
    331	if (!pdu)
    332		return dr;
    333
    334	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
    335		pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
    336		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    337			pdu->flags |= ISCSI_FLAG_DATA_ACK;
    338
    339		next_burst_len = 0;
    340	} else {
    341		if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
    342		     conn->sess->sess_ops->MaxBurstLength)
    343			next_burst_len += pdu->length;
    344		else {
    345			pdu->flags |= ISCSI_FLAG_CMD_FINAL;
    346			if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    347				pdu->flags |= ISCSI_FLAG_DATA_ACK;
    348
    349			next_burst_len = 0;
    350		}
    351	}
    352
    353	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
    354	if (!dr->recovery) {
    355		cmd->next_burst_len = next_burst_len;
    356		cmd->read_data_done += pdu->length;
    357	} else {
    358		dr->next_burst_len = next_burst_len;
    359		dr->read_data_done += pdu->length;
    360	}
    361
    362	datain->flags = pdu->flags;
    363	datain->length = pdu->length;
    364	datain->offset = pdu->offset;
    365	datain->data_sn = pdu->data_sn;
    366
    367	if (!dr->recovery) {
    368		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
    369			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
    370
    371		return dr;
    372	}
    373
    374	if (!dr->runlength) {
    375		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
    376			dr->dr_complete =
    377			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    378				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    379				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    380		}
    381	} else {
    382		if ((dr->begrun + dr->runlength) == dr->data_sn) {
    383			dr->dr_complete =
    384			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    385				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    386				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    387		}
    388	}
    389
    390	return dr;
    391}
    392
    393/*
    394 *	For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
    395 */
    396static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
    397	struct iscsit_cmd *cmd,
    398	struct iscsi_datain *datain)
    399{
    400	u32 read_data_done, read_data_left, seq_send_order;
    401	struct iscsit_conn *conn = cmd->conn;
    402	struct iscsi_datain_req *dr;
    403	struct iscsi_pdu *pdu;
    404	struct iscsi_seq *seq = NULL;
    405
    406	dr = iscsit_get_datain_req(cmd);
    407	if (!dr)
    408		return NULL;
    409
    410	if (dr->recovery && dr->generate_recovery_values) {
    411		if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
    412					cmd, dr) < 0)
    413			return NULL;
    414
    415		dr->generate_recovery_values = 0;
    416	}
    417
    418	read_data_done = (!dr->recovery) ?
    419			cmd->read_data_done : dr->read_data_done;
    420	seq_send_order = (!dr->recovery) ?
    421			cmd->seq_send_order : dr->seq_send_order;
    422
    423	read_data_left = (cmd->se_cmd.data_length - read_data_done);
    424	if (!read_data_left) {
    425		pr_err("ITT: 0x%08x read_data_left is zero!\n",
    426				cmd->init_task_tag);
    427		return NULL;
    428	}
    429
    430	seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
    431	if (!seq)
    432		return NULL;
    433
    434	seq->sent = 1;
    435
    436	if (!dr->recovery && !seq->next_burst_len)
    437		seq->first_datasn = cmd->data_sn;
    438
    439	pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
    440	if (!pdu)
    441		return NULL;
    442
    443	if (seq->pdu_send_order == seq->pdu_count) {
    444		pdu->flags |= ISCSI_FLAG_CMD_FINAL;
    445		if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
    446			pdu->flags |= ISCSI_FLAG_DATA_ACK;
    447
    448		seq->next_burst_len = 0;
    449		seq_send_order++;
    450	} else
    451		seq->next_burst_len += pdu->length;
    452
    453	if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
    454		pdu->flags |= ISCSI_FLAG_DATA_STATUS;
    455
    456	pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
    457	if (!dr->recovery) {
    458		cmd->seq_send_order = seq_send_order;
    459		cmd->read_data_done += pdu->length;
    460	} else {
    461		dr->seq_send_order = seq_send_order;
    462		dr->read_data_done += pdu->length;
    463	}
    464
    465	datain->flags = pdu->flags;
    466	datain->length = pdu->length;
    467	datain->offset = pdu->offset;
    468	datain->data_sn = pdu->data_sn;
    469
    470	if (!dr->recovery) {
    471		if (datain->flags & ISCSI_FLAG_CMD_FINAL)
    472			seq->last_datasn = datain->data_sn;
    473		if (datain->flags & ISCSI_FLAG_DATA_STATUS)
    474			dr->dr_complete = DATAIN_COMPLETE_NORMAL;
    475
    476		return dr;
    477	}
    478
    479	if (!dr->runlength) {
    480		if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
    481			dr->dr_complete =
    482			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    483				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    484				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    485		}
    486	} else {
    487		if ((dr->begrun + dr->runlength) == dr->data_sn) {
    488			dr->dr_complete =
    489			    (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
    490				DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
    491				DATAIN_COMPLETE_CONNECTION_RECOVERY;
    492		}
    493	}
    494
    495	return dr;
    496}
    497
    498struct iscsi_datain_req *iscsit_get_datain_values(
    499	struct iscsit_cmd *cmd,
    500	struct iscsi_datain *datain)
    501{
    502	struct iscsit_conn *conn = cmd->conn;
    503
    504	if (conn->sess->sess_ops->DataSequenceInOrder &&
    505	    conn->sess->sess_ops->DataPDUInOrder)
    506		return iscsit_set_datain_values_yes_and_yes(cmd, datain);
    507	else if (!conn->sess->sess_ops->DataSequenceInOrder &&
    508		  conn->sess->sess_ops->DataPDUInOrder)
    509		return iscsit_set_datain_values_no_and_yes(cmd, datain);
    510	else if (conn->sess->sess_ops->DataSequenceInOrder &&
    511		 !conn->sess->sess_ops->DataPDUInOrder)
    512		return iscsit_set_datain_values_yes_and_no(cmd, datain);
    513	else if (!conn->sess->sess_ops->DataSequenceInOrder &&
    514		   !conn->sess->sess_ops->DataPDUInOrder)
    515		return iscsit_set_datain_values_no_and_no(cmd, datain);
    516
    517	return NULL;
    518}
    519EXPORT_SYMBOL(iscsit_get_datain_values);