mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-19 22:42:38 +00:00
- 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:
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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---
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user