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

📄 initiator_utilities.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	initiator/initiator_utilities.c * *	vi: set autoindent tabstop=8 shiftwidth=8 : * *	This file contains auxilliary functions for iscsi initiator code *	that are responsible for connecting and maintaining sessions *	between initiator and 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 of 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"/* holds bytes of zeros that are sent as pad bytes when needed */static __u32 pad_bytes = 0;/* allocates a new r2t cookie for this session * but only initializes the order_link thread in this structure */struct r2t_cookie * __attribute__ ((no_instrument_function))create_r2t_cookie(struct session *this_session){	struct r2t_cookie *cookie;	if (unlikely(list_empty(&this_session->free_r2t_cookies))) {		/* allocate a new r2t cookie */		cookie = (struct r2t_cookie *)			my_kmalloc(sizeof(struct r2t_cookie), "r2t cookie");		if (unlikely(cookie == NULL))			goto out;	} else {		/* remove an old r2t cookie from the free list and reuse it */		cookie = list_entry(this_session->free_r2t_cookies.next,				    struct r2t_cookie, link);		list_del(&cookie->link);	}	INIT_LIST_HEAD(&cookie->order_link);out:	return cookie;}/* finishes initializing an r2t cookie and adds it to end of command's * cookie list */void __attribute__ ((no_instrument_function))hookup_r2t_cookie(struct r2t_cookie *cookie,		  struct session *this_session,		  struct connection *this_connection,		  struct command *this_command,		  __u32 local_ttt){	cookie->target_xfer_tag = local_ttt;	if (local_ttt != ALL_ONES) {		/* this is a "real" (not implied) r2t.		 * count it and check number outstanding.		 */		this_command->n_r2t_cookies++;		if (unlikely(this_command->n_r2t_cookies >				this_session->oper_param->MaxOutstandingR2T)) {			/* too many outstanding R2Ts */			TRACE_ERROR("Target sent %u outstanding R2Ts, "				    "but MaxOutstandingR2T is %u\n",				    this_command->n_r2t_cookies,				    this_session->oper_param->				    MaxOutstandingR2T);			/* now ignore this, since we can handle it ok */		}	}	/* Draft 20, Section 10.7.5 DataSN	 * "For output (write) data PDUs, the DataSN is the Data-Out PDU number	 * within the current output sequence.  The current output sequence is	 * either identified by the Initiator Task Tag (for unsolicited data) or	 * is a data sequence generated for one R2T (for data solicited through	 * R2T)."	 *	 * Therefore, each R2T resets data_out_sn to 0.	 */	cookie->data_out_sn = 0;	/* Draft 20, Section 10.8 Ready to Transfer (R2T)	 * "The target may send several R2T PDUs.  It, therefore, can have a	 * number of pending data transfers.  The number of outstanding R2T	 * PDUs [per task] are limited by the value of the negotiated key	 * MaxOutstandingR2T.  Within a connection, outstanding R2Ts MUST be	 * fulfilled by the initiator in the order in which they were received."	 *	 * Therefore, each R2T gets put on ordered list within its connection.	 */	list_add_tail(&cookie->order_link, &this_connection->r2t_list);	/* Update command offset to that expected in next in-order R2T */	this_command->data_offset += cookie->r2t_xfer_length;	if (unlikely(this_session->oper_param->DataSequenceInOrder == 0)) {		/* DataSequenceInOrder==No */		merge_offset_length(&this_command->r2t_range_list,				    cookie->offset, cookie->r2t_xfer_length);	}	if (unlikely(this_session->oper_param->DataPDUInOrder == 0)) {		/* DataPDUInOrder==No, send Data Out PDUs backwards */		cookie->offset += cookie->r2t_xfer_length;      /* set limit */	}	/* add this to end of cookie list for this command */	list_add_tail(&cookie->link, &this_command->r2t_cookies);}/* put a no longer used cookie structure on available list for session */void __attribute__ ((no_instrument_function))uncreate_r2t_cookie(struct r2t_cookie *cookie, struct session *this_session){	/* remove this cookie from the ordered list of cookies	 * remaining to process on this connection	 */	list_del(&cookie->order_link);	list_add_tail(&cookie->link, &this_session->free_r2t_cookies);}/* removes cookie from this command's and this connection's cookie lists */void __attribute__ ((no_instrument_function))free_r2t_cookie(struct connection *this_connection,		struct command *this_command,		struct r2t_cookie *cookie){	if (cookie->target_xfer_tag != ALL_ONES) {		/* this is a "real" (not implied) r2t.			reduce number still outstanding */		/*   Draft 20 Section 12.17 MaxOutstandingR2T		 * "An R2T is considered outstanding until the last data		 * PDU (with the F bit set to 1) is transferred, or a		 * sequence reception timeout (Section 6.1.4.1 Recovery		 * Within-command) is encountered for that data		 * sequence."		 */		this_command->n_r2t_cookies--;	}	/* remove cookie from list of r2t cookies for this command */	list_del(&cookie->link);	/* then add it to front of list of available cookies */	uncreate_r2t_cookie(cookie, this_connection->my_session);}/* info - debug * keeps track of maximum  number of io vector slots actually used */int max_iov_count = 0;/* * executed by init_recovery thread, tx thread, scsi midlevel process. * the session->sess_lock MUST be held by the calling process/thread. * set up the transmit i/o vector for the iscsi header */static void __attribute__ ((no_instrument_function))setup_header_iovec(struct connection *conn, struct command *this_command){	this_command->data_offset = 0;	this_command->data_checksum = 0;	this_command->tx_size = conn->basic_hdr_len;	this_command->tx_iov->iov_base = &this_command->iscsi_cmd;	this_command->tx_iov->iov_len = conn->basic_hdr_len;	this_command->tx_iovlen = 1;}/* * executed only by tx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called by iscsi_initiator_tx_thread() and tx_retransmit_state1(). * build a SCSI Command with write data to be sent */voidbuild_write_command(struct session *current_session,		    struct connection *current_connection,		    struct command *new_command){	struct iovec *iov;	struct iscsi_init_scsi_cmnd *iscsi_cmd;	struct scsi_cmnd *Cmnd;	struct r2t_cookie *cookie;	int len, count = 1;	int negotiated_immediate_data_length;	int actual_immediate_data_length = 0;	int space_left;	Cmnd = new_command->SCpnt;	if (unlikely(Cmnd == NULL)) {		/* should never happen */		TRACE_ERROR("No SCpnt for command %p\n", new_command);		goto out;	}	/* first, set up the transmit i/o vector for the iscsi header */	setup_header_iovec(current_connection, new_command);	iscsi_cmd = &new_command->iscsi_cmd;	iscsi_cmd->flags = W_BIT;	if (Cmnd->request_bufflen		&& current_session->oper_param->ImmediateData) {		/* We are allowed to send immediate data.		 * get the smaller of target's MaxRecvDataSegmentLength or		 * FirstBurstLength		 */		negotiated_immediate_data_length			= current_connection->max_send_length;		if (negotiated_immediate_data_length			> current_session->oper_param->FirstBurstLength) {			negotiated_immediate_data_length			    = current_session->oper_param->FirstBurstLength;		}		/* Actual datalength to be sent as immediate data is minimum of		 * what command wants to send and the negotiated mimimum allowed		 * for immediate data		 */		actual_immediate_data_length = Cmnd->request_bufflen;		if (actual_immediate_data_length			> negotiated_immediate_data_length)			actual_immediate_data_length				= negotiated_immediate_data_length;		TRACE(TRACE_DEBUG, "Sending immediate data %d\n",		      actual_immediate_data_length);		/* get pointer to tx i/o vector (which is already set up		 * for header)		 */		iov = new_command->tx_iov;		if (Cmnd->use_sg > 0) {			/* we have a scatter gather list to be sent */			int immediate_data_to_be_filled				= actual_immediate_data_length;			struct scatterlist *sg				= (struct scatterlist *) Cmnd->request_buffer;#ifdef K26			if (use_sendpage(current_connection, new_command)) {				new_command->pindex = 0;				new_command->padding = 0;			}#endif			while (immediate_data_to_be_filled > 0) {				/* set up iovector to send immediate_data */				count++;				iov++;#ifdef K26				/* Convert page struct passed in SG				 * to kernel vaddr. We can sleep on this				 * call so have to release our lock.				 */				UNH_UNLOCK(&current_session->sess_lock, 					current_connection->tx_lock_flags);				sg_dma_address(sg) = (dma_addr_t)kmap(sg->page);				UNH_LOCK(&current_session->sess_lock, 					current_connection->tx_lock_flags);											sg_dma_address(sg) += sg->offset;				TRACE(TRACE_DEBUG,				      "sg %p sg_address %x sg_length %d "				      "immediate_data_filled %d\n",				      sg, sg_dma_address(sg), sg_dma_len(sg),				      immediate_data_to_be_filled);				iov->iov_base					 = (unsigned long *)sg_dma_address(sg);				iov->iov_len = sg_dma_len(sg);				immediate_data_to_be_filled -= sg_dma_len(sg);				if (use_sendpage(current_connection, new_command)) {					new_command->sg[new_command->pindex] = *sg;					new_command->pindex++;				}#else				TRACE(TRACE_DEBUG,				      "sg_address %p sg_length %d "				      "immediate_data_filled %d\n",				      sg->address, sg->length,				      immediate_data_to_be_filled);				iov->iov_base = sg->address;				iov->iov_len = sg->length;				immediate_data_to_be_filled -= sg->length;#endif				if (immediate_data_to_be_filled < 0) {					/* went too far, last element					 * needs to be shortened					 */					iov->iov_len						+= immediate_data_to_be_filled;				}				/* compute the partial data digest if we				 * are using them				 */				if (current_connection->connection_flags					& USE_DATADIGEST) {					do_crc(iov->iov_base, iov->iov_len,					       &new_command->data_checksum);				}				sg++;			}		} else {			/* we have single buffer passed from SCSI Mid-level */			count++;			iov++;			iov->iov_len = actual_immediate_data_length;			iov->iov_base = Cmnd->request_buffer;			/* compute the data digest if we are using them */			if (current_connection->connection_flags				& USE_DATADIGEST) {				do_crc(iov->iov_base, iov->iov_len,				       &new_command->data_checksum);			}		}		iscsi_cmd->length = htonl(actual_immediate_data_length);		new_command->tx_data_length = actual_immediate_data_length;		new_command->tx_size += actual_immediate_data_length;		new_command->data_offset = actual_immediate_data_length;		if (unlikely(current_session->oper_param->DataSequenceInOrder									== 0)) {			/* DataSequenceInOrder==No */			merge_offset_length(&new_command->r2t_range_list,					    0, actual_immediate_data_length);		}		/* now deal with any padding that is needed		 *		 * Draft 20, Section 10.1 iSCSI PDU Length and Padding		 * "iSCSI PDUs are padded to the closest integer number of		 * four byte words.  The padding bytes SHOULD be sent as 0."		 */		len = (-actual_immediate_data_length) & 3;		if (unlikely(len != 0)) {			/* send len pad bytes in another element in iovector */			count++;			iov++;			iov->iov_base = &pad_bytes;			iov->iov_len = len;			new_command->tx_size += len;	/* now a multiple of 4*/			TRACE(TRACE_ISCSI_FULL, "Attach %d pad bytes\n", len);			/* compute partial data digest if we are using them */			if (current_connection->connection_flags				& USE_DATADIGEST) {				do_crc(iov->iov_base, iov->iov_len,				       &new_command->data_checksum);			}#ifdef K26			if (use_sendpage(current_connection, new_command))				new_command->padding = len;#endif		}		/* if data digests are in use, be sure to set it up now */		if (current_connection->connection_flags & USE_DATADIGEST) {			count++;			iov++;			iov->iov_base = &new_command->data_checksum;			iov->iov_len = CRC_LEN;			new_command->tx_size += CRC_LEN;			TRACE(TRACE_ISCSI_FULL, "Attach DataDigest\n");		}	}	/* total number of data bytes left to send by this write command */	new_command->still_to_send = Cmnd->request_bufflen						- actual_immediate_data_length;	/* number of bytes that could go into first burst as unsolicited */

⌨️ 快捷键说明

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