[Fwd: [PATCH] [Target_Core_Mod/STGT]: Add struct Scsi_Host target infrastructure WIP]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings STGT folks,

I sent the original patch to the old STGT list..  Resending to get
feedback + comments from interested folks..

Many thanks for your most valuable of time,

--nab
--- Begin Message ---
Greetings all,

This patch adds the first pieces of a v3.x subsystem plugin that interacts
with Linux/SCSI to create a virtual target mode struct Scsi_Host, and using
userspace backstores from the existing STGT codebase.

So far, creating and removing STGT virtual target HBAs in through ConfigFS is
working and status appearing under /sys/bus/stgt_bus and /sys/class/scsi_host/host#/

Most of the code required for actual STGT struct scsi_cmnd is in place
(but not-tested yet), and the next main step is hooking up stgt_create_virtdevice()
in drivers/target/target_core_stgt.c to assoicate the userspace backstore
attached to the Target_Core_Mod/STGT virtual SCSI target mode HBA.

The long term goal to allow all kernel level fabric modules to take advantage of the
upstream STGT code in drivers/scsi/scsi_tgt_[if,lib].c.

Here is what the running code looks like:

*) tree /sys/kernel/config/target/core/

/sys/kernel/config/target/core/
|-- alua
|   |-- lu_gps
|   |   `-- default_lu_gp
|   |       |-- alua_access_state
|   |       |-- lu_gp_id
|   |       `-- members
|   `-- tg_pt_gps
|       `-- default_tg_pt_gp
|           |-- alua_access_state
|           |-- members
|           `-- tg_pt_gp_id
|-- stgt_0
|   `-- hba_info
|-- stgt_1
|   `-- hba_info
|-- stgt_2
|   `-- hba_info
`-- stgt_3
    `-- hba_info

*) tree /sys/bus/stgt_bus/

/sys/bus/stgt_bus/
|-- devices
|   |-- stgt_adapter0 -> ../../../devices/stgt_primary_0/stgt_adapter0
|   |-- stgt_adapter1 -> ../../../devices/stgt_primary_0/stgt_adapter1
|   |-- stgt_adapter2 -> ../../../devices/stgt_primary_0/stgt_adapter2
|   `-- stgt_adapter3 -> ../../../devices/stgt_primary_0/stgt_adapter3
|-- drivers
|   `-- stgt_tcm
|       |-- bind
|       |-- stgt_adapter0 -> ../../../../devices/stgt_primary_0/stgt_adapter0
|       |-- stgt_adapter1 -> ../../../../devices/stgt_primary_0/stgt_adapter1
|       |-- stgt_adapter2 -> ../../../../devices/stgt_primary_0/stgt_adapter2
|       |-- stgt_adapter3 -> ../../../../devices/stgt_primary_0/stgt_adapter3
|       |-- uevent
|       `-- unbind
|-- drivers_autoprobe
|-- drivers_probe
`-- uevent

*) Output in /sys/class/scsi_host/host$LINUX_HOST_ID for each stgt_tcm HBA target mode driver

target# cat /sys/class/scsi_host/host30/active_mode 
Target
target# cat /sys/class/scsi_host/host30/supported_mode 
Target
target# cat /sys/class/scsi_host/host30/proc_name      
stgt_tcm

11 directories, 6 files

*) lsmod

lsmod
Module                  Size  Used by
target_core_mod       194128  8 
scsi_transport_iscsi    26808  0 
scsi_tgt               11008  1 target_core_mod
configfs               21680  2 target_core_mod
pcnet32                29412  0 
mii                     4212  1 pcnet32

*) kernel ring buffer

TARGET_CORE[0]: Loading Generic Kernel Storage Engine: v3.0.0 on Linux/i686 on 2.6.29
TARGET_CORE[0]: Initialized ConfigFS Fabric Infrastructure: v1.0.0 on Linux/i686 on 2.6.29
SE_PC[0] - Registered Plugin Class: TRANSPORT
PLUGIN_TRANSPORT[1] - pscsi registered
PLUGIN_TRANSPORT[2] - stgt registered
CORE_STGT[0]: Bus Initalization complete
PLUGIN_TRANSPORT[4] - iblock registered
PLUGIN_TRANSPORT[5] - rd_dr registered
PLUGIN_TRANSPORT[6] - rd_mcp registered
PLUGIN_TRANSPORT[7] - fileio registered
SE_PC[1] - Registered Plugin Class: OBJ
PLUGIN_OBJ[1] - dev registered
Target_Core_ConfigFS: Located se_plugin: dfbc0850 plugin_name: stgt hba_type: 2 plugin_dep_id: 0
scsi27 : stgt_tcm
CORE_HBA[0] - Linux-iSCSI.org STGT HBA Driver v1.0 on Generic Target Core Stack v3.0
CORE_HBA[0] - stgt_tcm
CORE_HBA[0] - Attached STGT HBA to Generic Target Core with TCQ Depth: 1 MaxSectors: 1024
CORE_HBA[0] - Attached HBA to Generic Target Core
Target_Core_ConfigFS: Located se_plugin: dfbc0850 plugin_name: stgt hba_type: 2 plugin_dep_id: 1
scsi28 : stgt_tcm
CORE_HBA[1] - Linux-iSCSI.org STGT HBA Driver v1.0 on Generic Target Core Stack v3.0
CORE_HBA[1] - stgt_tcm
CORE_HBA[1] - Attached STGT HBA to Generic Target Core with TCQ Depth: 1 MaxSectors: 1024
CORE_HBA[1] - Attached HBA to Generic Target Core
Target_Core_ConfigFS: Located se_plugin: dfbc0850 plugin_name: stgt hba_type: 2 plugin_dep_id: 2
scsi29 : stgt_tcm
CORE_HBA[2] - Linux-iSCSI.org STGT HBA Driver v1.0 on Generic Target Core Stack v3.0
CORE_HBA[2] - stgt_tcm
CORE_HBA[2] - Attached STGT HBA to Generic Target Core with TCQ Depth: 1 MaxSectors: 1024
CORE_HBA[2] - Attached HBA to Generic Target Core
Target_Core_ConfigFS: Located se_plugin: dfbc0850 plugin_name: stgt hba_type: 2 plugin_dep_id: 3
scsi30 : stgt_tcm
CORE_HBA[3] - Linux-iSCSI.org STGT HBA Driver v1.0 on Generic Target Core Stack v3.0
CORE_HBA[3] - stgt_tcm
CORE_HBA[3] - Attached STGT HBA to Generic Target Core with TCQ Depth: 1 MaxSectors: 1024
CORE_HBA[3] - Attached HBA to Generic Target Core

