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

📄 initiator_rx.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}#endif	/* leave if command struct corresponding to task mgt rsp not found */	if (unlikely(related_command == NULL)) {		goto out;	}	if (likely((header->response == FUNCTION_COMPLETE)	    || (header->response == TASK_DOES_NOT_EXIST)	    || (header->response == LUN_DOES_NOT_EXIST)	    || (header->response == FUNCTION_REJECTED))) {		related_command->task_mgt_response = header->response;		TRACE(TRACE_DEBUG, "Got task mgt response 0x%02x\n",				    header->response);	} else {		TRACE_ERROR("Invalid task mgt response from target 0x%02x,"			    " returning reponse FUNCTION_REJECTED to SCSI\n",			    header->response);		related_command->task_mgt_response = FUNCTION_REJECTED;	}	/* Added the TASK REASSIGN handling for connection recovery - SAI */	if (related_command->task_mgt_function == TMF_TASK_REASSIGN) {		cmd = find_command_by_itt(related_command->ref_task_tag,					  current_connection);		if (likely(cmd != NULL)) {			/* Free the corresponding task mgt command */			if (related_command->task_mgt_response							== FUNCTION_REJECTED) {				/* TASK REASSIGN probably not supported.				 * Free pending command				 */				TRACE_ERROR				    ("Task Reassignment for task ITT %u, "				     "returned response %d\n",				     related_command->ref_task_tag,				     header->response);				TRACE(TRACE_DEBUG,				      "Freeing related command, ITT %u\n",				      related_command->ref_task_tag);				if (cmd->SCpnt != NULL) {					/* pass the final status back up					 * to SCSI Mid-level					 */					cmd->SCpnt->result = DID_ERROR << 16;				}				cmd->cmd_state |= CMD_STATE_RXDONE;				free_pending_command(cmd, current_connection);			}		} else {			/* could not find the corresponding command --			 * reject task mgt. command			 */			TRACE_ERROR("No task with ITT %u found\n",				    related_command->ref_task_tag);		}		TRACE(TRACE_DEBUG, "Freeing Task Mgt. request, ITT %u\n",		      related_command->init_task_tag);		related_command->cmd_state |= CMD_STATE_RXDONE;		free_pending_command(related_command, current_connection);		current_session->n_rec_tasks--;	}	/* wake up the process waiting on task_mgt_sem semaphore */	up(&current_connection->task_mgt_sem);out:	TRACE(TRACE_ENTER_LEAVE, "Leave rx_task_mgt_rsp ,current_connection"	      " %p\n", current_connection);	return 1;		/* nothing but success here */}/*RFC 3720 Section 10.17.1 Reason (field in Reject Response) */static char *reject_reasons[] = {	/* 0x02 */	"Data Digest Error",	/* 0x03 */	"SNACK Reject",	/* 0x04 */	"Protocol Error",	/* 0x05 */	"Command not supported",	/* 0x06 */	"Too many immediate commands",	/* 0x07 */	"Task in progress",	/* 0x08 */	"Invalid Data ACK",	/* 0x09 */	"Invalid PDU field",	/* 0x0a */	"Long Operation Reject",	/* 0x0b */	"Negotiation Reset",	/* 0x0c */	"Waiting for Logout"	};/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the Reject header. * Parameters: current_connection which is a ptr to the connection struct *			  where the Reject header was received. * Return Value: 0 to terminate the rx thread gracefully, 1 to keep going ***************************************************************************/static intrx_rjt(struct connection *conn, __u32 size, char *buffer){	int retval = 1, found;	__u32 local_itt;	struct iscsi_targ_rjt *rjt_header;	struct generic_pdu *bad_header;	struct iscsi_init_snack *header;	struct iscsi_init_scsi_cmnd *iscsi_cmd;	struct command *related_command;	struct session *sess;	struct scsi_sense_data *senseinfo;	char local_message[32], *local_ptr;	TRACE(TRACE_ENTER_LEAVE, "Enter rx_rjt, conn %p\n",	      conn);	sess = conn->my_session;	rjt_header = (struct iscsi_targ_rjt *)conn->rx_buf;	bad_header = (struct generic_pdu *)buffer;	if (unlikely(rjt_header->reason < REASON_DATA_DIGEST_ERR	    || rjt_header->reason > REASON_WAITING_FOR_LOGOUT)) {		sprintf(local_message, "out of range [0x%02x..0x%02x]",			REASON_DATA_DIGEST_ERR, REASON_WAITING_FOR_LOGOUT);		retval = 0;	/* fatal */		local_ptr = local_message;	} else {		local_ptr = reject_reasons[rjt_header->reason						- REASON_DATA_DIGEST_ERR];		if (rjt_header->reason >= REASON_PROTOCOL_ERR)			retval = 0;	/* fatal -- can't handle these yet */	}	/* Reject does NOT have an ITT value (i.e., it is 0xffffffff) */	if (likely(bad_header != NULL && size >= ISCSI_HDR_LEN)) {		local_itt = htonl(bad_header->init_task_tag);		related_command = find_command_by_itt(local_itt, conn);		TRACE_ERROR("Got Reject for ITT %u, reason 0x%02x: %s\n",			    local_itt, rjt_header->reason, local_ptr);		printk("header of rejected pdu:\n");		dump_buffer((__u8 *)buffer, size);	} else {		local_itt = ALL_ONES;		related_command = NULL;		TRACE_ERROR("Got Reject with bad data, reason 0x%02x: %s\n",			    rjt_header->reason, local_ptr);	}#ifdef ISCSI_CHECK_PDU_FORMAT	/* Check that reserved fields are zero */	if (unlikely(!((rjt_header->flags & ~F_BIT) == 0	      && rjt_header->rsvd2 == 0	      && rjt_header->rsvd4 == 0 && rjt_header->rsvd5 == 0))) {		reserved_not_0("Reject");	}#endif	if (retval == 0) {		/* look for reject of R2T SNACK previously sent on a write */		if (related_command != NULL && related_command->SCpnt != NULL			&& (bad_header->opcode & ISCSI_OPCODE)==ISCSI_INIT_SNACK			&& related_command->activity_flg == 2			&& sess->oper_param->ErrorRecoveryLevel > 0			&& sess->retran_period > 0			&& related_command->SCpnt->sc_data_direction					== SCSI_DATA_WRITE) {			/* found it, don't let this Reject advance the StatSN,			 * then wake up tx thread to send Status SNACK */			conn->exp_stat_sn = ntohl(bad_header->exp_stat_sn);			related_command->time_stamp -= sess->retran_period * HZ;			if (atomic_read(&conn->tx_sem.count) <= 0) {				/* get xmit thread going */				TRACE(TRACE_ISCSI_FULL,					"rx_r2t: wake up tx thread\n");				up(&conn->tx_sem);			}			retval = 1;	/* not fatal */		}		goto rjt_out;	}	/* ignore target digest errors and wait for target to send out any	 * recovery R2Ts new 18_04 - SAI	 */	if (rjt_header->reason == REASON_DATA_DIGEST_ERR) {		if ((iscsi_cmd=(struct iscsi_init_scsi_cmnd *)buffer) == NULL) {			retval = 0;	/* fatal */			goto rjt_out;		}		if (sess->retran_period > 0				&& (iscsi_cmd->opcode & ISCSI_OPCODE)						== ISCSI_INIT_SCSI_CMND) {			/* pdu was a SCSI Command, so there must have been data			 * attached (to generate digest error), so it must have			 * been a write. Therefore, if this is the first such			 * reject, set timestamp so it will be reissued at once			 */			if (related_command) {				related_command->time_stamp -=						sess->retran_period * HZ;				TRACE_ERROR("Reject due to Data Digest Error, "					 "retransmit command\n");				if (atomic_read(&conn->tx_sem.count) <= 0) {					/* get xmit thread going */					TRACE(TRACE_ISCSI_FULL,						"rx_r2t: wake up tx thread\n");					up(&conn->tx_sem);				}				goto rjt_out;			}		}		TRACE_ERROR("Reject due to Data Digest Error, do nothing\n");		goto rjt_out;	}	/* for all other type of rejects, abort the related command - SAI */	if (unlikely(bad_header == NULL)) {		TRACE_ERROR("Reject data buffer empty, ignore\n");		retval = 0;	/* fatal */		goto rjt_out;	}	/* in case the rejected command was a SNACK */	header = (struct iscsi_init_snack *)buffer;	if (unlikely(size < ISCSI_HDR_LEN)) {		TRACE_ERROR		    ("Reject DSL = %u less than header length %u, ignore\n",		     size, ISCSI_HDR_LEN);		retval = 0;	/* fatal */		goto rjt_out;	}	if (rjt_header->reason == REASON_DATA_SNACK) {		/* If the rejected SNACK is any other than Data/R2T		 * or Status, it's an error - SAI		 */		if (((header->flags & SNACK_TYPE) != DATA_R2T_SNACK)		    && ((header->flags & SNACK_TYPE) != STATUS_SNACK)) {			TRACE_ERROR			    ("Expected Data/R2T or Status header in Reject PDU,"			     " got type 0x%02x", (header->flags & SNACK_TYPE));			retval = 0;	/* fatal */			goto rjt_out;		}	}	/* if this ITT is not reserved, we should find a matching command */	found = 0;	list_for_each_entry(related_command,			    &conn->pending_commands,			    link) {		/* Status SNACK always has the ITT as ALL_ONES.		 * So for status snack, do not check for ITT --		 * new 18_04 SAI		 */		if (rjt_header->reason == REASON_DATA_SNACK		    && (header->flags & SNACK_TYPE) == STATUS_SNACK) {			if (related_command->snack_flags & STATUS_BIT) {				/* Do not terminate on SNACK reject - SAI */				TRACE(TRACE_DEBUG,				      "Found corresponding Status SNACK request"				      " - ITT %u\n",				      related_command->init_task_tag);				found = 1;				break;			}		} else if (related_command->init_task_tag == local_itt) {			found = 1;			break;		}	}	if (unlikely(found == 0)) {		TRACE_ERROR("No command has matching ITT %u\n", local_itt);		/* silently discard any snack rejects that appear delayed-SAI */		goto rjt_out;	}	/* all rejects should terminate the related command - SAI */	if (unlikely(related_command->SCpnt == NULL)) {		if (related_command->header_opcode == ISCSI_INIT_SCSI_CMND) {			/* No pointer to the SCSI Mid-level struct, bail out */			TRACE_ERROR("ITT %u command struct has SCpnt=NULL\n",				    local_itt);			retval = 0;	/* fatal */		}		if (sess->oper_param->SessionType) {			/* this is a discovery session, send a			 * logout to shut it down			 */			drive_logout(sess, conn, LOGOUT_CLOSE_SESSION);		}	} else {		/* We need to increment the exp_stat_sn as we will		 * not receive the missing status anymore		 */		conn->exp_stat_sn++;		related_command->SCpnt->result |= (DID_ERROR << 16);		senseinfo = (struct scsi_sense_data *)		    		related_command->SCpnt->sense_buffer;		memset(senseinfo, 0, sizeof(struct scsi_sense_data));		/* Draft 20 Section 10.4.7.2 Sense Data		 * Shows table of sense values		 */		/* Valid Bit set, Response = 0x70 */		senseinfo->response = 0xf0;		senseinfo->sense_key = ABORTED_COMMAND;	/* Protocol CRC Error */		senseinfo->asl = 10;	/* n-7 = 17-7 = 10 */		senseinfo->asc = 0x47;	/* Protocol CRC Error					   Additional Sense Code */		senseinfo->ascq = 0x05;	/* Protocol CRC Error					   Additional Sense Code qualifier */		related_command->SCpnt->result |= (DRIVER_SENSE << 24);	}	/* always free up the related command */	related_command->cmd_state |= CMD_STATE_RXDONE;	free_pending_command(related_command, conn);rjt_out:	TRACE(TRACE_ENTER_LEAVE, "Leave rx_rjt, retval %d\n", retval);	return retval;}/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the NopIn header. * 4 combinations of ITT and TTT to look for (resvd value is 0xffffffff): *TTT		ITT	StatSN	Respond *resvd		resvd	?	simple 	update to command window *resvd		!=resvd +1	no	response to NopOut sent by us *!=resvd	resvd 	+0	yes	provoke "ping" response from us *!=resvd	!=resvd	NA	NA	illegal * * Parameters: current_connection which is a ptr to the connection struct *			  where the NopIn header was received. * Return Value: >0 success (always) ***************************************************************************/static intrx_nopin(struct connection *current_connection, __u32 local_itt,	 struct command *related_command, __u32 size, char **buffer){	struct iscsi_targ_nopin *header;	struct session *related_session;	struct iscsi_init_nopout *nopout_cmd;	__u32 lun;	TRACE(TRACE_ENTER_LEAVE, "Enter rx_nopin, current_connection %p\n",	      current_connection);	header = (struct iscsi_targ_nopin *) current_connection->rx_buf;#ifdef ISCSI_CHECK_PDU_FORMAT	/* Check that reserved fields are zero */	if (unlikely(!((header->flags & ~F_BIT) == 0	      && header->rsvd1 == 0	      && header->rsvd2 == 0 && header->rsvd3 == 0))) {		reserved_not_0("NopIn");	}#endif	related_session = current_connection->my_session;	if (unlikely(size > current_connection->max_send_length)) {		/* don't send back more than target wants to get */		size = current_connection->max_send_length;	}	if (header->target_xfer_tag == ALL_ONES) {		/* sent by target either as a response to a NopOut		 * sent earlier by us or as a means to update the		 * command window.  In both cases, no response is		 * needed from the initiator.		 */		if (local_itt == ALL_ONES) {			/* this is not a response to a NopOut sent			 * earlier by us, but is just a simple update			 * of the command window and this has already			 * been done, so we are finished.			 */		} else {			/* this NopIn is a response to a NopOut sent			 * earlier by us			 */			if (related_command != NULL) {				/* found the corresponding NopOut command,					check it */				nopout_cmd = (struct iscsi_init_nopout *)				    &related_command->iscsi_cmd;				if ((nopout_cmd->opcode & ISCSI_OPCODE)							!= ISCSI_INIT_NOP_OUT) {					TRACE_ERROR					    ("Command matching NopIn has opcode"

⌨️ 快捷键说明

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