Merge of the sysfs branch. To enable the sysfs interface you should run "make disable...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 21 Oct 2009 16:49:52 +0000 (16:49 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 21 Oct 2009 16:49:52 +0000 (16:49 +0000)
The sysfs intarface is mostly finished. Only initiators-oriented access control not implemented and not all target drivers are updated. Only qla2x00t has been fully updated.

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@1229 d57e44dd-8a1f-0410-8b47-8ef2f437770f

50 files changed:
Makefile
iscsi-full_perf.patch [deleted file]
iscsi-release.patch [deleted file]
iscsi-scst/Makefile
iscsi-scst/kernel/config.c
iscsi-scst/kernel/conn.c
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/session.c
qla2x00t-full_perf.patch [deleted file]
qla2x00t-release.patch [deleted file]
qla2x00t/qla2x00-target/Makefile
qla2x00t/qla2x00-target/qla2x00t.c
qla2x00t/qla2x00-target/qla2x00t.h
qla2x00t/qla2x_tgt.h
qla2x00t/qla2x_tgt_def.h
qla2x00t/qla_attr.c
qla2x00t/qla_def.h
qla2x00t/qla_isr.c
qla2x00t/qla_os.c
scst-full_perf.patch [deleted file]
scst-release.patch [deleted file]
scst/Makefile
scst/README
scst/README_in-tree
scst/include/scst.h
scst/include/scst_const.h
scst/src/Makefile
scst/src/dev_handlers/Makefile
scst/src/dev_handlers/scst_cdrom.c
scst/src/dev_handlers/scst_changer.c
scst/src/dev_handlers/scst_dev_handler.h
scst/src/dev_handlers/scst_disk.c
scst/src/dev_handlers/scst_modisk.c
scst/src/dev_handlers/scst_processor.c
scst/src/dev_handlers/scst_raid.c
scst/src/dev_handlers/scst_tape.c
scst/src/dev_handlers/scst_user.c
scst/src/dev_handlers/scst_vdisk.c
scst/src/scst_lib.c
scst/src/scst_main.c
scst/src/scst_mem.c
scst/src/scst_mem.h
scst/src/scst_priv.h
scst/src/scst_proc.c
scst/src/scst_sysfs.c [new file with mode: 0644]
scst/src/scst_targ.c
usr-full_perf.patch [deleted file]
usr-release.patch [deleted file]
usr/fileio/Makefile

index 1464aa2..9513338 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -301,38 +301,63 @@ mvsas_clean:
 mvsas_extraclean:
        cd $(MVSAS_DIR) && $(MAKE) extraclean
 
-
 debug2perf:
-       echo "Changing current debug state from full debug to full performance"
-       patch -p0 <scst-full_perf.patch
-       patch -p0 <usr-full_perf.patch
-       patch -p0 <qla2x00t-full_perf.patch
-       patch -p0 <iscsi-full_perf.patch
-       patch -p0 <qla_isp-release.patch
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+       @if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
 
 debug2release:
-       echo "Changing current debug state from full debug to release"
-       patch -p0 <scst-release.patch
-       patch -p0 <usr-release.patch
-       patch -p0 <qla2x00t-release.patch
-       patch -p0 <iscsi-release.patch
-       patch -p0 <qla_isp-release.patch
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+       @if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
 
 perf2debug:
-       echo "Changing current debug state from full performance to full debug"
-       patch -p0 -R <scst-full_perf.patch
-       patch -p0 -R <usr-full_perf.patch
-       patch -p0 -R <qla2x00t-full_perf.patch
-       patch -p0 -R <iscsi-full_perf.patch
-       patch -p0 -R <qla_isp-release.patch
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 -R <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+       @if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
 
 release2debug:
-       echo "Changing current debug state from release to full debug"
-       patch -p0 -R <scst-release.patch
-       patch -p0 -R <usr-release.patch
-       patch -p0 -R <qla2x00t-release.patch
-       patch -p0 -R <iscsi-release.patch
-       patch -p0 -R <qla_isp-release.patch
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 -R <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+       @if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
+
+enable_proc:
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 -R <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
+
+disable_proc:
+       cd $(SCST_DIR) && $(MAKE) $@
+       @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+#      patch -p0 -R <qla_isp-release.patch
+#      @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
+       @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
+#      @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
 
 .PHONY: all install uninstall clean extraclean help \
        qla qla_install qla_uninstall qla_clean qla_extraclean \
@@ -345,4 +370,5 @@ release2debug:
        usr usr_install usr_uninstall usr_clean usr_extraclean \
        scst_local scst_local_install scst_local_uninstall scst_local_clean scst_local_extraclean \
        mvsas mvsas_install mvsas_uninstall mvsas_clean mvsas_extraclean \
-       debug2perf, debug2release, perf2debug, release2debug
+       debug2perf, debug2release, perf2debug, release2debug \
+       enable_proc disable_proc
diff --git a/iscsi-full_perf.patch b/iscsi-full_perf.patch
deleted file mode 100644 (file)
index cb663f6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Index: iscsi-scst/kernel/Makefile
-===================================================================
---- iscsi-scst/kernel/Makefile (revision 544)
-+++ iscsi-scst/kernel/Makefile (working copy)
-@@ -23,9 +23,9 @@
- EXTRA_CFLAGS += -I$(src)/../include -I$(SCST_INC_DIR)
- EXTRA_CFLAGS += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
- #EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
diff --git a/iscsi-release.patch b/iscsi-release.patch
deleted file mode 100644 (file)
index 58a75ba..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Index: iscsi-scst/kernel/Makefile
-===================================================================
---- iscsi-scst/kernel/Makefile (revision 544)
-+++ iscsi-scst/kernel/Makefile (working copy)
-@@ -23,9 +23,9 @@
- EXTRA_CFLAGS += -I$(src)/../include -I$(SCST_INC_DIR)
- EXTRA_CFLAGS += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
--#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
index 5638544..5672837 100644 (file)
@@ -14,6 +14,7 @@ SCST_DIR := $(shell pwd)/../scst/src
 SBINDIR := /usr/local/sbin
 INITDIR := /etc/init.d
 RCDIR := /etc/rc.d
+KMOD := $(shell pwd)/kernel
 
 ifeq ($(KVER),)
   ifeq ($(KDIR),)
@@ -29,7 +30,7 @@ endif
 all: include/iscsi_scst_itf_ver.h progs mods
 
 mods: Modules.symvers Module.symvers
-       $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(shell pwd)/kernel modules
+       $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) modules
 
 progs:
        $(MAKE) -C usr
@@ -79,11 +80,47 @@ endif
 
 clean:
        $(MAKE) -C usr clean
-       $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/kernel clean
+       $(MAKE) -C $(KDIR) SUBDIRS=$(KMOD) clean
        rm -f kernel/Modules.symvers kernel/Module.symvers \
                kernel/Module.markers kernel/modules.order \
                include/iscsi_scst_itf_ver.h
 
 extraclean: clean
 
-.PHONY: all mods progs install clean extraclean
+debug2release:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       rm $(KMOD)/Makefile.aa
+
+release2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       rm $(KMOD)/Makefile.aa
+
+debug2perf:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       rm $(KMOD)/Makefile.aa
+
+perf2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ $(KMOD)/Makefile
+       @cmp $(KMOD)/Makefile $(KMOD)/Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm $(KMOD)/Makefile.aa; echo "sed failed"; false; fi
+       rm $(KMOD)/Makefile.aa
+
+disable_proc:
+
+enable_proc:
+
+.PHONY: all mods progs install clean extraclean debug2release release2debug debug2perf perf2debug disable_proc enable_proc
index 0bae263..e279597 100644 (file)
  *  GNU General Public License for more details.
  */
 
-#include <linux/proc_fs.h>
-
 #include "iscsi.h"
 
+#ifdef CONFIG_SCST_PROC
+
+#include <linux/proc_fs.h>
+
 #define ISCSI_PROC_VERSION_NAME                "version"
 
 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
@@ -25,7 +27,7 @@
 
 #include <linux/proc_fs.h>
 
-static struct scst_proc_log iscsi_proc_local_trace_tbl[] =
+static struct scst_trace_log iscsi_local_trace_tbl[] =
 {
     { TRACE_D_READ,            "d_read" },
     { TRACE_D_WRITE,           "d_write" },
@@ -44,7 +46,7 @@ static int iscsi_log_info_show(struct seq_file *seq, void *v)
        TRACE_ENTRY();
 
        res = scst_proc_log_entry_read(seq, trace_flag,
-               iscsi_proc_local_trace_tbl);
+               iscsi_local_trace_tbl);
 
        TRACE_EXIT_RES(res);
        return res;
@@ -58,7 +60,7 @@ static ssize_t iscsi_proc_log_entry_write(struct file *file,
        TRACE_ENTRY();
 
        res = scst_proc_log_entry_write(file, buf, length, &trace_flag,
-               ISCSI_DEFAULT_LOG_FLAGS, iscsi_proc_local_trace_tbl);
+               ISCSI_DEFAULT_LOG_FLAGS, iscsi_local_trace_tbl);
 
        TRACE_EXIT_RES(res);
        return res;
@@ -231,6 +233,8 @@ err:
        goto out;
 }
 
+#endif /* CONFIG_SCST_PROC */
+
 /* target_mutex supposed to be locked */
 static int add_conn(struct iscsi_target *target, void __user *ptr)
 {
index 21ec29c..583f3eb 100644 (file)
@@ -21,6 +21,8 @@
 #include "iscsi.h"
 #include "digest.h"
 
+#ifdef CONFIG_SCST_PROC
+
 static void print_conn_state(char *p, size_t size, struct iscsi_conn *conn)
 {
        int printed = 0;
@@ -111,6 +113,8 @@ void conn_info_show(struct seq_file *seq, struct iscsi_session *session)
        }
 }
 
+#endif /* CONFIG_SCST_PROC */
+
 /* target_mutex supposed to be locked */
 struct iscsi_conn *conn_lookup(struct iscsi_session *session, u16 cid)
 {
index ff6b17c..2cca098 100644 (file)
@@ -3256,9 +3256,11 @@ static int __init iscsi_init(void)
 
        iscsi_template_registered = 1;
 
+#ifdef CONFIG_SCST_PROC
        err = iscsi_procfs_init();
        if (err < 0)
                goto out_reg_tmpl;
+#endif
 
        num = max((int)num_online_cpus(), 2);
 
@@ -3274,10 +3276,14 @@ out:
        return err;
 
 out_thr:
+#ifdef CONFIG_SCST_PROC
        iscsi_procfs_exit();
+#endif
        iscsi_stop_threads();
 
+#ifdef CONFIG_SCST_PROC
 out_reg_tmpl:
+#endif
        scst_unregister_target_template(&iscsi_template);
 
 out_kmem:
@@ -3305,7 +3311,9 @@ static void __exit iscsi_exit(void)
 
        unregister_chrdev(ctr_major, ctr_name);
 
+#ifdef CONFIG_SCST_PROC
        iscsi_procfs_exit();
+#endif
        event_exit();
 
        kmem_cache_destroy(iscsi_cmnd_cache);
index 131cc8d..eac1178 100644 (file)
@@ -18,7 +18,6 @@
 #define __ISCSI_H__
 
 #include <linux/pagemap.h>
-#include <linux/seq_file.h>
 #include <linux/mm.h>
 #include <linux/net.h>
 #include <net/sock.h>
@@ -439,7 +438,10 @@ extern void __mark_conn_closed(struct iscsi_conn *, int);
 
 extern void mark_conn_closed(struct iscsi_conn *);
 extern void iscsi_make_conn_wr_active(struct iscsi_conn *);
+
+#ifdef CONFIG_SCST_PROC
 extern void conn_info_show(struct seq_file *, struct iscsi_session *);
+#endif
 
 /* nthread.c */
 extern int iscsi_send(struct iscsi_conn *conn);
@@ -463,8 +465,10 @@ extern void target_del_all(void);
 extern const struct seq_operations iscsi_seq_op;
 
 /* config.c */
+#ifdef CONFIG_SCST_PROC
 extern int iscsi_procfs_init(void);
 extern void iscsi_procfs_exit(void);
+#endif
 
 /* session.c */
 extern const struct file_operations session_seq_fops;
index 35bcc21..42ee378 100644 (file)
@@ -311,6 +311,8 @@ int session_del(struct iscsi_target *target, u64 sid)
        return session_free(session, true);
 }
 
+#ifdef CONFIG_SCST_PROC
+
 /* target_mutex supposed to be locked */
 static void iscsi_session_info_show(struct seq_file *seq,
                                    struct iscsi_target *target)
@@ -345,3 +347,5 @@ const struct file_operations session_seq_fops = {
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
+
+#endif /* CONFIG_SCST_PROC */
diff --git a/qla2x00t-full_perf.patch b/qla2x00t-full_perf.patch
deleted file mode 100644 (file)
index befe6fc..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Index: qla2x00t/qla2x00-target/Makefile
-===================================================================
---- qla2x00t/qla2x00-target/Makefile   (revision 545)
-+++ qla2x00t/qla2x00-target/Makefile   (working copy)
-@@ -37,9 +37,9 @@ INSTALL_DIR := /lib/modules/$(shell unam
- EXTRA_CFLAGS += -W -Wno-unused-parameter -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS 
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS 
- #EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD
- ifeq ($(KVER),)
diff --git a/qla2x00t-release.patch b/qla2x00t-release.patch
deleted file mode 100644 (file)
index 117fa1d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Index: qla2x00t/qla2x00-target/Makefile
-===================================================================
---- qla2x00t/qla2x00-target/Makefile   (revision 545)
-+++ qla2x00t/qla2x00-target/Makefile   (working copy)
-@@ -37,9 +37,9 @@ INSTALL_DIR := /lib/modules/$(shell unam
- EXTRA_CFLAGS += -W -Wno-unused-parameter -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS 
--#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS 
-+EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD
- ifeq ($(KVER),)
index b5c351d..87fe804 100644 (file)
@@ -103,4 +103,46 @@ clean:
 
 extraclean: clean
 
-.PHONY: all tgt install uninstall clean extraclean
+debug2release:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+release2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+debug2perf:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+perf2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+disable_proc:
+       sed -c -i.aa s/"^#define CONFIG_SCST_PROC"/"\/* #define CONFIG_SCST_PROC *\/"/ ../qla_attr.c
+       @cmp ../qla_attr.c ../qla_attr.c.aa >/dev/null; if [[ $$? = 0 ]]; then rm ../qla_attr.c.aa; echo "sed failed"; false; fi
+       rm ../qla_attr.c.aa
+
+enable_proc:
+       sed -c -i.aa s/"\/\* #define CONFIG_SCST_PROC \*\/"/"#define CONFIG_SCST_PROC"/ ../qla_attr.c
+       @cmp ../qla_attr.c ../qla_attr.c.aa >/dev/null; if [[ $$? = 0 ]]; then rm ../qla_attr.c.aa; echo "sed failed"; false; fi
+       rm ../qla_attr.c.aa
+
+.PHONY: all tgt install uninstall clean extraclean debug2perf debug2release perf2debug release2debug disable_proc enable_proc
index 913d22e..387b5bd 100644 (file)
@@ -29,7 +29,6 @@
 #include <scsi/scsi_host.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/seq_file.h>
 #include <linux/list.h>
 
 #include <scst.h>
@@ -46,7 +45,7 @@
  *     including rings related fields,
  *
  *   - Or access to target mode variables from struct q2t_tgt doesn't
- *     cross those functions boundaries, except tgt_shutdown, which
+ *     cross those functions boundaries, except tgt_stop, which
  *     additionally protected by irq_cmd_count.
  */
 
@@ -65,7 +64,7 @@
 # endif
 #endif
 
-static int q2x_target_detect(struct scst_tgt_template *templ);
+static int q2t_target_detect(struct scst_tgt_template *templ);
 static int q2t_target_release(struct scst_tgt *scst_tgt);
 static int q2x_xmit_response(struct scst_cmd *scst_cmd);
 static int __q24_xmit_response(struct q2t_cmd *cmd, int xmit_type);
@@ -96,10 +95,46 @@ static void q2t_clear_tgt_db(struct q2t_tgt *tgt, bool local_only);
 static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd);
 static int q2t_unreg_sess(struct q2t_sess *sess);
 
+/** SYSFS **/
+
+static ssize_t q2t_version_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+
+struct kobj_attribute q2t_version_attr =
+       __ATTR(version, S_IRUGO, q2t_version_show, NULL);
+
+static const struct attribute *q2t_attrs[] = {
+       &q2t_version_attr.attr,
+       NULL,
+};
+
+static ssize_t q2t_show_expl_conf_enabled(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buffer);
+static ssize_t q2t_store_expl_conf_enabled(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buffer, size_t size);
+
+struct kobj_attribute q2t_expl_conf_attr =
+       __ATTR(explicit_confirmation, S_IRUGO|S_IWUSR,
+              q2t_show_expl_conf_enabled, q2t_store_expl_conf_enabled);
+
+static const struct attribute *q2t_tgt_attrs[] = {
+       &q2t_expl_conf_attr.attr,
+       NULL,
+};
+
+static ssize_t q2t_enable_tgt(struct scst_tgt *tgt, const char *buf,
+       size_t size);
+static bool q2t_is_tgt_enabled(struct scst_tgt *tgt);
+
 /*
  * Global Variables
  */
 
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+#define trace_flag q2t_trace_flag
+static unsigned long q2t_trace_flag = Q2T_DEFAULT_LOG_FLAGS;
+#endif
+
 static struct scst_tgt_template tgt2x_template = {
        .name = "qla2x00tgt",
        .sg_tablesize = 0,
@@ -112,19 +147,22 @@ static struct scst_tgt_template tgt2x_template = {
        .rdy_to_xfer_atomic = 1,
 #endif
        .max_hw_pending_time = Q2T_MAX_HW_PENDING_TIME,
-       .detect = q2x_target_detect,
+       .detect = q2t_target_detect,
        .release = q2t_target_release,
        .xmit_response = q2x_xmit_response,
        .rdy_to_xfer = q2t_rdy_to_xfer,
        .on_free_cmd = q2t_on_free_cmd,
        .task_mgmt_fn_done = q2t_task_mgmt_fn_done,
        .on_hw_pending_cmd_timeout = q2t_on_hw_pending_cmd_timeout,
-};
-
+       .enable_tgt = q2t_enable_tgt,
+       .is_tgt_enabled = q2t_is_tgt_enabled,
+       .tgtt_attrs = q2t_attrs,
+       .tgt_attrs = q2t_tgt_attrs,
 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
-#define trace_flag q2t_trace_flag
-static unsigned long q2t_trace_flag = Q2T_DEFAULT_LOG_FLAGS;
+       .default_trace_flags = Q2T_DEFAULT_LOG_FLAGS,
+       .trace_flags = &trace_flag,
 #endif
+};
 
 static struct kmem_cache *q2t_cmd_cachep;
 static struct kmem_cache *q2t_mgmt_cmd_cachep;
@@ -224,7 +262,7 @@ static inline int q2t_issue_marker(scsi_qla_host_t *ha, int ha_locked)
  * Registers with initiator driver (but target mode isn't enabled till
  * it's turned on via sysfs)
  */
-static int q2x_target_detect(struct scst_tgt_template *templ)
+static int q2t_target_detect(struct scst_tgt_template *tgtt)
 {
        int res;
        struct qla_tgt_data t = {
@@ -253,6 +291,8 @@ static int q2x_target_detect(struct scst_tgt_template *templ)
                goto out;
        }
 
+       qla2xxx_add_targets();
+
        PRINT_INFO("%s", "Target mode driver for QLogic 2x00 controller "
                "registered successfully");
 
@@ -622,7 +662,7 @@ static void q2t_fc_port_added(scsi_qla_host_t *ha, fc_port_t *fcport)
        if ((tgt == NULL) || (fcport->port_type != FCT_INITIATOR))
                goto out_unlock;
 
-       if (tgt->tgt_shutdown)
+       if (tgt->tgt_stop)
                goto out_unlock;
 
        spin_lock_irq(&ha->hardware_lock);
@@ -686,7 +726,7 @@ static void q2t_fc_port_deleted(scsi_qla_host_t *ha, fc_port_t *fcport)
 
        dev_loss_tmo = ha->port_down_retry_count + 5;
 
-       if (tgt->tgt_shutdown)
+       if (tgt->tgt_stop)
                goto out_unlock;
 
        spin_lock_irq(&ha->hardware_lock);
@@ -747,15 +787,16 @@ static inline int test_tgt_sess_count(struct q2t_tgt *tgt)
        return res;
 }
 
-/* Must be called under read locked q2t_unreg_rwsem */
-static int q2t_target_release(struct scst_tgt *scst_tgt)
+/* Must be called under tgt_host_action_mutex */
+static void q2t_target_stop(struct scst_tgt *scst_tgt)
 {
-       int res = 0;
        struct q2t_tgt *tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
        scsi_qla_host_t *ha = tgt->ha;
 
        TRACE_ENTRY();
 
+       TRACE_DBG("Stopping target for host %ld(%p)", ha->host_no, ha);
+
        /*
         * Mutex needed to sync with q2t_fc_port_[added,deleted].
         * Lock is needed, because we still can get an incoming packet.
@@ -763,7 +804,7 @@ static int q2t_target_release(struct scst_tgt *scst_tgt)
 
        mutex_lock(&ha->tgt_mutex);
        spin_lock_irq(&ha->hardware_lock);
-       tgt->tgt_shutdown = 1;
+       tgt->tgt_stop = 1;
        q2t_clear_tgt_db(tgt, false);
        spin_unlock_irq(&ha->hardware_lock);
        mutex_unlock(&ha->tgt_mutex);
@@ -786,7 +827,7 @@ static int q2t_target_release(struct scst_tgt *scst_tgt)
        wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
 
        /* Big hammer */
-       if (!ha->host_shutting_down)
+       if (!ha->host_shutting_down && qla_tgt_mode_enabled(ha))
                qla2x00_disable_tgt_mode(ha);
 
        /* Wait for sessions to clear out (just in case) */
@@ -802,17 +843,35 @@ static int q2t_target_release(struct scst_tgt *scst_tgt)
                udelay(2);
                spin_lock_irq(&ha->hardware_lock);
        }
-       scst_tgt_set_tgt_priv(scst_tgt, NULL);
        ha->tgt = NULL;
        spin_unlock_irq(&ha->hardware_lock);
        mutex_unlock(&ha->tgt_mutex);
 
+       TRACE_MGMT_DBG("Stop of tgt %p finished", tgt);
+
+       TRACE_EXIT();
+       return;
+}
+
+/* Must be called under tgt_host_action_mutex */
+static int q2t_target_release(struct scst_tgt *scst_tgt)
+{
+       struct q2t_tgt *tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
+       scsi_qla_host_t *ha = tgt->ha;
+
+       TRACE_ENTRY();
+
+       q2t_target_stop(scst_tgt);
+
+       ha->q2t_tgt = NULL;
+       scst_tgt_set_tgt_priv(scst_tgt, NULL);
+
        TRACE_MGMT_DBG("Release of tgt %p finished", tgt);
 
        kfree(tgt);
 
-       TRACE_EXIT_RES(res);
-       return res;
+       TRACE_EXIT();
+       return 0;
 }
 
 /*
@@ -1238,7 +1297,7 @@ out:
 
 uint32_t q2t_convert_to_fc_tm_status(int scst_mstatus)
 {
-       int res;
+       uint32_t res;
 
        switch (scst_mstatus) {
        case SCST_MGMT_STATUS_SUCCESS:
@@ -3039,7 +3098,7 @@ static int q2t_send_cmd_to_scst(scsi_qla_host_t *ha, atio_t *atio)
 
        TRACE_ENTRY();
 
-       if (unlikely(tgt->tgt_shutdown)) {
+       if (unlikely(tgt->tgt_stop)) {
                TRACE_MGMT_DBG("New command while device %p is shutting "
                        "down", tgt);
                res = -EFAULT;
@@ -4176,7 +4235,7 @@ static void q24_atio_pkt(scsi_qla_host_t *ha, atio7_entry_t *atio)
              atio, atio->entry_type, atio->entry_count);
 
        /*
-        * In tgt_shutdown mode we also should allow all requests to pass.
+        * In tgt_stop mode we also should allow all requests to pass.
         * Otherwise, some commands can stuck.
         */
 
@@ -4278,7 +4337,7 @@ static void q2t_response_pkt(scsi_qla_host_t *ha, response_t *pkt)
              pkt->handle);
 
        /*
-        * In tgt_shutdown mode we also should allow all requests to pass.
+        * In tgt_stop mode we also should allow all requests to pass.
         * Otherwise, some commands can stuck.
         */
 
@@ -4523,7 +4582,7 @@ static void q2t_async_event(uint16_t code, scsi_qla_host_t *ha,
        }
 
        /*
-        * In tgt_shutdown mode we also should allow all requests to pass.
+        * In tgt_stop mode we also should allow all requests to pass.
         * Otherwise, some commands can stuck.
         */
 
@@ -4696,7 +4755,7 @@ static struct q2t_sess *q2t_make_local_sess(scsi_qla_host_t *ha, atio_t *atio)
        if (rc != QLA_SUCCESS) {
                PRINT_ERROR("Failed to retrieve fcport information "
                        "-- get_port_database() returned %x "
-                       "(loop_id=0x%04x)\n", rc, loop_id);
+                       "(loop_id=0x%04x)", rc, loop_id);
                goto out_free_fcport;
        }
 
