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

📄 iscsi_initiator.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	connid = conn->connection_id;	TRACE(TRACE_DEBUG, "Only connection available is %p, id %u -"	      "Create new connection for recovery\n", conn, connid);	targ_data = &global_hostdata->target_data[sess->scsi_target_id];	restore_global_data(targ_data);	targ_data->nop_period = 0;	targ_data->init_sess_flags = 0;	targ_data->init_conn_flags = 0;	global_hostdata->init_sessrec_flg = 0;	/* find a connection id that is not yet used in this session */      retry:	connid++;	for (this_conn = sess->connection_head; this_conn;	     this_conn = this_conn->next) {		if (this_conn->connection_id == connid) {			/* this id already in use, try the next one */			goto retry;		}	}	/* find a lun that is already in use in this session */	lun = find_used_lun(sess);	if (unlikely(lun < 0)) {		retval = 0;		goto out;	}	/* got the lun, now create a new recovery session */	if (dup_inet_struct(conn->ip_address, &new_ip_address,							&new_ip_length) < 0		|| create_session(sess->scsi_target_id, new_ip_address,				new_ip_length, lun, connid, global_host) != 0) {		TRACE_ERROR("Unable to create recovery connection\n");		retval = 0;		goto out;	}	/* if any luns were assigned to old connection, reassign them */	if (conn->assigned_lun_count) {		UNH_LOCK(&host_data_lock, flags);		UNH_LOCK(&sess->sess_lock, lock_flags);		for (lun = 0; lun < MAX_LUNS; lun++) {			if (conn == sess->lun_assignments[lun]) {				locked_drop_lun_from_sess(lun, sess, 0);				locked_add_lun_to_sess(lun, sess);			}		}		UNH_UNLOCK(&sess->sess_lock, lock_flags);		UNH_UNLOCK(&host_data_lock, flags);	}	retval = 1;out:	TRACE(TRACE_ENTER_LEAVE, "Leaving create_rec_conn, retval = %d\n",		retval);	return retval;}/* * when called, NO LOCKS SHOULD BE LOCKED! * release a socket and free the connection structure */void __attribute__ ((no_instrument_function))free_connection(struct connection *conn){	char ip_string[INET6_ADDRSTRLEN+2], port_string[8];	if (conn->sock != NULL) {		TRACE(TRACE_NET, "Releasing socket %p\n", conn->sock);		if (cnv_inet_to_string(conn->ip_address, ip_string,					port_string) > 0) {			printk("Disconnected from %s:%s\n", ip_string,				port_string);		}		sock_release(conn->sock);		TRACE(TRACE_NET, "Released socket %p\n", conn->sock);		conn->sock = NULL;	}	TRACE(TRACE_NET, "Free ip_address %p\n", conn->ip_address);	my_kfree((void **)&conn->ip_address, "ip_address");	TRACE(TRACE_NET, "Free local_ip_address %p\n", conn->local_ip_address);	my_kfree((void **)&conn->local_ip_address, "local_ip_address");	TRACE(TRACE_DEBUG, "%s Free conn %p\n", current->comm, conn);	my_kfree((void **)&conn, "connection");}/* * when called, NO LOCKS SHOULD BE LOCKED! * clear disconnected and unused connections - SAI */void __attribute__ ((no_instrument_function))clear_free_conn(struct session *sess){	struct connection *prev, *conn;	if (!sess->connection_head) {		TRACE_ERROR("No Valid connections available\n");		return;	}	if (sess->nconnections <= 1	    && sess->connection_head->connection_state==CONNECTION_RECOVERING) {		/* No connections available - Need to create a new one - SAI */		create_rec_conn(sess->connection_head);	}	for (prev = NULL, conn = sess->connection_head;	     conn != NULL;	     conn = conn->next) {		if ((conn->connection_state == CONNECTION_NOT_PRESENT)) {			TRACE(TRACE_ISCSI, "Releasing connection %p\n", conn);			if (prev == NULL)				sess->connection_head = conn->next;			else				prev->next = conn->next;			/* Adjust the round robin connection head - SAI */			if (conn == sess->rr_conn_head) {				sess->rr_conn_head = prev;			}			free_connection(conn);			break;		}		prev = conn;	}	return;}/* * executed by scsi midlevel process and rx thread * the session->sess_lock MUST be held by the calling process/thread. * performs round-robin scheduling by picking up at last connection we * scheduled and moving to next one that is in full feature phase. * Returns pointer to next connection to schedule, and leaves session's * rr_conn_head pointing to it. */static struct connection * __attribute__ ((no_instrument_function))do_round_robin(struct session *session){	int nconn;	struct connection *conn;	if ((conn = session->rr_conn_head) == NULL	   || (conn = conn->next) == NULL)		conn = session->connection_head;	for (nconn = 0; nconn < session->nconnections; nconn++) {		if (conn->connection_state == CONNECTION_FULL_FEATURE_PHASE)			break;		if ((conn = conn->next) == NULL)			conn = session->connection_head;	}	return session->rr_conn_head = conn;}/* * executed by scsi midlevel process and rx thread * the session->sess_lock MUST be held by the calling process/thread. * Multiple Connection Scheduling Algorithm - SAI */struct connection * __attribute__ ((no_instrument_function))get_connection(struct scsi_cmnd * Cmnd, struct session *sess){	struct connection *conn;	TRACE(TRACE_ENTER_LEAVE, "Entering get_connection\n");	switch (sess->sched_scheme) {	case CONN_SCHED_RR:		/* get the next connection in the round-robin */		if (sess->nconnections == 1)			conn = sess->connection_head;		else {			conn = do_round_robin(sess);		}		break;	case CONN_SCHED_LUN:		/* get the connection assigned to this LUN */#ifdef K26		conn = sess->lun_assignments[Cmnd->device->lun];#else		conn = sess->lun_assignments[Cmnd->lun];#endif		break;	default:		/* use only one connection */		conn = sess->connection_head;		break;	}	TRACE(TRACE_ENTER_LEAVE, "Leaving get_connection\n");	return conn;}/****************************************************************************** When called, io_request_lock is held by the midlevel caller.* This function is called by the SCSI Mid-level whenever a Read/Write Request* has to be satisfied. This function will set up TCP buffers for sending SCSI* Command and, if the negotiated ImmediateData is 1, ImmediateData. After* setting up the TCP buffers, the tx thread is woken up which is waiting on* tx_sem.* Parameters: struct scsi_cmnd,*	  done function which is called when any SCSI Command is satisfied.* Return Value: 0, on success* 		-1, on failure (any non-zero value seems to work)** Note that the done() function should not be called until queuecommand returns!******************************************************************************/static intiscsi_initiator_queuecommand(struct scsi_cmnd * Cmnd,			     void (*done) (struct scsi_cmnd *)){	int retval = 0;		/* assume this function will succeed */	__u32 target_id;	struct iscsi_hostdata *hostdata;	struct session *current_session;	unsigned long flags, lock_flags;/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	target_id = Cmnd->device->id;#else	target_id = Cmnd->target;#endif	TRACE(TRACE_ENTER_LEAVE,	      "Enter iscsi_initiator_queuecommand, target id %u\n", target_id);/* RDR */#ifndef K26	/* must not hold io_request_lock when trying to get our locks */	spin_unlock(&io_request_lock);#endif	/* get exclusive access to the iscsi structures */	UNH_LOCK(&host_data_lock, flags);	if (unlikely(global_host == NULL || global_hostdata == NULL)) {		TRACE_ERROR("queuecommand called after shutdown\n");		retval = -1;		goto out;	}	/* get pointer to hostdata struct registered to the SCSI Mid-level *//* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	hostdata = (struct iscsi_hostdata *) Cmnd->device->host->hostdata;#else	hostdata = (struct iscsi_hostdata *) Cmnd->host->hostdata;#endif	if (unlikely(hostdata != global_hostdata)) {		TRACE_ERROR		    ("Hostdata struct %p not same as global_hostdata %p\n",		     hostdata, global_hostdata);		retval = -1;		goto out;	}	/* tell Mid-level when I am done receiving the SCSI Cmnd info. */	Cmnd->scsi_done = done;	/* Find out the session corresponding to the target_id */	current_session = find_session_by_id(target_id, hostdata);	/* Check that we have finished the Login Phase	 * with the concerned target and are now in the	 * full feature phase of a normal session	 */	if (unlikely(current_session == NULL	    || current_session->session_state != SESSION_FULL_FEATURE_PHASE	    || current_session->connection_head == NULL	    || current_session->connection_head->rx_thread == NULL	    || current_session->connection_head->tx_thread == NULL	    || current_session->oper_param->SessionType)) {		/* Check to see if session recovery is active - SAI */		if (global_hostdata && global_hostdata->init_sessrec_flg) {			/* changes for session recovery new 18_04 - SAI */			TRACE(TRACE_ISCSI, "iscsi_initiator_queuecommand : "			      "Recovery in Progress for target %u\n",			      target_id);			/* create a new session recovery structure or			 * get the already existing session recovery			 * structure depending on whether one or			 * multiple sessions participate in session			 * recovery - new 18_04 SAI			 */			/* NOTE XXX jpd 7/18/2003			 * this section has changed in ref20_17 compared			 * to ref20_10 (RPM 1.2.0) .			 * Needs investigations for lock spliting			 * per-session. I don't know why these are commented			 * out .			 */			/* create and store in a recovery session - SAI */			set_rec_group(Cmnd);			goto out;		}		printk("iscsi Target %u not logged in\n", target_id);		Cmnd->result = DID_NO_CONNECT << 16;		if (likely(done != NULL))			/* should not do this before queuecommand returns! */			done(Cmnd);		goto out;	}	UNH_LOCK(&current_session->sess_lock, lock_flags);	retval = scsi_to_iscsi(Cmnd, current_session);	UNH_UNLOCK(&current_session->sess_lock, lock_flags);out:	/* release our exclusive access to the iscsi structures */	UNH_UNLOCK(&host_data_lock, flags);	TRACE(TRACE_ENTER_LEAVE,	      "Leave iscsi_initiator_queuecommand, retval %d\n", retval);/* RDR */#ifndef K26	/* get back midlevel caller's lock */	spin_lock(&io_request_lock);#endif	return retval;}/***************************************************************************** * executed by scsi midlevel process and init_recovery thread * host_data_lock and sess->sess_lock MUST be held by the calling process/thread * This function takes the command and data from the scsi buffers, forms a new * iSCSI PDU with the corresponding command and data filled-in and attaches the * command to the end of the pending commands list for the session - SAI * scsi midlevel's SPIN_LOCK io_request_lock must NOT be held*****************************************************************************/intscsi_to_iscsi(struct scsi_cmnd * Cmnd, struct session *current_session){	int retval = 0;		/* assume this function succeeds */	__u32 lun;	struct iscsi_init_scsi_cmnd *iscsi_cmd;	struct command *new_command;	struct connection *conn;	TRACE(TRACE_ENTER_LEAVE, "Enter scsi_to_iscsi\n");/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	lun = Cmnd->device->lun;#else	lun = Cmnd->lun;#endif	if (current_session->nconnections <= 1)		conn = current_session->connection_head;	else {		/* multiple connections usage - SAI */		conn = get_connection(Cmnd, current_session);	}	if (unlikely(conn == NULL)) {		TRACE_ERROR("Session %u has no connections for lun %u\n",			    current_session->scsi_target_id, lun);		retval = -1;		goto out;	}	/* make sure connection is still in FFP */	if (unlikely(conn->connection_state != CONNECTION_FULL_FEATURE_PHASE)) {		/* rx_thread gone -- peer probably reset the connection */		Cmnd->result = DID_NO_CONNECT << 16;		if (likely(Cmnd->scsi_done != NULL)) {			/* can we do this before queuecommand returns?! */			call_back_scsi_done(Cmnd);		}		goto out;	}	/* get a new struct command to send SCSI Request PDU to target */	new_command = setup_command(Cmnd, conn);	if (unlikely(new_command == NULL)) {		retval = -1;		goto out;	}	/* set up the SCSI_Cmnd header that is to be sent to the target */	iscsi_cmd = &new_command->iscsi_cmd;	iscsi_cmd->opcode = ISCSI_INIT_SCSI_CMND;	/* SAM-2, section 4.12.2 LUN 0 address	 * "To address the LUN 0 of a SCSI device the peripheral device	 * address method shall be used."	 *	 * What this means is that whenever the LUN is 0, the full 8 bytes of	 * the LUN field in the iscsi PDU will also be 0. Because we have

⌨️ 快捷键说明

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