You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
[SCSI] target: Add LIO target core v4.0.0-rc6
LIO target is a full featured in-kernel target framework with the
following feature set:
High-performance, non-blocking, multithreaded architecture with SIMD
support.
Advanced SCSI feature set:
* Persistent Reservations (PRs)
* Asymmetric Logical Unit Assignment (ALUA)
* Protocol and intra-nexus multiplexing, load-balancing and failover (MC/S)
* Full Error Recovery (ERL=0,1,2)
* Active/active task migration and session continuation (ERL=2)
* Thin LUN provisioning (UNMAP and WRITE_SAMExx)
Multiprotocol target plugins
Storage media independence:
* Virtualization of all storage media; transparent mapping of IO to LUNs
* No hard limits on number of LUNs per Target; maximum LUN size ~750 TB
* Backstores: SATA, SAS, SCSI, BluRay, DVD, FLASH, USB, ramdisk, etc.
Standards compliance:
* Full compliance with IETF (RFC 3720)
* Full implementation of SPC-4 PRs and ALUA
Significant code cleanups done by Christoph Hellwig.
[jejb: fix up for new block bdev exclusive interface. Minor fixes from
Randy Dunlap and Dan Carpenter.]
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
committed by
James Bottomley
parent
f4013c3879
commit
c66ac9db8d
1094
Documentation/target/tcm_mod_builder.py
Executable file
1094
Documentation/target/tcm_mod_builder.py
Executable file
File diff suppressed because it is too large
Load Diff
145
Documentation/target/tcm_mod_builder.txt
Normal file
145
Documentation/target/tcm_mod_builder.txt
Normal file
@@ -0,0 +1,145 @@
|
||||
>>>>>>>>>> The TCM v4 fabric module script generator <<<<<<<<<<
|
||||
|
||||
Greetings all,
|
||||
|
||||
This document is intended to be a mini-HOWTO for using the tcm_mod_builder.py
|
||||
script to generate a brand new functional TCM v4 fabric .ko module of your very own,
|
||||
that once built can be immediately be loaded to start access the new TCM/ConfigFS
|
||||
fabric skeleton, by simply using:
|
||||
|
||||
modprobe $TCM_NEW_MOD
|
||||
mkdir -p /sys/kernel/config/target/$TCM_NEW_MOD
|
||||
|
||||
This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following
|
||||
|
||||
*) Generate new API callers for drivers/target/target_core_fabric_configs.c logic
|
||||
->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg()
|
||||
->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c
|
||||
*) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module
|
||||
using a skeleton struct target_core_fabric_ops API template.
|
||||
*) Based on user defined T10 Proto_Ident for the new fabric module being built,
|
||||
the TransportID / Initiator and Target WWPN related handlers for
|
||||
SPC-3 persistent reservation are automatically generated in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c
|
||||
using drivers/target/target_core_fabric_lib.c logic.
|
||||
*) NOP API calls for all other Data I/O path and fabric dependent attribute logic
|
||||
in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c
|
||||
|
||||
tcm_mod_builder.py depends upon the mandatory '-p $PROTO_IDENT' and '-m
|
||||
$FABRIC_MOD_name' parameters, and actually running the script looks like:
|
||||
|
||||
target:/mnt/sdb/lio-core-2.6.git/Documentation/target# python tcm_mod_builder.py -p iSCSI -m tcm_nab5000
|
||||
tcm_dir: /mnt/sdb/lio-core-2.6.git/Documentation/target/../../
|
||||
Set fabric_mod_name: tcm_nab5000
|
||||
Set fabric_mod_dir:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000
|
||||
Using proto_ident: iSCSI
|
||||
Creating fabric_mod_dir:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_base.h
|
||||
Using tcm_mod_scan_fabric_ops:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../include/target/target_core_fabric_ops.h
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.c
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.h
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_configfs.c
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kbuild
|
||||
Writing file:
|
||||
/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kconfig
|
||||
Would you like to add tcm_nab5000to drivers/target/Kbuild..? [yes,no]: yes
|
||||
Would you like to add tcm_nab5000to drivers/target/Kconfig..? [yes,no]: yes
|
||||
|
||||
At the end of tcm_mod_builder.py. the script will ask to add the following
|
||||
line to drivers/target/Kbuild:
|
||||
|
||||
obj-$(CONFIG_TCM_NAB5000) += tcm_nab5000/
|
||||
|
||||
and the same for drivers/target/Kconfig:
|
||||
|
||||
source "drivers/target/tcm_nab5000/Kconfig"
|
||||
|
||||
*) Run 'make menuconfig' and select the new CONFIG_TCM_NAB5000 item:
|
||||
|
||||
<M> TCM_NAB5000 fabric module
|
||||
|
||||
*) Build using 'make modules', once completed you will have:
|
||||
|
||||
target:/mnt/sdb/lio-core-2.6.git# ls -la drivers/target/tcm_nab5000/
|
||||
total 1348
|
||||
drwxr-xr-x 2 root root 4096 2010-10-05 03:23 .
|
||||
drwxr-xr-x 9 root root 4096 2010-10-05 03:22 ..
|
||||
-rw-r--r-- 1 root root 282 2010-10-05 03:22 Kbuild
|
||||
-rw-r--r-- 1 root root 171 2010-10-05 03:22 Kconfig
|
||||
-rw-r--r-- 1 root root 49 2010-10-05 03:23 modules.order
|
||||
-rw-r--r-- 1 root root 738 2010-10-05 03:22 tcm_nab5000_base.h
|
||||
-rw-r--r-- 1 root root 9096 2010-10-05 03:22 tcm_nab5000_configfs.c
|
||||
-rw-r--r-- 1 root root 191200 2010-10-05 03:23 tcm_nab5000_configfs.o
|
||||
-rw-r--r-- 1 root root 40504 2010-10-05 03:23 .tcm_nab5000_configfs.o.cmd
|
||||
-rw-r--r-- 1 root root 5414 2010-10-05 03:22 tcm_nab5000_fabric.c
|
||||
-rw-r--r-- 1 root root 2016 2010-10-05 03:22 tcm_nab5000_fabric.h
|
||||
-rw-r--r-- 1 root root 190932 2010-10-05 03:23 tcm_nab5000_fabric.o
|
||||
-rw-r--r-- 1 root root 40713 2010-10-05 03:23 .tcm_nab5000_fabric.o.cmd
|
||||
-rw-r--r-- 1 root root 401861 2010-10-05 03:23 tcm_nab5000.ko
|
||||
-rw-r--r-- 1 root root 265 2010-10-05 03:23 .tcm_nab5000.ko.cmd
|
||||
-rw-r--r-- 1 root root 459 2010-10-05 03:23 tcm_nab5000.mod.c
|
||||
-rw-r--r-- 1 root root 23896 2010-10-05 03:23 tcm_nab5000.mod.o
|
||||
-rw-r--r-- 1 root root 22655 2010-10-05 03:23 .tcm_nab5000.mod.o.cmd
|
||||
-rw-r--r-- 1 root root 379022 2010-10-05 03:23 tcm_nab5000.o
|
||||
-rw-r--r-- 1 root root 211 2010-10-05 03:23 .tcm_nab5000.o.cmd
|
||||
|
||||
*) Load the new module, create a lun_0 configfs group, and add new TCM Core
|
||||
IBLOCK backstore symlink to port:
|
||||
|
||||
target:/mnt/sdb/lio-core-2.6.git# insmod drivers/target/tcm_nab5000.ko
|
||||
target:/mnt/sdb/lio-core-2.6.git# mkdir -p /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0
|
||||
target:/mnt/sdb/lio-core-2.6.git# cd /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0/
|
||||
target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# ln -s /sys/kernel/config/target/core/iblock_0/lvm_test0 nab5000_port
|
||||
|
||||
target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# cd -
|
||||
target:/mnt/sdb/lio-core-2.6.git# tree /sys/kernel/config/target/nab5000/
|
||||
/sys/kernel/config/target/nab5000/
|
||||
|-- discovery_auth
|
||||
|-- iqn.foo
|
||||
| `-- tpgt_1
|
||||
| |-- acls
|
||||
| |-- attrib
|
||||
| |-- lun
|
||||
| | `-- lun_0
|
||||
| | |-- alua_tg_pt_gp
|
||||
| | |-- alua_tg_pt_offline
|
||||
| | |-- alua_tg_pt_status
|
||||
| | |-- alua_tg_pt_write_md
|
||||
| | `-- nab5000_port -> ../../../../../../target/core/iblock_0/lvm_test0
|
||||
| |-- np
|
||||
| `-- param
|
||||
`-- version
|
||||
|
||||
target:/mnt/sdb/lio-core-2.6.git# lsmod
|
||||
Module Size Used by
|
||||
tcm_nab5000 3935 4
|
||||
iscsi_target_mod 193211 0
|
||||
target_core_stgt 8090 0
|
||||
target_core_pscsi 11122 1
|
||||
target_core_file 9172 2
|
||||
target_core_iblock 9280 1
|
||||
target_core_mod 228575 31
|
||||
tcm_nab5000,iscsi_target_mod,target_core_stgt,target_core_pscsi,target_core_file,target_core_iblock
|
||||
libfc 73681 0
|
||||
scsi_debug 56265 0
|
||||
scsi_tgt 8666 1 target_core_stgt
|
||||
configfs 20644 2 target_core_mod
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Future TODO items:
|
||||
|
||||
*) Add more T10 proto_idents
|
||||
*) Make tcm_mod_dump_fabric_ops() smarter and generate function pointer
|
||||
defs directly from include/target/target_core_fabric_ops.h:struct target_core_fabric_ops
|
||||
structure members.
|
||||
|
||||
October 5th, 2010
|
||||
Nicholas A. Bellinger <nab@linux-iscsi.org>
|
||||
@@ -26,6 +26,8 @@ source "drivers/ata/Kconfig"
|
||||
|
||||
source "drivers/md/Kconfig"
|
||||
|
||||
source "drivers/target/Kconfig"
|
||||
|
||||
source "drivers/message/fusion/Kconfig"
|
||||
|
||||
source "drivers/firewire/Kconfig"
|
||||
|
||||
@@ -46,6 +46,7 @@ obj-y += macintosh/
|
||||
obj-$(CONFIG_IDE) += ide/
|
||||
obj-$(CONFIG_SCSI) += scsi/
|
||||
obj-$(CONFIG_ATA) += ata/
|
||||
obj-$(CONFIG_TARGET_CORE) += target/
|
||||
obj-$(CONFIG_MTD) += mtd/
|
||||
obj-$(CONFIG_SPI) += spi/
|
||||
obj-y += net/
|
||||
|
||||
32
drivers/target/Kconfig
Normal file
32
drivers/target/Kconfig
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
menuconfig TARGET_CORE
|
||||
tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure"
|
||||
depends on SCSI && BLOCK
|
||||
select CONFIGFS_FS
|
||||
default n
|
||||
help
|
||||
Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
|
||||
control path for target_core_mod. This includes built-in TCM RAMDISK
|
||||
subsystem logic for virtual LUN 0 access
|
||||
|
||||
if TARGET_CORE
|
||||
|
||||
config TCM_IBLOCK
|
||||
tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK"
|
||||
help
|
||||
Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered
|
||||
access to Linux/Block devices using BIO
|
||||
|
||||
config TCM_FILEIO
|
||||
tristate "TCM/FILEIO Subsystem Plugin for Linux/VFS"
|
||||
help
|
||||
Say Y here to enable the TCM/FILEIO subsystem plugin for buffered
|
||||
access to Linux/VFS struct file or struct block_device
|
||||
|
||||
config TCM_PSCSI
|
||||
tristate "TCM/pSCSI Subsystem Plugin for Linux/SCSI"
|
||||
help
|
||||
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
|
||||
passthrough access to Linux/SCSI device
|
||||
|
||||
endif
|
||||
24
drivers/target/Makefile
Normal file
24
drivers/target/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/
|
||||
|
||||
target_core_mod-y := target_core_configfs.o \
|
||||
target_core_device.o \
|
||||
target_core_fabric_configfs.o \
|
||||
target_core_fabric_lib.o \
|
||||
target_core_hba.o \
|
||||
target_core_pr.o \
|
||||
target_core_alua.o \
|
||||
target_core_scdb.o \
|
||||
target_core_tmr.o \
|
||||
target_core_tpg.o \
|
||||
target_core_transport.o \
|
||||
target_core_cdb.o \
|
||||
target_core_ua.o \
|
||||
target_core_rd.o \
|
||||
target_core_mib.o
|
||||
|
||||
obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
|
||||
|
||||
# Subsystem modules
|
||||
obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
|
||||
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
|
||||
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
|
||||
1991
drivers/target/target_core_alua.c
Normal file
1991
drivers/target/target_core_alua.c
Normal file
File diff suppressed because it is too large
Load Diff
126
drivers/target/target_core_alua.h
Normal file
126
drivers/target/target_core_alua.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef TARGET_CORE_ALUA_H
|
||||
#define TARGET_CORE_ALUA_H
|
||||
|
||||
/*
|
||||
* INQUIRY response data, TPGS Field
|
||||
*
|
||||
* from spc4r17 section 6.4.2 Table 135
|
||||
*/
|
||||
#define TPGS_NO_ALUA 0x00
|
||||
#define TPGS_IMPLICT_ALUA 0x10
|
||||
#define TPGS_EXPLICT_ALUA 0x20
|
||||
|
||||
/*
|
||||
* ASYMMETRIC ACCESS STATE field
|
||||
*
|
||||
* from spc4r17 section 6.27 Table 245
|
||||
*/
|
||||
#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0
|
||||
#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
|
||||
#define ALUA_ACCESS_STATE_STANDBY 0x2
|
||||
#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
|
||||
#define ALUA_ACCESS_STATE_OFFLINE 0xe
|
||||
#define ALUA_ACCESS_STATE_TRANSITION 0xf
|
||||
|
||||
/*
|
||||
* REPORT_TARGET_PORT_GROUP STATUS CODE
|
||||
*
|
||||
* from spc4r17 section 6.27 Table 246
|
||||
*/
|
||||
#define ALUA_STATUS_NONE 0x00
|
||||
#define ALUA_STATUS_ALTERED_BY_EXPLICT_STPG 0x01
|
||||
#define ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA 0x02
|
||||
|
||||
/*
|
||||
* From spc4r17, Table D.1: ASC and ASCQ Assignement
|
||||
*/
|
||||
#define ASCQ_04H_ALUA_STATE_TRANSITION 0x0a
|
||||
#define ASCQ_04H_ALUA_TG_PT_STANDBY 0x0b
|
||||
#define ASCQ_04H_ALUA_TG_PT_UNAVAILABLE 0x0c
|
||||
#define ASCQ_04H_ALUA_OFFLINE 0x12
|
||||
|
||||
/*
|
||||
* Used as the default for Active/NonOptimized delay (in milliseconds)
|
||||
* This can also be changed via configfs on a per target port group basis..
|
||||
*/
|
||||
#define ALUA_DEFAULT_NONOP_DELAY_MSECS 100
|
||||
#define ALUA_MAX_NONOP_DELAY_MSECS 10000 /* 10 seconds */
|
||||
/*
|
||||
* Used for implict and explict ALUA transitional delay, that is disabled
|
||||
* by default, and is intended to be used for debugging client side ALUA code.
|
||||
*/
|
||||
#define ALUA_DEFAULT_TRANS_DELAY_MSECS 0
|
||||
#define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */
|
||||
/*
|
||||
* Used by core_alua_update_tpg_primary_metadata() and
|
||||
* core_alua_update_tpg_secondary_metadata()
|
||||
*/
|
||||
#define ALUA_METADATA_PATH_LEN 512
|
||||
/*
|
||||
* Used by core_alua_update_tpg_secondary_metadata()
|
||||
*/
|
||||
#define ALUA_SECONDARY_METADATA_WWN_LEN 256
|
||||
|
||||
extern struct kmem_cache *t10_alua_lu_gp_cache;
|
||||
extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
|
||||
extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
|
||||
extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
|
||||
|
||||
extern int core_emulate_report_target_port_groups(struct se_cmd *);
|
||||
extern int core_emulate_set_target_port_groups(struct se_cmd *);
|
||||
extern int core_alua_check_nonop_delay(struct se_cmd *);
|
||||
extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
|
||||
struct se_device *, struct se_port *,
|
||||
struct se_node_acl *, int, int);
|
||||
extern char *core_alua_dump_status(int);
|
||||
extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int);
|
||||
extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16);
|
||||
extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *);
|
||||
extern void core_alua_free_lu_gp_mem(struct se_device *);
|
||||
extern struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *);
|
||||
extern void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *);
|
||||
extern void __core_alua_attach_lu_gp_mem(struct t10_alua_lu_gp_member *,
|
||||
struct t10_alua_lu_gp *);
|
||||
extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *,
|
||||
struct t10_alua_lu_gp *);
|
||||
extern void core_alua_drop_lu_gp_dev(struct se_device *);
|
||||
extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
|
||||
struct se_subsystem_dev *, const char *, int);
|
||||
extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16);
|
||||
extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
|
||||
struct se_port *);
|
||||
extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *);
|
||||
extern void core_alua_free_tg_pt_gp_mem(struct se_port *);
|
||||
extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *,
|
||||
struct t10_alua_tg_pt_gp *);
|
||||
extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *);
|
||||
extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *,
|
||||
size_t);
|
||||
extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *);
|
||||
extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *,
|
||||
const char *, size_t);
|
||||
extern ssize_t core_alua_show_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
|
||||
char *);
|
||||
extern ssize_t core_alua_store_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
|
||||
const char *, size_t);
|
||||
extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
|
||||
char *);
|
||||
extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
|
||||
const char *, size_t);
|
||||
extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *,
|
||||
char *);
|
||||
extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *,
|
||||
const char *, size_t);
|
||||
extern ssize_t core_alua_show_offline_bit(struct se_lun *, char *);
|
||||
extern ssize_t core_alua_store_offline_bit(struct se_lun *, const char *,
|
||||
size_t);
|
||||
extern ssize_t core_alua_show_secondary_status(struct se_lun *, char *);
|
||||
extern ssize_t core_alua_store_secondary_status(struct se_lun *,
|
||||
const char *, size_t);
|
||||
extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *,
|
||||
char *);
|
||||
extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *,
|
||||
const char *, size_t);
|
||||
extern int core_setup_alua(struct se_device *, int);
|
||||
|
||||
#endif /* TARGET_CORE_ALUA_H */
|
||||
1131
drivers/target/target_core_cdb.c
Normal file
1131
drivers/target/target_core_cdb.c
Normal file
File diff suppressed because it is too large
Load Diff
3225
drivers/target/target_core_configfs.c
Normal file
3225
drivers/target/target_core_configfs.c
Normal file
File diff suppressed because it is too large
Load Diff
1694
drivers/target/target_core_device.c
Normal file
1694
drivers/target/target_core_device.c
Normal file
File diff suppressed because it is too large
Load Diff
996
drivers/target/target_core_fabric_configfs.c
Normal file
996
drivers/target/target_core_fabric_configfs.c
Normal file
File diff suppressed because it is too large
Load Diff
451
drivers/target/target_core_fabric_lib.c
Normal file
451
drivers/target/target_core_fabric_lib.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/*******************************************************************************
|
||||
* Filename: target_core_fabric_lib.c
|
||||
*
|
||||
* This file contains generic high level protocol identifier and PR
|
||||
* handlers for TCM fabric modules
|
||||
*
|
||||
* Copyright (c) 2010 Rising Tide Systems, Inc.
|
||||
* Copyright (c) 2010 Linux-iSCSI.org
|
||||
*
|
||||
* Nicholas A. Bellinger <nab@linux-iscsi.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#include <target/target_core_base.h>
|
||||
#include <target/target_core_device.h>
|
||||
#include <target/target_core_transport.h>
|
||||
#include <target/target_core_fabric_ops.h>
|
||||
#include <target/target_core_configfs.h>
|
||||
|
||||
#include "target_core_hba.h"
|
||||
#include "target_core_pr.h"
|
||||
|
||||
/*
|
||||
* Handlers for Serial Attached SCSI (SAS)
|
||||
*/
|
||||
u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg)
|
||||
{
|
||||
/*
|
||||
* Return a SAS Serial SCSI Protocol identifier for loopback operations
|
||||
* This is defined in section 7.5.1 Table 362 in spc4r17
|
||||
*/
|
||||
return 0x6;
|
||||
}
|
||||
EXPORT_SYMBOL(sas_get_fabric_proto_ident);
|
||||
|
||||
u32 sas_get_pr_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code,
|
||||
unsigned char *buf)
|
||||
{
|
||||
unsigned char binary, *ptr;
|
||||
int i;
|
||||
u32 off = 4;
|
||||
/*
|
||||
* Set PROTOCOL IDENTIFIER to 6h for SAS
|
||||
*/
|
||||
buf[0] = 0x06;
|
||||
/*
|
||||
* From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
|
||||
* over SAS Serial SCSI Protocol
|
||||
*/
|
||||
ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */
|
||||
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
binary = transport_asciihex_to_binaryhex(&ptr[i]);
|
||||
buf[off++] = binary;
|
||||
}
|
||||
/*
|
||||
* The SAS Transport ID is a hardcoded 24-byte length
|
||||
*/
|
||||
return 24;
|
||||
}
|
||||
EXPORT_SYMBOL(sas_get_pr_transport_id);
|
||||
|
||||
u32 sas_get_pr_transport_id_len(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code)
|
||||
{
|
||||
*format_code = 0;
|
||||
/*
|
||||
* From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
|
||||
* over SAS Serial SCSI Protocol
|
||||
*
|
||||
* The SAS Transport ID is a hardcoded 24-byte length
|
||||
*/
|
||||
return 24;
|
||||
}
|
||||
EXPORT_SYMBOL(sas_get_pr_transport_id_len);
|
||||
|
||||
/*
|
||||
* Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
|
||||
* Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
|
||||
*/
|
||||
char *sas_parse_pr_out_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *buf,
|
||||
u32 *out_tid_len,
|
||||
char **port_nexus_ptr)
|
||||
{
|
||||
/*
|
||||
* Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID
|
||||
* for initiator ports using SCSI over SAS Serial SCSI Protocol
|
||||
*
|
||||
* The TransportID for a SAS Initiator Port is of fixed size of
|
||||
* 24 bytes, and SAS does not contain a I_T nexus identifier,
|
||||
* so we return the **port_nexus_ptr set to NULL.
|
||||
*/
|
||||
*port_nexus_ptr = NULL;
|
||||
*out_tid_len = 24;
|
||||
|
||||
return (char *)&buf[4];
|
||||
}
|
||||
EXPORT_SYMBOL(sas_parse_pr_out_transport_id);
|
||||
|
||||
/*
|
||||
* Handlers for Fibre Channel Protocol (FCP)
|
||||
*/
|
||||
u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg)
|
||||
{
|
||||
return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */
|
||||
}
|
||||
EXPORT_SYMBOL(fc_get_fabric_proto_ident);
|
||||
|
||||
u32 fc_get_pr_transport_id_len(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code)
|
||||
{
|
||||
*format_code = 0;
|
||||
/*
|
||||
* The FC Transport ID is a hardcoded 24-byte length
|
||||
*/
|
||||
return 24;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_get_pr_transport_id_len);
|
||||
|
||||
u32 fc_get_pr_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code,
|
||||
unsigned char *buf)
|
||||
{
|
||||
unsigned char binary, *ptr;
|
||||
int i;
|
||||
u32 off = 8;
|
||||
/*
|
||||
* PROTOCOL IDENTIFIER is 0h for FCP-2
|
||||
*
|
||||
* From spc4r17, 7.5.4.2 TransportID for initiator ports using
|
||||
* SCSI over Fibre Channel
|
||||
*
|
||||
* We convert the ASCII formatted N Port name into a binary
|
||||
* encoded TransportID.
|
||||
*/
|
||||
ptr = &se_nacl->initiatorname[0];
|
||||
|
||||
for (i = 0; i < 24; ) {
|
||||
if (!(strncmp(&ptr[i], ":", 1))) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
binary = transport_asciihex_to_binaryhex(&ptr[i]);
|
||||
buf[off++] = binary;
|
||||
i += 2;
|
||||
}
|
||||
/*
|
||||
* The FC Transport ID is a hardcoded 24-byte length
|
||||
*/
|
||||
return 24;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_get_pr_transport_id);
|
||||
|
||||
char *fc_parse_pr_out_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *buf,
|
||||
u32 *out_tid_len,
|
||||
char **port_nexus_ptr)
|
||||
{
|
||||
/*
|
||||
* The TransportID for a FC N Port is of fixed size of
|
||||
* 24 bytes, and FC does not contain a I_T nexus identifier,
|
||||
* so we return the **port_nexus_ptr set to NULL.
|
||||
*/
|
||||
*port_nexus_ptr = NULL;
|
||||
*out_tid_len = 24;
|
||||
|
||||
return (char *)&buf[8];
|
||||
}
|
||||
EXPORT_SYMBOL(fc_parse_pr_out_transport_id);
|
||||
|
||||
/*
|
||||
* Handlers for Internet Small Computer Systems Interface (iSCSI)
|
||||
*/
|
||||
|
||||
u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg)
|
||||
{
|
||||
/*
|
||||
* This value is defined for "Internet SCSI (iSCSI)"
|
||||
* in spc4r17 section 7.5.1 Table 362
|
||||
*/
|
||||
return 0x5;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_get_fabric_proto_ident);
|
||||
|
||||
u32 iscsi_get_pr_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code,
|
||||
unsigned char *buf)
|
||||
{
|
||||
u32 off = 4, padding = 0;
|
||||
u16 len = 0;
|
||||
|
||||
spin_lock_irq(&se_nacl->nacl_sess_lock);
|
||||
/*
|
||||
* Set PROTOCOL IDENTIFIER to 5h for iSCSI
|
||||
*/
|
||||
buf[0] = 0x05;
|
||||
/*
|
||||
* From spc4r17 Section 7.5.4.6: TransportID for initiator
|
||||
* ports using SCSI over iSCSI.
|
||||
*
|
||||
* The null-terminated, null-padded (see 4.4.2) ISCSI NAME field
|
||||
* shall contain the iSCSI name of an iSCSI initiator node (see
|
||||
* RFC 3720). The first ISCSI NAME field byte containing an ASCII
|
||||
* null character terminates the ISCSI NAME field without regard for
|
||||
* the specified length of the iSCSI TransportID or the contents of
|
||||
* the ADDITIONAL LENGTH field.
|
||||
*/
|
||||
len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
|
||||
/*
|
||||
* Add Extra byte for NULL terminator
|
||||
*/
|
||||
len++;
|
||||
/*
|
||||
* If there is ISID present with the registration and *format code == 1
|
||||
* 1, use iSCSI Initiator port TransportID format.
|
||||
*
|
||||
* Otherwise use iSCSI Initiator device TransportID format that
|
||||
* does not contain the ASCII encoded iSCSI Initiator iSID value
|
||||
* provied by the iSCSi Initiator during the iSCSI login process.
|
||||
*/
|
||||
if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
|
||||
/*
|
||||
* Set FORMAT CODE 01b for iSCSI Initiator port TransportID
|
||||
* format.
|
||||
*/
|
||||
buf[0] |= 0x40;
|
||||
/*
|
||||
* From spc4r17 Section 7.5.4.6: TransportID for initiator
|
||||
* ports using SCSI over iSCSI. Table 390
|
||||
*
|
||||
* The SEPARATOR field shall contain the five ASCII
|
||||
* characters ",i,0x".
|
||||
*
|
||||
* The null-terminated, null-padded ISCSI INITIATOR SESSION ID
|
||||
* field shall contain the iSCSI initiator session identifier
|
||||
* (see RFC 3720) in the form of ASCII characters that are the
|
||||
* hexadecimal digits converted from the binary iSCSI initiator
|
||||
* session identifier value. The first ISCSI INITIATOR SESSION
|
||||
* ID field byte containing an ASCII null character
|
||||
*/
|
||||
buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
|
||||
buf[off+len] = 0x69; off++; /* ASCII Character: "i" */
|
||||
buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
|
||||
buf[off+len] = 0x30; off++; /* ASCII Character: "0" */
|
||||
buf[off+len] = 0x78; off++; /* ASCII Character: "x" */
|
||||
len += 5;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[0]; off++;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[1]; off++;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[2]; off++;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[3]; off++;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[4]; off++;
|
||||
buf[off+len] = pr_reg->pr_reg_isid[5]; off++;
|
||||
buf[off+len] = '\0'; off++;
|
||||
len += 7;
|
||||
}
|
||||
spin_unlock_irq(&se_nacl->nacl_sess_lock);
|
||||
/*
|
||||
* The ADDITIONAL LENGTH field specifies the number of bytes that follow
|
||||
* in the TransportID. The additional length shall be at least 20 and
|
||||
* shall be a multiple of four.
|
||||
*/
|
||||
padding = ((-len) & 3);
|
||||
if (padding != 0)
|
||||
len += padding;
|
||||
|
||||
buf[2] = ((len >> 8) & 0xff);
|
||||
buf[3] = (len & 0xff);
|
||||
/*
|
||||
* Increment value for total payload + header length for
|
||||
* full status descriptor
|
||||
*/
|
||||
len += 4;
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_get_pr_transport_id);
|
||||
|
||||
u32 iscsi_get_pr_transport_id_len(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
int *format_code)
|
||||
{
|
||||
u32 len = 0, padding = 0;
|
||||
|
||||
spin_lock_irq(&se_nacl->nacl_sess_lock);
|
||||
len = strlen(se_nacl->initiatorname);
|
||||
/*
|
||||
* Add extra byte for NULL terminator
|
||||
*/
|
||||
len++;
|
||||
/*
|
||||
* If there is ISID present with the registration, use format code:
|
||||
* 01b: iSCSI Initiator port TransportID format
|
||||
*
|
||||
* If there is not an active iSCSI session, use format code:
|
||||
* 00b: iSCSI Initiator device TransportID format
|
||||
*/
|
||||
if (pr_reg->isid_present_at_reg) {
|
||||
len += 5; /* For ",i,0x" ASCII seperator */
|
||||
len += 7; /* For iSCSI Initiator Session ID + Null terminator */
|
||||
*format_code = 1;
|
||||
} else
|
||||
*format_code = 0;
|
||||
spin_unlock_irq(&se_nacl->nacl_sess_lock);
|
||||
/*
|
||||
* The ADDITIONAL LENGTH field specifies the number of bytes that follow
|
||||
* in the TransportID. The additional length shall be at least 20 and
|
||||
* shall be a multiple of four.
|
||||
*/
|
||||
padding = ((-len) & 3);
|
||||
if (padding != 0)
|
||||
len += padding;
|
||||
/*
|
||||
* Increment value for total payload + header length for
|
||||
* full status descriptor
|
||||
*/
|
||||
len += 4;
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_get_pr_transport_id_len);
|
||||
|
||||
char *iscsi_parse_pr_out_transport_id(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *buf,
|
||||
u32 *out_tid_len,
|
||||
char **port_nexus_ptr)
|
||||
{
|
||||
char *p;
|
||||
u32 tid_len, padding;
|
||||
int i;
|
||||
u16 add_len;
|
||||
u8 format_code = (buf[0] & 0xc0);
|
||||
/*
|
||||
* Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6:
|
||||
*
|
||||
* TransportID for initiator ports using SCSI over iSCSI,
|
||||
* from Table 388 -- iSCSI TransportID formats.
|
||||
*
|
||||
* 00b Initiator port is identified using the world wide unique
|
||||
* SCSI device name of the iSCSI initiator
|
||||
* device containing the initiator port (see table 389).
|
||||
* 01b Initiator port is identified using the world wide unique
|
||||
* initiator port identifier (see table 390).10b to 11b
|
||||
* Reserved
|
||||
*/
|
||||
if ((format_code != 0x00) && (format_code != 0x40)) {
|
||||
printk(KERN_ERR "Illegal format code: 0x%02x for iSCSI"
|
||||
" Initiator Transport ID\n", format_code);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* If the caller wants the TransportID Length, we set that value for the
|
||||
* entire iSCSI Tarnsport ID now.
|
||||
*/
|
||||
if (out_tid_len != NULL) {
|
||||
add_len = ((buf[2] >> 8) & 0xff);
|
||||
add_len |= (buf[3] & 0xff);
|
||||
|
||||
tid_len = strlen((char *)&buf[4]);
|
||||
tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
|
||||
tid_len += 1; /* Add one byte for NULL terminator */
|
||||
padding = ((-tid_len) & 3);
|
||||
if (padding != 0)
|
||||
tid_len += padding;
|
||||
|
||||
if ((add_len + 4) != tid_len) {
|
||||
printk(KERN_INFO "LIO-Target Extracted add_len: %hu "
|
||||
"does not match calculated tid_len: %u,"
|
||||
" using tid_len instead\n", add_len+4, tid_len);
|
||||
*out_tid_len = tid_len;
|
||||
} else
|
||||
*out_tid_len = (add_len + 4);
|
||||
}
|
||||
/*
|
||||
* Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator
|
||||
* Session ID as defined in Table 390 - iSCSI initiator port TransportID
|
||||
* format.
|
||||
*/
|
||||
if (format_code == 0x40) {
|
||||
p = strstr((char *)&buf[4], ",i,0x");
|
||||
if (!(p)) {
|
||||
printk(KERN_ERR "Unable to locate \",i,0x\" seperator"
|
||||
" for Initiator port identifier: %s\n",
|
||||
(char *)&buf[4]);
|
||||
return NULL;
|
||||
}
|
||||
*p = '\0'; /* Terminate iSCSI Name */
|
||||
p += 5; /* Skip over ",i,0x" seperator */
|
||||
|
||||
*port_nexus_ptr = p;
|
||||
/*
|
||||
* Go ahead and do the lower case conversion of the received
|
||||
* 12 ASCII characters representing the ISID in the TransportID
|
||||
* for comparision against the running iSCSI session's ISID from
|
||||
* iscsi_target.c:lio_sess_get_initiator_sid()
|
||||
*/
|
||||
for (i = 0; i < 12; i++) {
|
||||
if (isdigit(*p)) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
*p = tolower(*p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *)&buf[4];
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id);
|
||||
688
drivers/target/target_core_file.c
Normal file
688
drivers/target/target_core_file.c
Normal file
File diff suppressed because it is too large
Load Diff
50
drivers/target/target_core_file.h
Normal file
50
drivers/target/target_core_file.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef TARGET_CORE_FILE_H
|
||||
#define TARGET_CORE_FILE_H
|
||||
|
||||
#define FD_VERSION "4.0"
|
||||
|
||||
#define FD_MAX_DEV_NAME 256
|
||||
/* Maximum queuedepth for the FILEIO HBA */
|
||||
#define FD_HBA_QUEUE_DEPTH 256
|
||||
#define FD_DEVICE_QUEUE_DEPTH 32
|
||||
#define FD_MAX_DEVICE_QUEUE_DEPTH 128
|
||||
#define FD_BLOCKSIZE 512
|
||||
#define FD_MAX_SECTORS 1024
|
||||
|
||||
#define RRF_EMULATE_CDB 0x01
|
||||
#define RRF_GOT_LBA 0x02
|
||||
|
||||
struct fd_request {
|
||||
struct se_task fd_task;
|
||||
/* SCSI CDB from iSCSI Command PDU */
|
||||
unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
|
||||
/* FILEIO device */
|
||||
struct fd_dev *fd_dev;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
#define FBDF_HAS_PATH 0x01
|
||||
#define FBDF_HAS_SIZE 0x02
|
||||
#define FDBD_USE_BUFFERED_IO 0x04
|
||||
|
||||
struct fd_dev {
|
||||
u32 fbd_flags;
|
||||
unsigned char fd_dev_name[FD_MAX_DEV_NAME];
|
||||
/* Unique Ramdisk Device ID in Ramdisk HBA */
|
||||
u32 fd_dev_id;
|
||||
/* Number of SG tables in sg_table_array */
|
||||
u32 fd_table_count;
|
||||
u32 fd_queue_depth;
|
||||
u32 fd_block_size;
|
||||
unsigned long long fd_dev_size;
|
||||
struct file *fd_file;
|
||||
/* FILEIO HBA device is connected to */
|
||||
struct fd_host *fd_host;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct fd_host {
|
||||
u32 fd_host_dev_id_count;
|
||||
/* Unique FILEIO Host ID */
|
||||
u32 fd_host_id;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
#endif /* TARGET_CORE_FILE_H */
|
||||
185
drivers/target/target_core_hba.c
Normal file
185
drivers/target/target_core_hba.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*******************************************************************************
|
||||
* Filename: target_core_hba.c
|
||||
*
|
||||
* This file copntains the iSCSI HBA Transport related functions.
|
||||
*
|
||||
* Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
|
||||
* Copyright (c) 2005, 2006, 2007 SBE, Inc.
|
||||
* Copyright (c) 2007-2010 Rising Tide Systems
|
||||
* Copyright (c) 2008-2010 Linux-iSCSI.org
|
||||
*
|
||||
* Nicholas A. Bellinger <nab@kernel.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/net.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/in.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <target/target_core_base.h>
|
||||
#include <target/target_core_device.h>
|
||||
#include <target/target_core_device.h>
|
||||
#include <target/target_core_tpg.h>
|
||||
#include <target/target_core_transport.h>
|
||||
|
||||
#include "target_core_hba.h"
|
||||
|
||||
static LIST_HEAD(subsystem_list);
|
||||
static DEFINE_MUTEX(subsystem_mutex);
|
||||
|
||||
int transport_subsystem_register(struct se_subsystem_api *sub_api)
|
||||
{
|
||||
struct se_subsystem_api *s;
|
||||
|
||||
INIT_LIST_HEAD(&sub_api->sub_api_list);
|
||||
|
||||
mutex_lock(&subsystem_mutex);
|
||||
list_for_each_entry(s, &subsystem_list, sub_api_list) {
|
||||
if (!(strcmp(s->name, sub_api->name))) {
|
||||
printk(KERN_ERR "%p is already registered with"
|
||||
" duplicate name %s, unable to process"
|
||||
" request\n", s, s->name);
|
||||
mutex_unlock(&subsystem_mutex);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
list_add_tail(&sub_api->sub_api_list, &subsystem_list);
|
||||
mutex_unlock(&subsystem_mutex);
|
||||
|
||||
printk(KERN_INFO "TCM: Registered subsystem plugin: %s struct module:"
|
||||
" %p\n", sub_api->name, sub_api->owner);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(transport_subsystem_register);
|
||||
|
||||
void transport_subsystem_release(struct se_subsystem_api *sub_api)
|
||||
{
|
||||
mutex_lock(&subsystem_mutex);
|
||||
list_del(&sub_api->sub_api_list);
|
||||
mutex_unlock(&subsystem_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(transport_subsystem_release);
|
||||
|
||||
static struct se_subsystem_api *core_get_backend(const char *sub_name)
|
||||
{
|
||||
struct se_subsystem_api *s;
|
||||
|
||||
mutex_lock(&subsystem_mutex);
|
||||
list_for_each_entry(s, &subsystem_list, sub_api_list) {
|
||||
if (!strcmp(s->name, sub_name))
|
||||
goto found;
|
||||
}
|
||||
mutex_unlock(&subsystem_mutex);
|
||||
return NULL;
|
||||
found:
|
||||
if (s->owner && !try_module_get(s->owner))
|
||||
s = NULL;
|
||||
mutex_unlock(&subsystem_mutex);
|
||||
return s;
|
||||
}
|
||||
|
||||
struct se_hba *
|
||||
core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags)
|
||||
{
|
||||
struct se_hba *hba;
|
||||
int ret = 0;
|
||||
|
||||
hba = kzalloc(sizeof(*hba), GFP_KERNEL);
|
||||
if (!hba) {
|
||||
printk(KERN_ERR "Unable to allocate struct se_hba\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&hba->hba_dev_list);
|
||||
spin_lock_init(&hba->device_lock);
|
||||
spin_lock_init(&hba->hba_queue_lock);
|
||||
mutex_init(&hba->hba_access_mutex);
|
||||
|
||||
hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX);
|
||||
hba->hba_flags |= hba_flags;
|
||||
|
||||
atomic_set(&hba->max_queue_depth, 0);
|
||||
atomic_set(&hba->left_queue_depth, 0);
|
||||
|
||||
hba->transport = core_get_backend(plugin_name);
|
||||
if (!hba->transport) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_hba;
|
||||
}
|
||||
|
||||
ret = hba->transport->attach_hba(hba, plugin_dep_id);
|
||||
if (ret < 0)
|
||||
goto out_module_put;
|
||||
|
||||
spin_lock(&se_global->hba_lock);
|
||||
hba->hba_id = se_global->g_hba_id_counter++;
|
||||
list_add_tail(&hba->hba_list, &se_global->g_hba_list);
|
||||
spin_unlock(&se_global->hba_lock);
|
||||
|
||||
printk(KERN_INFO "CORE_HBA[%d] - Attached HBA to Generic Target"
|
||||
" Core\n", hba->hba_id);
|
||||
|
||||
return hba;
|
||||
|
||||
out_module_put:
|
||||
if (hba->transport->owner)
|
||||
module_put(hba->transport->owner);
|
||||
hba->transport = NULL;
|
||||
out_free_hba:
|
||||
kfree(hba);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int
|
||||
core_delete_hba(struct se_hba *hba)
|
||||
{
|
||||
struct se_device *dev, *dev_tmp;
|
||||
|
||||
spin_lock(&hba->device_lock);
|
||||
list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) {
|
||||
|
||||
se_clear_dev_ports(dev);
|
||||
spin_unlock(&hba->device_lock);
|
||||
|
||||
se_release_device_for_hba(dev);
|
||||
|
||||
spin_lock(&hba->device_lock);
|
||||
}
|
||||
spin_unlock(&hba->device_lock);
|
||||
|
||||
hba->transport->detach_hba(hba);
|
||||
|
||||
spin_lock(&se_global->hba_lock);
|
||||
list_del(&hba->hba_list);
|
||||
spin_unlock(&se_global->hba_lock);
|
||||
|
||||
printk(KERN_INFO "CORE_HBA[%d] - Detached HBA from Generic Target"
|
||||
" Core\n", hba->hba_id);
|
||||
|
||||
if (hba->transport->owner)
|
||||
module_put(hba->transport->owner);
|
||||
|
||||
hba->transport = NULL;
|
||||
kfree(hba);
|
||||
return 0;
|
||||
}
|
||||
7
drivers/target/target_core_hba.h
Normal file
7
drivers/target/target_core_hba.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef TARGET_CORE_HBA_H
|
||||
#define TARGET_CORE_HBA_H
|
||||
|
||||
extern struct se_hba *core_alloc_hba(const char *, u32, u32);
|
||||
extern int core_delete_hba(struct se_hba *);
|
||||
|
||||
#endif /* TARGET_CORE_HBA_H */
|
||||
808
drivers/target/target_core_iblock.c
Normal file
808
drivers/target/target_core_iblock.c
Normal file
File diff suppressed because it is too large
Load Diff
40
drivers/target/target_core_iblock.h
Normal file
40
drivers/target/target_core_iblock.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef TARGET_CORE_IBLOCK_H
|
||||
#define TARGET_CORE_IBLOCK_H
|
||||
|
||||
#define IBLOCK_VERSION "4.0"
|
||||
|
||||
#define IBLOCK_HBA_QUEUE_DEPTH 512
|
||||
#define IBLOCK_DEVICE_QUEUE_DEPTH 32
|
||||
#define IBLOCK_MAX_DEVICE_QUEUE_DEPTH 128
|
||||
#define IBLOCK_MAX_CDBS 16
|
||||
#define IBLOCK_LBA_SHIFT 9
|
||||
|
||||
struct iblock_req {
|
||||
struct se_task ib_task;
|
||||
unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
|
||||
atomic_t ib_bio_cnt;
|
||||
atomic_t ib_bio_err_cnt;
|
||||
struct bio *ib_bio;
|
||||
struct iblock_dev *ib_dev;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
#define IBDF_HAS_UDEV_PATH 0x01
|
||||
#define IBDF_HAS_FORCE 0x02
|
||||
|
||||
struct iblock_dev {
|
||||
unsigned char ibd_udev_path[SE_UDEV_PATH_LEN];
|
||||
int ibd_force;
|
||||
int ibd_major;
|
||||
int ibd_minor;
|
||||
u32 ibd_depth;
|
||||
u32 ibd_flags;
|
||||
struct bio_set *ibd_bio_set;
|
||||
struct block_device *ibd_bd;
|
||||
struct iblock_hba *ibd_host;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct iblock_hba {
|
||||
int iblock_host_id;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
#endif /* TARGET_CORE_IBLOCK_H */
|
||||
1078
drivers/target/target_core_mib.c
Normal file
1078
drivers/target/target_core_mib.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user