@@ -4726,7 +4785,7 @@ static int q2t_exec_sess_work(struct q2t_tgt *tgt,
        mutex_lock(&ha->tgt_mutex);
        spin_lock_irq(&ha->hardware_lock);
 
-       if (tgt->tgt_shutdown)
+       if (tgt->tgt_stop)
                goto send;
 
        if (IS_FWI2_CAPABLE(ha)) {
@@ -4751,7 +4810,7 @@ static int q2t_exec_sess_work(struct q2t_tgt *tgt,
        }
 
 send:
-       if (!tgt->tm_to_unknown && !tgt->tgt_shutdown && (sess != NULL)) {
+       if (!tgt->tm_to_unknown && !tgt->tgt_stop && (sess != NULL)) {
                TRACE_MGMT_DBG("Sending work cmd %p to SCST", cmd);
                res = q2t_do_send_cmd_to_scst(ha, cmd, sess);
        } else {
@@ -4891,11 +4950,135 @@ out_unlock:
        return;
 }
 
-/* No lock held on entry, process context */
+/* Must be called under tgt_host_action_mutex */
+static int q2t_add_target(scsi_qla_host_t *ha)
+{
+       int res, rc;
+       char *wwn;
+       int sg_tablesize;
+       struct q2t_tgt *tgt;
+
+       TRACE_ENTRY();
+
+       TRACE_DBG("Registering target for host %ld(%p)", ha->host_no, ha);
+
+       sBUG_ON((ha->q2t_tgt != NULL) || (ha->tgt != NULL));
+
+       tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
+       if (tgt == NULL) {
+               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of tgt "
+                       "failed");
+               res = -ENOMEM;
+               goto out;
+       }
+
+       tgt->ha = ha;
+       init_waitqueue_head(&tgt->waitQ);
+       INIT_LIST_HEAD(&tgt->sess_list);
+       INIT_LIST_HEAD(&tgt->del_sess_list);
+       init_timer(&tgt->sess_del_timer);
+       tgt->sess_del_timer.data = (unsigned long)tgt;
+       tgt->sess_del_timer.function = q2t_del_sess_timer_fn;
+       spin_lock_init(&tgt->sess_work_lock);
+       INIT_WORK(&tgt->sess_work, q2t_sess_work_fn);
+       INIT_LIST_HEAD(&tgt->sess_works_list);
+       spin_lock_init(&tgt->srr_lock);
+       INIT_LIST_HEAD(&tgt->srr_ctio_list);
+       INIT_LIST_HEAD(&tgt->srr_imm_list);
+       INIT_WORK(&tgt->srr_work, q2t_handle_srr_work);
+
+       ha->q2t_tgt = tgt;
+
+       if (q2t_get_target_name(ha, &wwn) != 0)
+               goto out_free;
+
+       tgt->scst_tgt = scst_register(&tgt2x_template, wwn);
+
+       kfree(wwn);
+
+       if (!tgt->scst_tgt) {
+               PRINT_ERROR("qla2x00tgt(%ld): scst_register() "
+                           "failed for host %ld(%p)", ha->instance,
+                           ha->host_no, ha);
+               res = -ENOMEM;
+               goto out_free;
+       }
+
+       if (IS_FWI2_CAPABLE(ha)) {
+               PRINT_INFO("qla2400tgt(%ld): using 64 Bit PCI "
+                          "addressing", ha->instance);
+                       tgt->tgt_enable_64bit_addr = 1;
+                       /* 3 is reserved */
+                       sg_tablesize =
+                           QLA_MAX_SG_24XX(ha->request_q_length - 3);
+                       tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND_24XX;
+                       tgt->datasegs_per_cont = DATASEGS_PER_CONT_24XX;
+       } else {
+               if (ha->flags.enable_64bit_addressing) {
+                       PRINT_INFO("qla2x00tgt(%ld): 64 Bit PCI "
+                                  "addressing enabled", ha->instance);
+                       tgt->tgt_enable_64bit_addr = 1;
+                       /* 3 is reserved */
+                       sg_tablesize =
+                               QLA_MAX_SG64(ha->request_q_length - 3);
+                       tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND64;
+                       tgt->datasegs_per_cont = DATASEGS_PER_CONT64;
+               } else {
+                       PRINT_INFO("qla2x00tgt(%ld): Using 32 Bit "
+                                  "PCI addressing", ha->instance);
+                       sg_tablesize =
+                               QLA_MAX_SG32(ha->request_q_length - 3);
+                       tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND32;
+                       tgt->datasegs_per_cont = DATASEGS_PER_CONT32;
+               }
+       }
+
+#ifndef CONFIG_SCST_PROC
+       rc = sysfs_create_link(scst_sysfs_get_tgt_kobj(tgt->scst_tgt),
+               &ha->host->shost_dev.kobj, "host");
+       if (rc != 0)
+               PRINT_ERROR("Unable to create \"host\" link for target "
+                       "%s", scst_get_tgt_name(tgt->scst_tgt));
+#endif
+
+       scst_tgt_set_sg_tablesize(tgt->scst_tgt, sg_tablesize);
+       scst_tgt_set_tgt_priv(tgt->scst_tgt, tgt);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+
+out_free:
+       ha->q2t_tgt = NULL;
+       kfree(tgt);
+       goto out;
+}
+
+/* Must be called under tgt_host_action_mutex */
+static int q2t_remove_target(scsi_qla_host_t *ha)
+{
+       TRACE_ENTRY();
+
+       if ((ha->q2t_tgt == NULL) || (ha->tgt != NULL)) {
+               PRINT_ERROR("qla2x00tgt(%ld): Can't remove "
+                       "existing target", ha->instance);
+       }
+
+       TRACE_DBG("Unregistering target for host %ld(%p)", ha->host_no, ha);
+       scst_unregister(ha->tgt->scst_tgt);
+       /*
+        * Free of tgt happens via callback q2t_target_release
+        * called from scst_unregister, so we shouldn't touch
+        * it again.
+        */
+
+       TRACE_EXIT();
+       return 0;
+}
+
 static int q2t_host_action(scsi_qla_host_t *ha,
-                           qla2x_tgt_host_action_t action)
+       qla2x_tgt_host_action_t action)
 {
-       struct q2t_tgt *tgt = NULL;
        int res = 0;
 
        TRACE_ENTRY();
@@ -4903,14 +5086,21 @@ static int q2t_host_action(scsi_qla_host_t *ha,
        sBUG_ON(ha == NULL);
 
        /* To sync with q2t_exit() */
-       down_read(&q2t_unreg_rwsem);
+       if (down_read_trylock(&q2t_unreg_rwsem) == 0)
+               goto out;
+
+       mutex_lock(&ha->tgt_host_action_mutex);
 
        switch (action) {
+       case ADD_TARGET:
+               res = q2t_add_target(ha);
+               break;
+       case REMOVE_TARGET:
+               res = q2t_remove_target(ha);
+               break;
        case ENABLE_TARGET_MODE:
        {
                fc_port_t *fcport;
-               char *wwn;
-               int sg_tablesize;
 
                if (qla_tgt_mode_enabled(ha)) {
                        PRINT_INFO("qla2x00tgt(%ld): Target mode already "
@@ -4918,103 +5108,22 @@ static int q2t_host_action(scsi_qla_host_t *ha,
                        break;
                }
 
-               PRINT_INFO("qla2x00tgt(%ld): Enabling target mode",
-                       ha->instance);
-
-               if (ha->tgt != NULL)
-                       goto do_enable;
-
-               tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
-               if (tgt == NULL) {
-                       TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of tgt "
-                               "failed");
-                       res = -ENOMEM;
+               if ((ha->q2t_tgt == NULL) || (ha->tgt != NULL)) {
+                       PRINT_ERROR("qla2x00tgt(%ld): Can't enable target mode "
+                               "for not existing target", ha->instance);
                        break;
                }
 
-               tgt->ha = ha;
-               init_waitqueue_head(&tgt->waitQ);
-               INIT_LIST_HEAD(&tgt->sess_list);
-               INIT_LIST_HEAD(&tgt->del_sess_list);
-               init_timer(&tgt->sess_del_timer);
-               tgt->sess_del_timer.data = (unsigned long)tgt;
-               tgt->sess_del_timer.function = q2t_del_sess_timer_fn;
-               spin_lock_init(&tgt->sess_work_lock);
-               INIT_WORK(&tgt->sess_work, q2t_sess_work_fn);
-               INIT_LIST_HEAD(&tgt->sess_works_list);
-               spin_lock_init(&tgt->srr_lock);
-               INIT_LIST_HEAD(&tgt->srr_ctio_list);
-               INIT_LIST_HEAD(&tgt->srr_imm_list);
-               INIT_WORK(&tgt->srr_work, q2t_handle_srr_work);
-
-               if (q2t_get_target_name(ha, &wwn) != 0) {
-                       kfree(tgt);
-                       break;
-               }
-
-               mutex_lock(&ha->tgt_mutex);
-
-               tgt->scst_tgt = scst_register(&tgt2x_template, wwn);
-
-               /*
-                * scst_tgt protected by tgt_mutex from not get freed before
-                * been initialized
-                */
-
-               kfree(wwn);
-
-               if (!tgt->scst_tgt) {
-                       PRINT_ERROR("qla2x00tgt(%ld): scst_register() "
-                                   "failed for host %ld(%p)", ha->instance,
-                                   ha->host_no, ha);
-                       kfree(tgt);
-                       res = -ENOMEM;
-                       break;
-               }
-
-               if (IS_FWI2_CAPABLE(ha)) {
-                       PRINT_INFO("qla2400tgt(%ld): using 64 Bit PCI "
-                                  "addressing", ha->instance);
-                               tgt->tgt_enable_64bit_addr = 1;
-                               /* 3 is reserved */
-                               sg_tablesize =
-                                   QLA_MAX_SG_24XX(ha->request_q_length - 3);
-                               tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND_24XX;
-                               tgt->datasegs_per_cont = DATASEGS_PER_CONT_24XX;
-               } else {
-                       if (ha->flags.enable_64bit_addressing) {
-                               PRINT_INFO("qla2x00tgt(%ld): 64 Bit PCI "
-                                          "addressing enabled", ha->instance);
-                               tgt->tgt_enable_64bit_addr = 1;
-                               /* 3 is reserved */
-                               sg_tablesize =
-                                       QLA_MAX_SG64(ha->request_q_length - 3);
-                               tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND64;
-                               tgt->datasegs_per_cont = DATASEGS_PER_CONT64;
-                       } else {
-                               PRINT_INFO("qla2x00tgt(%ld): Using 32 Bit "
-                                          "PCI addressing", ha->instance);
-                               sg_tablesize =
-                                       QLA_MAX_SG32(ha->request_q_length - 3);
-                               tgt->datasegs_per_cmd = DATASEGS_PER_COMMAND32;
-                               tgt->datasegs_per_cont = DATASEGS_PER_CONT32;
-                       }
-               }
-
-               scst_tgt_set_sg_tablesize(tgt->scst_tgt, sg_tablesize);
-               scst_tgt_set_tgt_priv(tgt->scst_tgt, tgt);
+               PRINT_INFO("qla2x00tgt(%ld): Enabling target mode",
+                       ha->instance);
 
                spin_lock_irq(&ha->hardware_lock);
-               ha->tgt = tgt;
+               ha->tgt = ha->q2t_tgt;
+               ha->tgt->tgt_stop = 0;
                spin_unlock_irq(&ha->hardware_lock);
-
-               mutex_unlock(&ha->tgt_mutex);
-
                list_for_each_entry_rcu(fcport, &ha->fcports, list) {
                        q2t_fc_port_added(ha, fcport);
                }
-
-do_enable:
                TRACE_DBG("Enable tgt mode for host %ld(%ld,%p)",
                          ha->host_no, ha->instance, ha);
                qla2x00_enable_tgt_mode(ha);
@@ -5033,14 +5142,7 @@ do_enable:
 
                sBUG_ON(ha->tgt == NULL);
 
-               TRACE_DBG("Unregistering target for host %ld(%p)",
-                       ha->host_no, ha);
-               scst_unregister(ha->tgt->scst_tgt);
-               /*
-                * Free of tgt happens via callback q2t_target_release
-                * called from scst_unregister, so we shouldn't touch
-                * it again.
-                */
+               q2t_target_stop(ha->tgt->scst_tgt);
                break;
 
        default:
@@ -5050,12 +5152,137 @@ do_enable:
                break;
        }
 
-       up_read(&q2t_unreg_rwsem);
+       mutex_unlock(&ha->tgt_host_action_mutex);
 
+       up_read(&q2t_unreg_rwsem);
+out:
        TRACE_EXIT_RES(res);
        return res;
 }
 
+static ssize_t q2t_enable_tgt(struct scst_tgt *scst_tgt, const char *buffer,
+       size_t size)
+{
+       struct q2t_tgt *tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
+       scsi_qla_host_t *ha = tgt->ha;
+       int res = 0;
+
+       switch (buffer[0]) {
+       case '0' : 
+               res = q2t_host_action(ha, DISABLE_TARGET_MODE);
+               break;
+       case '1' :
+               res = q2t_host_action(ha, ENABLE_TARGET_MODE);
+               break;
+       default:
+               PRINT_ERROR("%s: Requested action not understood: %s",
+                      __func__, buffer);
+               res = -EINVAL;
+               goto out;
+       }
+
+       if (res == 0)
+               res = size;
+
+       if ((size > 1) && (buffer[1] == 'r')) {
+               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               qla2x00_wait_for_hba_online(ha);
+       }
+
+out:
+       return res;
+}
+
+static bool q2t_is_tgt_enabled(struct scst_tgt *scst_tgt)
+{
+       struct q2t_tgt *tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
+       scsi_qla_host_t *ha = tgt->ha;
+
+       return qla_tgt_mode_enabled(ha);
+}
+
+static ssize_t q2t_show_expl_conf_enabled(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buffer)
+{
+       struct scst_tgt *scst_tgt;
+       struct q2t_tgt *tgt;
+       scsi_qla_host_t *ha;
+       ssize_t size;
+
+       scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
+       tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
+       ha = tgt->ha;
+
+       size = scnprintf(buffer, PAGE_SIZE, "%d\n", ha->enable_explicit_conf);
+
+       return size;
+}
+
+static ssize_t q2t_store_expl_conf_enabled(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buffer, size_t size)
+{
+       struct scst_tgt *scst_tgt;
+       struct q2t_tgt *tgt;
+       scsi_qla_host_t *ha;
+       unsigned long flags;
+
+       scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
+       tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
+       ha = tgt->ha;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+
+       switch (buffer[0]) {
+       case '0' : 
+               ha->enable_explicit_conf = 0;
+               PRINT_INFO("qla2xxx(%ld): explicit conformations disabled",
+                       ha->instance);
+               break;
+       case '1' :
+               ha->enable_explicit_conf = 1;
+               PRINT_INFO("qla2xxx(%ld): explicit conformations enabled",
+                       ha->instance);
+               break;
+       default:
+#if defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_11)
+               PRINT_INFO("%s: Requested action not understood: %s",
+                      __func__, buffer);
+#endif
+               break;
+       }
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       return size;
+}
+
+static ssize_t q2t_version_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       sprintf(buf, "%s\n", Q2T_VERSION_STRING);
+
+#ifdef CONFIG_SCST_EXTRACHECKS
+       strcat(buf, "EXTRACHECKS\n");
+#endif
+
+#ifdef CONFIG_SCST_TRACING
+       strcat(buf, "TRACING\n");
+#endif
+
+#ifdef CONFIG_SCST_DEBUG
+       strcat(buf, "DEBUG\n");
+#endif
+
+#ifdef CONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD
+       strcat(buf, "QLA_TGT_DEBUG_WORK_IN_THREAD\n");
+#endif
+
+       TRACE_EXIT();
+       return strlen(buf);
+}
+
+#ifdef CONFIG_SCST_PROC
+
 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
 
 #define Q2T_PROC_LOG_ENTRY_NAME     "trace_level"
@@ -5194,6 +5421,8 @@ static void q2t_proc_log_entry_clean(struct scst_tgt_template *templ)
        return;
 }
 
+#endif /* CONFIG_SCST_PROC */
+
 static int __init q2t_init(void)
 {
        int res = 0;
@@ -5233,15 +5462,19 @@ static int __init q2t_init(void)
         * called via scst_register_target_template()
         */
 
+#ifdef CONFIG_SCST_PROC
        res = q2t_proc_log_entry_build(&tgt2x_template);
        if (res < 0)
                goto out_unreg_target2x;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_unreg_target2x:
+#endif
        scst_unregister_target_template(&tgt2x_template);
        qla2xxx_tgt_unregister_driver();
 
@@ -5266,17 +5499,26 @@ static void __exit q2t_exit(void)
        /* To sync with q2t_host_action() */
        down_write(&q2t_unreg_rwsem);
 
+#ifdef CONFIG_SCST_PROC
        q2t_proc_log_entry_clean(&tgt2x_template);
-       scst_unregister_target_template(&tgt2x_template);
+#endif
 
-       up_write(&q2t_unreg_rwsem);
+       scst_unregister_target_template(&tgt2x_template);
 
+       /*
+        * Now we have everywhere target mode disabled and no possibilities
+        * to call us through sysfs, so we can safely remove all the references
+        * to our functions.
+        */
        qla2xxx_tgt_unregister_driver();
 
        mempool_destroy(q2t_mgmt_cmd_mempool);
        kmem_cache_destroy(q2t_mgmt_cmd_cachep);
        kmem_cache_destroy(q2t_cmd_cachep);
 
+       /* Let's make lockdep happy */
+       up_write(&q2t_unreg_rwsem);
+
        TRACE_EXIT();
        return;
 }
index c54782c..0fc79a6 100644 (file)
@@ -134,7 +134,7 @@ struct q2t_tgt {
         * Protected by tgt_mutex AND hardware_lock for writing and tgt_mutex
         * OR hardware_lock for reading.
         */
-       unsigned long tgt_shutdown; /* the driver is being released */
+       unsigned long tgt_stop; /* the driver is being stopped */
 
        /* Count of sessions refering q2t_tgt. Protected by hardware_lock. */
        int sess_count;
@@ -162,6 +162,8 @@ struct q2t_tgt {
        struct list_head srr_ctio_list;
        struct list_head srr_imm_list;
        struct work_struct srr_work;
+
+       struct list_head tgt_list_entry;
 };
 
 /*
index b43e8fd..df7ed72 100644 (file)
@@ -129,6 +129,8 @@ qla2x00_send_enable_lun(scsi_qla_host_t *ha, bool enable)
        }
 }
 
+extern void qla2xxx_add_targets(void);
+
 #endif /* CONFIG_SCSI_QLA2XXX_TARGET */
 
 #endif /* __QLA2X_TGT_H */
index d3fdfea..2eb5d3f 100644 (file)
  * Must be changed on any change in any initiator visible interfaces or
  * data in the target add-on
  */
-#define QLA2X_TARGET_MAGIC     264
+#define QLA2X_TARGET_MAGIC     265
 
 /*
  * Must be changed on any change in any target visible interfaces or
  * data in the initiator
  */
-#define QLA2X_INITIATOR_MAGIC   57217
+#define QLA2X_INITIATOR_MAGIC   57218
 
 #define QLA2X00_COMMAND_COUNT_INIT     250
 #define QLA2X00_IMMED_NOTIFY_COUNT_INIT 250
@@ -689,8 +689,10 @@ typedef struct {
 \********************************************************************/
 
 typedef enum {
-       DISABLE_TARGET_MODE = 0,
-       ENABLE_TARGET_MODE = 1
+       ADD_TARGET = 0,
+       REMOVE_TARGET,
+       DISABLE_TARGET_MODE,
+       ENABLE_TARGET_MODE,
 } qla2x_tgt_host_action_t;
 
 /* Changing it don't forget to change QLA2X_TARGET_MAGIC! */
index 06441e6..d649c15 100644 (file)
@@ -96,6 +96,10 @@ static DEVICE_ATTR(class2_enabled,
 
 #ifdef CONFIG_SCSI_QLA2XXX_TARGET
 
+#define CONFIG_SCST_PROC
+
+#ifdef CONFIG_SCST_PROC
+
 static ssize_t
 qla2x00_show_tgt_enabled(struct device *dev,
        struct device_attribute *attr, char *buffer)
@@ -208,6 +212,8 @@ static DEVICE_ATTR(explicit_conform_enabled,
                   qla2x00_show_expl_conf_enabled,
                   qla2x00_store_expl_conf_enabled);
 
+#endif /* CONFIG_SCST_PROC */
+
 static ssize_t
 qla2x00_show_resource_counts(struct device *dev,
        struct device_attribute *attr, char *buffer)
@@ -377,7 +383,7 @@ out_free:
                        gid = (struct gid_list_info *)id_iter;
                        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
                                size += scnprintf(buffer+size, max_size-size,
-                                                " %02x  %02x%02x%02x\n",
+                                                "%02x  %02x%02x%02x\n",
                                                 gid->loop_id_2100,
                                                 gid->domain,
                                                 gid->area,
@@ -1332,8 +1338,10 @@ struct device_attribute *qla2x00_host_attrs[] = {
        &dev_attr_optrom_fw_version,
        &dev_attr_class2_enabled,
 #ifdef CONFIG_SCSI_QLA2XXX_TARGET
+#ifdef CONFIG_SCST_PROC
        &dev_attr_target_mode_enabled,
        &dev_attr_explicit_conform_enabled,
+#endif
        &dev_attr_resource_counts,
        &dev_attr_port_database,
 #endif
index f36eb04..03a5001 100644 (file)
@@ -2447,8 +2447,7 @@ typedef struct scsi_qla_host {
         * accessed from many contexts, including concurrently. Seems, the
         * original author of this code thought that if anything never deleted
         * from this list, it is always safe to travel over it without any
-        * protection. Obviously, this isn't true. (The whole decision to keep
-        * stale entries forever is quite questionable as well.) We will fix
+        * protection. Obviously, this isn't true. We will fix
         * that making access to fcports list using RCU functions. This isn't
         * a complete solution, because it isn't clear if it's safe if some
         * function going over this list misses just added entry, but definitely
@@ -2628,6 +2627,13 @@ typedef struct scsi_qla_host {
 #ifdef CONFIG_SCSI_QLA2XXX_TARGET
        struct mutex    tgt_mutex;
 
+       struct mutex    tgt_host_action_mutex;
+
+       /* Protected by tgt_host_action_mutex */
+       struct q2t_tgt  *q2t_tgt;
+
+       struct list_head ha_list_entry;
+
        int             saved_set;
        uint16_t        saved_exchange_count;
        uint32_t        saved_firmware_options_1;
@@ -2635,7 +2641,7 @@ typedef struct scsi_qla_host {
        uint32_t        saved_firmware_options_3;
        uint8_t         saved_firmware_options[2];
        uint8_t         saved_add_firmware_options[2];
-#endif
+#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
 
        struct scsi_qla_host    *parent;        /* holds pport */
        unsigned long           vp_flags;
index 660d79c..3a33a46 100644 (file)
@@ -8,10 +8,6 @@
 #include "qla_def.h"
 #include "qla2x_tgt.h"
 
-#ifdef CONFIG_SCSI_QLA2XXX_TARGET
-struct qla_tgt_data qla_target;
-#endif
-
 #include <linux/delay.h>
 #include <scsi/scsi_tcq.h>
 
index 849b496..b02f423 100644 (file)
  */
 char qla2x00_version_str[40];
 
+#ifdef CONFIG_SCSI_QLA2XXX_TARGET
+/*
+ * Target mode add-on's callbacks
+ */
+struct qla_tgt_data qla_target;
+
+/*
+ * List of ha's and mutex protecting it.
+ */
+static LIST_HEAD(qla_ha_list);
+static DEFINE_MUTEX(qla_ha_list_mutex);
+#endif
+
 /*
  * SRB allocation cache
  */
@@ -591,6 +604,7 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
 
        return (return_status);
 }
+EXPORT_SYMBOL(qla2x00_wait_for_hba_online);
 
 /*
  * qla2x00_wait_for_loop_ready
@@ -1544,6 +1558,23 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
        return atomic_read(&ha->loop_state) == LOOP_READY;
 }
 
+#ifdef CONFIG_SCSI_QLA2XXX_TARGET
+void
+qla2xxx_add_targets(void)
+{
+       scsi_qla_host_t *ha;
+
+       mutex_lock(&qla_ha_list_mutex);
+       list_for_each_entry(ha, &qla_ha_list, ha_list_entry) {
+               if (qla_target.tgt_host_action != NULL)
+                       qla_target.tgt_host_action(ha, ADD_TARGET);
+       }
+       mutex_unlock(&qla_ha_list_mutex);
+       return;
+}
+EXPORT_SYMBOL(qla2xxx_add_targets);
+#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
+
 /*
  * PCI driver interface
  */
@@ -1608,11 +1639,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->parent = NULL;
        ha->bars = bars;
        ha->mem_only = mem_only;
+
+       spin_lock_init(&ha->hardware_lock);
+
 #ifdef CONFIG_SCSI_QLA2XXX_TARGET
        mutex_init(&ha->tgt_mutex);
+       mutex_init(&ha->tgt_host_action_mutex);
        qla_clear_tgt_mode(ha);
 #endif
-       spin_lock_init(&ha->hardware_lock);
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -1796,6 +1830,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
            ha->isp_ops->fw_version_str(ha, fw_str));
 
+#ifdef CONFIG_SCSI_QLA2XXX_TARGET
+       if (qla_target.tgt_host_action != NULL)
+               qla_target.tgt_host_action(ha, ADD_TARGET);
+
+       /*
+        * Must be after tgt_host_action() to not race with
+        * qla2xxx_add_targets().
+        */
+       mutex_lock(&qla_ha_list_mutex);
+       list_add_tail(&ha->ha_list_entry, &qla_ha_list);
+       mutex_unlock(&qla_ha_list_mutex);
+#endif
+
        return 0;
 
 probe_failed:
@@ -1838,14 +1885,18 @@ qla2x00_remove_one(struct pci_dev *pdev)
        ha = pci_get_drvdata(pdev);
 
 #ifdef CONFIG_SCSI_QLA2XXX_TARGET
-       {
-               unsigned long flags;
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               ha->host_shutting_down = 1;
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       }
-       if (qla_target.tgt_host_action != NULL)
-               qla_target.tgt_host_action(ha, DISABLE_TARGET_MODE);
+       /*
+        * Must be before tgt_host_action() to not race with
+        * qla2xxx_add_targets().
+        */
+       mutex_lock(&qla_ha_list_mutex);
+       list_del(&ha->ha_list_entry);
+       mutex_unlock(&qla_ha_list_mutex);
+
+       ha->host_shutting_down = 1;
+
+       if (qla_target.tgt_host_action != NULL) 
+               qla_target.tgt_host_action(ha, REMOVE_TARGET);
 #endif
 
        /* Necessary to prevent races with it */
diff --git a/scst-full_perf.patch b/scst-full_perf.patch
deleted file mode 100644 (file)
index d5d1904..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-Index: scst/src/Makefile
-===================================================================
---- scst/src/Makefile  (revision 544)
-+++ scst/src/Makefile  (working copy)
-@@ -117,7 +117,7 @@ EXTRA_CFLAGS += -I$(SCST_INC_DIR) -Wextr
- #EXTRA_CFLAGS += -DCONFIG_SCST_STRICT_SERIALIZING
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
- #EXTRA_CFLAGS += -DCONFIG_SCST_USE_EXPECTED_VALUES
- #EXTRA_CFLAGS += -DALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
-@@ -127,7 +127,7 @@ EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECK
- #EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_TM -DCONFIG_SCST_TM_DBG_GO_OFFLINE
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_RETRY
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_OOM
-Index: scst/src/dev_handlers/Makefile
-===================================================================
---- scst/src/dev_handlers/Makefile     (revision 544)
-+++ scst/src/dev_handlers/Makefile     (working copy)
-@@ -70,10 +70,10 @@ endif
- EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter \
-               -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
- #EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- clean:
-       rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers \
diff --git a/scst-release.patch b/scst-release.patch
deleted file mode 100644 (file)
index 6820288..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-Index: scst/src/Makefile
-===================================================================
---- scst/src/Makefile  (revision 544)
-+++ scst/src/Makefile  (working copy)
-@@ -117,7 +117,7 @@ EXTRA_CFLAGS += -I$(SCST_INC_DIR) -Wextr
- #EXTRA_CFLAGS += -DCONFIG_SCST_STRICT_SERIALIZING
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
- #EXTRA_CFLAGS += -DCONFIG_SCST_USE_EXPECTED_VALUES
- #EXTRA_CFLAGS += -DALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
-@@ -125,9 +125,9 @@ EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECK
- #EXTRA_CFLAGS += -fno-inline
--#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
-+EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_TM -DCONFIG_SCST_TM_DBG_GO_OFFLINE
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_RETRY
- #EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG_OOM
-Index: scst/src/dev_handlers/Makefile
-===================================================================
---- scst/src/dev_handlers/Makefile     (revision 544)
-+++ scst/src/dev_handlers/Makefile     (working copy)
-@@ -70,10 +70,10 @@ endif
- EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter \
-               -Wno-missing-field-initializers
--EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
-+#EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
--#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
--EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
-+EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
-+#EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g
- clean:
-       rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers \
index e443058..4e5113d 100644 (file)
 
 SCST_DIR=src
 
-all: 
+all:
        cd $(SCST_DIR) && $(MAKE) $@
 
-install: 
+install:
        cd $(SCST_DIR) && $(MAKE) $@
 
-uninstall: 
+uninstall:
        cd $(SCST_DIR) && $(MAKE) $@
 
-clean: 
+clean:
        cd $(SCST_DIR) && $(MAKE) $@
 
-extraclean: 
+extraclean:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+debug2release:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+release2debug:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+debug2perf:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+perf2debug:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+disable_proc:
+       cd $(SCST_DIR) && $(MAKE) $@
+
+enable_proc:
        cd $(SCST_DIR) && $(MAKE) $@
 
 help:
@@ -48,4 +66,4 @@ help:
        @echo "         - be sure to compile qla against the correct initiator"
        @echo "           driver. Read its README for details."
 
-.PHONY: all install uninstall clean extraclean help
+.PHONY: all install uninstall clean extraclean help debug2release release2debug debug2perf perf2debug disable_proc enable_proc
index 8af0ae0..1bbdfd3 100644 (file)
@@ -63,16 +63,18 @@ them are optional, so, if you don't need the corresponding
 functionality, you may not apply them.
 
 1. scst_exec_req_fifo-2.6.X.patch. This patch is necessary for
-pass-through dev handlers (scst_disk, scst_tape, etc.). Kernels <2.6.30
-need it, because in them scsi_do_req()/scsi_execute_async() work in LIFO
-order, instead of expected and required FIFO. So, SCST needs new
-functions scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in
-the kernel. Kernels >=2.6.30 need it, because in them there is no
-functionality to execute commands with data in scatter-gather buffers.
-This patch adds the necessary functionality to the kernel. You may not
-patch your kernel if you don't need pass-through support. Alternatively,
-on kernels <2.6.30 you can define CONFIG_SCST_STRICT_SERIALIZING compile
-option during the compilation (see description below).
+pass-through dev handlers, because in the mainstream kernels
+scsi_do_req()/scsi_execute_async() work in LIFO order, instead of
+expected and required FIFO. So SCST needs new functions
+scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in the
+kernel. This patch does that. You may not patch the kernel if you don't
+need the pass-through support. Alternatively, you can define
+CONFIG_SCST_STRICT_SERIALIZING compile option during the compilation
+(see description below). Unfortunately, the CONFIG_SCST_STRICT_SERIALIZING
+trick doesn't work on kernels starting from 2.6.30, because those
+kernels don't have the required functionality (scsi_execute_async())
+anymore. So, on them to have pass-through working you have to apply
+scst_exec_req_fifo-2.6.X.patch.
 
 2. io_context-2.6.X.patch. This patch exports some IO context management
 functions from the kernel. For performance reasons SCST queues commands
@@ -257,13 +259,13 @@ in/out in Makefile:
    support supplying expected values.
 
  - CONFIG_SCST_DEBUG_TM - if defined, turns on task management functions
-   debugging, when 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
-   define CONFIG_SCST_TM_DBG_GO_OFFLINE symbol in the Makefile if you
-   want that the device eventually become completely unresponsive, or
-   otherwise to circle around ABORTs and RESETs code. Needs CONFIG_SCST_DEBUG
-   turned on.
+   debugging, when on LUN 6 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 define
+   CONFIG_SCST_TM_DBG_GO_OFFLINE symbol in the Makefile if you want that
+   the device eventually become completely unresponsive, or otherwise to
+   circle around ABORTs and RESETs code. Needs CONFIG_SCST_DEBUG turned
+   on.
 
  - CONFIG_SCST_STRICT_SERIALIZING - if defined, makes SCST send all commands to
    underlying SCSI device synchronously, one after one. This makes task
@@ -275,8 +277,9 @@ in/out in Makefile:
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
    need as much error recovery reliability as possible. As a side effect
-   of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
-   for pass-through device handlers (scst_disk, etc.).
+   of CONFIG_SCST_STRICT_SERIALIZING, on kernels below 2.6.30 no kernel
+   patching is necessary for pass-through device handlers (scst_disk,
+   etc.).
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
@@ -1121,4 +1124,8 @@ Thanks to:
    for UNH-iSCSI project (http://www.iol.unh.edu/consortiums/iscsi/index.html)
    on which interface between SCST core and target drivers was based.
 
+ * Daniel Debonzi <debonzi@linux.vnet.ibm.com> for a big part of SCST sysfs tree
+   implementation
+
 Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net
index 00fae17..318d48f 100644 (file)
@@ -180,13 +180,13 @@ your favorite kernel configuration Makefile target, e.g. "make xconfig":
    support supplying expected values.
 
  - CONFIG_SCST_DEBUG_TM - if defined, turns on task management functions
-   debugging, when 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
-   define CONFIG_SCST_TM_DBG_GO_OFFLINE symbol in the Makefile if you
-   want that the device eventually become completely unresponsive, or
-   otherwise to circle around ABORTs and RESETs code. Needs CONFIG_SCST_DEBUG
-   turned on.
+   debugging, when on LUN 6 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 define
+   CONFIG_SCST_TM_DBG_GO_OFFLINE symbol in the Makefile if you want that
+   the device eventually become completely unresponsive, or otherwise to
+   circle around ABORTs and RESETs code. Needs CONFIG_SCST_DEBUG turned
+   on.
 
  - CONFIG_SCST_STRICT_SERIALIZING - if defined, makes SCST send all commands to
    underlying SCSI device synchronously, one after one. This makes task
@@ -198,8 +198,9 @@ your favorite kernel configuration Makefile target, e.g. "make xconfig":
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
    need as much error recovery reliability as possible. As a side effect
-   of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
-   for pass-through device handlers (scst_disk, etc.).
+   of CONFIG_SCST_STRICT_SERIALIZING, on kernels below 2.6.30 no kernel
+   patching is necessary for pass-through device handlers (scst_disk,
+   etc.).
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
@@ -1030,4 +1031,8 @@ Thanks to:
 
  * Bart Van Assche <bart.vanassche@gmail.com> for a lot of help
 
+ * Daniel Debonzi <debonzi@linux.vnet.ibm.com> for a big part of SCST sysfs tree
+   implementation
+
+
 Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net
index 7027c38..2514515 100644 (file)
 #include <linux/version.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
-#include <linux/proc_fs.h>
 #include <linux/wait.h>
 
+#define CONFIG_SCST_PROC
+
+#ifdef CONFIG_SCST_PROC
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif
+
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_eh.h>
@@ -52,8 +58,13 @@ typedef _Bool bool;
  * and FIO_REV in usr/fileio/common.h as well.
  */
 #define SCST_VERSION(a, b, c, d)    (((a) << 24) + ((b) << 16) + ((c) << 8) + d)
-#define SCST_VERSION_CODE          SCST_VERSION(1, 0, 2, 0)
-#define SCST_VERSION_STRING        "1.0.2"
+#define SCST_VERSION_CODE          SCST_VERSION(2, 0, 0, 0)
+#ifdef CONFIG_SCST_PROC
+#define SCST_VERSION_STRING_SUFFIX  "-procfs"
+#else
+#define SCST_VERSION_STRING_SUFFIX
+#endif
+#define SCST_VERSION_STRING        "2.0.0-pre1" SCST_VERSION_STRING_SUFFIX
 #define SCST_INTERFACE_VERSION     \
                SCST_VERSION_STRING "$Revision$" SCST_CONST_VERSION
 
@@ -455,11 +466,15 @@ enum scst_exec_context {
 
 #define SCST_TGT_DEV_CLUST_POOL                        11
 
+#ifdef CONFIG_SCST_PROC
+
 /*************************************************************
  ** Name of the entry in /proc
  *************************************************************/
 #define SCST_PROC_ENTRY_NAME         "scsi_tgt"
 
+#endif
+
 /*************************************************************
  ** Activities suspending timeout
  *************************************************************/
@@ -580,8 +595,10 @@ struct scst_tgt_template {
        unsigned xmit_response_atomic:1;
        unsigned rdy_to_xfer_atomic:1;
 
+#ifdef CONFIG_SCST_PROC
        /* True, if the template doesn't need the entry in /proc */
        unsigned no_proc_entry:1;
+#endif
 
        /*
         * The maximum time in seconds cmd can stay inside the target
@@ -784,6 +801,7 @@ struct scst_tgt_template {
         */
        int (*report_aen) (struct scst_aen *aen);
 
+#ifdef CONFIG_SCST_PROC
        /*
         * Those functions can be used to export the driver's statistics and
         * other infos to the world outside the kernel as well as to get some
@@ -794,6 +812,26 @@ struct scst_tgt_template {
        int (*read_proc) (struct seq_file *seq, struct scst_tgt *tgt);
        int (*write_proc) (char *buffer, char **start, off_t offset,
                int length, int *eof, struct scst_tgt *tgt);
+#endif
+
+       /*
+        * This function allows to enable or disable particular target.
+        * A disabled target doesn't receive and process any SCSI commands.
+        *
+        * SHOULD HAVE to avoid race when there are connected initiators,
+        * while target not yet completed the initial configuration. In this
+        * case the too early connected initiators would see not those devices,
+        * which they intended to see.
+        */
+       ssize_t (*enable_tgt) (struct scst_tgt *tgt, const char *buffer,
+                          size_t size);
+
+       /*
+        * This function shows if particular target is enabled or not.
+        *
+        * SHOULD HAVE, see above why.
+        */
+       bool (*is_tgt_enabled) (struct scst_tgt *tgt);
 
        /*
         * Name of the template. Must be unique to identify
@@ -809,7 +847,25 @@ struct scst_tgt_template {
         */
        int threads_num;
 
-       /* Private, must be inited to 0 by memset() */
+       /* Optional default log flags */
+       const unsigned long default_trace_flags;
+
+       /* Optional pointer to trace flags */
+       unsigned long *trace_flags;
+
+       /* Optional local trace table */
+       struct scst_trace_log *trace_tbl;
+
+       /* Optional local trace table help string */
+       const char *trace_tbl_help;
+
+       /* Optional sysfs attributes */
+       const struct attribute **tgtt_attrs;
+
+       /* Optional sysfs target attributes */
+       const struct attribute **tgt_attrs;
+
+       /** Private, must be inited to 0 by memset() **/
 
        /* List of targets per template, protected by scst_mutex */
        struct list_head tgt_list;
@@ -817,11 +873,22 @@ struct scst_tgt_template {
        /* List entry of global templates list */
        struct list_head scst_template_list_entry;
 
+#ifdef CONFIG_SCST_PROC
        /* The pointer to the /proc directory entry */
        struct proc_dir_entry *proc_tgt_root;
+#endif
+
+       /* Set if tgtt_kobj was initialized */
+       unsigned int tgtt_kobj_initialized:1;
+
+       struct kobject tgtt_kobj; /* kobject for this struct */
+
+       struct completion tgtt_kobj_release_cmpl;
 
+#ifdef CONFIG_SCST_PROC
        /* Device number in /proc */
        int proc_dev_num;
+#endif
 };
 
 struct scst_dev_type {
@@ -836,8 +903,10 @@ struct scst_dev_type {
        unsigned exec_atomic:1;
        unsigned dev_done_atomic:1;
 
+#ifdef CONFIG_SCST_PROC
        /* Set, if no /proc files should be automatically created by SCST */
        unsigned no_proc:1;
+#endif
 
        /*
         * Should be set, if exec() is synchronous. This is a hint to SCST core
@@ -948,6 +1017,7 @@ struct scst_dev_type {
        /* Called when tgt_dev (session) is detaching from the dev handler */
        void (*detach_tgt) (struct scst_tgt_dev *tgt_dev);
 
+#ifdef CONFIG_SCST_PROC
        /*
         * Those functions can be used to export the handler's statistics and
         * other infos to the world outside the kernel as well as to get some
@@ -958,6 +1028,7 @@ struct scst_dev_type {
        int (*read_proc) (struct seq_file *seq, struct scst_dev_type *dev_type);
        int (*write_proc) (char *buffer, char **start, off_t offset,
                int length, int *eof, struct scst_dev_type *dev_type);
+#endif
 
        /*
         * Name of the dev handler. Must be unique. MUST HAVE.
@@ -972,15 +1043,48 @@ struct scst_dev_type {
         */
        int threads_num;
 
+       /* Optional default log flags */
+       const unsigned long default_trace_flags;
+
+       /* Optional pointer to trace flags */
+       unsigned long *trace_flags;
+
+       /* Optional local trace table */
+       struct scst_trace_log *trace_tbl;
+
+       /* Optional local trace table help string */
+       const char *trace_tbl_help;
+
+       /* Optional sysfs attributes */
+       const struct attribute **devt_attrs;
+
+       /* Optional sysfs device attributes */
+       const struct attribute **dev_attrs;
+
+       /* Pointer to dev handler's private data */
+       void *devt_priv;
+
+       /* Pointer to parent dev type in the sysfs hierarchy */
+       struct scst_dev_type *parent;
+
        struct module *module;
 
-       /* private: */
+       /** Private, must be inited to 0 by memset() **/
 
        /* list entry in scst_dev_type_list */
        struct list_head dev_type_list_entry;
 
+#ifdef CONFIG_SCST_PROC
        /* The pointer to the /proc directory entry */
        struct proc_dir_entry *proc_dev_type_root;
+#endif
+
+       unsigned int devt_kobj_initialized:1;
+
+       struct kobject devt_kobj; /* main handlers/driver */
+
+       /* To wait until devt_kobj released */
+       struct completion devt_kobj_release_compl;
 };
 
 struct scst_tgt {
@@ -992,6 +1096,8 @@ struct scst_tgt {
 
        struct scst_tgt_template *tgtt; /* corresponding target template */
 
+       struct scst_acg *default_acg; /* The default acg for this target. */
+
        /*
         * Maximum SG table size. Needed here, since different cards on the
         * same target template can have different SG table limitations.
@@ -1017,11 +1123,26 @@ struct scst_tgt {
        /* Used to wait until session finished to unregister */
        wait_queue_head_t unreg_waitQ;
 
+#ifdef CONFIG_SCST_PROC
        /* Device number in /proc */
        int proc_num;
+#endif
+
+       /* Name of the target */
+       char *tgt_name;
 
+#ifdef CONFIG_SCST_PROC
        /* Name on the default security group ("Default_target_name") */
        char *default_group_name;
+#endif
+
+       /* Set if tgt_kobj was initialized */
+       unsigned int tgt_kobj_initialized:1;
+
+       struct kobject tgt_kobj; /* main targets/target kobject */
+       struct kobject *tgt_sess_kobj; /* target/sessions/ */
+       struct kobject *tgt_luns_kobj; /* target/luns/ */
+       struct kobject *tgt_ini_grp_kobj; /* target/ini_groups/ */
 };
 
 /* Hash size and hash fn for hash based lun translation */
@@ -1144,6 +1265,11 @@ struct scst_session {
        /* Used if scst_unregister_session() called in wait mode */
        struct completion *shutdown_compl;
 
+       /* Set if sess_kobj was initialized */
+       unsigned int sess_kobj_initialized:1;
+
+       struct kobject sess_kobj; /* kobject for this struct */
+
        /*
         * Functions and data for user callbacks from scst_register_session()
         * and scst_unregister_session()
@@ -1636,7 +1762,7 @@ struct scst_device {
        int virt_id;
 
        /* Pointer to virtual device name, for convenience only */
-       const char *virt_name;
+       char *virt_name;
 
        /* List entry in global devices list */
        struct list_head dev_list_entry;
@@ -1655,6 +1781,15 @@ struct scst_device {
 
        /* Device number */
        int dev_num;
+
+       /* Set if tgt_kobj was initialized */
+       unsigned int dev_kobj_initialized:1;
+
+       struct kobject dev_kobj; /* kobject for this struct */
+       struct kobject *dev_exp_kobj; /* exported groups */
+
+       /* Export number in the dev's sysfs list. Protected by scst_mutex */
+       int dev_exported_lun_num;
 };
 
 /*
@@ -1766,15 +1901,25 @@ struct scst_tgt_dev {
  */
 struct scst_acg_dev {
        struct scst_device *dev; /* corresponding device */
-       uint64_t lun;           /* device's LUN in this acg */
-       unsigned int rd_only:1; /* if != 0, then read only */
-       struct scst_acg *acg;   /* parent acg */
 
-       /* list entry in dev->dev_acg_dev_list */
+       uint64_t lun; /* device's LUN in this acg */
+
+       /* If set, the corresponding LU is read only */
+       unsigned int rd_only:1;
+
+       /* Set if acg_dev_kobj was initialized */
+       unsigned int acg_dev_kobj_initialized:1;
+
+       struct scst_acg *acg; /* parent acg */
+
+       /* List entry in dev->dev_acg_dev_list */
        struct list_head dev_acg_dev_list_entry;
 
-       /* list entry in acg->acg_dev_list */
+       /* List entry in acg->acg_dev_list */
        struct list_head acg_dev_list_entry;
+
+       /* kobject for this structure */
+       struct kobject acg_dev_kobj;
 };
 
 /*
@@ -1797,8 +1942,10 @@ struct scst_acg {
        /* Name of this acg */
        const char *acg_name;
 
+#ifdef CONFIG_SCST_PROC
        /* The pointer to the /proc directory entry */
        struct proc_dir_entry *acg_proc_root;
+#endif
 };
 
 /*
@@ -1895,8 +2042,7 @@ void scst_unregister(struct scst_tgt *tgt);
  *     this function will block until the session registration is completed.
  *   initiator_name - remote initiator's name, any NULL-terminated string,
  *      e.g. iSCSI name, which used as the key to found appropriate access
- *      control group. Could be NULL, then "default" group is used.
- *      The groups are set up via /proc interface.
+ *      control group. Could be NULL, then the default target's LUNs are used.
  *   data - any target driver supplied data
  *   result_fn - pointer to the function that will be
  *      asynchronously called when session initialization finishes.
@@ -2852,7 +2998,7 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg)
        return sg;
 }
 
-#endif
+#endif /* __BACKPORT_LINUX_SCATTERLIST_H_TO_2_6_23__ */
 
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */
 
@@ -3012,49 +3158,44 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd);
  */
 void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd);
 
+struct scst_trace_log {
+       unsigned int val;
+       const char *token;
+};
+
+#ifdef CONFIG_SCST_PROC
+
 /*
  * Returns target driver's root entry in SCST's /proc hierarchy.
  * The driver can create own files/directories here, which should
  * be deleted in the driver's release().
  */
-static inline struct proc_dir_entry *scst_proc_get_tgt_root(
-       struct scst_tgt_template *vtt)
-{
-       return vtt->proc_tgt_root;
-}
+struct proc_dir_entry *scst_proc_get_tgt_root(
+       struct scst_tgt_template *vtt);
 
 /*
  * Returns device handler's root entry in SCST's /proc hierarchy.
  * The driver can create own files/directories here, which should
  * be deleted in the driver's detach()/release().
  */
-static inline struct proc_dir_entry *scst_proc_get_dev_type_root(
-       struct scst_dev_type *dtt)
-{
-       return dtt->proc_dev_type_root;
-}
+struct proc_dir_entry *scst_proc_get_dev_type_root(
+       struct scst_dev_type *dtt);
 
 /**
  ** Two library functions and the structure to help the drivers
  ** that use scst_debug.* facilities manage "trace_level" /proc entry.
  ** The functions service "standard" log levels and allow to work
  ** with driver specific levels, which should be passed inside as
- ** NULL-terminated array of struct scst_proc_log's, where:
+ ** NULL-terminated array of struct scst_trace_log's, where:
  **   - val - the level's numeric value
  **   - token - its string representation
  **/
 
-struct scst_proc_log {
-       unsigned int val;
-       const char *token;
-};
-
 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
-       const struct scst_proc_log *tbl);
-
+       const struct scst_trace_log *tbl);
 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
        unsigned long length, unsigned long *log_level,
-       unsigned long default_level, const struct scst_proc_log *tbl);
+       unsigned long default_level, const struct scst_trace_log *tbl);
 
 /*
  * helper data structure and function to create proc entry.
@@ -3080,6 +3221,56 @@ struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
                .release        = single_release,      \
        },
 
+#else /* CONFIG_SCST_PROC */
+
+/*
+ * Returns target driver's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_tgtt_kobj(
+       struct scst_tgt_template *tgtt)
+{
+       return &tgtt->tgtt_kobj;
+}
+
+/*
+ * Returns target's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_tgt_kobj(
+       struct scst_tgt *tgt)
+{
+       return &tgt->tgt_kobj;
+}
+
+/*
+ * Returns device handler's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_devt_kobj(
+       struct scst_dev_type *devt)
+{
+       return &devt->devt_kobj;
+}
+
+/*
+ * Returns device's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_dev_kobj(
+       struct scst_device *dev)
+{
+       return &dev->dev_kobj;
+}
+
+#endif /* CONFIG_SCST_PROC */
+
+/* Returns target name */
+static inline const char *scst_get_tgt_name(const struct scst_tgt *tgt)
+{
+       return tgt->tgt_name;
+}
+
 /*
  * Adds and deletes (stops) num of global SCST's threads. Returns 0 on
  * success, error code otherwise.
index ab738f2..4cd87f1 100644 (file)
@@ -131,6 +131,11 @@ enum scst_cmd_queue_type {
  *************************************************************/
 #define SCST_DEFAULT_ACG_NAME                  "Default"
 
+/*************************************************************
+ ** Default suffix for targets with NULL names
+ *************************************************************/
+#define SCST_DEFAULT_TGT_NAME_SUFFIX           "_target_"
+
 /*************************************************************
  ** Sense manipulation and examination
  *************************************************************/
@@ -331,4 +336,9 @@ enum scst_cmd_queue_type {
 
 #define SCST_MAX_OTHER_TIMEOUT                 (14000 * HZ)
 
+/*************************************************************
+ ** Misc constants
+ *************************************************************/
+#define SCST_SYSFS_BLOCK_SIZE (PAGE_SIZE - 64)
+
 #endif /* __SCST_CONST_H */
index 42b63e7..3ed9c02 100644 (file)
@@ -33,12 +33,12 @@ ifneq ($(PATCHLEVEL),)
 SCST_INC_DIR := $(SUBDIRS)/../include
 
 obj-m := scst.o
-scst-objs := scst_main.o scst_targ.o scst_lib.o scst_mem.o scst_proc.o
 
 scst-y        += scst_main.o
 scst-y        += scst_targ.o
 scst-y        += scst_lib.o
 scst-y        += scst_proc.o
+#scst-y        += scst_sysfs.o
 scst-y        += scst_mem.o
 scst-y        += scst_debug.o
 obj-$(CONFIG_SCST)   += scst.o dev_handlers/
@@ -149,4 +149,60 @@ clean:
 
 extraclean: clean
 
-.PHONY: all install uninstall clean extraclean
+debug2release:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+       cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
+
+release2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+       cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
+
+debug2perf:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+       cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
+
+perf2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+       cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
+
+disable_proc:
+       sed -c -i.aa s/"^#define CONFIG_SCST_PROC"/"\/* #define CONFIG_SCST_PROC *\/"/ ../include/scst.h
+       @cmp ../include/scst.h ../include/scst.h.aa >/dev/null; if [[ $$? = 0 ]]; then rm ../include/scst.h.aa; echo "sed failed"; false; fi
+       rm ../include/scst.h.aa
+       sed -c -i.aa s/"^scst-y        += scst_proc.o"/"#scst\-y        += scst_proc.o"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#scst\-y        += scst_sysfs.o"/"scst\-y        += scst_sysfs.o"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+enable_proc:
+       sed -c -i.aa s/"\/\* #define CONFIG_SCST_PROC \*\/"/"#define CONFIG_SCST_PROC"/ ../include/scst.h
+       @cmp ../include/scst.h ../include/scst.h.aa >/dev/null; if [[ $$? = 0 ]]; then rm ../include/scst.h.aa; echo "sed failed"; false; fi
+       rm ../include/scst.h.aa
+       sed -c -i.aa s/"#scst\-y        += scst_proc.o"/"scst\-y        += scst_proc.o"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^scst\-y        += scst_sysfs.o"/"#scst\-y        += scst_sysfs.o"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+.PHONY: all install uninstall clean extraclean debug2release release2debug debug2perf perf2debug disable_proc enable_proc
index fd87ff8..f7f76db 100644 (file)
@@ -82,4 +82,36 @@ clean:
 
 extraclean: clean
 
-.PHONY: all install uninstall clean extraclean
+debug2release:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+release2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+debug2perf:
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+perf2debug:
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       sed -c -i.aa s/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g"/ Makefile
+       @cmp Makefile Makefile.aa >/dev/null; if [[ $$? = 0 ]]; then rm Makefile.aa; echo "sed failed"; false; fi
+       rm Makefile.aa
+
+.PHONY: all install uninstall clean extraclean debug2release release2debug debug2perf perf2debug
index cef3f9f..80f95ea 100644 (file)
 
 #define CDROM_NAME     "dev_cdrom"
 
-#define CDROM_TYPE {                           \
-       .name =                 CDROM_NAME,     \
-       .type =                 TYPE_ROM,       \
-       .parse_atomic =         1,              \
-       .dev_done_atomic =      1,              \
-       .attach =               cdrom_attach,   \
-       .detach =               cdrom_detach,   \
-       .parse =                cdrom_parse,    \
-       .dev_done =             cdrom_done,     \
-}
-
 #define CDROM_DEF_BLOCK_SHIFT  11
 
 struct cdrom_params {
@@ -50,7 +39,20 @@ static void cdrom_detach(struct scst_device *);
 static int cdrom_parse(struct scst_cmd *);
 static int cdrom_done(struct scst_cmd *);
 
-static struct scst_dev_type cdrom_devtype = CDROM_TYPE;
+static struct scst_dev_type cdrom_devtype = {
+       .name =                 CDROM_NAME,
+       .type =                 TYPE_ROM,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .attach =               cdrom_attach,
+       .detach =               cdrom_detach,
+       .parse =                cdrom_parse,
+       .dev_done =             cdrom_done,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 /**************************************************************
  *  Function:  cdrom_attach
@@ -150,9 +152,7 @@ static int cdrom_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out_free_buf;
        }
 
@@ -274,23 +274,29 @@ static int __init cdrom_init(void)
        if (res < 0)
                goto out;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_dev_handler_build_std_proc(&cdrom_devtype);
        if (res != 0)
                goto out_err;
+#endif
 
 out:
        TRACE_EXIT();
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_err:
        scst_unregister_dev_driver(&cdrom_devtype);
        goto out;
+#endif
 }
 
 static void __exit cdrom_exit(void)
 {
        TRACE_ENTRY();
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&cdrom_devtype);
+#endif
        scst_unregister_dev_driver(&cdrom_devtype);
        TRACE_EXIT();
        return;
index 5c5fdf8..3d0b072 100644 (file)
 
 #define CHANGER_NAME   "dev_changer"
 
-#define CHANGER_TYPE {                         \
-       .name = CHANGER_NAME,                   \
-       .type = TYPE_MEDIUM_CHANGER,            \
-       .parse_atomic = 1,                      \
-/*     .dev_done_atomic =      1, */           \
-       .attach =       changer_attach,         \
-/*     .detach =       changer_detach, */      \
-       .parse =        changer_parse,          \
-/*     .dev_done =     changer_done */         \
-}
-
 #define CHANGER_RETRIES       2
 #define READ_CAP_LEN          8
 
@@ -46,7 +35,20 @@ static int changer_attach(struct scst_device *);
 static int changer_parse(struct scst_cmd *);
 /* static int changer_done(struct scst_cmd *); */
 
-static struct scst_dev_type changer_devtype = CHANGER_TYPE;
+static struct scst_dev_type changer_devtype = {
+       .name = CHANGER_NAME,
+       .type = TYPE_MEDIUM_CHANGER,
+       .parse_atomic = 1,
+/*     .dev_done_atomic =      1, */
+       .attach =       changer_attach,
+/*     .detach =       changer_detach, */
+       .parse =        changer_parse,
+/*     .dev_done =     changer_done */
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 /**************************************************************
  *  Function:  changer_attach
@@ -101,9 +103,7 @@ static int changer_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out;
        }
 
@@ -202,23 +202,28 @@ static int __init changer_init(void)
        if (res < 0)
                goto out;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_dev_handler_build_std_proc(&changer_devtype);
        if (res != 0)
                goto out_err;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
-
+#ifdef CONFIG_SCST_PROC
 out_err:
        scst_unregister_dev_driver(&changer_devtype);
        goto out;
+#endif
 }
 
 static void __exit changer_exit(void)
 {
        TRACE_ENTRY();
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&changer_devtype);
+#endif
        scst_unregister_dev_driver(&changer_devtype);
        TRACE_EXIT();
        return;
index d13608d..58fce86 100644 (file)
@@ -2,8 +2,6 @@
 #define __SCST_DEV_HANDLER_H
 
 #include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <scsi/scsi_eh.h>
 #include "scst_debug.h"
 
@@ -12,8 +10,6 @@
 
 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
 
-#define DEV_HANDLER_LOG_ENTRY_NAME "trace_level"
-
 #ifdef CONFIG_SCST_DEBUG
 #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
        TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MGMT_MINOR | \
 static unsigned long dh_trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
 #define trace_flag dh_trace_flag
 
+#ifdef CONFIG_SCST_PROC
+
+#define DEV_HANDLER_LOG_ENTRY_NAME "trace_level"
+
 #ifndef trace_log_tbl
 #define trace_log_tbl  NULL
 #endif
@@ -57,8 +57,13 @@ static ssize_t scst_dev_handler_proc_log_entry_write(struct file *file,
        TRACE_EXIT_RES(res);
        return res;
 }
+
+#endif /* CONFIG_SCST_PROC */
+
 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
 
+#ifdef CONFIG_SCST_PROC
+
 static int scst_dev_handler_build_std_proc(struct scst_dev_type *dev_type)
 {
        int res = 0;
@@ -69,14 +74,20 @@ static int scst_dev_handler_build_std_proc(struct scst_dev_type *dev_type)
 
        root = scst_proc_get_dev_type_root(dev_type);
        if (root) {
-               /* create the proc file entry for the device */
-               dev_handler_log_proc_data.data = (void *)dev_type->name;
+               /* Create the proc file entry for the device */
+               /* Workaround to keep /proc ABI intact */
+               const char *name;
+               if (strcmp(dev_type->name, "vdisk_fileio") == 0)
+                       name = "vdisk";
+               else
+                       name = dev_type->name;
+               dev_handler_log_proc_data.data = (void *)name;
                p = scst_create_proc_entry(root, DEV_HANDLER_LOG_ENTRY_NAME,
                                           &dev_handler_log_proc_data);
                if (p == NULL) {
                        PRINT_ERROR("Not enough memory to register dev "
                             "handler %s entry %s in /proc",
-                             dev_type->name, DEV_HANDLER_LOG_ENTRY_NAME);
+                            name, DEV_HANDLER_LOG_ENTRY_NAME);
                        res = -ENOMEM;
                        goto out;
                }
@@ -110,4 +121,6 @@ static struct scst_proc_data dev_handler_log_proc_data = {
 };
 #endif
 
+#endif /* CONFIG_SCST_PROC */
+
 #endif /* __SCST_DEV_HANDLER_H */
index ce5ea2c..ad30507 100644 (file)
 # define DISK_NAME           "dev_disk"
 # define DISK_PERF_NAME      "dev_disk_perf"
 
-#define DISK_TYPE {                                    \
-       .name =                 DISK_NAME,              \
-       .type =                 TYPE_DISK,              \
-       .parse_atomic =         1,                      \
-       .dev_done_atomic =      1,                      \
-       .exec_atomic =          1,                      \
-       .attach =               disk_attach,            \
-       .detach =               disk_detach,            \
-       .parse =                disk_parse,             \
-       .dev_done =             disk_done,              \
-}
-
-#define DISK_PERF_TYPE {                               \
-       .name =                 DISK_PERF_NAME,         \
-       .type =                 TYPE_DISK,              \
-       .parse_atomic =         1,                      \
-       .dev_done_atomic =      1,                      \
-       .exec_atomic =          1,                      \
-       .attach =               disk_attach,            \
-       .detach =               disk_detach,            \
-       .parse =                disk_parse,             \
-       .dev_done =             disk_done,              \
-       .exec =                 disk_exec,              \
-}
-
 #define DISK_DEF_BLOCK_SHIFT   9
 
 struct disk_params {
@@ -70,8 +45,38 @@ static int disk_parse(struct scst_cmd *cmd);
 static int disk_done(struct scst_cmd *cmd);
 static int disk_exec(struct scst_cmd *cmd);
 
-static struct scst_dev_type disk_devtype = DISK_TYPE;
-static struct scst_dev_type disk_devtype_perf = DISK_PERF_TYPE;
+static struct scst_dev_type disk_devtype = {
+       .name =                 DISK_NAME,
+       .type =                 TYPE_DISK,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               disk_attach,
+       .detach =               disk_detach,
+       .parse =                disk_parse,
+       .dev_done =             disk_done,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags = &trace_flag,
+#endif
+};
+
+static struct scst_dev_type disk_devtype_perf = {
+       .name =                 DISK_PERF_NAME,
+       .type =                 TYPE_DISK,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               disk_attach,
+       .detach =               disk_detach,
+       .parse =                disk_parse,
+       .dev_done =             disk_done,
+       .exec =                 disk_exec,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 static int __init init_scst_disk_driver(void)
 {
@@ -85,31 +90,35 @@ static int __init init_scst_disk_driver(void)
        if (res < 0)
                goto out;
 
-       res = scst_dev_handler_build_std_proc(&disk_devtype);
-       if (res != 0)
-               goto out_unreg1;
-
        disk_devtype_perf.module = THIS_MODULE;
 
        res = scst_register_dev_driver(&disk_devtype_perf);
        if (res < 0)
-               goto out_unreg1_err1;
+               goto out_unreg;
+
+#ifdef CONFIG_SCST_PROC
+       res = scst_dev_handler_build_std_proc(&disk_devtype);
+       if (res != 0)
+               goto out_unreg1;
 
        res = scst_dev_handler_build_std_proc(&disk_devtype_perf);
        if (res != 0)
                goto out_unreg2;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_unreg2:
-       scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
-
-out_unreg1_err1:
        scst_dev_handler_destroy_std_proc(&disk_devtype);
 
 out_unreg1:
+       scst_unregister_dev_driver(&disk_devtype_perf);
+#endif
+
+out_unreg:
        scst_unregister_dev_driver(&disk_devtype);
        goto out;
 }
@@ -117,10 +126,14 @@ out_unreg1:
 static void __exit exit_scst_disk_driver(void)
 {
        TRACE_ENTRY();
+
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
-       scst_unregister_dev_driver(&disk_devtype_perf);
        scst_dev_handler_destroy_std_proc(&disk_devtype);
+#endif
+       scst_unregister_dev_driver(&disk_devtype_perf);
        scst_unregister_dev_driver(&disk_devtype);
+
        TRACE_EXIT();
        return;
 }
@@ -226,9 +239,7 @@ static int disk_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out_free_buf;
        }
 
index 222dba6..5512635 100644 (file)
 # define MODISK_NAME           "dev_modisk"
 # define MODISK_PERF_NAME      "dev_modisk_perf"
 
-#define MODISK_TYPE {                          \
-       .name =                 MODISK_NAME,    \
-       .type =                 TYPE_MOD,       \
-       .parse_atomic =         1,              \
-       .dev_done_atomic =      1,              \
-       .exec_atomic =          1,              \
-       .attach =               modisk_attach,  \
-       .detach =               modisk_detach,  \
-       .parse =                modisk_parse,   \
-       .dev_done =             modisk_done,    \
-}
-
-#define MODISK_PERF_TYPE {                             \
-       .name =                 MODISK_PERF_NAME,       \
-       .type =                 TYPE_MOD,               \
-       .parse_atomic =         1,                      \
-       .dev_done_atomic =      1,                      \
-       .exec_atomic =          1,                      \
-       .attach =               modisk_attach,          \
-       .detach =               modisk_detach,          \
-       .parse =                modisk_parse,           \
-       .dev_done =             modisk_done,            \
-       .exec =                 modisk_exec,            \
-}
-
 #define MODISK_DEF_BLOCK_SHIFT    10
 
 struct modisk_params {
@@ -70,8 +45,38 @@ static int modisk_parse(struct scst_cmd *);
 static int modisk_done(struct scst_cmd *);
 static int modisk_exec(struct scst_cmd *);
 
-static struct scst_dev_type modisk_devtype = MODISK_TYPE;
-static struct scst_dev_type modisk_devtype_perf = MODISK_PERF_TYPE;
+static struct scst_dev_type modisk_devtype = {
+       .name =                 MODISK_NAME,
+       .type =                 TYPE_MOD,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               modisk_attach,
+       .detach =               modisk_detach,
+       .parse =                modisk_parse,
+       .dev_done =             modisk_done,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
+
+static struct scst_dev_type modisk_devtype_perf = {
+       .name =                 MODISK_PERF_NAME,
+       .type =                 TYPE_MOD,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               modisk_attach,
+       .detach =               modisk_detach,
+       .parse =                modisk_parse,
+       .dev_done =             modisk_done,
+       .exec =                 modisk_exec,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 static int __init init_scst_modisk_driver(void)
 {
@@ -85,31 +90,35 @@ static int __init init_scst_modisk_driver(void)
        if (res < 0)
                goto out;
 
-       res = scst_dev_handler_build_std_proc(&modisk_devtype);
-       if (res != 0)
-               goto out_unreg1;
-
        modisk_devtype_perf.module = THIS_MODULE;
 
        res = scst_register_dev_driver(&modisk_devtype_perf);
        if (res < 0)
-               goto out_unreg1_err1;
+               goto out_unreg;
+
+#ifdef CONFIG_SCST_PROC
+       res = scst_dev_handler_build_std_proc(&modisk_devtype);
+       if (res != 0)
+               goto out_unreg1;
 
        res = scst_dev_handler_build_std_proc(&modisk_devtype_perf);
        if (res != 0)
                goto out_unreg2;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_unreg2:
-       scst_dev_handler_destroy_std_proc(&modisk_devtype_perf);
-
-out_unreg1_err1:
        scst_dev_handler_destroy_std_proc(&modisk_devtype);
 
 out_unreg1:
+       scst_unregister_dev_driver(&modisk_devtype_perf);
+#endif
+
+out_unreg:
        scst_unregister_dev_driver(&modisk_devtype);
        goto out;
 }
@@ -117,10 +126,14 @@ out_unreg1:
 static void __exit exit_scst_modisk_driver(void)
 {
        TRACE_ENTRY();
+
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&modisk_devtype_perf);
-       scst_unregister_dev_driver(&modisk_devtype_perf);
        scst_dev_handler_destroy_std_proc(&modisk_devtype);
+#endif
+       scst_unregister_dev_driver(&modisk_devtype_perf);
        scst_unregister_dev_driver(&modisk_devtype);
+
        TRACE_EXIT();
        return;
 }
@@ -242,9 +255,7 @@ static int modisk_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d: %x", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun, res);
+                       "%s: %x", dev->virt_name, res);
                goto out_free_buf;
        }
 
index 2caf640..55d4911 100644 (file)
 
 #define PROCESSOR_NAME "dev_processor"
 
-#define PROCESSOR_TYPE {                               \
-       .name =                 PROCESSOR_NAME,         \
-       .type =                 TYPE_PROCESSOR,         \
-       .parse_atomic =         1,                      \
-/*     .dev_done_atomic =      1,*/                    \
-       .attach =               processor_attach,       \
-/*     .detach =               processor_detach,*/     \
-       .parse =                processor_parse,        \
-/*     .dev_done =             processor_done*/        \
-}
-
-#define PROCESSOR_RETRIES       2
-#define READ_CAP_LEN          8
+#define PROCESSOR_RETRIES      2
+#define READ_CAP_LEN           8
 
 static int processor_attach(struct scst_device *);
 /*static void processor_detach(struct scst_device *);*/
 static int processor_parse(struct scst_cmd *);
 /*static int processor_done(struct scst_cmd *);*/
 
-static struct scst_dev_type processor_devtype = PROCESSOR_TYPE;
+static struct scst_dev_type processor_devtype = {
+       .name =                 PROCESSOR_NAME,
+       .type =                 TYPE_PROCESSOR,
+       .parse_atomic =         1,
+/*     .dev_done_atomic =      1,*/
+       .attach =               processor_attach,
+/*     .detach =               processor_detach,*/
+       .parse =                processor_parse,
+/*     .dev_done =             processor_done*/
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 /**************************************************************
  *  Function:  processor_attach
@@ -101,9 +103,7 @@ static int processor_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out;
        }
 
@@ -202,23 +202,28 @@ static int __init processor_init(void)
        if (res < 0)
                goto out;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_dev_handler_build_std_proc(&processor_devtype);
        if (res != 0)
                goto out_err;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
-
+#ifdef CONFIG_SCST_PROC
 out_err:
        scst_unregister_dev_driver(&processor_devtype);
        goto out;
+#endif
 }
 
 static void __exit processor_exit(void)
 {
        TRACE_ENTRY();
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&processor_devtype);
+#endif
        scst_unregister_dev_driver(&processor_devtype);
        TRACE_EXIT();
        return;
index 37e481c..e08b902 100644 (file)
 
 #define RAID_NAME      "dev_raid"
 
-#define RAID_TYPE {                            \
-       .name =                 RAID_NAME,      \
-       .type =                 TYPE_RAID,      \
-       .parse_atomic =         1,              \
-/*     .dev_done_atomic =      1,*/            \
-       .attach =               raid_attach,    \
-/*     .detach =               raid_detach,*/  \
-       .parse =                raid_parse,     \
-/*     .dev_done =             raid_done*/     \
-}
-
-#define RAID_RETRIES       2
-#define READ_CAP_LEN          8
+#define RAID_RETRIES           2
+#define READ_CAP_LEN           8
 
 static int raid_attach(struct scst_device *);
 /* static void raid_detach(struct scst_device *); */
 static int raid_parse(struct scst_cmd *);
 /* static int raid_done(struct scst_cmd *); */
 
-static struct scst_dev_type raid_devtype = RAID_TYPE;
+static struct scst_dev_type raid_devtype = {
+       .name =                 RAID_NAME,
+       .type =                 TYPE_RAID,
+       .parse_atomic =         1,
+/*     .dev_done_atomic =      1,*/
+       .attach =               raid_attach,
+/*     .detach =               raid_detach,*/
+       .parse =                raid_parse,
+/*     .dev_done =             raid_done,*/
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 /**************************************************************
  *  Function:  raid_attach
@@ -101,9 +103,7 @@ static int raid_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out;
        }
 
@@ -202,23 +202,29 @@ static int __init raid_init(void)
        if (res < 0)
                goto out;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_dev_handler_build_std_proc(&raid_devtype);
        if (res != 0)
                goto out_err;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_err:
        scst_unregister_dev_driver(&raid_devtype);
        goto out;
+#endif
 }
 
 static void __exit raid_exit(void)
 {
        TRACE_ENTRY();
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&raid_devtype);
+#endif
        scst_unregister_dev_driver(&raid_devtype);
        TRACE_EXIT();
        return;
index e2a320e..ffe4c87 100644 (file)
 # define TAPE_NAME           "dev_tape"
 # define TAPE_PERF_NAME      "dev_tape_perf"
 
-#define TAPE_TYPE {                            \
-       .name =                 TAPE_NAME,      \
-       .type =                 TYPE_TAPE,      \
-       .parse_atomic =         1,              \
-       .dev_done_atomic =      1,              \
-       .exec_atomic =          1,              \
-       .attach =               tape_attach,    \
-       .detach =               tape_detach,    \
-       .parse =                tape_parse,     \
-       .dev_done =             tape_done,      \
-}
-
-#define TAPE_PERF_TYPE {                       \
-       .name =                 TAPE_PERF_NAME, \
-       .type =                 TYPE_TAPE,      \
-       .parse_atomic =         1,              \
-       .dev_done_atomic =      1,              \
-       .exec_atomic =          1,              \
-       .attach =               tape_attach,    \
-       .detach =               tape_detach,    \
-       .parse =                tape_parse,     \
-       .dev_done =             tape_done,      \
-       .exec =                 tape_exec,      \
-}
-
-#define TAPE_RETRIES        2
+#define TAPE_RETRIES           2
 
 #define TAPE_DEF_BLOCK_SIZE    512
 
 /* The fixed bit in READ/WRITE/VERIFY */
-#define SILI_BIT            2
+#define SILI_BIT               2
 
 struct tape_params {
        int block_size;
@@ -75,8 +50,38 @@ static int tape_parse(struct scst_cmd *);
 static int tape_done(struct scst_cmd *);
 static int tape_exec(struct scst_cmd *);
 
-static struct scst_dev_type tape_devtype = TAPE_TYPE;
-static struct scst_dev_type tape_devtype_perf = TAPE_PERF_TYPE;
+static struct scst_dev_type tape_devtype = {
+       .name =                 TAPE_NAME,
+       .type =                 TYPE_TAPE,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               tape_attach,
+       .detach =               tape_detach,
+       .parse =                tape_parse,
+       .dev_done =             tape_done,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
+
+static struct scst_dev_type tape_devtype_perf = {
+       .name =                 TAPE_PERF_NAME,
+       .type =                 TYPE_TAPE,
+       .parse_atomic =         1,
+       .dev_done_atomic =      1,
+       .exec_atomic =          1,
+       .attach =               tape_attach,
+       .detach =               tape_detach,
+       .parse =                tape_parse,
+       .dev_done =             tape_done,
+       .exec =                 tape_exec,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+#endif
+};
 
 static int __init init_scst_tape_driver(void)
 {
@@ -90,31 +95,35 @@ static int __init init_scst_tape_driver(void)
        if (res < 0)
                goto out;
 
-       res = scst_dev_handler_build_std_proc(&tape_devtype);
-       if (res != 0)
-               goto out_unreg1;
-
        tape_devtype_perf.module = THIS_MODULE;
 
        res = scst_register_dev_driver(&tape_devtype_perf);
        if (res < 0)
-               goto out_unreg1_err1;
+               goto out_unreg;
+
+#ifdef CONFIG_SCST_PROC
+       res = scst_dev_handler_build_std_proc(&tape_devtype);
+       if (res != 0)
+               goto out_unreg1;
 
        res = scst_dev_handler_build_std_proc(&tape_devtype_perf);
        if (res != 0)
                goto out_unreg2;
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_unreg2:
-       scst_dev_handler_destroy_std_proc(&tape_devtype_perf);
-
-out_unreg1_err1:
        scst_dev_handler_destroy_std_proc(&tape_devtype);
 
 out_unreg1:
+       scst_unregister_dev_driver(&tape_devtype_perf);
+#endif
+
+out_unreg:
        scst_unregister_dev_driver(&tape_devtype);
        goto out;
 }
@@ -122,10 +131,14 @@ out_unreg1:
 static void __exit exit_scst_tape_driver(void)
 {
        TRACE_ENTRY();
+
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&tape_devtype_perf);
-       scst_unregister_dev_driver(&tape_devtype_perf);
        scst_dev_handler_destroy_std_proc(&tape_devtype);
+#endif
+       scst_unregister_dev_driver(&tape_devtype_perf);
        scst_unregister_dev_driver(&tape_devtype);
+
        TRACE_EXIT();
        return;
 }
@@ -226,9 +239,7 @@ static int tape_attach(struct scst_device *dev)
        res = scst_obtain_device_parameters(dev);
        if (res != 0) {
                PRINT_ERROR("Failed to obtain control parameters for device "
-                       "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun);
+                       "%s", dev->virt_name);
                goto out_free_buf;
        }
 
index 260bf1b..21b54ad 100644 (file)
@@ -180,8 +180,13 @@ static long dev_user_ioctl(struct file *file, unsigned int cmd,
        unsigned long arg);
 static int dev_user_release(struct inode *inode, struct file *file);
 static int dev_user_exit_dev(struct scst_user_dev *dev);
+
+#ifdef CONFIG_SCST_PROC
 static int dev_user_read_proc(struct seq_file *seq,
        struct scst_dev_type *dev_type);
+#endif
+
+static int dev_usr_parse(struct scst_cmd *cmd);
 
 /** Data **/
 
@@ -199,6 +204,19 @@ static const struct file_operations dev_user_fops = {
        .release        = dev_user_release,
 };
 
+static struct scst_dev_type dev_user_devtype = {
+       .name =         DEV_USER_NAME,
+       .type =         -1,
+       .parse =        dev_usr_parse,
+#ifdef CONFIG_SCST_PROC
+       .read_proc =    dev_user_read_proc,
+#endif
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags = &trace_flag,
+#endif
+};
+
 static struct class *dev_user_sysfs_class;
 
 static DEFINE_SPINLOCK(dev_list_lock);
@@ -2489,13 +2507,11 @@ static int dev_user_attach_tgt(struct scst_tgt_dev *tgt_dev)
                sizeof(ucmd->user_cmd.sess.initiator_name)-1);
        ucmd->user_cmd.sess.initiator_name[
                sizeof(ucmd->user_cmd.sess.initiator_name)-1] = '\0';
-       if (tgt_dev->sess->tgt->default_group_name != NULL) {
-               strncpy(ucmd->user_cmd.sess.target_name,
-                       &tgt_dev->sess->tgt->default_group_name[sizeof(SCST_DEFAULT_ACG_NAME)],
-                       sizeof(ucmd->user_cmd.sess.target_name)-1);
-               ucmd->user_cmd.sess.target_name[
-                       sizeof(ucmd->user_cmd.sess.target_name)-1] = '\0';
-       }
+       strncpy(ucmd->user_cmd.sess.target_name,
+               tgt_dev->sess->tgt->tgt_name,
+               sizeof(ucmd->user_cmd.sess.target_name)-1);
+       ucmd->user_cmd.sess.target_name[
+               sizeof(ucmd->user_cmd.sess.target_name)-1] = '\0';
 
        TRACE_MGMT_DBG("Preparing ATTACH_SESS %p (h %d, sess_h %llx, LUN %llx, "
                "threads_num %d, rd_only %d, initiator %s, target %s)",
@@ -2758,7 +2774,9 @@ static int dev_user_register_dev(struct file *file,
        dev->devtype.parse_atomic = 1;
        dev->devtype.exec_atomic = 0; /* no point to make it 1 */
        dev->devtype.dev_done_atomic = 1;
+#ifdef CONFIG_SCST_PROC
        dev->devtype.no_proc = 1;
+#endif
        dev->devtype.attach = dev_user_attach;
        dev->devtype.detach = dev_user_detach;
        dev->devtype.attach_tgt = dev_user_attach_tgt;
@@ -2767,6 +2785,8 @@ static int dev_user_register_dev(struct file *file,
        dev->devtype.on_free_cmd = dev_user_on_free_cmd;
        dev->devtype.task_mgmt_fn = dev_user_task_mgmt_fn;
 
+       dev->devtype.parent = &dev_user_devtype;
+
        init_completion(&dev->cleanup_cmpl);
        dev->block = block;
        dev->def_block = block;
@@ -3200,16 +3220,6 @@ static int dev_usr_parse(struct scst_cmd *cmd)
        return SCST_CMD_STATE_DEFAULT;
 }
 
-/* Needed only for /proc support */
-#define USR_TYPE {                     \
-       .name =         DEV_USER_NAME,  \
-       .type =         -1,             \
-       .parse =        dev_usr_parse,  \
-       .read_proc =    dev_user_read_proc, \
-}
-
-static struct scst_dev_type dev_user_devtype = USR_TYPE;
-
 static int dev_user_exit_dev(struct scst_user_dev *dev)
 {
        TRACE_ENTRY();
@@ -3351,7 +3361,7 @@ out:
        return res;
 }
 
-
+#ifdef CONFIG_SCST_PROC
 /*
  * Called when a file in the /proc/scsi_tgt/scst_user is read
  */
@@ -3389,6 +3399,7 @@ static int dev_user_read_proc(struct seq_file *seq, struct scst_dev_type *dev_ty
        TRACE_EXIT_RES(res);
        return res;
 }
+#endif /* CONFIG_SCST_PROC */
 
 static inline int test_cleanup_list(void)
 {
@@ -3522,16 +3533,22 @@ static int __init init_scst_user(void)
        if (res < 0)
                goto out_cache1;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_dev_handler_build_std_proc(&dev_user_devtype);
        if (res != 0)
                goto out_unreg;
+#endif
 
        dev_user_sysfs_class = class_create(THIS_MODULE, DEV_USER_NAME);
        if (IS_ERR(dev_user_sysfs_class)) {
                PRINT_ERROR("%s", "Unable create sysfs class for SCST user "
                        "space handler");
                res = PTR_ERR(dev_user_sysfs_class);
+#ifdef CONFIG_SCST_PROC
                goto out_proc;
+#else
+               goto out_unreg;
+#endif
        }
 
        res = register_chrdev(DEV_USER_MAJOR, DEV_USER_NAME, &dev_user_fops);
@@ -3586,8 +3603,10 @@ out_chrdev:
 out_class:
        class_destroy(dev_user_sysfs_class);
 
+#ifdef CONFIG_SCST_PROC
 out_proc:
        scst_dev_handler_destroy_std_proc(&dev_user_devtype);
+#endif
 
 out_unreg:
        scst_unregister_dev_driver(&dev_user_devtype);
@@ -3618,7 +3637,9 @@ static void __exit exit_scst_user(void)
 #endif
        class_destroy(dev_user_sysfs_class);
 
+#ifdef CONFIG_SCST_PROC
        scst_dev_handler_destroy_std_proc(&dev_user_devtype);
+#endif
        scst_unregister_virtual_dev_driver(&dev_user_devtype);
 
        kmem_cache_destroy(user_get_cmd_cachep);
index c5917dd..3694c4b 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/uio.h>
-#include <linux/proc_fs.h>
 #include <linux/list.h>
 #include <linux/ctype.h>
 #include <linux/writeback.h>
 
 #define TRACE_ORDER    0x80000000
 
-static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
+static struct scst_trace_log vdisk_local_trace_tbl[] =
 {
     { TRACE_ORDER,             "order" },
     { 0,                       NULL }
 };
-#define trace_log_tbl  vdisk_proc_local_trace_tbl
+#define trace_log_tbl                  vdisk_local_trace_tbl
+
+#define VDISK_TRACE_TLB_HELP   ", order"
 
 #endif
 
@@ -64,7 +65,7 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
 #define SCST_FIO_VENDOR                        "SCST_FIO"
 #define SCST_BIO_VENDOR                        "SCST_BIO"
 /* 4 byte ASCII Product Revision Level - left aligned */
-#define SCST_FIO_REV                   " 102"
+#define SCST_FIO_REV                   " 200"
 
 #define MAX_USN_LEN                    (20+1) /* For '\0' */
 
@@ -90,11 +91,11 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
 #define        DEF_SECTORS                     56
 #define        DEF_HEADS                       255
 #define LEN_MEM                                (32 * 1024)
-#define VDISK_NAME                     "vdisk"
-#define VCDROM_NAME                    "vcdrom"
 
 #define VDISK_NULLIO_SIZE              (3LL*1024*1024*1024*1024/2)
 
+#define VDEV_NONE_FILENAME             "none"
+
 #define DEF_TST                                SCST_CONTR_MODE_SEP_TASK_SETS
 /*
  * Since we can't control backstorage device's reordering, we have to always
@@ -107,7 +108,9 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
 
 #define DEF_DSENSE             SCST_CONTR_MODE_FIXED_SENSE
 
+#ifdef CONFIG_SCST_PROC
 #define VDISK_PROC_HELP                "help"
+#endif
 
 static unsigned int random_values[256] = {
            9862592UL,  3744545211UL,  2348289082UL,  4036111983UL,
@@ -176,6 +179,8 @@ static unsigned int random_values[256] = {
         1056807896UL,  3525009458UL,  1174811641UL,  3049738746UL,
 };
 
+struct vdev_type;
+
 struct scst_vdisk_dev {
        uint32_t block_size;
        uint64_t nblocks;
@@ -185,7 +190,7 @@ struct scst_vdisk_dev {
        /*
         * This lock can be taken on both SIRQ and thread context, but in
         * all cases for each particular instance it's taken consistenly either
-        * on SIRQ or thread context. Mix of them is impossible.
+        * on SIRQ or thread context. Mix of them is forbidden.
         */
        spinlock_t flags_lock;
 
@@ -203,13 +208,16 @@ struct scst_vdisk_dev {
        unsigned int blockio:1;
        unsigned int cdrom_empty:1;
        unsigned int removable:1;
+
        int virt_id;
-       char name[16+1];        /* Name of virtual device,
+       char name[16+1];        /* Name of the virtual device,
                                   must be <= SCSI Model + 1 */
        char *file_name;        /* File name */
        char usn[MAX_USN_LEN];
        struct scst_device *dev;
        struct list_head vdisk_dev_list_entry;
+
+       const struct vdev_type *vdt;
 };
 
 struct scst_vdisk_tgt_dev {
@@ -229,8 +237,85 @@ struct scst_vdisk_thr {
        int iv_count;
 };
 
-static struct kmem_cache *vdisk_thr_cachep;
-static struct kmem_cache *blockio_work_cachep;
+/***
+ *** We make virtual devices emulation in OOP-like fashion: vdev is
+ *** an abstract class serving SPC set of commands and some common management
+ *** tasks, vdisk - an SBC (abstract) class with fileio, blockio and nullio
+ *** end classes, vcdrom - an MMC device class.
+ ***
+ *** Unfortunately, C doesn't support encapsulation and inheritance, so we
+ *** have to open code it, which makes the code look much less beautiful, than
+ *** it should.
+ ***
+ *** Only part to of the work is done. The second half is ToDo.
+ ***/
+
+/* VDEV sysfs actions */
+#define VDEV_ACTION_OPEN               0
+#define VDEV_ACTION_CLOSE              1
+
+/* VDISK sysfs actions */
+#define VDISK_ACTION_RESYNC_SIZE       100
+
+/* VCDROM sysfs actions */
+#define VCDROM_ACTION_CHANGE           100
+
+struct vdev_type_funcs {
+       struct scst_vdisk_dev *(*vdev_create) (struct vdev_type *vdt);
+       void (*vdev_destroy) (struct scst_vdisk_dev *virt_dev);
+
+       void (*vdev_init) (struct vdev_type *vdt,
+               struct scst_vdisk_dev *virt_dev);
+       void (*vdev_deinit) (struct scst_vdisk_dev *virt_dev);
+
+       /* Both supposed to be called under scst_vdisk_mutex */
+       int (*vdev_open) (struct vdev_type *vdt, char *p, const char *name);
+       int (*vdev_close) (struct vdev_type *vdt, const char *name);
+
+       /* All 3 supposed to be called under scst_vdisk_mutex */
+       void (*vdev_add) (struct scst_vdisk_dev *virt_dev);
+       void (*vdev_del) (struct scst_vdisk_dev *virt_dev);
+       struct scst_vdisk_dev *(*vdev_find) (const char *name);
+
+       int (*parse_cmd) (struct vdev_type *vdt, char *p, int *action);
+
+       /* Supposed to be called under scst_vdisk_mutex */
+       int (*perform_cmd) (struct vdev_type *vdt, int action, char *p,
+                               char *name);
+
+       int (*parse_option) (struct scst_vdisk_dev *virt_dev, char *p);
+
+       int (*pre_register) (struct scst_vdisk_dev *virt_dev);
+};
+
+struct vdev_type {
+       const char *vdt_name;
+       const char *help_string;
+
+       struct scst_dev_type *vdt_devt;
+
+       struct vdev_type_funcs vfns;
+};
+
+struct vdisk_fileio_type {
+       struct vdev_type parent_vdt;
+       struct vdev_type_funcs parent_vdt_vfns;
+};
+
+struct vdisk_blockio_type {
+       struct vdev_type parent_vdt;
+       struct vdev_type_funcs parent_vdt_vfns;
+};
+
+struct vdisk_nullio_type {
+       struct vdev_type parent_vdt;
+       struct vdev_type_funcs parent_vdt_vfns;
+};
+
+struct vcdrom_type {
+       struct vdev_type parent_vdt;
+       struct vdev_type_funcs parent_vdt_vfns;
+};
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
 #define DEF_NUM_THREADS                5
@@ -270,6 +355,7 @@ static void vdisk_exec_read_toc(struct scst_cmd *cmd);
 static void vdisk_exec_prevent_allow_medium_removal(struct scst_cmd *cmd);
 static int vdisk_fsync(struct scst_vdisk_thr *thr, loff_t loff,
        loff_t len, struct scst_cmd *cmd, struct scst_device *dev);
+#ifdef CONFIG_SCST_PROC
 static int vdisk_read_proc(struct seq_file *seq,
        struct scst_dev_type *dev_type);
 static int vdisk_write_proc(char *buffer, char **start, off_t offset,
@@ -278,114 +364,252 @@ static int vcdrom_read_proc(struct seq_file *seq,
        struct scst_dev_type *dev_type);
 static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
        int length, int *eof, struct scst_dev_type *dev_type);
+#endif
 static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
        struct scst_tgt_dev *tgt_dev);
 
-/*
- * Name of FILEIO vdisk can't be changed from "vdisk", since it is the name
- * of the corresponding /proc/scsi_tgt entry, hence a part of user space ABI.
- */
+/** SYSFS **/
 
-#define VDISK_TYPE {                                   \
-       .name =                 VDISK_NAME,             \
-       .type =                 TYPE_DISK,              \
-       .exec_sync =            1,                      \
-       .threads_num =          -1,                     \
-       .parse_atomic =         1,                      \
-       .exec_atomic =          0,                      \
-       .dev_done_atomic =      1,                      \
-       .attach =               vdisk_attach,           \
-       .detach =               vdisk_detach,           \
-       .attach_tgt =           vdisk_attach_tgt,       \
-       .detach_tgt =           vdisk_detach_tgt,       \
-       .parse =                vdisk_parse,            \
-       .exec =                 vdisk_do_job,           \
-       .read_proc =            vdisk_read_proc,        \
-       .write_proc =           vdisk_write_proc,       \
-       .task_mgmt_fn =         vdisk_task_mgmt_fn,     \
-}
-
-#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,                      \
-       .attach =               vdisk_attach,           \
-       .detach =               vdisk_detach,           \
-       .attach_tgt =           vdisk_attach_tgt,       \
-       .detach_tgt =           vdisk_detach_tgt,       \
-       .parse =                vdisk_parse,            \
-       .exec =                 vdisk_do_job,           \
-       .task_mgmt_fn =         vdisk_task_mgmt_fn,     \
-}
-
-#define VDISK_NULL_TYPE {                              \
-       .name =                 VDISK_NAME "_null",     \
-       .type =                 TYPE_DISK,              \
-       .threads_num =          0,                      \
-       .parse_atomic =         1,                      \
-       .exec_atomic =          1,                      \
-       .dev_done_atomic =      1,                      \
-       .no_proc =              1,                      \
-       .attach =               vdisk_attach,           \
-       .detach =               vdisk_detach,           \
-       .attach_tgt =           vdisk_attach_tgt,       \
-       .detach_tgt =           vdisk_detach_tgt,       \
-       .parse =                vdisk_parse,            \
-       .exec =                 vdisk_do_job,           \
-       .task_mgmt_fn =         vdisk_task_mgmt_fn,     \
-}
-
-#define VCDROM_TYPE {                                  \
-       .name =                 VCDROM_NAME,            \
-       .type =                 TYPE_ROM,               \
-       .exec_sync =            1,                      \
-       .threads_num =          -1,                     \
-       .parse_atomic =         1,                      \
-       .exec_atomic =          0,                      \
-       .dev_done_atomic =      1,                      \
-       .attach =               vdisk_attach,           \
-       .detach =               vdisk_detach,           \
-       .attach_tgt =           vdisk_attach_tgt,       \
-       .detach_tgt =           vdisk_detach_tgt,       \
-       .parse =                vcdrom_parse,           \
-       .exec =                 vcdrom_exec,            \
-       .read_proc =            vcdrom_read_proc,       \
-       .write_proc =           vcdrom_write_proc,      \
-       .task_mgmt_fn =         vdisk_task_mgmt_fn,     \
-}
+static ssize_t vdisk_mgmt_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_mgmt_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count);
+
+struct kobj_attribute vdisk_mgmt_attr =
+       __ATTR(mgmt, S_IRUGO | S_IWUSR, vdisk_mgmt_show, vdisk_mgmt_store);
+
+static const struct attribute *vdisk_attrs[] = {
+       &vdisk_mgmt_attr.attr,
+       NULL,
+};
+
+static ssize_t vdisk_sysfs_size_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_blocksize_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_rd_only_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_filename_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count);
+
+static struct kobj_attribute vdisk_size_attr =
+       __ATTR(size, S_IRUGO, vdisk_sysfs_size_show, NULL);
+static struct kobj_attribute vdisk_blocksize_attr =
+       __ATTR(block_size, S_IRUGO, vdisk_sysfs_blocksize_show, NULL);
+static struct kobj_attribute vdisk_rd_only_attr =
+       __ATTR(read_only, S_IRUGO, vdisk_sysfs_rd_only_show, NULL);
+static struct kobj_attribute vdisk_wt_attr =
+       __ATTR(write_through, S_IRUGO, vdisk_sysfs_wt_show, NULL);
+static struct kobj_attribute vdisk_nv_cache_attr =
+       __ATTR(nv_cache, S_IRUGO, vdisk_sysfs_nv_cache_show, NULL);
+static struct kobj_attribute vdisk_o_direct_attr =
+       __ATTR(o_direct, S_IRUGO, vdisk_sysfs_o_direct_show, NULL);
+static struct kobj_attribute vdisk_removable_attr =
+       __ATTR(removable, S_IRUGO, vdisk_sysfs_removable_show, NULL);
+static struct kobj_attribute vdisk_filename_attr =
+       __ATTR(filename, S_IRUGO, vdisk_sysfs_filename_show, NULL);
+static struct kobj_attribute vdisk_resync_size_attr =
+       __ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store);
+
+static const struct attribute *vdisk_fileio_attrs[] = {
+       &vdisk_size_attr.attr,
+       &vdisk_blocksize_attr.attr,
+       &vdisk_rd_only_attr.attr,
+       &vdisk_wt_attr.attr,
+       &vdisk_nv_cache_attr.attr,
+       &vdisk_o_direct_attr.attr,
+       &vdisk_removable_attr.attr,
+       &vdisk_filename_attr.attr,
+       &vdisk_resync_size_attr.attr,
+       NULL,
+};
+
+static const struct attribute *vdisk_blockio_attrs[] = {
+       &vdisk_size_attr.attr,
+       &vdisk_blocksize_attr.attr,
+       &vdisk_rd_only_attr.attr,
+       &vdisk_removable_attr.attr,
+       &vdisk_filename_attr.attr,
+       &vdisk_resync_size_attr.attr,
+       NULL,
+};
+
+static const struct attribute *vdisk_nullio_attrs[] = {
+       &vdisk_size_attr.attr,
+       &vdisk_blocksize_attr.attr,
+       &vdisk_rd_only_attr.attr,
+       &vdisk_removable_attr.attr,
+       NULL,
+};
+
+static const struct attribute *vcdrom_attrs[] = {
+       &vdisk_size_attr.attr,
+       &vdisk_removable_attr.attr,
+       &vdisk_filename_attr.attr,
+       NULL,
+};
 
 static DEFINE_MUTEX(scst_vdisk_mutex);
+
+/* Both protected by scst_vdisk_mutex */
 static LIST_HEAD(vdisk_dev_list);
 static LIST_HEAD(vcdrom_dev_list);
 
-static struct scst_dev_type vdisk_file_devtype = VDISK_TYPE;
-static struct scst_dev_type vdisk_blk_devtype = VDISK_BLK_TYPE;
-static struct scst_dev_type vdisk_null_devtype = VDISK_NULL_TYPE;
-static struct scst_dev_type vcdrom_devtype = VCDROM_TYPE;
+static struct vdisk_fileio_type fileio_type;
+static struct kmem_cache *vdisk_thr_cachep;
+
+/*
+ * Be careful changing "name" field, since it is the name of the corresponding
+ * /sys/kernel/scst_tgt entry, hence a part of user space ABI.
+ */
+
+static struct scst_dev_type vdisk_file_devtype = {
+       .name =                 "vdisk_fileio",
+       .type =                 TYPE_DISK,
+       .exec_sync =            1,
+       .threads_num =          -1,
+       .parse_atomic =         1,
+       .exec_atomic =          0,
+       .dev_done_atomic =      1,
+       .attach =               vdisk_attach,
+       .detach =               vdisk_detach,
+       .attach_tgt =           vdisk_attach_tgt,
+       .detach_tgt =           vdisk_detach_tgt,
+       .parse =                vdisk_parse,
+       .exec =                 vdisk_do_job,
+#ifdef CONFIG_SCST_PROC
+       .read_proc =            vdisk_read_proc,
+       .write_proc =           vdisk_write_proc,
+#endif
+       .task_mgmt_fn =         vdisk_task_mgmt_fn,
+       .devt_attrs =           vdisk_attrs,
+       .dev_attrs =            vdisk_fileio_attrs,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+       .trace_tbl =            vdisk_local_trace_tbl,
+       .trace_tbl_help =       VDISK_TRACE_TLB_HELP,
+#endif
+};
+
+static struct vdisk_blockio_type blockio_type;
+static struct kmem_cache *blockio_work_cachep;
+
+static struct scst_dev_type vdisk_blk_devtype = {
+       .name =                 "vdisk_blockio",
+       .type =                 TYPE_DISK,
+       .threads_num =          0,
+       .parse_atomic =         1,
+       .exec_atomic =          0,
+       .dev_done_atomic =      1,
+#ifdef CONFIG_SCST_PROC
+       .no_proc =              1,
+#endif
+       .attach =               vdisk_attach,
+       .detach =               vdisk_detach,
+       .attach_tgt =           vdisk_attach_tgt,
+       .detach_tgt =           vdisk_detach_tgt,
+       .parse =                vdisk_parse,
+       .exec =                 vdisk_do_job,
+       .task_mgmt_fn =         vdisk_task_mgmt_fn,
+       .devt_attrs =           vdisk_attrs,
+       .dev_attrs =            vdisk_blockio_attrs,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+       .trace_tbl =            vdisk_local_trace_tbl,
+       .trace_tbl_help =       VDISK_TRACE_TLB_HELP,
+#endif
+};
+
+static struct vdisk_blockio_type nullio_type;
+static struct scst_dev_type vdisk_null_devtype = {
+       .name =                 "vdisk_nullio",
+       .type =                 TYPE_DISK,
+       .threads_num =          0,
+       .parse_atomic =         1,
+       .exec_atomic =          1,
+       .dev_done_atomic =      1,
+#ifdef CONFIG_SCST_PROC
+       .no_proc =              1,
+#endif
+       .attach =               vdisk_attach,
+       .detach =               vdisk_detach,
+       .attach_tgt =           vdisk_attach_tgt,
+       .detach_tgt =           vdisk_detach_tgt,
+       .parse =                vdisk_parse,
+       .exec =                 vdisk_do_job,
+       .task_mgmt_fn =         vdisk_task_mgmt_fn,
+       .devt_attrs =           vdisk_attrs,
+       .dev_attrs =            vdisk_nullio_attrs,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+       .trace_tbl =            vdisk_local_trace_tbl,
+       .trace_tbl_help =       VDISK_TRACE_TLB_HELP,
+#endif
+};
+
+static struct vcdrom_type vcdrom_type;
+static struct scst_dev_type vcdrom_devtype = {
+       .name =                 "vcdrom",
+       .type =                 TYPE_ROM,
+       .exec_sync =            1,
+       .threads_num =          -1,
+       .parse_atomic =         1,
+       .exec_atomic =          0,
+       .dev_done_atomic =      1,
+       .attach =               vdisk_attach,
+       .detach =               vdisk_detach,
+       .attach_tgt =           vdisk_attach_tgt,
+       .detach_tgt =           vdisk_detach_tgt,
+       .parse =                vcdrom_parse,
+       .exec =                 vcdrom_exec,
+#ifdef CONFIG_SCST_PROC
+       .read_proc =            vcdrom_read_proc,
+       .write_proc =           vcdrom_write_proc,
+#endif
+       .task_mgmt_fn =         vdisk_task_mgmt_fn,
+       .devt_attrs =           vdisk_attrs,
+       .dev_attrs =            vcdrom_attrs,
+#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
+       .default_trace_flags =  SCST_DEFAULT_DEV_LOG_FLAGS,
+       .trace_flags =          &trace_flag,
+       .trace_tbl =            vdisk_local_trace_tbl,
+       .trace_tbl_help =       VDISK_TRACE_TLB_HELP,
+#endif
+};
 
 static struct scst_vdisk_thr nullio_thr_data;
 
+#ifdef CONFIG_SCST_PROC
 static char *vdisk_proc_help_string =
        "echo \"open|close|resync_size NAME [FILE_NAME [BLOCK_SIZE] "
        "[WRITE_THROUGH READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" "
-       ">/proc/scsi_tgt/" VDISK_NAME "/" VDISK_NAME "\n";
+       ">/proc/scsi_tgt/vdisk/vdisk\n";
 
 static char *vcdrom_proc_help_string =
        "echo \"open|change|close NAME [FILE_NAME]\" "
-       ">/proc/scsi_tgt/" VCDROM_NAME "/" VCDROM_NAME "\n";
+       ">/proc/scsi_tgt/vcdrom/vcdrom\n";
+#endif
 
 static int scst_vdisk_ID;
 
 module_param_named(scst_vdisk_ID, scst_vdisk_ID, int, S_IRUGO);
 MODULE_PARM_DESC(scst_vdisk_ID, "SCST virtual disk subsystem ID");
 
-
 /**************************************************************
- *  Function:  vdisk_open
+ *  Function:  vdev_open_fd
  *
  *  Argument:
  *
@@ -393,7 +617,7 @@ MODULE_PARM_DESC(scst_vdisk_ID, "SCST virtual disk subsystem ID");
  *
  *  Description:
  *************************************************************/
-static struct file *vdisk_open(const struct scst_vdisk_dev *virt_dev)
+static struct file *vdev_open_fd(const struct scst_vdisk_dev *virt_dev)
 {
        int open_flags = 0;
        struct file *fd;
@@ -553,15 +777,7 @@ static int vdisk_attach(struct scst_device *dev)
        } else
                virt_dev->file_size = 0;
 
-       if (dev->type == TYPE_DISK) {
-               virt_dev->nblocks =
-                       virt_dev->file_size >> virt_dev->block_shift;
-       } else {
-               virt_dev->block_size = DEF_CDROM_BLOCKSIZE;
-               virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT;
-               virt_dev->nblocks =
-                       virt_dev->file_size >> DEF_CDROM_BLOCKSIZE_SHIFT;
-       }
+       virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift;
 
        if (!virt_dev->cdrom_empty) {
                PRINT_INFO("Attached SCSI target virtual %s %s "
@@ -666,7 +882,7 @@ static struct scst_vdisk_thr *vdisk_init_thr_data(
        }
 
        if (!virt_dev->cdrom_empty) {
-               res->fd = vdisk_open(virt_dev);
+               res->fd = vdev_open_fd(virt_dev);
                if (IS_ERR(res->fd)) {
                        PRINT_ERROR("filp_open(%s) returned an error %ld",
                                virt_dev->file_name, PTR_ERR(res->fd));
@@ -769,10 +985,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
 
        switch (cmd->queue_type) {
        case SCST_CMD_QUEUE_ORDERED:
-               TRACE(TRACE_ORDER, "ORDERED cmd %p", cmd);
+               TRACE(TRACE_ORDER, "ORDERED cmd %p (op %x)", cmd, cmd->cdb[0]);
                break;
        case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
-               TRACE(TRACE_ORDER, "HQ cmd %p", cmd);
+               TRACE(TRACE_ORDER, "HQ cmd %p (op %x)", cmd, cmd->cdb[0]);
                break;
        default:
                break;
@@ -1196,7 +1412,7 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
        }
 
        buf[0] = cmd->dev->type;      /* type dev */
-       if ((buf[0] == TYPE_ROM) || virt_dev->removable)
+       if (virt_dev->removable)
                buf[1] = 0x80;      /* removable */
        /* Vital Product */
        if (cmd->cdb[1] & EVPD) {
@@ -2692,20 +2908,6 @@ out:
        return;
 }
 
-static inline struct scst_vdisk_dev *vdisk_alloc_dev(void)
-{
-       struct scst_vdisk_dev *dev;
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of virtual "
-                       "device failed");
-               goto out;
-       }
-       spin_lock_init(&dev->flags_lock);
-out:
-       return dev;
-}
-
 static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
        struct scst_tgt_dev *tgt_dev)
 {
@@ -2733,83 +2935,13 @@ static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
        return SCST_DEV_TM_NOT_COMPLETED;
 }
 
-/*
- * Called when a file in the /proc/VDISK_NAME/VDISK_NAME is read
- */
-static int vdisk_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type)
-{
-       int res = 0;
-       struct scst_vdisk_dev *virt_dev;
-
-       TRACE_ENTRY();
-
-       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
-               res = -EINTR;
-               goto out;
-       }
-
-       seq_printf(seq, "%-17s %-11s %-11s %-15s %s\n",
-                  "Name", "Size(MB)", "Block size", "Options", "File name");
-
-       list_for_each_entry(virt_dev, &vdisk_dev_list, vdisk_dev_list_entry) {
-               int c;
-               seq_printf(seq, "%-17s %-11d %-12d", virt_dev->name,
-                       (uint32_t)(virt_dev->file_size >> 20),
-                       virt_dev->block_size);
-               c = 0;
-               if (virt_dev->wt_flag) {
-                       seq_printf(seq, "WT ");
-                       c += 3;
-               }
-               if (virt_dev->nv_cache) {
-                       seq_printf(seq, "NV ");
-                       c += 3;
-               }
-               if (virt_dev->dev != NULL) {
-                       if (virt_dev->dev->rd_only) {
-                               seq_printf(seq, "RO ");
-                               c += 3;
-                       }
-               } else if (virt_dev->rd_only) {
-                       seq_printf(seq, "RO ");
-                       c += 3;
-               }
-               if (virt_dev->o_direct_flag) {
-                       seq_printf(seq, "DR ");
-                       c += 3;
-               }
-               if (virt_dev->nullio) {
-                       seq_printf(seq, "NIO ");
-                       c += 4;
-               }
-               if (virt_dev->blockio) {
-                       seq_printf(seq, "BIO ");
-                       c += 4;
-               }
-               if (virt_dev->removable) {
-                       seq_printf(seq, "RM ");
-                       c += 4;
-               }
-               while (c < 16) {
-                       seq_printf(seq, " ");
-                       c++;
-               }
-               seq_printf(seq, "%s\n", virt_dev->file_name);
-       }
-       mutex_unlock(&scst_vdisk_mutex);
-out:
-       TRACE_EXIT_RES(res);
-       return res;
-}
-
-static void vdisk_report_registering(const char *type,
-       const struct scst_vdisk_dev *virt_dev)
+static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
 {
        char buf[128];
        int i, j;
 
        i = snprintf(buf, sizeof(buf), "Registering virtual %s device %s ",
-               type, virt_dev->name);
+               virt_dev->vdt->vdt_name, virt_dev->name);
        j = i;
 
        if (virt_dev->wt_flag)
@@ -2848,7 +2980,7 @@ static void vdisk_report_registering(const char *type,
 }
 
 /* scst_vdisk_mutex supposed to be held */
-static int vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
+static int __vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
 {
        loff_t file_size;
        int res = 0;
@@ -2893,73 +3025,1081 @@ out:
        return res;
 }
 
-/*
- * Called when a file in the /proc/VDISK_NAME/VDISK_NAME is written
- */
-static int vdisk_write_proc(char *buffer, char **start, off_t offset,
-       int length, int *eof, struct scst_dev_type *dev_type)
+/* scst_vdisk_mutex supposed to be held */
+static int vdisk_resync_size(struct vdev_type *vdt, char *p, const char *name)
 {
-       int res = 0, action;
-       char *p, *name, *file_name;
-       struct scst_vdisk_dev *virt_dev, *vv;
-       uint32_t block_size = DEF_DISK_BLOCKSIZE;
-       int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
-       size_t len;
+       struct scst_vdisk_dev *virt_dev;
+       int res;
 
-       TRACE_ENTRY();
+       virt_dev = vdt->vfns.vdev_find(name);
+       if (virt_dev == NULL) {
+               PRINT_ERROR("Device %s not found", name);
+               res = -EINVAL;
+               goto out;
+       }
 
-       /* VERY UGLY code. You can rewrite it if you want */
+       res = __vdisk_resync_size(virt_dev);
 
-       if (buffer[0] == '\0')
-               goto out;
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
 
-       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
-               res = -EINTR;
+static void vdev_init(struct vdev_type *vdt, struct scst_vdisk_dev *virt_dev)
+{
+       memset(virt_dev, 0, sizeof(*virt_dev));
+       spin_lock_init(&virt_dev->flags_lock);
+       virt_dev->vdt = vdt;
+
+       virt_dev->block_size = DEF_DISK_BLOCKSIZE;
+       virt_dev->block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
+
+       return;
+}
+
+static struct scst_vdisk_dev *vdev_create(struct vdev_type *vdt)
+{
+       struct scst_vdisk_dev *virt_dev;
+
+       virt_dev = kmalloc(sizeof(*virt_dev), GFP_KERNEL);
+       if (virt_dev == NULL) {
+               PRINT_ERROR("Allocation of virtual device %s failed",
+                       vdt->vdt_name);
                goto out;
        }
 
-       p = buffer;
-       if (p[strlen(p) - 1] == '\n')
-               p[strlen(p) - 1] = '\0';
-       if (!strncmp("close ", p, 6)) {
-               p += 6;
-               action = 0;
-       } else if (!strncmp("open ", p, 5)) {
-               p += 5;
-               action = 1;
-       } else if (!strncmp("resync_size ", p, 12)) {
-               p += 12;
-               action = 2;
-       } else {
-               PRINT_ERROR("Unknown action \"%s\"", p);
+       vdt->vfns.vdev_init(vdt, virt_dev);
+
+out:
+       return virt_dev;
+}
+
+static void vdev_deinit(struct scst_vdisk_dev *virt_dev)
+{
+       kfree(virt_dev->file_name);
+       return;
+}
+
+static void vdev_destroy(struct scst_vdisk_dev *virt_dev)
+{
+       virt_dev->vdt->vfns.vdev_deinit(virt_dev);
+       kfree(virt_dev);
+       return;
+}
+
+static int vdisk_fileio_pre_register(struct scst_vdisk_dev *virt_dev)
+{
+       int res = 0;
+
+       if ((virt_dev->file_name == NULL) ||
+           (strcmp(virt_dev->file_name, VDEV_NONE_FILENAME) == 0)) {
+               PRINT_ERROR("%s", "File name required");
                res = -EINVAL;
-               goto out_up;
+               goto out;
        }
 
-       while (isspace(*p) && *p != '\0')
-               p++;
-       name = p;
-       while (!isspace(*p) && *p != '\0')
-               p++;
-       *p++ = '\0';
-       if (*name == '\0') {
-               PRINT_ERROR("%s", "Name required");
+       if (virt_dev->rd_only && (virt_dev->wt_flag || virt_dev->nv_cache)) {
+               PRINT_ERROR("Write options on read only device %s",
+                       virt_dev->name);
                res = -EINVAL;
-               goto out_up;
-       } else if (strlen(name) >= sizeof(virt_dev->name)) {
-               PRINT_ERROR("Name is too long (max %zd "
-                       "characters)", sizeof(virt_dev->name)-1);
+               goto out;
+       }
+
+out:
+       return res;
+}
+
+static int vdisk_blockio_pre_register(struct scst_vdisk_dev *virt_dev)
+{
+       int res = 0;
+
+       if ((virt_dev->file_name == NULL) ||
+           (strcmp(virt_dev->file_name, VDEV_NONE_FILENAME) == 0)) {
+               PRINT_ERROR("%s", "File name required");
                res = -EINVAL;
-               goto out_up;
+               goto out;
        }
 
-       if (action == 1) {
-               /* open */
-               virt_dev = NULL;
-               list_for_each_entry(vv, &vdisk_dev_list,
-                                       vdisk_dev_list_entry) {
-                       if (strcmp(vv->name, name) == 0) {
-                               virt_dev = vv;
+out:
+       return res;
+}
+
+static void vdisk_blockio_init(struct vdev_type *vdt,
+       struct scst_vdisk_dev *virt_dev)
+{
+       struct vdisk_blockio_type *v;
+
+       v = container_of(vdt, struct vdisk_blockio_type, parent_vdt);
+
+       v->parent_vdt_vfns.vdev_init(vdt, virt_dev);
+
+       virt_dev->blockio = 1;
+       return;
+}
+
+static void vdisk_nullio_init(struct vdev_type *vdt,
+       struct scst_vdisk_dev *virt_dev)
+{
+       struct vdisk_nullio_type *v;
+
+       v = container_of(vdt, struct vdisk_nullio_type, parent_vdt);
+
+       v->parent_vdt_vfns.vdev_init(vdt, virt_dev);
+
+       virt_dev->nullio = 1;
+       return;
+}
+
+static int vdisk_parse_option(struct scst_vdisk_dev *virt_dev, char *p)
+{
+       int res = -EINVAL;
+
+       TRACE_ENTRY();
+
+       if (!strncmp("READ_ONLY", p, 9)) {
+               res = 9;
+               virt_dev->rd_only = 1;
+               TRACE_DBG("%s", "READ_ONLY");
+       } else if (!strncmp("REMOVABLE", p, 9)) {
+               res = 9;
+               virt_dev->removable = 1;
+               TRACE_DBG("%s", "REMOVABLE");
+       }
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int vdisk_fileio_parse_option(struct scst_vdisk_dev *virt_dev, char *p)
+{
+       int res;
+
+       TRACE_ENTRY();
+
+       res = vdisk_parse_option(virt_dev, p);
+       if (res >= 0)
+               goto out;
+
+       if (!strncmp("WRITE_THROUGH", p, 13)) {
+               res = 13;
+               virt_dev->wt_flag = 1;
+               TRACE_DBG("%s", "WRITE_THROUGH");
+       } else if (!strncmp("NV_CACHE", p, 8)) {
+               res = 8;
+               virt_dev->nv_cache = 1;
+               TRACE_DBG("%s", "NON-VOLATILE CACHE");
+       } else if (!strncmp("O_DIRECT", p, 8)) {
+               res = 8;
+#if 0
+               virt_dev->o_direct_flag = 1;
+               TRACE_DBG("%s", "O_DIRECT");
+#else
+               PRINT_INFO("%s flag doesn't currently"
+                       " work, ignoring it, use fileio_tgt "
+                       "in O_DIRECT mode instead", "O_DIRECT");
+#endif
+       }
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static int vdev_open(struct vdev_type *vdt, char *p, const char *name)
+{
+       int res = 0;
+       char *file_name;
+       struct scst_vdisk_dev *virt_dev;
+       size_t len;
+
+       TRACE_ENTRY();
+
+       virt_dev = vdt->vfns.vdev_find(name);
+       if (virt_dev != NULL) {
+               PRINT_ERROR("Virtual device with name %s already exist", name);
+               res = -EINVAL;
+               goto out;
+       }
+
+       while (isspace(*p) && *p != '\0')
+               p++;
+       file_name = p;
+       if ((*file_name == '/') || (strcmp(file_name, VDEV_NONE_FILENAME) == 0)) {
+               while (!isspace(*p) && *p != '\0')
+                       p++;
+               *p++ = '\0';
+
+               TRACE_DBG("file name %s", file_name);
+
+               while (isspace(*p) && *p != '\0')
+                       p++;
+       } else {
+               TRACE_DBG("file name %s", "not specified");
+               file_name = NULL;
+       }
+
+       virt_dev = vdt->vfns.vdev_create(vdt);
+       if (virt_dev == NULL) {
+               TRACE(TRACE_OUT_OF_MEM, "Creation of virt_dev %s failed", name);
+               res = -ENOMEM;
+               goto out;
+       }
+
+       if (isdigit(*p)) {
+               uint32_t block_size;
+               int block_shift;
+               char *pp;
+
+               block_size = simple_strtoul(p, &pp, 0);
+               p = pp;
+               if ((*p != '\0') && !isspace(*p)) {
+                       PRINT_ERROR("Parse error: \"%s\"", p);
+                       res = -EINVAL;
+                       goto out_free_vdev;
+               }
+               while (isspace(*p) && *p != '\0')
+                       p++;
+
+               block_shift = scst_calc_block_shift(block_size);
+               if (block_shift < 9) {
+                       res = -EINVAL;
+                       goto out_free_vdev;
+               }
+
+               TRACE_DBG("block_size %d, block_shift %d", block_size,
+                       block_shift);
+
+               virt_dev->block_size = block_size;
+               virt_dev->block_shift = block_shift;
+       }
+
+       while (*p != '\0') {
+               while (isspace(*p) && *p != '\0')
+                       p++;
+
+               if (vdt->vfns.parse_option != NULL)
+                       res = vdt->vfns.parse_option(virt_dev, p);
+               else
+                       res = -EINVAL;
+
+               if (res < 0) {
+                       PRINT_ERROR("Unknown option \"%s\"", p);
+                       goto out_free_vdev;
+               } else if (res == 0)
+                       break;
+
+               p += res;
+
+               if (!isspace(*p) && (*p != '\0')) {
+                       PRINT_ERROR("Syntax error on %s", p);
+                       goto out_free_vdev;
+               }
+       }
+
+       strcpy(virt_dev->name, name);
+
+       scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx",
+                       vdisk_gen_dev_id_num(virt_dev));
+       TRACE_DBG("usn %s", virt_dev->usn);
+
+       if (file_name != NULL) {
+               len = strlen(file_name) + 1;
+               virt_dev->file_name = kmalloc(len, GFP_KERNEL);
+               if (virt_dev->file_name == NULL) {
+                       TRACE(TRACE_OUT_OF_MEM, "Allocation of file_name %s "
+                               "failed", file_name);
+                       res = -ENOMEM;
+                       goto out_free_vdev;
+               }
+               strncpy(virt_dev->file_name, file_name, len);
+       }
+
+       if (vdt->vfns.pre_register != NULL) {
+               res = vdt->vfns.pre_register(virt_dev);
+               if (res != 0)
+                       goto out_free_vpath;
+       }
+
+       vdt->vfns.vdev_add(virt_dev);
+
+       vdisk_report_registering(virt_dev);
+       virt_dev->virt_id = scst_register_virtual_device(vdt->vdt_devt,
+                                                virt_dev->name);
+       if (virt_dev->virt_id < 0) {
+               res = virt_dev->virt_id;
+               goto out_del;
+       }
+
+       TRACE_DBG("Added virt_dev (name %s, file name %s, id %d, block size "
+               "%d) to vdisk_dev_list", virt_dev->name, virt_dev->file_name,
+               virt_dev->virt_id, virt_dev->block_size);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+
+out_del:
+       vdt->vfns.vdev_del(virt_dev);
+
+out_free_vpath:
+       kfree(virt_dev->file_name);
+
+out_free_vdev:
+       kfree(virt_dev);
+       goto out;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static int vdev_close(struct vdev_type *vdt, const char *name)
+{
+       int res = 0;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       virt_dev = vdt->vfns.vdev_find(name);
+       if (virt_dev == NULL) {
+               PRINT_ERROR("Device %s not found", name);
+               res = -EINVAL;
+               goto out;
+       }
+
+       scst_unregister_virtual_device(virt_dev->virt_id);
+
+       PRINT_INFO("Virtual device %s unregistered", virt_dev->name);
+       TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
+
+       vdt->vfns.vdev_del(virt_dev);
+       vdt->vfns.vdev_destroy(virt_dev);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static void vdev_del(struct scst_vdisk_dev *virt_dev)
+{
+       TRACE_ENTRY();
+
+       list_del(&virt_dev->vdisk_dev_list_entry);
+
+       TRACE_EXIT();
+       return;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static void vdisk_add(struct scst_vdisk_dev *virt_dev)
+{
+       TRACE_ENTRY();
+
+       list_add_tail(&virt_dev->vdisk_dev_list_entry, &vdisk_dev_list);
+
+       TRACE_EXIT();
+       return;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static struct scst_vdisk_dev *vdisk_find(const char *name)
+{
+       struct scst_vdisk_dev *res, *vv;
+
+       TRACE_ENTRY();
+
+       res = NULL;
+       list_for_each_entry(vv, &vdisk_dev_list, vdisk_dev_list_entry) {
+               if (strcmp(vv->name, name) == 0) {
+                       res = vv;
+                       break;
+               }
+       }
+
+       TRACE_EXIT_HRES((unsigned long)res);
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static void vcdrom_add(struct scst_vdisk_dev *virt_dev)
+{
+       TRACE_ENTRY();
+
+       list_add_tail(&virt_dev->vdisk_dev_list_entry, &vcdrom_dev_list);
+
+       TRACE_EXIT();
+       return;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static struct scst_vdisk_dev *vcdrom_find(const char *name)
+{
+       struct scst_vdisk_dev *res, *vv;
+
+       TRACE_ENTRY();
+
+       res = NULL;
+       list_for_each_entry(vv, &vcdrom_dev_list, vdisk_dev_list_entry) {
+               if (strcmp(vv->name, name) == 0) {
+                       res = vv;
+                       break;
+               }
+       }
+
+       TRACE_EXIT_HRES((unsigned long)res);
+       return res;
+}
+
+static int vdisk_parse_cmd(struct vdev_type *vdt, char *p, int *action)
+{
+       int res = -EINVAL;
+
+       TRACE_ENTRY();
+
+       if (!strncmp("resync_size", p, 11)) {
+               res = 11;
+               p += res;
+               *action = VDISK_ACTION_RESYNC_SIZE;
+       }
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static int vdisk_perform_cmd(struct vdev_type *vdt, int action, char *p,
+       char *name)
+{
+       int res = -EINVAL;
+
+       TRACE_ENTRY();
+
+       if (action == VDISK_ACTION_RESYNC_SIZE)
+               res = vdisk_resync_size(vdt, p, name);
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static void vcdrom_init(struct vdev_type *vdt,
+       struct scst_vdisk_dev *virt_dev)
+{
+       struct vcdrom_type *vt;
+
+       vt = container_of(vdt, struct vcdrom_type, parent_vdt);
+
+       vt->parent_vdt_vfns.vdev_init(vdt, virt_dev);
+
+       virt_dev->rd_only = 1;
+       virt_dev->removable = 1;
+
+       virt_dev->block_size = DEF_CDROM_BLOCKSIZE;
+       virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT;
+
+       return;
+}
+
+static int vcdrom_pre_register(struct scst_vdisk_dev *virt_dev)
+{
+       int res = 0;
+
+       if ((virt_dev->file_name == NULL) ||
+           (strcmp(virt_dev->file_name, VDEV_NONE_FILENAME) == 0))
+               virt_dev->cdrom_empty = 1;
+
+       if (virt_dev->block_size != DEF_CDROM_BLOCKSIZE) {
+               PRINT_WARNING("Block size %d for vortual device %s ignored",
+                       virt_dev->block_size, virt_dev->name);
+               virt_dev->block_size = DEF_CDROM_BLOCKSIZE;
+               virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT;
+       }
+
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static int vcdrom_change(struct vdev_type *vdt, char *p, const char *name)
+{
+       loff_t err;
+       struct scst_vdisk_dev *virt_dev;
+       char *file_name, *fn = NULL, *old_fn;
+       int len;
+       int res = 0;
+
+       virt_dev = vdt->vfns.vdev_find(name);
+       if (virt_dev == NULL) {
+               PRINT_ERROR("Virtual device with name "
+                      "%s not found", name);
+               res = -EINVAL;
+               goto out;
+       }
+
+       while (isspace(*p) && *p != '\0')
+               p++;
+       file_name = p;
+       while (!isspace(*p) && *p != '\0')
+               p++;
+       *p++ = '\0';
+       if (*file_name == '\0') {
+               virt_dev->cdrom_empty = 1;
+               TRACE_DBG("%s", "No media");
+       } else if (*file_name != '/') {
+               PRINT_ERROR("File path \"%s\" is not "
+                       "absolute", file_name);
+               res = -EINVAL;
+               goto out;
+       } else
+               virt_dev->cdrom_empty = 0;
+
+       old_fn = virt_dev->file_name;
+
+       if (!virt_dev->cdrom_empty) {
+               len = strlen(file_name) + 1;
+               fn = kmalloc(len, GFP_KERNEL);
+               if (fn == NULL) {
+                       TRACE(TRACE_OUT_OF_MEM, "%s",
+                               "Allocation of file_name failed");
+                       res = -ENOMEM;
+                       goto out;
+               }
+
+               strncpy(fn, file_name, len);
+               virt_dev->file_name = fn;
+
+               res = vdisk_get_file_size(virt_dev->file_name,
+                               virt_dev->blockio, &err);
+               if (res != 0)
+                       goto out_free;
+       } else {
+               err = 0;
+               virt_dev->file_name = NULL;
+       }
+
+       res = scst_suspend_activity(true);
+       if (res != 0)
+               goto out_free;
+
+       if (virt_dev->prevent_allow_medium_removal) {
+               PRINT_ERROR("Prevent medium removal for "
+                       "virtual device with name %s", name);
+               res = -EINVAL;
+               goto out_free_resume;
+       }
+
+       virt_dev->file_size = err;
+       virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift;
+       if (!virt_dev->cdrom_empty)
+               virt_dev->media_changed = 1;
+
+       scst_dev_del_all_thr_data(virt_dev->dev);
+
+       if (!virt_dev->cdrom_empty) {
+               PRINT_INFO("Changed SCSI target virtual cdrom %s "
+                       "(file=\"%s\", fs=%lldMB, bs=%d, nblocks=%lld,"
+                       " cyln=%lld%s)", virt_dev->name, virt_dev->file_name,
+                       virt_dev->file_size >> 20, virt_dev->block_size,
+                       (long long unsigned int)virt_dev->nblocks,
+                       (long long unsigned int)virt_dev->nblocks/64/32,
+                       virt_dev->nblocks < 64*32 ? " !WARNING! cyln less "
+                                                       "than 1" : "");
+       } else {
+               PRINT_INFO("Removed media from SCSI target virtual cdrom %s",
+                       virt_dev->name);
+       }
+
+       kfree(old_fn);
+
+out_resume:
+       scst_resume_activity();
+
+out:
+       return res;
+
+out_free:
+       virt_dev->file_name = old_fn;
+       kfree(fn);
+       goto out;
+
+out_free_resume:
+       virt_dev->file_name = old_fn;
+       kfree(fn);
+       goto out_resume;
+}
+
+static int vcdrom_parse_cmd(struct vdev_type *vdt, char *p, int *action)
+{
+       int res = -EINVAL;
+
+       TRACE_ENTRY();
+
+       if (!strncmp("change", p, 6)) {
+               res = 6;
+               p += res;
+               *action = VCDROM_ACTION_CHANGE;
+       }
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+/* scst_vdisk_mutex supposed to be held */
+static int vcdrom_perform_cmd(struct vdev_type *vdt, int action, char *p,
+       char *name)
+{
+       int res = -EINVAL;
+
+       TRACE_ENTRY();
+
+       if (action == VCDROM_ACTION_CHANGE)
+               res = vcdrom_change(vdt, p, name);
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int vdisk_mgmt_cmd(const char *buffer, int length,
+       struct vdev_type *vdt)
+{
+       int res = 0, action;
+       char *p, *name, *i_buf;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       if ((length == 0) || (buffer == NULL) || (buffer[0] == '\0'))
+               goto out;
+
+       i_buf = kmalloc(length+1, GFP_KERNEL);
+       if (i_buf == NULL) {
+               PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
+                       length+1);
+               goto out;
+       }
+
+       memcpy(i_buf, buffer, length);
+       i_buf[length] = '\0';
+
+       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
+               res = -EINTR;
+               goto out_free;
+       }
+
+       p = i_buf;
+       if (p[strlen(p) - 1] == '\n')
+               p[strlen(p) - 1] = '\0';
+       if (!strncmp("open", p, 4)) {
+               p += 4;
+               action = VDEV_ACTION_OPEN;
+       } else if (!strncmp("close", p, 5)) {
+               p += 5;
+               action = VDEV_ACTION_CLOSE;
+       } else {
+               int n;
+               n = vdt->vfns.parse_cmd(vdt, p, &action);
+               if (n > 0)
+                       p += n;
+               else {
+                       PRINT_ERROR("Unknown action \"%s\"", p);
+                       res = -EINVAL;
+                       goto out_up;
+               }
+       }
+
+       if (!isspace(*p)) {
+               PRINT_ERROR("Syntax error on %s", p);
+               res = -EINVAL;
+               goto out_up;
+       }
+
+       while (isspace(*p) && *p != '\0')
+               p++;
+       name = p;
+       while (!isspace(*p) && *p != '\0')
+               p++;
+       *p++ = '\0';
+       if (*name == '\0') {
+               PRINT_ERROR("%s", "Name required");
+               res = -EINVAL;
+               goto out_up;
+       } else if (strlen(name) >= sizeof(virt_dev->name)) {
+               PRINT_ERROR("Name is too long (max %zd "
+                       "characters)", sizeof(virt_dev->name)-1);
+               res = -EINVAL;
+               goto out_up;
+       }
+
+       if (action == VDEV_ACTION_OPEN) {
+               res = vdt->vfns.vdev_open(vdt, p, name);
+               if (res != 0)
+                       goto out_up;
+       } else if (action == VDEV_ACTION_CLOSE) {
+               res = vdt->vfns.vdev_close(vdt, name);
+               if (res != 0)
+                       goto out_up;
+       } else {
+               res = vdt->vfns.perform_cmd(vdt, action, p, name);
+               if (res != 0)
+                       goto out_up;
+       }
+       res = length;
+
+out_up:
+       mutex_unlock(&scst_vdisk_mutex);
+
+out_free:
+       kfree(i_buf);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static ssize_t vdisk_mgmt_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       struct scst_dev_type *devt;
+       struct vdev_type *vdt;
+
+       devt = container_of(kobj, struct scst_dev_type, devt_kobj);
+       vdt = (struct vdev_type *)devt->devt_priv;
+
+       return scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, vdt->help_string);
+}
+
+static ssize_t vdisk_mgmt_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       struct scst_dev_type *devt;
+       int res = count;
+
+       devt = container_of(kobj, struct scst_dev_type, devt_kobj);
+
+       res = vdisk_mgmt_cmd(buf, count, (struct vdev_type *)devt->devt_priv);
+
+       return res;
+}
+
+static ssize_t vdisk_sysfs_size_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%lld\n", virt_dev->file_size);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_blocksize_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", (int)virt_dev->block_size);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_rd_only_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", virt_dev->rd_only ? 1 : 0);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", virt_dev->wt_flag ? 1 : 0);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", virt_dev->nv_cache ? 1 : 0);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", virt_dev->o_direct_flag ? 1 : 0);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%d\n", virt_dev->removable ? 1 : 0);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_filename_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       pos = sprintf(buf, "%s\n", virt_dev->file_name);
+
+       TRACE_EXIT_RES(pos);
+       return pos;
+}
+
+static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       int res;
+       struct scst_device *dev;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       dev = container_of(kobj, struct scst_device, dev_kobj);
+       virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
+
+       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
+               res = -EINTR;
+               goto out;
+       }
+
+       res = __vdisk_resync_size(virt_dev);
+       if (res != 0)
+               goto out_unlock;
+
+       res = count;
+
+out_unlock:
+       mutex_unlock(&scst_vdisk_mutex);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+#ifdef CONFIG_SCST_PROC
+
+/*
+ * ProcFS
+ */
+
+/*
+ * Called when a file in the /proc/VDISK_NAME/VDISK_NAME is read
+ */
+static int vdisk_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type)
+{
+       int res = 0;
+       struct scst_vdisk_dev *virt_dev;
+
+       TRACE_ENTRY();
+
+       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
+               res = -EINTR;
+               goto out;
+       }
+
+       seq_printf(seq, "%-17s %-11s %-11s %-15s %s\n",
+                  "Name", "Size(MB)", "Block size", "Options", "File name");
+
+       list_for_each_entry(virt_dev, &vdisk_dev_list, vdisk_dev_list_entry) {
+               int c;
+               seq_printf(seq, "%-17s %-11d %-12d", virt_dev->name,
+                       (uint32_t)(virt_dev->file_size >> 20),
+                       virt_dev->block_size);
+               c = 0;
+               if (virt_dev->wt_flag) {
+                       seq_printf(seq, "WT ");
+                       c += 3;
+               }
+               if (virt_dev->nv_cache) {
+                       seq_printf(seq, "NV ");
+                       c += 3;
+               }
+               if (virt_dev->dev != NULL) {
+                       if (virt_dev->dev->rd_only) {
+                               seq_printf(seq, "RO ");
+                               c += 3;
+                       }
+               } else if (virt_dev->rd_only) {
+                       seq_printf(seq, "RO ");
+                       c += 3;
+               }
+               if (virt_dev->o_direct_flag) {
+                       seq_printf(seq, "DR ");
+                       c += 3;
+               }
+               if (virt_dev->nullio) {
+                       seq_printf(seq, "NIO ");
+                       c += 4;
+               }
+               if (virt_dev->blockio) {
+                       seq_printf(seq, "BIO ");
+                       c += 4;
+               }
+               if (virt_dev->removable) {
+                       seq_printf(seq, "RM ");
+                       c += 4;
+               }
+               while (c < 16) {
+                       seq_printf(seq, " ");
+                       c++;
+               }
+               seq_printf(seq, "%s\n", virt_dev->file_name);
+       }
+       mutex_unlock(&scst_vdisk_mutex);
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int vdisk_proc_mgmt_cmd(const char *buffer, int length,
+                              struct scst_dev_type *dev_type)
+{
+       int res = 0, action;
+       char *p, *name, *file_name, *i_buf;
+       struct scst_vdisk_dev *virt_dev, *vv;
+       uint32_t block_size = DEF_DISK_BLOCKSIZE;
+       int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
+       size_t len;
+
+       TRACE_ENTRY();
+
+       if ((length == 0) || (buffer == NULL) || (buffer[0] == '\0'))
+               goto out;
+
+       i_buf = kmalloc(length+1, GFP_KERNEL);
+       if (i_buf == NULL) {
+               PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
+                       length+1);
+               goto out;
+       }
+
+       memcpy(i_buf, buffer, length);
+       i_buf[length] = '\0';
+
+       if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
+               res = -EINTR;
+               goto out_free;
+       }
+
+       p = i_buf;
+       if (p[strlen(p) - 1] == '\n')
+               p[strlen(p) - 1] = '\0';
+       if (!strncmp("close ", p, 6)) {
+               p += 6;
+               action = 0;
+       } else if (!strncmp("open ", p, 5)) {
+               p += 5;
+               action = 1;
+       } else if (!strncmp("resync_size ", p, 12)) {
+               p += 12;
+               action = 2;
+       } else {
+               PRINT_ERROR("Unknown action \"%s\"", p);
+               res = -EINVAL;
+               goto out_up;
+       }
+
+       while (isspace(*p) && *p != '\0')
+               p++;
+       name = p;
+       while (!isspace(*p) && *p != '\0')
+               p++;
+       *p++ = '\0';
+       if (*name == '\0') {
+               PRINT_ERROR("%s", "Name required");
+               res = -EINVAL;
+               goto out_up;
+       } else if (strlen(name) >= sizeof(virt_dev->name)) {
+               PRINT_ERROR("Name is too long (max %zd "
+                       "characters)", sizeof(virt_dev->name)-1);
+               res = -EINVAL;
+               goto out_up;
+       }
+
+       if (action == 1) {
+               /* open */
+               virt_dev = NULL;
+               list_for_each_entry(vv, &vdisk_dev_list,
+                                       vdisk_dev_list_entry) {
+                       if (strcmp(vv->name, name) == 0) {
+                               virt_dev = vv;
                                break;
                        }
                }
@@ -2982,13 +4122,16 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
                        goto out_up;
                }
 
-               virt_dev = vdisk_alloc_dev();
+               /* It's going to be removed code, anyway */
+               virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
                if (virt_dev == NULL) {
                        TRACE(TRACE_OUT_OF_MEM, "%s",
                                  "Allocation of virt_dev failed");
                        res = -ENOMEM;
                        goto out_up;
                }
+               spin_lock_init(&virt_dev->flags_lock);
+               virt_dev->vdt = &fileio_type.parent_vdt;
 
                while (isspace(*p) && *p != '\0')
                        p++;
@@ -3036,388 +4179,143 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
 #else
                                PRINT_INFO("%s flag doesn't currently"
                                        " work, ignoring it, use fileio_tgt "
-                                       "in O_DIRECT mode instead", "O_DIRECT");
-#endif
-                       } else if (!strncmp("NULLIO", p, 6)) {
-                               p += 6;
-                               virt_dev->nullio = 1;
-                               TRACE_DBG("%s", "NULLIO");
-                       } else if (!strncmp("BLOCKIO", p, 7)) {
-                               p += 7;
-                               virt_dev->blockio = 1;
-                               TRACE_DBG("%s", "BLOCKIO");
-                       } else if (!strncmp("REMOVABLE", p, 9)) {
-                               p += 9;
-                               virt_dev->removable = 1;
-                               TRACE_DBG("%s", "REMOVABLE");
-                       } else {
-                               PRINT_ERROR("Unknown flag \"%s\"", p);
-                               res = -EINVAL;
-                               goto out_free_vdev;
-                       }
-                       while (isspace(*p) && *p != '\0')
-                               p++;
-               }
-
-               if (!virt_dev->nullio && (*file_name != '/')) {
-                       PRINT_ERROR("File path \"%s\" is not "
-                               "absolute", file_name);
-                       res = -EINVAL;
-                       goto out_up;
-               }
-
-               strcpy(virt_dev->name, name);
-
-               scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx",
-                               vdisk_gen_dev_id_num(virt_dev));
-               TRACE_DBG("usn %s", virt_dev->usn);
-
-               len = strlen(file_name) + 1;
-               virt_dev->file_name = kmalloc(len, GFP_KERNEL);
-               if (virt_dev->file_name == NULL) {
-                       TRACE(TRACE_OUT_OF_MEM, "%s",
-                                 "Allocation of file_name failed");
-                       res = -ENOMEM;
-                       goto out_free_vdev;
-               }
-               strncpy(virt_dev->file_name, file_name, len);
-
-               list_add_tail(&virt_dev->vdisk_dev_list_entry,
-                                 &vdisk_dev_list);
-
-               if (virt_dev->blockio) {
-                       vdisk_report_registering("BLOCKIO", virt_dev);
-                       virt_dev->virt_id =
-                               scst_register_virtual_device(&vdisk_blk_devtype,
-                                                        virt_dev->name);
-               } else if (virt_dev->nullio) {
-                       vdisk_report_registering("NULLIO", virt_dev);
-                       virt_dev->virt_id =
-                              scst_register_virtual_device(&vdisk_null_devtype,
-                                                        virt_dev->name);
-               } else {
-                       vdisk_report_registering("FILEIO", virt_dev);
-                       virt_dev->virt_id =
-                              scst_register_virtual_device(&vdisk_file_devtype,
-                                                        virt_dev->name);
-               }
-               if (virt_dev->virt_id < 0) {
-                       res = virt_dev->virt_id;
-                       goto out_free_vpath;
-               }
-               TRACE_DBG("Added virt_dev (name %s, file name %s, "
-                       "id %d, block size %d) to "
-                       "vdisk_dev_list", virt_dev->name,
-                       virt_dev->file_name, virt_dev->virt_id,
-                       virt_dev->block_size);
-       } else if (action == 0) {       /* close */
-               virt_dev = NULL;
-               list_for_each_entry(vv, &vdisk_dev_list,
-                                       vdisk_dev_list_entry) {
-                       if (strcmp(vv->name, name) == 0) {
-                               virt_dev = vv;
-                               break;
-                       }
-               }
-               if (virt_dev == NULL) {
-                       PRINT_ERROR("Device %s not found", name);
-                       res = -EINVAL;
-                       goto out_up;
-               }
-               scst_unregister_virtual_device(virt_dev->virt_id);
-               PRINT_INFO("Virtual device %s unregistered",
-                       virt_dev->name);
-               TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
-
-               list_del(&virt_dev->vdisk_dev_list_entry);
-
-               kfree(virt_dev->file_name);
-               kfree(virt_dev);
-       } else {        /* resync_size */
-               virt_dev = NULL;
-               list_for_each_entry(vv, &vdisk_dev_list,
-                                       vdisk_dev_list_entry) {
-                       if (strcmp(vv->name, name) == 0) {
-                               virt_dev = vv;
-                               break;
-                       }
-               }
-               if (virt_dev == NULL) {
-                       PRINT_ERROR("Device %s not found", name);
-                       res = -EINVAL;
-                       goto out_up;
-               }
-
-               res = vdisk_resync_size(virt_dev);
-               if (res != 0)
-                       goto out_up;
-       }
-       res = length;
-
-out_up:
-       mutex_unlock(&scst_vdisk_mutex);
-
-out:
-       TRACE_EXIT_RES(res);
-       return res;
-
-out_free_vpath:
-       list_del(&virt_dev->vdisk_dev_list_entry);
-       kfree(virt_dev->file_name);
-
-out_free_vdev:
-       kfree(virt_dev);
-       goto out_up;
-}
-
-/* scst_vdisk_mutex supposed to be held */
-static int vcdrom_open(char *p, char *name)
-{
-       struct scst_vdisk_dev *virt_dev, *vv;
-       char *file_name;
-       int len;
-       int res = 0;
-       int cdrom_empty;
-
-       virt_dev = NULL;
-       list_for_each_entry(vv, &vcdrom_dev_list, vdisk_dev_list_entry)
-       {
-               if (strcmp(vv->name, name) == 0) {
-                       virt_dev = vv;
-                       break;
-               }
-       }
-       if (virt_dev) {
-               PRINT_ERROR("Virtual device with name "
-                      "%s already exist", name);
-               res = -EINVAL;
-               goto out;
-       }
-
-       while (isspace(*p) && *p != '\0')
-               p++;
-       file_name = p;
-       while (!isspace(*p) && *p != '\0')
-               p++;
-       *p++ = '\0';
-       if (*file_name == '\0') {
-               cdrom_empty = 1;
-               TRACE_DBG("%s", "No media");
-       } else if (*file_name != '/') {
-               PRINT_ERROR("File path \"%s\" is not "
-                       "absolute", file_name);
-               res = -EINVAL;
-               goto out;
-       } else
-               cdrom_empty = 0;
-
-       virt_dev = vdisk_alloc_dev();
-       if (virt_dev == NULL) {
-               TRACE(TRACE_OUT_OF_MEM, "%s",
-                     "Allocation of virt_dev failed");
-               res = -ENOMEM;
-               goto out;
-       }
-       virt_dev->cdrom_empty = cdrom_empty;
-
-       strcpy(virt_dev->name, name);
-
-       scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx",
-                       vdisk_gen_dev_id_num(virt_dev));
-       TRACE_DBG("usn %s", virt_dev->usn);
-
-       if (!virt_dev->cdrom_empty) {
-               len = strlen(file_name) + 1;
-               virt_dev->file_name = kmalloc(len, GFP_KERNEL);
-               if (virt_dev->file_name == NULL) {
-                       TRACE(TRACE_OUT_OF_MEM, "%s",
-                             "Allocation of file_name failed");
-                       res = -ENOMEM;
-                       goto out_free_vdev;
-               }
-               strncpy(virt_dev->file_name, file_name, len);
-       }
-
-       list_add_tail(&virt_dev->vdisk_dev_list_entry,
-                     &vcdrom_dev_list);
-
-       PRINT_INFO("Registering virtual CDROM %s", name);
-
-       virt_dev->virt_id =
-           scst_register_virtual_device(&vcdrom_devtype,
-                                        virt_dev->name);
-       if (virt_dev->virt_id < 0) {
-               res = virt_dev->virt_id;
-               goto out_free_vpath;
-       }
-       TRACE_DBG("Added virt_dev (name %s file_name %s id %d) "
-                 "to vcdrom_dev_list", virt_dev->name,
-                 virt_dev->file_name, virt_dev->virt_id);
-
-out:
-       return res;
-
-out_free_vpath:
-       list_del(&virt_dev->vdisk_dev_list_entry);
-       kfree(virt_dev->file_name);
-
-out_free_vdev:
-       kfree(virt_dev);
-       goto out;
-}
-
-/* scst_vdisk_mutex supposed to be held */
-static int vcdrom_close(char *name)
-{
-       struct scst_vdisk_dev *virt_dev, *vv;
-       int res = 0;
-
-       virt_dev = NULL;
-       list_for_each_entry(vv, &vcdrom_dev_list,
-                           vdisk_dev_list_entry)
-       {
-               if (strcmp(vv->name, name) == 0) {
-                       virt_dev = vv;
-                       break;
-               }
-       }
-       if (virt_dev == NULL) {
-               PRINT_ERROR("Virtual device with name "
-                      "%s not found", name);
-               res = -EINVAL;
-               goto out;
-       }
-       scst_unregister_virtual_device(virt_dev->virt_id);
-       PRINT_INFO("Virtual device %s unregistered",
-               virt_dev->name);
-       TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
-
-       list_del(&virt_dev->vdisk_dev_list_entry);
-
-       kfree(virt_dev->file_name);
-       kfree(virt_dev);
-
-out:
-       return res;
-}
-
-/* scst_vdisk_mutex supposed to be held */
-static int vcdrom_change(char *p, char *name)
-{
-       loff_t err;
-       struct scst_vdisk_dev *virt_dev, *vv;
-       char *file_name, *fn = NULL, *old_fn;
-       int len;
-       int res = 0;
+                                       "in O_DIRECT mode instead", "O_DIRECT");
+#endif
+                       } else if (!strncmp("NULLIO", p, 6)) {
+                               p += 6;
+                               virt_dev->nullio = 1;
+                               virt_dev->vdt = &nullio_type.parent_vdt;
+                               TRACE_DBG("%s", "NULLIO");
+                       } else if (!strncmp("BLOCKIO", p, 7)) {
+                               p += 7;
+                               virt_dev->blockio = 1;
+                               virt_dev->vdt = &blockio_type.parent_vdt;
+                               TRACE_DBG("%s", "BLOCKIO");
+                       } else if (!strncmp("REMOVABLE", p, 9)) {
+                               p += 9;
+                               virt_dev->removable = 1;
+                               TRACE_DBG("%s", "REMOVABLE");
+                       } else {
+                               PRINT_ERROR("Unknown flag \"%s\"", p);
+                               res = -EINVAL;
+                               goto out_free_vdev;
+                       }
+                       while (isspace(*p) && *p != '\0')
+                               p++;
+               }
 