These patches are made against lio-core-2.6.git/master and tested on v2.6.29 x86 32-bit
HVM. The lio-core-2.6.git tree can be found at: 

http://git.kernel.org/?p=linux/kernel/git/nab/lio-core-2.6.git;a=summary

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/target/MCONFIG_TARGET                 |    1 +
 drivers/target/Makefile                       |    4 +
 drivers/target/target_core_stgt.c             |  916 +++++++++++++++++++++++++
 drivers/target/target_core_transport.c        |    7 +
 include/target/target_core_base.h             |    2 +-
 include/target/target_core_stgt.h             |  200 ++++++
 include/target/target_core_transport_plugin.h |    7 +
 7 files changed, 1136 insertions(+), 1 deletions(-)
 create mode 100644 drivers/target/target_core_stgt.c
 create mode 100644 include/target/target_core_stgt.h

diff --git a/drivers/target/MCONFIG_TARGET b/drivers/target/MCONFIG_TARGET
index 77378be..8023deb 100644
--- a/drivers/target/MCONFIG_TARGET
+++ b/drivers/target/MCONFIG_TARGET
@@ -9,6 +9,7 @@ PYX_ISCSI_VENDOR ?="Linux-iSCSI.org"
 # Transport Plugins and Devices.
 #
 LINUX_PARALLEL_SCSI ?= 1
+LINUX_STGT ?= 1
 LINUX_SCSI_MEDIA_ROM ?= 1
 LINUX_PARALLEL_ATA ?= 0
 LINUX_IBLOCK ?= 1
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 63c1e3b..47fef07 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -51,6 +51,10 @@ ifeq ($(LINUX_PARALLEL_SCSI), 1)
 target_core_mod-objs			+=	target_core_pscsi.o
 EXTRA_CFLAGS				+=	-DPARALLEL_SCSI
 endif
+ifeq ($(LINUX_STGT), 1)
+target_core_mod-objs			+=	target_core_stgt.o
+EXTRA_CFLAGS				+=	-DSTGT_PLUGIN
+endif
 ifeq ($(LINUX_RAMDISK), 1)
 target_core_mod-objs			+=	target_core_rd.o
 EXTRA_CFLAGS				+=	-DPYX_RAMDISK
