mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger: "Lots of activity in target land the last months. The highlights include: - Convert fabric drivers tree-wide to target_register_template() (hch + bart) - iser-target hardening fixes + v1.0 improvements (sagi) - Convert iscsi_thread_set usage to kthread.h + kill iscsi_target_tq.c (sagi + nab) - Add support for T10-PI WRITE_STRIP + READ_INSERT operation (mkp + sagi + nab) - DIF fixes for CONFIG_DEBUG_SG=y + UNMAP file emulation (akinobu + sagi + mkp) - Extended TCMU ABI v2 for future BIDI + DIF support (andy + ilias) - Fix COMPARE_AND_WRITE handling for NO_ALLLOC drivers (hch + nab) Thanks to everyone who contributed this round with new features, bug-reports, fixes, cleanups and improvements. Looking forward, it's currently shaping up to be a busy v4.2 as well" * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (69 commits) target: Put TCMU under a new config option target: Version 2 of TCMU ABI target: fix tcm_mod_builder.py target/file: Fix UNMAP with DIF protection support target/file: Fix SG table for prot_buf initialization target/file: Fix BUG() when CONFIG_DEBUG_SG=y and DIF protection enabled target: Make core_tmr_abort_task() skip TMFs target/sbc: Update sbc_dif_generate pr_debug output target/sbc: Make internal DIF emulation honor ->prot_checks target/sbc: Return INVALID_CDB_FIELD if DIF + sess_prot_type disabled target: Ensure sess_prot_type is saved across session restart target/rd: Don't pass incomplete scatterlist entries to sbc_dif_verify_* target: Remove the unused flag SCF_ACK_KREF target: Fix two sparse warnings target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling target: simplify the target template registration API target: simplify target_xcopy_init_pt_lun target: remove the unused SCF_CMD_XCOPY_PASSTHROUGH flag target/rd: reduce code duplication in rd_execute_rw() tcm_loop: fixup tpgt string to integer conversion ...
This commit is contained in:
commit
c6668726d2
@ -237,8 +237,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
|
||||
buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
|
||||
buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
|
||||
|
||||
buf += "/* Local pointer to allocated TCM configfs fabric module */\n"
|
||||
buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n"
|
||||
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n"
|
||||
|
||||
buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
|
||||
buf += " struct se_portal_group *se_tpg,\n"
|
||||
@ -309,8 +308,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
|
||||
buf += " }\n"
|
||||
buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
|
||||
buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
|
||||
buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n"
|
||||
buf += " &tpg->se_tpg, (void *)tpg,\n"
|
||||
buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
|
||||
buf += " &tpg->se_tpg, tpg,\n"
|
||||
buf += " TRANSPORT_TPG_TYPE_NORMAL);\n"
|
||||
buf += " if (ret < 0) {\n"
|
||||
buf += " kfree(tpg);\n"
|
||||
@ -370,7 +369,10 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
|
||||
buf += " NULL,\n"
|
||||
buf += "};\n\n"
|
||||
|
||||
buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
|
||||
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
|
||||
buf += " .module = THIS_MODULE,\n"
|
||||
buf += " .name = " + fabric_mod_name + ",\n"
|
||||
buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n"
|
||||
buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n"
|
||||
buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n"
|
||||
buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n"
|
||||
@ -413,75 +415,18 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
|
||||
buf += " .fabric_drop_np = NULL,\n"
|
||||
buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n"
|
||||
buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n"
|
||||
buf += "};\n\n"
|
||||
|
||||
buf += "static int " + fabric_mod_name + "_register_configfs(void)\n"
|
||||
buf += "{\n"
|
||||
buf += " struct target_fabric_configfs *fabric;\n"
|
||||
buf += " int ret;\n\n"
|
||||
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
|
||||
buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
|
||||
buf += " utsname()->machine);\n"
|
||||
buf += " /*\n"
|
||||
buf += " * Register the top level struct config_item_type with TCM core\n"
|
||||
buf += " */\n"
|
||||
buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n"
|
||||
buf += " if (IS_ERR(fabric)) {\n"
|
||||
buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
|
||||
buf += " return PTR_ERR(fabric);\n"
|
||||
buf += " }\n"
|
||||
buf += " /*\n"
|
||||
buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n"
|
||||
buf += " */\n"
|
||||
buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n"
|
||||
buf += " /*\n"
|
||||
buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n"
|
||||
buf += " */\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n"
|
||||
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n"
|
||||
buf += " /*\n"
|
||||
buf += " * Register the fabric for use within TCM\n"
|
||||
buf += " */\n"
|
||||
buf += " ret = target_fabric_configfs_register(fabric);\n"
|
||||
buf += " if (ret < 0) {\n"
|
||||
buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n"
|
||||
buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n"
|
||||
buf += " return ret;\n"
|
||||
buf += " }\n"
|
||||
buf += " /*\n"
|
||||
buf += " * Setup our local pointer to *fabric\n"
|
||||
buf += " */\n"
|
||||
buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n"
|
||||
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n"
|
||||
buf += " return 0;\n"
|
||||
buf += "};\n\n"
|
||||
buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n"
|
||||
buf += "{\n"
|
||||
buf += " if (!" + fabric_mod_name + "_fabric_configfs)\n"
|
||||
buf += " return;\n\n"
|
||||
buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n"
|
||||
buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n"
|
||||
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n"
|
||||
buf += "\n"
|
||||
buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
|
||||
buf += "};\n\n"
|
||||
|
||||
buf += "static int __init " + fabric_mod_name + "_init(void)\n"
|
||||
buf += "{\n"
|
||||
buf += " int ret;\n\n"
|
||||
buf += " ret = " + fabric_mod_name + "_register_configfs();\n"
|
||||
buf += " if (ret < 0)\n"
|
||||
buf += " return ret;\n\n"
|
||||
buf += " return 0;\n"
|
||||
buf += " return target_register_template(" + fabric_mod_name + "_ops);\n"
|
||||
buf += "};\n\n"
|
||||
|
||||
buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
|
||||
buf += "{\n"
|
||||
buf += " " + fabric_mod_name + "_deregister_configfs();\n"
|
||||
buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n"
|
||||
buf += "};\n\n"
|
||||
|
||||
buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
|
||||
|
@ -138,27 +138,40 @@ signals the kernel via a 4-byte write(). When cmd_head equals
|
||||
cmd_tail, the ring is empty -- no commands are currently waiting to be
|
||||
processed by userspace.
|
||||
|
||||
TCMU commands start with a common header containing "len_op", a 32-bit
|
||||
value that stores the length, as well as the opcode in the lowest
|
||||
unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and
|
||||
TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it
|
||||
should skip ahead by the bytes in "length". (The kernel inserts PAD
|
||||
entries to ensure each CMD entry fits contigously into the circular
|
||||
buffer.)
|
||||
TCMU commands are 8-byte aligned. They start with a common header
|
||||
containing "len_op", a 32-bit value that stores the length, as well as
|
||||
the opcode in the lowest unused bits. It also contains cmd_id and
|
||||
flags fields for setting by the kernel (kflags) and userspace
|
||||
(uflags).
|
||||
|
||||
When userspace handles a CMD, it finds the SCSI CDB (Command Data
|
||||
Block) via tcmu_cmd_entry.req.cdb_off. This is an offset from the
|
||||
start of the overall shared memory region, not the entry. The data
|
||||
in/out buffers are accessible via tht req.iov[] array. Note that
|
||||
each iov.iov_base is also an offset from the start of the region.
|
||||
Currently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD.
|
||||
|
||||
TCMU currently does not support BIDI operations.
|
||||
When the opcode is CMD, the entry in the command ring is a struct
|
||||
tcmu_cmd_entry. Userspace finds the SCSI CDB (Command Data Block) via
|
||||
tcmu_cmd_entry.req.cdb_off. This is an offset from the start of the
|
||||
overall shared memory region, not the entry. The data in/out buffers
|
||||
are accessible via tht req.iov[] array. iov_cnt contains the number of
|
||||
entries in iov[] needed to describe either the Data-In or Data-Out
|
||||
buffers. For bidirectional commands, iov_cnt specifies how many iovec
|
||||
entries cover the Data-Out area, and iov_bidi_count specifies how many
|
||||
iovec entries immediately after that in iov[] cover the Data-In
|
||||
area. Just like other fields, iov.iov_base is an offset from the start
|
||||
of the region.
|
||||
|
||||
When completing a command, userspace sets rsp.scsi_status, and
|
||||
rsp.sense_buffer if necessary. Userspace then increments
|
||||
mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the
|
||||
kernel via the UIO method, a 4-byte write to the file descriptor.
|
||||
|
||||
When the opcode is PAD, userspace only updates cmd_tail as above --
|
||||
it's a no-op. (The kernel inserts PAD entries to ensure each CMD entry
|
||||
is contiguous within the command ring.)
|
||||
|
||||
More opcodes may be added in the future. If userspace encounters an
|
||||
opcode it does not handle, it must set UNKNOWN_OP bit (bit 0) in
|
||||
hdr.uflags, update cmd_tail, and proceed with processing additional
|
||||
commands, if any.
|
||||
|
||||
The Data Area:
|
||||
|
||||
This is shared-memory space after the command ring. The organization
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,6 @@
|
||||
#define isert_err(fmt, arg...) \
|
||||
pr_err(PFX "%s: " fmt, __func__ , ## arg)
|
||||
|
||||
#define ISERT_RDMA_LISTEN_BACKLOG 10
|
||||
#define ISCSI_ISER_SG_TABLESIZE 256
|
||||
#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
|
||||
#define ISER_BEACON_WRID 0xfffffffffffffffeULL
|
||||
@ -160,27 +159,25 @@ struct isert_conn {
|
||||
u64 login_req_dma;
|
||||
int login_req_len;
|
||||
u64 login_rsp_dma;
|
||||
unsigned int conn_rx_desc_head;
|
||||
struct iser_rx_desc *conn_rx_descs;
|
||||
struct ib_recv_wr conn_rx_wr[ISERT_MIN_POSTED_RX];
|
||||
unsigned int rx_desc_head;
|
||||
struct iser_rx_desc *rx_descs;
|
||||
struct ib_recv_wr rx_wr[ISERT_MIN_POSTED_RX];
|
||||
struct iscsi_conn *conn;
|
||||
struct list_head conn_accept_node;
|
||||
struct completion conn_login_comp;
|
||||
struct list_head accept_node;
|
||||
struct completion login_comp;
|
||||
struct completion login_req_comp;
|
||||
struct iser_tx_desc conn_login_tx_desc;
|
||||
struct rdma_cm_id *conn_cm_id;
|
||||
struct ib_pd *conn_pd;
|
||||
struct ib_mr *conn_mr;
|
||||
struct ib_qp *conn_qp;
|
||||
struct isert_device *conn_device;
|
||||
struct mutex conn_mutex;
|
||||
struct completion conn_wait;
|
||||
struct completion conn_wait_comp_err;
|
||||
struct kref conn_kref;
|
||||
struct list_head conn_fr_pool;
|
||||
int conn_fr_pool_size;
|
||||
struct iser_tx_desc login_tx_desc;
|
||||
struct rdma_cm_id *cm_id;
|
||||
struct ib_qp *qp;
|
||||
struct isert_device *device;
|
||||
struct mutex mutex;
|
||||
struct completion wait;
|
||||
struct completion wait_comp_err;
|
||||
struct kref kref;
|
||||
struct list_head fr_pool;
|
||||
int fr_pool_size;
|
||||
/* lock to protect fastreg pool */
|
||||
spinlock_t conn_lock;
|
||||
spinlock_t pool_lock;
|
||||
struct work_struct release_work;
|
||||
struct ib_recv_wr beacon;
|
||||
bool logout_posted;
|
||||
@ -211,6 +208,8 @@ struct isert_device {
|
||||
bool pi_capable;
|
||||
int refcount;
|
||||
struct ib_device *ib_device;
|
||||
struct ib_pd *pd;
|
||||
struct ib_mr *mr;
|
||||
struct isert_comp *comps;
|
||||
int comps_used;
|
||||
struct list_head dev_node;
|
||||
|
@ -93,7 +93,7 @@ MODULE_PARM_DESC(srpt_service_guid,
|
||||
" instead of using the node_guid of the first HCA.");
|
||||
|
||||
static struct ib_client srpt_client;
|
||||
static struct target_fabric_configfs *srpt_target;
|
||||
static const struct target_core_fabric_ops srpt_template;
|
||||
static void srpt_release_channel(struct srpt_rdma_ch *ch);
|
||||
static int srpt_queue_status(struct se_cmd *cmd);
|
||||
|
||||
@ -3845,7 +3845,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
|
||||
int res;
|
||||
|
||||
/* Initialize sport->port_wwn and sport->port_tpg_1 */
|
||||
res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn,
|
||||
res = core_tpg_register(&srpt_template, &sport->port_wwn,
|
||||
&sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (res)
|
||||
return ERR_PTR(res);
|
||||
@ -3913,7 +3913,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct target_core_fabric_ops srpt_template = {
|
||||
static const struct target_core_fabric_ops srpt_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "srpt",
|
||||
.get_fabric_name = srpt_get_fabric_name,
|
||||
.get_fabric_proto_ident = srpt_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = srpt_get_fabric_wwn,
|
||||
@ -3958,6 +3960,10 @@ static struct target_core_fabric_ops srpt_template = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = srpt_make_nodeacl,
|
||||
.fabric_drop_nodeacl = srpt_drop_nodeacl,
|
||||
|
||||
.tfc_wwn_attrs = srpt_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = srpt_tpg_attrs,
|
||||
.tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3988,33 +3994,9 @@ static int __init srpt_init_module(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt");
|
||||
if (IS_ERR(srpt_target)) {
|
||||
pr_err("couldn't register\n");
|
||||
ret = PTR_ERR(srpt_target);
|
||||
ret = target_register_template(&srpt_template);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
srpt_target->tf_ops = srpt_template;
|
||||
|
||||
/*
|
||||
* Set up default attribute lists.
|
||||
*/
|
||||
srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
|
||||
ret = target_fabric_configfs_register(srpt_target);
|
||||
if (ret < 0) {
|
||||
pr_err("couldn't register\n");
|
||||
goto out_free_target;
|
||||
}
|
||||
|
||||
ret = ib_register_client(&srpt_client);
|
||||
if (ret) {
|
||||
@ -4025,11 +4007,7 @@ static int __init srpt_init_module(void)
|
||||
return 0;
|
||||
|
||||
out_unregister_target:
|
||||
target_fabric_configfs_deregister(srpt_target);
|
||||
srpt_target = NULL;
|
||||
out_free_target:
|
||||
if (srpt_target)
|
||||
target_fabric_configfs_free(srpt_target);
|
||||
target_unregister_template(&srpt_template);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -4037,8 +4015,7 @@ out:
|
||||
static void __exit srpt_cleanup_module(void)
|
||||
{
|
||||
ib_unregister_client(&srpt_client);
|
||||
target_fabric_configfs_deregister(srpt_target);
|
||||
srpt_target = NULL;
|
||||
target_unregister_template(&srpt_template);
|
||||
}
|
||||
|
||||
module_init(srpt_init_module);
|
||||
|
@ -3065,7 +3065,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct se_cmd *se_cmd;
|
||||
struct target_core_fabric_ops *tfo;
|
||||
const struct target_core_fabric_ops *tfo;
|
||||
struct qla_tgt_cmd *cmd;
|
||||
|
||||
if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) {
|
||||
|
@ -53,9 +53,8 @@
|
||||
static struct workqueue_struct *tcm_qla2xxx_free_wq;
|
||||
static struct workqueue_struct *tcm_qla2xxx_cmd_wq;
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
|
||||
static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
|
||||
static const struct target_core_fabric_ops tcm_qla2xxx_ops;
|
||||
static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops;
|
||||
|
||||
/*
|
||||
* Parse WWN.
|
||||
@ -336,6 +335,14 @@ static int tcm_qla2xxx_check_demo_mode_login_only(struct se_portal_group *se_tpg
|
||||
return tpg->tpg_attrib.demo_mode_login_only;
|
||||
}
|
||||
|
||||
static int tcm_qla2xxx_check_prot_fabric_only(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
|
||||
struct tcm_qla2xxx_tpg, se_tpg);
|
||||
|
||||
return tpg->tpg_attrib.fabric_prot_type;
|
||||
}
|
||||
|
||||
static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl(
|
||||
struct se_portal_group *se_tpg)
|
||||
{
|
||||
@ -1082,8 +1089,53 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
|
||||
|
||||
TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR);
|
||||
|
||||
static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions(
|
||||
struct se_portal_group *se_tpg,
|
||||
char *page)
|
||||
{
|
||||
return target_show_dynamic_sessions(se_tpg, page);
|
||||
}
|
||||
|
||||
TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions);
|
||||
|
||||
static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *page,
|
||||
size_t count)
|
||||
{
|
||||
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
|
||||
struct tcm_qla2xxx_tpg, se_tpg);
|
||||
unsigned long val;
|
||||
int ret = kstrtoul(page, 0, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (val != 0 && val != 1 && val != 3) {
|
||||
pr_err("Invalid qla2xxx fabric_prot_type: %lu\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
tpg->tpg_attrib.fabric_prot_type = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
char *page)
|
||||
{
|
||||
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
|
||||
struct tcm_qla2xxx_tpg, se_tpg);
|
||||
|
||||
return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type);
|
||||
}
|
||||
TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR);
|
||||
|
||||
static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = {
|
||||
&tcm_qla2xxx_tpg_enable.attr,
|
||||
&tcm_qla2xxx_tpg_dynamic_sessions.attr,
|
||||
&tcm_qla2xxx_tpg_fabric_prot_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1124,7 +1176,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
|
||||
tpg->tpg_attrib.cache_dynamic_acls = 1;
|
||||
tpg->tpg_attrib.demo_mode_login_only = 1;
|
||||
|
||||
ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn,
|
||||
ret = core_tpg_register(&tcm_qla2xxx_ops, wwn,
|
||||
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
kfree(tpg);
|
||||
@ -1244,7 +1296,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
|
||||
tpg->tpg_attrib.cache_dynamic_acls = 1;
|
||||
tpg->tpg_attrib.demo_mode_login_only = 1;
|
||||
|
||||
ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
|
||||
ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn,
|
||||
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
kfree(tpg);
|
||||
@ -1560,7 +1612,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
|
||||
|
||||
se_sess = transport_init_session_tags(num_tags,
|
||||
sizeof(struct qla_tgt_cmd),
|
||||
TARGET_PROT_NORMAL);
|
||||
TARGET_PROT_ALL);
|
||||
if (IS_ERR(se_sess)) {
|
||||
pr_err("Unable to initialize struct se_session\n");
|
||||
return PTR_ERR(se_sess);
|
||||
@ -1934,7 +1986,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct target_core_fabric_ops tcm_qla2xxx_ops = {
|
||||
static const struct target_core_fabric_ops tcm_qla2xxx_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "qla2xxx",
|
||||
.get_fabric_name = tcm_qla2xxx_get_fabric_name,
|
||||
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
|
||||
@ -1949,6 +2003,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
|
||||
tcm_qla2xxx_check_demo_write_protect,
|
||||
.tpg_check_prod_mode_write_protect =
|
||||
tcm_qla2xxx_check_prod_write_protect,
|
||||
.tpg_check_prot_fabric_only = tcm_qla2xxx_check_prot_fabric_only,
|
||||
.tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
|
||||
.tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl,
|
||||
.tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl,
|
||||
@ -1983,9 +2038,15 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
||||
.fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl,
|
||||
|
||||
.tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs,
|
||||
.tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs,
|
||||
};
|
||||
|
||||
static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
|
||||
static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "qla2xxx_npiv",
|
||||
.get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name,
|
||||
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
|
||||
@ -2033,94 +2094,26 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
||||
.fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl,
|
||||
|
||||
.tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs,
|
||||
};
|
||||
|
||||
static int tcm_qla2xxx_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric, *npiv_fabric;
|
||||
int ret;
|
||||
|
||||
pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
|
||||
UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
|
||||
utsname()->machine);
|
||||
/*
|
||||
* Register the top level struct config_item_type with TCM core
|
||||
*/
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("target_fabric_configfs_init() failed\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
/*
|
||||
* Setup fabric->tf_ops from our local tcm_qla2xxx_ops
|
||||
*/
|
||||
fabric->tf_ops = tcm_qla2xxx_ops;
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs =
|
||||
tcm_qla2xxx_tpg_attrib_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* Register the fabric for use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Setup our local pointer to *fabric
|
||||
*/
|
||||
tcm_qla2xxx_fabric_configfs = fabric;
|
||||
pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n");
|
||||
|
||||
/*
|
||||
* Register the top level struct config_item_type for NPIV with TCM core
|
||||
*/
|
||||
npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv");
|
||||
if (IS_ERR(npiv_fabric)) {
|
||||
pr_err("target_fabric_configfs_init() failed\n");
|
||||
ret = PTR_ERR(npiv_fabric);
|
||||
ret = target_register_template(&tcm_qla2xxx_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = target_register_template(&tcm_qla2xxx_npiv_ops);
|
||||
if (ret)
|
||||
goto out_fabric;
|
||||
}
|
||||
/*
|
||||
* Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops
|
||||
*/
|
||||
npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops;
|
||||
/*
|
||||
* Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
|
||||
*/
|
||||
npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
|
||||
tcm_qla2xxx_npiv_tpg_attrs;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* Register the npiv_fabric for use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(npiv_fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
|
||||
goto out_fabric;
|
||||
}
|
||||
/*
|
||||
* Setup our local pointer to *npiv_fabric
|
||||
*/
|
||||
tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric;
|
||||
pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n");
|
||||
|
||||
tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free",
|
||||
WQ_MEM_RECLAIM, 0);
|
||||
@ -2140,9 +2133,9 @@ static int tcm_qla2xxx_register_configfs(void)
|
||||
out_free_wq:
|
||||
destroy_workqueue(tcm_qla2xxx_free_wq);
|
||||
out_fabric_npiv:
|
||||
target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
|
||||
target_unregister_template(&tcm_qla2xxx_npiv_ops);
|
||||
out_fabric:
|
||||
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
|
||||
target_unregister_template(&tcm_qla2xxx_ops);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2151,13 +2144,8 @@ static void tcm_qla2xxx_deregister_configfs(void)
|
||||
destroy_workqueue(tcm_qla2xxx_cmd_wq);
|
||||
destroy_workqueue(tcm_qla2xxx_free_wq);
|
||||
|
||||
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
|
||||
tcm_qla2xxx_fabric_configfs = NULL;
|
||||
pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n");
|
||||
|
||||
target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
|
||||
tcm_qla2xxx_npiv_fabric_configfs = NULL;
|
||||
pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n");
|
||||
target_unregister_template(&tcm_qla2xxx_ops);
|
||||
target_unregister_template(&tcm_qla2xxx_npiv_ops);
|
||||
}
|
||||
|
||||
static int __init tcm_qla2xxx_init(void)
|
||||
|
@ -33,6 +33,7 @@ struct tcm_qla2xxx_tpg_attrib {
|
||||
int demo_mode_write_protect;
|
||||
int prod_mode_write_protect;
|
||||
int demo_mode_login_only;
|
||||
int fabric_prot_type;
|
||||
};
|
||||
|
||||
struct tcm_qla2xxx_tpg {
|
||||
|
@ -31,12 +31,13 @@ config TCM_PSCSI
|
||||
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
|
||||
passthrough access to Linux/SCSI device
|
||||
|
||||
config TCM_USER
|
||||
config TCM_USER2
|
||||
tristate "TCM/USER Subsystem Plugin for Linux"
|
||||
depends on UIO && NET
|
||||
help
|
||||
Say Y here to enable the TCM/USER subsystem plugin for a userspace
|
||||
process to handle requests
|
||||
process to handle requests. This is version 2 of the ABI; version 1
|
||||
is obsolete.
|
||||
|
||||
source "drivers/target/loopback/Kconfig"
|
||||
source "drivers/target/tcm_fc/Kconfig"
|
||||
|
@ -22,7 +22,7 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
|
||||
obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
|
||||
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
|
||||
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
|
||||
obj-$(CONFIG_TCM_USER) += target_core_user.o
|
||||
obj-$(CONFIG_TCM_USER2) += target_core_user.o
|
||||
|
||||
# Fabric modules
|
||||
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
|
||||
|
@ -1,6 +1,5 @@
|
||||
iscsi_target_mod-y += iscsi_target_parameters.o \
|
||||
iscsi_target_seq_pdu_list.o \
|
||||
iscsi_target_tq.o \
|
||||
iscsi_target_auth.o \
|
||||
iscsi_target_datain_values.o \
|
||||
iscsi_target_device.o \
|
||||
|
@ -33,8 +33,6 @@
|
||||
#include <target/iscsi/iscsi_target_core.h>
|
||||
#include "iscsi_target_parameters.h"
|
||||
#include "iscsi_target_seq_pdu_list.h"
|
||||
#include "iscsi_target_tq.h"
|
||||
#include "iscsi_target_configfs.h"
|
||||
#include "iscsi_target_datain_values.h"
|
||||
#include "iscsi_target_erl0.h"
|
||||
#include "iscsi_target_erl1.h"
|
||||
@ -537,7 +535,7 @@ static struct iscsit_transport iscsi_target_transport = {
|
||||
|
||||
static int __init iscsi_target_init_module(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 0, size;
|
||||
|
||||
pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
|
||||
|
||||
@ -546,24 +544,21 @@ static int __init iscsi_target_init_module(void)
|
||||
pr_err("Unable to allocate memory for iscsit_global\n");
|
||||
return -1;
|
||||
}
|
||||
spin_lock_init(&iscsit_global->ts_bitmap_lock);
|
||||
mutex_init(&auth_id_lock);
|
||||
spin_lock_init(&sess_idr_lock);
|
||||
idr_init(&tiqn_idr);
|
||||
idr_init(&sess_idr);
|
||||
|
||||
ret = iscsi_target_register_configfs();
|
||||
if (ret < 0)
|
||||
ret = target_register_template(&iscsi_ops);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iscsi_thread_set_init();
|
||||
if (ret < 0)
|
||||
size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
|
||||
iscsit_global->ts_bitmap = vzalloc(size);
|
||||
if (!iscsit_global->ts_bitmap) {
|
||||
pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
|
||||
goto configfs_out;
|
||||
|
||||
if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) !=
|
||||
TARGET_THREAD_SET_COUNT) {
|
||||
pr_err("iscsi_allocate_thread_sets() returned"
|
||||
" unexpected value!\n");
|
||||
goto ts_out1;
|
||||
}
|
||||
|
||||
lio_qr_cache = kmem_cache_create("lio_qr_cache",
|
||||
@ -572,7 +567,7 @@ static int __init iscsi_target_init_module(void)
|
||||
if (!lio_qr_cache) {
|
||||
pr_err("nable to kmem_cache_create() for"
|
||||
" lio_qr_cache\n");
|
||||
goto ts_out2;
|
||||
goto bitmap_out;
|
||||
}
|
||||
|
||||
lio_dr_cache = kmem_cache_create("lio_dr_cache",
|
||||
@ -617,12 +612,13 @@ dr_out:
|
||||
kmem_cache_destroy(lio_dr_cache);
|
||||
qr_out:
|
||||
kmem_cache_destroy(lio_qr_cache);
|
||||
ts_out2:
|
||||
iscsi_deallocate_thread_sets();
|
||||
ts_out1:
|
||||
iscsi_thread_set_free();
|
||||
bitmap_out:
|
||||
vfree(iscsit_global->ts_bitmap);
|
||||
configfs_out:
|
||||
iscsi_target_deregister_configfs();
|
||||
/* XXX: this probably wants it to be it's own unwind step.. */
|
||||
if (iscsit_global->discovery_tpg)
|
||||
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
|
||||
target_unregister_template(&iscsi_ops);
|
||||
out:
|
||||
kfree(iscsit_global);
|
||||
return -ENOMEM;
|
||||
@ -630,8 +626,6 @@ out:
|
||||
|
||||
static void __exit iscsi_target_cleanup_module(void)
|
||||
{
|
||||
iscsi_deallocate_thread_sets();
|
||||
iscsi_thread_set_free();
|
||||
iscsit_release_discovery_tpg();
|
||||
iscsit_unregister_transport(&iscsi_target_transport);
|
||||
kmem_cache_destroy(lio_qr_cache);
|
||||
@ -639,8 +633,15 @@ static void __exit iscsi_target_cleanup_module(void)
|
||||
kmem_cache_destroy(lio_ooo_cache);
|
||||
kmem_cache_destroy(lio_r2t_cache);
|
||||
|
||||
iscsi_target_deregister_configfs();
|
||||
/*
|
||||
* Shutdown discovery sessions and disable discovery TPG
|
||||
*/
|
||||
if (iscsit_global->discovery_tpg)
|
||||
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
|
||||
|
||||
target_unregister_template(&iscsi_ops);
|
||||
|
||||
vfree(iscsit_global->ts_bitmap);
|
||||
kfree(iscsit_global);
|
||||
}
|
||||
|
||||
@ -990,7 +991,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
||||
/*
|
||||
* Initialize struct se_cmd descriptor from target_core_mod infrastructure
|
||||
*/
|
||||
transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
|
||||
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
|
||||
conn->sess->se_sess, be32_to_cpu(hdr->data_length),
|
||||
cmd->data_direction, sam_task_attr,
|
||||
cmd->sense_buffer + 2);
|
||||
@ -1805,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
||||
u8 tcm_function;
|
||||
int ret;
|
||||
|
||||
transport_init_se_cmd(&cmd->se_cmd,
|
||||
&lio_target_fabric_configfs->tf_ops,
|
||||
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
|
||||
conn->sess->se_sess, 0, DMA_NONE,
|
||||
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
|
||||
|
||||
@ -2155,7 +2155,6 @@ reject:
|
||||
cmd->text_in_ptr = NULL;
|
||||
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_handle_text_cmd);
|
||||
|
||||
int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
|
||||
{
|
||||
@ -3715,17 +3714,16 @@ static int iscsit_send_reject(
|
||||
|
||||
void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_thread_set *ts = conn->thread_set;
|
||||
int ord, cpu;
|
||||
/*
|
||||
* thread_id is assigned from iscsit_global->ts_bitmap from
|
||||
* within iscsi_thread_set.c:iscsi_allocate_thread_sets()
|
||||
* bitmap_id is assigned from iscsit_global->ts_bitmap from
|
||||
* within iscsit_start_kthreads()
|
||||
*
|
||||
* Here we use thread_id to determine which CPU that this
|
||||
* iSCSI connection's iscsi_thread_set will be scheduled to
|
||||
* Here we use bitmap_id to determine which CPU that this
|
||||
* iSCSI connection's RX/TX threads will be scheduled to
|
||||
* execute upon.
|
||||
*/
|
||||
ord = ts->thread_id % cpumask_weight(cpu_online_mask);
|
||||
ord = conn->bitmap_id % cpumask_weight(cpu_online_mask);
|
||||
for_each_online_cpu(cpu) {
|
||||
if (ord-- == 0) {
|
||||
cpumask_set_cpu(cpu, conn->conn_cpumask);
|
||||
@ -3914,7 +3912,7 @@ check_rsp_state:
|
||||
switch (state) {
|
||||
case ISTATE_SEND_LOGOUTRSP:
|
||||
if (!iscsit_logout_post_handler(cmd, conn))
|
||||
goto restart;
|
||||
return -ECONNRESET;
|
||||
/* fall through */
|
||||
case ISTATE_SEND_STATUS:
|
||||
case ISTATE_SEND_ASYNCMSG:
|
||||
@ -3942,8 +3940,6 @@ check_rsp_state:
|
||||
|
||||
err:
|
||||
return -1;
|
||||
restart:
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int iscsit_handle_response_queue(struct iscsi_conn *conn)
|
||||
@ -3970,21 +3966,13 @@ static int iscsit_handle_response_queue(struct iscsi_conn *conn)
|
||||
int iscsi_target_tx_thread(void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct iscsi_conn *conn;
|
||||
struct iscsi_thread_set *ts = arg;
|
||||
struct iscsi_conn *conn = arg;
|
||||
/*
|
||||
* Allow ourselves to be interrupted by SIGINT so that a
|
||||
* connection recovery / failure event can be triggered externally.
|
||||
*/
|
||||
allow_signal(SIGINT);
|
||||
|
||||
restart:
|
||||
conn = iscsi_tx_thread_pre_handler(ts);
|
||||
if (!conn)
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
/*
|
||||
* Ensure that both TX and RX per connection kthreads
|
||||
@ -3993,11 +3981,9 @@ restart:
|
||||
iscsit_thread_check_cpumask(conn, current, 1);
|
||||
|
||||
wait_event_interruptible(conn->queues_wq,
|
||||
!iscsit_conn_all_queues_empty(conn) ||
|
||||
ts->status == ISCSI_THREAD_SET_RESET);
|
||||
!iscsit_conn_all_queues_empty(conn));
|
||||
|
||||
if ((ts->status == ISCSI_THREAD_SET_RESET) ||
|
||||
signal_pending(current))
|
||||
if (signal_pending(current))
|
||||
goto transport_err;
|
||||
|
||||
get_immediate:
|
||||
@ -4008,15 +3994,14 @@ get_immediate:
|
||||
ret = iscsit_handle_response_queue(conn);
|
||||
if (ret == 1)
|
||||
goto get_immediate;
|
||||
else if (ret == -EAGAIN)
|
||||
goto restart;
|
||||
else if (ret == -ECONNRESET)
|
||||
goto out;
|
||||
else if (ret < 0)
|
||||
goto transport_err;
|
||||
}
|
||||
|
||||
transport_err:
|
||||
iscsit_take_action_for_connection_exit(conn);
|
||||
goto restart;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
@ -4111,8 +4096,7 @@ int iscsi_target_rx_thread(void *arg)
|
||||
int ret;
|
||||
u8 buffer[ISCSI_HDR_LEN], opcode;
|
||||
u32 checksum = 0, digest = 0;
|
||||
struct iscsi_conn *conn = NULL;
|
||||
struct iscsi_thread_set *ts = arg;
|
||||
struct iscsi_conn *conn = arg;
|
||||
struct kvec iov;
|
||||
/*
|
||||
* Allow ourselves to be interrupted by SIGINT so that a
|
||||
@ -4120,11 +4104,6 @@ int iscsi_target_rx_thread(void *arg)
|
||||
*/
|
||||
allow_signal(SIGINT);
|
||||
|
||||
restart:
|
||||
conn = iscsi_rx_thread_pre_handler(ts);
|
||||
if (!conn)
|
||||
goto out;
|
||||
|
||||
if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
|
||||
struct completion comp;
|
||||
int rc;
|
||||
@ -4134,7 +4113,7 @@ restart:
|
||||
if (rc < 0)
|
||||
goto transport_err;
|
||||
|
||||
goto out;
|
||||
goto transport_err;
|
||||
}
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
@ -4210,8 +4189,6 @@ transport_err:
|
||||
if (!signal_pending(current))
|
||||
atomic_set(&conn->transport_failed, 1);
|
||||
iscsit_take_action_for_connection_exit(conn);
|
||||
goto restart;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4273,7 +4250,24 @@ int iscsit_close_connection(
|
||||
if (conn->conn_transport->transport_type == ISCSI_TCP)
|
||||
complete(&conn->conn_logout_comp);
|
||||
|
||||
iscsi_release_thread_set(conn);
|
||||
if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) {
|
||||
if (conn->tx_thread &&
|
||||
cmpxchg(&conn->tx_thread_active, true, false)) {
|
||||
send_sig(SIGINT, conn->tx_thread, 1);
|
||||
kthread_stop(conn->tx_thread);
|
||||
}
|
||||
} else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) {
|
||||
if (conn->rx_thread &&
|
||||
cmpxchg(&conn->rx_thread_active, true, false)) {
|
||||
send_sig(SIGINT, conn->rx_thread, 1);
|
||||
kthread_stop(conn->rx_thread);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&iscsit_global->ts_bitmap_lock);
|
||||
bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
|
||||
get_order(1));
|
||||
spin_unlock(&iscsit_global->ts_bitmap_lock);
|
||||
|
||||
iscsit_stop_timers_for_cmds(conn);
|
||||
iscsit_stop_nopin_response_timer(conn);
|
||||
@ -4383,8 +4377,6 @@ int iscsit_close_connection(
|
||||
|
||||
iscsit_put_transport(conn->conn_transport);
|
||||
|
||||
conn->thread_set = NULL;
|
||||
|
||||
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
|
||||
conn->conn_state = TARG_CONN_STATE_FREE;
|
||||
kfree(conn);
|
||||
@ -4551,15 +4543,13 @@ static void iscsit_logout_post_handler_closesession(
|
||||
struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_session *sess = conn->sess;
|
||||
|
||||
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
|
||||
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
|
||||
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
|
||||
|
||||
atomic_set(&conn->conn_logout_remove, 0);
|
||||
complete(&conn->conn_logout_comp);
|
||||
|
||||
iscsit_dec_conn_usage_count(conn);
|
||||
iscsit_stop_session(sess, 1, 1);
|
||||
iscsit_stop_session(sess, sleep, sleep);
|
||||
iscsit_dec_session_usage_count(sess);
|
||||
target_put_session(sess->se_sess);
|
||||
}
|
||||
@ -4567,13 +4557,12 @@ static void iscsit_logout_post_handler_closesession(
|
||||
static void iscsit_logout_post_handler_samecid(
|
||||
struct iscsi_conn *conn)
|
||||
{
|
||||
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
|
||||
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
|
||||
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
|
||||
|
||||
atomic_set(&conn->conn_logout_remove, 0);
|
||||
complete(&conn->conn_logout_comp);
|
||||
|
||||
iscsit_cause_connection_reinstatement(conn, 1);
|
||||
iscsit_cause_connection_reinstatement(conn, sleep);
|
||||
iscsit_dec_conn_usage_count(conn);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ extern void iscsit_stop_session(struct iscsi_session *, int, int);
|
||||
extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
|
||||
|
||||
extern struct iscsit_global *iscsit_global;
|
||||
extern struct target_fabric_configfs *lio_target_fabric_configfs;
|
||||
extern const struct target_core_fabric_ops iscsi_ops;
|
||||
|
||||
extern struct kmem_cache *lio_dr_cache;
|
||||
extern struct kmem_cache *lio_ooo_cache;
|
||||
|
@ -37,9 +37,6 @@
|
||||
#include "iscsi_target_util.h"
|
||||
#include "iscsi_target.h"
|
||||
#include <target/iscsi/iscsi_target_stat.h>
|
||||
#include "iscsi_target_configfs.h"
|
||||
|
||||
struct target_fabric_configfs *lio_target_fabric_configfs;
|
||||
|
||||
struct lio_target_configfs_attribute {
|
||||
struct configfs_attribute attr;
|
||||
@ -1052,6 +1049,11 @@ TPG_ATTR(default_erl, S_IRUGO | S_IWUSR);
|
||||
*/
|
||||
DEF_TPG_ATTRIB(t10_pi);
|
||||
TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR);
|
||||
/*
|
||||
* Define iscsi_tpg_attrib_s_fabric_prot_type
|
||||
*/
|
||||
DEF_TPG_ATTRIB(fabric_prot_type);
|
||||
TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR);
|
||||
|
||||
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_authentication.attr,
|
||||
@ -1065,6 +1067,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_demo_mode_discovery.attr,
|
||||
&iscsi_tpg_attrib_default_erl.attr,
|
||||
&iscsi_tpg_attrib_t10_pi.attr,
|
||||
&iscsi_tpg_attrib_fabric_prot_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1410,8 +1413,18 @@ out:
|
||||
|
||||
TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
|
||||
|
||||
static ssize_t lio_target_tpg_show_dynamic_sessions(
|
||||
struct se_portal_group *se_tpg,
|
||||
char *page)
|
||||
{
|
||||
return target_show_dynamic_sessions(se_tpg, page);
|
||||
}
|
||||
|
||||
TF_TPG_BASE_ATTR_RO(lio_target, dynamic_sessions);
|
||||
|
||||
static struct configfs_attribute *lio_target_tpg_attrs[] = {
|
||||
&lio_target_tpg_enable.attr,
|
||||
&lio_target_tpg_dynamic_sessions.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1450,10 +1463,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
|
||||
if (!tpg)
|
||||
return NULL;
|
||||
|
||||
ret = core_tpg_register(
|
||||
&lio_target_fabric_configfs->tf_ops,
|
||||
wwn, &tpg->tpg_se_tpg, tpg,
|
||||
TRANSPORT_TPG_TYPE_NORMAL);
|
||||
ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg,
|
||||
tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
@ -1872,6 +1883,20 @@ static int lio_tpg_check_prod_mode_write_protect(
|
||||
return tpg->tpg_attrib.prod_mode_write_protect;
|
||||
}
|
||||
|
||||
static int lio_tpg_check_prot_fabric_only(
|
||||
struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
|
||||
/*
|
||||
* Only report fabric_prot_type if t10_pi has also been enabled
|
||||
* for incoming ib_isert sessions.
|
||||
*/
|
||||
if (!tpg->tpg_attrib.t10_pi)
|
||||
return 0;
|
||||
|
||||
return tpg->tpg_attrib.fabric_prot_type;
|
||||
}
|
||||
|
||||
static void lio_tpg_release_fabric_acl(
|
||||
struct se_portal_group *se_tpg,
|
||||
struct se_node_acl *se_acl)
|
||||
@ -1953,115 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
|
||||
iscsit_release_cmd(cmd);
|
||||
}
|
||||
|
||||
/* End functions for target_core_fabric_ops */
|
||||
const struct target_core_fabric_ops iscsi_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "iscsi",
|
||||
.get_fabric_name = iscsi_get_fabric_name,
|
||||
.get_fabric_proto_ident = iscsi_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = lio_tpg_get_endpoint_wwn,
|
||||
.tpg_get_tag = lio_tpg_get_tag,
|
||||
.tpg_get_default_depth = lio_tpg_get_default_depth,
|
||||
.tpg_get_pr_transport_id = iscsi_get_pr_transport_id,
|
||||
.tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len,
|
||||
.tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id,
|
||||
.tpg_check_demo_mode = lio_tpg_check_demo_mode,
|
||||
.tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache,
|
||||
.tpg_check_demo_mode_write_protect =
|
||||
lio_tpg_check_demo_mode_write_protect,
|
||||
.tpg_check_prod_mode_write_protect =
|
||||
lio_tpg_check_prod_mode_write_protect,
|
||||
.tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only,
|
||||
.tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl,
|
||||
.tpg_release_fabric_acl = lio_tpg_release_fabric_acl,
|
||||
.tpg_get_inst_index = lio_tpg_get_inst_index,
|
||||
.check_stop_free = lio_check_stop_free,
|
||||
.release_cmd = lio_release_cmd,
|
||||
.shutdown_session = lio_tpg_shutdown_session,
|
||||
.close_session = lio_tpg_close_session,
|
||||
.sess_get_index = lio_sess_get_index,
|
||||
.sess_get_initiator_sid = lio_sess_get_initiator_sid,
|
||||
.write_pending = lio_write_pending,
|
||||
.write_pending_status = lio_write_pending_status,
|
||||
.set_default_node_attributes = lio_set_default_node_attributes,
|
||||
.get_task_tag = iscsi_get_task_tag,
|
||||
.get_cmd_state = iscsi_get_cmd_state,
|
||||
.queue_data_in = lio_queue_data_in,
|
||||
.queue_status = lio_queue_status,
|
||||
.queue_tm_rsp = lio_queue_tm_rsp,
|
||||
.aborted_task = lio_aborted_task,
|
||||
.fabric_make_wwn = lio_target_call_coreaddtiqn,
|
||||
.fabric_drop_wwn = lio_target_call_coredeltiqn,
|
||||
.fabric_make_tpg = lio_target_tiqn_addtpg,
|
||||
.fabric_drop_tpg = lio_target_tiqn_deltpg,
|
||||
.fabric_make_np = lio_target_call_addnptotpg,
|
||||
.fabric_drop_np = lio_target_call_delnpfromtpg,
|
||||
.fabric_make_nodeacl = lio_target_make_nodeacl,
|
||||
.fabric_drop_nodeacl = lio_target_drop_nodeacl,
|
||||
|
||||
int iscsi_target_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
lio_target_fabric_configfs = NULL;
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("target_fabric_configfs_init() for"
|
||||
" LIO-Target failed!\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
/*
|
||||
* Setup the fabric API of function pointers used by target_core_mod..
|
||||
*/
|
||||
fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name;
|
||||
fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident;
|
||||
fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn;
|
||||
fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag;
|
||||
fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth;
|
||||
fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id;
|
||||
fabric->tf_ops.tpg_get_pr_transport_id_len =
|
||||
&iscsi_get_pr_transport_id_len;
|
||||
fabric->tf_ops.tpg_parse_pr_out_transport_id =
|
||||
&iscsi_parse_pr_out_transport_id;
|
||||
fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode;
|
||||
fabric->tf_ops.tpg_check_demo_mode_cache =
|
||||
&lio_tpg_check_demo_mode_cache;
|
||||
fabric->tf_ops.tpg_check_demo_mode_write_protect =
|
||||
&lio_tpg_check_demo_mode_write_protect;
|
||||
fabric->tf_ops.tpg_check_prod_mode_write_protect =
|
||||
&lio_tpg_check_prod_mode_write_protect;
|
||||
fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl;
|
||||
fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl;
|
||||
fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index;
|
||||
fabric->tf_ops.check_stop_free = &lio_check_stop_free,
|
||||
fabric->tf_ops.release_cmd = &lio_release_cmd;
|
||||
fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
|
||||
fabric->tf_ops.close_session = &lio_tpg_close_session;
|
||||
fabric->tf_ops.sess_get_index = &lio_sess_get_index;
|
||||
fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid;
|
||||
fabric->tf_ops.write_pending = &lio_write_pending;
|
||||
fabric->tf_ops.write_pending_status = &lio_write_pending_status;
|
||||
fabric->tf_ops.set_default_node_attributes =
|
||||
&lio_set_default_node_attributes;
|
||||
fabric->tf_ops.get_task_tag = &iscsi_get_task_tag;
|
||||
fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state;
|
||||
fabric->tf_ops.queue_data_in = &lio_queue_data_in;
|
||||
fabric->tf_ops.queue_status = &lio_queue_status;
|
||||
fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
|
||||
fabric->tf_ops.aborted_task = &lio_aborted_task;
|
||||
/*
|
||||
* Setup function pointers for generic logic in target_core_fabric_configfs.c
|
||||
*/
|
||||
fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn;
|
||||
fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn;
|
||||
fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg;
|
||||
fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg;
|
||||
fabric->tf_ops.fabric_post_link = NULL;
|
||||
fabric->tf_ops.fabric_pre_unlink = NULL;
|
||||
fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg;
|
||||
fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg;
|
||||
fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl;
|
||||
fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl;
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
* sturct config_item_type's
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs;
|
||||
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() for"
|
||||
" LIO-Target failed!\n");
|
||||
target_fabric_configfs_free(fabric);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lio_target_fabric_configfs = fabric;
|
||||
pr_debug("LIO_TARGET[0] - Set fabric ->"
|
||||
" lio_target_fabric_configfs\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void iscsi_target_deregister_configfs(void)
|
||||
{
|
||||
if (!lio_target_fabric_configfs)
|
||||
return;
|
||||
/*
|
||||
* Shutdown discovery sessions and disable discovery TPG
|
||||
*/
|
||||
if (iscsit_global->discovery_tpg)
|
||||
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
|
||||
|
||||
target_fabric_configfs_deregister(lio_target_fabric_configfs);
|
||||
lio_target_fabric_configfs = NULL;
|
||||
pr_debug("LIO_TARGET[0] - Cleared"
|
||||
" lio_target_fabric_configfs\n");
|
||||
}
|
||||
.tfc_discovery_attrs = lio_target_discovery_auth_attrs,
|
||||
.tfc_wwn_attrs = lio_target_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = lio_target_tpg_attrs,
|
||||
.tfc_tpg_attrib_attrs = lio_target_tpg_attrib_attrs,
|
||||
.tfc_tpg_auth_attrs = lio_target_tpg_auth_attrs,
|
||||
.tfc_tpg_param_attrs = lio_target_tpg_param_attrs,
|
||||
.tfc_tpg_np_base_attrs = lio_target_portal_attrs,
|
||||
.tfc_tpg_nacl_base_attrs = lio_target_initiator_attrs,
|
||||
.tfc_tpg_nacl_attrib_attrs = lio_target_nacl_attrib_attrs,
|
||||
.tfc_tpg_nacl_auth_attrs = lio_target_nacl_auth_attrs,
|
||||
.tfc_tpg_nacl_param_attrs = lio_target_nacl_param_attrs,
|
||||
};
|
||||
|
@ -1,7 +0,0 @@
|
||||
#ifndef ISCSI_TARGET_CONFIGFS_H
|
||||
#define ISCSI_TARGET_CONFIGFS_H
|
||||
|
||||
extern int iscsi_target_register_configfs(void);
|
||||
extern void iscsi_target_deregister_configfs(void);
|
||||
|
||||
#endif /* ISCSI_TARGET_CONFIGFS_H */
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include <target/iscsi/iscsi_target_core.h>
|
||||
#include "iscsi_target_seq_pdu_list.h"
|
||||
#include "iscsi_target_tq.h"
|
||||
#include "iscsi_target_erl0.h"
|
||||
#include "iscsi_target_erl1.h"
|
||||
#include "iscsi_target_erl2.h"
|
||||
@ -860,7 +859,10 @@ void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn)
|
||||
}
|
||||
spin_unlock_bh(&conn->state_lock);
|
||||
|
||||
iscsi_thread_set_force_reinstatement(conn);
|
||||
if (conn->tx_thread && conn->tx_thread_active)
|
||||
send_sig(SIGINT, conn->tx_thread, 1);
|
||||
if (conn->rx_thread && conn->rx_thread_active)
|
||||
send_sig(SIGINT, conn->rx_thread, 1);
|
||||
|
||||
sleep:
|
||||
wait_for_completion(&conn->conn_wait_rcfr_comp);
|
||||
@ -885,10 +887,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (iscsi_thread_set_force_reinstatement(conn) < 0) {
|
||||
spin_unlock_bh(&conn->state_lock);
|
||||
return;
|
||||
}
|
||||
if (conn->tx_thread && conn->tx_thread_active)
|
||||
send_sig(SIGINT, conn->tx_thread, 1);
|
||||
if (conn->rx_thread && conn->rx_thread_active)
|
||||
send_sig(SIGINT, conn->rx_thread, 1);
|
||||
|
||||
atomic_set(&conn->connection_reinstatement, 1);
|
||||
if (!sleep) {
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include <target/iscsi/iscsi_target_core.h>
|
||||
#include <target/iscsi/iscsi_target_stat.h>
|
||||
#include "iscsi_target_tq.h"
|
||||
#include "iscsi_target_device.h"
|
||||
#include "iscsi_target_nego.h"
|
||||
#include "iscsi_target_erl0.h"
|
||||
@ -699,6 +698,51 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
|
||||
iscsit_start_nopin_timer(conn);
|
||||
}
|
||||
|
||||
static int iscsit_start_kthreads(struct iscsi_conn *conn)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&iscsit_global->ts_bitmap_lock);
|
||||
conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
|
||||
ISCSIT_BITMAP_BITS, get_order(1));
|
||||
spin_unlock(&iscsit_global->ts_bitmap_lock);
|
||||
|
||||
if (conn->bitmap_id < 0) {
|
||||
pr_err("bitmap_find_free_region() failed for"
|
||||
" iscsit_start_kthreads()\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn,
|
||||
"%s", ISCSI_TX_THREAD_NAME);
|
||||
if (IS_ERR(conn->tx_thread)) {
|
||||
pr_err("Unable to start iscsi_target_tx_thread\n");
|
||||
ret = PTR_ERR(conn->tx_thread);
|
||||
goto out_bitmap;
|
||||
}
|
||||
conn->tx_thread_active = true;
|
||||
|
||||
conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn,
|
||||
"%s", ISCSI_RX_THREAD_NAME);
|
||||
if (IS_ERR(conn->rx_thread)) {
|
||||
pr_err("Unable to start iscsi_target_rx_thread\n");
|
||||
ret = PTR_ERR(conn->rx_thread);
|
||||
goto out_tx;
|
||||
}
|
||||
conn->rx_thread_active = true;
|
||||
|
||||
return 0;
|
||||
out_tx:
|
||||
kthread_stop(conn->tx_thread);
|
||||
conn->tx_thread_active = false;
|
||||
out_bitmap:
|
||||
spin_lock(&iscsit_global->ts_bitmap_lock);
|
||||
bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
|
||||
get_order(1));
|
||||
spin_unlock(&iscsit_global->ts_bitmap_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iscsi_post_login_handler(
|
||||
struct iscsi_np *np,
|
||||
struct iscsi_conn *conn,
|
||||
@ -709,7 +753,7 @@ int iscsi_post_login_handler(
|
||||
struct se_session *se_sess = sess->se_sess;
|
||||
struct iscsi_portal_group *tpg = sess->tpg;
|
||||
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
|
||||
struct iscsi_thread_set *ts;
|
||||
int rc;
|
||||
|
||||
iscsit_inc_conn_usage_count(conn);
|
||||
|
||||
@ -724,7 +768,6 @@ int iscsi_post_login_handler(
|
||||
/*
|
||||
* SCSI Initiator -> SCSI Target Port Mapping
|
||||
*/
|
||||
ts = iscsi_get_thread_set();
|
||||
if (!zero_tsih) {
|
||||
iscsi_set_session_parameters(sess->sess_ops,
|
||||
conn->param_list, 0);
|
||||
@ -751,9 +794,11 @@ int iscsi_post_login_handler(
|
||||
sess->sess_ops->InitiatorName);
|
||||
spin_unlock_bh(&sess->conn_lock);
|
||||
|
||||
iscsi_post_login_start_timers(conn);
|
||||
rc = iscsit_start_kthreads(conn);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
iscsi_activate_thread_set(conn, ts);
|
||||
iscsi_post_login_start_timers(conn);
|
||||
/*
|
||||
* Determine CPU mask to ensure connection's RX and TX kthreads
|
||||
* are scheduled on the same CPU.
|
||||
@ -810,8 +855,11 @@ int iscsi_post_login_handler(
|
||||
" iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
|
||||
spin_unlock_bh(&se_tpg->session_lock);
|
||||
|
||||
rc = iscsit_start_kthreads(conn);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
iscsi_post_login_start_timers(conn);
|
||||
iscsi_activate_thread_set(conn, ts);
|
||||
/*
|
||||
* Determine CPU mask to ensure connection's RX and TX kthreads
|
||||
* are scheduled on the same CPU.
|
||||
|
@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = core_tpg_register(
|
||||
&lio_target_fabric_configfs->tf_ops,
|
||||
NULL, &tpg->tpg_se_tpg, tpg,
|
||||
TRANSPORT_TPG_TYPE_DISCOVERY);
|
||||
ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg,
|
||||
tpg, TRANSPORT_TPG_TYPE_DISCOVERY);
|
||||
if (ret < 0) {
|
||||
kfree(tpg);
|
||||
return -1;
|
||||
@ -228,6 +226,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
|
||||
a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY;
|
||||
a->default_erl = TA_DEFAULT_ERL;
|
||||
a->t10_pi = TA_DEFAULT_T10_PI;
|
||||
a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
|
||||
}
|
||||
|
||||
int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
|
||||
@ -878,3 +877,21 @@ int iscsit_ta_t10_pi(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iscsit_ta_fabric_prot_type(
|
||||
struct iscsi_portal_group *tpg,
|
||||
u32 prot_type)
|
||||
{
|
||||
struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
|
||||
|
||||
if ((prot_type != 0) && (prot_type != 1) && (prot_type != 3)) {
|
||||
pr_err("Illegal value for fabric_prot_type: %u\n", prot_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
a->fabric_prot_type = prot_type;
|
||||
pr_debug("iSCSI_TPG[%hu] - T10 Fabric Protection Type: %u\n",
|
||||
tpg->tpgt, prot_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,5 +39,6 @@ extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
|
||||
|
||||
#endif /* ISCSI_TARGET_TPG_H */
|
||||
|
@ -1,495 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file contains the iSCSI Login Thread and Thread Queue functions.
|
||||
*
|
||||
* (c) Copyright 2007-2013 Datera, Inc.
|
||||
*
|
||||
* Author: 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.
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
#include <target/iscsi/iscsi_target_core.h>
|
||||
#include "iscsi_target_tq.h"
|
||||
#include "iscsi_target.h"
|
||||
|
||||
static LIST_HEAD(inactive_ts_list);
|
||||
static DEFINE_SPINLOCK(inactive_ts_lock);
|
||||
static DEFINE_SPINLOCK(ts_bitmap_lock);
|
||||
|
||||
static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
|
||||
{
|
||||
if (!list_empty(&ts->ts_list)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
spin_lock(&inactive_ts_lock);
|
||||
list_add_tail(&ts->ts_list, &inactive_ts_list);
|
||||
iscsit_global->inactive_ts++;
|
||||
spin_unlock(&inactive_ts_lock);
|
||||
}
|
||||
|
||||
static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
|
||||
{
|
||||
struct iscsi_thread_set *ts;
|
||||
|
||||
spin_lock(&inactive_ts_lock);
|
||||
if (list_empty(&inactive_ts_list)) {
|
||||
spin_unlock(&inactive_ts_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list);
|
||||
|
||||
list_del_init(&ts->ts_list);
|
||||
iscsit_global->inactive_ts--;
|
||||
spin_unlock(&inactive_ts_lock);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int iscsi_allocate_thread_sets(u32 thread_pair_count)
|
||||
{
|
||||
int allocated_thread_pair_count = 0, i, thread_id;
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
|
||||
for (i = 0; i < thread_pair_count; i++) {
|
||||
ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL);
|
||||
if (!ts) {
|
||||
pr_err("Unable to allocate memory for"
|
||||
" thread set.\n");
|
||||
return allocated_thread_pair_count;
|
||||
}
|
||||
/*
|
||||
* Locate the next available regision in the thread_set_bitmap
|
||||
*/
|
||||
spin_lock(&ts_bitmap_lock);
|
||||
thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
|
||||
iscsit_global->ts_bitmap_count, get_order(1));
|
||||
spin_unlock(&ts_bitmap_lock);
|
||||
if (thread_id < 0) {
|
||||
pr_err("bitmap_find_free_region() failed for"
|
||||
" thread_set_bitmap\n");
|
||||
kfree(ts);
|
||||
return allocated_thread_pair_count;
|
||||
}
|
||||
|
||||
ts->thread_id = thread_id;
|
||||
ts->status = ISCSI_THREAD_SET_FREE;
|
||||
INIT_LIST_HEAD(&ts->ts_list);
|
||||
spin_lock_init(&ts->ts_state_lock);
|
||||
init_completion(&ts->rx_restart_comp);
|
||||
init_completion(&ts->tx_restart_comp);
|
||||
init_completion(&ts->rx_start_comp);
|
||||
init_completion(&ts->tx_start_comp);
|
||||
sema_init(&ts->ts_activate_sem, 0);
|
||||
|
||||
ts->create_threads = 1;
|
||||
ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
|
||||
ISCSI_TX_THREAD_NAME);
|
||||
if (IS_ERR(ts->tx_thread)) {
|
||||
dump_stack();
|
||||
pr_err("Unable to start iscsi_target_tx_thread\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s",
|
||||
ISCSI_RX_THREAD_NAME);
|
||||
if (IS_ERR(ts->rx_thread)) {
|
||||
kthread_stop(ts->tx_thread);
|
||||
pr_err("Unable to start iscsi_target_rx_thread\n");
|
||||
break;
|
||||
}
|
||||
ts->create_threads = 0;
|
||||
|
||||
iscsi_add_ts_to_inactive_list(ts);
|
||||
allocated_thread_pair_count++;
|
||||
}
|
||||
|
||||
pr_debug("Spawned %d thread set(s) (%d total threads).\n",
|
||||
allocated_thread_pair_count, allocated_thread_pair_count * 2);
|
||||
return allocated_thread_pair_count;
|
||||
}
|
||||
|
||||
static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts)
|
||||
{
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->status = ISCSI_THREAD_SET_DIE;
|
||||
|
||||
if (ts->rx_thread) {
|
||||
complete(&ts->rx_start_comp);
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
kthread_stop(ts->rx_thread);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
if (ts->tx_thread) {
|
||||
complete(&ts->tx_start_comp);
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
kthread_stop(ts->tx_thread);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
/*
|
||||
* Release this thread_id in the thread_set_bitmap
|
||||
*/
|
||||
spin_lock(&ts_bitmap_lock);
|
||||
bitmap_release_region(iscsit_global->ts_bitmap,
|
||||
ts->thread_id, get_order(1));
|
||||
spin_unlock(&ts_bitmap_lock);
|
||||
|
||||
kfree(ts);
|
||||
}
|
||||
|
||||
void iscsi_deallocate_thread_sets(void)
|
||||
{
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
u32 released_count = 0;
|
||||
|
||||
while ((ts = iscsi_get_ts_from_inactive_list())) {
|
||||
|
||||
iscsi_deallocate_thread_one(ts);
|
||||
released_count++;
|
||||
}
|
||||
|
||||
if (released_count)
|
||||
pr_debug("Stopped %d thread set(s) (%d total threads)."
|
||||
"\n", released_count, released_count * 2);
|
||||
}
|
||||
|
||||
static void iscsi_deallocate_extra_thread_sets(void)
|
||||
{
|
||||
u32 orig_count, released_count = 0;
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
|
||||
orig_count = TARGET_THREAD_SET_COUNT;
|
||||
|
||||
while ((iscsit_global->inactive_ts + 1) > orig_count) {
|
||||
ts = iscsi_get_ts_from_inactive_list();
|
||||
if (!ts)
|
||||
break;
|
||||
|
||||
iscsi_deallocate_thread_one(ts);
|
||||
released_count++;
|
||||
}
|
||||
|
||||
if (released_count)
|
||||
pr_debug("Stopped %d thread set(s) (%d total threads)."
|
||||
"\n", released_count, released_count * 2);
|
||||
}
|
||||
|
||||
void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
|
||||
{
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
conn->thread_set = ts;
|
||||
ts->conn = conn;
|
||||
ts->status = ISCSI_THREAD_SET_ACTIVE;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
complete(&ts->rx_start_comp);
|
||||
complete(&ts->tx_start_comp);
|
||||
|
||||
down(&ts->ts_activate_sem);
|
||||
}
|
||||
|
||||
struct iscsi_thread_set *iscsi_get_thread_set(void)
|
||||
{
|
||||
struct iscsi_thread_set *ts;
|
||||
|
||||
get_set:
|
||||
ts = iscsi_get_ts_from_inactive_list();
|
||||
if (!ts) {
|
||||
iscsi_allocate_thread_sets(1);
|
||||
goto get_set;
|
||||
}
|
||||
|
||||
ts->delay_inactive = 1;
|
||||
ts->signal_sent = 0;
|
||||
ts->thread_count = 2;
|
||||
init_completion(&ts->rx_restart_comp);
|
||||
init_completion(&ts->tx_restart_comp);
|
||||
sema_init(&ts->ts_activate_sem, 0);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear)
|
||||
{
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
|
||||
if (!conn->thread_set) {
|
||||
pr_err("struct iscsi_conn->thread_set is NULL\n");
|
||||
return;
|
||||
}
|
||||
ts = conn->thread_set;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->thread_clear &= ~thread_clear;
|
||||
|
||||
if ((thread_clear & ISCSI_CLEAR_RX_THREAD) &&
|
||||
(ts->blocked_threads & ISCSI_BLOCK_RX_THREAD))
|
||||
complete(&ts->rx_restart_comp);
|
||||
else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) &&
|
||||
(ts->blocked_threads & ISCSI_BLOCK_TX_THREAD))
|
||||
complete(&ts->tx_restart_comp);
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
|
||||
void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent)
|
||||
{
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
|
||||
if (!conn->thread_set) {
|
||||
pr_err("struct iscsi_conn->thread_set is NULL\n");
|
||||
return;
|
||||
}
|
||||
ts = conn->thread_set;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->signal_sent |= signal_sent;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
|
||||
int iscsi_release_thread_set(struct iscsi_conn *conn)
|
||||
{
|
||||
int thread_called = 0;
|
||||
struct iscsi_thread_set *ts = NULL;
|
||||
|
||||
if (!conn || !conn->thread_set) {
|
||||
pr_err("connection or thread set pointer is NULL\n");
|
||||
BUG();
|
||||
}
|
||||
ts = conn->thread_set;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->status = ISCSI_THREAD_SET_RESET;
|
||||
|
||||
if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME,
|
||||
strlen(ISCSI_RX_THREAD_NAME)))
|
||||
thread_called = ISCSI_RX_THREAD;
|
||||
else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME,
|
||||
strlen(ISCSI_TX_THREAD_NAME)))
|
||||
thread_called = ISCSI_TX_THREAD;
|
||||
|
||||
if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) &&
|
||||
(ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) {
|
||||
|
||||
if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) {
|
||||
send_sig(SIGINT, ts->rx_thread, 1);
|
||||
ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
|
||||
}
|
||||
ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
wait_for_completion(&ts->rx_restart_comp);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD;
|
||||
}
|
||||
if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) &&
|
||||
(ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) {
|
||||
|
||||
if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) {
|
||||
send_sig(SIGINT, ts->tx_thread, 1);
|
||||
ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
|
||||
}
|
||||
ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
wait_for_completion(&ts->tx_restart_comp);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD;
|
||||
}
|
||||
|
||||
ts->conn = NULL;
|
||||
ts->status = ISCSI_THREAD_SET_FREE;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_thread_set *ts;
|
||||
|
||||
if (!conn->thread_set)
|
||||
return -1;
|
||||
ts = conn->thread_set;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (ts->status != ISCSI_THREAD_SET_ACTIVE) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) {
|
||||
send_sig(SIGINT, ts->tx_thread, 1);
|
||||
ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
|
||||
}
|
||||
if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) {
|
||||
send_sig(SIGINT, ts->rx_thread, 1);
|
||||
ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
|
||||
}
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iscsi_check_to_add_additional_sets(void)
|
||||
{
|
||||
int thread_sets_add;
|
||||
|
||||
spin_lock(&inactive_ts_lock);
|
||||
thread_sets_add = iscsit_global->inactive_ts;
|
||||
spin_unlock(&inactive_ts_lock);
|
||||
if (thread_sets_add == 1)
|
||||
iscsi_allocate_thread_sets(1);
|
||||
}
|
||||
|
||||
static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts)
|
||||
{
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (ts->status == ISCSI_THREAD_SET_DIE || kthread_should_stop() ||
|
||||
signal_pending(current)) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
return -1;
|
||||
}
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (ts->create_threads) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
goto sleep;
|
||||
}
|
||||
|
||||
if (ts->status != ISCSI_THREAD_SET_DIE)
|
||||
flush_signals(current);
|
||||
|
||||
if (ts->delay_inactive && (--ts->thread_count == 0)) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
if (!iscsit_global->in_shutdown)
|
||||
iscsi_deallocate_extra_thread_sets();
|
||||
|
||||
iscsi_add_ts_to_inactive_list(ts);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
|
||||
if ((ts->status == ISCSI_THREAD_SET_RESET) &&
|
||||
(ts->thread_clear & ISCSI_CLEAR_RX_THREAD))
|
||||
complete(&ts->rx_restart_comp);
|
||||
|
||||
ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
sleep:
|
||||
ret = wait_for_completion_interruptible(&ts->rx_start_comp);
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
if (iscsi_signal_thread_pre_handler(ts) < 0)
|
||||
return NULL;
|
||||
|
||||
iscsi_check_to_add_additional_sets();
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (!ts->conn) {
|
||||
pr_err("struct iscsi_thread_set->conn is NULL for"
|
||||
" RX thread_id: %s/%d\n", current->comm, current->pid);
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
return NULL;
|
||||
}
|
||||
ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
up(&ts->ts_activate_sem);
|
||||
|
||||
return ts->conn;
|
||||
}
|
||||
|
||||
struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (ts->create_threads) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
goto sleep;
|
||||
}
|
||||
|
||||
if (ts->status != ISCSI_THREAD_SET_DIE)
|
||||
flush_signals(current);
|
||||
|
||||
if (ts->delay_inactive && (--ts->thread_count == 0)) {
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
if (!iscsit_global->in_shutdown)
|
||||
iscsi_deallocate_extra_thread_sets();
|
||||
|
||||
iscsi_add_ts_to_inactive_list(ts);
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
}
|
||||
if ((ts->status == ISCSI_THREAD_SET_RESET) &&
|
||||
(ts->thread_clear & ISCSI_CLEAR_TX_THREAD))
|
||||
complete(&ts->tx_restart_comp);
|
||||
|
||||
ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
sleep:
|
||||
ret = wait_for_completion_interruptible(&ts->tx_start_comp);
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
if (iscsi_signal_thread_pre_handler(ts) < 0)
|
||||
return NULL;
|
||||
|
||||
iscsi_check_to_add_additional_sets();
|
||||
|
||||
spin_lock_bh(&ts->ts_state_lock);
|
||||
if (!ts->conn) {
|
||||
pr_err("struct iscsi_thread_set->conn is NULL for"
|
||||
" TX thread_id: %s/%d\n", current->comm, current->pid);
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
return NULL;
|
||||
}
|
||||
ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
|
||||
spin_unlock_bh(&ts->ts_state_lock);
|
||||
|
||||
up(&ts->ts_activate_sem);
|
||||
|
||||
return ts->conn;
|
||||
}
|
||||
|
||||
int iscsi_thread_set_init(void)
|
||||
{
|
||||
int size;
|
||||
|
||||
iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS;
|
||||
|
||||
size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long);
|
||||
iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL);
|
||||
if (!iscsit_global->ts_bitmap) {
|
||||
pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iscsi_thread_set_free(void)
|
||||
{
|
||||
kfree(iscsit_global->ts_bitmap);
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
#ifndef ISCSI_THREAD_QUEUE_H
|
||||
#define ISCSI_THREAD_QUEUE_H
|
||||
|
||||
/*
|
||||
* Defines for thread sets.
|
||||
*/
|
||||
extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *);
|
||||
extern int iscsi_allocate_thread_sets(u32);
|
||||
extern void iscsi_deallocate_thread_sets(void);
|
||||
extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *);
|
||||
extern struct iscsi_thread_set *iscsi_get_thread_set(void);
|
||||
extern void iscsi_set_thread_clear(struct iscsi_conn *, u8);
|
||||
extern void iscsi_set_thread_set_signal(struct iscsi_conn *, u8);
|
||||
extern int iscsi_release_thread_set(struct iscsi_conn *);
|
||||
extern struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *);
|
||||
extern struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *);
|
||||
extern int iscsi_thread_set_init(void);
|
||||
extern void iscsi_thread_set_free(void);
|
||||
|
||||
extern int iscsi_target_tx_thread(void *);
|
||||
extern int iscsi_target_rx_thread(void *);
|
||||
|
||||
#define TARGET_THREAD_SET_COUNT 4
|
||||
|
||||
#define ISCSI_RX_THREAD 1
|
||||
#define ISCSI_TX_THREAD 2
|
||||
#define ISCSI_RX_THREAD_NAME "iscsi_trx"
|
||||
#define ISCSI_TX_THREAD_NAME "iscsi_ttx"
|
||||
#define ISCSI_BLOCK_RX_THREAD 0x1
|
||||
#define ISCSI_BLOCK_TX_THREAD 0x2
|
||||
#define ISCSI_CLEAR_RX_THREAD 0x1
|
||||
#define ISCSI_CLEAR_TX_THREAD 0x2
|
||||
#define ISCSI_SIGNAL_RX_THREAD 0x1
|
||||
#define ISCSI_SIGNAL_TX_THREAD 0x2
|
||||
|
||||
/* struct iscsi_thread_set->status */
|
||||
#define ISCSI_THREAD_SET_FREE 1
|
||||
#define ISCSI_THREAD_SET_ACTIVE 2
|
||||
#define ISCSI_THREAD_SET_DIE 3
|
||||
#define ISCSI_THREAD_SET_RESET 4
|
||||
#define ISCSI_THREAD_SET_DEALLOCATE_THREADS 5
|
||||
|
||||
/* By default allow a maximum of 32K iSCSI connections */
|
||||
#define ISCSI_TS_BITMAP_BITS 32768
|
||||
|
||||
struct iscsi_thread_set {
|
||||
/* flags used for blocking and restarting sets */
|
||||
int blocked_threads;
|
||||
/* flag for creating threads */
|
||||
int create_threads;
|
||||
/* flag for delaying readding to inactive list */
|
||||
int delay_inactive;
|
||||
/* status for thread set */
|
||||
int status;
|
||||
/* which threads have had signals sent */
|
||||
int signal_sent;
|
||||
/* flag for which threads exited first */
|
||||
int thread_clear;
|
||||
/* Active threads in the thread set */
|
||||
int thread_count;
|
||||
/* Unique thread ID */
|
||||
u32 thread_id;
|
||||
/* pointer to connection if set is active */
|
||||
struct iscsi_conn *conn;
|
||||
/* used for controlling ts state accesses */
|
||||
spinlock_t ts_state_lock;
|
||||
/* used for restarting thread queue */
|
||||
struct completion rx_restart_comp;
|
||||
/* used for restarting thread queue */
|
||||
struct completion tx_restart_comp;
|
||||
/* used for normal unused blocking */
|
||||
struct completion rx_start_comp;
|
||||
/* used for normal unused blocking */
|
||||
struct completion tx_start_comp;
|
||||
/* OS descriptor for rx thread */
|
||||
struct task_struct *rx_thread;
|
||||
/* OS descriptor for tx thread */
|
||||
struct task_struct *tx_thread;
|
||||
/* struct iscsi_thread_set in list list head*/
|
||||
struct list_head ts_list;
|
||||
struct semaphore ts_activate_sem;
|
||||
};
|
||||
|
||||
#endif /*** ISCSI_THREAD_QUEUE_H ***/
|
@ -33,7 +33,6 @@
|
||||
#include "iscsi_target_erl1.h"
|
||||
#include "iscsi_target_erl2.h"
|
||||
#include "iscsi_target_tpg.h"
|
||||
#include "iscsi_target_tq.h"
|
||||
#include "iscsi_target_util.h"
|
||||
#include "iscsi_target.h"
|
||||
|
||||
|
@ -41,8 +41,7 @@
|
||||
|
||||
#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev)
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
static struct target_fabric_configfs *tcm_loop_fabric_configfs;
|
||||
static const struct target_core_fabric_ops loop_ops;
|
||||
|
||||
static struct workqueue_struct *tcm_loop_workqueue;
|
||||
static struct kmem_cache *tcm_loop_cmd_cache;
|
||||
@ -108,7 +107,7 @@ static struct device_driver tcm_loop_driverfs = {
|
||||
/*
|
||||
* Used with root_device_register() in tcm_loop_alloc_core_bus() below
|
||||
*/
|
||||
struct device *tcm_loop_primary;
|
||||
static struct device *tcm_loop_primary;
|
||||
|
||||
static void tcm_loop_submission_work(struct work_struct *work)
|
||||
{
|
||||
@ -697,6 +696,13 @@ static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
|
||||
tl_se_tpg);
|
||||
return tl_tpg->tl_fabric_prot_type;
|
||||
}
|
||||
|
||||
static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl(
|
||||
struct se_portal_group *se_tpg)
|
||||
{
|
||||
@ -912,6 +918,46 @@ static void tcm_loop_port_unlink(
|
||||
|
||||
/* End items for tcm_loop_port_cit */
|
||||
|
||||
static ssize_t tcm_loop_tpg_attrib_show_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
char *page)
|
||||
{
|
||||
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
|
||||
tl_se_tpg);
|
||||
|
||||
return sprintf(page, "%d\n", tl_tpg->tl_fabric_prot_type);
|
||||
}
|
||||
|
||||
static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *page,
|
||||
size_t count)
|
||||
{
|
||||
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
|
||||
tl_se_tpg);
|
||||
unsigned long val;
|
||||
int ret = kstrtoul(page, 0, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (val != 0 && val != 1 && val != 3) {
|
||||
pr_err("Invalid qla2xxx fabric_prot_type: %lu\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
tl_tpg->tl_fabric_prot_type = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
TF_TPG_ATTRIB_ATTR(tcm_loop, fabric_prot_type, S_IRUGO | S_IWUSR);
|
||||
|
||||
static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = {
|
||||
&tcm_loop_tpg_attrib_fabric_prot_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Start items for tcm_loop_nexus_cit */
|
||||
|
||||
static int tcm_loop_make_nexus(
|
||||
@ -937,7 +983,8 @@ static int tcm_loop_make_nexus(
|
||||
/*
|
||||
* Initialize the struct se_session pointer
|
||||
*/
|
||||
tl_nexus->se_sess = transport_init_session(TARGET_PROT_ALL);
|
||||
tl_nexus->se_sess = transport_init_session(
|
||||
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
|
||||
if (IS_ERR(tl_nexus->se_sess)) {
|
||||
ret = PTR_ERR(tl_nexus->se_sess);
|
||||
goto out;
|
||||
@ -1165,21 +1212,19 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
|
||||
struct tcm_loop_hba *tl_hba = container_of(wwn,
|
||||
struct tcm_loop_hba, tl_hba_wwn);
|
||||
struct tcm_loop_tpg *tl_tpg;
|
||||
char *tpgt_str, *end_ptr;
|
||||
int ret;
|
||||
unsigned short int tpgt;
|
||||
unsigned long tpgt;
|
||||
|
||||
tpgt_str = strstr(name, "tpgt_");
|
||||
if (!tpgt_str) {
|
||||
if (strstr(name, "tpgt_") != name) {
|
||||
pr_err("Unable to locate \"tpgt_#\" directory"
|
||||
" group\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
tpgt_str += 5; /* Skip ahead of "tpgt_" */
|
||||
tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
|
||||
if (kstrtoul(name+5, 10, &tpgt))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (tpgt >= TL_TPGS_PER_HBA) {
|
||||
pr_err("Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:"
|
||||
pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA:"
|
||||
" %u\n", tpgt, TL_TPGS_PER_HBA);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -1189,14 +1234,13 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
|
||||
/*
|
||||
* Register the tl_tpg as a emulated SAS TCM Target Endpoint
|
||||
*/
|
||||
ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops,
|
||||
wwn, &tl_tpg->tl_se_tpg, tl_tpg,
|
||||
ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg,
|
||||
TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s"
|
||||
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
|
||||
" Target Port %s,t,0x%04lx\n", tcm_loop_dump_proto_id(tl_hba),
|
||||
config_item_name(&wwn->wwn_group.cg_item), tpgt);
|
||||
|
||||
return &tl_tpg->tl_se_tpg;
|
||||
@ -1338,127 +1382,51 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
|
||||
|
||||
/* End items for tcm_loop_cit */
|
||||
|
||||
static int tcm_loop_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
/*
|
||||
* Set the TCM Loop HBA counter to zero
|
||||
*/
|
||||
tcm_loop_hba_no_cnt = 0;
|
||||
/*
|
||||
* Register the top level struct config_item_type with TCM core
|
||||
*/
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("tcm_loop_register_configfs() failed!\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
/*
|
||||
* Setup the fabric API of function pointers used by target_core_mod
|
||||
*/
|
||||
fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
|
||||
fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
|
||||
fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
|
||||
fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
|
||||
fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
|
||||
fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
|
||||
fabric->tf_ops.tpg_get_pr_transport_id_len =
|
||||
&tcm_loop_get_pr_transport_id_len;
|
||||
fabric->tf_ops.tpg_parse_pr_out_transport_id =
|
||||
&tcm_loop_parse_pr_out_transport_id;
|
||||
fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
|
||||
fabric->tf_ops.tpg_check_demo_mode_cache =
|
||||
&tcm_loop_check_demo_mode_cache;
|
||||
fabric->tf_ops.tpg_check_demo_mode_write_protect =
|
||||
&tcm_loop_check_demo_mode_write_protect;
|
||||
fabric->tf_ops.tpg_check_prod_mode_write_protect =
|
||||
&tcm_loop_check_prod_mode_write_protect;
|
||||
/*
|
||||
* The TCM loopback fabric module runs in demo-mode to a local
|
||||
* virtual SCSI device, so fabric dependent initator ACLs are
|
||||
* not required.
|
||||
*/
|
||||
fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
|
||||
fabric->tf_ops.tpg_release_fabric_acl =
|
||||
&tcm_loop_tpg_release_fabric_acl;
|
||||
fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index;
|
||||
/*
|
||||
* Used for setting up remaining TCM resources in process context
|
||||
*/
|
||||
fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
|
||||
fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
|
||||
fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
|
||||
fabric->tf_ops.close_session = &tcm_loop_close_session;
|
||||
fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
|
||||
fabric->tf_ops.sess_get_initiator_sid = NULL;
|
||||
fabric->tf_ops.write_pending = &tcm_loop_write_pending;
|
||||
fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status;
|
||||
/*
|
||||
* Not used for TCM loopback
|
||||
*/
|
||||
fabric->tf_ops.set_default_node_attributes =
|
||||
&tcm_loop_set_default_node_attributes;
|
||||
fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag;
|
||||
fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state;
|
||||
fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
|
||||
fabric->tf_ops.queue_status = &tcm_loop_queue_status;
|
||||
fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
|
||||
fabric->tf_ops.aborted_task = &tcm_loop_aborted_task;
|
||||
|
||||
/*
|
||||
* Setup function pointers for generic logic in target_core_fabric_configfs.c
|
||||
*/
|
||||
fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba;
|
||||
fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba;
|
||||
fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg;
|
||||
fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg;
|
||||
/*
|
||||
* fabric_post_link() and fabric_pre_unlink() are used for
|
||||
* registration and release of TCM Loop Virtual SCSI LUNs.
|
||||
*/
|
||||
fabric->tf_ops.fabric_post_link = &tcm_loop_port_link;
|
||||
fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink;
|
||||
fabric->tf_ops.fabric_make_np = NULL;
|
||||
fabric->tf_ops.fabric_drop_np = NULL;
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* Once fabric->tf_ops has been setup, now register the fabric for
|
||||
* use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() for"
|
||||
" TCM_Loop failed!\n");
|
||||
target_fabric_configfs_free(fabric);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Setup our local pointer to *fabric.
|
||||
*/
|
||||
tcm_loop_fabric_configfs = fabric;
|
||||
pr_debug("TCM_LOOP[0] - Set fabric ->"
|
||||
" tcm_loop_fabric_configfs\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcm_loop_deregister_configfs(void)
|
||||
{
|
||||
if (!tcm_loop_fabric_configfs)
|
||||
return;
|
||||
|
||||
target_fabric_configfs_deregister(tcm_loop_fabric_configfs);
|
||||
tcm_loop_fabric_configfs = NULL;
|
||||
pr_debug("TCM_LOOP[0] - Cleared"
|
||||
" tcm_loop_fabric_configfs\n");
|
||||
}
|
||||
static const struct target_core_fabric_ops loop_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "loopback",
|
||||
.get_fabric_name = tcm_loop_get_fabric_name,
|
||||
.get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = tcm_loop_get_endpoint_wwn,
|
||||
.tpg_get_tag = tcm_loop_get_tag,
|
||||
.tpg_get_default_depth = tcm_loop_get_default_depth,
|
||||
.tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id,
|
||||
.tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len,
|
||||
.tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id,
|
||||
.tpg_check_demo_mode = tcm_loop_check_demo_mode,
|
||||
.tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache,
|
||||
.tpg_check_demo_mode_write_protect =
|
||||
tcm_loop_check_demo_mode_write_protect,
|
||||
.tpg_check_prod_mode_write_protect =
|
||||
tcm_loop_check_prod_mode_write_protect,
|
||||
.tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only,
|
||||
.tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl,
|
||||
.tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl,
|
||||
.tpg_get_inst_index = tcm_loop_get_inst_index,
|
||||
.check_stop_free = tcm_loop_check_stop_free,
|
||||
.release_cmd = tcm_loop_release_cmd,
|
||||
.shutdown_session = tcm_loop_shutdown_session,
|
||||
.close_session = tcm_loop_close_session,
|
||||
.sess_get_index = tcm_loop_sess_get_index,
|
||||
.write_pending = tcm_loop_write_pending,
|
||||
.write_pending_status = tcm_loop_write_pending_status,
|
||||
.set_default_node_attributes = tcm_loop_set_default_node_attributes,
|
||||
.get_task_tag = tcm_loop_get_task_tag,
|
||||
.get_cmd_state = tcm_loop_get_cmd_state,
|
||||
.queue_data_in = tcm_loop_queue_data_in,
|
||||
.queue_status = tcm_loop_queue_status,
|
||||
.queue_tm_rsp = tcm_loop_queue_tm_rsp,
|
||||
.aborted_task = tcm_loop_aborted_task,
|
||||
.fabric_make_wwn = tcm_loop_make_scsi_hba,
|
||||
.fabric_drop_wwn = tcm_loop_drop_scsi_hba,
|
||||
.fabric_make_tpg = tcm_loop_make_naa_tpg,
|
||||
.fabric_drop_tpg = tcm_loop_drop_naa_tpg,
|
||||
.fabric_post_link = tcm_loop_port_link,
|
||||
.fabric_pre_unlink = tcm_loop_port_unlink,
|
||||
.tfc_wwn_attrs = tcm_loop_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = tcm_loop_tpg_attrs,
|
||||
.tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs,
|
||||
};
|
||||
|
||||
static int __init tcm_loop_fabric_init(void)
|
||||
{
|
||||
@ -1482,7 +1450,7 @@ static int __init tcm_loop_fabric_init(void)
|
||||
if (ret)
|
||||
goto out_destroy_cache;
|
||||
|
||||
ret = tcm_loop_register_configfs();
|
||||
ret = target_register_template(&loop_ops);
|
||||
if (ret)
|
||||
goto out_release_core_bus;
|
||||
|
||||
@ -1500,7 +1468,7 @@ out:
|
||||
|
||||
static void __exit tcm_loop_fabric_exit(void)
|
||||
{
|
||||
tcm_loop_deregister_configfs();
|
||||
target_unregister_template(&loop_ops);
|
||||
tcm_loop_release_core_bus();
|
||||
kmem_cache_destroy(tcm_loop_cmd_cache);
|
||||
destroy_workqueue(tcm_loop_workqueue);
|
||||
|
@ -43,6 +43,7 @@ struct tcm_loop_nacl {
|
||||
struct tcm_loop_tpg {
|
||||
unsigned short tl_tpgt;
|
||||
unsigned short tl_transport_status;
|
||||
enum target_prot_type tl_fabric_prot_type;
|
||||
atomic_t tl_tpg_port_count;
|
||||
struct se_portal_group tl_se_tpg;
|
||||
struct tcm_loop_hba *tl_hba;
|
||||
|
@ -42,8 +42,7 @@
|
||||
|
||||
#include "sbp_target.h"
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
static struct target_fabric_configfs *sbp_fabric_configfs;
|
||||
static const struct target_core_fabric_ops sbp_ops;
|
||||
|
||||
/* FireWire address region for management and command block address handlers */
|
||||
static const struct fw_address_region sbp_register_region = {
|
||||
@ -2215,8 +2214,7 @@ static struct se_portal_group *sbp_make_tpg(
|
||||
goto out_free_tpg;
|
||||
}
|
||||
|
||||
ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
|
||||
&tpg->se_tpg, (void *)tpg,
|
||||
ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg,
|
||||
TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0)
|
||||
goto out_unreg_mgt_agt;
|
||||
@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct target_core_fabric_ops sbp_ops = {
|
||||
static const struct target_core_fabric_ops sbp_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "sbp",
|
||||
.get_fabric_name = sbp_get_fabric_name,
|
||||
.get_fabric_proto_ident = sbp_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = sbp_get_fabric_wwn,
|
||||
@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = sbp_make_nodeacl,
|
||||
.fabric_drop_nodeacl = sbp_drop_nodeacl,
|
||||
};
|
||||
|
||||
static int sbp_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("target_fabric_configfs_init() failed\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
|
||||
fabric->tf_ops = sbp_ops;
|
||||
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() failed for SBP\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sbp_fabric_configfs = fabric;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void sbp_deregister_configfs(void)
|
||||
{
|
||||
if (!sbp_fabric_configfs)
|
||||
return;
|
||||
|
||||
target_fabric_configfs_deregister(sbp_fabric_configfs);
|
||||
sbp_fabric_configfs = NULL;
|
||||
.tfc_wwn_attrs = sbp_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = sbp_tpg_base_attrs,
|
||||
.tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs,
|
||||
};
|
||||
|
||||
static int __init sbp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sbp_register_configfs();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return target_register_template(&sbp_ops);
|
||||
};
|
||||
|
||||
static void __exit sbp_exit(void)
|
||||
{
|
||||
sbp_deregister_configfs();
|
||||
target_unregister_template(&sbp_ops);
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("FireWire SBP fabric driver");
|
||||
|
@ -142,8 +142,8 @@ static struct config_group *target_core_register_fabric(
|
||||
|
||||
tf = target_core_get_fabric(name);
|
||||
if (!tf) {
|
||||
pr_err("target_core_register_fabric() trying autoload for %s\n",
|
||||
name);
|
||||
pr_debug("target_core_register_fabric() trying autoload for %s\n",
|
||||
name);
|
||||
|
||||
/*
|
||||
* Below are some hardcoded request_module() calls to automatically
|
||||
@ -165,8 +165,8 @@ static struct config_group *target_core_register_fabric(
|
||||
*/
|
||||
ret = request_module("iscsi_target_mod");
|
||||
if (ret < 0) {
|
||||
pr_err("request_module() failed for"
|
||||
" iscsi_target_mod.ko: %d\n", ret);
|
||||
pr_debug("request_module() failed for"
|
||||
" iscsi_target_mod.ko: %d\n", ret);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
} else if (!strncmp(name, "loopback", 8)) {
|
||||
@ -178,8 +178,8 @@ static struct config_group *target_core_register_fabric(
|
||||
*/
|
||||
ret = request_module("tcm_loop");
|
||||
if (ret < 0) {
|
||||
pr_err("request_module() failed for"
|
||||
" tcm_loop.ko: %d\n", ret);
|
||||
pr_debug("request_module() failed for"
|
||||
" tcm_loop.ko: %d\n", ret);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
}
|
||||
@ -188,8 +188,8 @@ static struct config_group *target_core_register_fabric(
|
||||
}
|
||||
|
||||
if (!tf) {
|
||||
pr_err("target_core_get_fabric() failed for %s\n",
|
||||
name);
|
||||
pr_debug("target_core_get_fabric() failed for %s\n",
|
||||
name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:"
|
||||
@ -300,81 +300,17 @@ struct configfs_subsystem *target_core_subsystem[] = {
|
||||
// Start functions called by external Target Fabrics Modules
|
||||
//############################################################################*/
|
||||
|
||||
/*
|
||||
* First function called by fabric modules to:
|
||||
*
|
||||
* 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer.
|
||||
* 2) Add struct target_fabric_configfs to g_tf_list
|
||||
* 3) Return struct target_fabric_configfs to fabric module to be passed
|
||||
* into target_fabric_configfs_register().
|
||||
*/
|
||||
struct target_fabric_configfs *target_fabric_configfs_init(
|
||||
struct module *fabric_mod,
|
||||
const char *name)
|
||||
static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo)
|
||||
{
|
||||
struct target_fabric_configfs *tf;
|
||||
|
||||
if (!(name)) {
|
||||
pr_err("Unable to locate passed fabric name\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (!tfo->name) {
|
||||
pr_err("Missing tfo->name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) {
|
||||
if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) {
|
||||
pr_err("Passed name: %s exceeds TARGET_FABRIC"
|
||||
"_NAME_SIZE\n", name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
"_NAME_SIZE\n", tfo->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
|
||||
if (!tf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&tf->tf_list);
|
||||
atomic_set(&tf->tf_access_cnt, 0);
|
||||
/*
|
||||
* Setup the default generic struct config_item_type's (cits) in
|
||||
* struct target_fabric_configfs->tf_cit_tmpl
|
||||
*/
|
||||
tf->tf_module = fabric_mod;
|
||||
target_fabric_setup_cits(tf);
|
||||
|
||||
tf->tf_subsys = target_core_subsystem[0];
|
||||
snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name);
|
||||
|
||||
mutex_lock(&g_tf_lock);
|
||||
list_add_tail(&tf->tf_list, &g_tf_list);
|
||||
mutex_unlock(&g_tf_lock);
|
||||
|
||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>"
|
||||
">>>>>>>>>>>>>>\n");
|
||||
pr_debug("Initialized struct target_fabric_configfs: %p for"
|
||||
" %s\n", tf, tf->tf_name);
|
||||
return tf;
|
||||
}
|
||||
EXPORT_SYMBOL(target_fabric_configfs_init);
|
||||
|
||||
/*
|
||||
* Called by fabric plugins after FAILED target_fabric_configfs_register() call.
|
||||
*/
|
||||
void target_fabric_configfs_free(
|
||||
struct target_fabric_configfs *tf)
|
||||
{
|
||||
mutex_lock(&g_tf_lock);
|
||||
list_del(&tf->tf_list);
|
||||
mutex_unlock(&g_tf_lock);
|
||||
|
||||
kfree(tf);
|
||||
}
|
||||
EXPORT_SYMBOL(target_fabric_configfs_free);
|
||||
|
||||
/*
|
||||
* Perform a sanity check of the passed tf->tf_ops before completing
|
||||
* TCM fabric module registration.
|
||||
*/
|
||||
static int target_fabric_tf_ops_check(
|
||||
struct target_fabric_configfs *tf)
|
||||
{
|
||||
struct target_core_fabric_ops *tfo = &tf->tf_ops;
|
||||
|
||||
if (!tfo->get_fabric_name) {
|
||||
pr_err("Missing tfo->get_fabric_name()\n");
|
||||
return -EINVAL;
|
||||
@ -508,77 +444,59 @@ static int target_fabric_tf_ops_check(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called 2nd from fabric module with returned parameter of
|
||||
* struct target_fabric_configfs * from target_fabric_configfs_init().
|
||||
*
|
||||
* Upon a successful registration, the new fabric's struct config_item is
|
||||
* return. Also, a pointer to this struct is set in the passed
|
||||
* struct target_fabric_configfs.
|
||||
*/
|
||||
int target_fabric_configfs_register(
|
||||
struct target_fabric_configfs *tf)
|
||||
int target_register_template(const struct target_core_fabric_ops *fo)
|
||||
{
|
||||
struct target_fabric_configfs *tf;
|
||||
int ret;
|
||||
|
||||
if (!tf) {
|
||||
pr_err("Unable to locate target_fabric_configfs"
|
||||
" pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!tf->tf_subsys) {
|
||||
pr_err("Unable to target struct config_subsystem"
|
||||
" pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = target_fabric_tf_ops_check(tf);
|
||||
if (ret < 0)
|
||||
ret = target_fabric_tf_ops_check(fo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
|
||||
">>>>>>>>>>\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(target_fabric_configfs_register);
|
||||
|
||||
void target_fabric_configfs_deregister(
|
||||
struct target_fabric_configfs *tf)
|
||||
{
|
||||
struct configfs_subsystem *su;
|
||||
|
||||
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
|
||||
if (!tf) {
|
||||
pr_err("Unable to locate passed target_fabric_"
|
||||
"configfs\n");
|
||||
return;
|
||||
pr_err("%s: could not allocate memory!\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
su = tf->tf_subsys;
|
||||
if (!su) {
|
||||
pr_err("Unable to locate passed tf->tf_subsys"
|
||||
" pointer\n");
|
||||
return;
|
||||
}
|
||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
|
||||
">>>>>>>>>>>>\n");
|
||||
|
||||
INIT_LIST_HEAD(&tf->tf_list);
|
||||
atomic_set(&tf->tf_access_cnt, 0);
|
||||
|
||||
/*
|
||||
* Setup the default generic struct config_item_type's (cits) in
|
||||
* struct target_fabric_configfs->tf_cit_tmpl
|
||||
*/
|
||||
tf->tf_module = fo->module;
|
||||
tf->tf_subsys = target_core_subsystem[0];
|
||||
snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name);
|
||||
|
||||
tf->tf_ops = *fo;
|
||||
target_fabric_setup_cits(tf);
|
||||
|
||||
mutex_lock(&g_tf_lock);
|
||||
if (atomic_read(&tf->tf_access_cnt)) {
|
||||
mutex_unlock(&g_tf_lock);
|
||||
pr_err("Non zero tf->tf_access_cnt for fabric %s\n",
|
||||
tf->tf_name);
|
||||
BUG();
|
||||
}
|
||||
list_del(&tf->tf_list);
|
||||
list_add_tail(&tf->tf_list, &g_tf_list);
|
||||
mutex_unlock(&g_tf_lock);
|
||||
|
||||
pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
|
||||
" %s\n", tf->tf_name);
|
||||
tf->tf_module = NULL;
|
||||
tf->tf_subsys = NULL;
|
||||
kfree(tf);
|
||||
|
||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
|
||||
">>>>>\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(target_fabric_configfs_deregister);
|
||||
EXPORT_SYMBOL(target_register_template);
|
||||
|
||||
void target_unregister_template(const struct target_core_fabric_ops *fo)
|
||||
{
|
||||
struct target_fabric_configfs *t;
|
||||
|
||||
mutex_lock(&g_tf_lock);
|
||||
list_for_each_entry(t, &g_tf_list, tf_list) {
|
||||
if (!strcmp(t->tf_name, fo->name)) {
|
||||
BUG_ON(atomic_read(&t->tf_access_cnt));
|
||||
list_del(&t->tf_list);
|
||||
kfree(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&g_tf_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(target_unregister_template);
|
||||
|
||||
/*##############################################################################
|
||||
// Stop functions called by external Target Fabrics Modules
|
||||
@ -945,7 +863,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
|
||||
struct se_lun *lun;
|
||||
struct se_portal_group *se_tpg;
|
||||
struct t10_pr_registration *pr_reg;
|
||||
struct target_core_fabric_ops *tfo;
|
||||
const struct target_core_fabric_ops *tfo;
|
||||
ssize_t len = 0;
|
||||
|
||||
spin_lock(&dev->dev_reservation_lock);
|
||||
@ -979,7 +897,7 @@ SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
|
||||
static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
|
||||
struct se_device *dev, char *page)
|
||||
{
|
||||
struct target_core_fabric_ops *tfo;
|
||||
const struct target_core_fabric_ops *tfo;
|
||||
struct t10_pr_registration *pr_reg;
|
||||
unsigned char buf[384];
|
||||
char i_buf[PR_REG_ISID_ID_LEN];
|
||||
|
@ -56,6 +56,20 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf)
|
||||
pr_debug("Setup generic %s\n", __stringify(_name)); \
|
||||
}
|
||||
|
||||
#define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \
|
||||
static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
|
||||
{ \
|
||||
struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \
|
||||
struct config_item_type *cit = &tfc->tfc_##_name##_cit; \
|
||||
struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \
|
||||
\
|
||||
cit->ct_item_ops = _item_ops; \
|
||||
cit->ct_group_ops = _group_ops; \
|
||||
cit->ct_attrs = attrs; \
|
||||
cit->ct_owner = tf->tf_module; \
|
||||
pr_debug("Setup generic %s\n", __stringify(_name)); \
|
||||
}
|
||||
|
||||
/* Start of tfc_tpg_mappedlun_cit */
|
||||
|
||||
static int target_fabric_mappedlun_link(
|
||||
@ -278,7 +292,7 @@ static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = {
|
||||
.store_attribute = target_fabric_nacl_attrib_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_nacl_attrib_cit */
|
||||
|
||||
@ -291,7 +305,7 @@ static struct configfs_item_operations target_fabric_nacl_auth_item_ops = {
|
||||
.store_attribute = target_fabric_nacl_auth_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_nacl_auth_cit */
|
||||
|
||||
@ -304,7 +318,7 @@ static struct configfs_item_operations target_fabric_nacl_param_item_ops = {
|
||||
.store_attribute = target_fabric_nacl_param_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_nacl_param_cit */
|
||||
|
||||
@ -461,8 +475,8 @@ static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
|
||||
.drop_item = target_fabric_drop_mappedlun,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
|
||||
&target_fabric_nacl_base_group_ops, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
|
||||
&target_fabric_nacl_base_group_ops);
|
||||
|
||||
/* End of tfc_tpg_nacl_base_cit */
|
||||
|
||||
@ -570,7 +584,7 @@ static struct configfs_item_operations target_fabric_np_base_item_ops = {
|
||||
.store_attribute = target_fabric_np_base_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_np_base_cit */
|
||||
|
||||
@ -966,7 +980,7 @@ static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = {
|
||||
.store_attribute = target_fabric_tpg_attrib_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_attrib_cit */
|
||||
|
||||
@ -979,7 +993,7 @@ static struct configfs_item_operations target_fabric_tpg_auth_item_ops = {
|
||||
.store_attribute = target_fabric_tpg_auth_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_attrib_cit */
|
||||
|
||||
@ -992,7 +1006,7 @@ static struct configfs_item_operations target_fabric_tpg_param_item_ops = {
|
||||
.store_attribute = target_fabric_tpg_param_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_param_cit */
|
||||
|
||||
@ -1018,7 +1032,7 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
|
||||
.store_attribute = target_fabric_tpg_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL);
|
||||
|
||||
/* End of tfc_tpg_base_cit */
|
||||
|
||||
@ -1192,7 +1206,7 @@ static struct configfs_item_operations target_fabric_wwn_item_ops = {
|
||||
.store_attribute = target_fabric_wwn_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL);
|
||||
TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops);
|
||||
|
||||
/* End of tfc_wwn_cit */
|
||||
|
||||
@ -1206,7 +1220,7 @@ static struct configfs_item_operations target_fabric_discovery_item_ops = {
|
||||
.store_attribute = target_fabric_discovery_attr_store,
|
||||
};
|
||||
|
||||
TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL);
|
||||
TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL);
|
||||
|
||||
/* End of tfc_discovery_cit */
|
||||
|
||||
|
@ -264,40 +264,32 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
struct fd_dev *dev = FD_DEV(se_dev);
|
||||
struct file *prot_fd = dev->fd_prot_file;
|
||||
struct scatterlist *sg;
|
||||
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
|
||||
unsigned char *buf;
|
||||
u32 prot_size, len, size;
|
||||
int rc, ret = 1, i;
|
||||
u32 prot_size;
|
||||
int rc, ret = 1;
|
||||
|
||||
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
|
||||
se_dev->prot_length;
|
||||
|
||||
if (!is_write) {
|
||||
fd_prot->prot_buf = vzalloc(prot_size);
|
||||
fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL);
|
||||
if (!fd_prot->prot_buf) {
|
||||
pr_err("Unable to allocate fd_prot->prot_buf\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf = fd_prot->prot_buf;
|
||||
|
||||
fd_prot->prot_sg_nents = cmd->t_prot_nents;
|
||||
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
|
||||
fd_prot->prot_sg_nents, GFP_KERNEL);
|
||||
fd_prot->prot_sg_nents = 1;
|
||||
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist),
|
||||
GFP_KERNEL);
|
||||
if (!fd_prot->prot_sg) {
|
||||
pr_err("Unable to allocate fd_prot->prot_sg\n");
|
||||
vfree(fd_prot->prot_buf);
|
||||
kfree(fd_prot->prot_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
size = prot_size;
|
||||
|
||||
for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
|
||||
|
||||
len = min_t(u32, PAGE_SIZE, size);
|
||||
sg_set_buf(sg, buf, len);
|
||||
size -= len;
|
||||
buf += len;
|
||||
}
|
||||
sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents);
|
||||
sg_set_buf(fd_prot->prot_sg, buf, prot_size);
|
||||
}
|
||||
|
||||
if (is_write) {
|
||||
@ -318,7 +310,7 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
|
||||
|
||||
if (is_write || ret < 0) {
|
||||
kfree(fd_prot->prot_sg);
|
||||
vfree(fd_prot->prot_buf);
|
||||
kfree(fd_prot->prot_buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -331,36 +323,33 @@ static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,
|
||||
struct fd_dev *dev = FD_DEV(se_dev);
|
||||
struct file *fd = dev->fd_file;
|
||||
struct scatterlist *sg;
|
||||
struct iovec *iov;
|
||||
mm_segment_t old_fs;
|
||||
struct iov_iter iter;
|
||||
struct bio_vec *bvec;
|
||||
ssize_t len = 0;
|
||||
loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);
|
||||
int ret = 0, i;
|
||||
|
||||
iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
|
||||
if (!iov) {
|
||||
bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);
|
||||
if (!bvec) {
|
||||
pr_err("Unable to allocate fd_do_readv iov[]\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for_each_sg(sgl, sg, sgl_nents, i) {
|
||||
iov[i].iov_len = sg->length;
|
||||
iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
|
||||
bvec[i].bv_page = sg_page(sg);
|
||||
bvec[i].bv_len = sg->length;
|
||||
bvec[i].bv_offset = sg->offset;
|
||||
|
||||
len += sg->length;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
|
||||
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
|
||||
if (is_write)
|
||||
ret = vfs_writev(fd, &iov[0], sgl_nents, &pos);
|
||||
ret = vfs_iter_write(fd, &iter, &pos);
|
||||
else
|
||||
ret = vfs_readv(fd, &iov[0], sgl_nents, &pos);
|
||||
ret = vfs_iter_read(fd, &iter, &pos);
|
||||
|
||||
set_fs(old_fs);
|
||||
|
||||
for_each_sg(sgl, sg, sgl_nents, i)
|
||||
kunmap(sg_page(sg));
|
||||
|
||||
kfree(iov);
|
||||
kfree(bvec);
|
||||
|
||||
if (is_write) {
|
||||
if (ret < 0 || ret != cmd->data_length) {
|
||||
@ -436,59 +425,17 @@ fd_execute_sync_cache(struct se_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg,
|
||||
unsigned int len)
|
||||
{
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
unsigned int block_size = se_dev->dev_attrib.block_size;
|
||||
unsigned int i = 0, end;
|
||||
unsigned char *buf, *p, *kmap_buf;
|
||||
|
||||
buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
pr_err("Unable to allocate fd_execute_write_same buf\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kmap_buf = kmap(sg_page(sg)) + sg->offset;
|
||||
if (!kmap_buf) {
|
||||
pr_err("kmap() failed in fd_setup_write_same\n");
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Fill local *buf to contain multiple WRITE_SAME blocks up to
|
||||
* min(len, PAGE_SIZE)
|
||||
*/
|
||||
p = buf;
|
||||
end = min_t(unsigned int, len, PAGE_SIZE);
|
||||
|
||||
while (i < end) {
|
||||
memcpy(p, kmap_buf, block_size);
|
||||
|
||||
i += block_size;
|
||||
p += block_size;
|
||||
}
|
||||
kunmap(sg_page(sg));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
fd_execute_write_same(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
struct fd_dev *fd_dev = FD_DEV(se_dev);
|
||||
struct file *f = fd_dev->fd_file;
|
||||
struct scatterlist *sg;
|
||||
struct iovec *iov;
|
||||
mm_segment_t old_fs;
|
||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
|
||||
unsigned int len, len_tmp, iov_num;
|
||||
int i, rc;
|
||||
unsigned char *buf;
|
||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||
struct iov_iter iter;
|
||||
struct bio_vec *bvec;
|
||||
unsigned int len = 0, i;
|
||||
ssize_t ret;
|
||||
|
||||
if (!nolb) {
|
||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||
@ -499,49 +446,35 @@ fd_execute_write_same(struct se_cmd *cmd)
|
||||
" backends not supported\n");
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
sg = &cmd->t_data_sg[0];
|
||||
|
||||
if (cmd->t_data_nents > 1 ||
|
||||
sg->length != cmd->se_dev->dev_attrib.block_size) {
|
||||
cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
|
||||
pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
|
||||
" block_size: %u\n", cmd->t_data_nents, sg->length,
|
||||
" block_size: %u\n",
|
||||
cmd->t_data_nents,
|
||||
cmd->t_data_sg[0].length,
|
||||
cmd->se_dev->dev_attrib.block_size);
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
}
|
||||
|
||||
len = len_tmp = nolb * se_dev->dev_attrib.block_size;
|
||||
iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
|
||||
|
||||
buf = fd_setup_write_same_buf(cmd, sg, len);
|
||||
if (!buf)
|
||||
bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);
|
||||
if (!bvec)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
iov = vzalloc(sizeof(struct iovec) * iov_num);
|
||||
if (!iov) {
|
||||
pr_err("Unable to allocate fd_execute_write_same iovecs\n");
|
||||
kfree(buf);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
/*
|
||||
* Map the single fabric received scatterlist block now populated
|
||||
* in *buf into each iovec for I/O submission.
|
||||
*/
|
||||
for (i = 0; i < iov_num; i++) {
|
||||
iov[i].iov_base = buf;
|
||||
iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE);
|
||||
len_tmp -= iov[i].iov_len;
|
||||
for (i = 0; i < nolb; i++) {
|
||||
bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]);
|
||||
bvec[i].bv_len = cmd->t_data_sg[0].length;
|
||||
bvec[i].bv_offset = cmd->t_data_sg[0].offset;
|
||||
|
||||
len += se_dev->dev_attrib.block_size;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
rc = vfs_writev(f, &iov[0], iov_num, &pos);
|
||||
set_fs(old_fs);
|
||||
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
|
||||
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos);
|
||||
|
||||
vfree(iov);
|
||||
kfree(buf);
|
||||
|
||||
if (rc < 0 || rc != len) {
|
||||
pr_err("vfs_writev() returned %d for write same\n", rc);
|
||||
kfree(bvec);
|
||||
if (ret < 0 || ret != len) {
|
||||
pr_err("vfs_iter_write() returned %zd for write same\n", ret);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
@ -549,6 +482,56 @@ fd_execute_write_same(struct se_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb,
|
||||
void *buf, size_t bufsize)
|
||||
{
|
||||
struct fd_dev *fd_dev = FD_DEV(se_dev);
|
||||
struct file *prot_fd = fd_dev->fd_prot_file;
|
||||
sector_t prot_length, prot;
|
||||
loff_t pos = lba * se_dev->prot_length;
|
||||
|
||||
if (!prot_fd) {
|
||||
pr_err("Unable to locate fd_dev->fd_prot_file\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
prot_length = nolb * se_dev->prot_length;
|
||||
|
||||
for (prot = 0; prot < prot_length;) {
|
||||
sector_t len = min_t(sector_t, bufsize, prot_length - prot);
|
||||
ssize_t ret = kernel_write(prot_fd, buf, len, pos + prot);
|
||||
|
||||
if (ret != len) {
|
||||
pr_err("vfs_write to prot file failed: %zd\n", ret);
|
||||
return ret < 0 ? ret : -ENODEV;
|
||||
}
|
||||
prot += ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
|
||||
{
|
||||
void *buf;
|
||||
int rc;
|
||||
|
||||
buf = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf) {
|
||||
pr_err("Unable to allocate FILEIO prot buf\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(buf, 0xff, PAGE_SIZE);
|
||||
|
||||
rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE);
|
||||
|
||||
free_page((unsigned long)buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
|
||||
{
|
||||
@ -556,6 +539,12 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int ret;
|
||||
|
||||
if (cmd->se_dev->dev_attrib.pi_prot_type) {
|
||||
ret = fd_do_prot_unmap(cmd, lba, nolb);
|
||||
if (ret)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
if (S_ISBLK(inode->i_mode)) {
|
||||
/* The backend is block device, use discard */
|
||||
struct block_device *bdev = inode->i_bdev;
|
||||
@ -595,7 +584,7 @@ fd_execute_write_same_unmap(struct se_cmd *cmd)
|
||||
struct file *file = fd_dev->fd_file;
|
||||
sector_t lba = cmd->t_task_lba;
|
||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||
int ret;
|
||||
sense_reason_t ret;
|
||||
|
||||
if (!nolb) {
|
||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||
@ -643,7 +632,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
if (data_direction == DMA_FROM_DEVICE) {
|
||||
memset(&fd_prot, 0, sizeof(struct fd_prot));
|
||||
|
||||
if (cmd->prot_type) {
|
||||
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||
ret = fd_do_prot_rw(cmd, &fd_prot, false);
|
||||
if (ret < 0)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
@ -651,23 +640,23 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
|
||||
ret = fd_do_rw(cmd, sgl, sgl_nents, 0);
|
||||
|
||||
if (ret > 0 && cmd->prot_type) {
|
||||
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
|
||||
|
||||
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
|
||||
0, fd_prot.prot_sg, 0);
|
||||
if (rc) {
|
||||
kfree(fd_prot.prot_sg);
|
||||
vfree(fd_prot.prot_buf);
|
||||
kfree(fd_prot.prot_buf);
|
||||
return rc;
|
||||
}
|
||||
kfree(fd_prot.prot_sg);
|
||||
vfree(fd_prot.prot_buf);
|
||||
kfree(fd_prot.prot_buf);
|
||||
}
|
||||
} else {
|
||||
memset(&fd_prot, 0, sizeof(struct fd_prot));
|
||||
|
||||
if (cmd->prot_type) {
|
||||
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
|
||||
|
||||
ret = fd_do_prot_rw(cmd, &fd_prot, false);
|
||||
@ -678,7 +667,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
0, fd_prot.prot_sg, 0);
|
||||
if (rc) {
|
||||
kfree(fd_prot.prot_sg);
|
||||
vfree(fd_prot.prot_buf);
|
||||
kfree(fd_prot.prot_buf);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@ -705,7 +694,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
|
||||
}
|
||||
|
||||
if (ret > 0 && cmd->prot_type) {
|
||||
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||
ret = fd_do_prot_rw(cmd, &fd_prot, true);
|
||||
if (ret < 0)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
@ -714,7 +703,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
|
||||
if (ret < 0) {
|
||||
kfree(fd_prot.prot_sg);
|
||||
vfree(fd_prot.prot_buf);
|
||||
kfree(fd_prot.prot_buf);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
@ -878,48 +867,28 @@ static int fd_init_prot(struct se_device *dev)
|
||||
|
||||
static int fd_format_prot(struct se_device *dev)
|
||||
{
|
||||
struct fd_dev *fd_dev = FD_DEV(dev);
|
||||
struct file *prot_fd = fd_dev->fd_prot_file;
|
||||
sector_t prot_length, prot;
|
||||
unsigned char *buf;
|
||||
loff_t pos = 0;
|
||||
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
|
||||
int rc, ret = 0, size, len;
|
||||
int ret;
|
||||
|
||||
if (!dev->dev_attrib.pi_prot_type) {
|
||||
pr_err("Unable to format_prot while pi_prot_type == 0\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!prot_fd) {
|
||||
pr_err("Unable to locate fd_dev->fd_prot_file\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
buf = vzalloc(unit_size);
|
||||
if (!buf) {
|
||||
pr_err("Unable to allocate FILEIO prot buf\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
|
||||
size = prot_length;
|
||||
|
||||
pr_debug("Using FILEIO prot_length: %llu\n",
|
||||
(unsigned long long)prot_length);
|
||||
(unsigned long long)(dev->transport->get_blocks(dev) + 1) *
|
||||
dev->prot_length);
|
||||
|
||||
memset(buf, 0xff, unit_size);
|
||||
for (prot = 0; prot < prot_length; prot += unit_size) {
|
||||
len = min(unit_size, size);
|
||||
rc = kernel_write(prot_fd, buf, len, pos);
|
||||
if (rc != len) {
|
||||
pr_err("vfs_write to prot file failed: %d\n", rc);
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
pos += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
out:
|
||||
ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1,
|
||||
buf, unit_size);
|
||||
vfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ iblock_execute_write_same_unmap(struct se_cmd *cmd)
|
||||
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
|
||||
sector_t lba = cmd->t_task_lba;
|
||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||
int ret;
|
||||
sense_reason_t ret;
|
||||
|
||||
ret = iblock_do_unmap(cmd, bdev, lba, nolb);
|
||||
if (ret)
|
||||
@ -774,7 +774,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
sg_num--;
|
||||
}
|
||||
|
||||
if (cmd->prot_type) {
|
||||
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||
int rc = iblock_alloc_bip(cmd, bio_start);
|
||||
if (rc)
|
||||
goto fail_put_bios;
|
||||
|
@ -4,7 +4,13 @@
|
||||
/* target_core_alua.c */
|
||||
extern struct t10_alua_lu_gp *default_lu_gp;
|
||||
|
||||
/* target_core_configfs.c */
|
||||
extern struct configfs_subsystem *target_core_subsystem[];
|
||||
|
||||
/* target_core_device.c */
|
||||
extern struct mutex g_device_mutex;
|
||||
extern struct list_head g_device_list;
|
||||
|
||||
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
|
||||
int core_free_device_list_for_node(struct se_node_acl *,
|
||||
struct se_portal_group *);
|
||||
|
@ -78,6 +78,22 @@ enum preempt_type {
|
||||
static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
|
||||
struct t10_pr_registration *, int, int);
|
||||
|
||||
static int is_reservation_holder(
|
||||
struct t10_pr_registration *pr_res_holder,
|
||||
struct t10_pr_registration *pr_reg)
|
||||
{
|
||||
int pr_res_type;
|
||||
|
||||
if (pr_res_holder) {
|
||||
pr_res_type = pr_res_holder->pr_res_type;
|
||||
|
||||
return pr_res_holder == pr_reg ||
|
||||
pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
|
||||
pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
target_scsi2_reservation_check(struct se_cmd *cmd)
|
||||
{
|
||||
@ -664,7 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
|
||||
struct se_dev_entry *deve_tmp;
|
||||
struct se_node_acl *nacl_tmp;
|
||||
struct se_port *port, *port_tmp;
|
||||
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||
int ret;
|
||||
/*
|
||||
@ -963,7 +979,7 @@ int core_scsi3_check_aptpl_registration(
|
||||
}
|
||||
|
||||
static void __core_scsi3_dump_registration(
|
||||
struct target_core_fabric_ops *tfo,
|
||||
const struct target_core_fabric_ops *tfo,
|
||||
struct se_device *dev,
|
||||
struct se_node_acl *nacl,
|
||||
struct t10_pr_registration *pr_reg,
|
||||
@ -1004,7 +1020,7 @@ static void __core_scsi3_add_registration(
|
||||
enum register_type register_type,
|
||||
int register_move)
|
||||
{
|
||||
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||
|
||||
@ -1220,8 +1236,10 @@ static void __core_scsi3_free_registration(
|
||||
struct t10_pr_registration *pr_reg,
|
||||
struct list_head *preempt_and_abort_list,
|
||||
int dec_holders)
|
||||
__releases(&pr_tmpl->registration_lock)
|
||||
__acquires(&pr_tmpl->registration_lock)
|
||||
{
|
||||
struct target_core_fabric_ops *tfo =
|
||||
const struct target_core_fabric_ops *tfo =
|
||||
pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
|
||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||
char i_buf[PR_REG_ISID_ID_LEN];
|
||||
@ -1445,7 +1463,7 @@ core_scsi3_decode_spec_i_port(
|
||||
struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||
LIST_HEAD(tid_dest_list);
|
||||
struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
|
||||
struct target_core_fabric_ops *tmp_tf_ops;
|
||||
const struct target_core_fabric_ops *tmp_tf_ops;
|
||||
unsigned char *buf;
|
||||
unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
|
||||
char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
|
||||
@ -2287,7 +2305,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
|
||||
spin_lock(&dev->dev_reservation_lock);
|
||||
pr_res_holder = dev->dev_pr_res_holder;
|
||||
if (pr_res_holder) {
|
||||
int pr_res_type = pr_res_holder->pr_res_type;
|
||||
/*
|
||||
* From spc4r17 Section 5.7.9: Reserving:
|
||||
*
|
||||
@ -2298,9 +2315,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
|
||||
* the logical unit, then the command shall be completed with
|
||||
* RESERVATION CONFLICT status.
|
||||
*/
|
||||
if ((pr_res_holder != pr_reg) &&
|
||||
(pr_res_type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
|
||||
(pr_res_type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
|
||||
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
|
||||
struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
|
||||
pr_err("SPC-3 PR: Attempted RESERVE from"
|
||||
" [%s]: %s while reservation already held by"
|
||||
@ -2409,7 +2424,7 @@ static void __core_scsi3_complete_pro_release(
|
||||
int explicit,
|
||||
int unreg)
|
||||
{
|
||||
struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
|
||||
const struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
|
||||
char i_buf[PR_REG_ISID_ID_LEN];
|
||||
int pr_res_type = 0, pr_res_scope = 0;
|
||||
|
||||
@ -2477,7 +2492,6 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
|
||||
struct se_lun *se_lun = cmd->se_lun;
|
||||
struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
|
||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||
int all_reg = 0;
|
||||
sense_reason_t ret = 0;
|
||||
|
||||
if (!se_sess || !se_lun) {
|
||||
@ -2514,13 +2528,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
|
||||
spin_unlock(&dev->dev_reservation_lock);
|
||||
goto out_put_pr_reg;
|
||||
}
|
||||
if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
|
||||
(pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
|
||||
all_reg = 1;
|
||||
|
||||
if ((all_reg == 0) && (pr_res_holder != pr_reg)) {
|
||||
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
|
||||
/*
|
||||
* Non 'All Registrants' PR Type cases..
|
||||
* Release request from a registered I_T nexus that is not a
|
||||
* persistent reservation holder. return GOOD status.
|
||||
*/
|
||||
@ -2726,7 +2736,7 @@ static void __core_scsi3_complete_pro_preempt(
|
||||
enum preempt_type preempt_type)
|
||||
{
|
||||
struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
|
||||
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
|
||||
char i_buf[PR_REG_ISID_ID_LEN];
|
||||
|
||||
memset(i_buf, 0, PR_REG_ISID_ID_LEN);
|
||||
@ -3111,7 +3121,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
|
||||
struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
|
||||
struct se_port *se_port;
|
||||
struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
|
||||
struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
|
||||
const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
|
||||
struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
|
||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||
unsigned char *buf;
|
||||
@ -3375,7 +3385,7 @@ after_iport_check:
|
||||
* From spc4r17 section 5.7.8 Table 50 --
|
||||
* Register behaviors for a REGISTER AND MOVE service action
|
||||
*/
|
||||
if (pr_res_holder != pr_reg) {
|
||||
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
|
||||
pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
|
||||
" Nexus is not reservation holder\n");
|
||||
spin_unlock(&dev->dev_reservation_lock);
|
||||
|
@ -139,10 +139,22 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
|
||||
unsigned char *p;
|
||||
|
||||
while (total_sg_needed) {
|
||||
unsigned int chain_entry = 0;
|
||||
|
||||
sg_per_table = (total_sg_needed > max_sg_per_table) ?
|
||||
max_sg_per_table : total_sg_needed;
|
||||
|
||||
sg = kzalloc(sg_per_table * sizeof(struct scatterlist),
|
||||
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
|
||||
|
||||
/*
|
||||
* Reserve extra element for chain entry
|
||||
*/
|
||||
if (sg_per_table < total_sg_needed)
|
||||
chain_entry = 1;
|
||||
|
||||
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
|
||||
|
||||
sg = kcalloc(sg_per_table + chain_entry, sizeof(*sg),
|
||||
GFP_KERNEL);
|
||||
if (!sg) {
|
||||
pr_err("Unable to allocate scatterlist array"
|
||||
@ -150,7 +162,16 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sg_init_table(sg, sg_per_table);
|
||||
sg_init_table(sg, sg_per_table + chain_entry);
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
|
||||
|
||||
if (i > 0) {
|
||||
sg_chain(sg_table[i - 1].sg_table,
|
||||
max_sg_per_table + 1, sg);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
|
||||
|
||||
sg_table[i].sg_table = sg;
|
||||
sg_table[i].rd_sg_count = sg_per_table;
|
||||
@ -382,6 +403,76 @@ static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef sense_reason_t (*dif_verify)(struct se_cmd *, sector_t, unsigned int,
|
||||
unsigned int, struct scatterlist *, int);
|
||||
|
||||
static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify)
|
||||
{
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
struct rd_dev *dev = RD_DEV(se_dev);
|
||||
struct rd_dev_sg_table *prot_table;
|
||||
bool need_to_release = false;
|
||||
struct scatterlist *prot_sg;
|
||||
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
|
||||
u32 prot_offset, prot_page;
|
||||
u32 prot_npages __maybe_unused;
|
||||
u64 tmp;
|
||||
sense_reason_t rc = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
tmp = cmd->t_task_lba * se_dev->prot_length;
|
||||
prot_offset = do_div(tmp, PAGE_SIZE);
|
||||
prot_page = tmp;
|
||||
|
||||
prot_table = rd_get_prot_table(dev, prot_page);
|
||||
if (!prot_table)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
prot_sg = &prot_table->sg_table[prot_page -
|
||||
prot_table->page_start_offset];
|
||||
|
||||
#ifndef CONFIG_ARCH_HAS_SG_CHAIN
|
||||
|
||||
prot_npages = DIV_ROUND_UP(prot_offset + sectors * se_dev->prot_length,
|
||||
PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Allocate temporaly contiguous scatterlist entries if prot pages
|
||||
* straddles multiple scatterlist tables.
|
||||
*/
|
||||
if (prot_table->page_end_offset < prot_page + prot_npages - 1) {
|
||||
int i;
|
||||
|
||||
prot_sg = kcalloc(prot_npages, sizeof(*prot_sg), GFP_KERNEL);
|
||||
if (!prot_sg)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
need_to_release = true;
|
||||
sg_init_table(prot_sg, prot_npages);
|
||||
|
||||
for (i = 0; i < prot_npages; i++) {
|
||||
if (prot_page + i > prot_table->page_end_offset) {
|
||||
prot_table = rd_get_prot_table(dev,
|
||||
prot_page + i);
|
||||
if (!prot_table) {
|
||||
kfree(prot_sg);
|
||||
return rc;
|
||||
}
|
||||
sg_unmark_end(&prot_sg[i - 1]);
|
||||
}
|
||||
prot_sg[i] = prot_table->sg_table[prot_page + i -
|
||||
prot_table->page_start_offset];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_ARCH_HAS_SG_CHAIN */
|
||||
|
||||
rc = dif_verify(cmd, cmd->t_task_lba, sectors, 0, prot_sg, prot_offset);
|
||||
if (need_to_release)
|
||||
kfree(prot_sg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
enum dma_data_direction data_direction)
|
||||
@ -419,24 +510,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
|
||||
cmd->t_task_lba, rd_size, rd_page, rd_offset);
|
||||
|
||||
if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
|
||||
struct rd_dev_sg_table *prot_table;
|
||||
struct scatterlist *prot_sg;
|
||||
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
|
||||
u32 prot_offset, prot_page;
|
||||
|
||||
tmp = cmd->t_task_lba * se_dev->prot_length;
|
||||
prot_offset = do_div(tmp, PAGE_SIZE);
|
||||
prot_page = tmp;
|
||||
|
||||
prot_table = rd_get_prot_table(dev, prot_page);
|
||||
if (!prot_table)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
|
||||
|
||||
rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0,
|
||||
prot_sg, prot_offset);
|
||||
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
|
||||
data_direction == DMA_TO_DEVICE) {
|
||||
rc = rd_do_prot_rw(cmd, sbc_dif_verify_write);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@ -502,24 +578,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
}
|
||||
sg_miter_stop(&m);
|
||||
|
||||
if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
|
||||
struct rd_dev_sg_table *prot_table;
|
||||
struct scatterlist *prot_sg;
|
||||
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
|
||||
u32 prot_offset, prot_page;
|
||||
|
||||
tmp = cmd->t_task_lba * se_dev->prot_length;
|
||||
prot_offset = do_div(tmp, PAGE_SIZE);
|
||||
prot_page = tmp;
|
||||
|
||||
prot_table = rd_get_prot_table(dev, prot_page);
|
||||
if (!prot_table)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
|
||||
|
||||
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
|
||||
prot_sg, prot_offset);
|
||||
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
|
||||
data_direction == DMA_FROM_DEVICE) {
|
||||
rc = rd_do_prot_rw(cmd, sbc_dif_verify_read);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
@ -93,6 +93,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_session *sess = cmd->se_sess;
|
||||
int pi_prot_type = dev->dev_attrib.pi_prot_type;
|
||||
|
||||
unsigned char *rbuf;
|
||||
unsigned char buf[32];
|
||||
unsigned long long blocks = dev->transport->get_blocks(dev);
|
||||
@ -114,8 +116,15 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||
* Set P_TYPE and PROT_EN bits for DIF support
|
||||
*/
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
|
||||
/*
|
||||
* Only override a device's pi_prot_type if no T10-PI is
|
||||
* available, and sess_prot_type has been explicitly enabled.
|
||||
*/
|
||||
if (!pi_prot_type)
|
||||
pi_prot_type = sess->sess_prot_type;
|
||||
|
||||
if (pi_prot_type)
|
||||
buf[12] = (pi_prot_type - 1) << 1 | 0x1;
|
||||
}
|
||||
|
||||
if (dev->transport->get_lbppbe)
|
||||
@ -312,7 +321,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd)
|
||||
static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success)
|
||||
{
|
||||
unsigned char *buf, *addr;
|
||||
struct scatterlist *sg;
|
||||
@ -376,7 +385,7 @@ sbc_execute_rw(struct se_cmd *cmd)
|
||||
cmd->data_direction);
|
||||
}
|
||||
|
||||
static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
|
||||
static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
|
||||
@ -399,7 +408,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
|
||||
return TCM_NO_SENSE;
|
||||
}
|
||||
|
||||
static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
|
||||
static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct scatterlist *write_sg = NULL, *sg;
|
||||
@ -414,10 +423,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
|
||||
|
||||
/*
|
||||
* Handle early failure in transport_generic_request_failure(),
|
||||
* which will not have taken ->caw_mutex yet..
|
||||
* which will not have taken ->caw_sem yet..
|
||||
*/
|
||||
if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
|
||||
if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg))
|
||||
return TCM_NO_SENSE;
|
||||
/*
|
||||
* Handle special case for zero-length COMPARE_AND_WRITE
|
||||
*/
|
||||
if (!cmd->data_length)
|
||||
goto out;
|
||||
/*
|
||||
* Immediately exit + release dev->caw_sem if command has already
|
||||
* been failed with a non-zero SCSI status.
|
||||
@ -581,12 +595,13 @@ sbc_compare_and_write(struct se_cmd *cmd)
|
||||
}
|
||||
|
||||
static int
|
||||
sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
|
||||
sbc_set_prot_op_checks(u8 protect, bool fabric_prot, enum target_prot_type prot_type,
|
||||
bool is_write, struct se_cmd *cmd)
|
||||
{
|
||||
if (is_write) {
|
||||
cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS :
|
||||
TARGET_PROT_DOUT_INSERT;
|
||||
cmd->prot_op = fabric_prot ? TARGET_PROT_DOUT_STRIP :
|
||||
protect ? TARGET_PROT_DOUT_PASS :
|
||||
TARGET_PROT_DOUT_INSERT;
|
||||
switch (protect) {
|
||||
case 0x0:
|
||||
case 0x3:
|
||||
@ -610,8 +625,9 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
cmd->prot_op = protect ? TARGET_PROT_DIN_PASS :
|
||||
TARGET_PROT_DIN_STRIP;
|
||||
cmd->prot_op = fabric_prot ? TARGET_PROT_DIN_INSERT :
|
||||
protect ? TARGET_PROT_DIN_PASS :
|
||||
TARGET_PROT_DIN_STRIP;
|
||||
switch (protect) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
@ -644,11 +660,15 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
|
||||
u32 sectors, bool is_write)
|
||||
{
|
||||
u8 protect = cdb[1] >> 5;
|
||||
int sp_ops = cmd->se_sess->sup_prot_ops;
|
||||
int pi_prot_type = dev->dev_attrib.pi_prot_type;
|
||||
bool fabric_prot = false;
|
||||
|
||||
if (!cmd->t_prot_sg || !cmd->t_prot_nents) {
|
||||
if (protect && !dev->dev_attrib.pi_prot_type) {
|
||||
pr_err("CDB contains protect bit, but device does not"
|
||||
" advertise PROTECT=1 feature bit\n");
|
||||
if (unlikely(protect &&
|
||||
!dev->dev_attrib.pi_prot_type && !cmd->se_sess->sess_prot_type)) {
|
||||
pr_err("CDB contains protect bit, but device + fabric does"
|
||||
" not advertise PROTECT=1 feature bit\n");
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
}
|
||||
if (cmd->prot_pto)
|
||||
@ -669,15 +689,32 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
|
||||
cmd->reftag_seed = cmd->t_task_lba;
|
||||
break;
|
||||
case TARGET_DIF_TYPE0_PROT:
|
||||
/*
|
||||
* See if the fabric supports T10-PI, and the session has been
|
||||
* configured to allow export PROTECT=1 feature bit with backend
|
||||
* devices that don't support T10-PI.
|
||||
*/
|
||||
fabric_prot = is_write ?
|
||||
!!(sp_ops & (TARGET_PROT_DOUT_PASS | TARGET_PROT_DOUT_STRIP)) :
|
||||
!!(sp_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DIN_INSERT));
|
||||
|
||||
if (fabric_prot && cmd->se_sess->sess_prot_type) {
|
||||
pi_prot_type = cmd->se_sess->sess_prot_type;
|
||||
break;
|
||||
}
|
||||
if (!protect)
|
||||
return TCM_NO_SENSE;
|
||||
/* Fallthrough */
|
||||
default:
|
||||
return TCM_NO_SENSE;
|
||||
pr_err("Unable to determine pi_prot_type for CDB: 0x%02x "
|
||||
"PROTECT: 0x%02x\n", cdb[0], protect);
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
}
|
||||
|
||||
if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type,
|
||||
is_write, cmd))
|
||||
if (sbc_set_prot_op_checks(protect, fabric_prot, pi_prot_type, is_write, cmd))
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
|
||||
cmd->prot_type = dev->dev_attrib.pi_prot_type;
|
||||
cmd->prot_type = pi_prot_type;
|
||||
cmd->prot_length = dev->prot_length * sectors;
|
||||
|
||||
/**
|
||||
@ -1166,14 +1203,16 @@ sbc_dif_generate(struct se_cmd *cmd)
|
||||
sdt = paddr + offset;
|
||||
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
|
||||
dev->dev_attrib.block_size));
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
|
||||
sdt->app_tag = 0;
|
||||
|
||||
pr_debug("DIF WRITE INSERT sector: %llu guard_tag: 0x%04x"
|
||||
pr_debug("DIF %s INSERT sector: %llu guard_tag: 0x%04x"
|
||||
" app_tag: 0x%04x ref_tag: %u\n",
|
||||
(unsigned long long)sector, sdt->guard_tag,
|
||||
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
|
||||
(cmd->data_direction == DMA_TO_DEVICE) ?
|
||||
"WRITE" : "READ", (unsigned long long)sector,
|
||||
sdt->guard_tag, sdt->app_tag,
|
||||
be32_to_cpu(sdt->ref_tag));
|
||||
|
||||
sector++;
|
||||
offset += sizeof(struct se_dif_v1_tuple);
|
||||
@ -1185,12 +1224,16 @@ sbc_dif_generate(struct se_cmd *cmd)
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
|
||||
sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt,
|
||||
const void *p, sector_t sector, unsigned int ei_lba)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
int block_size = dev->dev_attrib.block_size;
|
||||
__be16 csum;
|
||||
|
||||
if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD))
|
||||
goto check_ref;
|
||||
|
||||
csum = cpu_to_be16(crc_t10dif(p, block_size));
|
||||
|
||||
if (sdt->guard_tag != csum) {
|
||||
@ -1200,7 +1243,11 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
|
||||
return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
|
||||
}
|
||||
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT &&
|
||||
check_ref:
|
||||
if (!(cmd->prot_checks & TARGET_DIF_CHECK_REFTAG))
|
||||
return 0;
|
||||
|
||||
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT &&
|
||||
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
|
||||
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
|
||||
" sector MSB: 0x%08x\n", (unsigned long long)sector,
|
||||
@ -1208,7 +1255,7 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
|
||||
return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
|
||||
}
|
||||
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT &&
|
||||
if (cmd->prot_type == TARGET_DIF_TYPE2_PROT &&
|
||||
be32_to_cpu(sdt->ref_tag) != ei_lba) {
|
||||
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
|
||||
" ei_lba: 0x%08x\n", (unsigned long long)sector,
|
||||
@ -1229,6 +1276,9 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
|
||||
unsigned int i, len, left;
|
||||
unsigned int offset = sg_off;
|
||||
|
||||
if (!sg)
|
||||
return;
|
||||
|
||||
left = sectors * dev->prot_length;
|
||||
|
||||
for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
|
||||
@ -1292,7 +1342,7 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
(unsigned long long)sector, sdt->guard_tag,
|
||||
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
|
||||
|
||||
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
|
||||
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
|
||||
ei_lba);
|
||||
if (rc) {
|
||||
kunmap_atomic(paddr);
|
||||
@ -1309,6 +1359,9 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
kunmap_atomic(paddr);
|
||||
kunmap_atomic(daddr);
|
||||
}
|
||||
if (!sg)
|
||||
return 0;
|
||||
|
||||
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
|
||||
|
||||
return 0;
|
||||
@ -1353,7 +1406,7 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
|
||||
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
|
||||
ei_lba);
|
||||
if (rc) {
|
||||
kunmap_atomic(paddr);
|
||||
|
@ -103,10 +103,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
|
||||
buf[5] |= 0x8;
|
||||
/*
|
||||
* Set Protection (PROTECT) bit when DIF has been enabled on the
|
||||
* device, and the transport supports VERIFY + PASS.
|
||||
* device, and the fabric supports VERIFY + PASS. Also report
|
||||
* PROTECT=1 if sess_prot_type has been configured to allow T10-PI
|
||||
* to unprotected devices.
|
||||
*/
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
if (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)
|
||||
buf[5] |= 0x1;
|
||||
}
|
||||
|
||||
@ -467,9 +469,11 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
|
||||
* only for TYPE3 protection.
|
||||
*/
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT ||
|
||||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
buf[4] = 0x5;
|
||||
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
|
||||
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
|
||||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
|
||||
buf[4] = 0x4;
|
||||
}
|
||||
|
||||
@ -861,7 +865,7 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p)
|
||||
* TAG field.
|
||||
*/
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
if (dev->dev_attrib.pi_prot_type || sess->sess_prot_type)
|
||||
p[5] |= 0x80;
|
||||
}
|
||||
|
||||
@ -1099,7 +1103,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||
unsigned char *buf;
|
||||
unsigned char tbuf[SE_MODE_PAGE_BUF];
|
||||
int length;
|
||||
int ret = 0;
|
||||
sense_reason_t ret = 0;
|
||||
int i;
|
||||
|
||||
if (!cmd->data_length) {
|
||||
|
@ -125,8 +125,8 @@ void core_tmr_abort_task(
|
||||
if (dev != se_cmd->se_dev)
|
||||
continue;
|
||||
|
||||
/* skip se_cmd associated with tmr */
|
||||
if (tmr->task_cmd == se_cmd)
|
||||
/* skip task management functions, including tmr->task_cmd */
|
||||
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
|
||||
continue;
|
||||
|
||||
ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);
|
||||
|
@ -672,7 +672,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
|
||||
}
|
||||
|
||||
int core_tpg_register(
|
||||
struct target_core_fabric_ops *tfo,
|
||||
const struct target_core_fabric_ops *tfo,
|
||||
struct se_wwn *se_wwn,
|
||||
struct se_portal_group *se_tpg,
|
||||
void *tpg_fabric_ptr,
|
||||
|
@ -322,6 +322,7 @@ void __transport_register_session(
|
||||
struct se_session *se_sess,
|
||||
void *fabric_sess_ptr)
|
||||
{
|
||||
const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo;
|
||||
unsigned char buf[PR_REG_ISID_LEN];
|
||||
|
||||
se_sess->se_tpg = se_tpg;
|
||||
@ -333,6 +334,21 @@ void __transport_register_session(
|
||||
* eg: *NOT* discovery sessions.
|
||||
*/
|
||||
if (se_nacl) {
|
||||
/*
|
||||
*
|
||||
* Determine if fabric allows for T10-PI feature bits exposed to
|
||||
* initiators for device backends with !dev->dev_attrib.pi_prot_type.
|
||||
*
|
||||
* If so, then always save prot_type on a per se_node_acl node
|
||||
* basis and re-instate the previous sess_prot_type to avoid
|
||||
* disabling PI from below any previously initiator side
|
||||
* registered LUNs.
|
||||
*/
|
||||
if (se_nacl->saved_prot_type)
|
||||
se_sess->sess_prot_type = se_nacl->saved_prot_type;
|
||||
else if (tfo->tpg_check_prot_fabric_only)
|
||||
se_sess->sess_prot_type = se_nacl->saved_prot_type =
|
||||
tfo->tpg_check_prot_fabric_only(se_tpg);
|
||||
/*
|
||||
* If the fabric module supports an ISID based TransportID,
|
||||
* save this value in binary from the fabric I_T Nexus now.
|
||||
@ -404,6 +420,30 @@ void target_put_session(struct se_session *se_sess)
|
||||
}
|
||||
EXPORT_SYMBOL(target_put_session);
|
||||
|
||||
ssize_t target_show_dynamic_sessions(struct se_portal_group *se_tpg, char *page)
|
||||
{
|
||||
struct se_session *se_sess;
|
||||
ssize_t len = 0;
|
||||
|
||||
spin_lock_bh(&se_tpg->session_lock);
|
||||
list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
|
||||
if (!se_sess->se_node_acl)
|
||||
continue;
|
||||
if (!se_sess->se_node_acl->dynamic_node_acl)
|
||||
continue;
|
||||
if (strlen(se_sess->se_node_acl->initiatorname) + 1 + len > PAGE_SIZE)
|
||||
break;
|
||||
|
||||
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
|
||||
se_sess->se_node_acl->initiatorname);
|
||||
len += 1; /* Include NULL terminator */
|
||||
}
|
||||
spin_unlock_bh(&se_tpg->session_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(target_show_dynamic_sessions);
|
||||
|
||||
static void target_complete_nacl(struct kref *kref)
|
||||
{
|
||||
struct se_node_acl *nacl = container_of(kref,
|
||||
@ -462,7 +502,7 @@ EXPORT_SYMBOL(transport_free_session);
|
||||
void transport_deregister_session(struct se_session *se_sess)
|
||||
{
|
||||
struct se_portal_group *se_tpg = se_sess->se_tpg;
|
||||
struct target_core_fabric_ops *se_tfo;
|
||||
const struct target_core_fabric_ops *se_tfo;
|
||||
struct se_node_acl *se_nacl;
|
||||
unsigned long flags;
|
||||
bool comp_nacl = true;
|
||||
@ -1118,7 +1158,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
|
||||
*/
|
||||
void transport_init_se_cmd(
|
||||
struct se_cmd *cmd,
|
||||
struct target_core_fabric_ops *tfo,
|
||||
const struct target_core_fabric_ops *tfo,
|
||||
struct se_session *se_sess,
|
||||
u32 data_length,
|
||||
int data_direction,
|
||||
@ -1570,6 +1610,8 @@ EXPORT_SYMBOL(target_submit_tmr);
|
||||
* has completed.
|
||||
*/
|
||||
bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
|
||||
__releases(&cmd->t_state_lock)
|
||||
__acquires(&cmd->t_state_lock)
|
||||
{
|
||||
bool was_active = false;
|
||||
|
||||
@ -1615,11 +1657,11 @@ void transport_generic_request_failure(struct se_cmd *cmd,
|
||||
transport_complete_task_attr(cmd);
|
||||
/*
|
||||
* Handle special case for COMPARE_AND_WRITE failure, where the
|
||||
* callback is expected to drop the per device ->caw_mutex.
|
||||
* callback is expected to drop the per device ->caw_sem.
|
||||
*/
|
||||
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
|
||||
cmd->transport_complete_callback)
|
||||
cmd->transport_complete_callback(cmd);
|
||||
cmd->transport_complete_callback(cmd, false);
|
||||
|
||||
switch (sense_reason) {
|
||||
case TCM_NON_EXISTENT_LUN:
|
||||
@ -1706,6 +1748,41 @@ void __target_execute_cmd(struct se_cmd *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static int target_write_prot_action(struct se_cmd *cmd)
|
||||
{
|
||||
u32 sectors;
|
||||
/*
|
||||
* Perform WRITE_INSERT of PI using software emulation when backend
|
||||
* device has PI enabled, if the transport has not already generated
|
||||
* PI using hardware WRITE_INSERT offload.
|
||||
*/
|
||||
switch (cmd->prot_op) {
|
||||
case TARGET_PROT_DOUT_INSERT:
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
|
||||
sbc_dif_generate(cmd);
|
||||
break;
|
||||
case TARGET_PROT_DOUT_STRIP:
|
||||
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_STRIP)
|
||||
break;
|
||||
|
||||
sectors = cmd->data_length >> ilog2(cmd->se_dev->dev_attrib.block_size);
|
||||
cmd->pi_err = sbc_dif_verify_write(cmd, cmd->t_task_lba,
|
||||
sectors, 0, NULL, 0);
|
||||
if (unlikely(cmd->pi_err)) {
|
||||
spin_lock_irq(&cmd->t_state_lock);
|
||||
cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
transport_generic_request_failure(cmd, cmd->pi_err);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool target_handle_task_attr(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
@ -1785,15 +1862,9 @@ void target_execute_cmd(struct se_cmd *cmd)
|
||||
cmd->t_state = TRANSPORT_PROCESSING;
|
||||
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
/*
|
||||
* Perform WRITE_INSERT of PI using software emulation when backend
|
||||
* device has PI enabled, if the transport has not already generated
|
||||
* PI using hardware WRITE_INSERT offload.
|
||||
*/
|
||||
if (cmd->prot_op == TARGET_PROT_DOUT_INSERT) {
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
|
||||
sbc_dif_generate(cmd);
|
||||
}
|
||||
|
||||
if (target_write_prot_action(cmd))
|
||||
return;
|
||||
|
||||
if (target_handle_task_attr(cmd)) {
|
||||
spin_lock_irq(&cmd->t_state_lock);
|
||||
@ -1919,16 +1990,28 @@ static void transport_handle_queue_full(
|
||||
schedule_work(&cmd->se_dev->qf_work_queue);
|
||||
}
|
||||
|
||||
static bool target_check_read_strip(struct se_cmd *cmd)
|
||||
static bool target_read_prot_action(struct se_cmd *cmd)
|
||||
{
|
||||
sense_reason_t rc;
|
||||
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
|
||||
rc = sbc_dif_read_strip(cmd);
|
||||
if (rc) {
|
||||
cmd->pi_err = rc;
|
||||
return true;
|
||||
switch (cmd->prot_op) {
|
||||
case TARGET_PROT_DIN_STRIP:
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
|
||||
rc = sbc_dif_read_strip(cmd);
|
||||
if (rc) {
|
||||
cmd->pi_err = rc;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_PROT_DIN_INSERT:
|
||||
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_INSERT)
|
||||
break;
|
||||
|
||||
sbc_dif_generate(cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1975,8 +2058,12 @@ static void target_complete_ok_work(struct work_struct *work)
|
||||
if (cmd->transport_complete_callback) {
|
||||
sense_reason_t rc;
|
||||
|
||||
rc = cmd->transport_complete_callback(cmd);
|
||||
rc = cmd->transport_complete_callback(cmd, true);
|
||||
if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) {
|
||||
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
|
||||
!cmd->data_length)
|
||||
goto queue_rsp;
|
||||
|
||||
return;
|
||||
} else if (rc) {
|
||||
ret = transport_send_check_condition_and_sense(cmd,
|
||||
@ -1990,6 +2077,7 @@ static void target_complete_ok_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
queue_rsp:
|
||||
switch (cmd->data_direction) {
|
||||
case DMA_FROM_DEVICE:
|
||||
spin_lock(&cmd->se_lun->lun_sep_lock);
|
||||
@ -2003,8 +2091,7 @@ static void target_complete_ok_work(struct work_struct *work)
|
||||
* backend had PI enabled, if the transport will not be
|
||||
* performing hardware READ_STRIP offload.
|
||||
*/
|
||||
if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
|
||||
target_check_read_strip(cmd)) {
|
||||
if (target_read_prot_action(cmd)) {
|
||||
ret = transport_send_check_condition_and_sense(cmd,
|
||||
cmd->pi_err, 0);
|
||||
if (ret == -EAGAIN || ret == -ENOMEM)
|
||||
@ -2094,6 +2181,16 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd)
|
||||
static inline void transport_free_pages(struct se_cmd *cmd)
|
||||
{
|
||||
if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
|
||||
/*
|
||||
* Release special case READ buffer payload required for
|
||||
* SG_TO_MEM_NOALLOC to function with COMPARE_AND_WRITE
|
||||
*/
|
||||
if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) {
|
||||
transport_free_sgl(cmd->t_bidi_data_sg,
|
||||
cmd->t_bidi_data_nents);
|
||||
cmd->t_bidi_data_sg = NULL;
|
||||
cmd->t_bidi_data_nents = 0;
|
||||
}
|
||||
transport_reset_sgl_orig(cmd);
|
||||
return;
|
||||
}
|
||||
@ -2246,6 +2343,7 @@ sense_reason_t
|
||||
transport_generic_new_cmd(struct se_cmd *cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
|
||||
|
||||
/*
|
||||
* Determine is the TCM fabric module has already allocated physical
|
||||
@ -2254,7 +2352,6 @@ transport_generic_new_cmd(struct se_cmd *cmd)
|
||||
*/
|
||||
if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) &&
|
||||
cmd->data_length) {
|
||||
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
|
||||
|
||||
if ((cmd->se_cmd_flags & SCF_BIDI) ||
|
||||
(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) {
|
||||
@ -2285,6 +2382,20 @@ transport_generic_new_cmd(struct se_cmd *cmd)
|
||||
cmd->data_length, zero_flag);
|
||||
if (ret < 0)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
} else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
|
||||
cmd->data_length) {
|
||||
/*
|
||||
* Special case for COMPARE_AND_WRITE with fabrics
|
||||
* using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC.
|
||||
*/
|
||||
u32 caw_length = cmd->t_task_nolb *
|
||||
cmd->se_dev->dev_attrib.block_size;
|
||||
|
||||
ret = target_alloc_sgl(&cmd->t_bidi_data_sg,
|
||||
&cmd->t_bidi_data_nents,
|
||||
caw_length, zero_flag);
|
||||
if (ret < 0)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
/*
|
||||
* If this command is not a write we can execute it right here,
|
||||
@ -2376,10 +2487,8 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
|
||||
* fabric acknowledgement that requires two target_put_sess_cmd()
|
||||
* invocations before se_cmd descriptor release.
|
||||
*/
|
||||
if (ack_kref) {
|
||||
if (ack_kref)
|
||||
kref_get(&se_cmd->cmd_kref);
|
||||
se_cmd->se_cmd_flags |= SCF_ACK_KREF;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
||||
if (se_sess->sess_tearing_down) {
|
||||
@ -2398,6 +2507,7 @@ out:
|
||||
EXPORT_SYMBOL(target_get_sess_cmd);
|
||||
|
||||
static void target_release_cmd_kref(struct kref *kref)
|
||||
__releases(&se_cmd->se_sess->sess_cmd_lock)
|
||||
{
|
||||
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
|
||||
struct se_session *se_sess = se_cmd->se_sess;
|
||||
|
@ -344,8 +344,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||
|
||||
entry = (void *) mb + CMDR_OFF + cmd_head;
|
||||
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD);
|
||||
tcmu_hdr_set_len(&entry->hdr, pad_size);
|
||||
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD);
|
||||
tcmu_hdr_set_len(&entry->hdr.len_op, pad_size);
|
||||
entry->hdr.cmd_id = 0; /* not used for PAD */
|
||||
entry->hdr.kflags = 0;
|
||||
entry->hdr.uflags = 0;
|
||||
|
||||
UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size);
|
||||
|
||||
@ -355,9 +358,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||
|
||||
entry = (void *) mb + CMDR_OFF + cmd_head;
|
||||
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD);
|
||||
tcmu_hdr_set_len(&entry->hdr, command_size);
|
||||
entry->cmd_id = tcmu_cmd->cmd_id;
|
||||
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
|
||||
tcmu_hdr_set_len(&entry->hdr.len_op, command_size);
|
||||
entry->hdr.cmd_id = tcmu_cmd->cmd_id;
|
||||
entry->hdr.kflags = 0;
|
||||
entry->hdr.uflags = 0;
|
||||
|
||||
/*
|
||||
* Fix up iovecs, and handle if allocation in data ring wrapped.
|
||||
@ -376,7 +381,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||
|
||||
/* Even iov_base is relative to mb_addr */
|
||||
iov->iov_len = copy_bytes;
|
||||
iov->iov_base = (void *) udev->data_off + udev->data_head;
|
||||
iov->iov_base = (void __user *) udev->data_off +
|
||||
udev->data_head;
|
||||
iov_cnt++;
|
||||
iov++;
|
||||
|
||||
@ -388,7 +394,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||
copy_bytes = sg->length - copy_bytes;
|
||||
|
||||
iov->iov_len = copy_bytes;
|
||||
iov->iov_base = (void *) udev->data_off + udev->data_head;
|
||||
iov->iov_base = (void __user *) udev->data_off +
|
||||
udev->data_head;
|
||||
|
||||
if (se_cmd->data_direction == DMA_TO_DEVICE) {
|
||||
to = (void *) mb + udev->data_off + udev->data_head;
|
||||
@ -405,6 +412,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||
kunmap_atomic(from);
|
||||
}
|
||||
entry->req.iov_cnt = iov_cnt;
|
||||
entry->req.iov_bidi_cnt = 0;
|
||||
entry->req.iov_dif_cnt = 0;
|
||||
|
||||
/* All offsets relative to mb_addr, not start of entry! */
|
||||
cdb_off = CMDR_OFF + cmd_head + base_command_size;
|
||||
@ -462,6 +471,17 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) {
|
||||
UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size);
|
||||
pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n",
|
||||
cmd->se_cmd);
|
||||
transport_generic_request_failure(cmd->se_cmd,
|
||||
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
|
||||
cmd->se_cmd = NULL;
|
||||
kmem_cache_free(tcmu_cmd_cache, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
|
||||
memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
|
||||
se_cmd->scsi_sense_length);
|
||||
@ -540,14 +560,16 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
|
||||
|
||||
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||
|
||||
if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) {
|
||||
UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size);
|
||||
if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) {
|
||||
UPDATE_HEAD(udev->cmdr_last_cleaned,
|
||||
tcmu_hdr_get_len(entry->hdr.len_op),
|
||||
udev->cmdr_size);
|
||||
continue;
|
||||
}
|
||||
WARN_ON(tcmu_hdr_get_op(&entry->hdr) != TCMU_OP_CMD);
|
||||
WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD);
|
||||
|
||||
spin_lock(&udev->commands_lock);
|
||||
cmd = idr_find(&udev->commands, entry->cmd_id);
|
||||
cmd = idr_find(&udev->commands, entry->hdr.cmd_id);
|
||||
if (cmd)
|
||||
idr_remove(&udev->commands, cmd->cmd_id);
|
||||
spin_unlock(&udev->commands_lock);
|
||||
@ -560,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
|
||||
|
||||
tcmu_handle_completion(cmd, entry);
|
||||
|
||||
UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size);
|
||||
UPDATE_HEAD(udev->cmdr_last_cleaned,
|
||||
tcmu_hdr_get_len(entry->hdr.len_op),
|
||||
udev->cmdr_size);
|
||||
|
||||
handled++;
|
||||
}
|
||||
@ -838,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev)
|
||||
udev->data_size = TCMU_RING_SIZE - CMDR_SIZE;
|
||||
|
||||
mb = udev->mb_addr;
|
||||
mb->version = 1;
|
||||
mb->version = TCMU_MAILBOX_VERSION;
|
||||
mb->cmdr_off = CMDR_OFF;
|
||||
mb->cmdr_size = udev->cmdr_size;
|
||||
|
||||
WARN_ON(!PAGE_ALIGNED(udev->data_off));
|
||||
WARN_ON(udev->data_size % PAGE_SIZE);
|
||||
|
||||
info->version = "1";
|
||||
info->version = xstr(TCMU_MAILBOX_VERSION);
|
||||
|
||||
info->mem[0].name = "tcm-user command & data buffer";
|
||||
info->mem[0].addr = (phys_addr_t) udev->mb_addr;
|
||||
|
@ -34,20 +34,12 @@
|
||||
#include <target/target_core_fabric.h>
|
||||
#include <target/target_core_configfs.h>
|
||||
|
||||
#include "target_core_internal.h"
|
||||
#include "target_core_pr.h"
|
||||
#include "target_core_ua.h"
|
||||
#include "target_core_xcopy.h"
|
||||
|
||||
static struct workqueue_struct *xcopy_wq = NULL;
|
||||
/*
|
||||
* From target_core_device.c
|
||||
*/
|
||||
extern struct mutex g_device_mutex;
|
||||
extern struct list_head g_device_list;
|
||||
/*
|
||||
* From target_core_configfs.c
|
||||
*/
|
||||
extern struct configfs_subsystem *target_core_subsystem[];
|
||||
|
||||
static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
|
||||
{
|
||||
@ -433,7 +425,7 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct target_core_fabric_ops xcopy_pt_tfo = {
|
||||
static const struct target_core_fabric_ops xcopy_pt_tfo = {
|
||||
.get_fabric_name = xcopy_pt_get_fabric_name,
|
||||
.get_task_tag = xcopy_pt_get_tag,
|
||||
.get_cmd_state = xcopy_pt_get_cmd_state,
|
||||
@ -548,33 +540,22 @@ static void target_xcopy_setup_pt_port(
|
||||
}
|
||||
}
|
||||
|
||||
static int target_xcopy_init_pt_lun(
|
||||
struct xcopy_pt_cmd *xpt_cmd,
|
||||
struct xcopy_op *xop,
|
||||
struct se_device *se_dev,
|
||||
struct se_cmd *pt_cmd,
|
||||
bool remote_port)
|
||||
static void target_xcopy_init_pt_lun(struct se_device *se_dev,
|
||||
struct se_cmd *pt_cmd, bool remote_port)
|
||||
{
|
||||
/*
|
||||
* Don't allocate + init an pt_cmd->se_lun if honoring local port for
|
||||
* reservations. The pt_cmd->se_lun pointer will be setup from within
|
||||
* target_xcopy_setup_pt_port()
|
||||
*/
|
||||
if (!remote_port) {
|
||||
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
|
||||
return 0;
|
||||
if (remote_port) {
|
||||
pr_debug("Setup emulated se_dev: %p from se_dev\n",
|
||||
pt_cmd->se_dev);
|
||||
pt_cmd->se_lun = &se_dev->xcopy_lun;
|
||||
pt_cmd->se_dev = se_dev;
|
||||
}
|
||||
|
||||
pt_cmd->se_lun = &se_dev->xcopy_lun;
|
||||
pt_cmd->se_dev = se_dev;
|
||||
|
||||
pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev);
|
||||
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
|
||||
|
||||
pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n",
|
||||
pt_cmd->se_lun->lun_se_dev);
|
||||
|
||||
return 0;
|
||||
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
|
||||
}
|
||||
|
||||
static int target_xcopy_setup_pt_cmd(
|
||||
@ -592,11 +573,8 @@ static int target_xcopy_setup_pt_cmd(
|
||||
* Setup LUN+port to honor reservations based upon xop->op_origin for
|
||||
* X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
|
||||
*/
|
||||
rc = target_xcopy_init_pt_lun(xpt_cmd, xop, se_dev, cmd, remote_port);
|
||||
if (rc < 0) {
|
||||
ret = rc;
|
||||
goto out;
|
||||
}
|
||||
target_xcopy_init_pt_lun(se_dev, cmd, remote_port);
|
||||
|
||||
xpt_cmd->xcopy_op = xop;
|
||||
target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);
|
||||
|
||||
|
@ -129,7 +129,6 @@ struct ft_cmd {
|
||||
|
||||
extern struct mutex ft_lport_lock;
|
||||
extern struct fc4_prov ft_prov;
|
||||
extern struct target_fabric_configfs *ft_configfs;
|
||||
extern unsigned int ft_debug_logging;
|
||||
|
||||
/*
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
#include "tcm_fc.h"
|
||||
|
||||
struct target_fabric_configfs *ft_configfs;
|
||||
static const struct target_core_fabric_ops ft_fabric_ops;
|
||||
|
||||
static LIST_HEAD(ft_wwn_list);
|
||||
DEFINE_MUTEX(ft_lport_lock);
|
||||
@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
|
||||
ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg,
|
||||
tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
destroy_workqueue(wq);
|
||||
@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
|
||||
return tpg->index;
|
||||
}
|
||||
|
||||
static struct target_core_fabric_ops ft_fabric_ops = {
|
||||
static const struct target_core_fabric_ops ft_fabric_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "fc",
|
||||
.get_fabric_name = ft_get_fabric_name,
|
||||
.get_fabric_proto_ident = fc_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = ft_get_fabric_wwn,
|
||||
@ -552,78 +554,35 @@ static struct target_core_fabric_ops ft_fabric_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = &ft_add_acl,
|
||||
.fabric_drop_nodeacl = &ft_del_acl,
|
||||
|
||||
.tfc_wwn_attrs = ft_wwn_attrs,
|
||||
.tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
|
||||
};
|
||||
|
||||
static int ft_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Register the top level struct config_item_type with TCM core
|
||||
*/
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "fc");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("%s: target_fabric_configfs_init() failed!\n",
|
||||
__func__);
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
fabric->tf_ops = ft_fabric_ops;
|
||||
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs =
|
||||
ft_nacl_base_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* register the fabric for use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_debug("target_fabric_configfs_register() for"
|
||||
" FC Target failed!\n");
|
||||
target_fabric_configfs_free(fabric);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup our local pointer to *fabric.
|
||||
*/
|
||||
ft_configfs = fabric;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ft_deregister_configfs(void)
|
||||
{
|
||||
if (!ft_configfs)
|
||||
return;
|
||||
target_fabric_configfs_deregister(ft_configfs);
|
||||
ft_configfs = NULL;
|
||||
}
|
||||
|
||||
static struct notifier_block ft_notifier = {
|
||||
.notifier_call = ft_lport_notify
|
||||
};
|
||||
|
||||
static int __init ft_init(void)
|
||||
{
|
||||
if (ft_register_configfs())
|
||||
return -1;
|
||||
if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) {
|
||||
ft_deregister_configfs();
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
|
||||
ret = target_register_template(&ft_fabric_ops);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov);
|
||||
if (ret)
|
||||
goto out_unregister_template;
|
||||
|
||||
blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
|
||||
fc_lport_iterate(ft_lport_add, NULL);
|
||||
return 0;
|
||||
|
||||
out_unregister_template:
|
||||
target_unregister_template(&ft_fabric_ops);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ft_exit(void)
|
||||
@ -632,7 +591,7 @@ static void __exit ft_exit(void)
|
||||
&ft_notifier);
|
||||
fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
|
||||
fc_lport_iterate(ft_lport_del, NULL);
|
||||
ft_deregister_configfs();
|
||||
target_unregister_template(&ft_fabric_ops);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
USB_GADGET_COMPOSITE_OPTIONS();
|
||||
|
||||
static struct target_fabric_configfs *usbg_fabric_configfs;
|
||||
static const struct target_core_fabric_ops usbg_ops;
|
||||
|
||||
static inline struct f_uas *to_f_uas(struct usb_function *f)
|
||||
{
|
||||
@ -1572,8 +1572,7 @@ static struct se_portal_group *usbg_make_tpg(
|
||||
tpg->tport = tport;
|
||||
tpg->tport_tpgt = tpgt;
|
||||
|
||||
ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
|
||||
&tpg->se_tpg, tpg,
|
||||
ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg,
|
||||
TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
destroy_workqueue(tpg->workqueue);
|
||||
@ -1864,7 +1863,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct target_core_fabric_ops usbg_ops = {
|
||||
static const struct target_core_fabric_ops usbg_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "usb_gadget",
|
||||
.get_fabric_name = usbg_get_fabric_name,
|
||||
.get_fabric_proto_ident = usbg_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = usbg_get_fabric_wwn,
|
||||
@ -1906,46 +1907,9 @@ static struct target_core_fabric_ops usbg_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = usbg_make_nodeacl,
|
||||
.fabric_drop_nodeacl = usbg_drop_nodeacl,
|
||||
};
|
||||
|
||||
static int usbg_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
|
||||
if (IS_ERR(fabric)) {
|
||||
printk(KERN_ERR "target_fabric_configfs_init() failed\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
|
||||
fabric->tf_ops = usbg_ops;
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "target_fabric_configfs_register() failed"
|
||||
" for usb-gadget\n");
|
||||
return ret;
|
||||
}
|
||||
usbg_fabric_configfs = fabric;
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void usbg_deregister_configfs(void)
|
||||
{
|
||||
if (!(usbg_fabric_configfs))
|
||||
return;
|
||||
|
||||
target_fabric_configfs_deregister(usbg_fabric_configfs);
|
||||
usbg_fabric_configfs = NULL;
|
||||
.tfc_wwn_attrs = usbg_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = usbg_base_attrs,
|
||||
};
|
||||
|
||||
/* Start gadget.c code */
|
||||
@ -2454,16 +2418,13 @@ static void usbg_detach(struct usbg_tpg *tpg)
|
||||
|
||||
static int __init usb_target_gadget_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usbg_register_configfs();
|
||||
return ret;
|
||||
return target_register_template(&usbg_ops);
|
||||
}
|
||||
module_init(usb_target_gadget_init);
|
||||
|
||||
static void __exit usb_target_gadget_exit(void)
|
||||
{
|
||||
usbg_deregister_configfs();
|
||||
target_unregister_template(&usbg_ops);
|
||||
}
|
||||
module_exit(usb_target_gadget_exit);
|
||||
|
||||
|
@ -131,6 +131,8 @@ struct vhost_scsi_tpg {
|
||||
int tv_tpg_port_count;
|
||||
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
|
||||
int tv_tpg_vhost_count;
|
||||
/* Used for enabling T10-PI with legacy devices */
|
||||
int tv_fabric_prot_type;
|
||||
/* list for vhost_scsi_list */
|
||||
struct list_head tv_tpg_list;
|
||||
/* Used to protect access for tpg_nexus */
|
||||
@ -214,9 +216,7 @@ struct vhost_scsi {
|
||||
int vs_events_nr; /* num of pending events, protected by vq->mutex */
|
||||
};
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
|
||||
|
||||
static struct target_core_fabric_ops vhost_scsi_ops;
|
||||
static struct workqueue_struct *vhost_scsi_workqueue;
|
||||
|
||||
/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
|
||||
@ -431,6 +431,14 @@ vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
|
||||
port_nexus_ptr);
|
||||
}
|
||||
|
||||
static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
|
||||
struct vhost_scsi_tpg, se_tpg);
|
||||
|
||||
return tpg->tv_fabric_prot_type;
|
||||
}
|
||||
|
||||
static struct se_node_acl *
|
||||
vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg)
|
||||
{
|
||||
@ -1878,6 +1886,45 @@ static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus,
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
const char *page,
|
||||
size_t count)
|
||||
{
|
||||
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
|
||||
struct vhost_scsi_tpg, se_tpg);
|
||||
unsigned long val;
|
||||
int ret = kstrtoul(page, 0, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (val != 0 && val != 1 && val != 3) {
|
||||
pr_err("Invalid vhost_scsi fabric_prot_type: %lu\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
tpg->tv_fabric_prot_type = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t vhost_scsi_tpg_attrib_show_fabric_prot_type(
|
||||
struct se_portal_group *se_tpg,
|
||||
char *page)
|
||||
{
|
||||
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
|
||||
struct vhost_scsi_tpg, se_tpg);
|
||||
|
||||
return sprintf(page, "%d\n", tpg->tv_fabric_prot_type);
|
||||
}
|
||||
TF_TPG_ATTRIB_ATTR(vhost_scsi, fabric_prot_type, S_IRUGO | S_IWUSR);
|
||||
|
||||
static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = {
|
||||
&vhost_scsi_tpg_attrib_fabric_prot_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
|
||||
const char *name)
|
||||
{
|
||||
@ -2155,7 +2202,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn,
|
||||
tpg->tport = tport;
|
||||
tpg->tport_tpgt = tpgt;
|
||||
|
||||
ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn,
|
||||
ret = core_tpg_register(&vhost_scsi_ops, wwn,
|
||||
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
kfree(tpg);
|
||||
@ -2277,6 +2324,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
|
||||
};
|
||||
|
||||
static struct target_core_fabric_ops vhost_scsi_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "vhost",
|
||||
.get_fabric_name = vhost_scsi_get_fabric_name,
|
||||
.get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = vhost_scsi_get_fabric_wwn,
|
||||
@ -2289,6 +2338,7 @@ static struct target_core_fabric_ops vhost_scsi_ops = {
|
||||
.tpg_check_demo_mode_cache = vhost_scsi_check_true,
|
||||
.tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
|
||||
.tpg_check_prod_mode_write_protect = vhost_scsi_check_false,
|
||||
.tpg_check_prot_fabric_only = vhost_scsi_check_prot_fabric_only,
|
||||
.tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl,
|
||||
.tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
|
||||
.tpg_get_inst_index = vhost_scsi_tpg_get_inst_index,
|
||||
@ -2320,70 +2370,20 @@ static struct target_core_fabric_ops vhost_scsi_ops = {
|
||||
.fabric_drop_np = NULL,
|
||||
.fabric_make_nodeacl = vhost_scsi_make_nodeacl,
|
||||
.fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
|
||||
};
|
||||
|
||||
static int vhost_scsi_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
pr_debug("vhost-scsi fabric module %s on %s/%s"
|
||||
" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
|
||||
utsname()->machine);
|
||||
/*
|
||||
* Register the top level struct config_item_type with TCM core
|
||||
*/
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "vhost");
|
||||
if (IS_ERR(fabric)) {
|
||||
pr_err("target_fabric_configfs_init() failed\n");
|
||||
return PTR_ERR(fabric);
|
||||
}
|
||||
/*
|
||||
* Setup fabric->tf_ops from our local vhost_scsi_ops
|
||||
*/
|
||||
fabric->tf_ops = vhost_scsi_ops;
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* Register the fabric for use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
pr_err("target_fabric_configfs_register() failed"
|
||||
" for TCM_VHOST\n");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Setup our local pointer to *fabric
|
||||
*/
|
||||
vhost_scsi_fabric_configfs = fabric;
|
||||
pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n");
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void vhost_scsi_deregister_configfs(void)
|
||||
{
|
||||
if (!vhost_scsi_fabric_configfs)
|
||||
return;
|
||||
|
||||
target_fabric_configfs_deregister(vhost_scsi_fabric_configfs);
|
||||
vhost_scsi_fabric_configfs = NULL;
|
||||
pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n");
|
||||
.tfc_wwn_attrs = vhost_scsi_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = vhost_scsi_tpg_attrs,
|
||||
.tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs,
|
||||
};
|
||||
|
||||
static int __init vhost_scsi_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
pr_debug("TCM_VHOST fabric module %s on %s/%s"
|
||||
" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
|
||||
utsname()->machine);
|
||||
|
||||
/*
|
||||
* Use our own dedicated workqueue for submitting I/O into
|
||||
* target core to avoid contention within system_wq.
|
||||
@ -2396,7 +2396,7 @@ static int __init vhost_scsi_init(void)
|
||||
if (ret < 0)
|
||||
goto out_destroy_workqueue;
|
||||
|
||||
ret = vhost_scsi_register_configfs();
|
||||
ret = target_register_template(&vhost_scsi_ops);
|
||||
if (ret < 0)
|
||||
goto out_vhost_scsi_deregister;
|
||||
|
||||
@ -2412,7 +2412,7 @@ out:
|
||||
|
||||
static void vhost_scsi_exit(void)
|
||||
{
|
||||
vhost_scsi_deregister_configfs();
|
||||
target_unregister_template(&vhost_scsi_ops);
|
||||
vhost_scsi_deregister();
|
||||
destroy_workqueue(vhost_scsi_workqueue);
|
||||
};
|
||||
|
@ -204,8 +204,7 @@ static LIST_HEAD(scsiback_free_pages);
|
||||
static DEFINE_MUTEX(scsiback_mutex);
|
||||
static LIST_HEAD(scsiback_list);
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
static struct target_fabric_configfs *scsiback_fabric_configfs;
|
||||
static const struct target_core_fabric_ops scsiback_ops;
|
||||
|
||||
static void scsiback_get(struct vscsibk_info *info)
|
||||
{
|
||||
@ -1902,7 +1901,7 @@ scsiback_make_tpg(struct se_wwn *wwn,
|
||||
tpg->tport = tport;
|
||||
tpg->tport_tpgt = tpgt;
|
||||
|
||||
ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn,
|
||||
ret = core_tpg_register(&scsiback_ops, wwn,
|
||||
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||
if (ret < 0) {
|
||||
kfree(tpg);
|
||||
@ -1944,7 +1943,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct target_core_fabric_ops scsiback_ops = {
|
||||
static const struct target_core_fabric_ops scsiback_ops = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "xen-pvscsi",
|
||||
.get_fabric_name = scsiback_get_fabric_name,
|
||||
.get_fabric_proto_ident = scsiback_get_fabric_proto_ident,
|
||||
.tpg_get_wwn = scsiback_get_fabric_wwn,
|
||||
@ -1991,62 +1992,10 @@ static struct target_core_fabric_ops scsiback_ops = {
|
||||
.fabric_make_nodeacl = scsiback_make_nodeacl,
|
||||
.fabric_drop_nodeacl = scsiback_drop_nodeacl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int scsiback_register_configfs(void)
|
||||
{
|
||||
struct target_fabric_configfs *fabric;
|
||||
int ret;
|
||||
|
||||
pr_debug("fabric module %s on %s/%s on "UTS_RELEASE"\n",
|
||||
VSCSI_VERSION, utsname()->sysname, utsname()->machine);
|
||||
/*
|
||||
* Register the top level struct config_item_type with TCM core
|
||||
*/
|
||||
fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi");
|
||||
if (IS_ERR(fabric))
|
||||
return PTR_ERR(fabric);
|
||||
|
||||
/*
|
||||
* Setup fabric->tf_ops from our local scsiback_ops
|
||||
*/
|
||||
fabric->tf_ops = scsiback_ops;
|
||||
/*
|
||||
* Setup default attribute lists for various fabric->tf_cit_tmpl
|
||||
*/
|
||||
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
|
||||
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
|
||||
/*
|
||||
* Register the fabric for use within TCM
|
||||
*/
|
||||
ret = target_fabric_configfs_register(fabric);
|
||||
if (ret < 0) {
|
||||
target_fabric_configfs_free(fabric);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Setup our local pointer to *fabric
|
||||
*/
|
||||
scsiback_fabric_configfs = fabric;
|
||||
pr_debug("Set fabric -> scsiback_fabric_configfs\n");
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void scsiback_deregister_configfs(void)
|
||||
{
|
||||
if (!scsiback_fabric_configfs)
|
||||
return;
|
||||
|
||||
target_fabric_configfs_deregister(scsiback_fabric_configfs);
|
||||
scsiback_fabric_configfs = NULL;
|
||||
pr_debug("Cleared scsiback_fabric_configfs\n");
|
||||
.tfc_wwn_attrs = scsiback_wwn_attrs,
|
||||
.tfc_tpg_base_attrs = scsiback_tpg_attrs,
|
||||
.tfc_tpg_param_attrs = scsiback_param_attrs,
|
||||
};
|
||||
|
||||
static const struct xenbus_device_id scsiback_ids[] = {
|
||||
@ -2078,6 +2027,9 @@ static int __init scsiback_init(void)
|
||||
if (!xen_domain())
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n",
|
||||
VSCSI_VERSION, utsname()->sysname, utsname()->machine);
|
||||
|
||||
scsiback_cachep = kmem_cache_create("vscsiif_cache",
|
||||
sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
|
||||
if (!scsiback_cachep)
|
||||
@ -2087,7 +2039,7 @@ static int __init scsiback_init(void)
|
||||
if (ret)
|
||||
goto out_cache_destroy;
|
||||
|
||||
ret = scsiback_register_configfs();
|
||||
ret = target_register_template(&scsiback_ops);
|
||||
if (ret)
|
||||
goto out_unregister_xenbus;
|
||||
|
||||
@ -2110,7 +2062,7 @@ static void __exit scsiback_exit(void)
|
||||
BUG();
|
||||
gnttab_free_pages(1, &page);
|
||||
}
|
||||
scsiback_deregister_configfs();
|
||||
target_unregister_template(&scsiback_ops);
|
||||
xenbus_unregister_driver(&scsiback_driver);
|
||||
kmem_cache_destroy(scsiback_cachep);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
#define ISCSIT_MIN_TAGS 16
|
||||
#define ISCSIT_EXTRA_TAGS 8
|
||||
#define ISCSIT_TCP_BACKLOG 256
|
||||
#define ISCSI_RX_THREAD_NAME "iscsi_trx"
|
||||
#define ISCSI_TX_THREAD_NAME "iscsi_ttx"
|
||||
|
||||
/* struct iscsi_node_attrib sanity values */
|
||||
#define NA_DATAOUT_TIMEOUT 3
|
||||
@ -60,6 +62,7 @@
|
||||
#define TA_CACHE_CORE_NPS 0
|
||||
/* T10 protection information disabled by default */
|
||||
#define TA_DEFAULT_T10_PI 0
|
||||
#define TA_DEFAULT_FABRIC_PROT_TYPE 0
|
||||
|
||||
#define ISCSI_IOV_DATA_BUFFER 5
|
||||
|
||||
@ -600,8 +603,11 @@ struct iscsi_conn {
|
||||
struct iscsi_tpg_np *tpg_np;
|
||||
/* Pointer to parent session */
|
||||
struct iscsi_session *sess;
|
||||
/* Pointer to thread_set in use for this conn's threads */
|
||||
struct iscsi_thread_set *thread_set;
|
||||
int bitmap_id;
|
||||
int rx_thread_active;
|
||||
struct task_struct *rx_thread;
|
||||
int tx_thread_active;
|
||||
struct task_struct *tx_thread;
|
||||
/* list_head for session connection list */
|
||||
struct list_head conn_list;
|
||||
} ____cacheline_aligned;
|
||||
@ -767,6 +773,7 @@ struct iscsi_tpg_attrib {
|
||||
u32 demo_mode_discovery;
|
||||
u32 default_erl;
|
||||
u8 t10_pi;
|
||||
u32 fabric_prot_type;
|
||||
struct iscsi_portal_group *tpg;
|
||||
};
|
||||
|
||||
@ -871,10 +878,10 @@ struct iscsit_global {
|
||||
/* Unique identifier used for the authentication daemon */
|
||||
u32 auth_id;
|
||||
u32 inactive_ts;
|
||||
/* Thread Set bitmap count */
|
||||
int ts_bitmap_count;
|
||||
#define ISCSIT_BITMAP_BITS 262144
|
||||
/* Thread Set bitmap pointer */
|
||||
unsigned long *ts_bitmap;
|
||||
spinlock_t ts_bitmap_lock;
|
||||
/* Used for iSCSI discovery session authentication */
|
||||
struct iscsi_node_acl discovery_acl;
|
||||
struct iscsi_portal_group *discovery_tpg;
|
||||
|
@ -165,10 +165,8 @@ enum se_cmd_flags_table {
|
||||
SCF_SEND_DELAYED_TAS = 0x00004000,
|
||||
SCF_ALUA_NON_OPTIMIZED = 0x00008000,
|
||||
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
|
||||
SCF_ACK_KREF = 0x00040000,
|
||||
SCF_COMPARE_AND_WRITE = 0x00080000,
|
||||
SCF_COMPARE_AND_WRITE_POST = 0x00100000,
|
||||
SCF_CMD_XCOPY_PASSTHROUGH = 0x00200000,
|
||||
};
|
||||
|
||||
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
|
||||
@ -520,11 +518,11 @@ struct se_cmd {
|
||||
struct list_head se_cmd_list;
|
||||
struct completion cmd_wait_comp;
|
||||
struct kref cmd_kref;
|
||||
struct target_core_fabric_ops *se_tfo;
|
||||
const struct target_core_fabric_ops *se_tfo;
|
||||
sense_reason_t (*execute_cmd)(struct se_cmd *);
|
||||
sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *,
|
||||
u32, enum dma_data_direction);
|
||||
sense_reason_t (*transport_complete_callback)(struct se_cmd *);
|
||||
sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool);
|
||||
|
||||
unsigned char *t_task_cdb;
|
||||
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
|
||||
@ -591,6 +589,7 @@ struct se_node_acl {
|
||||
bool acl_stop:1;
|
||||
u32 queue_depth;
|
||||
u32 acl_index;
|
||||
enum target_prot_type saved_prot_type;
|
||||
#define MAX_ACL_TAG_SIZE 64
|
||||
char acl_tag[MAX_ACL_TAG_SIZE];
|
||||
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
|
||||
@ -616,6 +615,7 @@ struct se_session {
|
||||
unsigned sess_tearing_down:1;
|
||||
u64 sess_bin_isid;
|
||||
enum target_prot_op sup_prot_ops;
|
||||
enum target_prot_type sess_prot_type;
|
||||
struct se_node_acl *se_node_acl;
|
||||
struct se_portal_group *se_tpg;
|
||||
void *fabric_sess_ptr;
|
||||
@ -890,7 +890,7 @@ struct se_portal_group {
|
||||
/* List of TCM sessions associated wth this TPG */
|
||||
struct list_head tpg_sess_list;
|
||||
/* Pointer to $FABRIC_MOD dependent code */
|
||||
struct target_core_fabric_ops *se_tpg_tfo;
|
||||
const struct target_core_fabric_ops *se_tpg_tfo;
|
||||
struct se_wwn *se_tpg_wwn;
|
||||
struct config_group tpg_group;
|
||||
struct config_group *tpg_default_groups[7];
|
||||
|
@ -5,12 +5,6 @@
|
||||
#define TARGET_CORE_NAME_MAX_LEN 64
|
||||
#define TARGET_FABRIC_NAME_SIZE 32
|
||||
|
||||
extern struct target_fabric_configfs *target_fabric_configfs_init(
|
||||
struct module *, const char *);
|
||||
extern void target_fabric_configfs_free(struct target_fabric_configfs *);
|
||||
extern int target_fabric_configfs_register(struct target_fabric_configfs *);
|
||||
extern void target_fabric_configfs_deregister(struct target_fabric_configfs *);
|
||||
|
||||
struct target_fabric_configfs_template {
|
||||
struct config_item_type tfc_discovery_cit;
|
||||
struct config_item_type tfc_wwn_cit;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define TARGET_CORE_FABRIC_H
|
||||
|
||||
struct target_core_fabric_ops {
|
||||
struct module *module;
|
||||
const char *name;
|
||||
struct configfs_subsystem *tf_subsys;
|
||||
char *(*get_fabric_name)(void);
|
||||
u8 (*get_fabric_proto_ident)(struct se_portal_group *);
|
||||
@ -27,6 +29,14 @@ struct target_core_fabric_ops {
|
||||
* inquiry response
|
||||
*/
|
||||
int (*tpg_check_demo_mode_login_only)(struct se_portal_group *);
|
||||
/*
|
||||
* Optionally used as a configfs tunable to determine when
|
||||
* target-core should signal the PROTECT=1 feature bit for
|
||||
* backends that don't support T10-PI, so that either fabric
|
||||
* HW offload or target-core emulation performs the associated
|
||||
* WRITE_STRIP and READ_INSERT operations.
|
||||
*/
|
||||
int (*tpg_check_prot_fabric_only)(struct se_portal_group *);
|
||||
struct se_node_acl *(*tpg_alloc_fabric_acl)(
|
||||
struct se_portal_group *);
|
||||
void (*tpg_release_fabric_acl)(struct se_portal_group *,
|
||||
@ -82,8 +92,23 @@ struct target_core_fabric_ops {
|
||||
struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *,
|
||||
struct config_group *, const char *);
|
||||
void (*fabric_drop_nodeacl)(struct se_node_acl *);
|
||||
|
||||
struct configfs_attribute **tfc_discovery_attrs;
|
||||
struct configfs_attribute **tfc_wwn_attrs;
|
||||
struct configfs_attribute **tfc_tpg_base_attrs;
|
||||
struct configfs_attribute **tfc_tpg_np_base_attrs;
|
||||
struct configfs_attribute **tfc_tpg_attrib_attrs;
|
||||
struct configfs_attribute **tfc_tpg_auth_attrs;
|
||||
struct configfs_attribute **tfc_tpg_param_attrs;
|
||||
struct configfs_attribute **tfc_tpg_nacl_base_attrs;
|
||||
struct configfs_attribute **tfc_tpg_nacl_attrib_attrs;
|
||||
struct configfs_attribute **tfc_tpg_nacl_auth_attrs;
|
||||
struct configfs_attribute **tfc_tpg_nacl_param_attrs;
|
||||
};
|
||||
|
||||
int target_register_template(const struct target_core_fabric_ops *fo);
|
||||
void target_unregister_template(const struct target_core_fabric_ops *fo);
|
||||
|
||||
struct se_session *transport_init_session(enum target_prot_op);
|
||||
int transport_alloc_session_tags(struct se_session *, unsigned int,
|
||||
unsigned int);
|
||||
@ -95,13 +120,15 @@ void transport_register_session(struct se_portal_group *,
|
||||
struct se_node_acl *, struct se_session *, void *);
|
||||
void target_get_session(struct se_session *);
|
||||
void target_put_session(struct se_session *);
|
||||
ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *);
|
||||
void transport_free_session(struct se_session *);
|
||||
void target_put_nacl(struct se_node_acl *);
|
||||
void transport_deregister_session_configfs(struct se_session *);
|
||||
void transport_deregister_session(struct se_session *);
|
||||
|
||||
|
||||
void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
|
||||
void transport_init_se_cmd(struct se_cmd *,
|
||||
const struct target_core_fabric_ops *,
|
||||
struct se_session *, u32, int, int, unsigned char *);
|
||||
sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
|
||||
sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
|
||||
@ -153,8 +180,8 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
|
||||
unsigned char *, u32, int);
|
||||
int core_tpg_set_initiator_node_tag(struct se_portal_group *,
|
||||
struct se_node_acl *, const char *);
|
||||
int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *,
|
||||
struct se_portal_group *, void *, int);
|
||||
int core_tpg_register(const struct target_core_fabric_ops *,
|
||||
struct se_wwn *, struct se_portal_group *, void *, int);
|
||||
int core_tpg_deregister(struct se_portal_group *);
|
||||
|
||||
/* SAS helpers */
|
||||
|
@ -90,6 +90,11 @@ static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
|
||||
_fabric##_tpg_store_##_name);
|
||||
|
||||
|
||||
#define TF_TPG_BASE_ATTR_RO(_fabric, _name) \
|
||||
static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
|
||||
__CONFIGFS_EATTR_RO(_name, \
|
||||
_fabric##_tpg_show_##_name);
|
||||
|
||||
CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs);
|
||||
#define TF_WWN_ATTR(_fabric, _name, _mode) \
|
||||
static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#define TCMU_VERSION "1.0"
|
||||
#define TCMU_VERSION "2.0"
|
||||
|
||||
/*
|
||||
* Ring Design
|
||||
@ -39,9 +39,13 @@
|
||||
* should process the next packet the same way, and so on.
|
||||
*/
|
||||
|
||||
#define TCMU_MAILBOX_VERSION 1
|
||||
#define TCMU_MAILBOX_VERSION 2
|
||||
#define ALIGN_SIZE 64 /* Should be enough for most CPUs */
|
||||
|
||||
/* See https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
struct tcmu_mailbox {
|
||||
__u16 version;
|
||||
__u16 flags;
|
||||
@ -64,31 +68,36 @@ enum tcmu_opcode {
|
||||
* Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode.
|
||||
*/
|
||||
struct tcmu_cmd_entry_hdr {
|
||||
__u32 len_op;
|
||||
__u32 len_op;
|
||||
__u16 cmd_id;
|
||||
__u8 kflags;
|
||||
#define TCMU_UFLAG_UNKNOWN_OP 0x1
|
||||
__u8 uflags;
|
||||
|
||||
} __packed;
|
||||
|
||||
#define TCMU_OP_MASK 0x7
|
||||
|
||||
static inline enum tcmu_opcode tcmu_hdr_get_op(struct tcmu_cmd_entry_hdr *hdr)
|
||||
static inline enum tcmu_opcode tcmu_hdr_get_op(__u32 len_op)
|
||||
{
|
||||
return hdr->len_op & TCMU_OP_MASK;
|
||||
return len_op & TCMU_OP_MASK;
|
||||
}
|
||||
|
||||
static inline void tcmu_hdr_set_op(struct tcmu_cmd_entry_hdr *hdr, enum tcmu_opcode op)
|
||||
static inline void tcmu_hdr_set_op(__u32 *len_op, enum tcmu_opcode op)
|
||||
{
|
||||
hdr->len_op &= ~TCMU_OP_MASK;
|
||||
hdr->len_op |= (op & TCMU_OP_MASK);
|
||||
*len_op &= ~TCMU_OP_MASK;
|
||||
*len_op |= (op & TCMU_OP_MASK);
|
||||
}
|
||||
|
||||
static inline __u32 tcmu_hdr_get_len(struct tcmu_cmd_entry_hdr *hdr)
|
||||
static inline __u32 tcmu_hdr_get_len(__u32 len_op)
|
||||
{
|
||||
return hdr->len_op & ~TCMU_OP_MASK;
|
||||
return len_op & ~TCMU_OP_MASK;
|
||||
}
|
||||
|
||||
static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len)
|
||||
static inline void tcmu_hdr_set_len(__u32 *len_op, __u32 len)
|
||||
{
|
||||
hdr->len_op &= TCMU_OP_MASK;
|
||||
hdr->len_op |= len;
|
||||
*len_op &= TCMU_OP_MASK;
|
||||
*len_op |= len;
|
||||
}
|
||||
|
||||
/* Currently the same as SCSI_SENSE_BUFFERSIZE */
|
||||
@ -97,13 +106,14 @@ static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len)
|
||||
struct tcmu_cmd_entry {
|
||||
struct tcmu_cmd_entry_hdr hdr;
|
||||
|
||||
uint16_t cmd_id;
|
||||
uint16_t __pad1;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t iov_cnt;
|
||||
uint32_t iov_bidi_cnt;
|
||||
uint32_t iov_dif_cnt;
|
||||
uint64_t cdb_off;
|
||||
uint64_t iov_cnt;
|
||||
uint64_t __pad1;
|
||||
uint64_t __pad2;
|
||||
struct iovec iov[0];
|
||||
} req;
|
||||
struct {
|
||||
|
Loading…
Reference in New Issue
Block a user