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

📄 iscsi_target.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				TRACE(TRACE_ERROR_RECOVERY,					  "Start payload digest error recovery\n");				err_rec.curr_conn = cmd->conn;				err_rec.pdu_hdr = (struct generic_pdu *)buffer;				err_rec.cmd = cmd;				err_rec.err_type = PAYLOAD_DIGERR;				err = targ_do_error_recovery(&err_rec);			}			my_kfree((void**)&data_buf, "data_buf");		} else {			*result = data_buf;		}	} else {		err = -1;	}	return err;}/* * executed only by the rx thread. * read data segment for command into list of buffers at given offset * this can be either immediate data in a write, or the payload of a DataIn * returns > 0 if ok, < 0 if error, = 0 if error recovery completed ok */static intread_list_data_seg(struct generic_pdu *hdr, struct iscsi_cmnd *cmd,				   struct scatterlist *st_list, int offset){	struct targ_error_rec err_rec;	struct iovec *iov;	int size, niov, padding, err, sgindex;	__u32 digest, pad_bytes;	size = hdr->length;	niov = find_iovec_needed(size, st_list, offset);	if (niov <= 0) {		TRACE_ERROR("%s Trouble in find_iovec_needed\n", current->comm);		return -1;	}	/* allocate 2 extra iov slots for possible padding and crc */	iov = (struct iovec *)my_kmalloc((niov + 2) * sizeof(struct iovec),									 "iovec");	if (!iov) {		return -1;	}	/* gives back number of st_list elements used */	sgindex = fill_iovec(iov, 0, niov, st_list, &offset, size);	padding = (-size) & 3;	if (padding) {		iov[niov].iov_base = &pad_bytes;		iov[niov].iov_len = padding;		niov++;		size += padding;	}	if (cmd->conn->data_crc) {		iov[niov].iov_base = &digest;		iov[niov].iov_len = CRC_LEN;		niov++;		size += CRC_LEN;	}	err = iscsi_rx_data(cmd->conn, iov, niov, size);	if (err == size) {		/* we received everything we expected to receive		 * Store scatter list count and offset for recovery purposes - SAI		 */		cmd->scatter_list_count += sgindex;		cmd->scatter_list_offset = offset;		update_after_read(hdr, cmd);	} else {		/* Payload Digest Error Recovery - SAI */		if (err == PAYLOAD_DIGERR) {			TRACE(TRACE_ERROR_RECOVERY,				  "Start payload digest error recovery\n");			err_rec.curr_conn = cmd->conn;			err_rec.pdu_hdr = hdr;			err_rec.cmd = cmd;			err_rec.err_type = PAYLOAD_DIGERR;			err = targ_do_error_recovery(&err_rec);		}	}	my_kfree((void**)&iov, "iovec");	return err;}/* * executed only by the tx thread. * iscsi_tx_data: will transmit a fixed-size PDU of any type. * INPUT: struct iscsi_conn (what connection), struct iovec, number of iovecs, * total amount of data in bytes, * iovec[0] must be the 48-byte PDU header. * iovec[1] (if header digests are in use, calculate it in this function) * iovec[...] the data * iovec[niov-1] (if data digests are in use, calculate it in this function) * OUTPUT: int total bytes written if everything is okay * 	       < 0 if trouble */intiscsi_tx_data(struct iscsi_conn *conn, struct iovec *iov, int niov, int data){# ifdef DEBUG_DATA	int i, j;	struct iovec *debug_iov;	__u8 *to_print;# endif	struct msghdr msg;	int msg_iovlen;	int total_tx, tx_loop;	__u32 hdr_crc, data_crc;	int data_len, k;	mm_segment_t oldfs;	struct iovec *iov_copy, *iov_ptr;	struct generic_pdu *pdu;	if (!conn->conn_socket) {		TRACE_ERROR("%s NULL conn_socket\n", current->comm);		return -1;	}# ifdef DEBUG_DATA	TRACE(TRACE_DEBUG, "iscsi_tx_data: iovlen %d\n", niov);	debug_iov = iov;	for (i = 0; i < niov; i++) {		to_print = (__u8 *) debug_iov->iov_base;		for (j = 0; ((j < debug_iov->iov_len) && (j < 64)); j++) {			TRACE(TRACE_DEBUG, "%.2x ", to_print[j]);			if (((j + 1) % 16) == 0)				TRACE(TRACE_DEBUG, "\n");			else if (((j + 1) % 4) == 0)				TRACE(TRACE_DEBUG, "    ");		}		TRACE(TRACE_DEBUG, "\n");		debug_iov++;	}# endif	/* compute optional header digest */	if (conn->hdr_crc) {		hdr_crc = 0;		do_crc(iov[0].iov_base, ISCSI_HDR_LEN, &hdr_crc);		iov[1].iov_base = &hdr_crc;		iov[1].iov_len = CRC_LEN;		TRACE(TRACE_ISCSI_FULL, "Send header crc 0x%08x\n", ntohl(hdr_crc));	}	/* compute optional data digest */	if (conn->data_crc && niov > conn->hdr_crc + 2) {		data_len = 0;		data_crc = 0;		for (k = conn->hdr_crc + 1; k < niov - 1; k++) {			do_crc(iov[k].iov_base, iov[k].iov_len, &data_crc);			data_len += iov[k].iov_len;		}		iov[niov - 1].iov_base = &data_crc;		iov[niov - 1].iov_len = CRC_LEN;		TRACE(TRACE_ISCSI_FULL, "Send data len %d, data crc 0x%08x\n",			  data_len, ntohl(data_crc));	}	iov_copy =		(struct iovec *)my_kmalloc(niov * sizeof(struct iovec), "iovec");	if (iov_copy == NULL)		return -1;	total_tx = 0;	while (total_tx < data) {		/* get a clean copy of the original io vector to work with */		memcpy(iov_copy, iov, niov * sizeof(struct iovec));		msg_iovlen = niov;		iov_ptr = iov_copy;		if ((tx_loop = total_tx)) {			TRACE(TRACE_ISCSI,				  "iscsi_tx_data: data %d not completed, recompute iov\n",data);			do {				if (iov_ptr->iov_len <= tx_loop) {					tx_loop -= iov_ptr->iov_len;					iov_ptr++;					msg_iovlen--;				} else {					iov_ptr->iov_base += tx_loop;					iov_ptr->iov_len -= tx_loop;					tx_loop = 0;				}			} while (tx_loop);			TRACE(TRACE_ISCSI, "sock_sendmsg total_tx %d, data %d, niov %d, "							   "msg_iovlen %d\n",							   total_tx, data, niov, msg_iovlen);		}		memset(&msg, 0, sizeof(struct msghdr));		msg.msg_iov = iov_ptr;		msg.msg_iovlen = msg_iovlen;		msg.msg_flags = MSG_NOSIGNAL;		TRACE(TRACE_DEBUG, "iscsi_tx_data: niov %d, data %d, total_tx %d\n",			  niov, data, total_tx);		oldfs = get_fs();		set_fs(get_ds());		tx_loop = sock_sendmsg(conn->conn_socket, &msg, (data - total_tx));		set_fs(oldfs);		if (tx_loop <= 0) {			pdu = (struct generic_pdu *)iov[0].iov_base;			TRACE_ERROR("%s sock_sendmsg error %d, total_tx %d, data %d, niov "						"%d, msg_iovlen %d, op 0x%02x, flags 0x%02x, ITT %u\n",						current->comm, tx_loop, total_tx, data, niov,						msg_iovlen, pdu->opcode, pdu->flags,						ntohl(pdu->init_task_tag));			my_kfree((void**)&iov_copy, "iovec");			return tx_loop;		}		total_tx += tx_loop;		TRACE(TRACE_DEBUG, "iscsi_tx_data: tx_loop %d total_tx %d\n", tx_loop,			  total_tx);	}	my_kfree((void**)&iov_copy, "iovec");	return total_tx;}/* * executed only by the tx thread. * RDR */static intsend_hdr_plus_1_data(struct iscsi_conn *conn, void *iscsi_hdr,					 void *data_buf, int data_len){	struct iovec iov[5];	int niov, total_size, padding, retval;	int pad_bytes = 0;		/* set up the header in the first iov slot */	iov[0].iov_base = iscsi_hdr;	iov[0].iov_len = ISCSI_HDR_LEN;	total_size = ISCSI_HDR_LEN;	niov = 1;					/* one for the header */	if (conn->hdr_crc) {		/* set up the header digest in the second iov slot */		iov[niov].iov_len = CRC_LEN;		total_size += CRC_LEN;		niov++;					/* one for header digest */	}	if (data_len) {		/* set up the data in the next iov slot */		iov[niov].iov_base = data_buf;		iov[niov].iov_len = data_len;		total_size += data_len;		niov++;						/* one for data */		padding = (-data_len) & 3;		if (padding) {			/* set up the data padding in the next iov slot */			iov[niov].iov_base = &pad_bytes;			iov[niov].iov_len = padding;			total_size += padding;			niov++;					/* one for padding */			TRACE(TRACE_DEBUG, "padding attached: %d bytes\n", padding);		}		if (conn->data_crc) {			/* set up the data digest in the next iov slot */			iov[niov].iov_len = CRC_LEN;			total_size += CRC_LEN;			niov++;					/* one for data digest */		}	}	retval = iscsi_tx_data(conn, iov, niov, total_size);	if (retval != total_size) {		TRACE_ERROR("%s Trouble in iscsi_tx_data, expected %d bytes, got %d\n",					current->comm, total_size, retval);		retval = -1;	}	return retval;}/* * executed only by the tx thread. * RDR */static inline intsend_hdr_only(struct iscsi_conn *conn, void *iscsi_hdr){	return send_hdr_plus_1_data(conn, iscsi_hdr, NULL, 0);}/*	Draft 20, Section 3.2.2.1 Command Numbering and Acknowledging *	... *	For non-immediate commands, the CmdSN field can take any value from *	ExpCmdSN to MaxCmdSN inclusive.  The target MUST silently ignore *	any non-immediate command outside of this range or non-immediate *	duplicates within the range.  The CmdSN carried by immediate commands *	may lie outside the ExpCmdSN to MaxCmdSN range. *//*	RDR: check that cmd_sn is within the range [ExpCmdSN .. MaxCmdSN] *	returns 0 if equal to exp_cmd_sn (and exp_cmd_sn is updated) *			1 if greater than exp_cmd_sn (exp_cmd_sn not updated) *			-1 if outside the range (and hence should be ignored) *			0 for all immediate commands, regardless of cmd_sn value *  when called, session->cmnd_sem is locked so access to session-wide *  max_cmd_sn and exp_cmd_sn fields is atomic. */static intcheck_cmd_sn(struct iscsi_cmnd *cmnd, void *ptr, struct iscsi_session *session,			 __u32 increment){	struct generic_pdu *pdu = ptr;	int delta;	if (!(pdu->opcode & I_BIT)) {		/* this is an non-immediate command */		delta = session->max_cmd_sn - pdu->cmd_sn;		if (delta < 0) {		/* cmd_sn is greater than MaxCmdSN */			return -1;		}		delta = pdu->cmd_sn - session->exp_cmd_sn;		if (delta < 0) {		/* cmd_sn is less than ExpCmdSN */			return -1;		}		if (delta > 0) {		/* cmd_sn is in range, but out of order */			return 1;		}		/* non-immediate command is in expected order */		if (increment) {			session->exp_cmd_sn++;		} else {			/* exp_cmd_sn is not incremented.			 * This only happens on in-order, non-immediate SCSI command pdus,			 * which don't bump exp_cmd_sn until after midlevel confirms			 * command was delivered.  Set cmd_sn_increment to tell			 * check_queued_cmnd() not to process this command once it has been			 * queued!			 */			cmnd->cmd_sn_increment = 1;			/* increment exp_cmd_sn later */		}	}	return 0;}/* * executed only by the rx thread. * find commands for this connection already in the queue that have already * sent everything and are being ACKed by this command in order to mark them * for dequeueing. * Then adds this command to end of queue if flag is set. * Finally, if any command's state was changed, or if this command was added * to the queue, wake up the tx thread. * NOTE: cmnd MAY be NULL, and if it is, add_cmnd_to_queue MUST be 0! * returns 0 on success, -1 on error. */static intack_sent_cmnds(struct iscsi_conn *conn,				  struct iscsi_cmnd *cmnd,				  __u32 exp_stat_sn,				  int add_cmnd_to_queue){	struct iscsi_cmnd *temp;	int delta, changed_something, count;	changed_something = add_cmnd_to_queue;	if (down_interruptible(&conn->session->cmnd_sem))		return -1;	count = 0;	for (temp = conn->session->cmnd_list; temp != NULL; temp = temp->next) {		if (temp->conn == conn) {			count++;			if (temp->state == ISCSI_SENT) {				delta = temp->stat_sn - exp_stat_sn;				if (delta < 0) {					TRACE(TRACE_DEBUG, "set dequeue command statsn %d, "						  "received exp_stat_sn %d, command state %d\n",						  temp->stat_sn, exp_stat_sn, temp->state);					temp->state = ISCSI_DEQUEUE;					changed_something = 1;				}			}		}		if (temp->next == NULL)			break;	}	if (add_cmnd_to_queue) {		/* Add this command to the queue */		TRACE(TRACE_DEBUG, "%s add command %p to queue, ITT %u, CmdSN %u, "			  "state %d, count %d\n", current->comm, cmnd, cmnd->init_task_tag,			  cmnd->cmd_sn, cmnd->state, count);		count++;		if (temp)			temp->next = cmnd;		else			conn->session->cmnd_list = cmnd;	}	up(&conn->session->cmnd_sem);	/* tell the tx thread it has something to do */	if (changed_something) {		if (atomic_read(&conn->tx_sem.count) <= 0) {			TRACE(TRACE_DEBUG, "%s up(tx_sem), %d cmnds in queue\n",				  current->comm, count);			up(&conn->tx_sem);		}	}	return 0;}/* * RDR * allocate and zero out a new struct iscsi_cmnd. * Returns pointer to the new struct if all ok, else NULL after error message */struct iscsi_cmnd *get_new_cmnd( void ){	struct iscsi_cmnd *cmnd;	cmnd =		(struct iscsi_cmnd *)my_kmalloc(sizeof(struct iscsi_cmnd), "cmnd");	if (cmnd) {		memset(cmnd, 0, sizeof(struct iscsi_cmnd));		cmnd->state = ISCSI_NEW_CMND;	}	return cmnd;}/**************************************************************************//*                          handle income pdu                             *//**************************************************************************//* * called only from rx thread. * handle_login: This function is responsible for interpreting the login * message and then making sure the necessary details get filled in, a * new session is opened if required by the login and the response is returned * * INPUT: Details of the connection, buffer containing the login * OUTPUT: 0 if everything is okay, < 0 if there is a problem * Note a 0 value returned may still mean that a connection is rejected */static inthandle_login(struct iscsi_conn *conn, __u8 *buffer){	struct iscsi_init_login_cmnd *pdu = (struct iscsi_init_login_cmnd *) buffer;	struct i

⌨️ 快捷键说明

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