⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 initiator_rx.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	initiator/initiator_rx.c * *	vi: set autoindent tabstop=8 shiftwidth=8 : * *	This file contains the functions for iscsi initiator code that are *	responsible for reading and processing PDUs sent by the target. * *	Copyright (C) 2001-2004 InterOperability Lab (IOL) *	University of New Hampshire (UNH) *	Durham, NH 03824 * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2, or (at your option) *	any later version. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, *	USA. * *	The name IOL and/or UNH may not be used to endorse or promote  *	products derived from this software without specific prior  * 	written permission.*/#include "iscsi_initiator.h"#include "initiator_utilities.h"#include "initiator_error_rec.h"#include "../common/lun_packing.h"/* attributes for each opcode that can be received from target */#define ITT_OPTIONAL	0x0000#define ITT_REQUIRED	0x0100#define ITT_RESERVED	0x0200#define ITT_MASK	0x0300#define F_MUST_BE_1	0x0400#define ILLEGAL_REPLY	0x0800#define DSL_MUST_BE_0	0x1000#define LUN_MUST_BE_0	0x2000/* table of attributes (in byte 1) and related opcode (in byte 0) * for each opcode that can be received from target */static __u16 opcode_attributes[32] = {/* 0x20	NopIn ==> NopOut */	F_MUST_BE_1 | ITT_OPTIONAL | ISCSI_INIT_NOP_OUT,/* 0x21	SCSI Response ==> SCSI Command */	LUN_MUST_BE_0 | F_MUST_BE_1 | ITT_REQUIRED | ISCSI_INIT_SCSI_CMND,/* 0x22	Task Management Response ==> Task Management Request */	LUN_MUST_BE_0 | DSL_MUST_BE_0 | F_MUST_BE_1 | ITT_REQUIRED						| ISCSI_INIT_TASK_MGMT_CMND,/* 0x23	Login Response ==>Login Request */	ITT_REQUIRED | ISCSI_INIT_LOGIN_CMND,/* 0x24	Text Response ==>Text Request */	ITT_REQUIRED | ISCSI_INIT_TEXT_CMND,/* 0x25	DataIn ==> SCSI Command */	ITT_REQUIRED | ISCSI_INIT_SCSI_CMND,/* 0x26	Logout Response ==> Logout Request */	LUN_MUST_BE_0 | DSL_MUST_BE_0 | F_MUST_BE_1 | ITT_REQUIRED						| ISCSI_INIT_LOGOUT_CMND,/* 0x27 */ ILLEGAL_REPLY,/* 0x28 */ ILLEGAL_REPLY,/* 0x29 */ ILLEGAL_REPLY,/* 0x2a */ ILLEGAL_REPLY,/* 0x2b */ ILLEGAL_REPLY,/* 0x2c */ ILLEGAL_REPLY,/* 0x2d */ ILLEGAL_REPLY,/* 0x2e */ ILLEGAL_REPLY,/* 0x2f */ ILLEGAL_REPLY,/* 0x30 */ ILLEGAL_REPLY,/* 0x31	R2T ==> SCSI Command */	DSL_MUST_BE_0 | F_MUST_BE_1 | ITT_REQUIRED | ISCSI_INIT_SCSI_CMND,/* 0x32	Asynch ==> -none- */	F_MUST_BE_1 | ITT_RESERVED,/* 0x33 */ ILLEGAL_REPLY,/* 0x34 */ ILLEGAL_REPLY,/* 0x35 */ ILLEGAL_REPLY,/* 0x36 */ ILLEGAL_REPLY,/* 0x37 */ ILLEGAL_REPLY,/* 0x38 */ ILLEGAL_REPLY,/* 0x39 */ ILLEGAL_REPLY,/* 0x3a */ ILLEGAL_REPLY,/* 0x3b */ ILLEGAL_REPLY,/* 0x3c */ ILLEGAL_REPLY,/* 0x3d */ ILLEGAL_REPLY,/* 0x3e */ ILLEGAL_REPLY,/* 0x3f	Reject ==> -none- */	LUN_MUST_BE_0 | F_MUST_BE_1 | ITT_RESERVED};#ifdef ISCSI_CHECK_PDU_FORMAT/* utility function called by all rx___() functions when they * determine that their reserved fields are not all 0 */static void __attribute__ ((no_instrument_function))reserved_not_0(char *pdu_name){	if (TRACE_TEST(TRACE_ISCSI)) {		TRACE_WARNING("reserved fields in %s header not all 0\n",			      pdu_name);	}}#endifstatic void __attribute__ ((no_instrument_function))debug_print_ip(struct connection *conn, char *message){	char ip_string[INET6_ADDRSTRLEN+2], port_string[8];	if (cnv_inet_to_string(conn->ip_address, ip_string, port_string) > 0) {		TRACE(TRACE_DEBUG, "%s from %s:%s\n", message,							ip_string, port_string);	}}/* * searches conn's pending_commands list for a command with init_task_tag that * matches this_itt. * returns pointer to that command if found, *	   NULL if not found */static inline struct command * __attribute__ ((no_instrument_function))find_command_by_itt(__u32 this_itt, struct connection *conn){	struct command *cmd;	list_for_each_entry(cmd, &conn->pending_commands, link) {		if (cmd->init_task_tag == this_itt) {			return cmd;		}	}	return NULL;}/**************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the DataIn payload of a DataIn PDU. It fills the * scatter-gather buffers provided by the SCSI Mid-level. The data digest * is also checked (if such checking has been enabled). * * Parameters:	- current_connection which is a ptr to the struct where the SCSI *				DataIn Header was received. *		- related_command which is a ptr to the struct for the SCSI READ *				command to which this DataIn is related. * Return Value: >0 success, session lock is locked *		 =0 failure, session lock is locked *		 <0 failure, session lock is NOT locked * * While reading, the following variables in the related_command maintain state: *	r2t_range_list.limit	sum of the size of all finally accepted DataIn *				pdus in command -- incremented by size of *				every good recvd data-in pdu that will not be *				retransmitted later. *	r2t_range_list.offset	offset to first DataIN pdu in current sequence. *				set at start of an out-of-order seq if *				in-order pdus. set at end of sequence *				of out-of-order pdus *	data_offset		expected offset in next in-order DataIn pdu *				incremented by size of every recvd DataIn pdu. *				set at start of an out-of-order sequence *	recvd_length		sum of size of recvd data-in pdus in this *				sequence incremented by size of every recvd *				data-in pdu reset to 0 at end of each sequence . *				used to test for start of a new sequence when 0. *	pdu_range_list.limit	largest limit of any out-of-order pdu *				in current seq . *	pdu_range_list.offset	smallest offset of any out-of-order pdu in *				cur seq used to set r2t_range_list.offset at *				end of seq. ****************************************************************/static intrx_data(struct connection *current_connection,	__u32 local_itt, struct command *related_command,	__u32 size, char *string){	struct iscsi_targ_scsi_data_in *data_in_header;	int received = 1, delta;	int over_flow_data_size = 0;	struct session *related_session;	struct init_error_rec err_rec;	char *over_flow_buffer = NULL;	__u32 lun;	__u32 sg_size;	TRACE(TRACE_ENTER_LEAVE, "Enter rx_data, current_connection %p\n",	      current_connection);	data_in_header = (struct iscsi_targ_scsi_data_in *)						current_connection->rx_buf;	sg_size = 0;	if (likely(related_command != NULL && related_command->SCpnt != NULL))		sg_size = related_command->SCpnt->use_sg;	related_session = current_connection->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT	/* Check if reserved fields are zero or not */	if (unlikely(!((data_in_header->rsvd1 == 0)	      && ((data_in_header->flags & (W_BIT|BRO_BIT|BRU_BIT)) == 0)))) {		reserved_not_0("SCSI DataIn");	}#endif	if (unlikely(data_in_header->flags & A_BIT)) {		/* A bit is 1 -- MUST have ErrorRecoveryLevel > 0,				and TTT and LUN must be valid */		/* Draft 20, Section 10.7.2 A (Acknowledge) bit		 * "The Target MUST NOT set to 1 the A bit for sessions with		 * ErrorRecoveryLevel=0.  The initiator MUST ignore the A bit		 * set to 1 for sessions with ErrorRecoveryLevel=0.		 */		if (related_session->oper_param->ErrorRecoveryLevel == 0) {			TRACE_WARNING("Ignoring A_Bit=1 in DataIn, ITT %u, with"					" ErrorRecoveryLevel=0\n", local_itt);		}		/* Draft 20, Section 10.7.4 Target Transfer Tag and LUN		 * "On incoming data, the Target Transfer Tag and LUN MUST be		 * provided by the target if the A bit is set to 1; otherwise		 * they are reserved. ...		 *		 * The Target Transfer Tag values are not specified by this		 * protocol except that the value 0xffffffff is reserved and		 * means that the Target Transfer Tag is not supplied.  If the		 * Target Transfer Tag is provided, then the LUN field MUST hold		 * a valid value and be consistent with whatever was specified		 * with the command; otherwise, the LUN field is reserved."		 */		if (data_in_header->target_xfer_tag == ALL_ONES) {			/* TTT is reserved, this is an error */			TRACE_ERROR			    ("DataIn with A bit = 1 has reserved TTT 0x%08x, "			     "expected valid value\n", ALL_ONES);		} else if (related_command != NULL &&				related_command->SCpnt != NULL) {			/* TTT is valid, LUN must be same as in related Cmnd */			lun = unpack_lun((__u8 *) & data_in_header->lun);/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26			if (lun != related_command->SCpnt->device->lun) {				TRACE_ERROR(				  "DataIn for ITT %u has LUN %u, expected %u\n",				  local_itt, lun,				  related_command->SCpnt->device->lun);			}#else			if (lun != related_command->SCpnt->lun) {				TRACE_ERROR(				  "DataIn for ITT %u has LUN %u, expected %u\n",				  local_itt, lun,				  related_command->SCpnt->lun);			}			/* else LUN matches the command's LUN, all ok */#endif		}	} else {		/* A bit is 0 -- TTT can be reserved, doesn't have to be */		if (data_in_header->target_xfer_tag == ALL_ONES) {			/* TTT is reserved */			if (unlikely(data_in_header->lun != 0LL)) {				/* TTT is reserved, LUN is not, that's bad */				TRACE_ERROR("DataIn with reserved TTT 0x%08x, "					    "non-reserved LUN %s\n",					    ALL_ONES,					    string_llx(data_in_header->lun,					    			string));			}			/* else LUN is also reserved, all ok */		} else if (related_command != NULL &&				related_command->SCpnt != NULL) {					/* TTT has valid value, LUN must						be same as in related Cmnd */			lun = unpack_lun((__u8 *) & data_in_header->lun);/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26			if (unlikely(lun != related_command							->SCpnt->device->lun)) {				TRACE_ERROR				    ("DataIn with ITT %u has invalid LUN %u, "				     "expected %u\n", local_itt, lun,				     related_command->SCpnt->device->lun);			}#else			if (unlikely(lun != related_command->SCpnt->lun)) {				TRACE_ERROR				    ("DataIn with ITT %u has invalid LUN %u, "				     "expected %u\n", local_itt, lun,				     related_command->SCpnt->lun);			}#endif		}	}#ifdef ISCSI_CHECK_PDU_FORMAT	if (data_in_header->flags & S_BIT) {		/* this command is a "phase collapse" with "good" status */		if (unlikely(!(data_in_header->flags & F_BIT))) {			/* F bit not set, but it should be when S bit is set */			/* Draft 20, Section 10.7.3 Flags (byte 1)			 * "bit 7 S (status) - set to indicate that the Command			 * Status field contains status.  If this bit is set			 * to 1, the F bit MUST also be set to 1."			 */			TRACE_ERROR(			    "DataIn with ITT %u, S bit = 1 has F Bit = 0, "			    "expected 1\n", local_itt);		}	}#endif	data_in_header->offset = ntohl(data_in_header->offset);	data_in_header->data_sn = ntohl(data_in_header->data_sn);	if (unlikely(related_command==NULL || related_command->SCpnt==NULL)) {		/* We lost the ptr to the command or to the SCSI		   Midlevel struct, can't do anything */		TRACE(TRACE_ERROR_RECOVERY,		      "No related command/SCpnt: ITT %u, size %u, offset %u, "		      "DataSN %u\n", local_itt, size, data_in_header->offset,		      data_in_header->data_sn);		if (size > 0) {			/* read in and ignore this PDU's data payload */			received = recv_ignore_data(current_connection, size);		}	} else {		/* have matched the DataIn to a legitimate SCSI READ request */		/* Check if DataSN field in header is what we expected */		delta = data_in_header->data_sn - related_command->data_in_sn;		if (unlikely(delta != 0)) {			TRACE_ERROR("DataIn with ITT %u, got DataSN %u, "				    "expected %u\n", local_itt,				    data_in_header->data_sn,				    related_command->data_in_sn);			if (delta < 0) {				/* duplicate DataSn, just silently ignore					this PDU */				if (size > 0) {					/* read in and ignore this PDU's						data payload */					received = recv_ignore_data(						current_connection,						size);				}				goto out;			} else {				/* DataIn PDU Sequence Error - SAI */				err_rec.curr_conn = current_connection;				err_rec.related_cmd = related_command;				err_rec.err_type = SEQUENCE_ERR;				if ((received				       = init_do_error_recovery(&err_rec)) <= 0)					goto out;				/* Fall thru and use this out-of-order data.				 * Force the expected data offset to the				 * one received in order to avoid a				 * cascade of error messages.				 */				related_command->data_offset						= data_in_header->offset;				/* for the same reason, force the start					of a new sequence */				related_command->recvd_length = 0;			}		}		/* Draft 20, Section 10.7.1 F (Final) Bit		 * "Splitting the data stream into sequences does not affect		 * DataSN counting on Data-In PDUs."		 *		 * Draft 20, Section 10.7.5 DataSN		 * "For input (read) or bidirectional Data-IN PDUs, the DataSN		 * is the input PDU number within the data transfer for the		 * command identified by the Initiator Task Tag."		 *		 * Therefore, we do not reset data_in_sn at the end of a data-in		 * sequence -- it continues incrementing over all data-in		 * sequence boundaries.		 */		related_command->data_in_sn++;		/* Check if we are overflowing the SCSI Mid-level buffers */		if (unlikely((over_flow_data_size = data_in_header->offset			+ size - related_command->SCpnt->request_bufflen) > 0)){			TRACE_ERROR("DataIn with ITT %u, Received buffer size "				   "%u bytes will overflow SCSI buffer by %d\n",				   local_itt, size, over_flow_data_size);			if (related_command->SCpnt->request_bufflen						> data_in_header->offset)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -