- Module scst_user and user space utility to test it added

- Support for per-target default security groups added
 - FILEIO made multithreaded
 - BLOCKIO made async
 - Other improvements, fixes and cleanups


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@121 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-05-31 17:11:57 +00:00
parent 581cb5cd4f
commit 61b0176514
22 changed files with 6371 additions and 122 deletions
+29 -1
View File
@@ -22,33 +22,39 @@ SCST_DIR=scst
QLA_INI_DIR=qla2x00t
QLA_DIR=qla2x00t/qla2x00-target
LSI_DIR=mpt
USR_DIR=usr/fileio
all:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
# @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
install:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
@if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
# @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
uninstall:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
@if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
clean:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
@if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
extraclean:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
@if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
scst:
cd $(SCST_DIR) && $(MAKE)
@@ -97,6 +103,21 @@ lsi_clean:
lsi_extraclean:
cd $(LSI_DIR) && $(MAKE) extraclean
usr:
cd $(USR_DIR) && $(MAKE)
usr_install:
cd $(USR_DIR) && $(MAKE) install
usr_uninstall:
cd $(USR_DIR) && $(MAKE) uninstall
usr_clean:
cd $(USR_DIR) && $(MAKE) clean
usr_extraclean:
cd $(USR_DIR) && $(MAKE) extraclean
help:
@echo " all (the default) : make all"
@echo " clean : clean files"
@@ -121,6 +142,12 @@ help:
@echo " lsi_extraclean : lsi target: clean + clean dependencies"
@echo " lsi_install : lsi target: install"
@echo " lsi_uninstall : lsi target: uninstall"
@echo ""
@echo " usr : make usr target"
@echo " usr_clean : usr target: clean "
@echo " usr_extraclean : usr target: clean + clean dependencies"
@echo " usr_install : usr target: install"
@echo " usr_uninstall : usr target: uninstall"
@echo " Notes :"
@echo " - install and uninstall must be made as root"
@@ -128,3 +155,4 @@ help:
qla qla_install qla_uninstall qla_clean qla_extraclean \
lsi lsi_install lsi_uninstall lsi_clean lsi_extraclean \
scst scst_install scst_uninstall scst_clean scst_extraclean
usr usr_install usr_uninstall usr_clean usr_extraclean
+6 -4
View File
@@ -4,11 +4,13 @@ Summary of changes between versions 0.9.5 and 0.9.6
- FILEIO was renamed to VDISK. BLOCKIO added to it, thanks to Ross S. W.
Walker and Vu Pham.
- Internal locking and execution context were reimplemnted. Particularly,
implemented full support for SCSI task attributes (SIMPLE, ORDERED,
etc.).
- Updated to work on 2.6.20.x, no update for 2.6.21.x isn't needed
- Updated to work on 2.6.20.x, no update for 2.6.21.x isn't needed.
- Internal locking and execution context were reimplemnted. As some of
the results now FILEIO has >1 IO threads and implemented full support
for SCSI task attributes (SIMPLE, ORDERED, etc.).
- Ability to have per-target default security groups added.
- Updated to work on 2.6.19.x, thanks to Ming Zhang.
+32 -19
View File
@@ -106,7 +106,7 @@ allows to work directly over a block device, e.g. local IDE or SCSI disk
or ever disk partition, where there is no file systems overhead. Using
block devices comparing to sending SCSI commands directly to SCSI
mid-level via scsi_do_req()/scsi_execute_async() has advantage that data
are transfered via system cache, so it is possible to fully benefit from
are transferred via system cache, so it is possible to fully benefit from
caching and read ahead performed by Linux's VM subsystem. The only
disadvantage here that in the FILEIO mode there is superfluous data
copying between the cache and SCST's buffers. This issue is going to be
@@ -145,12 +145,12 @@ in/out in Makefile:
- EXTRACHECKS - adds extra validity checks in the various places.
- DEBUG_TM - turns on task management functions debugging, when on
LUN 0 in the "Default" group some of the commands will be delayed for
about 60 sec., so making the remote initiator send TM functions, eg
ABORT TASK and TARGET RESET. Also set TM_DBG_GO_OFFLINE symbol in the
Makefile to 1 if you want that the device eventually become
completely unresponsive, or to 0 otherwise to circle around ABORTs
and RESETs code. Needs DEBUG turned on.
LUN 0 in the default access control group some of the commands will
be delayed for about 60 sec., so making the remote initiator send TM
functions, eg ABORT TASK and TARGET RESET. Also set TM_DBG_GO_OFFLINE
symbol in the Makefile to 1 if you want that the device eventually
become completely unresponsive, or to 0 otherwise to circle around
ABORTs and RESETs code. Needs DEBUG turned on.
- STRICT_SERIALIZING - makes SCST send all commands to underlying SCSI
device synchronously, one after one. This makes task management more
@@ -235,19 +235,21 @@ Access and devices visibility management (LUN masking)
Access and devices visibility management allows for an initiator or
group of initiators to have different limited set of LUs/LUNs (security
group) each with appropriate access permissions. Initiator is
represented as a SCST session. Session is binded to security group on
its registration time by character "name" parameter of the registration
represented as a SCST session. Session is bound to security group on its
registration time by character "name" parameter of the registration
function, which provided by target driver, based on its internal
authentication. For example, for FC "name" could be WWN or just loop
ID. For iSCSI this could be iSCSI login credentials or iSCSI initiator
name. Each security group has set of names assigned to it by system
administrator. Session is binded to security group with provided name.
If no such groups found, the session binded to "Default" group.
authentication. For example, for FC "name" could be WWN or just loop ID.
For iSCSI this could be iSCSI login credentials or iSCSI initiator name.
Each security group has set of names assigned to it by system
administrator. Session is bound to security group with provided name. If
no such groups found, the session bound to either "Default_target_name",
or "Default" group, depending from either "Default_target_name" exists
or not. In "Default_target_name" target name means name of the target.
In /proc/scsi_tgt each group represented as "groups/GROUP_NAME/"
subdirectory. In it there are files "devices" and "users". File
"devices" lists all devices and their LUNs in the group, file "users"
lists all names that should be binded to this group.
lists all names that should be bound to this group.
To configure access and devices visibility management SCST provides the
following files and directories under /proc/scsi_tgt:
@@ -310,7 +312,7 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
device "NAME" with block size "BLOCK_SIZE" bytes with flags
"FLAGS". "PATH" could be empty only for VDISK CDROM. "BLOCK_SIZE"
and "FLAGS" are valid only for disk VDISK. The block size must be
power of 2 and >= 512 bytes Default is 512. Possible flags:
power of 2 and >= 512 bytes. Default is 512. Possible flags:
- WRITE_THROUGH - write back caching disabled
@@ -479,8 +481,15 @@ II. In order to get the maximum performance you should:
- Disable in Makefile TRACING, DEBUG
IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
========= currently rather for development, not for performance.
- If your initiator(s) use dedicated exported from the target virtual
SCSI devices and have more or equal amount of memory, than the
target, it is recommended to use O_DIRECT option (currently it is
available only with fileio_tgt user space program) or BLOCKIO. With
them you could have up to 100% increase in throughput.
IMPORTANT: Some of the compilation options enabled by default, i.e. SCST
========= is optimized currently rather for development and bug hunting,
not for performance.
4. For kernel:
@@ -496,7 +505,11 @@ IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
parameters in /sys/block/device directory, they also affect the
performance. If you find the best values, please share them with us.
- Also it is recommended to turn the kernel preemption off, i.e. set
- Use on the target deadline IO scheduler with read_expire and
write_expire increased on all exported devices to 5000 and 20000
correspondingly.
- It is recommended to turn the kernel preemption off, i.e. set
the kernel preemption model to "No Forced Preemption (Server)".
5. For hardware.
+39 -10
View File
@@ -39,7 +39,7 @@
/* Version numbers, the same as for the kernel */
#define SCST_VERSION_CODE 0x000906
#define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#define SCST_VERSION_STRING "0.9.6-pre1"
#define SCST_VERSION_STRING "0.9.6-pre2"
/*************************************************************
** States of command processing state machine
@@ -481,8 +481,15 @@ struct scst_tgt_template
void (*on_free_cmd) (struct scst_cmd *cmd);
/*
* This function allows the target driver to handle data buffer
* This function allows target driver to handle data buffer
* allocations on its own.
*
* Target driver doesn't have to always allocate buffer in this
* function, but if it decide to do it, it must check that
* scst_cmd_get_data_buff_alloced() returns 0, otherwise to avoid
* double buffer allocation and memory leaks alloc_data_buf() shall
* fail.
*
* Shall return 0 in case of success or < 0 (preferrably -ENOMEM)
* in case of error, or > 0 if the regular SCST allocation should be
* done. In case of returning successfully, scst_cmd->data_buf_alloced
@@ -492,9 +499,9 @@ struct scst_tgt_template
* desired or fails and consequently < 0 is returned, this function
* will be re-called in thread context.
*
* Please note that the driver will have to handle all relevant details
* such as scatterlist setup, highmem, freeing the allocated memory, ...
* itself.
* Please note that the driver will have to handle itself all relevant
* details such as scatterlist setup, highmem, freeing the allocated
* memory, etc.
*
* OPTIONAL.
*/
@@ -593,6 +600,14 @@ struct scst_tgt_template
*/
const char name[50];
/*
* Number of additional threads to the pool of dedicated threads.
* Used if xmit_response() or rdy_to_xfer() is blocking.
* It is the target driver's duty to ensure that not more, than that
* number of threads, are blocked in those functions at any time.
*/
int threads_num;
/* Private, must be inited to 0 by memset() */
/* List of targets per template, protected by scst_mutex */
@@ -620,7 +635,6 @@ struct scst_dev_type
unsigned parse_atomic:1;
unsigned exec_atomic:1;
unsigned dev_done_atomic:1;
unsigned dedicated_thread:1;
/* Set, if no /proc files should be automatically created by SCST */
unsigned no_proc:1;
@@ -748,6 +762,12 @@ struct scst_dev_type
/* SCSI type of the supported device. MUST HAVE */
int type;
/*
* Number of dedicated threads. If 0 - no dedicated threads will
* be created, if <0 - creation of dedicated threads is prohibited.
*/
int threads_num;
struct module *module;
/* private: */
@@ -795,6 +815,9 @@ struct scst_tgt
/* Used for storage of target driver private stuff */
void *tgt_priv;
/* Name on the default security group ("Default_target_name") */
char *default_group_name;
};
/* Hash size and hash fn for hash based lun translation */
@@ -1314,8 +1337,8 @@ struct scst_tgt_dev
/* internal tmp list entry */
struct list_head extra_tgt_dev_list_entry;
/* Dedicated thread. Doesn't need any protection. */
struct task_struct *thread;
/* List of dedicated threads. Doesn't need any protection. */
struct list_head threads_list;
};
/*
@@ -1419,9 +1442,15 @@ void scst_unregister_target_template(struct scst_tgt_template *vtt);
/*
* Registers and returns target adapter
* Returns new target structure on success or NULL otherwise
* Returns new target structure on success or NULL otherwise.
*
* If parameter "target_name" isn't NULL, then new security group with name
* "Default_##target_name" will be created and all sessions, which don't
* belong to any defined security groups, will be assigned to it instead of
* the "Default" one.
*/
struct scst_tgt *scst_register(struct scst_tgt_template *vtt);
struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
const char *target_name);
/*
* Unregisters target adapter
+257
View File
@@ -0,0 +1,257 @@
/*
* include/scst_user.h
*
* Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* Contains macroses for execution tracing and error reporting
*
* 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, version 2
* of the License.
*
* 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.
*/
#ifndef __SCST_USER_H
#define __SCST_USER_H
#include <scst_const.h>
#define DEV_USER_NAME "scst_user"
#define DEV_USER_PATH "/dev/"
#define DEV_USER_VERSION 96
/*
* Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec)
* (the largest one)
*/
#define SCST_MAX_NAME 45
#define SCST_USER_PARSE_STANDARD 0
#define SCST_USER_PARSE_CALL 1
#define SCST_USER_PARSE_EXCEPTION 2
#define SCST_USER_MAX_PARSE_OPT SCST_USER_PARSE_EXCEPTION
#define SCST_USER_ON_FREE_CMD_CALL 0
#define SCST_USER_ON_FREE_CMD_IGNORE 1
#define SCST_USER_MAX_ON_FREE_CMD_OPT SCST_USER_ON_FREE_CMD_IGNORE
#define SCST_USER_MEM_NO_REUSE 0
#define SCST_USER_MEM_REUSE_READ 1
#define SCST_USER_MEM_REUSE_WRITE 2
#define SCST_USER_MEM_REUSE_ALL 3
#define SCST_USER_MAX_MEM_REUSE_OPT SCST_USER_MEM_REUSE_ALL
#define SCST_USER_PRIO_QUEUE_SINGLE 0
#define SCST_USER_PRIO_QUEUE_SEPARATE 1
#define SCST_USER_MAX_PRIO_QUEUE_OPT SCST_USER_PRIO_QUEUE_SEPARATE
#define SCST_USER_PARTIAL_TRANSFERS_NOT_SUPPORTED 0
#define SCST_USER_PARTIAL_TRANSFERS_SUPPORTED_ORDERED 1
#define SCST_USER_PARTIAL_TRANSFERS_SUPPORTED 2
#define SCST_USER_MAX_PARTIAL_TRANSFERS_OPT SCST_USER_PARTIAL_TRANSFERS_SUPPORTED
#ifndef aligned_u64
#define aligned_u64 uint64_t __attribute__((aligned(8)))
#endif
/*************************************************************
** Private ucmd states
*************************************************************/
#define UCMD_STATE_NEW 0
#define UCMD_STATE_PARSING 1
#define UCMD_STATE_BUF_ALLOCING 2
#define UCMD_STATE_EXECING 3
#define UCMD_STATE_ON_FREEING 4
#define UCMD_STATE_ON_FREE_SKIPPED 5
#define UCMD_STATE_ON_CACHE_FREEING 6
#define UCMD_STATE_TM_EXECING 7
#define UCMD_STATE_ATTACH_SESS 0x20
#define UCMD_STATE_DETACH_SESS 0x21
/* Must be changed under cmd_lists.cmd_list_lock */
#define UCMD_STATE_SENT_MASK 0x10000
#define UCMD_STATE_RECV_MASK 0x20000
#define UCMD_STATE_JAMMED_MASK 0x40000
#define UCMD_STATE_MASK (UCMD_STATE_SENT_MASK | \
UCMD_STATE_RECV_MASK | \
UCMD_STATE_JAMMED_MASK)
struct scst_user_opt
{
uint8_t parse_type;
uint8_t on_free_cmd_type;
uint8_t memory_reuse_type;
uint8_t prio_queue_type;
uint8_t partial_transfers_type;
int32_t partial_len;
};
struct scst_user_dev_desc
{
uint8_t version;
uint8_t type;
struct scst_user_opt opt;
uint32_t block_size;
char name[SCST_MAX_NAME];
};
struct scst_user_sess
{
aligned_u64 sess_h;
aligned_u64 lun;
uint8_t rd_only;
char initiator_name[SCST_MAX_NAME];
};
struct scst_user_scsi_cmd_parse
{
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
int32_t cdb_len;
uint32_t timeout;
int32_t bufflen;
uint8_t queue_type;
uint8_t data_direction;
uint8_t expected_values_set;
uint8_t expected_data_direction;
int32_t expected_transfer_len;
};
struct scst_user_scsi_cmd_alloc_mem
{
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
int32_t cdb_len;
int32_t alloc_len;
uint8_t queue_type;
uint8_t data_direction;
};
struct scst_user_scsi_cmd_exec
{
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
int32_t cdb_len;
int32_t data_len;
int32_t bufflen;
int32_t alloc_len;
aligned_u64 pbuf;
uint8_t queue_type;
uint8_t data_direction;
uint8_t partial;
uint32_t timeout;
uint32_t parent_cmd_h;
int32_t parent_cmd_data_len;
uint32_t partial_offset;
};
struct scst_user_scsi_on_free_cmd
{
aligned_u64 pbuf;
int32_t resp_data_len;
uint8_t buffer_cached;
uint8_t status;
};
struct scst_user_on_cached_mem_free
{
aligned_u64 pbuf;
};
struct scst_user_tm
{
aligned_u64 sess_h;
uint32_t fn;
uint32_t cmd_h_to_abort;
};
struct scst_user_get_cmd
{
aligned_u64 preply;
uint32_t cmd_h;
uint32_t subcode;
union {
struct scst_user_sess sess;
struct scst_user_scsi_cmd_parse parse_cmd;
struct scst_user_scsi_cmd_alloc_mem alloc_cmd;
struct scst_user_scsi_cmd_exec exec_cmd;
struct scst_user_scsi_on_free_cmd on_free_cmd;
struct scst_user_on_cached_mem_free on_cached_mem_free;
struct scst_user_tm tm_cmd;
};
};
struct scst_user_scsi_cmd_reply_parse
{
uint8_t queue_type;
uint8_t data_direction;
int32_t data_len;
int32_t bufflen;
};
struct scst_user_scsi_cmd_reply_alloc_mem
{
aligned_u64 pbuf;
};
struct scst_user_scsi_cmd_reply_exec
{
int32_t resp_data_len;
aligned_u64 pbuf;
#define SCST_EXEC_REPLY_BACKGROUND 0
#define SCST_EXEC_REPLY_COMPLETED 1
uint8_t reply_type;
uint8_t status;
uint8_t sense_len;
aligned_u64 psense_buffer;
};
struct scst_user_reply_cmd
{
uint32_t cmd_h;
uint32_t subcode;
union {
int32_t result;
struct scst_user_scsi_cmd_reply_parse parse_reply;
struct scst_user_scsi_cmd_reply_alloc_mem alloc_reply;
struct scst_user_scsi_cmd_reply_exec exec_reply;
};
};
#define SCST_USER_REGISTER_DEVICE _IOW('u', 1, struct scst_user_dev_desc)
#define SCST_USER_SET_OPTIONS _IOW('u', 3, struct scst_user_opt)
#define SCST_USER_GET_OPTIONS _IOR('u', 4, struct scst_user_opt)
#define SCST_USER_REPLY_AND_GET_CMD _IOWR('u', 5, struct scst_user_get_cmd)
#define SCST_USER_REPLY_AND_GET_PRIO_CMD _IOWR('u', 6, struct scst_user_get_cmd)
#define SCST_USER_REPLY_CMD _IOW('u', 7, struct scst_user_reply_cmd)
/* Values for scst_user_get_cmd.subcode */
#define SCST_USER_ATTACH_SESS _IOR('s', UCMD_STATE_ATTACH_SESS, struct scst_user_sess)
#define SCST_USER_DETACH_SESS _IOR('s', UCMD_STATE_DETACH_SESS, struct scst_user_sess)
#define SCST_USER_PARSE _IOWR('s', UCMD_STATE_PARSING, struct scst_user_scsi_cmd_parse)
#define SCST_USER_ALLOC_MEM _IOWR('s', UCMD_STATE_BUF_ALLOCING, struct scst_user_scsi_cmd_alloc_mem)
#define SCST_USER_EXEC _IOWR('s', UCMD_STATE_EXECING, struct scst_user_scsi_cmd_exec)
#define SCST_USER_ON_FREE_CMD _IOR('s', UCMD_STATE_ON_FREEING, struct scst_user_scsi_on_free_cmd)
#define SCST_USER_ON_CACHED_MEM_FREE _IOR('s', UCMD_STATE_ON_CACHE_FREEING, struct scst_user_on_cached_mem_free)
#define SCST_USER_TASK_MGMT _IOWR('s', UCMD_STATE_TM_EXECING, struct scst_user_tm)
#endif /* __SCST_USER_H */
+7
View File
@@ -63,6 +63,13 @@ config SCSI_TARGET_VDISK
---help---
SCSI TARGET handler for virtual disk and/or cdrom device.
config SCSI_TARGET_USER
tristate "SCSI user space virtual target devices support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for virtual user space device.
config SCSI_TARGET_EXTRACHECKS
bool "Extrachecks support"
---help---
+2 -1
View File
@@ -15,4 +15,5 @@ obj-$(CONFIG_SCSI_TARGET_MODISK) += scst_modisk.o
obj-$(CONFIG_SCSI_TARGET_CHANGER) += scst_changer.o
obj-$(CONFIG_SCSI_TARGET_RAID) += scst_raid.o
obj-$(CONFIG_SCSI_TARGET_PROCESSOR) += scst_processor.o
obj-$(CONFIG_SCSI_TARGET_VDISK ) += scst_vdisk.o
obj-$(CONFIG_SCSI_TARGET_VDISK) += scst_vdisk.o
obj-$(CONFIG_SCSI_TARGET_USER) += scst_user.o
+1
View File
@@ -70,6 +70,7 @@ install: all
install -d $(INSTALL_DIR_H)
install -m 644 ../include/scsi_tgt.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_debug.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_user.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_const.h $(INSTALL_DIR_H)
ifneq ($(MODS_VERS),)
rm -f $(INSTALL_DIR_H)/Module.symvers
+2 -1
View File
@@ -30,7 +30,7 @@ ifneq ($(KERNELRELEASE),)
SCST_INC_DIR := $(SUBDIRS)/../include
obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \
scst_vdisk.o scst_raid.o scst_processor.o
scst_vdisk.o scst_raid.o scst_processor.o scst_user.o
obj-$(CONFIG_SCSI_TARGET_DISK) += scst_disk.o
obj-$(CONFIG_SCSI_TARGET_TAPE) += scst_tape.o
@@ -40,6 +40,7 @@ obj-$(CONFIG_SCSI_TARGET_CHANGER) += scst_changer.o
obj-$(CONFIG_SCSI_TARGET_RAID) += scst_raid.o
obj-$(CONFIG_SCSI_TARGET_PROCESSOR) += scst_processor.o
obj-$(CONFIG_SCSI_TARGET_VDISK) += scst_vdisk.o
obj-$(CONFIG_SCSI_TARGET_USER) += scst_user.o
else
ifeq ($(KDIR),)
File diff suppressed because it is too large Load Diff
+57 -18
View File
@@ -178,10 +178,10 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
#define VDISK_TYPE { \
name: VDISK_NAME, \
type: TYPE_DISK, \
threads_num: -1, \
parse_atomic: 1, \
exec_atomic: 0, \
dev_done_atomic: 1, \
dedicated_thread: 1, \
attach: vdisk_attach, \
detach: vdisk_detach, \
attach_tgt: vdisk_attach_tgt, \
@@ -192,13 +192,30 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
write_proc: vdisk_write_proc, \
}
#define VCDROM_TYPE { \
name: VCDROM_NAME, \
type: TYPE_ROM, \
#define VDISK_BLK_TYPE { \
name: VDISK_NAME "_blk", \
type: TYPE_DISK, \
threads_num: 0, \
parse_atomic: 1, \
exec_atomic: 0, \
dev_done_atomic: 1, \
no_proc: 1, \
inc_expected_sn_on_done: 1, \
attach: vdisk_attach, \
detach: vdisk_detach, \
attach_tgt: vdisk_attach_tgt, \
detach_tgt: vdisk_detach_tgt, \
parse: vdisk_parse, \
exec: vdisk_do_job, \
}
#define VCDROM_TYPE { \
name: VCDROM_NAME, \
type: TYPE_ROM, \
threads_num: -1, \
parse_atomic: 1, \
exec_atomic: 0, \
dev_done_atomic: 1, \
dedicated_thread: 1, \
attach: vdisk_attach, \
detach: vdisk_detach, \
attach_tgt: vdisk_attach_tgt, \
@@ -214,6 +231,7 @@ static LIST_HEAD(vdisk_dev_list);
static LIST_HEAD(vcdrom_dev_list);
static struct scst_dev_type vdisk_devtype = VDISK_TYPE;
static struct scst_dev_type vdisk_blk_devtype = VDISK_BLK_TYPE;
static struct scst_dev_type vcdrom_devtype = VCDROM_TYPE;
static char *vdisk_proc_help_string =
@@ -2497,9 +2515,14 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
list_add_tail(&virt_dev->vdisk_dev_list_entry,
&vdisk_dev_list);
virt_dev->virt_id =
scst_register_virtual_device(&vdisk_devtype,
virt_dev->name);
if (virt_dev->blockio)
virt_dev->virt_id =
scst_register_virtual_device(&vdisk_blk_devtype,
virt_dev->name);
else
virt_dev->virt_id =
scst_register_virtual_device(&vdisk_devtype,
virt_dev->name);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_free_vpath;
@@ -2999,13 +3022,14 @@ static int __init init_scst_vdisk(struct scst_dev_type *devtype)
if (res < 0)
goto out;
res = scst_dev_handler_build_std_proc(devtype);
if (res < 0)
goto out_unreg;
if (!devtype->no_proc) {
res = scst_dev_handler_build_std_proc(devtype);
if (res < 0)
goto out_unreg;
res = vdisk_proc_help_build(devtype);
if (res < 0) {
goto out_destroy_proc;
res = vdisk_proc_help_build(devtype);
if (res < 0)
goto out_destroy_proc;
}
out:
@@ -3013,7 +3037,8 @@ out:
return res;
out_destroy_proc:
scst_dev_handler_destroy_std_proc(devtype);
if (!devtype->no_proc)
scst_dev_handler_destroy_std_proc(devtype);
out_unreg:
scst_unregister_virtual_dev_driver(devtype);
@@ -3046,8 +3071,10 @@ static void __exit exit_scst_vdisk(struct scst_dev_type *devtype,
}
up(&scst_vdisk_mutex);
vdisk_proc_help_destroy(devtype);
scst_dev_handler_destroy_std_proc(devtype);
if (!devtype->no_proc) {
vdisk_proc_help_destroy(devtype);
scst_dev_handler_destroy_std_proc(devtype);
}
scst_unregister_virtual_dev_driver(devtype);
@@ -3057,7 +3084,7 @@ static void __exit exit_scst_vdisk(struct scst_dev_type *devtype,
static int __init init_scst_vdisk_driver(void)
{
int res;
int res, num_threads;
vdisk_thr_cachep = kmem_cache_create("vdisk_thr_data",
sizeof(struct scst_vdisk_thr), 0, VDISK_SLAB_FLAGS, NULL,
@@ -3067,10 +3094,18 @@ static int __init init_scst_vdisk_driver(void)
goto out;
}
num_threads = num_online_cpus() + 2;
vdisk_devtype.threads_num = num_threads;
vcdrom_devtype.threads_num = num_threads;
res = init_scst_vdisk(&vdisk_devtype);
if (res != 0)
goto out_free_slab;
res = init_scst_vdisk(&vdisk_blk_devtype);
if (res != 0)
goto out_free_vdisk;
res = init_scst_vdisk(&vcdrom_devtype);
if (res != 0)
goto out_err;
@@ -3079,6 +3114,9 @@ out:
return res;
out_err:
exit_scst_vdisk(&vdisk_blk_devtype, &vdisk_dev_list);
out_free_vdisk:
exit_scst_vdisk(&vdisk_devtype, &vdisk_dev_list);
out_free_slab:
@@ -3088,6 +3126,7 @@ out_free_slab:
static void __exit exit_scst_vdisk_driver(void)
{
exit_scst_vdisk(&vdisk_blk_devtype, &vdisk_dev_list);
exit_scst_vdisk(&vdisk_devtype, &vdisk_dev_list);
exit_scst_vdisk(&vcdrom_devtype, &vcdrom_dev_list);
kmem_cache_destroy(vdisk_thr_cachep);
+32 -9
View File
@@ -255,7 +255,8 @@ out_up:
return;
}
struct scst_tgt *scst_register(struct scst_tgt_template *vtt)
struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
const char *target_name)
{
struct scst_tgt *tgt;
@@ -281,27 +282,46 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt)
scst_suspend_activity();
down(&scst_mutex);
if (scst_build_proc_target_entries(tgt) < 0) {
kfree(tgt);
tgt = NULL;
goto out_up;
} else
if (target_name != NULL) {
int len = strlen(target_name) + 1 +
strlen(SCST_DEFAULT_ACG_NAME) + 1;
tgt->default_group_name = kmalloc(len, GFP_KERNEL);
if (tgt->default_group_name == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of default "
"group name failed");
goto out_free_err;
}
sprintf(tgt->default_group_name, "%s_%s", SCST_DEFAULT_ACG_NAME,
target_name);
}
if (scst_build_proc_target_entries(tgt) < 0)
goto out_free_name;
else
list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list);
up(&scst_mutex);
scst_resume_activity();
PRINT_INFO_PR("Target for template %s registered successfully",
vtt->name);
PRINT_INFO_PR("Target %s for template %s registered successfully",
target_name, vtt->name);
out:
TRACE_EXIT();
return tgt;
out_up:
out_free_name:
if (tgt->default_group_name)
kfree(tgt->default_group_name);
out_free_err:
up(&scst_mutex);
scst_resume_activity();
kfree(tgt);
tgt = NULL;
out_err:
PRINT_ERROR_PR("Failed to register target for template %s", vtt->name);
goto out;
@@ -344,6 +364,9 @@ void scst_unregister(struct scst_tgt *tgt)
scst_cleanup_proc_target_entries(tgt);
if (tgt->default_group_name)
kfree(tgt->default_group_name);
up(&scst_mutex);
scst_resume_activity();
+44 -23
View File
@@ -314,33 +314,50 @@ out:
static int scst_create_tgt_threads(struct scst_tgt_dev *tgt_dev)
{
int res = 0;
int i, res = 0;
int threads_num = tgt_dev->dev->handler->threads_num +
tgt_dev->sess->tgt->tgtt->threads_num;
static atomic_t major = ATOMIC_INIT(0);
int N, n = 0;
char nm[12];
TRACE_ENTRY();
if ( !tgt_dev->dev->handler->dedicated_thread)
if (tgt_dev->dev->handler->threads_num < 0)
threads_num = 0;
if (threads_num == 0)
goto out;
spin_lock_init(&tgt_dev->cmd_lists.cmd_list_lock);
INIT_LIST_HEAD(&tgt_dev->cmd_lists.active_cmd_list);
init_waitqueue_head(&tgt_dev->cmd_lists.cmd_list_waitQ);
/*
* Only ONE thread must be run here, otherwise the commands could
* be executed out of order !!
*/
if (tgt_dev->dev->handler->threads_num == 0)
threads_num += num_online_cpus();
strncpy(nm, tgt_dev->dev->handler->name, ARRAY_SIZE(nm)-1);
nm[ARRAY_SIZE(nm)-1] = '\0';
tgt_dev->thread = kthread_run(scst_cmd_thread, &tgt_dev->cmd_lists,
"%sd%d", nm, atomic_inc_return(&major));
if (IS_ERR(tgt_dev->thread)) {
res = PTR_ERR(tgt_dev->thread);
PRINT_ERROR_PR("kthread_create() failed: %d", res);
tgt_dev->thread = NULL;
goto out;
N = atomic_inc_return(&major);
for (i = 0; i < threads_num; i++) {
struct scst_cmd_thread_t *thr;
thr = kmalloc(sizeof(*thr), GFP_KERNEL);
if (!thr) {
res = -ENOMEM;
PRINT_ERROR_PR("fail to allocate thr %d", res);
goto out;
}
strncpy(nm, tgt_dev->dev->handler->name, ARRAY_SIZE(nm)-1);
nm[ARRAY_SIZE(nm)-1] = '\0';
thr->cmd_thread = kthread_run(scst_cmd_thread,
&tgt_dev->cmd_lists, "%sd%d_%d", nm, N, n++);
if (IS_ERR(thr->cmd_thread)) {
res = PTR_ERR(thr->cmd_thread);
PRINT_ERROR_PR("kthread_create() failed: %d", res);
kfree(thr);
goto out;
}
list_add(&thr->thread_list_entry, &tgt_dev->threads_list);
}
down(&scst_suspend_mutex);
@@ -357,16 +374,21 @@ out:
static void scst_stop_tgt_threads(struct scst_tgt_dev *tgt_dev)
{
int rc;
struct scst_cmd_thread_t *ct, *tmp;
TRACE_ENTRY();
if (tgt_dev->thread == NULL)
if (list_empty(&tgt_dev->threads_list))
goto out;
rc = kthread_stop(tgt_dev->thread);
if (rc < 0) {
TRACE_MGMT_DBG("kthread_stop() failed: %d", rc);
list_for_each_entry_safe(ct, tmp, &tgt_dev->threads_list,
thread_list_entry) {
int rc = kthread_stop(ct->cmd_thread);
if (rc < 0) {
TRACE_MGMT_DBG("kthread_stop() failed: %d", rc);
}
list_del(&ct->thread_list_entry);
kfree(ct);
}
if (tgt_dev->p_cmd_lists == &tgt_dev->cmd_lists) {
@@ -475,6 +497,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev->cur_sn_slot = &tgt_dev->sn_slots[0];
for(i = 0; i < (int)ARRAY_SIZE(tgt_dev->sn_slots); i++)
atomic_set(&tgt_dev->sn_slots[i], 0);
INIT_LIST_HEAD(&tgt_dev->threads_list);
if (dev->handler->parse_atomic &&
sess->tgt->tgtt->preprocessing_done_atomic) {
@@ -2955,9 +2978,7 @@ static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff };
void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
struct scst_acg_dev *acg_dev)
{
if (((acg_dev->acg == scst_default_acg) ||
(acg_dev->acg == tgt_dev->sess->tgt->default_acg)) &&
(acg_dev->lun == 0)) {
if ((acg_dev->acg == scst_default_acg) && (acg_dev->lun == 0)) {
unsigned long flags;
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
if (!tm_dbg_flags.tm_dbg_active) {
+3 -1
View File
@@ -179,7 +179,6 @@ extern spinlock_t scst_mcmd_lock;
/* The following lists protected by scst_mcmd_lock */
extern struct list_head scst_active_mgmt_cmd_list;
extern struct list_head scst_delayed_mgmt_cmd_list;
extern wait_queue_head_t scst_mgmt_cmd_list_waitQ;
struct scst_tasklet
@@ -252,6 +251,9 @@ void scst_free_device(struct scst_device *tgt_dev);
struct scst_acg *scst_alloc_add_acg(const char *acg_name);
int scst_destroy_acg(struct scst_acg *acg);
int scst_proc_group_add_tree(struct scst_acg *acg, const char *name);
void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
const char *name);
int scst_sess_alloc_tgt_devs(struct scst_session *sess);
void scst_sess_free_tgt_devs(struct scst_session *sess);
+7 -11
View File
@@ -408,17 +408,17 @@ static void __exit scst_proc_cleanup_module_log(void)
#endif
}
static int scst_proc_group_add_tree(struct scst_acg *acg, const char *p)
int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
{
int res = 0;
struct proc_dir_entry *generic;
TRACE_ENTRY();
acg->acg_proc_root = proc_mkdir(p, scst_proc_groups_root);
acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
if (acg->acg_proc_root == NULL) {
PRINT_ERROR_PR("Not enough memory to register %s entry in "
"/proc/%s/%s", p, SCST_PROC_ENTRY_NAME,
"/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
SCST_PROC_GROUPS_ENTRY_NAME);
goto out;
}
@@ -431,7 +431,7 @@ static int scst_proc_group_add_tree(struct scst_acg *acg, const char *p)
PRINT_ERROR_PR("cannot init /proc/%s/%s/%s/%s",
SCST_PROC_ENTRY_NAME,
SCST_PROC_GROUPS_ENTRY_NAME,
p, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
res = -ENOMEM;
goto out_remove;
}
@@ -444,7 +444,7 @@ static int scst_proc_group_add_tree(struct scst_acg *acg, const char *p)
PRINT_ERROR_PR("cannot init /proc/%s/%s/%s/%s",
SCST_PROC_ENTRY_NAME,
SCST_PROC_GROUPS_ENTRY_NAME,
p, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
res = -ENOMEM;
goto out_remove1;
}
@@ -458,11 +458,11 @@ out_remove1:
acg->acg_proc_root);
out_remove:
remove_proc_entry(p, scst_proc_groups_root);
remove_proc_entry(name, scst_proc_groups_root);
goto out;
}
static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
const char *name)
{
TRACE_ENTRY();
@@ -1610,10 +1610,6 @@ static int scst_version_info_show(struct seq_file *seq, void *v)
seq_printf(seq, "Strict serializing enabled\n");
#endif
#ifdef SINGLE_DEFAULT_GROUP
seq_printf(seq, "Single default group\n");
#endif
#ifdef EXTRACHECKS
seq_printf(seq, "EXTRACHECKS\n");
#endif
+36 -24
View File
@@ -137,7 +137,7 @@ out_redirect:
if (cmd->preprocessing_only) {
/*
* Poor man solution for single threaded targets, where
* blocking receiver at least somtimes means blocking all.
* blocking receiver at least sometimes means blocking all.
*/
sBUG_ON(context != SCST_CONTEXT_DIRECT);
scst_set_busy(cmd);
@@ -598,14 +598,6 @@ static int scst_prepare_space(struct scst_cmd *cmd)
TRACE_MEM("%s", "Custom tgt data buf allocation requested");
if (unlikely(cmd->data_buf_alloced)) {
PRINT_ERROR_PR("Target driver %s requested own data "
"allocation, but dev handler %s already "
"allocated them", cmd->tgtt->name,
cmd->dev->handler->name);
goto out_error;
}
r = cmd->tgtt->alloc_data_buf(cmd);
if (r > 0)
goto alloc;
@@ -618,15 +610,15 @@ static int scst_prepare_space(struct scst_cmd *cmd)
cmd->bufflen);
goto out_error;
}
}
goto check;
} else
goto check;
}
alloc:
if (!cmd->data_buf_alloced) {
r = scst_check_mem(cmd);
if (unlikely(r != 0))
goto out;
r = scst_check_mem(cmd);
if (unlikely(r != 0))
goto out;
else if (!cmd->data_buf_alloced) {
r = scst_alloc_space(cmd);
} else {
TRACE_MEM("%s", "data_buf_alloced set, returning");
@@ -4082,10 +4074,31 @@ out:
return res;
}
/* scst_mutex supposed to be held */
static struct scst_acg *scst_find_acg_by_name(const char *acg_name)
{
struct scst_acg *acg, *res = NULL;
TRACE_ENTRY();
list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
if (strcmp(acg->acg_name, acg_name) == 0) {
TRACE_DBG("Access control group %s found",
acg->acg_name);
res = acg;
goto out;
}
}
out:
TRACE_EXIT_HRES(res);
return res;
}
static int scst_init_session(struct scst_session *sess)
{
int res = 0;
struct scst_acg *acg;
struct scst_acg *acg = NULL;
struct scst_cmd *cmd;
struct scst_mgmt_cmd *mcmd, *tm;
int mwake = 0;
@@ -4095,17 +4108,16 @@ static int scst_init_session(struct scst_session *sess)
scst_suspend_activity();
down(&scst_mutex);
if (sess->initiator_name) {
if (sess->initiator_name)
acg = scst_find_acg(sess->initiator_name);
if (acg == NULL) {
PRINT_INFO_PR("Name %s not found, using default group",
sess->initiator_name);
acg = scst_default_acg;
}
}
else
if ((acg == NULL) && (sess->tgt->default_group_name != NULL))
acg = scst_find_acg_by_name(sess->tgt->default_group_name);
if (acg == NULL)
acg = scst_default_acg;
PRINT_INFO_PR("Using security group \"%s\" for initiator \"%s\"",
acg->acg_name, sess->initiator_name);
sess->acg = acg;
TRACE_DBG("Assigning session %p to acg %s", sess, acg->acg_name);
list_add_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list);
+79
View File
@@ -0,0 +1,79 @@
#
# SCSI target mid-level makefile
#
# Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
#
# 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, version 2
# of the License.
#
# 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.
SRCS_F = fileio.c common.c debug.c
OBJS_F = $(SRCS_F:.c=.o)
#SRCS_C =
#OBJS_C = $(SRCS_C:.c=.o)
SCST_INC_DIR := ../../scst/include
INSTALL_DIR := /usr/local/bin/scst
CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \
-I$(SCST_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \
-D__USE_LARGEFILE64
PROGS = fileio_tgt
LIBS = -lpthread
CFLAGS += -DEXTRACHECKS
#CFLAGS += -DTRACING
CFLAGS += -DDEBUG -g
#CFLAGS += -DDEBUG_NOMEM
#CFLAGS += -DDEBUG_SENSE
#CFLAGS += -DDEBUG_TM_IGNORE
#CFLAGS += -DDEBUG_TM_IGNORE -DDEBUG_TM_FN_IGNORE
#CFLAGS += -DDEBUG_TM_IGNORE_ALL
all: $(PROGS)
fileio_tgt: .depend_f $(OBJS_F)
$(CC) $(OBJS_F) $(LIBS) -o $@
#cdrom_tgt: .depend_c $(OBJS_C)
# $(CC) $(OBJS_C) $(LIBS) -o $@
ifeq (.depend_f,$(wildcard .depend_f))
-include .depend_f
endif
#ifeq (.depend_c,$(wildcard .depend_c))
#-include .depend_c
#endif
%.o: %.c Makefile
$(CC) -c -o $(@) $(CFLAGS) $(<)
.depend_f:
$(CC) -M $(CFLAGS) $(SRCS_F) >$(@)
#.depend_c:
# $(CC) -M $(CFLAGS) $(SRCS_C) >$(@)
install: all
install -d $(INSTALL_DIR)
install -m 755 $(PROGS) $(INSTALL_DIR)
uninstall:
rm -f $(INSTALL_DIR)/$(PROGS)
rm -rf $(INSTALL_DIR)
clean:
rm -f *.o $(PROGS) .depend*
extraclean: clean
.PHONY: all install uninstall clean extraclean
+1710
View File
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
/*
* common.h
*
* Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <scst_user.h>
#include "debug.h"
/* 8 byte ASCII Vendor */
#define VENDOR "SCST_USR"
/* 4 byte ASCII Product Revision Level - left aligned */
#define FIO_REV " 096"
#define MAX_USN_LEN 20
#define INQ_BUF_SZ 128
#define EVPD 0x01
#define CMDDT 0x02
#define MSENSE_BUF_SZ 256
#define DBD 0x08 /* disable block descriptor */
#define WP 0x80 /* write protect */
#define DPOFUA 0x10 /* DPOFUA bit */
#define WCE 0x04 /* write cache enable */
#define PF 0x10 /* page format */
#define SP 0x01 /* save pages */
#define PS 0x80 /* parameter saveable */
#define BYTE 8
#define DEF_SECTORS_PER 63
struct vdisk_tgt_dev {
uint64_t sess_h;
/*
* last_write_cmd_queue_type accessed without protection since we are
* guaranteed that only commands of the same type per tgt_dev can be
* processed simultaneously
*/
int last_write_cmd_queue_type;
};
struct vdisk_dev {
int scst_usr_fd;
uint32_t block_size;
uint64_t nblocks;
int block_shift;
loff_t file_size; /* in bytes */
void *(*alloc_fn)(size_t size);
pthread_mutex_t dev_mutex;
/* Below flags and are protected by dev_mutex */
unsigned int rd_only_flag:1;
unsigned int wt_flag:1;
unsigned int nv_cache:1;
unsigned int o_direct_flag:1;
unsigned int media_changed:1;
unsigned int prevent_allow_medium_removal:1;
unsigned int nullio:1;
unsigned int cdrom_empty:1;
unsigned int non_blocking:1;
unsigned int prio_thr:1;
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
unsigned int debug_tm_ignore:1;
#if defined(DEBUG_TM_IGNORE_ALL)
volatile int debug_tm_ignore_all;
#endif
#endif
struct vdisk_tgt_dev tgt_devs[25];
char *name; /* Name of virtual device,
must be <= SCSI Model + 1 */
char *file_name; /* File name */
char *usn;
int type;
};
struct vdisk_cmd
{
int fd;
struct scst_user_get_cmd *cmd;
struct vdisk_dev *dev;
struct scst_user_reply_cmd *reply;
uint8_t sense[SCST_SENSE_BUFFERSIZE];
};
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
#define max(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
void *main_loop(void *arg);
void *prio_loop(void *arg);
+120
View File
@@ -0,0 +1,120 @@
/*
* debug.c
*
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains helper functions for execution tracing and error reporting.
* Intended to be included in main .c file.
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <stdio.h>
#include <time.h>
#include "debug.h"
_syscall0(pid_t,gettid);
#if defined(DEBUG) || defined(TRACING)
#define TRACE_BUF_SIZE 512
static char trace_buf[TRACE_BUF_SIZE];
//static spinlock_t trace_buf_lock = SPIN_LOCK_UNLOCKED;
int debug_print_prefix(unsigned long trace_flag, const char *func,
int line)
{
int i = 0;
// spin_lock_irqsave(&trace_buf_lock, flags);
if (trace_flag & TRACE_TIME) {
struct tm t;
time_t tt;
time(&tt);
localtime_r(&tt, &t);
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE, "%d:%d:%d ",
t.tm_hour, t.tm_min, t.tm_sec);
}
if (trace_flag & TRACE_PID)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE, "[%d]: ",
gettid());
if (trace_flag & TRACE_FUNCTION)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", func);
if (trace_flag & TRACE_LINE)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%i:", line);
if (i > 0)
PRINTN("%s", trace_buf);
// spin_unlock_irqrestore(&trace_buf_lock, flags);
return i;
}
void debug_print_buffer(const void *data, int len)
{
int z, z1, i;
const unsigned char *buf = (const unsigned char *) data;
int f = 0;
if (buf == NULL)
return;
// spin_lock_irqsave(&trace_buf_lock, flags);
PRINT(" (h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F");
for (z = 0, z1 = 0, i = 0; z < len; z++) {
if (z % 16 == 0) {
if (z != 0) {
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
" ");
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1);
z1++) {
if ((buf[z1] >= 0x20) &&
(buf[z1] < 0x80))
trace_buf[i++] = buf[z1];
else
trace_buf[i++] = '.';
}
trace_buf[i] = '\0';
PRINT("%s", trace_buf);
i = 0;
f = 1;
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
"%4x: ", z);
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%02x ",
buf[z]);
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, " ");
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); z1++) {
if ((buf[z1] > 0x20) && (buf[z1] < 0x80))
trace_buf[i++] = buf[z1];
else
trace_buf[i++] = '.';
}
trace_buf[i] = '\0';
if (f) {
PRINT("%s", trace_buf)
} else {
PRINT("%s", trace_buf);
}
// spin_unlock_irqrestore(&trace_buf_lock, flags);
return;
}
#endif /* DEBUG || TRACING */
+260
View File
@@ -0,0 +1,260 @@
/*
* debug.h
*
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains macroses for execution tracing and error reporting
*
* 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, version 2
* of the License.
*
* 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.
*/
#ifndef __DEBUG_H
#define __DEBUG_H
#include <sys/types.h>
#include <linux/unistd.h>
#include <errno.h>
extern pid_t gettid(void);
#define sBUG() assert(0)
#define sBUG_ON(p) assert(!(p))
#ifdef EXTRACHECKS
#define EXTRACHECKS_BUG_ON(a) sBUG_ON(a)
#else
#define EXTRACHECKS_BUG_ON(a)
#endif
#define TRACE_NULL 0x00000000
#define TRACE_DEBUG 0x00000001
#define TRACE_FUNCTION 0x00000002
#define TRACE_LINE 0x00000004
#define TRACE_PID 0x00000008
#define TRACE_ENTRYEXIT 0x00000010
#define TRACE_BUFF 0x00000020
#define TRACE_MEMORY 0x00000040
#define TRACE_SG 0x00000080
#define TRACE_OUT_OF_MEM 0x00000100
#define TRACE_MINOR 0x00000200 /* less important events */
#define TRACE_MGMT 0x00000400
#define TRACE_MGMT_DEBUG 0x00000800
#define TRACE_SCSI 0x00001000
#define TRACE_SPECIAL 0x00002000 /* filtering debug, etc */
#define TRACE_TIME 0x00004000
#define TRACE_ORDER 0x00008000
#define TRACE_ALL 0xffffffff
#define PRINT(format, args...) fprintf(stdout, format "\n", ## args);
#define PRINTN(format, args...) fprintf(stdout, format, ## args);
extern char *app_name;
#define LOG_PREFIX app_name
#if defined(DEBUG) || defined(TRACING)
extern unsigned long trace_flag;
extern int debug_print_prefix(unsigned long trace_flag, const char *func, int line);
extern void debug_print_buffer(const void *data, int len);
#define TRACE(trace, format, args...) \
do { \
if (trace_flag & (trace)) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT(format, args); \
} \
} while(0)
#define TRACE_BUFFER(message, buff, len) \
do { \
if (trace_flag & TRACE_BUFF) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT("%s:", message); \
debug_print_buffer(buff, len); \
} \
} while(0)
#define TRACE_BUFF_FLAG(flag, message, buff, len) \
do { \
if (trace_flag & (flag)) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT("%s:", message); \
debug_print_buffer(buff, len); \
} \
} while(0)
#else /* DEBUG || TRACING */
#define TRACE(trace, args...) {}
#define TRACE_BUFFER(message, buff, len) {}
#define TRACE_BUFF_FLAG(flag, message, buff, len) {}
#endif /* DEBUG || TRACING */
#ifdef DEBUG
#include <assert.h>
#define TRACE_MEM(format, args...) \
do { \
if (trace_flag & TRACE_MEMORY) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT(format, args); \
} \
} while(0)
#define TRACE_DBG(format, args...) \
do { \
if (trace_flag & TRACE_DEBUG) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT(format, args); \
} \
} while(0)
#define TRACE_MGMT_DBG(format, args...) \
do { \
if (trace_flag & TRACE_MGMT_DEBUG) \
{ \
debug_print_prefix(trace_flag, __FUNCTION__, __LINE__); \
PRINT(format, args); \
} \
} while(0)
#define PRINT_ERROR_PR(format, args...) \
do { \
TRACE(trace_flag, "%s: ***ERROR*** " format, \
LOG_PREFIX, args); \
} while(0)
#define PRINT_INFO_PR(format, args...) \
do { \
TRACE(trace_flag, "%s: " \
format, LOG_PREFIX, args); \
} while(0)
#define PRINT_ERROR(format, args...) \
do { \
TRACE(trace_flag, "***ERROR*** " format, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
TRACE(trace_flag, format, args); \
} while(0)
#define TRACE_ENTRY() \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT("[%d]: ENTRY %s", gettid(), \
__FUNCTION__); \
} \
else \
{ \
PRINT("ENTRY %s", __FUNCTION__); \
} \
} \
} while(0)
#define TRACE_EXIT() \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT("[%d]: EXIT %s", gettid(), \
__FUNCTION__); \
} \
else \
{ \
PRINT("EXIT %s", __FUNCTION__); \
} \
} \
} while(0)
#define TRACE_EXIT_RES(res) \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT("[%d]: EXIT %s: %ld", gettid(), \
__FUNCTION__, (long)(res)); \
} \
else \
{ \
PRINT("EXIT %s: %ld", __FUNCTION__, (long)(res)); \
} \
} \
} while(0)
#define TRACE_EXIT_HRES(res) \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT("[%d]: EXIT %s: 0x%lx", gettid(), \
__FUNCTION__, (long)(res)); \
} \
else \
{ \
PRINT("EXIT %s: %lx", __FUNCTION__, (long)(res)); \
} \
} \
} while(0)
#else /* DEBUG */
#define NDEBUG
#include <assert.h>
#define TRACE_MEM(format, args...) {}
#define TRACE_DBG(format, args...) {}
#define TRACE_MGMT_DBG(format, args...) {}
#define TRACE_ENTRY() {}
#define TRACE_EXIT() {}
#define TRACE_EXIT_RES(res) {}
#define TRACE_EXIT_HRES(res) {}
#define PRINT_INFO_PR(format, args...) \
do { \
PRINT("%s: " format, LOG_PREFIX, args); \
} while(0)
#define PRINT_ERROR_PR(format, args...) \
do { \
PRINT("%s: ***ERROR*** " \
format, LOG_PREFIX, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
PRINT(format, args); \
} while(0)
#define PRINT_ERROR(format, args...) \
do { \
PRINT("***ERROR*** " format, args); \
} while(0)
#endif /* DEBUG */
#endif /* __DEBUG_H */
+488
View File
@@ -0,0 +1,488 @@
/*
* fileio.c
*
* Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <getopt.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <pthread.h>
char *app_name;
#define LOG_PREFIX app_name
#include "common.h"
#if defined(DEBUG) || defined(TRACING)
#ifdef DEBUG
/*#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF \
& ~TRACE_FUNCTION)
#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF & \
~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
*/
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | TRACE_ORDER | \
TRACE_TIME)
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
#else /* DEBUG */
# ifdef TRACING
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_TIME | TRACE_SPECIAL)
# else
#define DEFAULT_LOG_FLAGS 0
# endif
#endif /* DEBUG */
unsigned long trace_flag = DEFAULT_LOG_FLAGS;
#endif /* defined(DEBUG) || defined(TRACING) */
#define DEF_BLOCK_SHIFT 9
#define VERSION_STR "0.9.6"
#define THREADS 7
static struct option const long_options[] =
{
{"block", required_argument, 0, 'b'},
{"threads", required_argument, 0, 'e'},
{"write_through", no_argument, 0, 't'},
{"read_only", no_argument, 0, 'r'},
{"direct", no_argument, 0, 'o'},
{"nullio", no_argument, 0, 'n'},
{"nv_cache", no_argument, 0, 'c'},
{"parse", required_argument, 0, 'p'},
{"on_free", required_argument, 0, 'f'},
{"mem_reuse", required_argument, 0, 'm'},
{"prio_thread", no_argument, 0, 's'},
{"non_blocking", no_argument, 0, 'l'},
#if defined(DEBUG) || defined(TRACING)
{"debug", required_argument, 0, 'd'},
#endif
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
{"debug_tm_ignore", no_argument, 0, 'g'},
#endif
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
static void usage(void)
{
printf("Usage: %s [OPTION] name path\n", app_name);
printf("\nFILEIO disk target emulator for SCST\n");
printf(" -b, --block=size Block size, must be power of 2 and >=512\n");
printf(" -e, --threads=count Number of threads, %d by default\n", THREADS);
printf(" -t, --write_through Write through mode\n");
printf(" -r, --read_only Read only\n");
printf(" -o, --direct O_DIRECT mode\n");
printf(" -n, --nullio NULLIO mode\n");
printf(" -c, --nv_cache NV_CACHE mode\n");
printf(" -p, --parse=type Parse type, one of \"std\" "
"(default), \"call\" or \"excpt\"\n");
printf(" -f, --on_free=type On free call type, one of \"ignore\" "
"(default) or \"call\"\n");
printf(" -m, --mem_reuse=type Memory reuse type, one of \"all\" "
"(default), \"read\", \"write\" or \"none\"\n");
printf(" -s, --prio_thread Use separate thread for mgmt (prio) commands\n");
printf(" -l, --non_blocking Use non-blocking operations\n");
#if defined(DEBUG) || defined(TRACING)
printf(" -d, --debug=level Debug tracing level\n");
#endif
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
printf(" -g, --debug_tm_ignore Turn on DEBUG_TM_IGNORE\n");
#endif
return;
}
static int scst_calc_block_shift(int sector_size)
{
int block_shift = 0;
int t = sector_size;
if (sector_size == 0)
goto out;
t = sector_size;
while(1) {
if ((t & 1) != 0)
break;
t >>= 1;
block_shift++;
}
if (block_shift < 9) {
PRINT_ERROR_PR("Wrong sector size %d", sector_size);
block_shift = -1;
}
out:
TRACE_EXIT_RES(block_shift);
return block_shift;
}
static void *align_alloc(size_t size)
{
return memalign(PAGE_SIZE, size);
}
int main(int argc, char **argv)
{
int res = 0;
int ch, longindex;
int fd;
int parse_type = SCST_USER_PARSE_STANDARD;
int on_free_cmd_type = SCST_USER_ON_FREE_CMD_IGNORE;
int on_free_cmd_type_set = 0;
int memory_reuse_type = SCST_USER_MEM_REUSE_ALL;
int threads = THREADS;
struct scst_user_dev_desc desc;
struct vdisk_dev dev;
setlinebuf(stdout);
app_name = argv[0];
memset(&dev, 0, sizeof(dev));
dev.block_size = (1 << DEF_BLOCK_SHIFT);
dev.block_shift = DEF_BLOCK_SHIFT;
dev.type = TYPE_DISK;
dev.alloc_fn = align_alloc;
while ((ch = getopt_long(argc, argv, "+b:e:tronsglcp:f:m:d:vh", long_options,
&longindex)) >= 0) {
switch (ch) {
case 'b':
dev.block_size = atoi(optarg);
PRINT_INFO("block_size %x (%s)", dev.block_size, optarg);
dev.block_shift = scst_calc_block_shift(dev.block_size);
if (dev.block_shift < 9) {
res = -EINVAL;
goto out_usage;
}
break;
case 'e':
threads = strtol(optarg, (char **)NULL, 0);
break;
case 't':
dev.wt_flag = 1;
break;
#if defined(DEBUG) || defined(TRACING)
case 'd':
trace_flag = strtol(optarg, (char **)NULL, 0);
break;
#endif
case 'r':
dev.rd_only_flag = 1;
break;
case 'o':
dev.o_direct_flag = 1;
dev.alloc_fn = align_alloc;
break;
case 'n':
dev.nullio = 1;
break;
case 'c':
dev.nv_cache = 1;
break;
case 'p':
if (strncmp(optarg, "std", 3) == 0)
parse_type = SCST_USER_PARSE_STANDARD;
else if (strncmp(optarg, "call", 3) == 0)
parse_type = SCST_USER_PARSE_CALL;
else if (strncmp(optarg, "excpt", 5) == 0)
parse_type = SCST_USER_PARSE_EXCEPTION;
else
goto out_usage;
break;
case 'f':
on_free_cmd_type_set = 1;
if (strncmp(optarg, "ignore", 6) == 0)
on_free_cmd_type = SCST_USER_ON_FREE_CMD_IGNORE;
else if (strncmp(optarg, "call", 3) == 0)
on_free_cmd_type = SCST_USER_ON_FREE_CMD_CALL;
else
goto out_usage;
break;
case 'm':
if (strncmp(optarg, "all", 3) == 0)
memory_reuse_type = SCST_USER_MEM_REUSE_ALL;
else if (strncmp(optarg, "read", 4) == 0)
memory_reuse_type = SCST_USER_MEM_REUSE_READ;
else if (strncmp(optarg, "write", 5) == 0)
memory_reuse_type = SCST_USER_MEM_REUSE_WRITE;
else if (strncmp(optarg, "none", 4) == 0)
memory_reuse_type = SCST_USER_MEM_NO_REUSE;
else
goto out_usage;
break;
case 's':
dev.prio_thr = 1;
break;
case 'l':
dev.non_blocking = 1;
break;
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
case 'g':
dev.debug_tm_ignore = 1;
break;
#endif
case 'v':
printf("%s version %s\n", app_name, VERSION_STR);
goto out;
default:
goto out_usage;
}
}
if (optind != (argc-2))
goto out_usage;
if (!on_free_cmd_type_set &&
(memory_reuse_type != SCST_USER_MEM_REUSE_ALL))
on_free_cmd_type = SCST_USER_ON_FREE_CMD_CALL;
dev.name = argv[optind];
dev.file_name = argv[optind+1];
TRACE_DBG("Opening file %s", dev.file_name);
fd = open(dev.file_name, O_RDONLY|O_LARGEFILE);
if (fd < 0) {
res = errno;
PRINT_ERROR_PR("Unable to open file %s (%s)", dev.file_name,
strerror(res));
goto out;
}
dev.file_size = lseek64(fd, 0, SEEK_END);
dev.nblocks = dev.file_size >> dev.block_shift;
close(fd);
PRINT_INFO_PR("Virtual device \"%s\", path \"%s\", size %LdMb, "
"block size %d, nblocks %Ld, options:", dev.name, dev.file_name,
dev.file_size/1024/1024, dev.block_size, dev.nblocks);
if (dev.rd_only_flag)
PRINT_INFO(" %s", "READ ONLY");
if (dev.wt_flag)
PRINT_INFO(" %s", "WRITE THROUGH");
if (dev.nv_cache)
PRINT_INFO(" %s", "NV_CACHE");
if (dev.o_direct_flag)
PRINT_INFO(" %s", "O_DIRECT");
if (dev.nullio)
PRINT_INFO(" %s", "NULLIO");
if (dev.non_blocking)
PRINT_INFO(" %s", "NON-BLOCKING");
switch(parse_type) {
case SCST_USER_PARSE_STANDARD:
PRINT_INFO(" %s", "Standard parse");
break;
case SCST_USER_PARSE_CALL:
PRINT_INFO(" %s", "Call parse");
break;
case SCST_USER_PARSE_EXCEPTION:
PRINT_INFO(" %s", "Exception parse");
break;
default:
sBUG();
}
switch(on_free_cmd_type) {
case SCST_USER_ON_FREE_CMD_IGNORE:
PRINT_INFO(" %s", "Ignore on_free_cmd");
break;
case SCST_USER_ON_FREE_CMD_CALL:
PRINT_INFO(" %s", "Call on_free_cmd");
break;
default:
sBUG();
}
switch(memory_reuse_type) {
case SCST_USER_MEM_REUSE_ALL:
PRINT_INFO(" %s", "Full memory reuse enabled");
break;
case SCST_USER_MEM_REUSE_READ:
PRINT_INFO(" %s", "READ memory reuse enabled");
break;
case SCST_USER_MEM_REUSE_WRITE:
PRINT_INFO(" %s", "WRITE memory reuse enabled");
break;
case SCST_USER_MEM_NO_REUSE:
PRINT_INFO(" %s", "Memory reuse disabled");
break;
default:
sBUG();
}
if (!dev.o_direct_flag && (memory_reuse_type == SCST_USER_MEM_NO_REUSE)) {
PRINT_INFO(" %s", "Using unaligned buffers");
dev.alloc_fn = malloc;
}
if (dev.prio_thr) {
PRINT_INFO(" %s", "Using separate prio thread");
}
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
if (dev.debug_tm_ignore) {
PRINT_INFO(" %s", "DEBUG_TM_IGNORE");
}
#endif
#ifdef DEBUG
PRINT_INFO("trace_flag %lx", trace_flag);
#endif
dev.scst_usr_fd = open(DEV_USER_PATH DEV_USER_NAME, O_RDWR |
(dev.non_blocking ? O_NONBLOCK : 0));
if (dev.scst_usr_fd < 0) {
res = dev.scst_usr_fd;
PRINT_ERROR_PR("Unable to open SCST device %s (%s)",
DEV_USER_PATH DEV_USER_NAME, strerror(res));
goto out;
}
memset(&desc, 0, sizeof(desc));
desc.version = DEV_USER_VERSION;
strncpy(desc.name, dev.name, sizeof(desc.name)-1);
desc.name[sizeof(desc.name)-1] = '\0';
desc.type = dev.type;
desc.block_size = dev.block_size;
desc.opt.parse_type = parse_type;
desc.opt.on_free_cmd_type = on_free_cmd_type;
desc.opt.memory_reuse_type = memory_reuse_type;
if (dev.prio_thr)
desc.opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SEPARATE;
else
desc.opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SINGLE;
res = ioctl(dev.scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
if (res != 0) {
res = errno;
PRINT_ERROR_PR("Unable to register device: %s", strerror(res));
goto out_close;
}
#if 0
{
/* Not needed, added here only as a test */
struct scst_user_opt opt;
res = ioctl(dev.scst_usr_fd, SCST_USER_GET_OPTIONS, &opt);
if (res != 0) {
res = errno;
PRINT_ERROR_PR("Unable to get options: %s", strerror(res));
goto out_close;
}
opt.parse_type = parse_type;
opt.on_free_cmd_type = on_free_cmd_type;
opt.memory_reuse_type = memory_reuse_type;
if (dev.prio_thr)
opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SEPARATE;
else
opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SINGLE;
res = ioctl(dev.scst_usr_fd, SCST_USER_SET_OPTIONS, &opt);
if (res != 0) {
res = errno;
PRINT_ERROR_PR("Unable to get options: %s", strerror(res));
goto out_close;
}
}
#endif
res = pthread_mutex_init(&dev.dev_mutex, NULL);
if (res != 0) {
res = errno;
PRINT_ERROR_PR("pthread_mutex_init() failed: %s", strerror(res));
goto out_close;
}
{
pthread_t thread[threads];
pthread_t prio;
int i, j, rc;
void *rc1;
for(i = 0; i < threads; i++) {
rc = pthread_create(&thread[i], NULL, main_loop, &dev);
if (rc != 0) {
res = errno;
PRINT_ERROR_PR("pthread_create() failed: %s",
strerror(res));
break;
}
}
if (dev.prio_thr) {
rc = pthread_create(&prio, NULL, prio_loop, &dev);
if (rc != 0) {
res = errno;
PRINT_ERROR_PR("Prio pthread_create() failed: %s",
strerror(res));
dev.prio_thr = 0;
}
}
j = i;
for(i = 0; i < j; i++) {
rc = pthread_join(thread[i], &rc1);
if (rc != 0) {
res = errno;
PRINT_ERROR_PR("pthread_join() failed: %s",
strerror(res));
} else if (rc1 != NULL)
res = (int)rc1;
}
if (dev.prio_thr) {
rc = pthread_join(prio, &rc1);
if (rc != 0) {
res = errno;
PRINT_ERROR_PR("Prio pthread_join() failed: %s",
strerror(res));
} else if (rc1 != NULL)
res = (int)rc1;
}
}
pthread_mutex_destroy(&dev.dev_mutex);
out_close:
close(dev.scst_usr_fd);
out:
return res;
out_usage:
usage();
goto out;
}