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

📄 initiator_tx.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 3 * by issuing SNACK requests */static inttx_retransmit_state3(struct session *current_session,		     struct connection *current_connection,		     struct command *current_command){	int DInOrder = current_session->oper_param->DataSequenceInOrder;	int PInOrder = current_session->oper_param->DataPDUInOrder;	struct scsi_cmnd *SCpnt = current_command->SCpnt;	struct init_error_rec err_rec;	current_command->activity_flg = 3;	if (likely(current_command->SCpnt != NULL)) {		do {			err_rec.curr_conn = current_connection;			err_rec.related_cmd = current_command;			if (current_command->SCpnt->sc_data_direction							== SCSI_DATA_READ) {				/* take care of out-of-order PDUs too --				 * new 18_04 SAI				 */				if ( likely(DInOrder && PInOrder)) {					if (current_command->data_offset						!= SCpnt->request_bufflen) {						init_send_snack (&err_rec,						current_command->data_in_sn,						0, DATA_R2T_SNACK);						break;					}				} else {					if (check_range_list_complete(						&current_command->							r2t_range_list) > 0) {						init_send_snack( &err_rec,						current_command->data_in_sn,						0, DATA_R2T_SNACK);						break;					}				}			}			init_send_snack(&err_rec,					current_connection->exp_stat_sn, 1,					STATUS_SNACK);		} while (0);		/* Timestamp command transmission time - SAI */		current_command->time_stamp = jiffies;	}	return 1 ;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * command and determines if the commands needs re-sent * during 3 states: * State 0 -	Entered after original cmd is sent but NO reply is recv. *		State 0 sets up the command again and re-xmits. * State 1/2 -	Entered after state 0. Is sets up a no-op ping to see *		if the target is alive. This state is executed twice if *		necessary. * State 3 -	State 3 uses SNACKS requests to fill -in lost or dropped *		data PDU's. * * 0:  * returns 1 if ok, 0 if nothing works and thread should terminate * Retransmit a loss/dropped command */static int __attribute__ ((no_instrument_function))check_for_retransmit(struct session *current_session,		     struct connection *current_connection,		     struct command *current_command){	int retval = 1;	long delta_t;	if (unlikely(TRACE_TEST(TRACE_ERROR_RECOVERY))) {		TRACE(TRACE_ERROR_RECOVERY, "check_for_retransmit: ITT %u, "			"state 0x%08x, still_to_send %u\n",			current_command->init_task_tag,			current_command->cmd_state,			current_command->still_to_send);	}	if (current_session->oper_param->ErrorRecoveryLevel > 0					&& current_session->retran_period > 0) {		/* If timer expired and no activity, assume command was lost		 * and re-transmit command - SAI		 */		delta_t = jiffies - (current_command->time_stamp				     + ((current_session->retran_period) * HZ));		if (delta_t >= 0) {			/* nothing received for this command during last			 * retran_period seconds			 */			TRACE(TRACE_ERROR_RECOVERY,			      "Timeout, ITT %u, time_stamp %u, jiffies %lu, "			      "delta %ld retran_period %u, HZ %u, "			      "activity_flg %u\n",			      current_command->init_task_tag,			      current_command->time_stamp, jiffies, delta_t,			      current_session->retran_period, HZ,			      current_command->activity_flg);			if (!current_command->activity_flg) {				/* no reply from target, rexmit */				tx_retransmit_state1(current_session,						     current_connection,						     current_command);			} else if (current_command->activity_flg == 1) {				/* first timeout, allow 1 more				 * due to freezing				 */				tx_retransmit_state2(current_session,						     current_connection,						     current_command);			} else if (current_command->activity_flg == 2) {				/* for read commands, the data_in or				 * the scsi response could be lost				 * due to packet drops because of				 * bad connection or during connection				 * recovery. This function pro-actively				 * fills the gap in data-in pdus and				 * scsi responses. This uses the command				 * re-transmit timer for checking				 * and filling gaps - SAI				 */				retval = tx_retransmit_state3(current_session,							     current_connection,							     current_command);			} else {				/*				 * current_command->activity_flg == 3				 * Retransmit, Nop and SNACK all failed				 * nothing works, shut this tx thread down				 */				retval = 0;			}		}	}	return retval;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called by ready_to_xmit() and iscsi_initiator_tx_thread(). * returns 0 if command is immediate or its CmdSN is NOT beyond MaxCmdSN *		(i.e., it is ok to send it to target now) * returns 1 if command is non-immediate and its CmdSN is beyond MaxCmdSN */static intbeyond_window(struct session *current_session,	  struct connection *current_connection,	  struct command *current_command){	int retval = 0, delta;	if (!(current_command->iscsi_cmd.opcode & I_BIT)) {		/* non-immediate, is its sequence number		 * beyond target's window limit?		 */		delta = current_session->max_cmd_sn				- ntohl(current_command->iscsi_cmd.cmd_sn);		if (delta < 0) {			/* yes, mark that tx thread needs to be awakened */			current_connection->connection_flags |= NEED_TX_WAKEUP;			/* can't send this command now */			TRACE(TRACE_ISCSI_FULL, "Delay sending ITT %u: CmdSN "			      "%u beyond MaxCmdSN %u\n",			      current_command->init_task_tag,			      ntohl(current_command->iscsi_cmd.cmd_sn),			      current_session->max_cmd_sn);			retval = 1;		}	}	return retval;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * returns 0 if nothing to xmit for this command, * else size to xmit * returns -1 if this command was cut short */static intready_to_xmit(struct session *current_session,	      struct connection *current_connection,	      struct command *current_command){	int size;	long delta_t;	struct r2t_cookie *cookie;	if (unlikely(current_connection->short_command != NULL)) {		/* in the middle of a partial send */		if (current_connection->short_command != current_command) {			/* not a partial send of this command, leave now */			size = 0;			goto out;		}		delta_t = jiffies - current_command->tx_wait_to_send;		if (delta_t < 0) {			/* this command has not waited long enuf since			 * last partial send			 */			size = -1;			current_connection->connection_flags |= NEED_TX_WAKEUP;			goto out;		}		/* ready to resume after partial send,		 * everything already set up		 */		size = current_command->tx_size;	} else if (unlikely(current_command->cmd_state & CMD_STATE_ABORTING)) {		/* current command is being aborted, do not xmit anything */		size = 0;	} else if ((size = current_command->tx_size) == 0) {		/* current command has already been sent */		if (!list_empty(&current_command->r2t_cookies)) {			/* this command has an unsatisfied R2T ready to go */			cookie = list_entry(current_command->r2t_cookies.next,					    struct r2t_cookie, link);			if (&cookie->order_link					== current_connection->r2t_list.next) {				/* this r2t is next to send on this connection*/				if ((int) cookie->r2t_xfer_length > 0) {					/* still data left to send on this R2T*/					size = setup_dataoutpdu(							current_connection,							current_command,							cookie);				} else {					/* should never happen */					TRACE_ERROR("Cookie r2t_xfer_length %d "						    "not positive, ITT %u\n",						    (int) cookie							->r2t_xfer_length,						    current_command							->init_task_tag);					free_r2t_cookie(current_connection,							current_command,							cookie);					goto out;				}			}		}	}out:	return size;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by do_tx_send(). * Finalize a PDU header just before it is about to be transmitted. * This requires inserting the latest ExpStatSN on this connection * and then computing the header CRC if enabled. * The PDU header is always pointed to by the first slot in tx_iov * and the slot for the CRC is always at the end of that header. */static void __attribute__ ((no_instrument_function))finalize_header(struct connection *conn, struct command *command){	struct generic_pdu *pdu;	pdu = (struct generic_pdu *)command->tx_iov->iov_base;	pdu->exp_stat_sn = htonl(conn->exp_stat_sn);	/* compute and add the header digest if we are using them */	if (conn->connection_flags & USE_HEADERDIGEST) {		pdu->header_digest = 0;		do_crc((__u8 *)pdu, ISCSI_HDR_LEN, &pdu->header_digest);		TRACE(TRACE_ISCSI_FULL, "Attach HeaderDigest\n");	}	command->tx_sent_so_far = 0;		/* nothing sent so far */	command->retransmit_tx_size = command->tx_size;	command->header_complete = 1;		/* don't come back here again */}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * We have a command that needs to be sent on this connection * and target window is open enough to receive it. * session lock is held on entry and exit, * but is released during call to sock_sendmsg(). * returns : 1 on success, * 	     0 on incomplete send, * 	    -1 on fatal error */static intdo_tx_send(struct session *current_session,	   struct connection *current_connection,	   struct command *current_command){	mm_segment_t oldfs;	int size, sent, retval = 1, iovlen;	struct iovec *iov;	__u32 opcode;#if defined(CONFIG_ISCSI_DEBUG)	char op_buf[16];#endif	if (!current_command->header_complete) {		finalize_header(current_connection, current_command);	}	/* mark that this command was sent to target */	current_command->cmd_state |= CMD_STATE_TXSTARTED;	opcode = current_command->header_opcode & ISCSI_OPCODE;	TRACE(TRACE_DEBUG, "%s Header opcode 0x%.2x flags 0x%.2x\n",	      current->comm, current_command->header_opcode,	      current_command->header_flags);	iov = current_command->tx_iov;	iovlen = current_command->tx_iovlen;	size = current_command->tx_size;	if ((sent = current_command->tx_sent_so_far) == 0) {		/* first time sending this command, use original iovec */		TRACE(TRACE_ISCSI, "%s Send %s, ITT %u, %u bytes\n",		      current->comm, printable_iscsi_op(iov->iov_base, op_buf),		      current_command->init_task_tag, size);		if (unlikely(TRACE_TEST(TRACE_ISCSI_FULL))) {			print_iscsi_command(iov->iov_base);		}	} else {		/* previously did partial send, may need to use copy of iovec */		TRACE(TRACE_ISCSI, "%s More 0x%02x, ITT %u, %u bytes\n",		      current->comm, opcode,		      current_command->init_task_tag, size);		while (iov->iov_len <= sent) {			/* all of this iov already sent */			sent -= iov->iov_len;			iov++;			iovlen--;		}		if (sent > 0) {			/* copy the remaining iovecs so we can modify 1st one */			memcpy(current_command->tx_iov_copy, iov,			       iovlen * sizeof(struct iovec));			/* update copied iov to account for previous sends */			iov = current_command->tx_iov_copy;			iov->iov_base += sent;			iov->iov_len -= sent;		}	}	/* set up the message header for sendmsg */	memset(&current_command->tx_msghdr, 0, sizeof(struct msghdr));	current_command->tx_msghdr.msg_iov = iov;	current_command->tx_msghdr.msg_iovlen = iovlen;	current_command->tx_msghdr.msg_flags = current_command->cmd_msg_flags;	/***** uncomment this to put tx thread into non-blocking mode *****	current_command->tx_msghdr.msg_flags |= MSG_NOSIGNAL | MSG_DONTWAIT;	*****/	TRACE(TRACE_DEBUG, "--sending %d, ITT %u\n",	      size, current_command->init_task_tag);	/* Timestamp the command transmission time - SAI */	current_command->time_stamp = jiffies;	/* allow other threads to run while we send */	UNH_UNLOCK(&current_session->sess_lock,		   current_connection->tx_lock_flags);#ifdef K26	if (use_sendpage(current_connection, current_command) && 		current_command->pindex > 0) {		struct socket *sock = current_connection->sock;		struct scatterlist *sg;		int res = 0, total_len, total_sent = 0, first_offset;		int left_in_header;		int flags = MSG_MORE, padding = current_command->padding;		total_len = size - padding;		left_in_header = current_connection->basic_hdr_len					- current_command->tx_sent_so_far;		if (left_in_header > 0) {			current_command->tx_msghdr.msg_iovlen = 1;			oldfs = get_fs();			set_fs(get_ds());			res = sock_sendmsg(current_connection->sock,					   &current_command->tx_msghdr,					   left_in_header);			set_fs(oldfs);			if (res != left_in_header) {				sent = res;				goto finish;			}			total_len -= res;			total_sent += res;			first_offset = 0;		} else {			first_offset = sent;		}		sg = current_command->sg;		if (current_command->tx_iovlen != iovlen)			sg--;		while (total_len > 0) {			struct page *page = sg->page;			int i, len;			int sg_len = sg->length;			int nr = (sg->offset + sg->length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;			int offset = sg->offset + first_offset;			sg_len -= first_offset;			i = offset >> PAGE_SHIFT;			offset = offset & (PAGE_SIZE - 1);			for (; total_len > 0 && i < nr; i++) {				if (sg_len + offset > PAGE_SIZE)					len = PAGE_SIZE - offset;				else					len = sg_len;				if (len > total_len) {					len = total_len;				}				if (total_len == len)					flags = 0;				res = sock->ops->sendpage(sock, page, offset, len, flags);				if (len != res) {					if (res > 0) {						sent = total_sent;						goto finish;					} else {						if (res == -EAGAIN) {							sent = total_sent;							goto eagain;						}						sent = res;						goto finish;					}				}				page++;				offset = 0;				total_len -= res;				sg_len -= res;

⌨️ 快捷键说明

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