-       virt_dev = NULL;
-       list_for_each_entry(vv, &vcdrom_dev_list,
-                           vdisk_dev_list_entry) {
-               if (strcmp(vv->name, name) == 0) {
-                       virt_dev = vv;
-                       break;
+               if (!virt_dev->nullio && (*file_name != '/')) {
+                       PRINT_ERROR("File path \"%s\" is not "
+                               "absolute", file_name);
+                       res = -EINVAL;
+                       goto out_up;
                }
-       }
-       if (virt_dev == NULL) {
-               PRINT_ERROR("Virtual device with name "
-                      "%s not found", name);
-               res = -EINVAL;
-               goto out;
-       }
 
-       while (isspace(*p) && *p != '\0')
-               p++;
-       file_name = p;
-       while (!isspace(*p) && *p != '\0')
-               p++;
-       *p++ = '\0';
-       if (*file_name == '\0') {
-               virt_dev->cdrom_empty = 1;
-               TRACE_DBG("%s", "No media");
-       } else if (*file_name != '/') {
-               PRINT_ERROR("File path \"%s\" is not "
-                       "absolute", file_name);
-               res = -EINVAL;
-               goto out;
-       } else
-               virt_dev->cdrom_empty = 0;
+               strcpy(virt_dev->name, name);
 
-       old_fn = virt_dev->file_name;
+               scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx",
+                               vdisk_gen_dev_id_num(virt_dev));
+               TRACE_DBG("usn %s", virt_dev->usn);
 
