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

📄 target_error_rec.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/**************************************************************************** create an R2T cookie and store the R2T details in the cookie. This cookie* is esssential for R2T re-transmssions in error conditions.***************************************************************************/struct iscsi_cookie *create_r2t_cookie(struct iscsi_cmnd *cmnd){	struct iscsi_cookie *cookie = NULL;	TRACE(TRACE_ENTER_LEAVE, "Enter create_r2t_cookie\n");	cookie = (struct iscsi_cookie *)kmalloc(sizeof(struct iscsi_cookie),						GFP_KERNEL);	if (cookie == NULL) {		TRACE_ERROR("%s Malloc problem in creating R2T cookie\n",					current->comm);		goto end_iscsi_cookie;	}	cookie->next = NULL;	if (cmnd->first_r2t_cookie == NULL) {		cmnd->first_r2t_cookie = cmnd->last_r2t_cookie = cookie;	} else {		cmnd->last_r2t_cookie->next = cookie;		cmnd->last_r2t_cookie = cookie;	}end_iscsi_cookie:	TRACE(TRACE_ENTER_LEAVE, "Leave create_r2t_cookie\n");	return cookie;}/* free the long pending R2T cookie list after the command is completed - SAI */voidfree_r2t_cookie(struct iscsi_cmnd *cmnd){	struct iscsi_cookie *cookie = cmnd->first_r2t_cookie;	struct iscsi_cookie *tmp_cookie = NULL;	TRACE(TRACE_ENTER_LEAVE, "Enter free_r2t_cookie\n");	while (cookie) {		tmp_cookie = cookie;		cookie = cookie->next;		kfree(tmp_cookie);	}	TRACE(TRACE_ENTER_LEAVE, "Leave free_r2t_cookie\n");	return;}/******************************************************************************** This function uses the offset and data length parameter or cookie information* to build a recovery R2T to be sent to the intiator for missing Dataouts. This* function is called by SNACK mechanism and also by other places in the code* that find a discrepency in Dataouts using data sequence numbering or offsets.* with regard to R2TSN updating for recovery R2Ts:** RFC 3720 Section 2.1. Definitions* "- Recovery R2T: An R2T generated by a target upon detecting the loss*    of one or more Data-Out PDUs through one of the following means: a*    digest error, a sequence error, or a sequence reception timeout.  A*    recovery R2T carries the next unused R2TSN, but requests all or*    part of the data burst that an earlier R2T (with a lower R2TSN) had*    already requested."********************************************************************************/intsend_recovery_r2t(struct iscsi_cmnd *cmnd, int data_offset,		  struct iscsi_cookie *cookie, struct generic_pdu *hdr){	int data_length;	int max_burst_len;	int err = 0;	TRACE(TRACE_ENTER_LEAVE, "Enter send_recovery_r2t, recovery_r2t %u\n",	      cmnd->recovery_r2t);	if (cmnd->recovery_r2t) {		/* don't send recovery_r2t for another error */		if (hdr->flags & F_BIT) {			/* last DataOut in sequence to be recovered */			cmnd->recovery_r2t = 2;			cmnd->next_burst_len = 0;			cmnd->data_sn = 0;			goto out_wakeup;		}		goto out;	}	max_burst_len = cmnd->conn->session->oper_param->MaxBurstLength;	data_length = cmnd->data_length - data_offset;	if (!cookie) {		cmnd->r2t_data = data_length;		cookie = create_r2t_cookie(cmnd);		if (!cookie) {			err = -1;			goto out;		}		cmnd->startsn = cmnd->endsn = cmnd->r2t_sn;		cookie->seq = cmnd->r2t_sn++;	/* recovery R2T stays in R2T sequence */		cookie->offset = data_offset;		cookie->xfer_len = (data_length <= max_burst_len)					? data_length : max_burst_len;	} else {		data_offset = cookie->offset;		cmnd->r2t_data = cmnd->data_length - data_offset;		cmnd->r2t_sn = cookie->seq;		cmnd->startsn = cmnd->endsn = cmnd->r2t_sn;		cmnd->outstanding_r2t--;	}	TRACE_WARNING("%s Send recovery R2T, ITT %u R2TSN %u Buffer Offset %d\n",				   current->comm, cmnd->init_task_tag, cmnd->r2t_sn,				   data_offset);	if (hdr->flags & F_BIT) {		cmnd->recovery_r2t = 2;		cmnd->next_burst_len = 0;		cmnd->data_sn = 0;	} else {		cmnd->recovery_r2t = 1;	}	cmnd->state = ISCSI_BUFFER_RDY;out_wakeup:	if (atomic_read(&cmnd->conn->tx_sem.count) <= 0) {		up(&cmnd->conn->tx_sem);	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave send_recovery_r2t, recovery_r2t %u, "	      "err = %d\n", cmnd->recovery_r2t, err);	return err;}/************************************************************************ This thread remains blocked on a semaphore for most of the time.* When a r2t timeout happens this thread is awakened for re-transmitting* any r2t requests that have not generated any activity in a long time.***********************************************************************/intiscsi_retran_thread(void *param){	struct iscsi_session *session = (struct iscsi_session *) param;	struct iscsi_cmnd *cmnd;	lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	daemonize(#else	daemonize();	snprintf(current->comm, sizeof(current->comm),#endif			 "iscsi_tran_%d", session->devdata->ntsih);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18)	/*	 * Arne Redlich, agr1@users.sourceforge.net:	 * This prevents the retran thread from becoming a zombie after it exits	 */	reparent_to_init();#endif	siginitsetinv(&current->blocked, ISCSI_SHUTDOWN_SIGBITS);	/* mark that this retransmit thread is alive */	session->retran_thread = current;	unlock_kernel();	printk("%s Starting pid %d\n", current->comm, current->pid);	while (1) {		/* wait for periodic r2t timer to interrupt us */		if (down_interruptible(&session->retran_sem))			break;		/* lock the session-wide list of commands */		if (down_interruptible(&session->cmnd_sem))			continue;		for (cmnd = session->cmnd_list; cmnd; cmnd = cmnd->next) {			if (cmnd->outstanding_r2t > 0			   && jiffies > (cmnd->timestamp+session->r2t_period)			   && cmnd->state == ISCSI_BUFFER_RDY			   && !cmnd->retransmit_flg) {				/* this is a WRITE command with outstanding				 * R2Ts and no activity for a while.  Try				 * retransmitting the last R2T.				 */				TRACE(TRACE_ERROR_RECOVERY,				      "%s activity timeout, ITT %u, "				      "recovery_r2t %u\n",				      current->comm,				      cmnd->init_task_tag,				      cmnd->recovery_r2t);				if (cmnd->recovery_r2t) {					if (cmnd->recovery_r2t == 1)						cmnd->recovery_r2t = 2;				} else {					cmnd->retransmit_flg = 1;					cmnd->endsn = cmnd->startsn							= cmnd->r2t_sn - 1;				}				/* signal the tx thread to do the rexmit */				if (atomic_read(&cmnd->conn->tx_sem.count) <= 0) {					up(&cmnd->conn->tx_sem);				}			}		}		up(&session->cmnd_sem);	}	session->retran_thread = NULL;	up(&session->thr_kill_sem);	printk("%s Exiting pid %d\n", current->comm, current->pid);	return 0;}voidadd_data_to_queue(struct iscsi_cmnd *cmd, struct iscsi_cookie *dataq){	TRACE(TRACE_ENTER_LEAVE, "Entering add_data_to_queue\n");	if (!cmd->first_data_q) {		cmd->first_data_q = dataq;		cmd->last_data_q = dataq;	} else {		cmd->last_data_q->next = dataq;		cmd->last_data_q = cmd->last_data_q->next;	}	TRACE(TRACE_ENTER_LEAVE, "Leaving add_data_to_queue\n");	return;}/********************************************************************* This function drives the out-of-order dataouts received into the * appropriate scatter gather buffer location maintained by scsi. The* information about the out-of-order dataout and also the corresponding* scatter offsets are queued for future use.**********************************************************************/intqueue_data(struct targ_error_rec *err_rec){	int offset = 0, size = 0, list_offset = 0;	int count = 0;	int niov, padding, err, retval = 0, data_crc_len = 0;	__u32 data_sn, digest, pad_bytes;	struct iscsi_conn *conn = NULL;	struct iscsi_cmnd *cmd;	struct iscsi_init_scsi_data_out *hdr;	struct iscsi_cookie *dataq = NULL;	struct scatterlist *st_list;	struct iovec *iov = NULL;	TRACE(TRACE_ENTER_LEAVE, "Entering queue_data\n");	cmd = err_rec->cmd;	hdr = (struct iscsi_init_scsi_data_out *) err_rec->pdu_hdr;	list_offset = offset = hdr->offset;	data_sn = hdr->data_sn;	size = hdr->length;	conn = err_rec->curr_conn;	st_list = (struct scatterlist *) cmd->cmnd->req->sr_buffer;	while (st_list[count].length <= list_offset) {		list_offset -= st_list[count].length;		count++;	}	st_list += count;	niov = find_iovec_needed(size, st_list, list_offset);	if (niov < 0) {		TRACE_ERROR("%s queue data: find_iovec_needed returned an error\n",					current->comm);		return -1;	}	padding = -(size) & 3;	if (padding)		niov++;	if (conn->data_crc == 1)		niov++;	iov = (struct iovec *) kmalloc(niov * sizeof(struct iovec), GFP_KERNEL);	if (!iov) {		TRACE_ERROR("%s queue_data: Could not malloc iov\n", current->comm);		return -1;	}	TRACE(TRACE_DEBUG, "queue_data: no. of iovec needed %d\n", niov);	retval = fill_iovec(iov, 0, niov, st_list, &list_offset, size);	if (padding) {		iov[niov - 1 - conn->data_crc].iov_base = &pad_bytes;		iov[niov - 1 - conn->data_crc].iov_len = padding;	}	if (conn->data_crc == 1) {		data_crc_len = CRC_LEN;		iov[niov - 1].iov_base = &digest;		iov[niov - 1].iov_len = CRC_LEN;	}	err = iscsi_rx_data(cmd->conn, iov, niov, size + padding + data_crc_len);	if (err != (size + padding + data_crc_len)) {		TRACE_ERROR("%s queue_data: Trouble in iscsi_rx_data\n", current->comm);		if (err == PAYLOAD_DIGERR)			return err;	}	dataq = kmalloc(sizeof(struct iscsi_cookie), GFP_KERNEL);	if (!dataq) {		TRACE_ERROR("%s add_data_to_queue: Malloc returned an error\n",					current->comm);		return -1;	}	dataq->offset = offset;	dataq->xfer_len = size;	dataq->list_offset = list_offset;	dataq->list_count = retval;	dataq->next = NULL;	add_data_to_queue(cmd, dataq);	TRACE(TRACE_ENTER_LEAVE, "Leaving queue_data\n");	return 0;}/************************************************************************ This function is called everytime a in-sequence dataout pdu is* received. The function verifies if there was any previous* out-of-order dataouts for the command and updates the state variables* accordingly.***********************************************************************/voidsearch_data_q(struct iscsi_cmnd *cmd){	int unhook_flg = 0;	struct iscsi_cookie *dataq, *prev, *tmp_q;	TRACE(TRACE_ENTER_LEAVE, "Entering search_data_q\n");	if (!cmd->first_data_q)		return;	dataq = prev = cmd->first_data_q;	while (dataq) {		if (cmd->data_done > dataq->offset)			unhook_flg = 1;		else if (cmd->data_done == dataq->offset) {			cmd->scatter_list_count += dataq->list_count;			cmd->scatter_list_offset = dataq->list_offset;			cmd->data_done += dataq->xfer_len;			unhook_flg = 1;		}		if (unhook_flg) {			/* unhook data node */			if (prev == cmd->first_data_q) {				cmd->first_data_q = dataq->next;				prev = dataq->next;			} else if (dataq == cmd->last_data_q)				cmd->last_data_q = prev;			else				prev->next = dataq->next;			tmp_q = dataq;			dataq = dataq->next;			kfree(tmp_q);			unhook_flg = 0;		} else {			prev = dataq;			dataq = dataq->next;		}		if (cmd->data_done >= cmd->data_length)			break;	}	TRACE(TRACE_ENTER_LEAVE, "Leaving search_data_q\n");}

⌨️ 快捷键说明

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