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

📄 iscsi_initiator.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	initiator/iscsi_initiator.c * *	vi: set autoindent tabstop=8 shiftwidth=8 : * *	This file contains the core functions for iscsi initiator code that are *	responsible for connecting and maintaining sessions between initiator *	and target. The object file generated is the loadable kernel module. * *	Copyright (C) 2001-2004 InterOperability Lab (IOL) *	University of New Hampshire (UNH) *	Durham, NH 03824 * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2, or (at your option) *	any later version. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, *	USA. * *	The name of IOL and/or UNH may not be used to endorse or promote  *	products derived from this software without specific prior  * 	written permission.*/#include "iscsi_initiator.h"#include "initiator_utilities.h"#include "initiator_error_rec.h"#include "initiator_proc_iface.h"#include "../common/lun_packing.h"#include <linux/reboot.h>/* max number of redirects to follow during login on any connection */#define	MAX_REDIRECTION_RETRIES	2/* Holds pointer to private data part of Scsi_Host structure. * This is set up once, by iscsi_detect() * which is called when the initiator module is loaded */struct iscsi_hostdata *global_hostdata = NULL;/* Holds pointer to the registered Scsi_Host */struct Scsi_Host *global_host = NULL;/* Used for all access to the shared structures, and during the operation * of any single thread to prevent things from disappearing from under * the thread.*//* dummy that always returns false */inttarget_in_use(__u32 id){return 0;}UNH_LOCK_TYPE host_data_lock = UNH_LOCK_UNLOCKED;/* Mike Christie, mikenc@us.ibm.com */static int iscsi_initiator_halt(struct notifier_block *nb, ulong event,				void *buf);/* Mike Christie, mikenc@us.ibm.com *//* reboot notifier */static struct notifier_block iscsi_initiator_notifier = {		iscsi_initiator_halt, NULL, 0};/* * either the session->sess_lock MUST be held by the calling process/thread * or the session structure must not be active yet. * increase maximum number command structures session may use to: * 	(MAX_COMMANDS_PER_LUN + 1) * n_luns_in_session * (one extra in case of task-management and/or nopout commands) * Returns 1 on success, 0 on failure. */static int __attribute__ ((no_instrument_function))preallocate_commands(struct session *sess){	__u32 limit;	struct command *new_command;	limit = (MAX_COMMANDS_PER_LUN + 1) * sess->n_luns_in_session;	while (sess->n_commands_alloced < limit) {		new_command = (struct command *)my_kmalloc(					sizeof(struct command), "command");		if (unlikely(new_command == NULL)) {			return 0;		}		/* each new command goes at end of session's free list */		endup_command(new_command, sess);		sess->n_commands_alloced++;	}	TRACE(TRACE_DEBUG,"%u commands now allocated to session %p target %u\n",		sess->n_commands_alloced, sess, sess->scsi_target_id);	return 1;}/* * the session->sess_lock MUST be held by the calling process/thread. * reduce maximum number command structures session may use to: * 	(MAX_COMMANDS_PER_LUN + 1) * n_luns_in_session */static void __attribute__ ((no_instrument_function))unallocate_commands(struct session *sess){	__u32 limit;	struct command *old_command;	struct list_head *lptr;	limit = (MAX_COMMANDS_PER_LUN + 1) * sess->n_luns_in_session;	while (sess->n_commands_alloced > limit		&& !list_empty(&sess->free_commands)) {		lptr = sess->free_commands.next;		list_del(lptr);		old_command = list_entry(lptr, struct command, link);		my_kfree((void **)&old_command, "command");		sess->n_commands_alloced--;	}	TRACE(TRACE_DEBUG,"%u commands now allocated to session %p target %u\n",		sess->n_commands_alloced, sess, sess->scsi_target_id);}/* initialize all fields in struct iscsi_targetdata for one target */voidinit_targetdata(struct iscsi_targetdata *targ_data){	/* Initialize all fields to 0 or NULL */	memset(targ_data, 0, sizeof(struct iscsi_targetdata));	/* now go back and initialize those that are not 0 or NULL by default */	targ_data->isid_type = DEFAULT_ISID_TYPE;	targ_data->isid_number = DEFAULT_ISID_NUMBER;	targ_data->isid_qualifier = DEFAULT_ISID_QUALIFIER;	targ_data->auth_parameter.chap_local_ctx = CHAP_InitializeContext();	targ_data->auth_parameter.chap_peer_ctx = CHAP_InitializeContext();	targ_data->auth_parameter.srp_ctx = SRP_InitializeContext();	/* Initialize parameter list to a copy of default set of parameters */	param_tbl_init(targ_data->param_tbl);}/* uninitialize fields in struct iscsi_targetdata that need freeing */voiduninit_targetdata(struct iscsi_targetdata *targ_data){	param_tbl_uncpy(targ_data->param_tbl);        SRP_FinalizeContext(targ_data->auth_parameter.srp_ctx);	CHAP_FinalizeContext(targ_data->auth_parameter.chap_peer_ctx);        CHAP_FinalizeContext(targ_data->auth_parameter.chap_local_ctx);}/**************************************************************************** Called from iscsi_initiator_detect() and unh_iscsi_probe().* Initializes the hostdata structure.* Creates the parameter table for this hostdata.* Returns non-NULL pointer to parameter table if ok, NULL if error.***************************************************************************/static void __attribute__ ((no_instrument_function))init_initiator(struct iscsi_hostdata *hostdata){	int i;	struct iscsi_targetdata *targ_data;	TRACE(TRACE_ENTER_LEAVE, "Enter init_initiator, hostdata %p\n",	      hostdata);	/* Initialize all fields to 0 or NULL */	memset(hostdata, 0, sizeof(struct iscsi_hostdata));	/* now go back and initialize those that are not 0 or NULL by default */	INIT_LIST_HEAD(&hostdata->session_list);	for (i = 0, targ_data = hostdata->target_data;		i < MAX_TARGET_IDS;		targ_data++, i++) {		init_targetdata(targ_data);	}	TRACE(TRACE_ENTER_LEAVE, "Leave init_initiator\n");}/**************************************************************************** Called by the scsi subsystem when the iscsi_initiator module is loaded.* (via the detect field in the Scsi_Host_Template driver_template)* This allows the iscsi_initiator driver code to register itself with the* SCSI Mid-level as being the driver for this type of host adapter.* It registers space for iscsi_hostdata struct with the SCSI Mid-level.* When called, io_request_lock is held by the midlevel caller.* It returns:* 	n > 0 if ok, where n is number of host adapters of this type*		on this system (all will be driven by this code);* 	n < 0 on error.***************************************************************************/static intiscsi_initiator_detect(Scsi_Host_Template * tmpt){	int retval = 1;	struct Scsi_Host *host = NULL;	TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_initiator_detect, tmpt %p\n",	      tmpt);	/* scsi_register() is defined in linux/drivers/scsi/hosts.c */	host = scsi_register(tmpt, sizeof(struct iscsi_hostdata));	TRACE(TRACE_DEBUG, "Back from scsi_register, host %p\n", host);	if (unlikely(host == NULL)) {		retval = -1;		goto out;	}	TRACE(TRACE_ISCSI, "registered UNH iSCSI host number %d\n",	      host->host_no);	/* setup the security key hash table */	setup_security_hash_table();	/* three standard default values which can be overridden:	 * host->max_channel = 0;	 * host->max_id = 8;	 * host->max_lun = 8;	 */	/* set the number of allowed "targets" this adaptor "card" can handle.	*  the "target" numbers will be [0..max_id-1].	*   each "target" will have LUN numbers in [0..max_lun-1].	*/	host->max_id = MAX_TARGET_IDS;	host->max_lun = MAX_LUNS;	/* set the maximum number of bytes we will accept in a scsi cdb */	host->max_cmd_len = MAX_CDB_LEN;	/* scsi_register() allocated space for our private structure at the end	 *  of the host structure. This global variable is cheating!	 *  Potentially each (physical) adaptor card can have its own hostdata.	 *  We get away with having a single global variable here because	 *  we know we will never have more than 1 adaptor of this type ever.	*/	global_hostdata = (struct iscsi_hostdata *) host->hostdata;	global_host = host;	/* Initialize the adapter's private data structure */	init_initiator(global_hostdata);	(void) initiator_register_device();	/* Mike Christie, mikenc@us.ibm.com */	register_reboot_notifier(&iscsi_initiator_notifier);	TRACE(TRACE_DEBUG, "Register iSCSI host adapter \"%s\"\n",	      tmpt->proc_name);out:	TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_initiator_detect, retval %d\n",	      retval);	return retval;}/* called only when session->sched_scheme is CONN_SCHED_LUN. * the session->sess_lock MUST be held by the calling process/thread. * the host_data_lock MAY be held by the calling process/thread. * find the connection with the fewest number of LUNs assigned to it * and then to assign this lun to it */static void __attribute__ ((no_instrument_function))locked_add_lun_to_sess(__u32 lun, struct session *session){	__u32 min_count;	struct connection *conn, *sofar;	/* find the connection with the fewest luns assigned to it */	min_count = MAX_LUNS;	sofar = NULL;	for (conn = session->connection_head;	     conn != NULL;	     conn = conn->next) {		if (conn->connection_state == CONNECTION_FULL_FEATURE_PHASE			&& min_count > conn->assigned_lun_count) {			min_count = conn->assigned_lun_count;			sofar = conn;		}	}	if (sofar) {		session->lun_assignments[lun] = sofar;		sofar->assigned_lun_count++;		printk("Assign lun %u to connection %u, %u luns assigned\n",			lun, sofar->connection_id,			sofar->assigned_lun_count);	}}/* * when called, NO LOCKS SHOULD BE LOCKED! * find the connection with the fewest number of LUNs assigned to it * and then to assign this lun to it */static void __attribute__ ((no_instrument_function))add_lun_to_sess( __u32 lun, struct session *session ){	unsigned long lock_flags;	UNH_LOCK(&session->sess_lock, lock_flags);	/* find the connection with the fewest luns assigned to it */	locked_add_lun_to_sess(lun, session);	UNH_UNLOCK(&session->sess_lock, lock_flags);}/* * host_data_lock and sess->sess_lock MUST be held by the calling process/thread * called only when this lun is assigned to a specific connection * remove this lun from this session's table of assigned connections.*/static void __attribute__ ((no_instrument_function))locked_drop_lun_from_sess(__u32 lun, struct session *sess, int free_inquiry){	struct connection *conn;	/* this lun was assigned to this connection, unassign it now */	conn = sess->lun_assignments[lun];	sess->lun_assignments[lun] = NULL;	if (free_inquiry)		free_inquiry_stuff(sess, lun);	conn->assigned_lun_count--;	printk("Unassign lun %u from connection %u, %u luns assigned\n",		lun, conn->connection_id,		conn->assigned_lun_count);}/* * the host_data_lock MUST be held by the calling process/thread. * remove this lun from this session's table of assigned connections. */static void __attribute__ ((no_instrument_function))drop_lun_from_sess(__u32 lun, struct session *session){	unsigned long lock_flags;	if (session->lun_assignments[lun]) {		UNH_LOCK(&session->sess_lock, lock_flags);		/* this lun was assigned to this connection, unassign it now */		locked_drop_lun_from_sess(lun, session, 1);		UNH_UNLOCK(&session->sess_lock, lock_flags);	}}/* * when called, NO LOCKS SHOULD BE LOCKED! * find a lun that is already in use in this session. * returns -1 on error, else lun number in range [0..31] */intfind_used_lun(struct session *sess){	int lun;	if (unlikely(sess->lun_bits == 0)) {		TRACE_ERROR		    ("No LUNs currently in use by session %p target %u\n", sess,		     sess->scsi_target_id);		lun = -1;	} else {		/* at least 1 bit set in lun_bits, find the smallest		 * numbered 1 bit		 */		for (lun = 0; !(sess->lun_bits & (1 << lun)); lun++) {		}	}	return lun;}/* * when called, NO LOCKS SHOULD BE LOCKED! * Create a new recovery connection to keep the iSCSI session active. * Remember, iscsi requires at least one connection in a session to be active * for the session to be alive - SAI * Returns 1 on success, 0 on failure. */intcreate_rec_conn(struct connection *conn){	__u32 connid;	int lun, retval;	struct connection *this_conn;	struct session *sess = conn->my_session;	struct iscsi_targetdata *targ_data;	struct sockaddr *new_ip_address;	int new_ip_length;	unsigned long flags, lock_flags;	TRACE(TRACE_ENTER_LEAVE, "Entering create_rec_conn\n");

⌨️ 快捷键说明

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