-       if (!virt_dev->cdrom_empty && !virt_dev->nullio) {
                len = strlen(file_name) + 1;
-               fn = kmalloc(len, GFP_KERNEL);
-               if (fn == NULL) {
+               virt_dev->file_name = kmalloc(len, GFP_KERNEL);
+               if (virt_dev->file_name == NULL) {
                        TRACE(TRACE_OUT_OF_MEM, "%s",
-                               "Allocation of file_name failed");
+                                 "Allocation of file_name failed");
                        res = -ENOMEM;
-                       goto out;
+                       goto out_free_vdev;
                }
+               strncpy(virt_dev->file_name, file_name, len);
 
-               strncpy(fn, file_name, len);
-               virt_dev->file_name = fn;
+               list_add_tail(&virt_dev->vdisk_dev_list_entry,
+                                 &vdisk_dev_list);
 
-               res = vdisk_get_file_size(virt_dev->file_name,
-                               virt_dev->blockio, &err);
-               if (res != 0)
-                       goto out_free;
-       } else {
-               err = 0;
-               virt_dev->file_name = NULL;
-       }
+               vdisk_report_registering(virt_dev);
+               virt_dev->virt_id = scst_register_virtual_device(
+                       virt_dev->vdt->vdt_devt, virt_dev->name);
+               if (virt_dev->virt_id < 0) {
+                       res = virt_dev->virt_id;
+                       goto out_free_vpath;
+               }
+               TRACE_DBG("Added virt_dev (name %s, file name %s, "
+                       "id %d, block size %d) to "
+                       "vdisk_dev_list", virt_dev->name,
+                       virt_dev->file_name, virt_dev->virt_id,
+                       virt_dev->block_size);
+       } else if (action == 0) {       /* close */
+               virt_dev = NULL;
+               list_for_each_entry(vv, &vdisk_dev_list,
+                                       vdisk_dev_list_entry) {
+                       if (strcmp(vv->name, name) == 0) {
+                               virt_dev = vv;
+                               break;
+                       }
+               }
+               if (virt_dev == NULL) {
+                       PRINT_ERROR("Device %s not found", name);
+                       res = -EINVAL;
+                       goto out_up;
+               }
+               scst_unregister_virtual_device(virt_dev->virt_id);
+               PRINT_INFO("Virtual device %s unregistered",
+                       virt_dev->name);
+               TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
 
-        if (virt_dev->nullio)
-               err = VDISK_NULLIO_SIZE;
+               list_del(&virt_dev->vdisk_dev_list_entry);
 
-       res = scst_suspend_activity(true);
-       if (res != 0)
-               goto out_free;
+               kfree(virt_dev->file_name);
+               kfree(virt_dev);
+       } else {        /* resync_size */
+               virt_dev = NULL;
+               list_for_each_entry(vv, &vdisk_dev_list,
+                                       vdisk_dev_list_entry) {
+                       if (strcmp(vv->name, name) == 0) {
+                               virt_dev = vv;
+                               break;
+                       }
+               }
+               if (virt_dev == NULL) {
+                       PRINT_ERROR("Device %s not found", name);
+                       res = -EINVAL;
+                       goto out_up;
+               }
 
-       if (virt_dev->prevent_allow_medium_removal) {
-               PRINT_ERROR("Prevent medium removal for "
-                       "virtual device with name %s", name);
-               res = -EINVAL;
-               goto out_free_resume;
+               res = __vdisk_resync_size(virt_dev);
+               if (res != 0)
+                       goto out_up;
        }
+       res = length;
 
-       virt_dev->file_size = err;
-       virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift;
-       if (!virt_dev->cdrom_empty)
-               virt_dev->media_changed = 1;
+out_up:
+       mutex_unlock(&scst_vdisk_mutex);
 
-       scst_dev_del_all_thr_data(virt_dev->dev);
+out_free:
+       kfree(i_buf);
 
-       if (!virt_dev->cdrom_empty) {
-               PRINT_INFO("Changed SCSI target virtual cdrom %s "
-                       "(file=\"%s\", fs=%lldMB, bs=%d, nblocks=%lld,"
-                       " cyln=%lld%s)", virt_dev->name, virt_dev->file_name,
-                       virt_dev->file_size >> 20, virt_dev->block_size,
-                       (long long unsigned int)virt_dev->nblocks,
-                       (long long unsigned int)virt_dev->nblocks/64/32,
-                       virt_dev->nblocks < 64*32 ? " !WARNING! cyln less "
-                                                       "than 1" : "");
-       } else {
-               PRINT_INFO("Removed media from SCSI target virtual cdrom %s",
-                       virt_dev->name);
-       }
+out:
+       TRACE_EXIT_RES(res);
+       return res;
 
-       kfree(old_fn);
+out_free_vpath:
+       list_del(&virt_dev->vdisk_dev_list_entry);
+       kfree(virt_dev->file_name);
 
-out_resume:
-       scst_resume_activity();
+out_free_vdev:
+       kfree(virt_dev);
+       goto out_up;
+}
 
