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

📄 initiator_utilities.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called by rx_data(), recv_ignore_data(). * Called to receive *size bytes of data (can be 0) into a scsi buffer * pointed to by the related_command (can be NULL), * plus over_flow_data_size bytes of data into a locally allocated * buffer.  All the data is padded and checksummed as necessary. * On entry MUST have (*size + over_flow_data_size) > 0. * Called under protection of session->lock. * Returns	> 0 if ok, * 		= 0 on err and session->sess_lock still held, * 		< 0 on err and session->sess_lock not held. * ptr to local buffer is set on return if allocated, else unchanged. * if returned not NULL, this buffer must be freed by caller!*/intrecv_data_in_data(struct connection *current_connection,		  struct command *related_command,		  struct iscsi_targ_scsi_data_in *data_in_header,		  __u32 *size,		  int over_flow_data_size,		 char **over_flow_buffer){	struct scatterlist *sg;	__u8 *cur_ptr, extra_data_buffer[16];	__u32 cur_offset, recv_checksum, checksum;	int received = 1, count, cur_size, padbytes, nbytes;	struct iovec *iov;#ifdef K26	struct session *current_session = current_connection->my_session;#endif	TRACE(TRACE_ENTER_LEAVE, "Enter recv_data_in_data, size %u, "	      "over_flow_data_size %d\n", *size, over_flow_data_size);	iov = current_connection->rx_iov;	/* point at empty rx_iov[] */	count = 0;				/* no. of slots used in rx_iov*/	if ((nbytes = *size) > 0) {		/* Check if we have scatter-gather list to be filled */		if (related_command->SCpnt->use_sg == 0) {			/* No scatter-gather list, just 1 big buffer */			TRACE(TRACE_DEBUG, "No Sc-Gather list\n");			iov->iov_base = related_command->SCpnt->request_buffer					+ data_in_header->offset;			iov->iov_len = nbytes;			iov++;			count++;		} else {			/* We have to fill scatter-gather list */			TRACE(TRACE_DEBUG, "Gather size %d\n",					related_command->SCpnt->use_sg);			sg = (struct scatterlist *)			     related_command->SCpnt->request_buffer;			cur_offset = 0;/* donnelly */#ifdef K26/*	Notes on kernel 2.6 changes. *      Prior to 2.6, a device driver had to know if the memory *      model they existed under was either hi-mem or small *      and use the appropriate vaddr mapping of kmap() ( for large ) *      or  page_address() ( for small) . The only recommended way  *	now is to allow kmap() to set up the appropriate mappings  * 	avoid page_adress all together.  */			TRACE(TRACE_DEBUG,				"sg %p page %p off %x addr %x len %x\n",				sg,sg->page,sg->offset, sg->dma_address,				sg->length);			/* Convert page struct passed in SG instead of using			 * pci_map_sg(NULL,sg,SCpnt->use_sg,			 *      SCpnt->sc_data_direction)			 * or page_address for portability between memory 			 * models to create a kernel vaddr. 			 * We can sleep on this			 * call so have have to release our lock.			 * kmap can sleep        			 * kmap_atomic() won't sleep but can fail 			 */			UNH_UNLOCK(&current_session->sess_lock,				   current_connection->rx_lock_flags);			cur_ptr = kmap(sg->page);			sg_dma_address(sg) = (dma_addr_t)cur_ptr;			UNH_LOCK(&current_session->sess_lock,				 current_connection->rx_lock_flags);			sg_dma_address(sg) += sg->offset;			cur_ptr += sg->offset;#else			cur_ptr = sg->address;#endif			/* first find where to put data in the scatterlist */#ifdef K26			TRACE(TRACE_DEBUG, "cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n",				cur_offset, data_in_header->offset,				sg_dma_len(sg), cur_ptr, sg_dma_address(sg));			while (cur_offset < data_in_header->offset) {				if (cur_offset + sg_dma_len(sg) >					data_in_header->offset) {					cur_ptr = (char *)sg_dma_address(sg) +							data_in_header->offset -							cur_offset;					cur_offset = data_in_header->offset;			TRACE(TRACE_DEBUG, "In while: cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n",				cur_offset, data_in_header->offset,				sg_dma_len(sg), cur_ptr, sg_dma_address(sg));				} else {					cur_offset += sg_dma_len(sg);					sg++;					cur_ptr = (void *)sg_dma_address(sg);			TRACE(TRACE_DEBUG, "In else: cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n",				cur_offset, data_in_header->offset,				sg_dma_len(sg), cur_ptr, sg_dma_address(sg));				}			} /* while */#else			TRACE(TRACE_DEBUG, "cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %p\n",				cur_offset, data_in_header->offset,				sg->length, cur_ptr, sg->address);			while (cur_offset < data_in_header->offset) {				TRACE(TRACE_DEBUG,				      "cur_offset while %d %d %d %p %p\n",				      cur_offset, data_in_header->offset,				      sg->length, cur_ptr, sg->address);				if (cur_offset + sg->length						> data_in_header->offset) {					cur_ptr = cur_ptr						  + data_in_header->offset						  - cur_offset;					cur_offset = data_in_header->offset;				} else {					cur_offset += sg->length;					sg++;					cur_ptr = sg->address;				}			}#endif			/* fill in the buffers till we receive amount of data			 * corresponding to the datasegmentlength in the			 * DataIn header			 */			for (received = 0; received < nbytes;			     received += cur_size) {/* jpd */#ifdef K26				cur_size = (__u32) sg_dma_address(sg) +						sg_dma_len(sg) -						(__u32) cur_ptr;#else				cur_size = (__u32) sg->address + sg->length							- (__u32) cur_ptr;#endif				if (cur_size > nbytes - received) {					cur_size = nbytes - received;				}				iov->iov_len = cur_size;				iov->iov_base = cur_ptr;				sg++;/* jpd */#ifdef K26				cur_ptr = (__u8 *)sg_dma_address(sg);#else				cur_ptr = sg->address;#endif				iov++;				count++;			}		}	} /* end of  if (nbytes > 0) */	nbytes += over_flow_data_size;	/* may need to read padding and/or crc and/or extra data */	padbytes = (-nbytes) & 3;	if (unlikely(padbytes != 0)) {		/* have to receive pad bytes */		over_flow_data_size += padbytes;		nbytes += padbytes;	}	if (unlikely(over_flow_data_size > 0)) {		/* have to receive extra data and/or padding */		if (over_flow_data_size <= sizeof(extra_data_buffer)) {			/* use local buffer for small amounts of extra data */			iov->iov_base = extra_data_buffer;		} else {			/* have to allocate a big buffer for extra data */			*over_flow_buffer = (char *)my_kmalloc(							over_flow_data_size,							"local buf");			if (unlikely(*over_flow_buffer == NULL)) {				received = -ENOMEM;				goto out_unlock;			}			iov->iov_base = *over_flow_buffer;		}		iov->iov_len = over_flow_data_size;		iov++;		count++;	}	if (current_connection->connection_flags & USE_DATADIGEST) {		/* receive crc into local variable for checking */		iov->iov_base = &recv_checksum;		iov->iov_len = CRC_LEN;		nbytes += CRC_LEN;		iov++;		count++;		/* need to compute the checksum after reading,		 * but recvmsg destroys the iovector during		 * reading, so we need to make a copy now		*/		memcpy(current_connection->rx_iov_copy,		       current_connection->rx_iov,		       count * sizeof(struct iovec));	}	received = recv_iovector(current_connection, nbytes, count);	if (unlikely(received <= 0))		goto out;	if (current_connection->connection_flags & USE_DATADIGEST) {		/* need to go back to compute and check the checksum */		checksum = 0;		iov = current_connection->rx_iov_copy;		for (count--; count > 0; count--) {			do_crc(iov->iov_base, iov->iov_len, &checksum);			iov++;		}		if (unlikely(checksum != recv_checksum)) {			/* There is a Data Digest err,			 * handle appropriately - SAI			 */			TRACE_ERROR("opcode 0x%02x, ITT %u, Data CRC wrong: "				    "got 0x%08x, expected 0x%08x\n",				    data_in_header->opcode,				    related_command->init_task_tag,				    ntohl(recv_checksum),				    ntohl(checksum));			data_in_header->length = 0;	/*already got all data*/			received = recv_data_in_error(						current_connection,						related_command,						data_in_header,						size);		}	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave recv_data_in_data, received %d\n",		received);	return received;out_unlock:	UNH_UNLOCK(&current_connection->my_session->sess_lock,		   current_connection->rx_lock_flags);	goto out;}/* * the session->sess_lock MUST be held by the calling process/thread. * here to attach cmnds to the list after they have been properly * filled in.  The reason we needed to be a bit careful is that other * portions of the driver might be attempting to traverse the list * at the same time that we are here so we don't want to attach an * invalid entry. */voidattach_pending_command(struct command *new_command,		       struct connection *current_connection, int need_itt){	struct iscsi_init_scsi_cmnd *iscsi_cmd;	struct session *current_session;	TRACE(TRACE_ENTER_LEAVE,	      "Enter attach_pending_command, command %p, need_itt %d\n",	      new_command, need_itt);	/*  extract a copy of pdu's opcode and flags for use after sendmsg */	/*  These bytes are in the "iscsi_cmd" field of the "struct command"	   for all pdu types except DataOut when they are in the "data"	   field of the "struct command"	 */	new_command->header_opcode =	    ((__u8 *) (new_command->tx_iov[0].iov_base))[0];	new_command->header_flags =	    ((__u8 *) (new_command->tx_iov[0].iov_base))[1];	current_session = current_connection->my_session;	iscsi_cmd = &new_command->iscsi_cmd;	/* now allocate a session-wide command number, and task tag if needed */	if (need_itt >= 0) {		switch (need_itt) {		case 1:			/* set ITT to unique value != 0xffffffff */			new_command->init_task_tag					= current_session->cur_task_tag++;			if (unlikely(current_session->cur_task_tag == ALL_ONES))				current_session->cur_task_tag++;			iscsi_cmd->init_task_tag					= htonl(new_command->init_task_tag);			break;		case 0:			/* set ITT to 0xffffffff, and I bit to 1			 *			 * RFC 3721 Section 10.18.1 Initiator Task Tag (NOP-Out)			 * "If the Initiator Task Tag contains 0xffffffff, the			 * I bit MUST be set to 1 and the CmdSN is not advanced			 * after this PDU is sent."			 */			iscsi_cmd->init_task_tag = new_command->init_task_tag								= ALL_ONES;			iscsi_cmd->opcode |= I_BIT;			break;		case 2:			/* reusing old command struct, so ITT already set */			list_del(&new_command->link);			new_command->header_complete = 0;			break;		}	/* switch */		/*		 *  RFC 3720 Section 3.2.2.1 Command Numbering and Acknowledging		 *		 * "Commands meant for immediate delivery are marked with an		 * immediate delivery flag; they MUST also carry the		 * current CmdSN.  CmdSn does not advance after a command marked		 * for immediate delivery is sent.  Command numbering starts		 * with the first login request on the first connection of a		 * session (the leading login on the leading connection) and		 * command numbers are incremented by 1 for every non-immediate		 * command issued afterwards.		 * ...		 * For the numbering mechanism, the initiator and target		 * maintain the following three variables for each session:		 *		 * - CmdSN - the current command Sequence Number, advanced		 * by 1 on each command shipped except for commands marked for		 * immediate delivery.  CmdSN always contains the number to be		 * assigned to the next Command PDU."		 *		 * RFC 3720 Section 10.2.1.1 I (bit in Basic Header Segment)		 * "For request PDUs, the I bit set to 1 is an immediate		 * delivery marker."		 */		iscsi_cmd->cmd_sn = htonl(current_session->cur_cmd_sn);		if (likely(!(iscsi_cmd->opcode & I_BIT))) {			/* not an immediate command, advance CmdSN by 1 */			current_session->cur_cmd_sn++;		} /* else I bit is set (immediate command), CmdSN unchanged */	}	TRACE(TRACE_DEBUG, "attach_pending command %p connection %p ###\n",	      new_command, current_connection);	/* fill in fields for tx thread */	new_command->tx_sent_so_far = 0;       /* nothing sent so far */	new_command->retransmit_tx_size = new_command->tx_size;	/* first time command can be sent */	new_command->tx_wait_to_send = jiffies;	new_command->time_stamp = jiffies;	/* add this new command to end of pending commands list */	list_add_tail(&new_command->link,&current_connection->pending_commands);	TRACE(TRACE_DEBUG, "Attach pending command, ITT %u\n",	      new_command->init_task_tag);	/* signal the tx thread for this session that is has work to do */	if (atomic_read(&current_connection->tx_sem.count) <= 0) {		TRACE(TRACE_ISCSI_FULL, "wake up tx_thread\n");		up(&current_connection->tx_sem);	}	TRACE(TRACE_ENTER_LEAVE, "Leave attach_pending_command\n");}

⌨️ 快捷键说明

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