📄 scsi_target.c
字号:
/* 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 + -