-out:
-       return res;
+/*
+ * Called when a file in the /proc/VDISK_NAME/VDISK_NAME is written
+ */
+static int vdisk_write_proc(char *buffer, char **start, off_t offset,
+       int length, int *eof, struct scst_dev_type *dev_type)
+{
+       int res;
 
-out_free:
-       virt_dev->file_name = old_fn;
-       kfree(fn);
-       goto out;
+       res = vdisk_proc_mgmt_cmd(buffer, length, dev_type);
 
-out_free_resume:
-       virt_dev->file_name = old_fn;
-       kfree(fn);
-       goto out_resume;
+       return res;
 }
 
 /*
@@ -3452,24 +4350,34 @@ out:
        return res;
 }
 
-/*
- * Called when a file in the /proc/VCDROM_NAME/VCDROM_NAME is written
- */
-static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
-       int length, int *eof, struct scst_dev_type *dev_type)
+static int vcdrom_proc_mgmt_cmd(const char *buffer, int length,
+       struct scst_dev_type *dev_type)
 {
        int res = 0, action;
-       char *p, *name;
+       char *p, *name, *i_buf;
        struct scst_vdisk_dev *virt_dev;
 
        TRACE_ENTRY();
 
+       if ((length == 0) || (buffer == NULL) || (buffer[0] == '\0'))
+               goto out;
+
+       i_buf = kmalloc(length+1, GFP_KERNEL);
+       if (i_buf == NULL) {
+               PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
+                       length+1);
+               goto out;
+       }
+
+       memcpy(i_buf, buffer, length);
+       i_buf[length] = '\0';
+
        if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
                res = -EINTR;
