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

📄 initiator_error_rec.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return;}/************************************************************************* This function handles the digest errors and sequence errors that may* have caused because of previous digest errors.* When called, session lock must be locked* Returns >0 on success*	  =0 on failure, session lock is held*	  <0 on failure, session lock is NOT locked************************************************************************/intinit_digest_recovery(struct init_error_rec *err_rec){	int retval = 1;		/* assume success */	int size = 0, err_type = 0, delta;	int serial_no = 0;	__u32 opcode = 0;	struct response_pdu *header;	struct iscsi_targ_scsi_rsp *rsp_hdr;	struct connection *curr_conn;	struct session *current_session;	struct command *related_cmd;	struct iscsi_targ_scsi_data_in *data_in_hdr;	curr_conn = err_rec->curr_conn;	current_session = curr_conn->my_session;	related_cmd = err_rec->related_cmd;	err_type = err_rec->err_type;	TRACE(TRACE_ENTER_LEAVE, "Enter init_digest_recovery \n");	if (curr_conn->rx_buf == NULL) {		TRACE_ERROR("scsi Response Header is NULL\n");		retval = 0;		goto out;	} else {		header = (struct response_pdu *)curr_conn->rx_buf;		opcode = header->opcode;		size = ntohl(header->length);	}	if (err_type == HEADER_DIGERR) {		TRACE(TRACE_DEBUG, "Handling Header Digest Error \n");		if (size > 0) {			/* this size could be bad, but try using it anyway			 * to read in and ignore this PDU's data payload			 */			retval = recv_ignore_data(curr_conn, size);		}		goto out;	}	if (opcode == ISCSI_TARG_SCSI_DATA_IN) {		/* here on SEQUENCE_ERR or PAYLOAD_DIGERR only */		if (err_rec->related_cmd == NULL) {			TRACE_ERROR("Related SCSI Command is NULL - "				    "Snack Request not sent\n");			goto out;		}		data_in_hdr =		    (struct iscsi_targ_scsi_data_in *)curr_conn->rx_buf;		if (related_cmd->cmd_error_state == CMD_OK_SO_FAR) {			/* this is the first error for this command */			related_cmd->cmd_error_state = CMD_NEEDS_SNACK;			related_cmd->cmd_error_size = 0;			if (err_type == SEQUENCE_ERR) {				/* keep this pdu, missing pdus are in gap				 * before this one				 */				related_cmd->cmd_error_offset =				    related_cmd->data_offset;				related_cmd->cmd_error_begrun =				    related_cmd->data_in_sn;				related_cmd->data_in_sn = data_in_hdr->data_sn;				related_cmd->cmd_error_runlen =				    related_cmd->data_in_sn -				    related_cmd->cmd_error_begrun;			} else {				/* this pdu itself was bad,				 * need to ask for it again				 */				related_cmd->cmd_error_offset =				    data_in_hdr->offset;				related_cmd->cmd_error_begrun =				    data_in_hdr->data_sn;				related_cmd->cmd_error_runlen = 1;			}		} else if (related_cmd->cmd_error_state == CMD_NEEDS_SNACK) {			/* already saw a previous error for this command */			if (err_type == SEQUENCE_ERR) {				/* keep DataSN of the out-of-order DataIn PDU */				related_cmd->data_in_sn = data_in_hdr->data_sn;			}			/* effectively "throw away" any good pdus received since			 * previous bad pdu, as they will all be resent later			 */			related_cmd->r2t_range_list.limit -=				related_cmd->cmd_error_size;			related_cmd->cmd_error_size = 0;			related_cmd->cmd_error_runlen = related_cmd->data_in_sn			    - related_cmd->cmd_error_begrun;		} else {			/* already sent a SNACK, now have new errors in reply */			TRACE_ERROR("Error in replies to SNACK, "				    "escalate to session recovery\n");			retval = init_session_recovery(err_rec);		}	} else if (opcode == ISCSI_TARG_R2T) {		TRACE(TRACE_DEBUG, "Handling R2T Sequence Error\n");		serial_no = related_cmd->r2t_sn;		retval = init_send_snack(err_rec, serial_no, 0, DATA_R2T_SNACK);	} else if (opcode == ISCSI_TARG_SCSI_RSP) {		TRACE(TRACE_DEBUG, "Handling Response Sequence Error\n");		rsp_hdr = (struct iscsi_targ_scsi_rsp *)curr_conn->rx_buf;		if (related_cmd == NULL) {			TRACE_ERROR("Related SCSI Command is NULL - "				    "Snack Request not sent\n");			goto out;		}		if (related_cmd->data_in_sn != rsp_hdr->exp_data_sn) {			serial_no = related_cmd->data_in_sn;			retval = init_send_snack(err_rec, serial_no, 0,						    DATA_R2T_SNACK);		}		delta = ntohl(rsp_hdr->stat_sn) - curr_conn->exp_stat_sn;		if (delta < 0) {			TRACE(TRACE_ISCSI,			      "Discarding already received status PDU\n");		} else {			related_cmd->snack_flags |= STATUS_BIT;			serial_no = curr_conn->exp_stat_sn;			retval = init_send_snack(err_rec, serial_no, 1,						    STATUS_SNACK);		}	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave init_digest_recovery %d\n", retval);	return retval;}/********************************************************************************       Called to send a SNACK Request to target for retransmission of*	numbered-responses, data, or R2T PDU.*	Returns	>0 on success*		=0 on failure, session lock is locked*		<0 on failure, session lock is NOT locked*******************************************************************************/intinit_send_snack(struct init_error_rec *err_rec, int begrun, int runlen,		__u8 type){	int retval = 0;		/* assume we will hit an error */	struct connection *current_connection;	struct session *current_session;	struct command *new_command;	struct iscsi_init_snack *snack_cmd;	struct response_pdu *header;	TRACE(TRACE_ENTER_LEAVE, "Enter init_send_snack\n");	current_connection = err_rec->curr_conn;	current_session = current_connection->my_session;	header = (struct response_pdu *)current_connection->rx_buf;	if (type == DATA_R2T_SNACK) {		if (!(current_session->init_snack_flag & DATA_SNACK_ENABLE)) {			TRACE_ERROR("Initiator Data Snack Is Not Enabled - "				    "SNACK request Not Sent\n");			goto out;		}	}	if (type == STATUS_SNACK) {		if (!(current_session->init_snack_flag & STATUS_SNACK_ENABLE)) {			TRACE_ERROR("Initiator Status Snack Is Not Enabled - "				    "SNACK request Not Sent\n");			goto out;		}	}	new_command = setup_command(NULL, current_connection);	if (new_command == NULL) {		/* will not be able to send the snack */		goto out;	}	/* set up the SnackReq header (section 10.16) to send to the target */	snack_cmd = (struct iscsi_init_snack *)&new_command->iscsi_cmd;	snack_cmd->opcode = ISCSI_INIT_SNACK;	snack_cmd->flags = F_BIT | type;     /* F_BIT always set on SnackReq */	/* RFC 3720 Section 10.16.4 Initiator Task Tag (for SNACK Request)	   "For Status SNACK and DataACK, the Initiator Task Tag MUST be set to	   the reserved value 0xffffffff.  In all other cases, the Initiator	   Task Tag field MUST be set to the Initiator Task Tag of the	   referenced command."	 */	if (type != STATUS_SNACK && type != DATACK_SNACK) {		new_command->init_task_tag =		    err_rec->related_cmd->init_task_tag;		snack_cmd->init_task_tag =		    htonl(err_rec->related_cmd->init_task_tag);	} else {		new_command->init_task_tag = ALL_ONES;		snack_cmd->init_task_tag = ALL_ONES;		if (type == STATUS_SNACK)			err_rec->related_cmd->snack_flags |= STATUS_BIT;	}	/* Draft 20, Section 10.16.5 Target Transfer Tag or SNACK Tag	 * "For DataACK, the Target Transfer Tag MUST contain a copy of the	 * Target Transfer Tag and LUN provided with the SCSI Data-In PDU	 * with the A bit set to 1."	 * In all other cases, the Target Transfer Tag field MUST be se to the	 * reserved value of 0xffffffff.	 */	if (type == DATACK_SNACK) {		snack_cmd->target_xfer_tag = header->target_xfer_tag;		snack_cmd->lun = header->lun;	} else {		snack_cmd->target_xfer_tag = ALL_ONES;	}	snack_cmd->begrun = htonl(begrun);	snack_cmd->runlen = htonl(runlen);	TRACE(TRACE_ERROR_RECOVERY,	      "Send SNACK, ITT %u, type %u, begrun %d, runlen %d\n",	      ntohl(snack_cmd->init_task_tag), type, begrun, runlen);	/* can now attach the new SNACK to end of pending commands list	 * (ITT already set and SNACK has no CmdSN value)	 */	attach_pending_command(new_command, current_connection, -1);	retval = 1;		/* pessimistic assumption was wrong */out:	TRACE(TRACE_ENTER_LEAVE, "Leave init_send_snack, retval %d\n", retval);	return retval;}/****************************************************************** * executed only by rx thread. * the session->sess_lock MUST NOT be held by the calling process/thread. * Deal with the Connection Recovery after Time2Wait expires. * Called with no locks held. * Returns >0 on success, session lock not held *	   =0 on failure, session lock is held *	   <0 on failure, session lock is NOT locked ******************************************************************/intdeal_with_connrec(struct connection *fail_connection){	struct session *current_session;	struct connection *new_connection = NULL;	struct command *task_mgt_command = NULL, *cmd;	struct iscsi_init_task_mgt_command *task_mgt_command_hdr = NULL;	struct init_error_rec err_rec;	int lun, retval = 1;	struct list_head *lptr, *next;	TRACE(TRACE_ENTER_LEAVE, "Enter deal_with_connrec\n");	TRACE(TRACE_ERROR_RECOVERY, "Conn Recovery Timer expired\n");	current_session = fail_connection->my_session;	fail_connection->connection_state = CONNECTION_RECOVERING;	if (current_session->nconnections <= 1) {		/* This is last connection available, create new connection */		if (!create_rec_conn(fail_connection)) {			retval = -1;			goto out;		}	}	UNH_LOCK(&current_session->sess_lock, fail_connection->rx_lock_flags);	current_session->n_rec_tasks = 0;	list_for_each_safe(lptr, next, &fail_connection->pending_commands) {		cmd = list_entry(lptr, struct command, link);		cmd->activity_flg = 0;		if (cmd->iscsi_cmd.opcode != ISCSI_INIT_SCSI_CMND)			continue;		new_connection = get_connection(cmd->SCpnt, current_session);		if (new_connection == fail_connection) {			TRACE_ERROR("get_connection returned the failed "				    "connection - can't re-assign commands\n");			goto out_escalate;		}		if (!new_connection) {			TRACE_ERROR("get_connection returned NULL\n");			goto out_escalate;		}		if ((task_mgt_command =		     setup_command(NULL, new_connection)) == NULL) {			goto out_escalate;		}		TRACE(TRACE_DEBUG, "Populating task mgt command for connection "		      "recovery\n");		task_mgt_command->task_mgt_function = TMF_TASK_REASSIGN;		task_mgt_command->task_mgt_response = FUNCTION_REJECTED;		task_mgt_command->ref_task_tag = cmd->init_task_tag;		/* fill up the task_mgt_header info. */		task_mgt_command_hdr = (struct iscsi_init_task_mgt_command *)		    &task_mgt_command->iscsi_cmd;		task_mgt_command_hdr->opcode = ISCSI_INIT_TASK_MGMT_CMND;		task_mgt_command_hdr->opcode |= I_BIT;		task_mgt_command_hdr->function = (TMF_TASK_REASSIGN | F_BIT);		task_mgt_command_hdr->lun = cmd->iscsi_cmd.lun;		task_mgt_command_hdr->ref_task_tag = htonl(cmd->init_task_tag);		task_mgt_command_hdr->ref_cmd_sn = cmd->iscsi_cmd.cmd_sn;		TRACE(TRACE_ERROR_RECOVERY,		      "Send TASK MGT Cmnd, ITT %u, %u bytes\n",		      task_mgt_command->init_task_tag,		      task_mgt_command->tx_size);		/* attach the new task mgt command to end of pending commands		 * this also assigns a new ITT and sets the CmdSN.		 */		attach_pending_command(task_mgt_command, new_connection, 1);		current_session->n_rec_tasks++;		TRACE(TRACE_DEBUG,		      "Waiting to get task mgt. rsp from the target\n");		/* move command from old connection to new connection */		list_del(&cmd->link);		list_add_tail(&cmd->link, &new_connection->pending_commands);	}	if (current_session->n_rec_tasks > 0) {		TRACE(TRACE_DEBUG, "%d commands recovered\n",		      current_session->n_rec_tasks);	} else {		/* no tasks transferred */	}	UNH_UNLOCK(&current_session->sess_lock, fail_connection->rx_lock_flags);	/* find a lun that is already in use in this session */	if ((lun = find_used_lun(current_session)) >= 0) {		/* got the lun, remove failed connection from this session */		remove_session_from_hostdata(current_session->scsi_target_id,					     lun,					     fail_connection->connection_id,					     global_hostdata);	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave deal_with_connrec, retval %d\n",		retval);	return retval;out_escalate:	UNH_UNLOCK(&current_session->sess_lock, fail_connection->rx_lock_flags);	err_rec.curr_conn = fail_connection;	retval = init_session_recovery(&err_rec);	goto out;}static voidtime2wait_function(unsigned long wait_sem){	struct semaphore *rec_wait_sem = (struct semaphore *)wait_sem;	up(rec_wait_sem);}/***************************************************************	Start Time2Wait Timer for Connection Recovery***************************************************************/voidstart_connrec_timer(struct session *current_session,		    struct semaphore *rec_wait_sem, __u32 period){	TRACE(TRACE_ENTER_LEAVE, "Enter start_connrec_timer, period %u\n",	      period);	if (period > 0 && !timer_pending(&current_session->connrec_timer)) {			/* we can start the timer for a non-zero			 * period of time (in ticks)			 */		TRACE(TRACE_ERROR_RECOVERY, "Start timer for %u ticks\n",		      period);		current_session->connrec_timer.expires = jiffies + period;		current_session->connrec_timer.data =		    (unsigned long) rec_wait_sem;		current_session->connrec_timer.function = time2wait_function;		add_timer(&current_session->connrec_timer);	} else {		/* else period is 0 or no timer or timer already going,		 * don't start it now		 */		TRACE_ERROR("Conn Recovery Timer not started for %u ticks\n",			    period);	}	TRACE(TRACE_ENTER_LEAVE, "Leave start_connrec_timer\n");}voidrestore_global_data(struct iscsi_targetdata *targ_data){	char *targ_name, *init_name;	struct parameter_type *dst, *param;	/* Uncopy the old values from the parameter table */	TRACE(TRACE_ENTER_LEAVE, "Entering restore_global_data\n");	dst = targ_data->param_tbl;	param = find_parameter("TargetName", dst);	targ_name = strdup(param->str_value);	param = find_parameter("InitiatorName", dst);	init_name = strdup(param->str_value);	param_tbl_uncpy(dst);	param_tbl_init(dst);	param = find_parameter("TargetName", dst);	strreplace(&param->str_value, targ_name);	param->neg_info = KEY_TO_BE_NEGOTIATED;	param = find_parameter("InitiatorName", dst);	strreplace(&param->str_value, init_name);	param->neg_info = KEY_TO_BE_NEGOTIATED;	TRACE(TRACE_ENTER_LEAVE, "Leaving restore_global_data\n");}

⌨️ 快捷键说明

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