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

📄 scsi_target.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	target/scsi_target.c	vi: set autoindent tabstop=4 shiftwidth=4 : 	This file has all the functions for scsi midlevel on target side*//*	Copyright (C) 2001-2004 InterOperability Lab (IOL)					University of New Hampshier (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.*//* df revised begin */#ifndef LINUX_VERSION_CODE#include <linux/version.h>#endif#ifndef KERNEL_VERSION			/* pre-2.1.90 didn't have it */#define KERNEL_VERSION(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )#endif/* df revised end */#include <linux/proc_fs.h>#include "scsi_target.h"#include "../common/lun_packing.h"/*# define DEBUG_REGISTER# define DEBUG_DEREGISTER# define DEBUG_RX_CMND# define DEBUG_SCSI_DONE# define DEBUG_ALLOCN_LEN# define DEBUG_RX_DATA# define DEBUG_HANDLE_CMD# define DEBUG_SCSI_THREAD*//* FUNCTION DECLARATIONS */void scsi_target_process_thread(void *);# if defined (FILEIO) || defined (GENERICIO)static int build_filp_table(void);static void close_filp_table(void);# endif# if defined (FILEIO) || defined (MEMORYIO)/* Bjorn Thordarson, 9-May-2004 *//*****static int get_inquiry_response(Scsi_Request *, int);static int get_read_capacity_response(Scsi_Request *);*****/static int get_inquiry_response(Scsi_Request *, int, int);static int get_read_capacity_response(Target_Scsi_Cmnd *);# endifstatic int abort_notify(struct SM *);static void aen_notify(int, __u64);static int get_space(Scsi_Request *, int);static int hand_to_front_end(Target_Scsi_Cmnd *);static int handle_cmd(struct SC *);# ifdef GENERICIOstatic int fill_sg_hdr(Target_Scsi_Cmnd *, int);void signal_process_thread(void *);# endif# ifdef DISKIOstatic void te_cmnd_processed(Scsi_Cmnd *);static int fill_scsi_device(void);# endif#ifdef CONFIG_PROC_FSstatic int scsi_target_proc_info(char *buffer, char **start, off_t offset,								 int length);static int proc_scsi_target_gen_write(struct file *file, const char *buf,									  unsigned long length, void *data);static void build_proc_target_dir_entries(Scsi_Target_Device * the_device);#endifstruct proc_dir_entry *proc_scsi_target;/* RDR */#define MAX_FILE_NAME		64		/* limit on number of chars in file name */#define MAX_FILE_TARGETS	2		/* number of default file targets */#define MAX_FILE_LUNS		4		/* number of default file luns per target */struct target_map_item	{#if defined(DISKIO)#if defined(TRUST_CDB)		struct list_head link;		/* for doubly linked target_map_list */		int			target_id;		/* ordinal number of this target in list */#endif		Scsi_Device	*the_device;	/* a "real" scsi device */#endif#if defined(FILEIO) || defined(GENERICIO)		struct file	*the_file;		/* simulating scsi device with this file */		__u32		max_blocks;		/* maximum number of blocks in this file */		__u32		bytes_per_block;/* number of bytes in each block in file */		char		file_name[MAX_FILE_NAME];#endif		int			in_use;			/* 1 if this item is defined, else 0 */	};#if defined(DISKIO) && defined(TRUST_CDB)	/* doubly-linked circular list, one entry for every iscsi target	 * known to the scsi subsystem on this platform	 */	struct list_head target_map_list;#else	/* matrix with one entry for every possible target and lun */	static struct target_map_item target_map[MAX_TARGETS][MAX_LUNS];#endif/* mutex to control access to target_map array */DECLARE_MUTEX(target_map_sem);/* * Scsi_Target_Device: Maximum number of "active" targets at any time * Scsi_Target_Template: Maximum number of templates available * * The naming convention for variables is with the prefix "st" following * Eric's comments in the SCSI Initiator mid-level. * * The idea with the following variables is to have a generic linked * list of templates - there is one template for one "type" of device * whereas for each device there is a single entry in the device list */Target_Emulator target_data;/* * okay the following is to get something off the ground and working. * In the mode that the emulator is talking to a real disk drive, there * will be a need to map the id given to us by rx_cmnd to host, channel, * id as far as the SCSI mid-level is concerned. For the present moment * we map all of these to the same target. So all commands are directed * to different LUNs on a single device. I visualize this as being a * linked list of scsi disks attached to the system and whenever a * command is received, the rx_cmnd function does some id_lookup and map * the individual commands to one in the linked list. How this mapping * gets done is an upper level management function that I do not want to * deal with yet	ASHISH */int target_count = 0;# ifdef GENERICIOchar device[BYTE];# endif# ifdef FILEIOchar device[BYTE * 5];# endif/* * scsi_target_init_module: Initializes the SCSI target module * FUNCTION: carry out all the initialization stuff that is needed * INPUT: none * OUTPUT: 0: everything is okay * 	      else trouble */intscsi_target_init_module(void){	struct proc_dir_entry *generic;	debugInit("unh_scsi_target module Starting\n");#ifdef MEMORYIO	debugInit("unh_scsi_target using MEMORYIO\n");#endif#ifdef DISKIO#ifdef TRUST_CDB	debugInit("unh_scsi_target using DISKIO and TRUST_CDB\n");#else	debugInit("unh_scsi_target using DISKIO but not TRUST_CDB\n");#endif#endif#ifdef FILEIO	debugInit("unh_scsi_target using FILEIO\n");#endif#ifdef GENERICIO	debugInit("unh_scsi_target using GENERICIO\n");#endif	/* initialize the global target_data struct */	/*	 * initialize the target semaphore as locked because you want	 * the thread to block after entering the first loop	 */	init_MUTEX_LOCKED(&target_data.target_sem);	init_MUTEX_LOCKED(&target_data.thread_sem);	target_data.msg_lock = SPIN_LOCK_UNLOCKED;	target_data.st_device_list = NULL;	target_data.st_target_template = NULL;	target_data.cmd_queue_lock = SPIN_LOCK_UNLOCKED;	INIT_LIST_HEAD(&target_data.cmd_queue);	target_data.msgq_start = NULL;	target_data.msgq_end = NULL;	target_data.command_id = 0;	target_data.thread_id = NULL;# ifdef MEMORYIO		{/* in memory mode, all luns in all targets are always in use */			__u32 targ, lun;			for (targ = 0; targ < MAX_TARGETS; targ++) {				for (lun = 0; lun < MAX_LUNS; lun++) {					target_map[targ][lun].in_use = 1;				}			}			target_count = MAX_TARGETS * MAX_LUNS;		}# endif#if defined(DISKIO)#if defined(TRUST_CDB)	INIT_LIST_HEAD(&target_map_list);#endif	if (fill_scsi_device() == -1) {		printk("scsi_target_init_module: fill_scsi_device returned an error\n");		return -1;	}#endif	/*	 * create a list of devices that are available. This is a very	 * simplistic mapping of these devices. Each new device will	 * represent a new LUN. A new mapping function will have to	 * solve this problem - LATER - Ashish	 */# if defined(FILEIO) || defined(GENERICIO)	if (build_filp_table() < 0) {		printk("scsi_target_init_module: build_filp_table returned an error\n");		return -1;	}# endif#ifdef CONFIG_PROC_FS	proc_scsi_target = proc_mkdir("scsi_target", 0);	if (!proc_scsi_target) {		printk(KERN_ERR "cannot init /proc/scsi_target\n");		return -ENOMEM;	}	generic = create_proc_info_entry("scsi_target/scsi_target", 0, 0,									 scsi_target_proc_info);	if (!generic) {		printk(KERN_ERR "cannot init /proc/scsi_target/scsi_target\n");		remove_proc_entry("scsi_target", 0);		return -ENOMEM;	}	generic->write_proc = proc_scsi_target_gen_write;#endif	/* spawn a thread */	/* Bjorn Thordarson, 9-May-2004 -- start -- */	/*****	kernel_thread((int (*)(void *)) scsi_target_process_thread, NULL, 0);	*****/	if (target_count > 0) {		kernel_thread((int (*)(void *)) scsi_target_process_thread, NULL, 0);	}	/* Bjorn Thordarson, 9-May-2004 -- end -- */	return 0;}/* * scsi_target_cleanup_module: Removal of the module from the kernel * FUNCTION: carry out the cleanup stuff * INPUT: None allowed * OUTPUT: None allowed */voidscsi_target_cleanup_module(void){#ifdef GENERICIO	/* close all the devices that you have opened */	close_filp_table();	if (target_data.signal_id != NULL) {		send_sig(SIGKILL, target_data.signal_id, 1);		down_interruptible(&target_data.signal_sem);	}#endif#ifdef FILEIO	close_filp_table();#endif#if defined(DISKIO) && defined(TRUST_CDB)	struct list_head *lptr, *next;	struct target_map_item *this_item;	list_for_each_safe(lptr, next, &target_map_list) {		list_del(lptr);		this_item = list_entry(lptr, struct target_map_item, link);		kfree(this_item);	}#endif#ifdef CONFIG_PROC_FS	/* Don't show the /proc/scsi_target files */	remove_proc_entry("scsi_target/scsi_target", 0);	remove_proc_entry("scsi_target", 0);#endif	/* kill the thread */	if (target_data.thread_id != NULL) {		send_sig(SIGKILL, target_data.thread_id, 1);		down_interruptible(&target_data.thread_sem);	}	printk("scsi_target module Exiting\n");}module_init(scsi_target_init_module);module_exit(scsi_target_cleanup_module);/* * Returns 1 if any luns for this target are in use. * Returns 0 otherwise. */inttarget_in_use(__u32 target_id){	int result = 0;	if (!down_interruptible(&target_map_sem)) {#if defined(DISKIO) && defined(TRUST_CDB)		struct target_map_item *this_item;		list_for_each_entry(this_item, &target_map_list, link) {			if (this_item->target_id == target_id && this_item->in_use) {				result = 1;				break;			}		}#else	if (target_id < MAX_TARGETS) {		__u32 lun;		for (lun = 0; lun < MAX_LUNS; lun++) {			if (target_map[target_id][lun].in_use) {				result = 1;				break;			}		}	}#endif		up(&target_map_sem);	}	return result;}/* * register_target_template: to register a template with the midlevel * FUNCTION: to add the midlevel template to the linked list * INPUT: pointer to the template * OUTPUT: 0 for successful registration * 	   < 0 for trouble */intregister_target_template(Scsi_Target_Template * the_template){	int check;	Scsi_Target_Template *st_current;	if (!the_template) {		/* huh */		printk			("register_target_template: Refusal to register a NULL template\n");		return -1;	}	the_template->device_usage = 0;	/* check if the template is already in the list */	for (st_current = target_data.st_target_template; st_current != NULL;		 st_current = st_current->next) {		/* loop */# ifdef DEBUG_REGISTER		printk("Looping template\n");# endif		if (!strcmp(target_data.st_target_template->name, the_template->name))			break;	}	if (st_current != NULL) {	/* template is old */		printk("register_target_template: Template already present\n");		return -1;	}	the_template->next = target_data.st_target_template;	target_data.st_target_template = st_current = the_template;# ifdef DEBUG_REGISTER	printk("module count increased\n");# endif/* Ming Zhang, mingz@ele.uri.edu */#ifndef K26	MOD_INC_USE_COUNT;#endif	/* check if the device has a detect function */	if (st_current->detect) {		/* detect the device */		check = st_current->detect(the_template);		if (check < 0) {		/* error */			printk("Hosts detected: %d .. removing template\n", check);			deregister_target_template(the_template);			return check;		} else {			printk("Hosts detected: %d ... incrementing device usage\n", check);		}	} else {		printk			("register_target_template: template does not have a detect function\n");		deregister_target_template(the_template);		return -1;	}	return 0;}/* * deregister_target_template: * FUNCTION: removal of the target template from the list * INPUT: pointer to STT * OUTPUT: 0 for successful deregistration * 	   else < 0 for trouble */intderegister_target_template(Scsi_Target_Template * the_template){	Scsi_Target_Template *st_current, *st_prev = NULL;	Scsi_Target_Device *st_dev_curr;	st_dev_curr = target_data.st_device_list;	if (!the_template) {		/* huh */		printk("deregister_target_template: Cannot remove a NULL template\n");		return -1;	}	/* remove devices that are using this template */	while (st_dev_curr && st_dev_curr->template		   && (st_dev_curr->template->device_usage > 0)) {		st_dev_curr = target_data.st_device_list;		while (st_dev_curr) {

⌨️ 快捷键说明

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