-               goto out;
+               goto out_free;
        }
 
-       p = buffer;
+       p = i_buf;
        if (p[strlen(p) - 1] == '\n')
                p[strlen(p) - 1] = '\0';
        if (!strncmp("close ", p, 6)) {
@@ -3506,17 +4414,17 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
 
        if (action == 2) {
                /* open */
-               res = vcdrom_open(p, name);
+               res = vdev_open(&vcdrom_type.parent_vdt, p, name);
                if (res != 0)
                        goto out_up;
        } else if (action == 1) {
                /* change */
-               res = vcdrom_change(p, name);
+               res = vcdrom_change(&vcdrom_type.parent_vdt, p, name);
                if (res != 0)
                        goto out_up;
        } else {
                /* close */
-               res = vcdrom_close(name);
+               res = vdev_close(&vcdrom_type.parent_vdt, name);
                if (res != 0)
                        goto out_up;
        }
@@ -3525,11 +4433,27 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
 out_up:
        mutex_unlock(&scst_vdisk_mutex);
 
+out_free:
+       kfree(i_buf);
+
 out:
        TRACE_EXIT_RES(res);
        return res;
 }
 
+/*
+ * Called when a file in the /proc/VCDROM_NAME/VCDROM_NAME is written
+ */
+static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
+       int length, int *eof, struct scst_dev_type *dev_type)
+{
+       int res;
+
+       res = vcdrom_proc_mgmt_cmd(buffer, length, dev_type);
+
+       return res;
+}
+
 static int vdisk_help_info_show(struct seq_file *seq, void *v)
 {
        char *s = (char *)seq->private;
@@ -3562,8 +4486,7 @@ static int vdisk_proc_help_build(struct scst_dev_type *dev_type)
                                   &vdisk_help_proc_data);
        if (p == NULL) {
                PRINT_ERROR("Not enough memory to register dev "
-                    "handler %s entry %s in /proc",
-                     dev_type->name, VDISK_PROC_HELP);
+                    "handler %s entry %s in /proc", "vdisk", VDISK_PROC_HELP);
                res = -ENOMEM;
        }
 
@@ -3584,18 +4507,25 @@ static void vdisk_proc_help_destroy(struct scst_dev_type *dev_type)
        TRACE_EXIT();
 }
 
-static int __init init_scst_vdisk(struct scst_dev_type *devtype)
+#endif /* CONFIG_SCST_PROC */
+
+static int __init init_scst_vdisk(struct scst_dev_type *devtype,
+       struct vdev_type *vdt)
 {
        int res = 0;
 
        TRACE_ENTRY();
 
+       vdt->vdt_devt = devtype;
+       devtype->devt_priv = vdt;
+
        devtype->module = THIS_MODULE;
 
        res = scst_register_virtual_dev_driver(devtype);
        if (res < 0)
                goto out;
 
+#ifdef CONFIG_SCST_PROC
        if (!devtype->no_proc) {
                res = scst_dev_handler_build_std_proc(devtype);
                if (res < 0)
@@ -3605,11 +4535,13 @@ static int __init init_scst_vdisk(struct scst_dev_type *devtype)
                if (res < 0)
                        goto out_destroy_proc;
        }
+#endif
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
+#ifdef CONFIG_SCST_PROC
 out_destroy_proc:
        if (!devtype->no_proc)
                scst_dev_handler_destroy_std_proc(devtype);
@@ -3617,6 +4549,7 @@ out_destroy_proc:
 out_unreg:
        scst_unregister_virtual_dev_driver(devtype);
        goto out;
+#endif
 }
 
 static void exit_scst_vdisk(struct scst_dev_type *devtype,
@@ -3645,10 +4578,12 @@ static void exit_scst_vdisk(struct scst_dev_type *devtype,
        }
        mutex_unlock(&scst_vdisk_mutex);
 
+#ifdef CONFIG_SCST_PROC
        if (!devtype->no_proc) {
                vdisk_proc_help_destroy(devtype);
                scst_dev_handler_destroy_std_proc(devtype);
        }
+#endif
 
        scst_unregister_virtual_dev_driver(devtype);
 
@@ -3656,6 +4591,110 @@ static void exit_scst_vdisk(struct scst_dev_type *devtype,
        return;
 }
 
+static void __init init_vdev_type(struct vdev_type *vdt)
+{
+       /* vdt supposed to be already zeroed */
+
+       vdt->vfns.vdev_create = vdev_create;
+       vdt->vfns.vdev_destroy = vdev_destroy;
+       vdt->vfns.vdev_open = vdev_open;
+       vdt->vfns.vdev_close = vdev_close;
+       vdt->vfns.vdev_del = vdev_del;
+       vdt->vfns.vdev_init = vdev_init;
+       vdt->vfns.vdev_deinit = vdev_deinit;
+}
+
+static void __init init_fileio_type(void)
+{
+       struct vdev_type *vdt = &fileio_type.parent_vdt;
+
+       init_vdev_type(vdt);
+
+       vdt->vdt_name = "FILEIO";
+       vdt->help_string = "Usage:\n"
+               "       echo \"open|close|resync_size NAME [FILE_NAME "
+               "[BLOCK_SIZE] [WRITE_THROUGH] [READ_ONLY] [O_DIRECT] "
+               "[NV_CACHE] [REMOVABLE]]\" >mgmt\n";
+
+       fileio_type.parent_vdt_vfns = vdt->vfns;
+
+       vdt->vfns.vdev_add = vdisk_add;
+       vdt->vfns.vdev_find = vdisk_find;
+       vdt->vfns.parse_cmd = vdisk_parse_cmd;
+       vdt->vfns.perform_cmd = vdisk_perform_cmd;
+       vdt->vfns.parse_option = vdisk_fileio_parse_option;
+       vdt->vfns.pre_register = vdisk_fileio_pre_register;
+
+       return;
+}
+
+static void __init init_blockio_type(void)
+{
+       struct vdev_type *vdt = &blockio_type.parent_vdt;
+
+       init_vdev_type(vdt);
+
+       vdt->vdt_name = "BLOCKIO";
+       vdt->help_string = "Usage:\n"
+               "       echo \"open|close|resync_size NAME [DEVICE_NAME "
+               "[BLOCK_SIZE] [READ_ONLY] [REMOVABLE]]\" >mgmt\n";
+
+       blockio_type.parent_vdt_vfns = vdt->vfns;
+
+       vdt->vfns.vdev_init = vdisk_blockio_init;
+       vdt->vfns.vdev_add = vdisk_add;
+       vdt->vfns.vdev_find = vdisk_find;
+       vdt->vfns.parse_cmd = vdisk_parse_cmd;
+       vdt->vfns.perform_cmd = vdisk_perform_cmd;
+       vdt->vfns.parse_option = vdisk_parse_option;
+       vdt->vfns.pre_register = vdisk_blockio_pre_register;
+
+       return;
+}
+static void __init init_nullio_type(void)
+{
+       struct vdev_type *vdt = &nullio_type.parent_vdt;
+
+       init_vdev_type(vdt);
+
+       vdt->vdt_name = "NULLIO";
+       vdt->help_string = "Usage:\n"
+               "       echo \"open|close NAME [none [BLOCK_SIZE] [READ_ONLY] "
+               "[REMOVABLE]]\" >mgmt\n";
+
+       nullio_type.parent_vdt_vfns = vdt->vfns;
+
+       vdt->vfns.vdev_init = vdisk_nullio_init;
+       vdt->vfns.vdev_add = vdisk_add;
+       vdt->vfns.vdev_find = vdisk_find;
+       vdt->vfns.parse_cmd = vdisk_parse_cmd;
+       vdt->vfns.parse_option = vdisk_parse_option;
+       vdt->vfns.perform_cmd = vdisk_perform_cmd;
+
+       return;
+}
+static void __init init_vcdrom_type(void)
+{
+       struct vdev_type *vdt = &vcdrom_type.parent_vdt;
+
+       init_vdev_type(vdt);
+
+       vdt->vdt_name = "VCDROM";
+       vdt->help_string = "Usage:\n"
+               "       echo \"open|change|close NAME [FILE_NAME]\" >mgmt\n";
+
+       vcdrom_type.parent_vdt_vfns = vdt->vfns;
+
+       vdt->vfns.vdev_init = vcdrom_init;
+       vdt->vfns.vdev_add = vcdrom_add;
+       vdt->vfns.vdev_find = vcdrom_find;
+       vdt->vfns.parse_cmd = vcdrom_parse_cmd;
+       vdt->vfns.perform_cmd = vcdrom_perform_cmd;
+       vdt->vfns.pre_register = vcdrom_pre_register;
+
+       return;
+}
+
 static int __init init_scst_vdisk_driver(void)
 {
        int res;
@@ -3683,19 +4722,24 @@ static int __init init_scst_vdisk_driver(void)
 
        atomic_set(&nullio_thr_data.hdr.ref, 1); /* never destroy it */
 
-       res = init_scst_vdisk(&vdisk_file_devtype);
+       init_fileio_type();
+       init_blockio_type();
+       init_nullio_type();
+       init_vcdrom_type();
+
+       res = init_scst_vdisk(&vdisk_file_devtype, &fileio_type.parent_vdt);
        if (res != 0)
                goto out_free_slab;
 
-       res = init_scst_vdisk(&vdisk_blk_devtype);
+       res = init_scst_vdisk(&vdisk_blk_devtype, &blockio_type.parent_vdt);
        if (res != 0)
                goto out_free_vdisk;
 
-       res = init_scst_vdisk(&vdisk_null_devtype);
+       res = init_scst_vdisk(&vdisk_null_devtype, &nullio_type.parent_vdt);
        if (res != 0)
                goto out_free_blk;
 
-       res = init_scst_vdisk(&vcdrom_devtype);
+       res = init_scst_vdisk(&vcdrom_devtype, &vcdrom_type.parent_vdt);
        if (res != 0)
                goto out_free_null;
 
index 305eda6..024f9b1 100644 (file)
@@ -57,11 +57,11 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
        const uint8_t *sense, int sense_len, int flags);
 static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
 static void scst_release_space(struct scst_cmd *cmd);
-static void scst_sess_free_tgt_devs(struct scst_session *sess);
 static void scst_unblock_cmds(struct scst_device *dev);
 static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev);
 static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
        struct scst_acg_dev *acg_dev);
+static void scst_tgt_retry_timer_fn(unsigned long arg);
 
 #ifdef CONFIG_SCST_DEBUG_TM
 static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
@@ -1244,6 +1244,44 @@ restart1:
        return;
 }
 
+struct scst_tgt *scst_alloc_tgt(struct scst_tgt_template *tgtt)
+{
+       struct scst_tgt *tgt;
+
+       TRACE_ENTRY();
+
+       tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
+       if (tgt == NULL) {
+               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of tgt failed");
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&tgt->sess_list);
+       init_waitqueue_head(&tgt->unreg_waitQ);
+       tgt->tgtt = tgtt;
+       tgt->sg_tablesize = tgtt->sg_tablesize;
+       spin_lock_init(&tgt->tgt_lock);
+       INIT_LIST_HEAD(&tgt->retry_cmd_list);
+       atomic_set(&tgt->finished_cmds, 0);
+       init_timer(&tgt->retry_timer);
+       tgt->retry_timer.data = (unsigned long)tgt;
+       tgt->retry_timer.function = scst_tgt_retry_timer_fn;
+
+out:
+       TRACE_EXIT_HRES((unsigned long)tgt);
+       return tgt;
+}
+
+void scst_free_tgt(struct scst_tgt *tgt)
+{
+       TRACE_ENTRY();
+
+       kfree(tgt);
+
+       TRACE_EXIT();
+       return;
+}
+
 /* Called under scst_mutex and suspended activity */
 int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
 {
@@ -1310,6 +1348,7 @@ void scst_free_device(struct scst_device *dev)
        }
 #endif
 
+       kfree(dev->virt_name);
        __exit_io_context(dev->dev_io_ctx);
 
        kfree(dev);
@@ -1356,6 +1395,16 @@ out:
        return res;
 }
 
+void scst_acg_dev_destroy(struct scst_acg_dev *acg_dev)
+{
+       TRACE_ENTRY();
+
+       kmem_cache_free(scst_acgd_cachep, acg_dev);
+
+       TRACE_EXIT();
+       return;
+}
+
 /* The activity supposed to be suspended and scst_mutex held */
 static void scst_free_acg_dev(struct scst_acg_dev *acg_dev)
 {
@@ -1366,7 +1415,11 @@ static void scst_free_acg_dev(struct scst_acg_dev *acg_dev)
        list_del(&acg_dev->acg_dev_list_entry);
        list_del(&acg_dev->dev_acg_dev_list_entry);
 
-       kmem_cache_free(scst_acgd_cachep, acg_dev);
+       if (acg_dev->acg_dev_kobj_initialized) {
+               kobject_del(&acg_dev->acg_dev_kobj);
+               kobject_put(&acg_dev->acg_dev_kobj);
+       } else
+               scst_acg_dev_destroy(acg_dev);
 
        TRACE_EXIT();
        return;
@@ -1505,16 +1558,8 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
        if (sess->tgt->tgtt->unchecked_isa_dma || ini_unchecked_isa_dma)
                scst_sgv_pool_use_dma(tgt_dev);
 
-       if (dev->scsi_dev != NULL) {
-               TRACE_MGMT_DBG("host=%d, channel=%d, id=%d, lun=%d, "
-                     "SCST lun=%lld", dev->scsi_dev->host->host_no,
-                     dev->scsi_dev->channel, dev->scsi_dev->id,
-                     dev->scsi_dev->lun,
-                     (long long unsigned int)tgt_dev->lun);
-       } else {
-               TRACE_MGMT_DBG("Virtual device %s on SCST lun=%lld",
-                      dev->virt_name, (long long unsigned int)tgt_dev->lun);
-       }
+       TRACE_MGMT_DBG("Device %s on SCST lun=%lld",
+              dev->virt_name, (long long unsigned int)tgt_dev->lun);
 
        spin_lock_init(&tgt_dev->tgt_dev_lock);
        INIT_LIST_HEAD(&tgt_dev->UA_list);
@@ -1750,7 +1795,7 @@ out_free:
  * scst_mutex supposed to be held, there must not be parallel activity in this
  * session.
  */
-static void scst_sess_free_tgt_devs(struct scst_session *sess)
+void scst_sess_free_tgt_devs(struct scst_session *sess)
 {
        int i;
        struct scst_tgt_dev *tgt_dev, *t;
@@ -1811,20 +1856,9 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
        if (gen_scst_report_luns_changed)
                scst_report_luns_changed(acg);
 
-       if (dev->virt_name != NULL) {
-               PRINT_INFO("Added device %s to group %s (LUN %lld, "
-                       "rd_only %d)", dev->virt_name, acg->acg_name,
-                       (long long unsigned int)lun,
-                       read_only);
-       } else {
-               PRINT_INFO("Added device %d:%d:%d:%d to group %s (LUN "
-                       "%lld, rd_only %d)",
-                       dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun, acg->acg_name,
-                       (long long unsigned int)lun,
-                       read_only);
-       }
+       PRINT_INFO("Added device %s to group %s (LUN %lld, "
+               "rd_only %d)", dev->virt_name, acg->acg_name,
+               (long long unsigned int)lun, read_only);
 
 out:
        TRACE_EXIT_RES(res);
@@ -1872,15 +1906,8 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev,
        if (gen_scst_report_luns_changed)
                scst_report_luns_changed(acg);
 
-       if (dev->virt_name != NULL) {
-               PRINT_INFO("Removed device %s from group %s",
-                       dev->virt_name, acg->acg_name);
-       } else {
-               PRINT_INFO("Removed device %d:%d:%d:%d from group %s",
-                       dev->scsi_dev->host->host_no,
-                       dev->scsi_dev->channel, dev->scsi_dev->id,
-                       dev->scsi_dev->lun, acg->acg_name);
-       }
+       PRINT_INFO("Removed device %s from group %s", dev->virt_name,
+               acg->acg_name);
 
 out:
        TRACE_EXIT_RES(res);
@@ -2158,9 +2185,7 @@ static void scst_send_release(struct scst_device *dev)
        req = scsi_allocate_request(scsi_dev, GFP_KERNEL);
        if (req == NULL) {
                PRINT_ERROR("Allocation of scsi_request failed: unable "
-                           "to RELEASE device %d:%d:%d:%d",
-                           scsi_dev->host->host_no, scsi_dev->channel,
-                           scsi_dev->id, scsi_dev->lun);
+                           "to RELEASE device %s", dev->virt_name);
                goto out;
        }
 
@@ -2347,10 +2372,21 @@ void scst_free_session(struct scst_session *sess)
 
        scst_sess_free_tgt_devs(sess);
 
+       /* Called under lock to protect from too early tgt release */
        wake_up_all(&sess->tgt->unreg_waitQ);
 
        mutex_unlock(&scst_mutex);
 
+       scst_sess_sysfs_put(sess);
+
+       TRACE_EXIT();
+       return;
+}
+
+void scst_release_session(struct scst_session *sess)
+{
+       TRACE_ENTRY();
+
        kfree(sess->initiator_name);
        kmem_cache_free(scst_sess_cachep, sess);
 
@@ -2611,7 +2647,7 @@ void scst_check_retries(struct scst_tgt *tgt)
        return;
 }
 
-void scst_tgt_retry_timer_fn(unsigned long arg)
+static void scst_tgt_retry_timer_fn(unsigned long arg)
 {
        struct scst_tgt *tgt = (struct scst_tgt *)arg;
        unsigned long flags;
@@ -3992,11 +4028,8 @@ int scst_obtain_device_parameters(struct scst_device *dev)
                        dev->tst = buffer[4+2] >> 5;
                        q = buffer[4+3] >> 4;
                        if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) {
-                               PRINT_ERROR("Too big QUEUE ALG %x, dev "
-                                       "%d:%d:%d:%d", dev->queue_alg,
-                                       dev->scsi_dev->host->host_no,
-                                       dev->scsi_dev->channel,
-                                       dev->scsi_dev->id, dev->scsi_dev->lun);
+                               PRINT_ERROR("Too big QUEUE ALG %x, dev %s",
+                                       dev->queue_alg, dev->virt_name);
                        }
                        dev->queue_alg = q;
                        dev->swp = (buffer[4+4] & 0x8) >> 3;
@@ -4011,12 +4044,10 @@ int scst_obtain_device_parameters(struct scst_device *dev)
                        dev->has_own_order_mgmt = !dev->queue_alg;
 
                        TRACE(TRACE_SCSI|TRACE_MGMT_MINOR,
-                               "Device %d:%d:%d:%d: TST %x, "
+                               "Device %s: TST %x, "
                                "QUEUE ALG %x, SWP %x, TAS %x, D_SENSE %d"
                                "has_own_order_mgmt %d",
-                               dev->scsi_dev->host->host_no,
-                               dev->scsi_dev->channel, dev->scsi_dev->id,
-                               dev->scsi_dev->lun, dev->tst, dev->queue_alg,
+                               dev->virt_name, dev->tst, dev->queue_alg,
                                dev->swp, dev->tas, dev->d_sense,
                                dev->has_own_order_mgmt);
 
@@ -4037,16 +4068,13 @@ int scst_obtain_device_parameters(struct scst_device *dev)
                                                SCST_SENSE_KEY_VALID,
                                                ILLEGAL_REQUEST, 0, 0)) {
                                        TRACE(TRACE_SCSI|TRACE_MGMT_MINOR,
-                                               "Device %d:%d:%d:%d doesn't "
+                                               "Device %s doesn't "
                                                "support control mode page, "
                                                "using defaults: TST %x, "
                                                "QUEUE ALG %x, SWP %x, "
                                                "TAS %x, D_SENSE %d, "
                                                "has_own_order_mgmt %d ",
-                                               dev->scsi_dev->host->host_no,
-                                               dev->scsi_dev->channel,
-                                               dev->scsi_dev->id,
-                                               dev->scsi_dev->lun,
+                                               dev->virt_name,
                                                dev->tst, dev->queue_alg,
                                                dev->swp, dev->tas,
                                                dev->d_sense,
@@ -4057,23 +4085,16 @@ int scst_obtain_device_parameters(struct scst_device *dev)
                                                sizeof(sense_buffer),
                                                SCST_SENSE_KEY_VALID,
                                                NOT_READY, 0, 0)) {
-                                       TRACE(TRACE_SCSI,
-                                               "Device %d:%d:%d:%d not ready",
-                                               dev->scsi_dev->host->host_no,
-                                               dev->scsi_dev->channel,
-                                               dev->scsi_dev->id,
-                                               dev->scsi_dev->lun);
+                                       TRACE(TRACE_SCSI, "Device %s not ready",
+                                               dev->virt_name);
                                        res = 0;
                                        goto out;
                                }
                        } else {
                                TRACE(TRACE_SCSI|TRACE_MGMT_MINOR,
                                        "Internal MODE SENSE to "
-                                       "device %d:%d:%d:%d failed: %x",
-                                       dev->scsi_dev->host->host_no,
-                                       dev->scsi_dev->channel,
-                                       dev->scsi_dev->id,
-                                       dev->scsi_dev->lun, res);
+                                       "device %s failed: %x",
+                                       dev->virt_name, res);
                                PRINT_BUFF_FLAG(TRACE_SCSI|TRACE_MGMT_MINOR,
                                        "MODE SENSE sense",
                                        sense_buffer, sizeof(sense_buffer));
@@ -5053,7 +5074,7 @@ static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff };
 static 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->lun == 0)) {
+       if (acg_dev->lun == 6) {
                unsigned long flags;
 
                if (tm_dbg_tgt_dev != NULL)
@@ -5065,8 +5086,9 @@ static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
                tm_dbg_on_state_passes =
                        tm_dbg_on_state_num_passes[tm_dbg_state];
                tm_dbg_tgt_dev = tgt_dev;
-               PRINT_INFO("LUN 0 connected from initiator %s is under "
+               PRINT_INFO("LUN %lld connected from initiator %s is under "
                        "TM debugging (tgt_dev %p)",
+                       (unsigned long long)tgt_dev->lun,
                        tgt_dev->sess->initiator_name, tgt_dev);
                spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
        }
index 7880a4a..91c8b75 100644 (file)
@@ -102,7 +102,9 @@ struct kmem_cache *scst_sess_cachep;
 struct kmem_cache *scst_acgd_cachep;
 
 struct list_head scst_acg_list;
+#ifdef CONFIG_SCST_PROC
 struct scst_acg *scst_default_acg;
+#endif
 
 spinlock_t scst_init_lock;
 wait_queue_head_t scst_init_cmd_list_waitQ;
@@ -188,21 +190,21 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
        }
 
        if (!vtt->detect) {
-               PRINT_ERROR("Target driver %s doesn't have a "
+               PRINT_ERROR("Target driver %s must have "
                        "detect() method.", vtt->name);
                res = -EINVAL;
                goto out_err;
        }
 
        if (!vtt->release) {
-               PRINT_ERROR("Target driver %s doesn't have a "
+               PRINT_ERROR("Target driver %s must have "
                        "release() method.", vtt->name);
                res = -EINVAL;
                goto out_err;
        }
 
        if (!vtt->xmit_response) {
-               PRINT_ERROR("Target driver %s doesn't have a "
+               PRINT_ERROR("Target driver %s must have "
                        "xmit_response() method.", vtt->name);
                res = -EINVAL;
                goto out_err;
@@ -216,26 +218,40 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
                goto out_err;
        }
 
+       if (!vtt->enable_tgt || !vtt->is_tgt_enabled) {
+               PRINT_WARNING("Target driver %s doesn't have enable_tgt() "
+                       "and/or is_tgt_enabled() method(s). This is unsafe "
+                       "and can lead that initiators connected on the "
+                       "initialization time can see an unexpected set of "
+                       "devices or no devices at all!", vtt->name);
+       }
+
+#ifdef CONFIG_SCST_PROC
        if (!vtt->no_proc_entry) {
                res = scst_build_proc_target_dir_entries(vtt);
                if (res < 0)
                        goto out_err;
        }
+#endif
+
+       res = scst_create_tgtt_sysfs(vtt);
+       if (res)
+               goto out_sysfs_err;
 
        if (vtt->rdy_to_xfer == NULL)
                vtt->rdy_to_xfer_atomic = 1;
 
        if (mutex_lock_interruptible(&m) != 0)
-               goto out_err;
+               goto out_sysfs_err;
 
        if (mutex_lock_interruptible(&scst_mutex) != 0)
-               goto out_m_up;
+               goto out_m_err;
        list_for_each_entry(t, &scst_template_list, scst_template_list_entry) {
                if (strcmp(t->name, vtt->name) == 0) {
                        PRINT_ERROR("Target driver %s already registered",
                                vtt->name);
                        mutex_unlock(&scst_mutex);
-                       goto out_cleanup;
+                       goto out_m_err;
                }
        }
        mutex_unlock(&scst_mutex);
@@ -246,7 +262,7 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
        if (res < 0) {
                PRINT_ERROR("%s", "The detect() routine failed");
                res = -EINVAL;
-               goto out_cleanup;
+               goto out_m_err;
        }
 
        mutex_lock(&scst_mutex);
@@ -263,12 +279,15 @@ out:
        TRACE_EXIT_RES(res);
        return res;
 
-out_cleanup:
-       scst_cleanup_proc_target_dir_entries(vtt);
-
-out_m_up:
+out_m_err:
        mutex_unlock(&m);
 
+out_sysfs_err:
+#ifdef CONFIG_SCST_PROC
+       scst_cleanup_proc_target_dir_entries(vtt);
+#endif
+       scst_tgtt_sysfs_put(vtt);
+
 out_err:
        PRINT_ERROR("Failed to register target template %s", vtt->name);
        goto out;
@@ -293,7 +312,7 @@ void scst_unregister_target_template(struct scst_tgt_template *vtt)
        }
        if (!found) {
                PRINT_ERROR("Target driver %s isn't registered", vtt->name);
-               goto out_up;
+               goto out_err_up;
        }
 
 restart:
@@ -305,15 +324,23 @@ restart:
        }
        list_del(&vtt->scst_template_list_entry);
 
-       PRINT_INFO("Target template %s unregistered successfully", vtt->name);
-
-out_up:
        mutex_unlock(&scst_mutex);
 
+#ifdef CONFIG_SCST_PROC
        scst_cleanup_proc_target_dir_entries(vtt);
+#endif
+
+       scst_tgtt_sysfs_put(vtt);
+
+       PRINT_INFO("Target template %s unregistered successfully", vtt->name);
 
+out:
        TRACE_EXIT();
        return;
+
+out_err_up:
+       mutex_unlock(&scst_mutex);
+       goto out;
 }
 EXPORT_SYMBOL(scst_unregister_target_template);
 
@@ -325,24 +352,12 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
 
        TRACE_ENTRY();
 
-       tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
+       tgt = scst_alloc_tgt(vtt);
        if (tgt == NULL) {
-               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of tgt failed");
                rc = -ENOMEM;
                goto out_err;
        }
 
-       INIT_LIST_HEAD(&tgt->sess_list);
-       init_waitqueue_head(&tgt->unreg_waitQ);
-       tgt->tgtt = vtt;
-       tgt->sg_tablesize = vtt->sg_tablesize;
-       spin_lock_init(&tgt->tgt_lock);
-       INIT_LIST_HEAD(&tgt->retry_cmd_list);
-       atomic_set(&tgt->finished_cmds, 0);
-       init_timer(&tgt->retry_timer);
-       tgt->retry_timer.data = (unsigned long)tgt;
-       tgt->retry_timer.function = scst_tgt_retry_timer_fn;
-
        rc = scst_suspend_activity(true);
        if (rc != 0)
                goto out_free_tgt_err;
@@ -353,25 +368,72 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
        }
 
        if (target_name != NULL) {
-               int len = strlen(target_name) + 1 +
-                       strlen(SCST_DEFAULT_ACG_NAME) + 1;
+#ifdef CONFIG_SCST_PROC
+               int len = strlen(target_name) +
+                       strlen(SCST_DEFAULT_ACG_NAME) + 1 + 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");
+                       TRACE(TRACE_OUT_OF_MEM, "Allocation of default "
+                               "group name failed (tgt %s)", target_name);
                        rc = -ENOMEM;
                        goto out_unlock_resume;
                }
                sprintf(tgt->default_group_name, "%s_%s", SCST_DEFAULT_ACG_NAME,
                        target_name);
+#endif
+
+               tgt->tgt_name = kmalloc(strlen(target_name) + 1, GFP_KERNEL);
+               if (tgt->tgt_name == NULL) {
+                       TRACE(TRACE_OUT_OF_MEM, "Allocation of tgt name %s failed",
+                               target_name);
+                       rc = -ENOMEM;
+#ifdef CONFIG_SCST_PROC
+                       goto out_free_def_name;
+#else
+                       goto out_unlock_resume;
+#endif
+               }
+               strcpy(tgt->tgt_name, target_name);
+       } else {
+               static int tgt_num; /* protected by scst_mutex */
+               int len = strlen(vtt->name) +
+                       strlen(SCST_DEFAULT_TGT_NAME_SUFFIX) + 11 + 1;
+
+               tgt->tgt_name = kmalloc(len, GFP_KERNEL);
+               if (tgt->tgt_name == NULL) {
+                       TRACE(TRACE_OUT_OF_MEM, "Allocation of tgt name failed "
+                               "(template name %s)", vtt->name);
+                       rc = -ENOMEM;
+#ifdef CONFIG_SCST_PROC
+                       goto out_free_def_name;
+#else
+                       goto out_unlock_resume;
+#endif
+               }
+               sprintf(tgt->tgt_name, "%s%s%d", vtt->name,
+                       SCST_DEFAULT_TGT_NAME_SUFFIX, tgt_num++);
        }
 
+       tgt->default_acg = scst_alloc_add_acg(tgt->tgt_name);
+       if (tgt->default_acg == NULL)
+               goto out_free_tgt_name;
+
+#ifdef CONFIG_SCST_PROC
        rc = scst_build_proc_target_entries(tgt);
        if (rc < 0)
-               goto out_free_name;
-       else
-               list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list);
+               goto out_free_acg;
+#endif
+
+       rc = scst_create_tgt_sysfs(tgt);
+       if (rc < 0)
+#ifdef CONFIG_SCST_PROC
+               goto out_clean_proc;
+#else
+               goto out_free_acg;
+#endif
+
+       list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list);
 
        mutex_unlock(&scst_mutex);
        scst_resume_activity();
@@ -383,8 +445,21 @@ out:
        TRACE_EXIT();
        return tgt;
 
-out_free_name:
+#ifdef CONFIG_SCST_PROC
+out_clean_proc:
+       scst_cleanup_proc_target_entries(tgt);
+#endif
+
+out_free_acg:
+       scst_destroy_acg(tgt->default_acg);
+
+out_free_tgt_name:
+       kfree(tgt->tgt_name);
+
+#ifdef CONFIG_SCST_PROC
+out_free_def_name:
        kfree(tgt->default_group_name);
+#endif
 
 out_unlock_resume:
        mutex_unlock(&scst_mutex);
@@ -393,7 +468,7 @@ out_resume_free:
        scst_resume_activity();
 
 out_free_tgt_err:
-       kfree(tgt);
+       scst_tgt_sysfs_put(tgt);
        tgt = NULL;
 
 out_err:
@@ -449,20 +524,31 @@ again:
 
        list_del(&tgt->tgt_list_entry);
 
+#ifdef CONFIG_SCST_PROC
        scst_cleanup_proc_target_entries(tgt);
-
-       kfree(tgt->default_group_name);
+#endif
 
        mutex_unlock(&scst_mutex);
        scst_resume_activity();
 
+       /*
+        * It should be before freeing of tgt_name, because acg_name
+        * points to it.
+        */
+       scst_destroy_acg(tgt->default_acg);
+
+       kfree(tgt->tgt_name);
+#ifdef CONFIG_SCST_PROC
+       kfree(tgt->default_group_name);
+#endif
+
        del_timer_sync(&tgt->retry_timer);
 
+       scst_tgt_sysfs_put(tgt);
+
        PRINT_INFO("Target %p for template %s unregistered successfully",
                tgt, vtt->name);
 
-       kfree(tgt);
-
        TRACE_EXIT();
        return;
 }
@@ -654,9 +740,21 @@ static int scst_register_device(struct scsi_device *scsidp)
 
        dev->type = scsidp->type;
 
+       dev->virt_name = kmalloc(50, GFP_KERNEL);
+       if (dev->virt_name == NULL) {
+               PRINT_ERROR("%s", "Unable to alloc device name");
+               res = -ENOMEM;
+               goto out_free_dev;
+       }
+       snprintf(dev->virt_name, 50, "%d:%d:%d:%d", scsidp->host->host_no,
+               scsidp->channel, scsidp->id, scsidp->lun);
+
        dev->rq_disk = alloc_disk(1);
        if (dev->rq_disk == NULL) {
+               PRINT_ERROR("Unable to alloc disk object for device %s",
+                       dev->virt_name);
                res = -ENOMEM;
+               /* virt_name will be freed in scst_free_dev() */
                goto out_free_dev;
        }
        dev->rq_disk->major = SCST_MAJOR;
@@ -665,6 +763,10 @@ static int scst_register_device(struct scsi_device *scsidp)
 
        list_add_tail(&dev->dev_list_entry, &scst_dev_list);
 