diff --git a/drivers/target/target_core_stgt.c b/drivers/target/target_core_stgt.c
new file mode 100644
index 0000000..6a72503
--- /dev/null
+++ b/drivers/target/target_core_stgt.c
@@ -0,0 +1,916 @@
+/*******************************************************************************
+ * Filename:  target_core_stgt.c
+ *
+ * This file contains the generic target mode <-> Linux SCSI subsystem plugin.
+ *
+ * Copyright (c) 2009 Rising Tide Systems, Inc.
+ * Copyright (c) 2009 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@xxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#define TARGET_CORE_STGT_C
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/genhd.h>
+#include <linux/cdrom.h>
+#include <linux/file.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_tgt.h>
+#include <sd.h>
+#include <sr.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_stgt.h>
+#include <target/target_core_plugin.h>
+#include <target/target_core_seobj.h>
+#include <target/target_core_transport_plugin.h>
+
+#undef TARGET_CORE_STGT_C
+
+#define to_stgt_hba(d)	container_of(d, struct stgt_hba_s, dev)
+
+static int stgt_host_no_cnt = 0;
+
+#define ISPRINT(a)  ((a >= ' ') && (a <= '~'))
+
+static int pseudo_lld_bus_match(struct device *dev,
+				struct device_driver *dev_driver)
+{
+	return 1;
+}
+
+static int stgt_lld_probe(struct device *);
+static int stgt_lld_remove(struct device *);
+
+static struct bus_type stgt_lld_bus = {
+	.name		= "stgt_bus",
+	.match		= pseudo_lld_bus_match,
+	.probe		= stgt_lld_probe,
+	.remove		= stgt_lld_remove,
+};
+
+static struct device_driver stgt_driverfs_driver = {
+	.name		= STGT_NAME,
+	.bus		= &stgt_lld_bus,
+};
+
+static void stgt_primary_release(struct device *dev)
+{
+	return;
+}
+
+static struct device stgt_primary = {
+	.init_name	= "stgt_primary_0",
+	.release	= stgt_primary_release,
+};
+
+static struct scsi_host_template stgt_driver_template = {
+	.name		= STGT_NAME,	
+	.module		= THIS_MODULE,
+	.can_queue	= 1,
+	.sg_tablesize	= SG_ALL,
+	.use_clustering	= DISABLE_CLUSTERING,
+	.max_sectors	= SCSI_DEFAULT_MAX_SECTORS,
+	.transfer_response = stgt_transfer_response,
+	.eh_abort_handler = NULL,
+	.shost_attrs	= NULL,
+	.proc_name	= STGT_NAME,
+	.supported_mode	= MODE_TARGET,
+};
+
+static void stgt_release_adapter(struct device * dev)
+{
+	stgt_hba_t *stgt_hba;
+
+	stgt_hba = to_stgt_hba(dev);
+	kfree(stgt_hba);
+}
+
+int stgt_plugin_init(void)
+{
+	int ret;
+
+	ret = device_register(&stgt_primary);
+	if (ret) {
+		printk(KERN_ERR "device_register() failed for stgt_primary\n");
+		return ret;
+	}
+
+	ret = bus_register(&stgt_lld_bus);
+	if (ret) {
+		printk(KERN_ERR "bus_register() failed for stgt_ldd_bus\n");
+		goto dev_unreg;
+	}
+
+	ret = driver_register(&stgt_driverfs_driver);
+	if (ret) {
+		printk(KERN_ERR "driver_register() failed for"
+			" stgt_driverfs_driver\n");
+		goto bus_unreg;
+	}
+
+	printk(KERN_INFO "CORE_STGT[0]: Bus Initalization complete\n");
+	return 0;
+
+bus_unreg:
+	bus_unregister(&stgt_lld_bus);
+dev_unreg:
+	device_unregister(&stgt_primary);
+	return ret;
+}
+
+void stgt_plugin_free(void)
+{
+	driver_unregister(&stgt_driverfs_driver);
+        bus_unregister(&stgt_lld_bus);
+        device_unregister(&stgt_primary);
+
+	printk(KERN_INFO "CORE_STGT[0]: Bus release complete\n");
+}
+
+/*	stgt_attach_hba():
+ *
+ */
+int stgt_attach_hba(se_hba_t *hba, u32 host_id)
+{
+	stgt_hba_t *stgt_hba;
+	int err;
+
+	stgt_hba = kzalloc(sizeof(stgt_hba_t), GFP_KERNEL);
+	if (!(stgt_hba)) {
+		printk("Unable to allocate stgt_hba_t\n");
+		return -ENOMEM;
+	}
+	stgt_hba->se_hba = hba;
+
+	stgt_hba->dev.bus = &stgt_lld_bus;
+	stgt_hba->dev.parent = &stgt_primary;
+	stgt_hba->dev.release = &stgt_release_adapter;
+	dev_set_name(&stgt_hba->dev, "stgt_adapter%d", stgt_host_no_cnt);
+
+	err = device_register(&stgt_hba->dev);
+	if (err) {
+		printk(KERN_ERR "device_register() for stgt_hba failed: %d\n", err);
+		return err;
+	}
+	stgt_host_no_cnt++;
+
+	return 0;
+}
+
+
+static int stgt_lld_probe(struct device *dev)
+{
+	se_hba_t *hba;
+	stgt_hba_t *stgt_hba;
+	struct Scsi_Host *sh;
+	int hba_depth, max_sectors, err;
+
+	stgt_hba = to_stgt_hba(dev);
+
+	sh = scsi_host_alloc(&stgt_driver_template, sizeof(stgt_hba));
+	if (!(sh)) {
+		printk(KERN_ERR "scsi_host_alloc() failed\n");
+		return -ENOMEM;
+	}
+	hba = stgt_hba->se_hba;
+	stgt_hba->scsi_host = sh;
+
+	sh->max_id = 10;
+	sh->max_lun = 10;
+
+	/*
+	 * Assign the stgt_hba_t pointer to struct Scsi_Host->hostdata..
+	 */
+	*(stgt_hba_t **)&sh->hostdata = stgt_hba;
+
+	err = scsi_add_host(sh, &stgt_hba->dev);
+	if (err) {
+		printk(KERN_ERR "scsi_add_host() failed with err: %d\n", err);
+		return err;
+	}
+
+	max_sectors = sh->max_sectors;
+	/*
+	 * Usually the SCSI LLD will use the hostt->can_queue value to define
+	 * its HBA TCQ depth.  Some other drivers (like 2.6 megaraid) don't set
+	 * this at all and set sh->can_queue at runtime.
+	 */
+	hba_depth = (sh->hostt->can_queue > sh->can_queue) ?
+		sh->hostt->can_queue : sh->can_queue;
+	atomic_set(&hba->left_queue_depth, hba_depth);
+	atomic_set(&hba->max_queue_depth, hba_depth);
+
+	hba->hba_ptr = (void *) sh;
+	hba->transport = &stgt_template;
+
+	printk(KERN_INFO "CORE_HBA[%d] - %s STGT HBA Driver %s on"
+		" Generic Target Core Stack %s\n", hba->hba_id,
+		PYX_ISCSI_VENDOR, STGT_VERSION, TARGET_CORE_MOD_VERSION);
+	printk(KERN_INFO "CORE_HBA[%d] - %s\n", hba->hba_id, (sh->hostt->name) ?
+			(sh->hostt->name) : "Unknown");
+	printk(KERN_INFO "CORE_HBA[%d] - Attached STGT HBA to Generic"
+		" Target Core with TCQ Depth: %d MaxSectors: %hu\n",
+		hba->hba_id, atomic_read(&hba->max_queue_depth), max_sectors);
+
+	return 0;
+}
+
+static int stgt_lld_remove(struct device *dev)
+{
+	stgt_hba_t *stgt_hba;
+	struct Scsi_Host *sh;
+
+	stgt_hba = to_stgt_hba(dev);
+	sh = stgt_hba->scsi_host;
+
+	scsi_remove_host(sh);
+	scsi_host_put(sh);
+
+	return 0;
+}
+
+/*	stgt_detach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int stgt_detach_hba(se_hba_t *hba)
+{
+	struct Scsi_Host *scsi_host = (struct Scsi_Host *) hba->hba_ptr;
+	stgt_hba_t *stgt_hba = *(stgt_hba_t **)shost_priv(scsi_host);
+
+	printk(KERN_INFO "CORE_HBA[%d] - Detached STGT HBA: %s from"
+		" Generic Target Core\n", hba->hba_id,
+		(scsi_host->hostt->name) ? (scsi_host->hostt->name) :
+		"Unknown");
+
+	device_unregister(&stgt_hba->dev);
+	hba->hba_ptr = NULL;
+
+	return 0;
+}
+
+void *stgt_allocate_virtdevice(se_hba_t *hba, const char *name)
+{
+	stgt_dev_virt_t *sdv;
+
+	sdv = kzalloc(sizeof(stgt_dev_virt_t), GFP_KERNEL);
+	if (!(sdv)) {
+		printk(KERN_ERR "Unable to allocate memory for stgt_dev_virt_t\n");
+		return NULL;
+	}
+	sdv->sdv_se_hba = hba;
+
+	printk(KERN_INFO "STGT: Allocated sdv: %p for %s\n", sdv, name);
+	return (void *)sdv;
+}
+
+#warning FIXME: implement stgt_create_virtdevice()
+se_device_t *stgt_create_virtdevice(
+	se_hba_t *hba,
+	se_subsystem_dev_t *se_dev,
+	void *p)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *)p;
+	struct Scsi_Host *sh = (struct Scsi_Host *) hba->hba_ptr;
+
+	if (!(sdv)) {
+		printk(KERN_ERR "Unable to locate stgt_dev_virt_t"
+				" parameter\n");
+		return NULL;
+	}
+
+	printk(KERN_ERR "Unable to locate %d:%d:%d:%d\n", sh->host_no,
+		sdv->sdv_channel_id,  sdv->sdv_target_id, sdv->sdv_lun_id);
+
+	return NULL;
+}
+
+/*	stgt_activate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int stgt_activate_device(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+	struct Scsi_Host *sh = sd->host;
+
+	printk(KERN_INFO "CORE_STGT[%d] - Activating %s Device with TCQ: %d at"
+		" SCSI Location (Channel/Target/LUN) %d/%d/%d\n", sh->host_no,
+		(sdv->sdv_legacy) ? "Legacy" : "REQ",  sd->queue_depth,
+		sd->channel, sd->id, sd->lun);
+
+	return 0;
+}
+
+/*	stgt_deactivate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void stgt_deactivate_device(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+	struct Scsi_Host *sh = sd->host;
+
+	printk(KERN_INFO "CORE_STGT[%d] - Deactivating %s Device with TCQ: %d"
+		" at SCSI Location (Channel/Target/LUN) %d/%d/%d\n",
+		sh->host_no, (sdv->sdv_legacy) ? "Legacy" : "REQ",
+		sd->queue_depth, sd->channel, sd->id, sd->lun);
+}
+
+/*	stgt_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void stgt_free_device(void *p)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) p;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	if (sdv->sdv_bd)
+		sdv->sdv_bd = NULL;
+
+	if (sd) {
+		if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM))
+			scsi_device_put(sd);
+
+		sdv->sdv_sd = NULL;
+	}
+
+	kfree(sdv);
+}
+
+/*	pscsi_transport_complete():
+ *
+ *
+ */
+int stgt_transport_complete(se_task_t *task)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *) task->transport_req;
+	int result;
+
+	result = st->stgt_result;
+	if (status_byte(result) & CHECK_CONDITION)
+		return 1;
+
+	return 0;
+}
+
+/*	stgt_allocate_request(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void *stgt_allocate_request(
+	se_task_t *task,
+	se_device_t *dev)
+{
+	stgt_plugin_task_t *st;
+
+	st = kzalloc(sizeof(stgt_plugin_task_t), GFP_KERNEL);
+	if (!(st)) {
+		printk(KERN_ERR "Unable to allocate stgt_plugin_task_t\n");
+		return NULL;
+	}
+
+	return st;
+}
+
+/*      stgt_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int stgt_do_task(se_task_t *task)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *) task->transport_req;
+	struct Scsi_Host *sh = task->se_dev->se_hba->hba_ptr;
+	struct scsi_cmnd *sc;
+	int tag = MSG_SIMPLE_TAG;
+
+	sc = scsi_host_get_command(sh, st->stgt_direction, GFP_KERNEL);
+	if (!sc) {
+		printk(KERN_ERR "Unable to allocate memory for struct"
+			" scsi_cmnd\n");
+		return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+	}
+
+	memcpy(sc->cmnd, st->stgt_cdb, MAX_COMMAND_SIZE);
+	sc->sdb.length = task->task_size;
+	sc->sdb.table.sgl = task->task_sg;
+	sc->tag = tag;
+
+	BUG();
+#warning FIXME: Get struct scsi_lun for scsi_tgt_queue_command()
+#if 0
+	err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
+			cmd->tag);
+	if (err) {
+		printk(KERN_INFO "scsi_tgt_queue_command() failed for sc:"
+			" %p\n", sc);
+		scsi_host_put_command(sh, sc);
+	}
+#endif
+	return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/*	stgt_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void stgt_free_task(se_task_t *task)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *)task->transport_req;
+
+	kfree(st);
+}
+
+ssize_t stgt_set_configfs_dev_params(se_hba_t *hba,
+	se_subsystem_dev_t *se_dev,
+	const char *page,
+	ssize_t count)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) se_dev->se_dev_su_ptr;
+	struct Scsi_Host *sh = (struct Scsi_Host *) hba->hba_ptr;
+	char *buf, *cur, *ptr, *ptr2;
+	int params = 0, ret;
+
+	buf = kzalloc(count, GFP_KERNEL);
+	if (!(buf)) {
+		printk(KERN_ERR "Unable to allocate memory for temporary"
+				" buffer\n");
+		return -ENOMEM;
+	}
+	memcpy(buf, page, count);
+	cur = buf;
+
+	while (cur) {
+		ptr = strstr(cur, "=");
+		if (!(ptr))
+			goto out;
+
+		*ptr = '\0';
+		ptr++;
+
+		ptr2 = strstr(cur, "scsi_channel_id");
+		if ((ptr2)) {
+			transport_check_dev_params_delim(ptr, &cur);
+			ret = strict_strtoul(ptr, 0,
+				(unsigned long *)&sdv->sdv_channel_id);
+			if (ret < 0) {
+				printk(KERN_ERR "strict_strtoul() failed for"
+					" scsi_channel_id=\n");
+				break;
+			}
+			printk(KERN_INFO "STGT[%d]: Referencing SCSI Channel"
+				" ID: %d\n",  sh->host_no, sdv->sdv_channel_id);
+			sdv->sdv_flags |= PDF_HAS_CHANNEL_ID;
+			params++;
+			continue;
+		}
+		ptr2 = strstr(cur, "scsi_target_id");
+		if ((ptr2)) {
+			transport_check_dev_params_delim(ptr, &cur);
+			ret = strict_strtoul(ptr, 0,
+				(unsigned long *)&sdv->sdv_target_id);
+			if (ret < 0) {
+				printk("strict_strtoul() failed for"
+					" strict_strtoul()\n");
+				break;
+			}
+			printk(KERN_INFO "STGT[%d]: Referencing SCSI Target"
+				" ID: %d\n", sh->host_no, sdv->sdv_target_id);
+			sdv->sdv_flags |= PDF_HAS_TARGET_ID;
+			params++;
+			continue;
+		}
+		ptr2 = strstr(cur, "scsi_lun_id");
+		if ((ptr2)) {
+			transport_check_dev_params_delim(ptr, &cur);
+			ret = strict_strtoul(ptr, 0,
+				(unsigned long *)&sdv->sdv_lun_id);
+			if (ret < 0) {
+				printk("strict_strtoul() failed for"
+					" scsi_lun_id=\n");
+				break;
+			}
+			printk(KERN_INFO "STGT[%d]: Referencing SCSI LUN ID:"
+				" %d\n", sh->host_no, sdv->sdv_lun_id);
+			sdv->sdv_flags |= PDF_HAS_LUN_ID;
+			params++;
+		} else
+			cur = NULL;
+	}
+
+out:
+	kfree(buf);
+	return (params) ? count : -EINVAL;
+}
+
+ssize_t stgt_check_configfs_dev_params(
+	se_hba_t *hba,
+	se_subsystem_dev_t *se_dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) se_dev->se_dev_su_ptr;
+
+	if (!(sdv->sdv_flags & PDF_HAS_CHANNEL_ID) ||
+	    !(sdv->sdv_flags & PDF_HAS_TARGET_ID) ||
+	    !(sdv->sdv_flags & PDF_HAS_TARGET_ID)) {
+		printk(KERN_ERR "Missing scsi_channel_id=, scsi_target_id= and"
+			" scsi_lun_id= parameters\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+ssize_t stgt_show_configfs_dev_params(
+	se_hba_t *hba,
+	se_subsystem_dev_t *se_dev,
+	char *page)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) se_dev->se_dev_su_ptr;
+	int bl = 0;
+
+	__stgt_get_dev_info(sdv, page, &bl);
+	return (ssize_t)bl;
+}
+
+void stgt_get_plugin_info(void *p, char *b, int *bl)
+{
+	*bl += sprintf(b + *bl, "%s STGT <-> Target_Core_Mod Plugin %s\n",
+		PYX_ISCSI_VENDOR, STGT_VERSION);
+}
+
+void stgt_get_hba_info(se_hba_t *hba, char *b, int *bl)
+{
+	struct Scsi_Host *sh = (struct Scsi_Host *) hba->hba_ptr;
+
+	*bl += sprintf(b + *bl, "Core Host ID: %u  SCSI Host ID: %u\n",
+			 hba->hba_id, sh->host_no);
+	*bl += sprintf(b + *bl, "        SCSI HBA: %s  <local>\n",
+		(sh->hostt->name) ? (sh->hostt->name) : "Unknown");
+}
+
+void stgt_get_dev_info(se_device_t *dev, char *b, int *bl)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+
+	__stgt_get_dev_info(sdv, b, bl);
+}
+
+void __stgt_get_dev_info(stgt_dev_virt_t *sdv, char *b, int *bl)
+{
+	int i;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	*bl += sprintf(b + *bl, "STGT SCSI Device Bus Location:"
+		" Channel ID: %d Target ID: %d LUN: %d\n",
+		sdv->sdv_channel_id, sdv->sdv_target_id, sdv->sdv_lun_id);
+
+	if (sd) {
+		*bl += sprintf(b + *bl, "        ");
+		*bl += sprintf(b + *bl, "Vendor: ");
+		for (i = 0; i < 8; i++) {
+			if (ISPRINT(sd->vendor[i]))   /* printable character? */
+				*bl += sprintf(b + *bl, "%c", sd->vendor[i]);
+			else
+				*bl += sprintf(b + *bl, " ");
+		}
+		*bl += sprintf(b + *bl, " Model: ");
+		for (i = 0; i < 16; i++) {
+			if (ISPRINT(sd->model[i]))   /* printable character ? */
+				*bl += sprintf(b + *bl, "%c", sd->model[i]);
+			else
+				*bl += sprintf(b + *bl, " ");
+		}
+		*bl += sprintf(b + *bl, " Rev: ");
+		for (i = 0; i < 4; i++) {
+			if (ISPRINT(sd->rev[i]))   /* printable character ? */
+				*bl += sprintf(b + *bl, "%c", sd->rev[i]);
+			else
+				*bl += sprintf(b + *bl, " ");
+		}
+
+		if (sd->type == TYPE_DISK) {
+			struct scsi_disk *sdisk =
+					dev_get_drvdata(&sd->sdev_gendev);
+			struct gendisk *disk = (struct gendisk *) sdisk->disk;
+			struct block_device *bdev = bdget(MKDEV(disk->major,
+						disk->first_minor));
+
+			bdev->bd_disk = disk;
+			*bl += sprintf(b + *bl, "   %s\n", (!bdev->bd_holder) ?
+					"" : (bdev->bd_holder ==
+					(struct scsi_device *)sd) ?
+					"CLAIMED: PSCSI" : "CLAIMED: OS");
+		} else
+			*bl += sprintf(b + *bl, "\n");
+	}
+
+	return;
+}
+
+/*      stgt_map_task_SG():
+ *
+ *
+ */
+int stgt_map_task_SG(se_task_t *task)
+{
+	return 0;
+}
+
+/*	stgt_map_task_non_SG():
+ *
+ *
+ */
+int stgt_map_task_non_SG(se_task_t *task)
+{
+	return 0;
+}
+
+/*	stgt_CDB_inquiry():
+ *
+ *
+ */
+int stgt_CDB_inquiry(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *) task->transport_req;
+
+	st->stgt_direction = DMA_FROM_DEVICE;
+	return stgt_map_task_non_SG(task);
+}
+
+int stgt_CDB_none(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *) task->transport_req;
+
+	st->stgt_direction = DMA_NONE;
+	return 0;
+}
+
+/*	stgt_CDB_read_non_SG():
+ *
+ *
+ */
+int stgt_CDB_read_non_SG(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *pt = (stgt_plugin_task_t *) task->transport_req;
+
+	pt->stgt_direction = DMA_FROM_DEVICE;
+	return stgt_map_task_non_SG(task);
+}
+
+/*	stgt_CDB_read_SG():
+ *
+ *
+ */
+int stgt_CDB_read_SG(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *pt = (stgt_plugin_task_t *) task->transport_req;
+
+	pt->stgt_direction = DMA_FROM_DEVICE;
+
+	if (stgt_map_task_SG(task) < 0)
+		return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+	return task->task_sg_num;
+}
+
+/*	stgt_CDB_write_non_SG():
+ *
+ *
+ */
+int stgt_CDB_write_non_SG(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *pt = (stgt_plugin_task_t *) task->transport_req;
+
+	pt->stgt_direction = DMA_TO_DEVICE;
+	return stgt_map_task_non_SG(task);
+}
+
+/*	stgt_CDB_write_SG():
+ *
+ *
+ */
+int stgt_CDB_write_SG(se_task_t *task, u32 size)
+{
+	stgt_plugin_task_t *st = (stgt_plugin_task_t *) task->transport_req;
+
+	st->stgt_direction = DMA_TO_DEVICE;
+
+	if (stgt_map_task_SG(task) < 0)
+		return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+	return task->task_sg_num;
+}
+
+/*	stgt_check_lba():
+ *
+ *
+ */
+int stgt_check_lba(unsigned long long lba, se_device_t *dev)
+{
+	return 0;
+}
+
+/*	stgt_check_for_SG():
+ *
+ *
+ */
+int stgt_check_for_SG(se_task_t *task)
+{
+	return task->task_sg_num;
+}
+
+/*	stgt_get_cdb():
+ *
+ *
+ */
+unsigned char *stgt_get_cdb(se_task_t *task)
+{
+	stgt_plugin_task_t *pt = (stgt_plugin_task_t *) task->transport_req;
+
+	return pt->stgt_cdb;
+}
+
+/*	stgt_get_sense_buffer():
+ *
+ *
+ */
+unsigned char *stgt_get_sense_buffer(se_task_t *task)
+{
+	stgt_plugin_task_t *pt = (stgt_plugin_task_t *) task->transport_req;
+
+	return (unsigned char *)&pt->stgt_sense[0];
+}
+
+/*	stgt_get_blocksize():
+ *
+ *
+ */
+u32 stgt_get_blocksize(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	return sd->sector_size;
+}
+
+/*	stgt_get_device_rev():
+ *
+ *
+ */
+u32 stgt_get_device_rev(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1;
+}
+
+/*	stgt_get_device_type():
+ *
+ *
+ */
+u32 stgt_get_device_type(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	return sd->type;
+}
+
+/*	stgt_get_dma_length():
+ *
+ *
+ */
+u32 stgt_get_dma_length(u32 task_size, se_device_t *dev)
+{
+	return PAGE_SIZE;
+}
+
+/*	stgt_get_max_sectors():
+ *
+ *
+ */
+u32 stgt_get_max_sectors(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+	return (sd->host->max_sectors > sd->request_queue->max_sectors) ?
+		sd->request_queue->max_sectors : sd->host->max_sectors;
+}
+
+/*	stgt_get_queue_depth():
+ *
+ *
+ */
+u32 stgt_get_queue_depth(se_device_t *dev)
+{
+	stgt_dev_virt_t *sdv = (stgt_dev_virt_t *) dev->dev_ptr;
+	struct scsi_device *sd = (struct scsi_device *) sdv->sdv_sd;
+
+	return sd->queue_depth;
+}
+
+void stgt_shutdown_hba(se_hba_t *hba)
+{
+	return;
+}
+
+/*	stgt_handle_SAM_STATUS_failures():
+ *
+ *
+ */
+static inline void stgt_process_SAM_status(
+	se_task_t *task,
+	stgt_plugin_task_t *st)
+{
+	task->task_scsi_status = status_byte(st->stgt_result);
+	if ((task->task_scsi_status)) {
+		task->task_scsi_status <<= 1;
+		printk(KERN_INFO "PSCSI Status Byte exception at task: %p CDB:"
+			" 0x%02x Result: 0x%08x\n", task, st->stgt_cdb[0],
+			st->stgt_result);
+	}
+
+	switch (host_byte(st->stgt_result)) {
+	case DID_OK:
+		transport_complete_task(task, (!task->task_scsi_status));
+		break;
+	default:
+		printk(KERN_INFO "PSCSI Host Byte exception at task: %p CDB:"
+			" 0x%02x Result: 0x%08x\n", task, st->stgt_cdb[0],
+			st->stgt_result);
+		task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
+		task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+		TASK_CMD(task)->transport_error_status =
+					PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+		transport_complete_task(task, 0);
+		break;
+	}
+
+	return;
+}
+
+/*
+ * Use for struct scsi_host_template->transfer_response() function pointer
+ * that is called from STGT in drivers/scsi/scsi_tgt_lib.c:
+ * scsi_tgt_transfer_response()
+ */
+int stgt_transfer_response(struct scsi_cmnd *sc,
+			   void (*done)(struct scsi_cmnd *))
+{
+	se_task_t *task = (se_task_t *)sc->SCp.ptr;
+	stgt_plugin_task_t *st;
+
+	if (!task) {
+		printk("se_task_t is NULL!\n");
+		BUG();
+	}
+	st = (stgt_plugin_task_t *)task->transport_req;
+	if (!st) {
+		printk("stgt_plugin_task_t is NULL!\n");
+		BUG();
+	}
+	st->stgt_result = sc->request->errors;
+	st->stgt_resid = sc->request->data_len;
+
+#warning FIXME: Sense for STGT struct scsi_cmnd usage..
+#if 0
+	memcpy(st->stgt_sense, sense, SCSI_SENSE_BUFFERSIZE);
+#endif
+	stgt_process_SAM_status(task, st);
+	done(sc);
+	return 0;
+}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4faaf12..ec130a6 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -516,6 +516,13 @@ void transport_load_plugins(void)
 			pscsi_template.name, PLUGIN_TYPE_TRANSPORT,
 			pscsi_template.get_plugin_info, NULL, NULL, &ret);
 #endif
