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

📄 initiator_tx.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	initiator/initiator_tx.c *  *	vi: set autoindent tabstop=8 shiftwidth=8 : * *	This file contains the functions for iscsi initiator code that are *	responsible for building and sending PDUS to a 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"/* * executed by rx thread or tx thread or command process. * the current_session->sess_lock MUST be held by the calling process/thread. * Called by drive_text_negotiate() and tx_nopout(). * add padding bytes, if necessary, to buffer which already has size bytes * update the command's iov and msghdr to point at this buffer * then compute and add data digest, if necessary * * 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." */static voidadd_padding(struct connection *current_connection,	    struct command *new_command, char *buffer, int size){	int n;	struct iovec *iov;	n = (-size) & 3;	if (unlikely(n != 0)) {		TRACE(TRACE_ISCSI_FULL, "Attach %u pad bytes\n", n);		memset(buffer + size, 0, n);		size += n;	}	/* get ptr to i/o vector which is already set up for header */	iov = new_command->tx_iov + new_command->tx_iovlen;	iov->iov_base = buffer;	iov->iov_len = size;	new_command->tx_size += size;	new_command->tx_iovlen++;	/* compute the final data digest if we are using them */	if (current_connection->connection_flags & USE_DATADIGEST) {		new_command->data_checksum = 0;		do_crc(iov->iov_base, iov->iov_len,		       &new_command->data_checksum);		iov++;		iov->iov_base = &new_command->data_checksum;		iov->iov_len = CRC_LEN;		new_command->tx_size += CRC_LEN;		new_command->tx_iovlen++;		TRACE(TRACE_ISCSI_FULL, "Attach DataDigest\n");	}}/* * executed by rx thread or tx thread or command process. * the current_session->sess_lock MUST be held by the calling process/thread. * Called to send a NopOut to target as: * 	a new nop (nopin_cmd == NULL, size == 0 ) * or * 	a new ping (nopin_cmd == NULL, size != 0 ) * or * 	a response to a NopIn (nopin_cmd != NULL). * Buffer points to data to send, and size is number of bytes * of data to send. * If size > 0 then better have buffer != NULL. * Returns 1 if all ok, else 0. */inttx_nopout(struct connection *current_connection, __u32 i_bit,	  struct iscsi_targ_nopin *nopin_cmd, char **buffer, int size){	int need_itt, retval = 1;	struct command *new_command;	struct iscsi_init_nopout *nopout_cmd;	TRACE(TRACE_ENTER_LEAVE, "Enter tx_nopout, size = %d\n", size);	new_command = setup_command(NULL, current_connection);	if (unlikely(new_command == NULL)) {		/* will not be able to send the nop */		retval = 0;		goto out;	}	/* set up the NopOut header (Draft 20, Section 10.18)	 * to be sent to the target	 */	nopout_cmd = (struct iscsi_init_nopout *)&new_command->iscsi_cmd;	nopout_cmd->opcode = ISCSI_INIT_NOP_OUT | i_bit;	nopout_cmd->flags = F_BIT;	/* always set on NopOut */	if (size > 0) {		/* we have data to send to target */		nopout_cmd->length = htonl(size);		/* now add padding bytes and data digest, if necessary */		add_padding(current_connection, new_command, *buffer, size);		/* mark that buffer will be freed in tx thread,		 * after NopOut is sent		 */		new_command->buffer_to_free = *buffer;		*buffer = NULL;	}	/* Draft 20, Section 10.18.2 Target Transfer Tag	 * "The NOP-Out MUST only have the Target Transfer Tag set if it is	 * issued in response to a NOP-In with a valid Target Transfer Tag.	 * In this case, it copies the Target Transfer Tag from the NOP-In PDU.	 * Otherwise, the Target Transfer Tag MUST be set to 0xffffffff.	 *	 * When the Target Transfer Tag is set to a value other than 0xffffffff,	 * the LUN field MUST also be copied from the NOP-In."	 */	if (nopin_cmd != NULL) {		/* this is a response to a NopIn from the target */		nopout_cmd->target_xfer_tag = nopin_cmd->target_xfer_tag;		nopout_cmd->lun = nopin_cmd->lun;		need_itt = 0;	/* need to set ITT to 0xffffffff */	} else {		/* this is a new nop or nop ping command to the target */		nopout_cmd->target_xfer_tag = ALL_ONES;		/*  Draft 20, Section 10.18.1 Initiator Task Tag		 * "The NOP-Out MUST have the Initiator Task Tag set to		 * a valid value only if a response in the form of		 * NOP-In is requested (i.e., the NOP-Out is used as a		 * ping request).  Otherwise, the Initiator Task		 * Tag MUST be set to 0xffffffff."		 */		if (size == 0) {			need_itt = 0;		} else {			need_itt = 1;	/* set ITT to next in sequence */		}	}	/* attach the new NopOut command to end of pending commands list.	 * This also sets the ITT, the I bit if needed, and the CmdSN.	 */	attach_pending_command(new_command, current_connection, need_itt);out:	TRACE(TRACE_ENTER_LEAVE, "Leave tx_nopout\n");	return retval;}static void deal_with_tx_timer(unsigned long data);/* * (re)start the tx timer -- period is always 1 second */static void __attribute__ ((no_instrument_function))restart_tx_timer(struct connection *conn){	if (likely(!timer_pending(&conn->tx_timer)	    && !(conn->connection_flags & TX_TIMER_OFF))) {		TRACE(TRACE_TIMERS, "Start timer for %u ticks for conn %u\n",		      HZ, conn->connection_id);		conn->tx_timer.expires = jiffies + HZ;		conn->tx_timer.data = (__u32) conn;		conn->tx_timer.function = deal_with_tx_timer;		add_timer(&conn->tx_timer);	} else {		/* no timer or timer already going or timer should be		 * stopped, don't (re)start it now		 */		TRACE(TRACE_TIMERS, "Timer not restarted for conn %u\n",		      conn->connection_id);	}}/* * Called by kernel when periodic session timer expires */static voiddeal_with_tx_timer(unsigned long data){	struct connection *conn;	conn = (struct connection *) data;	/* get the tx thread started, if necessary */	/* if( sem_getcount(&conn->tx_sem) <= 0 ) */	if (atomic_read(&conn->tx_sem.count) <= 0) {		TRACE(TRACE_TIMERS, "tx_timer: wake up tx thread\n");		up(&conn->tx_sem);	}	/* mark that the timer went off and keep it going */	atomic_inc(&conn->tx_timer_went_off);	restart_tx_timer(conn);}/* * executed by tx thread or command process. * the current_session->sess_lock MUST be held by the calling process/thread. * Called by do_test(), iscsi_initiator_tx_thread(), tx_retransmit_state2(). * drives sending of a nop out to the target * returns 0 on success, -1 on error */intdrive_nopout(struct connection *conn, struct session *current_session,	     __u32 i_bit, __u32 want_data){	char *buffer;	int size;	TRACE(TRACE_ENTER_LEAVE, "Enter drive_nopout\n");	if (!want_data) {		/* don't want any data attached to this nop out */		buffer = NULL;		if (i_bit)			size = 0;	/* send it immediate */		else			size = -1;	/* send it normal (forces empty ping) */	} else if ((buffer = my_kmalloc(32, "NopOut data")) == NULL) {		size = 0;	} else {		/* send the '\0' at the end of the string too */		size = 1 + sprintf(buffer, "NopOut_Ping_Number=%u",				   conn->nop_counter++);		TRACE(TRACE_DEBUG, "Send \"%s\", size %d\n", buffer, size);	}	tx_nopout(conn, i_bit, NULL, &buffer, size);	TRACE(TRACE_ENTER_LEAVE, "Leave drive_nopout\n");	return 0;}/* * executed by tx thread or command process. * the current_session->sess_lock MUST be held by the calling process/thread. * Called by do_test(), create_session(). * drives a discovery session * returns 0 on success, 1 on failure */intdrive_text_negotiate(struct connection *conn, struct session *current_session,		     __u32 i_bit, __u32 discovery){	struct command *new_command;	struct iscsi_init_text_cmnd *text_cmd;	int retval, size;	char *buffer;	struct parameter_type *param;	TRACE(TRACE_ENTER_LEAVE, "Enter drive_text_negotiate\n");	new_command = setup_command(NULL, conn);	if (unlikely(new_command == NULL)) {		/* will not be able to send the text request */		retval = 1;		goto out;	}	/* set up the Text Request header (Draft 20, Section 10.10)	 * to be sent to the target	 */	text_cmd = (struct iscsi_init_text_cmnd *)&new_command->iscsi_cmd;	text_cmd->opcode = ISCSI_INIT_TEXT_CMND | i_bit;	text_cmd->flags = F_BIT;		/* we have only 1 command */	text_cmd->target_xfer_tag = ALL_ONES;	/* reset the target */	/* LUN is 0 by default */	if (discovery && (param = find_flag_parameter(SENDTARGETS_FLAG,						      *current_session->						      session_params))) {		/* send an '=' and the '\0' at the end of the string too */		size = 2 + strlen(param->parameter_name);		if (param->str_value != NULL)			size += strlen(param->str_value);		/* must allocate an extra 3 bytes in case of padding */		buffer = my_kmalloc(size + 3, "Text data");		if (unlikely(buffer == NULL)) {			/* no space for the text request,			 * free up the command structure			 */			endup_command(new_command, current_session);			retval = 1;			goto out;		}		/* save ptr to this buffer so we can free it in		 * rx_text_rsp when done		 */		new_command->buffer_to_free = buffer;		strcpy(buffer, param->parameter_name);		strcat(buffer, "=");		if (param->str_value != NULL)			strcat(buffer, param->str_value);		text_cmd->length = htonl(size);		/* now add padding bytes and data digest, if necessary */		add_padding(conn, new_command, buffer, size);	}	/* attach the new Text Request command to end of pending commands list.	 * this also sets the ITT and the CmdSN	 */	attach_pending_command(new_command, conn, 1);	/* return success */	retval = 0;out:	TRACE(TRACE_ENTER_LEAVE, "Leave drive_text_negotiate, retval = %d\n",	      retval);	return retval;}/* * executed by tx thread or rx thread or init_recovery thread or command process * the current_session->sess_lock MUST be held by the calling process/thread. * Called by do_test(), iscsi_initiator_tx_thread(), init_recovery_thread(), *	rx_async_msg(), rx_text_rsp() * drives the logout of a session * returns 1 on success, 0 on failure * Modified to include connection logout - SAI * for legal "reason" values, see Draft 20, Section 10.14.1 Reason Code */intdrive_logout(struct session *current_session, struct connection *conn,	     int reason){	struct command *new_command;	struct iscsi_init_logout_cmnd *logout_cmd;	int retval;	TRACE(TRACE_ENTER_LEAVE, "Enter drive_logout\n");	new_command = setup_command(NULL, conn);	if (unlikely(new_command == NULL)) {		/* will not be able to send the logout request */		retval = 0;		goto out;	}	/* set up the Logout Request header (Draft 20, Section 10.14)	 * to send to the target	 */	logout_cmd = (struct iscsi_init_logout_cmnd *)&new_command->iscsi_cmd;	logout_cmd->opcode = ISCSI_INIT_LOGOUT_CMND | I_BIT;	/* use the reason code, always with F bit set to 1 - SAI */	logout_cmd->flags = F_BIT | reason;	/* RFC 3720 Section 10.14.3 CID	 * "This is the connection ID of the connection to be closed.	 * This field is only valid if the reason code is not 'close the	 * session'."	 */	if (reason != LOGOUT_CLOSE_SESSION)		logout_cmd->cid = cpu_to_be16(conn->connection_id);	/* attach the new Logout Request command to end of pending commands list	 * this also sets the ITT and the CmdSN	 */	attach_pending_command(new_command, conn, 1);	/* return success */	retval = 1;out:	TRACE(TRACE_ENTER_LEAVE, "Leave drive_logout, retval = %d\n", retval);	return retval;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by check_for_retransmit(). * Enter the xmit state of a command into state 1 * by rebuilding the cmd and setting up a resend */static inttx_retransmit_state1(struct session *current_session,		     struct connection* current_connection,		     struct command *current_command){	struct r2t_cookie *cookie;	/* never got anything back from target, rexmit */	if (current_command->cmd_state & CMD_STATE_REXMIT_ORIG) {		/* data out iovec overwrote original command iovec */		if (!list_empty(&current_command->r2t_cookies)) {			cookie = list_entry(current_command->r2t_cookies.next,					    struct r2t_cookie, link);			free_r2t_cookie(current_connection, current_command,					cookie);		}		build_write_command(current_session, current_connection,				    current_command);	}	TRACE(TRACE_ERROR_RECOVERY, "Re-Transmitting PDU, "	      "ITT %u, size %u\n", current_command->init_task_tag,	      current_command->retransmit_tx_size);	current_command->tx_sent_so_far = 0;	/* start again */	current_command->tx_size = current_command->retransmit_tx_size;	current_command->tx_wait_to_send = jiffies;	current_command->time_stamp = jiffies;	/* RDR - don't come back here a second time */	current_command->activity_flg = 1;	return 1;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by check_for_retransmit(). * Enter the xmit state of a command into state 2 * by marking the time and sending another nop */static inttx_retransmit_state2(struct session *current_session,		     struct connection *current_connection,		     struct command *current_command){	struct init_error_rec err_rec;	current_command->activity_flg = 2;	current_command->time_stamp = jiffies;	if (current_session->oper_param->ErrorRecoveryLevel > 0 &&		current_command->SCpnt->sc_data_direction == SCSI_DATA_WRITE) {		/* a WRITE, assume lost R2T		 * RFC 3720 Section 10.16.6 BegRun		 * "BegRun 0 when used in conjunction with		 * RunLength 0 means resend all unacknowledged		 * Data-In, R2T or Response PDUS."		 */		err_rec.curr_conn = current_connection;		err_rec.related_cmd = current_command;		init_send_snack(&err_rec, 0, 0, DATA_R2T_SNACK);	} else {		drive_nopout(current_connection, current_session, I_BIT, 0);	}

⌨️ 快捷键说明

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