+       res = scst_create_device_sysfs(dev);
+       if (res != 0)
+               goto out_free;
+
        list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
                if (dt->type == scsidp->type) {
                        res = scst_assign_dev_handler(dev, dt);
@@ -686,9 +788,9 @@ out_err:
                        "type %d", scsidp->host->host_no, scsidp->channel,
                        scsidp->id, scsidp->lun, scsidp->type);
        } else {
-               PRINT_ERROR("Failed to to scsi%d, channel %d, id %d, lun %d, "
-                       "type %d", scsidp->host->host_no, scsidp->channel,
-                       scsidp->id, scsidp->lun, scsidp->type);
+               PRINT_ERROR("Failed to attach to scsi%d, channel %d, id %d, "
+                       "lun %d, type %d", scsidp->host->host_no,
+                       scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
        }
 
        TRACE_EXIT_RES(res);
@@ -699,7 +801,7 @@ out_free:
        put_disk(dev->rq_disk);
 
 out_free_dev:
-       scst_free_device(dev);
+       scst_device_sysfs_put(dev);
        goto out_up;
 }
 
@@ -735,7 +837,7 @@ static void scst_unregister_device(struct scsi_device *scsidp)
        scst_assign_dev_handler(dev, &scst_null_devtype);
 
        put_disk(dev->rq_disk);
-       scst_free_device(dev);
+       scst_device_sysfs_put(dev);
 
        PRINT_INFO("Detached from scsi%d, channel %d, id %d, lun %d, type %d",
                scsidp->host->host_no, scsidp->channel, scsidp->id,
@@ -754,7 +856,7 @@ static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
        int res = 0;
 
        if (dev_handler->parse == NULL) {
-               PRINT_ERROR("scst dev_type driver %s doesn't have a "
+               PRINT_ERROR("scst dev handler %s must have "
                        "parse() method.", dev_handler->name);
                res = -EINVAL;
                goto out;
@@ -816,13 +918,25 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
 
        dev->type = dev_handler->type;
        dev->scsi_dev = NULL;
-       dev->virt_name = dev_name;
+       dev->virt_name = kstrdup(dev_name, GFP_KERNEL);
+       if (dev->virt_name == NULL) {
+               PRINT_ERROR("Unable to allocate virt_name for dev %s",
+                       dev_name);
+               res = -ENOMEM;
+               goto out_release;
+       }
        dev->virt_id = scst_virt_dev_last_id++;
 
        list_add_tail(&dev->dev_list_entry, &scst_dev_list);
 
        res = dev->virt_id;
 
+       rc = scst_create_device_sysfs(dev);
+       if (rc != 0) {
+               res = rc;
+               goto out_free_del;
+       }
+
        rc = scst_assign_dev_handler(dev, dev_handler);
        if (rc != 0) {
                res = rc;
@@ -847,7 +961,9 @@ out:
 
 out_free_del:
        list_del(&dev->dev_list_entry);
-       scst_free_device(dev);
+
+out_release:
+       scst_device_sysfs_put(dev);
        goto out_up;
 }
 EXPORT_SYMBOL(scst_register_virtual_device);
@@ -877,8 +993,7 @@ void scst_unregister_virtual_device(int id)
        list_del(&dev->dev_list_entry);
 
        list_for_each_entry_safe(acg_dev, aa, &dev->dev_acg_dev_list,
-                                dev_acg_dev_list_entry)
-       {
+                                dev_acg_dev_list_entry) {
                scst_acg_remove_dev(acg_dev->acg, dev, true);
        }
 
@@ -887,7 +1002,7 @@ void scst_unregister_virtual_device(int id)
        PRINT_INFO("Detached from virtual device %s (id %d)",
                dev->virt_name, dev->virt_id);
 
-       scst_free_device(dev);
+       scst_device_sysfs_put(dev);
 
 out_unblock:
        mutex_unlock(&scst_mutex);
@@ -959,9 +1074,17 @@ int __scst_register_dev_driver(struct scst_dev_type *dev_type,
        if (exist)
                goto out_up;
 
-       res = scst_build_proc_dev_handler_dir_entries(dev_type);
+#ifdef CONFIG_SCST_PROC
+       if (!dev_type->no_proc) {
+               res = scst_build_proc_dev_handler_dir_entries(dev_type);
+               if (res < 0)
+                       goto out_up;
+       }
+#endif
+
+       res = scst_create_devt_sysfs(dev_type);
        if (res < 0)
-               goto out_up;
+               goto out_free;
 
        list_add_tail(&dev_type->dev_type_list_entry, &scst_dev_type_list);
 
@@ -984,6 +1107,13 @@ out:
        TRACE_EXIT_RES(res);
        return res;
 
+out_free:
+#ifdef CONFIG_SCST_PROC
+       if (!dev_type->no_proc)
+               scst_cleanup_proc_dev_handler_dir_entries(dev_type);
+#endif
+       scst_devt_sysfs_put(dev_type);
+
 out_up:
        mutex_unlock(&scst_mutex);
 
@@ -1032,7 +1162,11 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type)
        mutex_unlock(&scst_mutex);
        scst_resume_activity();
 
+#ifdef CONFIG_SCST_PROC
        scst_cleanup_proc_dev_handler_dir_entries(dev_type);
+#endif
+
+       scst_devt_sysfs_put(dev_type);
 
        PRINT_INFO("Device handler \"%s\" for type %d unloaded",
                   dev_type->name, dev_type->type);
@@ -1066,11 +1200,17 @@ int __scst_register_virtual_dev_driver(struct scst_dev_type *dev_type,
        if (res != 0)
                goto out_err;
 
+#ifdef CONFIG_SCST_PROC
        if (!dev_type->no_proc) {
                res = scst_build_proc_dev_handler_dir_entries(dev_type);
                if (res < 0)
                        goto out_err;
        }
+#endif
+
+       res = scst_create_devt_sysfs(dev_type);
+       if (res < 0)
+               goto out_free;
 
        if (dev_type->type != -1) {
                PRINT_INFO("Virtual device handler %s for type %d "
@@ -1085,6 +1225,14 @@ out:
        TRACE_EXIT_RES(res);
        return res;
 
+out_free:
+#ifdef CONFIG_SCST_PROC
+       if (!dev_type->no_proc)
+               scst_cleanup_proc_dev_handler_dir_entries(dev_type);
+#endif
+
+       scst_devt_sysfs_put(dev_type);
+
 out_err:
        PRINT_ERROR("Failed to register virtual device handler \"%s\"",
                dev_type->name);
@@ -1096,8 +1244,12 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type)
 {
        TRACE_ENTRY();
 
+#ifdef CONFIG_SCST_PROC
        if (!dev_type->no_proc)
                scst_cleanup_proc_dev_handler_dir_entries(dev_type);
+#endif
+
+       scst_devt_sysfs_put(dev_type);
 
        PRINT_INFO("Device handler \"%s\" unloaded", dev_type->name);
 
@@ -1272,7 +1424,10 @@ int scst_assign_dev_handler(struct scst_device *dev,
        if (dev->handler == handler)
                goto out;
 
-       if (dev->handler && dev->handler->detach_tgt) {
+       if (dev->handler == NULL)
+               goto assign;
+
+       if (dev->handler->detach_tgt) {
                list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
                                dev_tgt_dev_list_entry) {
                        TRACE_DBG("Calling dev handler's detach_tgt(%p)",
@@ -1282,7 +1437,7 @@ int scst_assign_dev_handler(struct scst_device *dev,
                }
        }
 
-       if (dev->handler && dev->handler->detach) {
+       if (dev->handler->detach) {
                TRACE_DBG("%s", "Calling dev handler's detach()");
                dev->handler->detach(dev);
                TRACE_DBG("%s", "Old handler's detach() returned");
@@ -1290,26 +1445,34 @@ int scst_assign_dev_handler(struct scst_device *dev,
 
        scst_stop_dev_threads(dev);
 
+       scst_devt_dev_sysfs_put(dev);
+
+assign:
        dev->handler = handler;
 
-       if (handler) {
-               res = scst_create_dev_threads(dev);
-               if (res != 0)
-                       goto out_null;
-       }
+       if (handler == NULL)
+               goto out;
 
-       if (handler && handler->attach) {
+       res = scst_create_devt_dev_sysfs(dev);
+       if (res != 0)
+               goto out_null;
+
+       res = scst_create_dev_threads(dev);
+       if (res != 0)
+               goto out_remove_sysfs;
+
+       if (handler->attach) {
                TRACE_DBG("Calling new dev handler's attach(%p)", dev);
                res = handler->attach(dev);
                TRACE_DBG("New dev handler's attach() returned %d", res);
                if (res != 0) {
                        PRINT_ERROR("New device handler's %s attach() "
                                "failed: %d", handler->name, res);
+                       goto out_thr_null;
                }
-               goto out_thr_null;
        }
 
-       if (handler && handler->attach_tgt) {
+       if (handler->attach_tgt) {
                list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
                                dev_tgt_dev_list_entry) {
                        TRACE_DBG("Calling dev handler's attach_tgt(%p)",
@@ -1326,14 +1489,6 @@ int scst_assign_dev_handler(struct scst_device *dev,
                }
        }
 
-out_thr_null:
-       if (res != 0)
-               scst_stop_dev_threads(dev);
-
-out_null:
-       if (res != 0)
-               dev->handler = &scst_null_devtype;
-
 out:
        TRACE_EXIT_RES(res);
        return res;
@@ -1341,8 +1496,7 @@ out:
 out_err_detach_tgt:
        if (handler && handler->detach_tgt) {
                list_for_each_entry(tgt_dev, &attached_tgt_devs,
-                                extra_tgt_dev_list_entry)
-               {
+                                extra_tgt_dev_list_entry) {
                        TRACE_DBG("Calling handler's detach_tgt(%p)",
                                tgt_dev);
                        handler->detach_tgt(tgt_dev);
@@ -1354,7 +1508,16 @@ out_err_detach_tgt:
                handler->detach(dev);
                TRACE_DBG("%s", "Handler's detach() returned");
        }
-       goto out_null;
+
+out_thr_null:
+       scst_stop_dev_threads(dev);
+
+out_remove_sysfs:
+       scst_devt_dev_sysfs_put(dev);
+
+out_null:
+       dev->handler = &scst_null_devtype;
+       goto out;
 }
 
 int scst_global_threads_count(void)
@@ -1830,6 +1993,10 @@ static int __init init_scst(void)
                goto out_destroy_sense_mempool;
        }
 
+       res = scst_sysfs_init();
+       if (res != 0)
+               goto out_destroy_aen_mempool;
+
        if (scst_max_cmd_mem == 0) {
                struct sysinfo si;
                si_meminfo(&si);
@@ -1857,17 +2024,23 @@ static int __init init_scst(void)
        res = scst_sgv_pools_init(
                ((uint64_t)scst_max_cmd_mem << 10) >> (PAGE_SHIFT - 10), 0);
        if (res != 0)
-               goto out_destroy_aen_mempool;
+               goto out_sysfs_cleanup;
 
+#ifdef CONFIG_SCST_PROC
        scst_default_acg = scst_alloc_add_acg(SCST_DEFAULT_ACG_NAME);
        if (scst_default_acg == NULL) {
                res = -ENOMEM;
                goto out_destroy_sgv_pool;
        }
+#endif
 
        res = scsi_register_interface(&scst_interface);
        if (res != 0)
+#ifdef CONFIG_SCST_PROC
                goto out_free_acg;
+#else
+               goto out_destroy_sgv_pool;
+#endif
 
        for (i = 0; i < (int)ARRAY_SIZE(scst_tasklets); i++) {
                spin_lock_init(&scst_tasklets[i].tasklet_lock);
@@ -1884,10 +2057,11 @@ static int __init init_scst(void)
        if (res < 0)
                goto out_thread_free;
 
+#ifdef CONFIG_SCST_PROC
        res = scst_proc_init_module();
        if (res != 0)
                goto out_thread_free;
-
+#endif
 
        PRINT_INFO("SCST version %s loaded successfully (max mem for "
                "commands %dMB, per device %dMB)", SCST_VERSION_STRING,
@@ -1904,12 +2078,17 @@ out_thread_free:
 
        scsi_unregister_interface(&scst_interface);
 
+#ifdef CONFIG_SCST_PROC
 out_free_acg:
        scst_destroy_acg(scst_default_acg);
+#endif
 
 out_destroy_sgv_pool:
        scst_sgv_pools_deinit();
 
+out_sysfs_cleanup:
+       scst_sysfs_cleanup();
+
 out_destroy_aen_mempool:
        mempool_destroy(scst_aen_mempool);
 
@@ -1963,12 +2142,17 @@ static void __exit exit_scst(void)
 
        /* ToDo: unregister_cpu_notifier() */
 
+#ifdef CONFIG_SCST_PROC
        scst_proc_cleanup_module();
+#endif
+       scst_sysfs_cleanup();
 
        scst_stop_all_threads();
 
        scsi_unregister_interface(&scst_interface);
+#ifdef CONFIG_SCST_PROC
        scst_destroy_acg(scst_default_acg);
+#endif
 
        scst_sgv_pools_deinit();
 
index 99364d9..ceab469 100644 (file)
@@ -36,7 +36,7 @@
 /* Max pages freed from a pool per shrinking iteration */
 #define MAX_PAGES_PER_POOL     50
 
-static struct sgv_pool sgv_norm_clust_pool, sgv_norm_pool, sgv_dma_pool;
+static struct sgv_pool *sgv_norm_clust_pool, *sgv_norm_pool, *sgv_dma_pool;
 
 static atomic_t sgv_pages_total = ATOMIC_INIT(0);
 
@@ -78,7 +78,7 @@ static inline bool sgv_pool_clustered(const struct sgv_pool *pool)
 void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev)
 {
        tgt_dev->gfp_mask = __GFP_NOWARN;
-       tgt_dev->pool = &sgv_norm_pool;
+       tgt_dev->pool = sgv_norm_pool;
        clear_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
 }
 
@@ -86,7 +86,7 @@ void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev)
 {
        TRACE_MEM("%s", "Use clustering");
        tgt_dev->gfp_mask = __GFP_NOWARN;
-       tgt_dev->pool = &sgv_norm_clust_pool;
+       tgt_dev->pool = sgv_norm_clust_pool;
        set_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
 }
 
@@ -94,7 +94,7 @@ void scst_sgv_pool_use_dma(struct scst_tgt_dev *tgt_dev)
 {
        TRACE_MEM("%s", "Use ISA DMA memory");
        tgt_dev->gfp_mask = __GFP_NOWARN | GFP_DMA;
-       tgt_dev->pool = &sgv_dma_pool;
+       tgt_dev->pool = sgv_dma_pool;
        clear_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
 }
 
@@ -1292,7 +1292,7 @@ static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num)
 }
 
 /* Must be called under sgv_pools_mutex */
-int sgv_pool_init(struct sgv_pool *pool, const char *name,
+static int sgv_pool_init(struct sgv_pool *pool, const char *name,
        enum sgv_clustering_types clustering_type, int single_alloc_pages,
        int purge_interval)
 {
@@ -1436,7 +1436,7 @@ void sgv_pool_flush(struct sgv_pool *pool)
 }
 EXPORT_SYMBOL(sgv_pool_flush);
 
-void sgv_pool_deinit(struct sgv_pool *pool)
+static void sgv_pool_deinit_put(struct sgv_pool *pool)
 {
        int i;
 
@@ -1458,6 +1458,10 @@ void sgv_pool_deinit(struct sgv_pool *pool)
                pool->caches[i] = NULL;
        }
 
+       scst_sgv_sysfs_put(pool);
+
+       /* pool can be dead here */
+
        TRACE_EXIT();
        return;
 }
@@ -1511,6 +1515,10 @@ struct sgv_pool *sgv_pool_create(const char *name,
        if (rc != 0)
                goto out_free_unlock;
 
+       rc = scst_create_sgv_sysfs(pool);
+       if (rc != 0)
+               goto out_err_unlock_put;
+
 out_unlock:
        mutex_unlock(&sgv_pools_mutex);
 
@@ -1523,14 +1531,18 @@ out_free_unlock:
 out_err_unlock:
        pool = NULL;
        goto out_unlock;
+
+out_err_unlock_put:
+       mutex_unlock(&sgv_pools_mutex);
+       sgv_pool_deinit_put(pool);
+       goto out_err_unlock;
 }
 EXPORT_SYMBOL(sgv_pool_create);
 
-static void sgv_pool_destroy(struct sgv_pool *pool)
+void sgv_pool_destroy(struct sgv_pool *pool)
 {
        TRACE_ENTRY();
 
-       sgv_pool_deinit(pool);
        kfree(pool);
 
        TRACE_EXIT();
@@ -1551,7 +1563,7 @@ void sgv_pool_put(struct sgv_pool *pool)
        TRACE_MEM("Decrementing sgv pool %p ref (new value %d)",
                pool, atomic_read(&pool->sgv_pool_ref)-1);
        if (atomic_dec_and_test(&pool->sgv_pool_ref))
-               sgv_pool_destroy(pool);
+               sgv_pool_deinit_put(pool);
        return;
 }
 EXPORT_SYMBOL(sgv_pool_put);
@@ -1570,7 +1582,7 @@ EXPORT_SYMBOL(sgv_pool_del);
 /* Both parameters in pages */
 int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
 {
-       int res;
+       int res = 0;
 
        TRACE_ENTRY();
 
@@ -1579,23 +1591,20 @@ int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
 
        sgv_evaluate_local_max_pages();
 
-       mutex_lock(&sgv_pools_mutex);
+       sgv_norm_pool = sgv_pool_create("sgv", sgv_no_clustering, 0, false, 0);
+       if (sgv_norm_pool == NULL)
+               goto out_err;
 
-       res = sgv_pool_init(&sgv_norm_pool, "sgv", sgv_no_clustering, 0, 0);
-       if (res != 0)
-               goto out_unlock;
-
-       res = sgv_pool_init(&sgv_norm_clust_pool, "sgv-clust",
-               sgv_full_clustering, 0, 0);
-       if (res != 0)
+       sgv_norm_clust_pool = sgv_pool_create("sgv-clust",
+               sgv_full_clustering, 0, false, 0);
+       if (sgv_norm_clust_pool == NULL)
                goto out_free_norm;
 
-       res = sgv_pool_init(&sgv_dma_pool, "sgv-dma", sgv_no_clustering, 0, 0);
-       if (res != 0)
+       sgv_dma_pool = sgv_pool_create("sgv-dma", sgv_no_clustering, 0,
+                               false, 0);
+       if (sgv_dma_pool == NULL)
                goto out_free_clust;
 
-       mutex_unlock(&sgv_pools_mutex);
-
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
        sgv_shrinker = set_shrinker(DEFAULT_SEEKS, sgv_shrink);
 #else
@@ -1609,13 +1618,13 @@ out:
        return res;
 
 out_free_clust:
-       sgv_pool_deinit(&sgv_norm_clust_pool);
+       sgv_pool_deinit_put(sgv_norm_clust_pool);
 
 out_free_norm:
-       sgv_pool_deinit(&sgv_norm_pool);
+       sgv_pool_deinit_put(sgv_norm_pool);
 
-out_unlock:
-       mutex_unlock(&sgv_pools_mutex);
+out_err:
+       res = -ENOMEM;
        goto out;
 }
 
@@ -1629,9 +1638,9 @@ void scst_sgv_pools_deinit(void)
        unregister_shrinker(&sgv_shrinker);
 #endif
 
-       sgv_pool_deinit(&sgv_dma_pool);
-       sgv_pool_deinit(&sgv_norm_pool);
-       sgv_pool_deinit(&sgv_norm_clust_pool);
+       sgv_pool_deinit_put(sgv_dma_pool);
+       sgv_pool_deinit_put(sgv_norm_pool);
+       sgv_pool_deinit_put(sgv_norm_clust_pool);
 
        flush_scheduled_work();
 
@@ -1639,6 +1648,8 @@ void scst_sgv_pools_deinit(void)
        return;
 }
 
+#ifdef CONFIG_SCST_PROC
+
 static void sgv_do_proc_read(struct seq_file *seq, const struct sgv_pool *pool)
 {
        int i, total = 0, hit = 0, merged = 0, allocated = 0;
@@ -1730,3 +1741,90 @@ int sgv_procinfo_show(struct seq_file *seq, void *v)
        TRACE_EXIT();
        return 0;
 }
+
+#endif /* CONFIG_SCST_PROC */
+
+ssize_t sgv_sysfs_stat_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       struct sgv_pool *pool;
+       int i, total = 0, hit = 0, merged = 0, allocated = 0;
+       int oa, om, res;
+
+       pool = container_of(kobj, struct sgv_pool, sgv_kobj);
+
+       for (i = 0; i < SGV_POOL_ELEMENTS; i++) {
+               int t;
+
+               hit += atomic_read(&pool->cache_acc[i].hit_alloc);
+               total += atomic_read(&pool->cache_acc[i].total_alloc);
+
+               t = atomic_read(&pool->cache_acc[i].total_alloc) -
+                       atomic_read(&pool->cache_acc[i].hit_alloc);
+               allocated += t * (1 << i);
+               merged += atomic_read(&pool->cache_acc[i].merged);
+       }
+
+       res = sprintf(buf, "%-30s %-11s %-11s %-11s %-11s", "Name", "Hit", "Total",
+               "% merged", "Cached (P/I/O)");
+
+       res += sprintf(&buf[res], "\n%-30s %-11d %-11d %-11d %d/%d/%d\n",
+               pool->name, hit, total,
+               (allocated != 0) ? merged*100/allocated : 0,
+               pool->cached_pages, pool->inactive_cached_pages,
+               pool->cached_entries);
+
+       for (i = 0; i < SGV_POOL_ELEMENTS; i++) {
+               int t = atomic_read(&pool->cache_acc[i].total_alloc) -
+                       atomic_read(&pool->cache_acc[i].hit_alloc);
+               allocated = t * (1 << i);
+               merged = atomic_read(&pool->cache_acc[i].merged);
+
+               res += sprintf(&buf[res], "  %-28s %-11d %-11d %d\n",
+                       pool->cache_names[i],
+                       atomic_read(&pool->cache_acc[i].hit_alloc),
+                       atomic_read(&pool->cache_acc[i].total_alloc),
+                       (allocated != 0) ? merged*100/allocated : 0);
+       }
+
+       allocated = atomic_read(&pool->big_pages);
+       merged = atomic_read(&pool->big_merged);
+       oa = atomic_read(&pool->other_pages);
+       om = atomic_read(&pool->other_merged);
+
+       res += sprintf(&buf[res], "  %-40s %d/%-9d %d/%d\n", "big/other",
+               atomic_read(&pool->big_alloc), atomic_read(&pool->other_alloc),
+               (allocated != 0) ? merged*100/allocated : 0,
+               (oa != 0) ? om/oa : 0);
+
+       return res;
+}
+
+ssize_t sgv_sysfs_global_stat_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       struct sgv_pool *pool;
+       int inactive_pages = 0, res;
+
+       TRACE_ENTRY();
+
+       spin_lock_bh(&sgv_pools_lock);
+       list_for_each_entry(pool, &sgv_active_pools_list,
+                       sgv_active_pools_list_entry) {
+               inactive_pages += pool->inactive_cached_pages;
+       }
+       spin_unlock_bh(&sgv_pools_lock);
+
+       res = sprintf(buf, "%-42s %d/%d\n%-42s %d/%d\n%-42s %d/%d\n"
+               "%-42s %-11d\n",
+               "Inactive/active pages", inactive_pages,
+               atomic_read(&sgv_pages_total) - inactive_pages,
+               "Hi/lo watermarks [pages]", sgv_hi_wmk, sgv_lo_wmk,
+               "Hi watermark releases/failures",
+               atomic_read(&sgv_releases_on_hiwmk),
+               atomic_read(&sgv_releases_on_hiwmk_failed),
+               "Other allocs", atomic_read(&sgv_other_total_alloc));
+
+       TRACE_EXIT();
+       return res;
+}
index 2d1ba5c..1e3d912 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/scatterlist.h>
 #include <linux/workqueue.h>
-#include <linux/seq_file.h>
 
 #define SGV_POOL_ELEMENTS      11
 
@@ -77,8 +76,9 @@ struct sgv_pool {
 
        int purge_interval;
 
-       /* Protected by sgv_pool_lock */
+       /* Protected by sgv_pool_lock, if necessary */
        unsigned int purge_work_scheduled:1;
+       unsigned int sgv_kobj_initialized:1;
 
        /* Protected by sgv_pool_lock */
        struct list_head sorted_recycling_list;
@@ -114,22 +114,28 @@ struct sgv_pool {
        struct mm_struct *owner_mm;
 
        struct list_head sgv_pools_list_entry;
-};
 
-int sgv_pool_init(struct sgv_pool *pool, const char *name,
-       enum sgv_clustering_types clustering_type, int single_alloc_pages,
-       int purge_interval);
-void sgv_pool_deinit(struct sgv_pool *pool);
+       struct kobject sgv_kobj;
+};
 
 static inline struct scatterlist *sgv_pool_sg(struct sgv_pool_obj *obj)
 {
        return obj->sg_entries;
 }
 
-extern int scst_sgv_pools_init(unsigned long mem_hwmark,
-                              unsigned long mem_lwmark);
-extern void scst_sgv_pools_deinit(void);
-extern int sgv_procinfo_show(struct seq_file *seq, void *v);
+int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark);
+void scst_sgv_pools_deinit(void);
+
+void sgv_pool_destroy(struct sgv_pool *pool);
+
+#ifdef CONFIG_SCST_PROC
+int sgv_procinfo_show(struct seq_file *seq, void *v);
+#endif
+
+ssize_t sgv_sysfs_stat_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
+ssize_t sgv_sysfs_global_stat_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf);
 
 void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev);
 void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev);
index 4026412..0662e4f 100644 (file)
 
 #include "scst_debug.h"
 
+#ifdef CONFIG_SCST_PROC
+void sgv_pool_destroy(struct sgv_pool *pool);
+#endif
+
 #define SCST_MAJOR              177
 
 #define TRACE_RTRY              0x80000000
@@ -146,7 +150,9 @@ extern struct list_head scst_dev_type_list;
 extern wait_queue_head_t scst_dev_cmd_waitQ;
 
 extern struct list_head scst_acg_list;
+#ifdef CONFIG_SCST_PROC
 extern struct scst_acg *scst_default_acg;
+#endif
 
 extern spinlock_t scst_init_lock;
 extern struct list_head scst_init_cmd_list;
@@ -287,6 +293,12 @@ void scst_del_dev_threads(struct scst_device *dev, int num);
 
 int scst_queue_retry_cmd(struct scst_cmd *cmd, int finished_cmds);
 
+static inline void scst_tgtt_cleanup(struct scst_tgt_template *tgtt) { }
+static inline void scst_devt_cleanup(struct scst_dev_type *devt) { }
+
+struct scst_tgt *scst_alloc_tgt(struct scst_tgt_template *tgtt);
+void scst_free_tgt(struct scst_tgt *tgt);
+
 int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev);
 void scst_free_device(struct scst_device *dev);
 
@@ -298,6 +310,7 @@ struct scst_acg *scst_find_acg(const struct scst_session *sess);
 void scst_check_reassign_sessions(void);
 
 int scst_sess_alloc_tgt_devs(struct scst_session *sess);
+void scst_sess_free_tgt_devs(struct scst_session *sess);
 void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA);
 
 int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
@@ -305,6 +318,8 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
 int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev,
        bool gen_scst_report_luns_changed);
 
+void scst_acg_dev_destroy(struct scst_acg_dev *acg_dev);
+
 int scst_acg_add_name(struct scst_acg *acg, const char *name);
 int scst_acg_remove_name(struct scst_acg *acg, const char *name, bool reassign);
 void __scst_acg_remove_acn(struct scst_acn *n);
@@ -320,6 +335,7 @@ int scst_assign_dev_handler(struct scst_device *dev,
 struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask,
        const char *initiator_name);
 void scst_free_session(struct scst_session *sess);
+void scst_release_session(struct scst_session *sess);
 void scst_free_session_callback(struct scst_session *sess);
 
 struct scst_cmd *scst_alloc_cmd(gfp_t gfp_mask);
@@ -331,7 +347,6 @@ static inline void scst_destroy_cmd(struct scst_cmd *cmd)
 }
 
 void scst_check_retries(struct scst_tgt *tgt);
-void scst_tgt_retry_timer_fn(unsigned long arg);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
 int scst_alloc_request(struct scst_cmd *cmd);
@@ -360,7 +375,7 @@ static inline int scst_exec_req(struct scsi_device *sdev,
        return scsi_execute_async(sdev, cmd, cmd_len, data_direction, (void *)sgl,
                    bufflen, nents, timeout, retries, privdata, done, gfp);
 #elif !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
-       WARN_ON_ONCE(1);
+       WARN_ON();
        return -1;
 #else
        return scsi_execute_async_fifo(sdev, cmd, cmd_len, data_direction,
@@ -399,6 +414,7 @@ struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(gfp_t gfp_mask);
 void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd);
 void scst_done_cmd_mgmt(struct scst_cmd *cmd);
 
+#ifdef CONFIG_SCST_PROC
 /* /proc support */
 int scst_proc_init_module(void);
 void scst_proc_cleanup_module(void);
@@ -408,6 +424,96 @@ int scst_build_proc_target_entries(struct scst_tgt *vtt);
 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt);
 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
+#endif
+
+/* sysfs support  */
+#ifdef CONFIG_SCST_PROC
+static inline int scst_sysfs_init(void)
+{
+       return 0;
+}
+static inline void scst_sysfs_cleanup(void) { }
+
+static inline int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt)
+{
+       return 0;
+}
+static inline void scst_tgtt_sysfs_put(struct scst_tgt_template *tgtt)
+{
+       scst_tgtt_cleanup(tgtt);
+}
+
+static inline int scst_create_tgt_sysfs(struct scst_tgt *tgt)
+{
+       return 0;
+}
+static inline void scst_tgt_sysfs_put(struct scst_tgt *tgt)
+{
+       scst_free_tgt(tgt);
+}
+
+static inline int scst_create_sess_sysfs(struct scst_session *sess)
+{
+       return 0;
+}
+static inline void scst_sess_sysfs_put(struct scst_session *sess)
+{
+       scst_release_session(sess);
+}
+
+static inline int scst_create_sgv_sysfs(struct sgv_pool *pool)
+{
+       return 0;
+}
+static inline void scst_sgv_sysfs_put(struct sgv_pool *pool)
+{
+       sgv_pool_destroy(pool);
+}
+
+static inline int scst_create_devt_sysfs(struct scst_dev_type *devt)
+{
+       return 0;
+}
+static inline void scst_devt_sysfs_put(struct scst_dev_type *devt)
+{
+       scst_devt_cleanup(devt);
+}
+
+static inline int scst_create_device_sysfs(struct scst_device *dev)
+{
+       return 0;
+}
+static inline void scst_device_sysfs_put(struct scst_device *dev)
+{
+       scst_free_device(dev);
+}
+
+static inline int scst_create_devt_dev_sysfs(struct scst_device *dev)
+{
+       return 0;
+}
+static inline void scst_devt_dev_sysfs_put(struct scst_device *dev) { }
+
+#else /* CONFIG_SCST_PROC */
+
+int scst