+#ifdef STGT_PLUGIN
+	plugin_register((void *)&stgt_template, stgt_template.type,
+			stgt_template.name, PLUGIN_TYPE_TRANSPORT,
+			stgt_template.get_plugin_info,
+			stgt_template.plugin_init,
+			stgt_template.plugin_free, &ret);
+#endif
 #ifdef PYX_IBLOCK
 	plugin_register((void *)&iblock_template, iblock_template.type,
 			iblock_template.name, PLUGIN_TYPE_TRANSPORT,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 0151915..182270c 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -150,7 +150,7 @@
 
 /* se_device_t->type */
 #define PSCSI					1
-#define SSCSI					2
+#define STGT					2
 #define PATA					3
 #define IBLOCK					4
 #define RAMDISK_DR				5
diff --git a/include/target/target_core_stgt.h b/include/target/target_core_stgt.h
new file mode 100644
index 0000000..89a4f37
--- /dev/null
+++ b/include/target/target_core_stgt.h
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Filename:  target_core_stgt.h
+ *
+ * This file contains the generic target mode <-> Linux STGT subsystem plugin.
+ * specific definitions and prototypes.
+ *
+ * Copyright (c) 2009 Rising Tide Systems, Inc.
+ * Copyright (c) 2009 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@xxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#ifndef TARGET_CORE_STGT_H
+#define TARGET_CORE_STGT_H
+
+#define STGT_VERSION		"v1.0"
+#define STGT_NAME		"stgt_tcm"
+
+/* used in pscsi_add_device_to_list() */
+#define STGT_DEFAULT_QUEUEDEPTH	1
+
+#define PS_RETRY		5
+#define PS_TIMEOUT_DISK		(15*HZ)
+#define PS_TIMEOUT_OTHER	(500*HZ)
+
+extern se_global_t *se_global;
+extern struct block_device *linux_blockdevice_claim(int, int, void *);
+extern int linux_blockdevice_release(int, int, struct block_device *);
+extern int linux_blockdevice_check(int, int);
+
+extern int stgt_CDB_inquiry(se_task_t *, u32);
+extern int stgt_CDB_none(se_task_t *, u32);
+extern int stgt_CDB_read_non_SG(se_task_t *, u32);
+extern int stgt_CDB_read_SG(se_task_t *, u32);
+extern int stgt_CDB_write_non_SG(se_task_t *, u32);
+extern int stgt_CDB_write_SG(se_task_t *, u32);
+
+#ifndef STGT_INCLUDE_STRUCTS
+extern int stgt_plugin_init(void);
+extern void stgt_plugin_free(void);
+extern int stgt_attach_hba(se_hba_t *, u32);
+extern int stgt_detach_hba(se_hba_t *);
+#if 0
+extern int pscsi_claim_phydevice(se_hba_t *, se_device_t *);
+extern int pscsi_release_phydevice(se_device_t *);
+#endif
+extern void *stgt_allocate_virtdevice(se_hba_t *, const char *);
+extern se_device_t *stgt_create_virtdevice(se_hba_t *, se_subsystem_dev_t *,
+					void *);
+extern int stgt_activate_device(se_device_t *);
+extern void stgt_deactivate_device(se_device_t *);
+extern void stgt_free_device(void *);
+extern int stgt_transport_complete(se_task_t *);
+extern void *stgt_allocate_request(se_task_t *, se_device_t *);
+extern int stgt_do_task(se_task_t *);
+extern void stgt_free_task(se_task_t *);
+extern ssize_t stgt_set_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+						const char *, ssize_t);
+extern ssize_t stgt_check_configfs_dev_params(se_hba_t *,
+						se_subsystem_dev_t *);
+extern ssize_t stgt_show_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+						char *);
+#if 0
+extern se_device_t *scsi_create_virtdevice_from_fd(se_subsystem_dev_t *,
+						const char *);
+#endif
+extern void stgt_get_plugin_info(void *, char *, int *);
+extern void stgt_get_hba_info(se_hba_t *, char *, int *);
+extern void stgt_get_dev_info(se_device_t *, char *, int *);
+extern int stgt_check_lba(unsigned long long, se_device_t *);
+extern int stgt_check_for_SG(se_task_t *);
+extern unsigned char *stgt_get_cdb(se_task_t *);
+extern unsigned char *stgt_get_sense_buffer(se_task_t *);
+extern u32 stgt_get_blocksize(se_device_t *);
+extern u32 stgt_get_device_rev(se_device_t *);
+extern u32 stgt_get_device_type(se_device_t *);
+extern u32 stgt_get_dma_length(u32, se_device_t *);
+extern u32 stgt_get_max_sectors(se_device_t *);
+extern u32 stgt_get_queue_depth(se_device_t *);
+extern void stgt_shutdown_hba(struct se_hba_s *);
+extern void stgt_req_done(struct request *, int);
+extern int stgt_transfer_response(struct scsi_cmnd *,
+			          void (*done)(struct scsi_cmnd *));
+#endif
+
+#include <linux/device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_device.h>
+#include <linux/kref.h>
+#include <linux/kobject.h>
+
+typedef struct stgt_plugin_task_s {
+	unsigned char stgt_cdb[SCSI_CDB_SIZE];
+	unsigned char stgt_sense[SCSI_SENSE_BUFFERSIZE];
+	int	stgt_direction;
+	int	stgt_result;
+	u32	stgt_resid;
+	struct scsi_cmnd *stgt_cmd;
+} stgt_plugin_task_t;
+
+#define PDF_HAS_CHANNEL_ID	0x01
+#define PDF_HAS_TARGET_ID	0x02
+#define PDF_HAS_LUN_ID		0x04
+#define PDF_HAS_VPD_UNIT_SERIAL 0x08
+#define PDF_HAS_VPD_DEV_IDENT	0x10
+
+typedef struct stgt_dev_virt_s {
+	int	sdv_flags;
+	int	sdv_legacy; /* Use scsi_execute_async() from HTCL */
+	int	sdv_channel_id;
+	int	sdv_target_id;
+	int	sdv_lun_id;
+	struct block_device *sdv_bd; /* Temporary for v2.6.28 */
+	struct scsi_device *sdv_sd;
+	struct se_hba_s *sdv_se_hba;
+} stgt_dev_virt_t;
+
+typedef struct stgt_hba_s {
+	struct device dev;
+	struct se_hba_s *se_hba;
+	struct Scsi_Host *scsi_host;
+} stgt_hba_t;
+
+extern void __stgt_get_dev_info(stgt_dev_virt_t *, char *, int *);
+
+/*
+ * We use the generic command sequencer, so we must setup
+ * se_subsystem_spc_t.
+ */
+#ifndef STGT_INCLUDE_STRUCTS
+
+se_subsystem_spc_t stgt_template_spc = {
+	.inquiry		= stgt_CDB_inquiry,
+	.none			= stgt_CDB_none,
+	.read_non_SG		= stgt_CDB_read_non_SG,
+	.read_SG		= stgt_CDB_read_SG,
+	.write_non_SG		= stgt_CDB_write_non_SG,
+	.write_SG		= stgt_CDB_write_SG,
+};
+
+se_subsystem_api_t stgt_template = {
+	.name			= "stgt",			\
+	.type			= STGT,				\
+	.transport_type		= TRANSPORT_PLUGIN_VHBA_PDEV,	\
+	.attach_hba		= stgt_attach_hba,		\
+	.detach_hba		= stgt_detach_hba,		\
+	.activate_device	= stgt_activate_device,		\
+	.deactivate_device	= stgt_deactivate_device,	\
+	.claim_phydevice	= NULL,				\
+	.allocate_virtdevice	= stgt_allocate_virtdevice,	\
+	.create_virtdevice	= stgt_create_virtdevice,	\
+	.free_device		= stgt_free_device,		\
+	.release_phydevice	= NULL,				\
+	.transport_complete	= stgt_transport_complete,	\
+	.allocate_request	= stgt_allocate_request,	\
+	.do_task		= stgt_do_task,			\
+	.free_task		= stgt_free_task,		\
+	.check_configfs_dev_params = stgt_check_configfs_dev_params, \
+	.set_configfs_dev_params = stgt_set_configfs_dev_params, \
+	.show_configfs_dev_params = stgt_show_configfs_dev_params, \
+	.create_virtdevice_from_fd = NULL,			\
+	.plugin_init		= stgt_plugin_init,		\
+	.plugin_free		= stgt_plugin_free,		\
+	.get_plugin_info	= stgt_get_plugin_info,		\
+	.get_hba_info		= stgt_get_hba_info,		\
+	.get_dev_info		= stgt_get_dev_info,		\
+	.check_lba		= stgt_check_lba,		\
+	.check_for_SG		= stgt_check_for_SG,		\
+	.get_cdb		= stgt_get_cdb,			\
+	.get_sense_buffer	= stgt_get_sense_buffer,	\
+	.get_blocksize		= stgt_get_blocksize,		\
+	.get_device_rev		= stgt_get_device_rev,		\
+	.get_device_type	= stgt_get_device_type,		\
+	.get_dma_length		= stgt_get_dma_length,		\
+	.get_max_sectors	= stgt_get_max_sectors,		\
+	.get_queue_depth	= stgt_get_queue_depth,		\
+	.shutdown_hba		= stgt_shutdown_hba,		\
+	.write_pending		= NULL,				\
+	.spc			= &stgt_template_spc,		\
+};
+
+#endif
+
+#endif   /*** TARGET_CORE_STGT_H ***/
diff --git a/include/target/target_core_transport_plugin.h b/include/target/target_core_transport_plugin.h
index 118ee3a..7e46360 100644
--- a/include/target/target_core_transport_plugin.h
+++ b/include/target/target_core_transport_plugin.h
@@ -35,6 +35,13 @@
 extern se_subsystem_api_t pscsi_template;
 #endif /* PARALLEL_SCSI */
 
+#ifdef STGT_PLUGIN
+#define STGT_INCLUDE_STRUCTS
+#include <target/target_core_stgt.h>
+#undef STGT_INCLUDE_STRUCTS
+extern se_subsystem_api_t stgt_template;
+#endif /* STGT_PLUGIN */
+
 #ifdef PYX_IBLOCK
 #define IBLOCK_INCLUDE_STRUCTS
 #include <target/target_core_iblock.h>
-- 
1.5.4.1



--- End Message ---

[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux