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 + "_base.h\"\n"
|
||||||
buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
|
buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
|
||||||
|
|
||||||
buf += "/* Local pointer to allocated TCM configfs fabric module */\n"
|
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n"
|
||||||
buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n"
|
|
||||||
|
|
||||||
buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
|
buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
|
||||||
buf += " struct se_portal_group *se_tpg,\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 += " }\n"
|
||||||
buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
|
buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
|
||||||
buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\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 += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
|
||||||
buf += " &tpg->se_tpg, (void *)tpg,\n"
|
buf += " &tpg->se_tpg, tpg,\n"
|
||||||
buf += " TRANSPORT_TPG_TYPE_NORMAL);\n"
|
buf += " TRANSPORT_TPG_TYPE_NORMAL);\n"
|
||||||
buf += " if (ret < 0) {\n"
|
buf += " if (ret < 0) {\n"
|
||||||
buf += " kfree(tpg);\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 += " NULL,\n"
|
||||||
buf += "};\n\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_name = " + fabric_mod_name + "_get_fabric_name,\n"
|
||||||
buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\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"
|
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_drop_np = NULL,\n"
|
||||||
buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n"
|
buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n"
|
||||||
buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n"
|
buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n"
|
||||||
buf += "};\n\n"
|
buf += "\n"
|
||||||
|
buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\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\n"
|
buf += "};\n\n"
|
||||||
|
|
||||||
buf += "static int __init " + fabric_mod_name + "_init(void)\n"
|
buf += "static int __init " + fabric_mod_name + "_init(void)\n"
|
||||||
buf += "{\n"
|
buf += "{\n"
|
||||||
buf += " int ret;\n\n"
|
buf += " return target_register_template(" + fabric_mod_name + "_ops);\n"
|
||||||
buf += " ret = " + fabric_mod_name + "_register_configfs();\n"
|
|
||||||
buf += " if (ret < 0)\n"
|
|
||||||
buf += " return ret;\n\n"
|
|
||||||
buf += " return 0;\n"
|
|
||||||
buf += "};\n\n"
|
buf += "};\n\n"
|
||||||
|
|
||||||
buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
|
buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
|
||||||
buf += "{\n"
|
buf += "{\n"
|
||||||
buf += " " + fabric_mod_name + "_deregister_configfs();\n"
|
buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n"
|
||||||
buf += "};\n\n"
|
buf += "};\n\n"
|
||||||
|
|
||||||
buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\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
|
cmd_tail, the ring is empty -- no commands are currently waiting to be
|
||||||
processed by userspace.
|
processed by userspace.
|
||||||
|
|
||||||
TCMU commands start with a common header containing "len_op", a 32-bit
|
TCMU commands are 8-byte aligned. They start with a common header
|
||||||
value that stores the length, as well as the opcode in the lowest
|
containing "len_op", a 32-bit value that stores the length, as well as
|
||||||
unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and
|
the opcode in the lowest unused bits. It also contains cmd_id and
|
||||||
TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it
|
flags fields for setting by the kernel (kflags) and userspace
|
||||||
should skip ahead by the bytes in "length". (The kernel inserts PAD
|
(uflags).
|
||||||
entries to ensure each CMD entry fits contigously into the circular
|
|
||||||
buffer.)
|
|
||||||
|
|
||||||
When userspace handles a CMD, it finds the SCSI CDB (Command Data
|
Currently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD.
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
When completing a command, userspace sets rsp.scsi_status, and
|
||||||
rsp.sense_buffer if necessary. Userspace then increments
|
rsp.sense_buffer if necessary. Userspace then increments
|
||||||
mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the
|
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.
|
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:
|
The Data Area:
|
||||||
|
|
||||||
This is shared-memory space after the command ring. The organization
|
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...) \
|
#define isert_err(fmt, arg...) \
|
||||||
pr_err(PFX "%s: " fmt, __func__ , ## arg)
|
pr_err(PFX "%s: " fmt, __func__ , ## arg)
|
||||||
|
|
||||||
#define ISERT_RDMA_LISTEN_BACKLOG 10
|
|
||||||
#define ISCSI_ISER_SG_TABLESIZE 256
|
#define ISCSI_ISER_SG_TABLESIZE 256
|
||||||
#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
|
#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
|
||||||
#define ISER_BEACON_WRID 0xfffffffffffffffeULL
|
#define ISER_BEACON_WRID 0xfffffffffffffffeULL
|
||||||
|
@ -160,27 +159,25 @@ struct isert_conn {
|
||||||
u64 login_req_dma;
|
u64 login_req_dma;
|
||||||
int login_req_len;
|
int login_req_len;
|
||||||
u64 login_rsp_dma;
|
u64 login_rsp_dma;
|
||||||
unsigned int conn_rx_desc_head;
|
unsigned int rx_desc_head;
|
||||||
struct iser_rx_desc *conn_rx_descs;
|
struct iser_rx_desc *rx_descs;
|
||||||
struct ib_recv_wr conn_rx_wr[ISERT_MIN_POSTED_RX];
|
struct ib_recv_wr rx_wr[ISERT_MIN_POSTED_RX];
|
||||||
struct iscsi_conn *conn;
|
struct iscsi_conn *conn;
|
||||||
struct list_head conn_accept_node;
|
struct list_head accept_node;
|
||||||
struct completion conn_login_comp;
|
struct completion login_comp;
|
||||||
struct completion login_req_comp;
|
struct completion login_req_comp;
|
||||||
struct iser_tx_desc conn_login_tx_desc;
|
struct iser_tx_desc login_tx_desc;
|
||||||
struct rdma_cm_id *conn_cm_id;
|
struct rdma_cm_id *cm_id;
|
||||||
struct ib_pd *conn_pd;
|
struct ib_qp *qp;
|
||||||
struct ib_mr *conn_mr;
|
struct isert_device *device;
|
||||||
struct ib_qp *conn_qp;
|
struct mutex mutex;
|
||||||
struct isert_device *conn_device;
|
struct completion wait;
|
||||||
struct mutex conn_mutex;
|
struct completion wait_comp_err;
|
||||||
struct completion conn_wait;
|
struct kref kref;
|
||||||
struct completion conn_wait_comp_err;
|
struct list_head fr_pool;
|
||||||
struct kref conn_kref;
|
int fr_pool_size;
|
||||||
struct list_head conn_fr_pool;
|
|
||||||
int conn_fr_pool_size;
|
|
||||||
/* lock to protect fastreg pool */
|
/* lock to protect fastreg pool */
|
||||||
spinlock_t conn_lock;
|
spinlock_t pool_lock;
|
||||||
struct work_struct release_work;
|
struct work_struct release_work;
|
||||||
struct ib_recv_wr beacon;
|
struct ib_recv_wr beacon;
|
||||||
bool logout_posted;
|
bool logout_posted;
|
||||||
|
@ -211,6 +208,8 @@ struct isert_device {
|
||||||
bool pi_capable;
|
bool pi_capable;
|
||||||
int refcount;
|
int refcount;
|
||||||
struct ib_device *ib_device;
|
struct ib_device *ib_device;
|
||||||
|
struct ib_pd *pd;
|
||||||
|
struct ib_mr *mr;
|
||||||
struct isert_comp *comps;
|
struct isert_comp *comps;
|
||||||
int comps_used;
|
int comps_used;
|
||||||
struct list_head dev_node;
|
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.");
|
" instead of using the node_guid of the first HCA.");
|
||||||
|
|
||||||
static struct ib_client srpt_client;
|
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 void srpt_release_channel(struct srpt_rdma_ch *ch);
|
||||||
static int srpt_queue_status(struct se_cmd *cmd);
|
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;
|
int res;
|
||||||
|
|
||||||
/* Initialize sport->port_wwn and sport->port_tpg_1 */
|
/* 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);
|
&sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (res)
|
if (res)
|
||||||
return ERR_PTR(res);
|
return ERR_PTR(res);
|
||||||
|
@ -3913,7 +3913,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = {
|
||||||
NULL,
|
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_name = srpt_get_fabric_name,
|
||||||
.get_fabric_proto_ident = srpt_get_fabric_proto_ident,
|
.get_fabric_proto_ident = srpt_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = srpt_get_fabric_wwn,
|
.tpg_get_wwn = srpt_get_fabric_wwn,
|
||||||
|
@ -3958,6 +3960,10 @@ static struct target_core_fabric_ops srpt_template = {
|
||||||
.fabric_drop_np = NULL,
|
.fabric_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = srpt_make_nodeacl,
|
.fabric_make_nodeacl = srpt_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = srpt_drop_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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt");
|
ret = target_register_template(&srpt_template);
|
||||||
if (IS_ERR(srpt_target)) {
|
if (ret)
|
||||||
pr_err("couldn't register\n");
|
|
||||||
ret = PTR_ERR(srpt_target);
|
|
||||||
goto out;
|
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);
|
ret = ib_register_client(&srpt_client);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -4025,11 +4007,7 @@ static int __init srpt_init_module(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_unregister_target:
|
out_unregister_target:
|
||||||
target_fabric_configfs_deregister(srpt_target);
|
target_unregister_template(&srpt_template);
|
||||||
srpt_target = NULL;
|
|
||||||
out_free_target:
|
|
||||||
if (srpt_target)
|
|
||||||
target_fabric_configfs_free(srpt_target);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -4037,8 +4015,7 @@ out:
|
||||||
static void __exit srpt_cleanup_module(void)
|
static void __exit srpt_cleanup_module(void)
|
||||||
{
|
{
|
||||||
ib_unregister_client(&srpt_client);
|
ib_unregister_client(&srpt_client);
|
||||||
target_fabric_configfs_deregister(srpt_target);
|
target_unregister_template(&srpt_template);
|
||||||
srpt_target = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(srpt_init_module);
|
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 qla_hw_data *ha = vha->hw;
|
||||||
struct se_cmd *se_cmd;
|
struct se_cmd *se_cmd;
|
||||||
struct target_core_fabric_ops *tfo;
|
const struct target_core_fabric_ops *tfo;
|
||||||
struct qla_tgt_cmd *cmd;
|
struct qla_tgt_cmd *cmd;
|
||||||
|
|
||||||
if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) {
|
if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) {
|
||||||
|
|
|
@ -53,9 +53,8 @@
|
||||||
static struct workqueue_struct *tcm_qla2xxx_free_wq;
|
static struct workqueue_struct *tcm_qla2xxx_free_wq;
|
||||||
static struct workqueue_struct *tcm_qla2xxx_cmd_wq;
|
static struct workqueue_struct *tcm_qla2xxx_cmd_wq;
|
||||||
|
|
||||||
/* Local pointer to allocated TCM configfs fabric module */
|
static const struct target_core_fabric_ops tcm_qla2xxx_ops;
|
||||||
static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
|
static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops;
|
||||||
static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse WWN.
|
* 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;
|
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(
|
static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl(
|
||||||
struct se_portal_group *se_tpg)
|
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);
|
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[] = {
|
static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = {
|
||||||
&tcm_qla2xxx_tpg_enable.attr,
|
&tcm_qla2xxx_tpg_enable.attr,
|
||||||
|
&tcm_qla2xxx_tpg_dynamic_sessions.attr,
|
||||||
|
&tcm_qla2xxx_tpg_fabric_prot_type.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1124,7 +1176,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
|
||||||
tpg->tpg_attrib.cache_dynamic_acls = 1;
|
tpg->tpg_attrib.cache_dynamic_acls = 1;
|
||||||
tpg->tpg_attrib.demo_mode_login_only = 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);
|
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(tpg);
|
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.cache_dynamic_acls = 1;
|
||||||
tpg->tpg_attrib.demo_mode_login_only = 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);
|
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(tpg);
|
kfree(tpg);
|
||||||
|
@ -1560,7 +1612,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
|
||||||
|
|
||||||
se_sess = transport_init_session_tags(num_tags,
|
se_sess = transport_init_session_tags(num_tags,
|
||||||
sizeof(struct qla_tgt_cmd),
|
sizeof(struct qla_tgt_cmd),
|
||||||
TARGET_PROT_NORMAL);
|
TARGET_PROT_ALL);
|
||||||
if (IS_ERR(se_sess)) {
|
if (IS_ERR(se_sess)) {
|
||||||
pr_err("Unable to initialize struct se_session\n");
|
pr_err("Unable to initialize struct se_session\n");
|
||||||
return PTR_ERR(se_sess);
|
return PTR_ERR(se_sess);
|
||||||
|
@ -1934,7 +1986,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
|
||||||
NULL,
|
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_name = tcm_qla2xxx_get_fabric_name,
|
||||||
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
|
.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,
|
tcm_qla2xxx_check_demo_write_protect,
|
||||||
.tpg_check_prod_mode_write_protect =
|
.tpg_check_prod_mode_write_protect =
|
||||||
tcm_qla2xxx_check_prod_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_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
|
||||||
.tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl,
|
.tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl,
|
||||||
.tpg_release_fabric_acl = tcm_qla2xxx_release_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_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = tcm_qla2xxx_drop_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_name = tcm_qla2xxx_npiv_get_fabric_name,
|
||||||
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
|
.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_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = tcm_qla2xxx_drop_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)
|
static int tcm_qla2xxx_register_configfs(void)
|
||||||
{
|
{
|
||||||
struct target_fabric_configfs *fabric, *npiv_fabric;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
|
pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
|
||||||
UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
|
UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
|
||||||
utsname()->machine);
|
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");
|
|
||||||
|
|
||||||
/*
|
ret = target_register_template(&tcm_qla2xxx_ops);
|
||||||
* Register the top level struct config_item_type for NPIV with TCM core
|
if (ret)
|
||||||
*/
|
return ret;
|
||||||
npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv");
|
|
||||||
if (IS_ERR(npiv_fabric)) {
|
ret = target_register_template(&tcm_qla2xxx_npiv_ops);
|
||||||
pr_err("target_fabric_configfs_init() failed\n");
|
if (ret)
|
||||||
ret = PTR_ERR(npiv_fabric);
|
|
||||||
goto out_fabric;
|
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",
|
tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free",
|
||||||
WQ_MEM_RECLAIM, 0);
|
WQ_MEM_RECLAIM, 0);
|
||||||
|
@ -2140,9 +2133,9 @@ static int tcm_qla2xxx_register_configfs(void)
|
||||||
out_free_wq:
|
out_free_wq:
|
||||||
destroy_workqueue(tcm_qla2xxx_free_wq);
|
destroy_workqueue(tcm_qla2xxx_free_wq);
|
||||||
out_fabric_npiv:
|
out_fabric_npiv:
|
||||||
target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
|
target_unregister_template(&tcm_qla2xxx_npiv_ops);
|
||||||
out_fabric:
|
out_fabric:
|
||||||
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
|
target_unregister_template(&tcm_qla2xxx_ops);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2151,13 +2144,8 @@ static void tcm_qla2xxx_deregister_configfs(void)
|
||||||
destroy_workqueue(tcm_qla2xxx_cmd_wq);
|
destroy_workqueue(tcm_qla2xxx_cmd_wq);
|
||||||
destroy_workqueue(tcm_qla2xxx_free_wq);
|
destroy_workqueue(tcm_qla2xxx_free_wq);
|
||||||
|
|
||||||
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
|
target_unregister_template(&tcm_qla2xxx_ops);
|
||||||
tcm_qla2xxx_fabric_configfs = NULL;
|
target_unregister_template(&tcm_qla2xxx_npiv_ops);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init tcm_qla2xxx_init(void)
|
static int __init tcm_qla2xxx_init(void)
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct tcm_qla2xxx_tpg_attrib {
|
||||||
int demo_mode_write_protect;
|
int demo_mode_write_protect;
|
||||||
int prod_mode_write_protect;
|
int prod_mode_write_protect;
|
||||||
int demo_mode_login_only;
|
int demo_mode_login_only;
|
||||||
|
int fabric_prot_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcm_qla2xxx_tpg {
|
struct tcm_qla2xxx_tpg {
|
||||||
|
|
|
@ -31,12 +31,13 @@ config TCM_PSCSI
|
||||||
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
|
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
|
||||||
passthrough access to Linux/SCSI device
|
passthrough access to Linux/SCSI device
|
||||||
|
|
||||||
config TCM_USER
|
config TCM_USER2
|
||||||
tristate "TCM/USER Subsystem Plugin for Linux"
|
tristate "TCM/USER Subsystem Plugin for Linux"
|
||||||
depends on UIO && NET
|
depends on UIO && NET
|
||||||
help
|
help
|
||||||
Say Y here to enable the TCM/USER subsystem plugin for a userspace
|
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/loopback/Kconfig"
|
||||||
source "drivers/target/tcm_fc/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_IBLOCK) += target_core_iblock.o
|
||||||
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
|
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
|
||||||
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.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
|
# Fabric modules
|
||||||
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
|
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
iscsi_target_mod-y += iscsi_target_parameters.o \
|
iscsi_target_mod-y += iscsi_target_parameters.o \
|
||||||
iscsi_target_seq_pdu_list.o \
|
iscsi_target_seq_pdu_list.o \
|
||||||
iscsi_target_tq.o \
|
|
||||||
iscsi_target_auth.o \
|
iscsi_target_auth.o \
|
||||||
iscsi_target_datain_values.o \
|
iscsi_target_datain_values.o \
|
||||||
iscsi_target_device.o \
|
iscsi_target_device.o \
|
||||||
|
|
|
@ -33,8 +33,6 @@
|
||||||
#include <target/iscsi/iscsi_target_core.h>
|
#include <target/iscsi/iscsi_target_core.h>
|
||||||
#include "iscsi_target_parameters.h"
|
#include "iscsi_target_parameters.h"
|
||||||
#include "iscsi_target_seq_pdu_list.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_datain_values.h"
|
||||||
#include "iscsi_target_erl0.h"
|
#include "iscsi_target_erl0.h"
|
||||||
#include "iscsi_target_erl1.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)
|
static int __init iscsi_target_init_module(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0, size;
|
||||||
|
|
||||||
pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
|
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");
|
pr_err("Unable to allocate memory for iscsit_global\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
spin_lock_init(&iscsit_global->ts_bitmap_lock);
|
||||||
mutex_init(&auth_id_lock);
|
mutex_init(&auth_id_lock);
|
||||||
spin_lock_init(&sess_idr_lock);
|
spin_lock_init(&sess_idr_lock);
|
||||||
idr_init(&tiqn_idr);
|
idr_init(&tiqn_idr);
|
||||||
idr_init(&sess_idr);
|
idr_init(&sess_idr);
|
||||||
|
|
||||||
ret = iscsi_target_register_configfs();
|
ret = target_register_template(&iscsi_ops);
|
||||||
if (ret < 0)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = iscsi_thread_set_init();
|
size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
|
||||||
if (ret < 0)
|
iscsit_global->ts_bitmap = vzalloc(size);
|
||||||
|
if (!iscsit_global->ts_bitmap) {
|
||||||
|
pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
|
||||||
goto configfs_out;
|
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",
|
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) {
|
if (!lio_qr_cache) {
|
||||||
pr_err("nable to kmem_cache_create() for"
|
pr_err("nable to kmem_cache_create() for"
|
||||||
" lio_qr_cache\n");
|
" lio_qr_cache\n");
|
||||||
goto ts_out2;
|
goto bitmap_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
lio_dr_cache = kmem_cache_create("lio_dr_cache",
|
lio_dr_cache = kmem_cache_create("lio_dr_cache",
|
||||||
|
@ -617,12 +612,13 @@ dr_out:
|
||||||
kmem_cache_destroy(lio_dr_cache);
|
kmem_cache_destroy(lio_dr_cache);
|
||||||
qr_out:
|
qr_out:
|
||||||
kmem_cache_destroy(lio_qr_cache);
|
kmem_cache_destroy(lio_qr_cache);
|
||||||
ts_out2:
|
bitmap_out:
|
||||||
iscsi_deallocate_thread_sets();
|
vfree(iscsit_global->ts_bitmap);
|
||||||
ts_out1:
|
|
||||||
iscsi_thread_set_free();
|
|
||||||
configfs_out:
|
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:
|
out:
|
||||||
kfree(iscsit_global);
|
kfree(iscsit_global);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -630,8 +626,6 @@ out:
|
||||||
|
|
||||||
static void __exit iscsi_target_cleanup_module(void)
|
static void __exit iscsi_target_cleanup_module(void)
|
||||||
{
|
{
|
||||||
iscsi_deallocate_thread_sets();
|
|
||||||
iscsi_thread_set_free();
|
|
||||||
iscsit_release_discovery_tpg();
|
iscsit_release_discovery_tpg();
|
||||||
iscsit_unregister_transport(&iscsi_target_transport);
|
iscsit_unregister_transport(&iscsi_target_transport);
|
||||||
kmem_cache_destroy(lio_qr_cache);
|
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_ooo_cache);
|
||||||
kmem_cache_destroy(lio_r2t_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);
|
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
|
* 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),
|
conn->sess->se_sess, be32_to_cpu(hdr->data_length),
|
||||||
cmd->data_direction, sam_task_attr,
|
cmd->data_direction, sam_task_attr,
|
||||||
cmd->sense_buffer + 2);
|
cmd->sense_buffer + 2);
|
||||||
|
@ -1805,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
||||||
u8 tcm_function;
|
u8 tcm_function;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
transport_init_se_cmd(&cmd->se_cmd,
|
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
|
||||||
&lio_target_fabric_configfs->tf_ops,
|
|
||||||
conn->sess->se_sess, 0, DMA_NONE,
|
conn->sess->se_sess, 0, DMA_NONE,
|
||||||
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
|
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
|
||||||
|
|
||||||
|
@ -2155,7 +2155,6 @@ reject:
|
||||||
cmd->text_in_ptr = NULL;
|
cmd->text_in_ptr = NULL;
|
||||||
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
|
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)
|
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)
|
void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
|
||||||
{
|
{
|
||||||
struct iscsi_thread_set *ts = conn->thread_set;
|
|
||||||
int ord, cpu;
|
int ord, cpu;
|
||||||
/*
|
/*
|
||||||
* thread_id is assigned from iscsit_global->ts_bitmap from
|
* bitmap_id is assigned from iscsit_global->ts_bitmap from
|
||||||
* within iscsi_thread_set.c:iscsi_allocate_thread_sets()
|
* within iscsit_start_kthreads()
|
||||||
*
|
*
|
||||||
* Here we use thread_id to determine which CPU that this
|
* Here we use bitmap_id to determine which CPU that this
|
||||||
* iSCSI connection's iscsi_thread_set will be scheduled to
|
* iSCSI connection's RX/TX threads will be scheduled to
|
||||||
* execute upon.
|
* 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) {
|
for_each_online_cpu(cpu) {
|
||||||
if (ord-- == 0) {
|
if (ord-- == 0) {
|
||||||
cpumask_set_cpu(cpu, conn->conn_cpumask);
|
cpumask_set_cpu(cpu, conn->conn_cpumask);
|
||||||
|
@ -3914,7 +3912,7 @@ check_rsp_state:
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ISTATE_SEND_LOGOUTRSP:
|
case ISTATE_SEND_LOGOUTRSP:
|
||||||
if (!iscsit_logout_post_handler(cmd, conn))
|
if (!iscsit_logout_post_handler(cmd, conn))
|
||||||
goto restart;
|
return -ECONNRESET;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case ISTATE_SEND_STATUS:
|
case ISTATE_SEND_STATUS:
|
||||||
case ISTATE_SEND_ASYNCMSG:
|
case ISTATE_SEND_ASYNCMSG:
|
||||||
|
@ -3942,8 +3940,6 @@ check_rsp_state:
|
||||||
|
|
||||||
err:
|
err:
|
||||||
return -1;
|
return -1;
|
||||||
restart:
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iscsit_handle_response_queue(struct iscsi_conn *conn)
|
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 iscsi_target_tx_thread(void *arg)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct iscsi_conn *conn;
|
struct iscsi_conn *conn = arg;
|
||||||
struct iscsi_thread_set *ts = arg;
|
|
||||||
/*
|
/*
|
||||||
* Allow ourselves to be interrupted by SIGINT so that a
|
* Allow ourselves to be interrupted by SIGINT so that a
|
||||||
* connection recovery / failure event can be triggered externally.
|
* connection recovery / failure event can be triggered externally.
|
||||||
*/
|
*/
|
||||||
allow_signal(SIGINT);
|
allow_signal(SIGINT);
|
||||||
|
|
||||||
restart:
|
|
||||||
conn = iscsi_tx_thread_pre_handler(ts);
|
|
||||||
if (!conn)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
/*
|
/*
|
||||||
* Ensure that both TX and RX per connection kthreads
|
* Ensure that both TX and RX per connection kthreads
|
||||||
|
@ -3993,11 +3981,9 @@ restart:
|
||||||
iscsit_thread_check_cpumask(conn, current, 1);
|
iscsit_thread_check_cpumask(conn, current, 1);
|
||||||
|
|
||||||
wait_event_interruptible(conn->queues_wq,
|
wait_event_interruptible(conn->queues_wq,
|
||||||
!iscsit_conn_all_queues_empty(conn) ||
|
!iscsit_conn_all_queues_empty(conn));
|
||||||
ts->status == ISCSI_THREAD_SET_RESET);
|
|
||||||
|
|
||||||
if ((ts->status == ISCSI_THREAD_SET_RESET) ||
|
if (signal_pending(current))
|
||||||
signal_pending(current))
|
|
||||||
goto transport_err;
|
goto transport_err;
|
||||||
|
|
||||||
get_immediate:
|
get_immediate:
|
||||||
|
@ -4008,15 +3994,14 @@ get_immediate:
|
||||||
ret = iscsit_handle_response_queue(conn);
|
ret = iscsit_handle_response_queue(conn);
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
goto get_immediate;
|
goto get_immediate;
|
||||||
else if (ret == -EAGAIN)
|
else if (ret == -ECONNRESET)
|
||||||
goto restart;
|
goto out;
|
||||||
else if (ret < 0)
|
else if (ret < 0)
|
||||||
goto transport_err;
|
goto transport_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
transport_err:
|
transport_err:
|
||||||
iscsit_take_action_for_connection_exit(conn);
|
iscsit_take_action_for_connection_exit(conn);
|
||||||
goto restart;
|
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4111,8 +4096,7 @@ int iscsi_target_rx_thread(void *arg)
|
||||||
int ret;
|
int ret;
|
||||||
u8 buffer[ISCSI_HDR_LEN], opcode;
|
u8 buffer[ISCSI_HDR_LEN], opcode;
|
||||||
u32 checksum = 0, digest = 0;
|
u32 checksum = 0, digest = 0;
|
||||||
struct iscsi_conn *conn = NULL;
|
struct iscsi_conn *conn = arg;
|
||||||
struct iscsi_thread_set *ts = arg;
|
|
||||||
struct kvec iov;
|
struct kvec iov;
|
||||||
/*
|
/*
|
||||||
* Allow ourselves to be interrupted by SIGINT so that a
|
* Allow ourselves to be interrupted by SIGINT so that a
|
||||||
|
@ -4120,11 +4104,6 @@ int iscsi_target_rx_thread(void *arg)
|
||||||
*/
|
*/
|
||||||
allow_signal(SIGINT);
|
allow_signal(SIGINT);
|
||||||
|
|
||||||
restart:
|
|
||||||
conn = iscsi_rx_thread_pre_handler(ts);
|
|
||||||
if (!conn)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
|
if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
|
||||||
struct completion comp;
|
struct completion comp;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -4134,7 +4113,7 @@ restart:
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto transport_err;
|
goto transport_err;
|
||||||
|
|
||||||
goto out;
|
goto transport_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
|
@ -4210,8 +4189,6 @@ transport_err:
|
||||||
if (!signal_pending(current))
|
if (!signal_pending(current))
|
||||||
atomic_set(&conn->transport_failed, 1);
|
atomic_set(&conn->transport_failed, 1);
|
||||||
iscsit_take_action_for_connection_exit(conn);
|
iscsit_take_action_for_connection_exit(conn);
|
||||||
goto restart;
|
|
||||||
out:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4273,7 +4250,24 @@ int iscsit_close_connection(
|
||||||
if (conn->conn_transport->transport_type == ISCSI_TCP)
|
if (conn->conn_transport->transport_type == ISCSI_TCP)
|
||||||
complete(&conn->conn_logout_comp);
|
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_timers_for_cmds(conn);
|
||||||
iscsit_stop_nopin_response_timer(conn);
|
iscsit_stop_nopin_response_timer(conn);
|
||||||
|
@ -4383,8 +4377,6 @@ int iscsit_close_connection(
|
||||||
|
|
||||||
iscsit_put_transport(conn->conn_transport);
|
iscsit_put_transport(conn->conn_transport);
|
||||||
|
|
||||||
conn->thread_set = NULL;
|
|
||||||
|
|
||||||
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
|
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
|
||||||
conn->conn_state = TARG_CONN_STATE_FREE;
|
conn->conn_state = TARG_CONN_STATE_FREE;
|
||||||
kfree(conn);
|
kfree(conn);
|
||||||
|
@ -4551,15 +4543,13 @@ static void iscsit_logout_post_handler_closesession(
|
||||||
struct iscsi_conn *conn)
|
struct iscsi_conn *conn)
|
||||||
{
|
{
|
||||||
struct iscsi_session *sess = conn->sess;
|
struct iscsi_session *sess = conn->sess;
|
||||||
|
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
|
||||||
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
|
|
||||||
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
|
|
||||||
|
|
||||||
atomic_set(&conn->conn_logout_remove, 0);
|
atomic_set(&conn->conn_logout_remove, 0);
|
||||||
complete(&conn->conn_logout_comp);
|
complete(&conn->conn_logout_comp);
|
||||||
|
|
||||||
iscsit_dec_conn_usage_count(conn);
|
iscsit_dec_conn_usage_count(conn);
|
||||||
iscsit_stop_session(sess, 1, 1);
|
iscsit_stop_session(sess, sleep, sleep);
|
||||||
iscsit_dec_session_usage_count(sess);
|
iscsit_dec_session_usage_count(sess);
|
||||||
target_put_session(sess->se_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(
|
static void iscsit_logout_post_handler_samecid(
|
||||||
struct iscsi_conn *conn)
|
struct iscsi_conn *conn)
|
||||||
{
|
{
|
||||||
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
|
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
|
||||||
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
|
|
||||||
|
|
||||||
atomic_set(&conn->conn_logout_remove, 0);
|
atomic_set(&conn->conn_logout_remove, 0);
|
||||||
complete(&conn->conn_logout_comp);
|
complete(&conn->conn_logout_comp);
|
||||||
|
|
||||||
iscsit_cause_connection_reinstatement(conn, 1);
|
iscsit_cause_connection_reinstatement(conn, sleep);
|
||||||
iscsit_dec_conn_usage_count(conn);
|
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 int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
|
||||||
|
|
||||||
extern struct iscsit_global *iscsit_global;
|
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_dr_cache;
|
||||||
extern struct kmem_cache *lio_ooo_cache;
|
extern struct kmem_cache *lio_ooo_cache;
|
||||||
|
|
|
@ -37,9 +37,6 @@
|
||||||
#include "iscsi_target_util.h"
|
#include "iscsi_target_util.h"
|
||||||
#include "iscsi_target.h"
|
#include "iscsi_target.h"
|
||||||
#include <target/iscsi/iscsi_target_stat.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 lio_target_configfs_attribute {
|
||||||
struct configfs_attribute attr;
|
struct configfs_attribute attr;
|
||||||
|
@ -1052,6 +1049,11 @@ TPG_ATTR(default_erl, S_IRUGO | S_IWUSR);
|
||||||
*/
|
*/
|
||||||
DEF_TPG_ATTRIB(t10_pi);
|
DEF_TPG_ATTRIB(t10_pi);
|
||||||
TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR);
|
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[] = {
|
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||||
&iscsi_tpg_attrib_authentication.attr,
|
&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_demo_mode_discovery.attr,
|
||||||
&iscsi_tpg_attrib_default_erl.attr,
|
&iscsi_tpg_attrib_default_erl.attr,
|
||||||
&iscsi_tpg_attrib_t10_pi.attr,
|
&iscsi_tpg_attrib_t10_pi.attr,
|
||||||
|
&iscsi_tpg_attrib_fabric_prot_type.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1410,8 +1413,18 @@ out:
|
||||||
|
|
||||||
TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
|
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[] = {
|
static struct configfs_attribute *lio_target_tpg_attrs[] = {
|
||||||
&lio_target_tpg_enable.attr,
|
&lio_target_tpg_enable.attr,
|
||||||
|
&lio_target_tpg_dynamic_sessions.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1450,10 +1463,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
|
||||||
if (!tpg)
|
if (!tpg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ret = core_tpg_register(
|
ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg,
|
||||||
&lio_target_fabric_configfs->tf_ops,
|
tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
wwn, &tpg->tpg_se_tpg, tpg,
|
|
||||||
TRANSPORT_TPG_TYPE_NORMAL);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1872,6 +1883,20 @@ static int lio_tpg_check_prod_mode_write_protect(
|
||||||
return tpg->tpg_attrib.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(
|
static void lio_tpg_release_fabric_acl(
|
||||||
struct se_portal_group *se_tpg,
|
struct se_portal_group *se_tpg,
|
||||||
struct se_node_acl *se_acl)
|
struct se_node_acl *se_acl)
|
||||||
|
@ -1953,115 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
|
||||||
iscsit_release_cmd(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)
|
.tfc_discovery_attrs = lio_target_discovery_auth_attrs,
|
||||||
{
|
.tfc_wwn_attrs = lio_target_wwn_attrs,
|
||||||
struct target_fabric_configfs *fabric;
|
.tfc_tpg_base_attrs = lio_target_tpg_attrs,
|
||||||
int ret;
|
.tfc_tpg_attrib_attrs = lio_target_tpg_attrib_attrs,
|
||||||
|
.tfc_tpg_auth_attrs = lio_target_tpg_auth_attrs,
|
||||||
lio_target_fabric_configfs = NULL;
|
.tfc_tpg_param_attrs = lio_target_tpg_param_attrs,
|
||||||
fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi");
|
.tfc_tpg_np_base_attrs = lio_target_portal_attrs,
|
||||||
if (IS_ERR(fabric)) {
|
.tfc_tpg_nacl_base_attrs = lio_target_initiator_attrs,
|
||||||
pr_err("target_fabric_configfs_init() for"
|
.tfc_tpg_nacl_attrib_attrs = lio_target_nacl_attrib_attrs,
|
||||||
" LIO-Target failed!\n");
|
.tfc_tpg_nacl_auth_attrs = lio_target_nacl_auth_attrs,
|
||||||
return PTR_ERR(fabric);
|
.tfc_tpg_nacl_param_attrs = lio_target_nacl_param_attrs,
|
||||||
}
|
};
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 <target/iscsi/iscsi_target_core.h>
|
||||||
#include "iscsi_target_seq_pdu_list.h"
|
#include "iscsi_target_seq_pdu_list.h"
|
||||||
#include "iscsi_target_tq.h"
|
|
||||||
#include "iscsi_target_erl0.h"
|
#include "iscsi_target_erl0.h"
|
||||||
#include "iscsi_target_erl1.h"
|
#include "iscsi_target_erl1.h"
|
||||||
#include "iscsi_target_erl2.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);
|
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:
|
sleep:
|
||||||
wait_for_completion(&conn->conn_wait_rcfr_comp);
|
wait_for_completion(&conn->conn_wait_rcfr_comp);
|
||||||
|
@ -885,10 +887,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsi_thread_set_force_reinstatement(conn) < 0) {
|
if (conn->tx_thread && conn->tx_thread_active)
|
||||||
spin_unlock_bh(&conn->state_lock);
|
send_sig(SIGINT, conn->tx_thread, 1);
|
||||||
return;
|
if (conn->rx_thread && conn->rx_thread_active)
|
||||||
}
|
send_sig(SIGINT, conn->rx_thread, 1);
|
||||||
|
|
||||||
atomic_set(&conn->connection_reinstatement, 1);
|
atomic_set(&conn->connection_reinstatement, 1);
|
||||||
if (!sleep) {
|
if (!sleep) {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include <target/iscsi/iscsi_target_core.h>
|
#include <target/iscsi/iscsi_target_core.h>
|
||||||
#include <target/iscsi/iscsi_target_stat.h>
|
#include <target/iscsi/iscsi_target_stat.h>
|
||||||
#include "iscsi_target_tq.h"
|
|
||||||
#include "iscsi_target_device.h"
|
#include "iscsi_target_device.h"
|
||||||
#include "iscsi_target_nego.h"
|
#include "iscsi_target_nego.h"
|
||||||
#include "iscsi_target_erl0.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);
|
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(
|
int iscsi_post_login_handler(
|
||||||
struct iscsi_np *np,
|
struct iscsi_np *np,
|
||||||
struct iscsi_conn *conn,
|
struct iscsi_conn *conn,
|
||||||
|
@ -709,7 +753,7 @@ int iscsi_post_login_handler(
|
||||||
struct se_session *se_sess = sess->se_sess;
|
struct se_session *se_sess = sess->se_sess;
|
||||||
struct iscsi_portal_group *tpg = sess->tpg;
|
struct iscsi_portal_group *tpg = sess->tpg;
|
||||||
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
|
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
|
||||||
struct iscsi_thread_set *ts;
|
int rc;
|
||||||
|
|
||||||
iscsit_inc_conn_usage_count(conn);
|
iscsit_inc_conn_usage_count(conn);
|
||||||
|
|
||||||
|
@ -724,7 +768,6 @@ int iscsi_post_login_handler(
|
||||||
/*
|
/*
|
||||||
* SCSI Initiator -> SCSI Target Port Mapping
|
* SCSI Initiator -> SCSI Target Port Mapping
|
||||||
*/
|
*/
|
||||||
ts = iscsi_get_thread_set();
|
|
||||||
if (!zero_tsih) {
|
if (!zero_tsih) {
|
||||||
iscsi_set_session_parameters(sess->sess_ops,
|
iscsi_set_session_parameters(sess->sess_ops,
|
||||||
conn->param_list, 0);
|
conn->param_list, 0);
|
||||||
|
@ -751,9 +794,11 @@ int iscsi_post_login_handler(
|
||||||
sess->sess_ops->InitiatorName);
|
sess->sess_ops->InitiatorName);
|
||||||
spin_unlock_bh(&sess->conn_lock);
|
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
|
* Determine CPU mask to ensure connection's RX and TX kthreads
|
||||||
* are scheduled on the same CPU.
|
* 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);
|
" iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
|
||||||
spin_unlock_bh(&se_tpg->session_lock);
|
spin_unlock_bh(&se_tpg->session_lock);
|
||||||
|
|
||||||
|
rc = iscsit_start_kthreads(conn);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
iscsi_post_login_start_timers(conn);
|
iscsi_post_login_start_timers(conn);
|
||||||
iscsi_activate_thread_set(conn, ts);
|
|
||||||
/*
|
/*
|
||||||
* Determine CPU mask to ensure connection's RX and TX kthreads
|
* Determine CPU mask to ensure connection's RX and TX kthreads
|
||||||
* are scheduled on the same CPU.
|
* are scheduled on the same CPU.
|
||||||
|
|
|
@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = core_tpg_register(
|
ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg,
|
||||||
&lio_target_fabric_configfs->tf_ops,
|
tpg, TRANSPORT_TPG_TYPE_DISCOVERY);
|
||||||
NULL, &tpg->tpg_se_tpg, tpg,
|
|
||||||
TRANSPORT_TPG_TYPE_DISCOVERY);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(tpg);
|
kfree(tpg);
|
||||||
return -1;
|
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->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY;
|
||||||
a->default_erl = TA_DEFAULT_ERL;
|
a->default_erl = TA_DEFAULT_ERL;
|
||||||
a->t10_pi = TA_DEFAULT_T10_PI;
|
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)
|
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;
|
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_demo_mode_discovery(struct iscsi_portal_group *, u32);
|
||||||
extern int iscsit_ta_default_erl(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_t10_pi(struct iscsi_portal_group *, u32);
|
||||||
|
extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
|
||||||
|
|
||||||
#endif /* ISCSI_TARGET_TPG_H */
|
#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_erl1.h"
|
||||||
#include "iscsi_target_erl2.h"
|
#include "iscsi_target_erl2.h"
|
||||||
#include "iscsi_target_tpg.h"
|
#include "iscsi_target_tpg.h"
|
||||||
#include "iscsi_target_tq.h"
|
|
||||||
#include "iscsi_target_util.h"
|
#include "iscsi_target_util.h"
|
||||||
#include "iscsi_target.h"
|
#include "iscsi_target.h"
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev)
|
#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev)
|
||||||
|
|
||||||
/* Local pointer to allocated TCM configfs fabric module */
|
static const struct target_core_fabric_ops loop_ops;
|
||||||
static struct target_fabric_configfs *tcm_loop_fabric_configfs;
|
|
||||||
|
|
||||||
static struct workqueue_struct *tcm_loop_workqueue;
|
static struct workqueue_struct *tcm_loop_workqueue;
|
||||||
static struct kmem_cache *tcm_loop_cmd_cache;
|
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
|
* 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)
|
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;
|
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(
|
static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl(
|
||||||
struct se_portal_group *se_tpg)
|
struct se_portal_group *se_tpg)
|
||||||
{
|
{
|
||||||
|
@ -912,6 +918,46 @@ static void tcm_loop_port_unlink(
|
||||||
|
|
||||||
/* End items for tcm_loop_port_cit */
|
/* 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 */
|
/* Start items for tcm_loop_nexus_cit */
|
||||||
|
|
||||||
static int tcm_loop_make_nexus(
|
static int tcm_loop_make_nexus(
|
||||||
|
@ -937,7 +983,8 @@ static int tcm_loop_make_nexus(
|
||||||
/*
|
/*
|
||||||
* Initialize the struct se_session pointer
|
* 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)) {
|
if (IS_ERR(tl_nexus->se_sess)) {
|
||||||
ret = PTR_ERR(tl_nexus->se_sess);
|
ret = PTR_ERR(tl_nexus->se_sess);
|
||||||
goto out;
|
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 = container_of(wwn,
|
||||||
struct tcm_loop_hba, tl_hba_wwn);
|
struct tcm_loop_hba, tl_hba_wwn);
|
||||||
struct tcm_loop_tpg *tl_tpg;
|
struct tcm_loop_tpg *tl_tpg;
|
||||||
char *tpgt_str, *end_ptr;
|
|
||||||
int ret;
|
int ret;
|
||||||
unsigned short int tpgt;
|
unsigned long tpgt;
|
||||||
|
|
||||||
tpgt_str = strstr(name, "tpgt_");
|
if (strstr(name, "tpgt_") != name) {
|
||||||
if (!tpgt_str) {
|
|
||||||
pr_err("Unable to locate \"tpgt_#\" directory"
|
pr_err("Unable to locate \"tpgt_#\" directory"
|
||||||
" group\n");
|
" group\n");
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
tpgt_str += 5; /* Skip ahead of "tpgt_" */
|
if (kstrtoul(name+5, 10, &tpgt))
|
||||||
tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
if (tpgt >= TL_TPGS_PER_HBA) {
|
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);
|
" %u\n", tpgt, TL_TPGS_PER_HBA);
|
||||||
return ERR_PTR(-EINVAL);
|
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
|
* Register the tl_tpg as a emulated SAS TCM Target Endpoint
|
||||||
*/
|
*/
|
||||||
ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops,
|
ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg,
|
||||||
wwn, &tl_tpg->tl_se_tpg, tl_tpg,
|
|
||||||
TRANSPORT_TPG_TYPE_NORMAL);
|
TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s"
|
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);
|
config_item_name(&wwn->wwn_group.cg_item), tpgt);
|
||||||
|
|
||||||
return &tl_tpg->tl_se_tpg;
|
return &tl_tpg->tl_se_tpg;
|
||||||
|
@ -1338,127 +1382,51 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
|
||||||
|
|
||||||
/* End items for tcm_loop_cit */
|
/* End items for tcm_loop_cit */
|
||||||
|
|
||||||
static int tcm_loop_register_configfs(void)
|
static const struct target_core_fabric_ops loop_ops = {
|
||||||
{
|
.module = THIS_MODULE,
|
||||||
struct target_fabric_configfs *fabric;
|
.name = "loopback",
|
||||||
int ret;
|
.get_fabric_name = tcm_loop_get_fabric_name,
|
||||||
/*
|
.get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident,
|
||||||
* Set the TCM Loop HBA counter to zero
|
.tpg_get_wwn = tcm_loop_get_endpoint_wwn,
|
||||||
*/
|
.tpg_get_tag = tcm_loop_get_tag,
|
||||||
tcm_loop_hba_no_cnt = 0;
|
.tpg_get_default_depth = tcm_loop_get_default_depth,
|
||||||
/*
|
.tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id,
|
||||||
* Register the top level struct config_item_type with TCM core
|
.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,
|
||||||
fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
|
.tpg_check_demo_mode = tcm_loop_check_demo_mode,
|
||||||
if (IS_ERR(fabric)) {
|
.tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache,
|
||||||
pr_err("tcm_loop_register_configfs() failed!\n");
|
.tpg_check_demo_mode_write_protect =
|
||||||
return PTR_ERR(fabric);
|
tcm_loop_check_demo_mode_write_protect,
|
||||||
}
|
.tpg_check_prod_mode_write_protect =
|
||||||
/*
|
tcm_loop_check_prod_mode_write_protect,
|
||||||
* Setup the fabric API of function pointers used by target_core_mod
|
.tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only,
|
||||||
*/
|
.tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl,
|
||||||
fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
|
.tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl,
|
||||||
fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
|
.tpg_get_inst_index = tcm_loop_get_inst_index,
|
||||||
fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
|
.check_stop_free = tcm_loop_check_stop_free,
|
||||||
fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
|
.release_cmd = tcm_loop_release_cmd,
|
||||||
fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
|
.shutdown_session = tcm_loop_shutdown_session,
|
||||||
fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
|
.close_session = tcm_loop_close_session,
|
||||||
fabric->tf_ops.tpg_get_pr_transport_id_len =
|
.sess_get_index = tcm_loop_sess_get_index,
|
||||||
&tcm_loop_get_pr_transport_id_len;
|
.write_pending = tcm_loop_write_pending,
|
||||||
fabric->tf_ops.tpg_parse_pr_out_transport_id =
|
.write_pending_status = tcm_loop_write_pending_status,
|
||||||
&tcm_loop_parse_pr_out_transport_id;
|
.set_default_node_attributes = tcm_loop_set_default_node_attributes,
|
||||||
fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
|
.get_task_tag = tcm_loop_get_task_tag,
|
||||||
fabric->tf_ops.tpg_check_demo_mode_cache =
|
.get_cmd_state = tcm_loop_get_cmd_state,
|
||||||
&tcm_loop_check_demo_mode_cache;
|
.queue_data_in = tcm_loop_queue_data_in,
|
||||||
fabric->tf_ops.tpg_check_demo_mode_write_protect =
|
.queue_status = tcm_loop_queue_status,
|
||||||
&tcm_loop_check_demo_mode_write_protect;
|
.queue_tm_rsp = tcm_loop_queue_tm_rsp,
|
||||||
fabric->tf_ops.tpg_check_prod_mode_write_protect =
|
.aborted_task = tcm_loop_aborted_task,
|
||||||
&tcm_loop_check_prod_mode_write_protect;
|
.fabric_make_wwn = tcm_loop_make_scsi_hba,
|
||||||
/*
|
.fabric_drop_wwn = tcm_loop_drop_scsi_hba,
|
||||||
* The TCM loopback fabric module runs in demo-mode to a local
|
.fabric_make_tpg = tcm_loop_make_naa_tpg,
|
||||||
* virtual SCSI device, so fabric dependent initator ACLs are
|
.fabric_drop_tpg = tcm_loop_drop_naa_tpg,
|
||||||
* not required.
|
.fabric_post_link = tcm_loop_port_link,
|
||||||
*/
|
.fabric_pre_unlink = tcm_loop_port_unlink,
|
||||||
fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
|
.tfc_wwn_attrs = tcm_loop_wwn_attrs,
|
||||||
fabric->tf_ops.tpg_release_fabric_acl =
|
.tfc_tpg_base_attrs = tcm_loop_tpg_attrs,
|
||||||
&tcm_loop_tpg_release_fabric_acl;
|
.tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs,
|
||||||
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 int __init tcm_loop_fabric_init(void)
|
static int __init tcm_loop_fabric_init(void)
|
||||||
{
|
{
|
||||||
|
@ -1482,7 +1450,7 @@ static int __init tcm_loop_fabric_init(void)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_destroy_cache;
|
goto out_destroy_cache;
|
||||||
|
|
||||||
ret = tcm_loop_register_configfs();
|
ret = target_register_template(&loop_ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_release_core_bus;
|
goto out_release_core_bus;
|
||||||
|
|
||||||
|
@ -1500,7 +1468,7 @@ out:
|
||||||
|
|
||||||
static void __exit tcm_loop_fabric_exit(void)
|
static void __exit tcm_loop_fabric_exit(void)
|
||||||
{
|
{
|
||||||
tcm_loop_deregister_configfs();
|
target_unregister_template(&loop_ops);
|
||||||
tcm_loop_release_core_bus();
|
tcm_loop_release_core_bus();
|
||||||
kmem_cache_destroy(tcm_loop_cmd_cache);
|
kmem_cache_destroy(tcm_loop_cmd_cache);
|
||||||
destroy_workqueue(tcm_loop_workqueue);
|
destroy_workqueue(tcm_loop_workqueue);
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct tcm_loop_nacl {
|
||||||
struct tcm_loop_tpg {
|
struct tcm_loop_tpg {
|
||||||
unsigned short tl_tpgt;
|
unsigned short tl_tpgt;
|
||||||
unsigned short tl_transport_status;
|
unsigned short tl_transport_status;
|
||||||
|
enum target_prot_type tl_fabric_prot_type;
|
||||||
atomic_t tl_tpg_port_count;
|
atomic_t tl_tpg_port_count;
|
||||||
struct se_portal_group tl_se_tpg;
|
struct se_portal_group tl_se_tpg;
|
||||||
struct tcm_loop_hba *tl_hba;
|
struct tcm_loop_hba *tl_hba;
|
||||||
|
|
|
@ -42,8 +42,7 @@
|
||||||
|
|
||||||
#include "sbp_target.h"
|
#include "sbp_target.h"
|
||||||
|
|
||||||
/* Local pointer to allocated TCM configfs fabric module */
|
static const struct target_core_fabric_ops sbp_ops;
|
||||||
static struct target_fabric_configfs *sbp_fabric_configfs;
|
|
||||||
|
|
||||||
/* FireWire address region for management and command block address handlers */
|
/* FireWire address region for management and command block address handlers */
|
||||||
static const struct fw_address_region sbp_register_region = {
|
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;
|
goto out_free_tpg;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
|
ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg,
|
||||||
&tpg->se_tpg, (void *)tpg,
|
|
||||||
TRANSPORT_TPG_TYPE_NORMAL);
|
TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_unreg_mgt_agt;
|
goto out_unreg_mgt_agt;
|
||||||
|
@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
|
||||||
NULL,
|
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_name = sbp_get_fabric_name,
|
||||||
.get_fabric_proto_ident = sbp_get_fabric_proto_ident,
|
.get_fabric_proto_ident = sbp_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = sbp_get_fabric_wwn,
|
.tpg_get_wwn = sbp_get_fabric_wwn,
|
||||||
|
@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = {
|
||||||
.fabric_drop_np = NULL,
|
.fabric_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = sbp_make_nodeacl,
|
.fabric_make_nodeacl = sbp_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = sbp_drop_nodeacl,
|
.fabric_drop_nodeacl = sbp_drop_nodeacl,
|
||||||
};
|
|
||||||
|
|
||||||
static int sbp_register_configfs(void)
|
.tfc_wwn_attrs = sbp_wwn_attrs,
|
||||||
{
|
.tfc_tpg_base_attrs = sbp_tpg_base_attrs,
|
||||||
struct target_fabric_configfs *fabric;
|
.tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs,
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sbp_init(void)
|
static int __init sbp_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
return target_register_template(&sbp_ops);
|
||||||
|
|
||||||
ret = sbp_register_configfs();
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __exit sbp_exit(void)
|
static void __exit sbp_exit(void)
|
||||||
{
|
{
|
||||||
sbp_deregister_configfs();
|
target_unregister_template(&sbp_ops);
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DESCRIPTION("FireWire SBP fabric driver");
|
MODULE_DESCRIPTION("FireWire SBP fabric driver");
|
||||||
|
|
|
@ -142,8 +142,8 @@ static struct config_group *target_core_register_fabric(
|
||||||
|
|
||||||
tf = target_core_get_fabric(name);
|
tf = target_core_get_fabric(name);
|
||||||
if (!tf) {
|
if (!tf) {
|
||||||
pr_err("target_core_register_fabric() trying autoload for %s\n",
|
pr_debug("target_core_register_fabric() trying autoload for %s\n",
|
||||||
name);
|
name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Below are some hardcoded request_module() calls to automatically
|
* 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");
|
ret = request_module("iscsi_target_mod");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_err("request_module() failed for"
|
pr_debug("request_module() failed for"
|
||||||
" iscsi_target_mod.ko: %d\n", ret);
|
" iscsi_target_mod.ko: %d\n", ret);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
} else if (!strncmp(name, "loopback", 8)) {
|
} else if (!strncmp(name, "loopback", 8)) {
|
||||||
|
@ -178,8 +178,8 @@ static struct config_group *target_core_register_fabric(
|
||||||
*/
|
*/
|
||||||
ret = request_module("tcm_loop");
|
ret = request_module("tcm_loop");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_err("request_module() failed for"
|
pr_debug("request_module() failed for"
|
||||||
" tcm_loop.ko: %d\n", ret);
|
" tcm_loop.ko: %d\n", ret);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,8 +188,8 @@ static struct config_group *target_core_register_fabric(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tf) {
|
if (!tf) {
|
||||||
pr_err("target_core_get_fabric() failed for %s\n",
|
pr_debug("target_core_get_fabric() failed for %s\n",
|
||||||
name);
|
name);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:"
|
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
|
// Start functions called by external Target Fabrics Modules
|
||||||
//############################################################################*/
|
//############################################################################*/
|
||||||
|
|
||||||
/*
|
static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
struct target_fabric_configfs *tf;
|
if (!tfo->name) {
|
||||||
|
pr_err("Missing tfo->name\n");
|
||||||
if (!(name)) {
|
return -EINVAL;
|
||||||
pr_err("Unable to locate passed fabric name\n");
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
}
|
||||||
if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) {
|
if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) {
|
||||||
pr_err("Passed name: %s exceeds TARGET_FABRIC"
|
pr_err("Passed name: %s exceeds TARGET_FABRIC"
|
||||||
"_NAME_SIZE\n", name);
|
"_NAME_SIZE\n", tfo->name);
|
||||||
return ERR_PTR(-EINVAL);
|
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) {
|
if (!tfo->get_fabric_name) {
|
||||||
pr_err("Missing tfo->get_fabric_name()\n");
|
pr_err("Missing tfo->get_fabric_name()\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -508,77 +444,59 @@ static int target_fabric_tf_ops_check(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int target_register_template(const struct target_core_fabric_ops *fo)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
|
struct target_fabric_configfs *tf;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!tf) {
|
ret = target_fabric_tf_ops_check(fo);
|
||||||
pr_err("Unable to locate target_fabric_configfs"
|
if (ret)
|
||||||
" 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)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
|
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
|
||||||
">>>>>>>>>>\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(target_fabric_configfs_register);
|
|
||||||
|
|
||||||
void target_fabric_configfs_deregister(
|
|
||||||
struct target_fabric_configfs *tf)
|
|
||||||
{
|
|
||||||
struct configfs_subsystem *su;
|
|
||||||
|
|
||||||
if (!tf) {
|
if (!tf) {
|
||||||
pr_err("Unable to locate passed target_fabric_"
|
pr_err("%s: could not allocate memory!\n", __func__);
|
||||||
"configfs\n");
|
return -ENOMEM;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
su = tf->tf_subsys;
|
|
||||||
if (!su) {
|
INIT_LIST_HEAD(&tf->tf_list);
|
||||||
pr_err("Unable to locate passed tf->tf_subsys"
|
atomic_set(&tf->tf_access_cnt, 0);
|
||||||
" pointer\n");
|
|
||||||
return;
|
/*
|
||||||
}
|
* Setup the default generic struct config_item_type's (cits) in
|
||||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
|
* struct target_fabric_configfs->tf_cit_tmpl
|
||||||
">>>>>>>>>>>>\n");
|
*/
|
||||||
|
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);
|
mutex_lock(&g_tf_lock);
|
||||||
if (atomic_read(&tf->tf_access_cnt)) {
|
list_add_tail(&tf->tf_list, &g_tf_list);
|
||||||
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);
|
|
||||||
mutex_unlock(&g_tf_lock);
|
mutex_unlock(&g_tf_lock);
|
||||||
|
|
||||||
pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
|
return 0;
|
||||||
" %s\n", tf->tf_name);
|
|
||||||
tf->tf_module = NULL;
|
|
||||||
tf->tf_subsys = NULL;
|
|
||||||
kfree(tf);
|
|
||||||
|
|
||||||
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
|
|
||||||
">>>>>\n");
|
|
||||||
}
|
}
|
||||||
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
|
// 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_lun *lun;
|
||||||
struct se_portal_group *se_tpg;
|
struct se_portal_group *se_tpg;
|
||||||
struct t10_pr_registration *pr_reg;
|
struct t10_pr_registration *pr_reg;
|
||||||
struct target_core_fabric_ops *tfo;
|
const struct target_core_fabric_ops *tfo;
|
||||||
ssize_t len = 0;
|
ssize_t len = 0;
|
||||||
|
|
||||||
spin_lock(&dev->dev_reservation_lock);
|
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(
|
static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
|
||||||
struct se_device *dev, char *page)
|
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;
|
struct t10_pr_registration *pr_reg;
|
||||||
unsigned char buf[384];
|
unsigned char buf[384];
|
||||||
char i_buf[PR_REG_ISID_ID_LEN];
|
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)); \
|
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 */
|
/* Start of tfc_tpg_mappedlun_cit */
|
||||||
|
|
||||||
static int target_fabric_mappedlun_link(
|
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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.drop_item = target_fabric_drop_mappedlun,
|
||||||
};
|
};
|
||||||
|
|
||||||
TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
|
TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
|
||||||
&target_fabric_nacl_base_group_ops, NULL);
|
&target_fabric_nacl_base_group_ops);
|
||||||
|
|
||||||
/* End of tfc_tpg_nacl_base_cit */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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,
|
.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 */
|
/* 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 se_device *se_dev = cmd->se_dev;
|
||||||
struct fd_dev *dev = FD_DEV(se_dev);
|
struct fd_dev *dev = FD_DEV(se_dev);
|
||||||
struct file *prot_fd = dev->fd_prot_file;
|
struct file *prot_fd = dev->fd_prot_file;
|
||||||
struct scatterlist *sg;
|
|
||||||
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
|
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
u32 prot_size, len, size;
|
u32 prot_size;
|
||||||
int rc, ret = 1, i;
|
int rc, ret = 1;
|
||||||
|
|
||||||
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
|
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
|
||||||
se_dev->prot_length;
|
se_dev->prot_length;
|
||||||
|
|
||||||
if (!is_write) {
|
if (!is_write) {
|
||||||
fd_prot->prot_buf = vzalloc(prot_size);
|
fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL);
|
||||||
if (!fd_prot->prot_buf) {
|
if (!fd_prot->prot_buf) {
|
||||||
pr_err("Unable to allocate fd_prot->prot_buf\n");
|
pr_err("Unable to allocate fd_prot->prot_buf\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
buf = fd_prot->prot_buf;
|
buf = fd_prot->prot_buf;
|
||||||
|
|
||||||
fd_prot->prot_sg_nents = cmd->t_prot_nents;
|
fd_prot->prot_sg_nents = 1;
|
||||||
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
|
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist),
|
||||||
fd_prot->prot_sg_nents, GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!fd_prot->prot_sg) {
|
if (!fd_prot->prot_sg) {
|
||||||
pr_err("Unable to allocate fd_prot->prot_sg\n");
|
pr_err("Unable to allocate fd_prot->prot_sg\n");
|
||||||
vfree(fd_prot->prot_buf);
|
kfree(fd_prot->prot_buf);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
size = prot_size;
|
sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents);
|
||||||
|
sg_set_buf(fd_prot->prot_sg, buf, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_write) {
|
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) {
|
if (is_write || ret < 0) {
|
||||||
kfree(fd_prot->prot_sg);
|
kfree(fd_prot->prot_sg);
|
||||||
vfree(fd_prot->prot_buf);
|
kfree(fd_prot->prot_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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 fd_dev *dev = FD_DEV(se_dev);
|
||||||
struct file *fd = dev->fd_file;
|
struct file *fd = dev->fd_file;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
struct iovec *iov;
|
struct iov_iter iter;
|
||||||
mm_segment_t old_fs;
|
struct bio_vec *bvec;
|
||||||
|
ssize_t len = 0;
|
||||||
loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);
|
loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
|
bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);
|
||||||
if (!iov) {
|
if (!bvec) {
|
||||||
pr_err("Unable to allocate fd_do_readv iov[]\n");
|
pr_err("Unable to allocate fd_do_readv iov[]\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_sg(sgl, sg, sgl_nents, i) {
|
for_each_sg(sgl, sg, sgl_nents, i) {
|
||||||
iov[i].iov_len = sg->length;
|
bvec[i].bv_page = sg_page(sg);
|
||||||
iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
|
bvec[i].bv_len = sg->length;
|
||||||
|
bvec[i].bv_offset = sg->offset;
|
||||||
|
|
||||||
|
len += sg->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_fs = get_fs();
|
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
|
||||||
set_fs(get_ds());
|
|
||||||
|
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ret = vfs_writev(fd, &iov[0], sgl_nents, &pos);
|
ret = vfs_iter_write(fd, &iter, &pos);
|
||||||
else
|
else
|
||||||
ret = vfs_readv(fd, &iov[0], sgl_nents, &pos);
|
ret = vfs_iter_read(fd, &iter, &pos);
|
||||||
|
|
||||||
set_fs(old_fs);
|
kfree(bvec);
|
||||||
|
|
||||||
for_each_sg(sgl, sg, sgl_nents, i)
|
|
||||||
kunmap(sg_page(sg));
|
|
||||||
|
|
||||||
kfree(iov);
|
|
||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
if (ret < 0 || ret != cmd->data_length) {
|
if (ret < 0 || ret != cmd->data_length) {
|
||||||
|
@ -436,59 +425,17 @@ fd_execute_sync_cache(struct se_cmd *cmd)
|
||||||
return 0;
|
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
|
static sense_reason_t
|
||||||
fd_execute_write_same(struct se_cmd *cmd)
|
fd_execute_write_same(struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
struct se_device *se_dev = cmd->se_dev;
|
struct se_device *se_dev = cmd->se_dev;
|
||||||
struct fd_dev *fd_dev = FD_DEV(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;
|
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
|
||||||
unsigned int len, len_tmp, iov_num;
|
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||||
int i, rc;
|
struct iov_iter iter;
|
||||||
unsigned char *buf;
|
struct bio_vec *bvec;
|
||||||
|
unsigned int len = 0, i;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
if (!nolb) {
|
if (!nolb) {
|
||||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||||
|
@ -499,49 +446,35 @@ fd_execute_write_same(struct se_cmd *cmd)
|
||||||
" backends not supported\n");
|
" backends not supported\n");
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||||
}
|
}
|
||||||
sg = &cmd->t_data_sg[0];
|
|
||||||
|
|
||||||
if (cmd->t_data_nents > 1 ||
|
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"
|
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);
|
cmd->se_dev->dev_attrib.block_size);
|
||||||
return TCM_INVALID_CDB_FIELD;
|
return TCM_INVALID_CDB_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = len_tmp = nolb * se_dev->dev_attrib.block_size;
|
bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);
|
||||||
iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
|
if (!bvec)
|
||||||
|
|
||||||
buf = fd_setup_write_same_buf(cmd, sg, len);
|
|
||||||
if (!buf)
|
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||||
|
|
||||||
iov = vzalloc(sizeof(struct iovec) * iov_num);
|
for (i = 0; i < nolb; i++) {
|
||||||
if (!iov) {
|
bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]);
|
||||||
pr_err("Unable to allocate fd_execute_write_same iovecs\n");
|
bvec[i].bv_len = cmd->t_data_sg[0].length;
|
||||||
kfree(buf);
|
bvec[i].bv_offset = cmd->t_data_sg[0].offset;
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
||||||
}
|
len += se_dev->dev_attrib.block_size;
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
old_fs = get_fs();
|
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
|
||||||
set_fs(get_ds());
|
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos);
|
||||||
rc = vfs_writev(f, &iov[0], iov_num, &pos);
|
|
||||||
set_fs(old_fs);
|
|
||||||
|
|
||||||
vfree(iov);
|
kfree(bvec);
|
||||||
kfree(buf);
|
if (ret < 0 || ret != len) {
|
||||||
|
pr_err("vfs_iter_write() returned %zd for write same\n", ret);
|
||||||
if (rc < 0 || rc != len) {
|
|
||||||
pr_err("vfs_writev() returned %d for write same\n", rc);
|
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +482,56 @@ fd_execute_write_same(struct se_cmd *cmd)
|
||||||
return 0;
|
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
|
static sense_reason_t
|
||||||
fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
|
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;
|
struct inode *inode = file->f_mapping->host;
|
||||||
int ret;
|
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)) {
|
if (S_ISBLK(inode->i_mode)) {
|
||||||
/* The backend is block device, use discard */
|
/* The backend is block device, use discard */
|
||||||
struct block_device *bdev = inode->i_bdev;
|
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;
|
struct file *file = fd_dev->fd_file;
|
||||||
sector_t lba = cmd->t_task_lba;
|
sector_t lba = cmd->t_task_lba;
|
||||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||||
int ret;
|
sense_reason_t ret;
|
||||||
|
|
||||||
if (!nolb) {
|
if (!nolb) {
|
||||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
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) {
|
if (data_direction == DMA_FROM_DEVICE) {
|
||||||
memset(&fd_prot, 0, sizeof(struct fd_prot));
|
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);
|
ret = fd_do_prot_rw(cmd, &fd_prot, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
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);
|
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;
|
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
|
||||||
|
|
||||||
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
|
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
|
||||||
0, fd_prot.prot_sg, 0);
|
0, fd_prot.prot_sg, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(fd_prot.prot_sg);
|
kfree(fd_prot.prot_sg);
|
||||||
vfree(fd_prot.prot_buf);
|
kfree(fd_prot.prot_buf);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
kfree(fd_prot.prot_sg);
|
kfree(fd_prot.prot_sg);
|
||||||
vfree(fd_prot.prot_buf);
|
kfree(fd_prot.prot_buf);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memset(&fd_prot, 0, sizeof(struct fd_prot));
|
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;
|
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
|
||||||
|
|
||||||
ret = fd_do_prot_rw(cmd, &fd_prot, false);
|
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);
|
0, fd_prot.prot_sg, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(fd_prot.prot_sg);
|
kfree(fd_prot.prot_sg);
|
||||||
vfree(fd_prot.prot_buf);
|
kfree(fd_prot.prot_buf);
|
||||||
return rc;
|
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);
|
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);
|
ret = fd_do_prot_rw(cmd, &fd_prot, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
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) {
|
if (ret < 0) {
|
||||||
kfree(fd_prot.prot_sg);
|
kfree(fd_prot.prot_sg);
|
||||||
vfree(fd_prot.prot_buf);
|
kfree(fd_prot.prot_buf);
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
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)
|
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;
|
unsigned char *buf;
|
||||||
loff_t pos = 0;
|
|
||||||
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
|
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) {
|
if (!dev->dev_attrib.pi_prot_type) {
|
||||||
pr_err("Unable to format_prot while pi_prot_type == 0\n");
|
pr_err("Unable to format_prot while pi_prot_type == 0\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
if (!prot_fd) {
|
|
||||||
pr_err("Unable to locate fd_dev->fd_prot_file\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = vzalloc(unit_size);
|
buf = vzalloc(unit_size);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
pr_err("Unable to allocate FILEIO prot buf\n");
|
pr_err("Unable to allocate FILEIO prot buf\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
|
|
||||||
size = prot_length;
|
|
||||||
|
|
||||||
pr_debug("Using FILEIO prot_length: %llu\n",
|
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);
|
memset(buf, 0xff, unit_size);
|
||||||
for (prot = 0; prot < prot_length; prot += unit_size) {
|
ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1,
|
||||||
len = min(unit_size, size);
|
buf, unit_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:
|
|
||||||
vfree(buf);
|
vfree(buf);
|
||||||
return ret;
|
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;
|
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
|
||||||
sector_t lba = cmd->t_task_lba;
|
sector_t lba = cmd->t_task_lba;
|
||||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||||
int ret;
|
sense_reason_t ret;
|
||||||
|
|
||||||
ret = iblock_do_unmap(cmd, bdev, lba, nolb);
|
ret = iblock_do_unmap(cmd, bdev, lba, nolb);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -774,7 +774,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||||
sg_num--;
|
sg_num--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd->prot_type) {
|
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
|
||||||
int rc = iblock_alloc_bip(cmd, bio_start);
|
int rc = iblock_alloc_bip(cmd, bio_start);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail_put_bios;
|
goto fail_put_bios;
|
||||||
|
|
|
@ -4,7 +4,13 @@
|
||||||
/* target_core_alua.c */
|
/* target_core_alua.c */
|
||||||
extern struct t10_alua_lu_gp *default_lu_gp;
|
extern struct t10_alua_lu_gp *default_lu_gp;
|
||||||
|
|
||||||
|
/* target_core_configfs.c */
|
||||||
|
extern struct configfs_subsystem *target_core_subsystem[];
|
||||||
|
|
||||||
/* target_core_device.c */
|
/* 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);
|
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 *,
|
int core_free_device_list_for_node(struct se_node_acl *,
|
||||||
struct se_portal_group *);
|
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 *,
|
static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
|
||||||
struct t10_pr_registration *, int, int);
|
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
|
static sense_reason_t
|
||||||
target_scsi2_reservation_check(struct se_cmd *cmd)
|
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_dev_entry *deve_tmp;
|
||||||
struct se_node_acl *nacl_tmp;
|
struct se_node_acl *nacl_tmp;
|
||||||
struct se_port *port, *port_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;
|
struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||||
int ret;
|
int ret;
|
||||||
/*
|
/*
|
||||||
|
@ -963,7 +979,7 @@ int core_scsi3_check_aptpl_registration(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __core_scsi3_dump_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_device *dev,
|
||||||
struct se_node_acl *nacl,
|
struct se_node_acl *nacl,
|
||||||
struct t10_pr_registration *pr_reg,
|
struct t10_pr_registration *pr_reg,
|
||||||
|
@ -1004,7 +1020,7 @@ static void __core_scsi3_add_registration(
|
||||||
enum register_type register_type,
|
enum register_type register_type,
|
||||||
int register_move)
|
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_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
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 t10_pr_registration *pr_reg,
|
||||||
struct list_head *preempt_and_abort_list,
|
struct list_head *preempt_and_abort_list,
|
||||||
int dec_holders)
|
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;
|
pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
|
||||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||||
char i_buf[PR_REG_ISID_ID_LEN];
|
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;
|
struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
|
||||||
LIST_HEAD(tid_dest_list);
|
LIST_HEAD(tid_dest_list);
|
||||||
struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
|
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 *buf;
|
||||||
unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
|
unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
|
||||||
char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
|
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);
|
spin_lock(&dev->dev_reservation_lock);
|
||||||
pr_res_holder = dev->dev_pr_res_holder;
|
pr_res_holder = dev->dev_pr_res_holder;
|
||||||
if (pr_res_holder) {
|
if (pr_res_holder) {
|
||||||
int pr_res_type = pr_res_holder->pr_res_type;
|
|
||||||
/*
|
/*
|
||||||
* From spc4r17 Section 5.7.9: Reserving:
|
* 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
|
* the logical unit, then the command shall be completed with
|
||||||
* RESERVATION CONFLICT status.
|
* RESERVATION CONFLICT status.
|
||||||
*/
|
*/
|
||||||
if ((pr_res_holder != pr_reg) &&
|
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
|
||||||
(pr_res_type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
|
|
||||||
(pr_res_type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
|
|
||||||
struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
|
struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
|
||||||
pr_err("SPC-3 PR: Attempted RESERVE from"
|
pr_err("SPC-3 PR: Attempted RESERVE from"
|
||||||
" [%s]: %s while reservation already held by"
|
" [%s]: %s while reservation already held by"
|
||||||
|
@ -2409,7 +2424,7 @@ static void __core_scsi3_complete_pro_release(
|
||||||
int explicit,
|
int explicit,
|
||||||
int unreg)
|
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];
|
char i_buf[PR_REG_ISID_ID_LEN];
|
||||||
int pr_res_type = 0, pr_res_scope = 0;
|
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 se_lun *se_lun = cmd->se_lun;
|
||||||
struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
|
struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
|
||||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||||
int all_reg = 0;
|
|
||||||
sense_reason_t ret = 0;
|
sense_reason_t ret = 0;
|
||||||
|
|
||||||
if (!se_sess || !se_lun) {
|
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);
|
spin_unlock(&dev->dev_reservation_lock);
|
||||||
goto out_put_pr_reg;
|
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
|
* Release request from a registered I_T nexus that is not a
|
||||||
* persistent reservation holder. return GOOD status.
|
* persistent reservation holder. return GOOD status.
|
||||||
*/
|
*/
|
||||||
|
@ -2726,7 +2736,7 @@ static void __core_scsi3_complete_pro_preempt(
|
||||||
enum preempt_type preempt_type)
|
enum preempt_type preempt_type)
|
||||||
{
|
{
|
||||||
struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
|
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];
|
char i_buf[PR_REG_ISID_ID_LEN];
|
||||||
|
|
||||||
memset(i_buf, 0, 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_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
|
||||||
struct se_port *se_port;
|
struct se_port *se_port;
|
||||||
struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
|
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_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
|
||||||
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
struct t10_reservation *pr_tmpl = &dev->t10_pr;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
@ -3375,7 +3385,7 @@ after_iport_check:
|
||||||
* From spc4r17 section 5.7.8 Table 50 --
|
* From spc4r17 section 5.7.8 Table 50 --
|
||||||
* Register behaviors for a REGISTER AND MOVE service action
|
* 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"
|
pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
|
||||||
" Nexus is not reservation holder\n");
|
" Nexus is not reservation holder\n");
|
||||||
spin_unlock(&dev->dev_reservation_lock);
|
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;
|
unsigned char *p;
|
||||||
|
|
||||||
while (total_sg_needed) {
|
while (total_sg_needed) {
|
||||||
|
unsigned int chain_entry = 0;
|
||||||
|
|
||||||
sg_per_table = (total_sg_needed > max_sg_per_table) ?
|
sg_per_table = (total_sg_needed > max_sg_per_table) ?
|
||||||
max_sg_per_table : total_sg_needed;
|
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);
|
GFP_KERNEL);
|
||||||
if (!sg) {
|
if (!sg) {
|
||||||
pr_err("Unable to allocate scatterlist array"
|
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;
|
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].sg_table = sg;
|
||||||
sg_table[i].rd_sg_count = sg_per_table;
|
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;
|
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
|
static sense_reason_t
|
||||||
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||||
enum dma_data_direction data_direction)
|
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",
|
data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
|
||||||
cmd->t_task_lba, rd_size, rd_page, rd_offset);
|
cmd->t_task_lba, rd_size, rd_page, rd_offset);
|
||||||
|
|
||||||
if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
|
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
|
||||||
struct rd_dev_sg_table *prot_table;
|
data_direction == DMA_TO_DEVICE) {
|
||||||
struct scatterlist *prot_sg;
|
rc = rd_do_prot_rw(cmd, sbc_dif_verify_write);
|
||||||
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 (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -502,24 +578,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||||
}
|
}
|
||||||
sg_miter_stop(&m);
|
sg_miter_stop(&m);
|
||||||
|
|
||||||
if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
|
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
|
||||||
struct rd_dev_sg_table *prot_table;
|
data_direction == DMA_FROM_DEVICE) {
|
||||||
struct scatterlist *prot_sg;
|
rc = rd_do_prot_rw(cmd, sbc_dif_verify_read);
|
||||||
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 (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
struct se_device *dev = cmd->se_dev;
|
struct se_device *dev = cmd->se_dev;
|
||||||
struct se_session *sess = cmd->se_sess;
|
struct se_session *sess = cmd->se_sess;
|
||||||
|
int pi_prot_type = dev->dev_attrib.pi_prot_type;
|
||||||
|
|
||||||
unsigned char *rbuf;
|
unsigned char *rbuf;
|
||||||
unsigned char buf[32];
|
unsigned char buf[32];
|
||||||
unsigned long long blocks = dev->transport->get_blocks(dev);
|
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
|
* Set P_TYPE and PROT_EN bits for DIF support
|
||||||
*/
|
*/
|
||||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
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)
|
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;
|
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;
|
unsigned char *buf, *addr;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
|
@ -376,7 +385,7 @@ sbc_execute_rw(struct se_cmd *cmd)
|
||||||
cmd->data_direction);
|
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;
|
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;
|
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 se_device *dev = cmd->se_dev;
|
||||||
struct scatterlist *write_sg = NULL, *sg;
|
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(),
|
* 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;
|
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
|
* Immediately exit + release dev->caw_sem if command has already
|
||||||
* been failed with a non-zero SCSI status.
|
* been failed with a non-zero SCSI status.
|
||||||
|
@ -581,12 +595,13 @@ sbc_compare_and_write(struct se_cmd *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
bool is_write, struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS :
|
cmd->prot_op = fabric_prot ? TARGET_PROT_DOUT_STRIP :
|
||||||
TARGET_PROT_DOUT_INSERT;
|
protect ? TARGET_PROT_DOUT_PASS :
|
||||||
|
TARGET_PROT_DOUT_INSERT;
|
||||||
switch (protect) {
|
switch (protect) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
case 0x3:
|
case 0x3:
|
||||||
|
@ -610,8 +625,9 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cmd->prot_op = protect ? TARGET_PROT_DIN_PASS :
|
cmd->prot_op = fabric_prot ? TARGET_PROT_DIN_INSERT :
|
||||||
TARGET_PROT_DIN_STRIP;
|
protect ? TARGET_PROT_DIN_PASS :
|
||||||
|
TARGET_PROT_DIN_STRIP;
|
||||||
switch (protect) {
|
switch (protect) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
case 0x1:
|
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)
|
u32 sectors, bool is_write)
|
||||||
{
|
{
|
||||||
u8 protect = cdb[1] >> 5;
|
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 (!cmd->t_prot_sg || !cmd->t_prot_nents) {
|
||||||
if (protect && !dev->dev_attrib.pi_prot_type) {
|
if (unlikely(protect &&
|
||||||
pr_err("CDB contains protect bit, but device does not"
|
!dev->dev_attrib.pi_prot_type && !cmd->se_sess->sess_prot_type)) {
|
||||||
" advertise PROTECT=1 feature bit\n");
|
pr_err("CDB contains protect bit, but device + fabric does"
|
||||||
|
" not advertise PROTECT=1 feature bit\n");
|
||||||
return TCM_INVALID_CDB_FIELD;
|
return TCM_INVALID_CDB_FIELD;
|
||||||
}
|
}
|
||||||
if (cmd->prot_pto)
|
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;
|
cmd->reftag_seed = cmd->t_task_lba;
|
||||||
break;
|
break;
|
||||||
case TARGET_DIF_TYPE0_PROT:
|
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:
|
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,
|
if (sbc_set_prot_op_checks(protect, fabric_prot, pi_prot_type, is_write, cmd))
|
||||||
is_write, cmd))
|
|
||||||
return TCM_INVALID_CDB_FIELD;
|
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;
|
cmd->prot_length = dev->prot_length * sectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1166,14 +1203,16 @@ sbc_dif_generate(struct se_cmd *cmd)
|
||||||
sdt = paddr + offset;
|
sdt = paddr + offset;
|
||||||
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
|
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
|
||||||
dev->dev_attrib.block_size));
|
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->ref_tag = cpu_to_be32(sector & 0xffffffff);
|
||||||
sdt->app_tag = 0;
|
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",
|
" app_tag: 0x%04x ref_tag: %u\n",
|
||||||
(unsigned long long)sector, sdt->guard_tag,
|
(cmd->data_direction == DMA_TO_DEVICE) ?
|
||||||
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
|
"WRITE" : "READ", (unsigned long long)sector,
|
||||||
|
sdt->guard_tag, sdt->app_tag,
|
||||||
|
be32_to_cpu(sdt->ref_tag));
|
||||||
|
|
||||||
sector++;
|
sector++;
|
||||||
offset += sizeof(struct se_dif_v1_tuple);
|
offset += sizeof(struct se_dif_v1_tuple);
|
||||||
|
@ -1185,12 +1224,16 @@ sbc_dif_generate(struct se_cmd *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static sense_reason_t
|
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)
|
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;
|
int block_size = dev->dev_attrib.block_size;
|
||||||
__be16 csum;
|
__be16 csum;
|
||||||
|
|
||||||
|
if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD))
|
||||||
|
goto check_ref;
|
||||||
|
|
||||||
csum = cpu_to_be16(crc_t10dif(p, block_size));
|
csum = cpu_to_be16(crc_t10dif(p, block_size));
|
||||||
|
|
||||||
if (sdt->guard_tag != csum) {
|
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;
|
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)) {
|
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
|
||||||
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
|
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
|
||||||
" sector MSB: 0x%08x\n", (unsigned long long)sector,
|
" 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;
|
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) {
|
be32_to_cpu(sdt->ref_tag) != ei_lba) {
|
||||||
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
|
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
|
||||||
" ei_lba: 0x%08x\n", (unsigned long long)sector,
|
" 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 i, len, left;
|
||||||
unsigned int offset = sg_off;
|
unsigned int offset = sg_off;
|
||||||
|
|
||||||
|
if (!sg)
|
||||||
|
return;
|
||||||
|
|
||||||
left = sectors * dev->prot_length;
|
left = sectors * dev->prot_length;
|
||||||
|
|
||||||
for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
|
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,
|
(unsigned long long)sector, sdt->guard_tag,
|
||||||
sdt->app_tag, be32_to_cpu(sdt->ref_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);
|
ei_lba);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kunmap_atomic(paddr);
|
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(paddr);
|
||||||
kunmap_atomic(daddr);
|
kunmap_atomic(daddr);
|
||||||
}
|
}
|
||||||
|
if (!sg)
|
||||||
|
return 0;
|
||||||
|
|
||||||
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
|
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1353,7 +1406,7 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
|
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
|
||||||
ei_lba);
|
ei_lba);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kunmap_atomic(paddr);
|
kunmap_atomic(paddr);
|
||||||
|
|
|
@ -103,10 +103,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
|
||||||
buf[5] |= 0x8;
|
buf[5] |= 0x8;
|
||||||
/*
|
/*
|
||||||
* Set Protection (PROTECT) bit when DIF has been enabled on the
|
* 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 (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;
|
buf[5] |= 0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,9 +469,11 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
|
||||||
* only for TYPE3 protection.
|
* only for TYPE3 protection.
|
||||||
*/
|
*/
|
||||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
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;
|
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;
|
buf[4] = 0x4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,7 +865,7 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p)
|
||||||
* TAG field.
|
* TAG field.
|
||||||
*/
|
*/
|
||||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
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;
|
p[5] |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,7 +1103,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
unsigned char tbuf[SE_MODE_PAGE_BUF];
|
unsigned char tbuf[SE_MODE_PAGE_BUF];
|
||||||
int length;
|
int length;
|
||||||
int ret = 0;
|
sense_reason_t ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!cmd->data_length) {
|
if (!cmd->data_length) {
|
||||||
|
|
|
@ -125,8 +125,8 @@ void core_tmr_abort_task(
|
||||||
if (dev != se_cmd->se_dev)
|
if (dev != se_cmd->se_dev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* skip se_cmd associated with tmr */
|
/* skip task management functions, including tmr->task_cmd */
|
||||||
if (tmr->task_cmd == se_cmd)
|
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);
|
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(
|
int core_tpg_register(
|
||||||
struct target_core_fabric_ops *tfo,
|
const struct target_core_fabric_ops *tfo,
|
||||||
struct se_wwn *se_wwn,
|
struct se_wwn *se_wwn,
|
||||||
struct se_portal_group *se_tpg,
|
struct se_portal_group *se_tpg,
|
||||||
void *tpg_fabric_ptr,
|
void *tpg_fabric_ptr,
|
||||||
|
|
|
@ -322,6 +322,7 @@ void __transport_register_session(
|
||||||
struct se_session *se_sess,
|
struct se_session *se_sess,
|
||||||
void *fabric_sess_ptr)
|
void *fabric_sess_ptr)
|
||||||
{
|
{
|
||||||
|
const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo;
|
||||||
unsigned char buf[PR_REG_ISID_LEN];
|
unsigned char buf[PR_REG_ISID_LEN];
|
||||||
|
|
||||||
se_sess->se_tpg = se_tpg;
|
se_sess->se_tpg = se_tpg;
|
||||||
|
@ -333,6 +334,21 @@ void __transport_register_session(
|
||||||
* eg: *NOT* discovery sessions.
|
* eg: *NOT* discovery sessions.
|
||||||
*/
|
*/
|
||||||
if (se_nacl) {
|
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,
|
* If the fabric module supports an ISID based TransportID,
|
||||||
* save this value in binary from the fabric I_T Nexus now.
|
* 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);
|
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)
|
static void target_complete_nacl(struct kref *kref)
|
||||||
{
|
{
|
||||||
struct se_node_acl *nacl = container_of(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)
|
void transport_deregister_session(struct se_session *se_sess)
|
||||||
{
|
{
|
||||||
struct se_portal_group *se_tpg = se_sess->se_tpg;
|
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;
|
struct se_node_acl *se_nacl;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
bool comp_nacl = true;
|
bool comp_nacl = true;
|
||||||
|
@ -1118,7 +1158,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
|
||||||
*/
|
*/
|
||||||
void transport_init_se_cmd(
|
void transport_init_se_cmd(
|
||||||
struct se_cmd *cmd,
|
struct se_cmd *cmd,
|
||||||
struct target_core_fabric_ops *tfo,
|
const struct target_core_fabric_ops *tfo,
|
||||||
struct se_session *se_sess,
|
struct se_session *se_sess,
|
||||||
u32 data_length,
|
u32 data_length,
|
||||||
int data_direction,
|
int data_direction,
|
||||||
|
@ -1570,6 +1610,8 @@ EXPORT_SYMBOL(target_submit_tmr);
|
||||||
* has completed.
|
* has completed.
|
||||||
*/
|
*/
|
||||||
bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
|
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;
|
bool was_active = false;
|
||||||
|
|
||||||
|
@ -1615,11 +1657,11 @@ void transport_generic_request_failure(struct se_cmd *cmd,
|
||||||
transport_complete_task_attr(cmd);
|
transport_complete_task_attr(cmd);
|
||||||
/*
|
/*
|
||||||
* Handle special case for COMPARE_AND_WRITE failure, where the
|
* 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) &&
|
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
|
||||||
cmd->transport_complete_callback)
|
cmd->transport_complete_callback)
|
||||||
cmd->transport_complete_callback(cmd);
|
cmd->transport_complete_callback(cmd, false);
|
||||||
|
|
||||||
switch (sense_reason) {
|
switch (sense_reason) {
|
||||||
case TCM_NON_EXISTENT_LUN:
|
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)
|
static bool target_handle_task_attr(struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
struct se_device *dev = cmd->se_dev;
|
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->t_state = TRANSPORT_PROCESSING;
|
||||||
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
||||||
spin_unlock_irq(&cmd->t_state_lock);
|
spin_unlock_irq(&cmd->t_state_lock);
|
||||||
/*
|
|
||||||
* Perform WRITE_INSERT of PI using software emulation when backend
|
if (target_write_prot_action(cmd))
|
||||||
* device has PI enabled, if the transport has not already generated
|
return;
|
||||||
* 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_handle_task_attr(cmd)) {
|
if (target_handle_task_attr(cmd)) {
|
||||||
spin_lock_irq(&cmd->t_state_lock);
|
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);
|
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;
|
sense_reason_t rc;
|
||||||
|
|
||||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
|
switch (cmd->prot_op) {
|
||||||
rc = sbc_dif_read_strip(cmd);
|
case TARGET_PROT_DIN_STRIP:
|
||||||
if (rc) {
|
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
|
||||||
cmd->pi_err = rc;
|
rc = sbc_dif_read_strip(cmd);
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
@ -1975,8 +2058,12 @@ static void target_complete_ok_work(struct work_struct *work)
|
||||||
if (cmd->transport_complete_callback) {
|
if (cmd->transport_complete_callback) {
|
||||||
sense_reason_t rc;
|
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 (!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;
|
return;
|
||||||
} else if (rc) {
|
} else if (rc) {
|
||||||
ret = transport_send_check_condition_and_sense(cmd,
|
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) {
|
switch (cmd->data_direction) {
|
||||||
case DMA_FROM_DEVICE:
|
case DMA_FROM_DEVICE:
|
||||||
spin_lock(&cmd->se_lun->lun_sep_lock);
|
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
|
* backend had PI enabled, if the transport will not be
|
||||||
* performing hardware READ_STRIP offload.
|
* performing hardware READ_STRIP offload.
|
||||||
*/
|
*/
|
||||||
if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
|
if (target_read_prot_action(cmd)) {
|
||||||
target_check_read_strip(cmd)) {
|
|
||||||
ret = transport_send_check_condition_and_sense(cmd,
|
ret = transport_send_check_condition_and_sense(cmd,
|
||||||
cmd->pi_err, 0);
|
cmd->pi_err, 0);
|
||||||
if (ret == -EAGAIN || ret == -ENOMEM)
|
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)
|
static inline void transport_free_pages(struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
|
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);
|
transport_reset_sgl_orig(cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2246,6 +2343,7 @@ sense_reason_t
|
||||||
transport_generic_new_cmd(struct se_cmd *cmd)
|
transport_generic_new_cmd(struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine is the TCM fabric module has already allocated physical
|
* 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) &&
|
if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) &&
|
||||||
cmd->data_length) {
|
cmd->data_length) {
|
||||||
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
|
|
||||||
|
|
||||||
if ((cmd->se_cmd_flags & SCF_BIDI) ||
|
if ((cmd->se_cmd_flags & SCF_BIDI) ||
|
||||||
(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) {
|
(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);
|
cmd->data_length, zero_flag);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
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,
|
* 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()
|
* fabric acknowledgement that requires two target_put_sess_cmd()
|
||||||
* invocations before se_cmd descriptor release.
|
* invocations before se_cmd descriptor release.
|
||||||
*/
|
*/
|
||||||
if (ack_kref) {
|
if (ack_kref)
|
||||||
kref_get(&se_cmd->cmd_kref);
|
kref_get(&se_cmd->cmd_kref);
|
||||||
se_cmd->se_cmd_flags |= SCF_ACK_KREF;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
||||||
if (se_sess->sess_tearing_down) {
|
if (se_sess->sess_tearing_down) {
|
||||||
|
@ -2398,6 +2507,7 @@ out:
|
||||||
EXPORT_SYMBOL(target_get_sess_cmd);
|
EXPORT_SYMBOL(target_get_sess_cmd);
|
||||||
|
|
||||||
static void target_release_cmd_kref(struct kref *kref)
|
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_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
|
||||||
struct se_session *se_sess = se_cmd->se_sess;
|
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;
|
entry = (void *) mb + CMDR_OFF + cmd_head;
|
||||||
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||||
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD);
|
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD);
|
||||||
tcmu_hdr_set_len(&entry->hdr, pad_size);
|
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);
|
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;
|
entry = (void *) mb + CMDR_OFF + cmd_head;
|
||||||
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||||
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD);
|
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
|
||||||
tcmu_hdr_set_len(&entry->hdr, command_size);
|
tcmu_hdr_set_len(&entry->hdr.len_op, command_size);
|
||||||
entry->cmd_id = tcmu_cmd->cmd_id;
|
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.
|
* 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 */
|
/* Even iov_base is relative to mb_addr */
|
||||||
iov->iov_len = 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;
|
||||||
iov_cnt++;
|
iov_cnt++;
|
||||||
iov++;
|
iov++;
|
||||||
|
|
||||||
|
@ -388,7 +394,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
|
||||||
copy_bytes = sg->length - copy_bytes;
|
copy_bytes = sg->length - copy_bytes;
|
||||||
|
|
||||||
iov->iov_len = 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) {
|
if (se_cmd->data_direction == DMA_TO_DEVICE) {
|
||||||
to = (void *) mb + udev->data_off + udev->data_head;
|
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);
|
kunmap_atomic(from);
|
||||||
}
|
}
|
||||||
entry->req.iov_cnt = iov_cnt;
|
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! */
|
/* All offsets relative to mb_addr, not start of entry! */
|
||||||
cdb_off = CMDR_OFF + cmd_head + base_command_size;
|
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;
|
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) {
|
if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
|
||||||
memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
|
memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
|
||||||
se_cmd->scsi_sense_length);
|
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));
|
tcmu_flush_dcache_range(entry, sizeof(*entry));
|
||||||
|
|
||||||
if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) {
|
if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) {
|
||||||
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);
|
||||||
continue;
|
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);
|
spin_lock(&udev->commands_lock);
|
||||||
cmd = idr_find(&udev->commands, entry->cmd_id);
|
cmd = idr_find(&udev->commands, entry->hdr.cmd_id);
|
||||||
if (cmd)
|
if (cmd)
|
||||||
idr_remove(&udev->commands, cmd->cmd_id);
|
idr_remove(&udev->commands, cmd->cmd_id);
|
||||||
spin_unlock(&udev->commands_lock);
|
spin_unlock(&udev->commands_lock);
|
||||||
|
@ -560,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
|
||||||
|
|
||||||
tcmu_handle_completion(cmd, entry);
|
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++;
|
handled++;
|
||||||
}
|
}
|
||||||
|
@ -838,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev)
|
||||||
udev->data_size = TCMU_RING_SIZE - CMDR_SIZE;
|
udev->data_size = TCMU_RING_SIZE - CMDR_SIZE;
|
||||||
|
|
||||||
mb = udev->mb_addr;
|
mb = udev->mb_addr;
|
||||||
mb->version = 1;
|
mb->version = TCMU_MAILBOX_VERSION;
|
||||||
mb->cmdr_off = CMDR_OFF;
|
mb->cmdr_off = CMDR_OFF;
|
||||||
mb->cmdr_size = udev->cmdr_size;
|
mb->cmdr_size = udev->cmdr_size;
|
||||||
|
|
||||||
WARN_ON(!PAGE_ALIGNED(udev->data_off));
|
WARN_ON(!PAGE_ALIGNED(udev->data_off));
|
||||||
WARN_ON(udev->data_size % PAGE_SIZE);
|
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].name = "tcm-user command & data buffer";
|
||||||
info->mem[0].addr = (phys_addr_t) udev->mb_addr;
|
info->mem[0].addr = (phys_addr_t) udev->mb_addr;
|
||||||
|
|
|
@ -34,20 +34,12 @@
|
||||||
#include <target/target_core_fabric.h>
|
#include <target/target_core_fabric.h>
|
||||||
#include <target/target_core_configfs.h>
|
#include <target/target_core_configfs.h>
|
||||||
|
|
||||||
|
#include "target_core_internal.h"
|
||||||
#include "target_core_pr.h"
|
#include "target_core_pr.h"
|
||||||
#include "target_core_ua.h"
|
#include "target_core_ua.h"
|
||||||
#include "target_core_xcopy.h"
|
#include "target_core_xcopy.h"
|
||||||
|
|
||||||
static struct workqueue_struct *xcopy_wq = NULL;
|
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)
|
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;
|
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_fabric_name = xcopy_pt_get_fabric_name,
|
||||||
.get_task_tag = xcopy_pt_get_tag,
|
.get_task_tag = xcopy_pt_get_tag,
|
||||||
.get_cmd_state = xcopy_pt_get_cmd_state,
|
.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(
|
static void target_xcopy_init_pt_lun(struct se_device *se_dev,
|
||||||
struct xcopy_pt_cmd *xpt_cmd,
|
struct se_cmd *pt_cmd, bool remote_port)
|
||||||
struct xcopy_op *xop,
|
|
||||||
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
|
* 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
|
* reservations. The pt_cmd->se_lun pointer will be setup from within
|
||||||
* target_xcopy_setup_pt_port()
|
* target_xcopy_setup_pt_port()
|
||||||
*/
|
*/
|
||||||
if (!remote_port) {
|
if (remote_port) {
|
||||||
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
|
pr_debug("Setup emulated se_dev: %p from se_dev\n",
|
||||||
return 0;
|
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_cmd_flags |= SCF_SE_LUN_CMD;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int target_xcopy_setup_pt_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
|
* 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.
|
* 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);
|
target_xcopy_init_pt_lun(se_dev, cmd, remote_port);
|
||||||
if (rc < 0) {
|
|
||||||
ret = rc;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
xpt_cmd->xcopy_op = xop;
|
xpt_cmd->xcopy_op = xop;
|
||||||
target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);
|
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 mutex ft_lport_lock;
|
||||||
extern struct fc4_prov ft_prov;
|
extern struct fc4_prov ft_prov;
|
||||||
extern struct target_fabric_configfs *ft_configfs;
|
|
||||||
extern unsigned int ft_debug_logging;
|
extern unsigned int ft_debug_logging;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
|
|
||||||
#include "tcm_fc.h"
|
#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);
|
static LIST_HEAD(ft_wwn_list);
|
||||||
DEFINE_MUTEX(ft_lport_lock);
|
DEFINE_MUTEX(ft_lport_lock);
|
||||||
|
@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg(
|
||||||
return NULL;
|
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);
|
tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
destroy_workqueue(wq);
|
destroy_workqueue(wq);
|
||||||
|
@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
|
||||||
return tpg->index;
|
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_name = ft_get_fabric_name,
|
||||||
.get_fabric_proto_ident = fc_get_fabric_proto_ident,
|
.get_fabric_proto_ident = fc_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = ft_get_fabric_wwn,
|
.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_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = &ft_add_acl,
|
.fabric_make_nodeacl = &ft_add_acl,
|
||||||
.fabric_drop_nodeacl = &ft_del_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 = {
|
static struct notifier_block ft_notifier = {
|
||||||
.notifier_call = ft_lport_notify
|
.notifier_call = ft_lport_notify
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ft_init(void)
|
static int __init ft_init(void)
|
||||||
{
|
{
|
||||||
if (ft_register_configfs())
|
int ret;
|
||||||
return -1;
|
|
||||||
if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) {
|
ret = target_register_template(&ft_fabric_ops);
|
||||||
ft_deregister_configfs();
|
if (ret)
|
||||||
return -1;
|
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);
|
blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
|
||||||
fc_lport_iterate(ft_lport_add, NULL);
|
fc_lport_iterate(ft_lport_add, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_unregister_template:
|
||||||
|
target_unregister_template(&ft_fabric_ops);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit ft_exit(void)
|
static void __exit ft_exit(void)
|
||||||
|
@ -632,7 +591,7 @@ static void __exit ft_exit(void)
|
||||||
&ft_notifier);
|
&ft_notifier);
|
||||||
fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
|
fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
|
||||||
fc_lport_iterate(ft_lport_del, NULL);
|
fc_lport_iterate(ft_lport_del, NULL);
|
||||||
ft_deregister_configfs();
|
target_unregister_template(&ft_fabric_ops);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
USB_GADGET_COMPOSITE_OPTIONS();
|
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)
|
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 = tport;
|
||||||
tpg->tport_tpgt = tpgt;
|
tpg->tport_tpgt = tpgt;
|
||||||
|
|
||||||
ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
|
ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg,
|
||||||
&tpg->se_tpg, tpg,
|
|
||||||
TRANSPORT_TPG_TYPE_NORMAL);
|
TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
destroy_workqueue(tpg->workqueue);
|
destroy_workqueue(tpg->workqueue);
|
||||||
|
@ -1864,7 +1863,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd)
|
||||||
return 1;
|
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_name = usbg_get_fabric_name,
|
||||||
.get_fabric_proto_ident = usbg_get_fabric_proto_ident,
|
.get_fabric_proto_ident = usbg_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = usbg_get_fabric_wwn,
|
.tpg_get_wwn = usbg_get_fabric_wwn,
|
||||||
|
@ -1906,46 +1907,9 @@ static struct target_core_fabric_ops usbg_ops = {
|
||||||
.fabric_drop_np = NULL,
|
.fabric_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = usbg_make_nodeacl,
|
.fabric_make_nodeacl = usbg_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = usbg_drop_nodeacl,
|
.fabric_drop_nodeacl = usbg_drop_nodeacl,
|
||||||
};
|
|
||||||
|
|
||||||
static int usbg_register_configfs(void)
|
.tfc_wwn_attrs = usbg_wwn_attrs,
|
||||||
{
|
.tfc_tpg_base_attrs = usbg_base_attrs,
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Start gadget.c code */
|
/* Start gadget.c code */
|
||||||
|
@ -2454,16 +2418,13 @@ static void usbg_detach(struct usbg_tpg *tpg)
|
||||||
|
|
||||||
static int __init usb_target_gadget_init(void)
|
static int __init usb_target_gadget_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
return target_register_template(&usbg_ops);
|
||||||
|
|
||||||
ret = usbg_register_configfs();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
module_init(usb_target_gadget_init);
|
module_init(usb_target_gadget_init);
|
||||||
|
|
||||||
static void __exit usb_target_gadget_exit(void)
|
static void __exit usb_target_gadget_exit(void)
|
||||||
{
|
{
|
||||||
usbg_deregister_configfs();
|
target_unregister_template(&usbg_ops);
|
||||||
}
|
}
|
||||||
module_exit(usb_target_gadget_exit);
|
module_exit(usb_target_gadget_exit);
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,8 @@ struct vhost_scsi_tpg {
|
||||||
int tv_tpg_port_count;
|
int tv_tpg_port_count;
|
||||||
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
|
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
|
||||||
int tv_tpg_vhost_count;
|
int tv_tpg_vhost_count;
|
||||||
|
/* Used for enabling T10-PI with legacy devices */
|
||||||
|
int tv_fabric_prot_type;
|
||||||
/* list for vhost_scsi_list */
|
/* list for vhost_scsi_list */
|
||||||
struct list_head tv_tpg_list;
|
struct list_head tv_tpg_list;
|
||||||
/* Used to protect access for tpg_nexus */
|
/* 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 */
|
int vs_events_nr; /* num of pending events, protected by vq->mutex */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Local pointer to allocated TCM configfs fabric module */
|
static struct target_core_fabric_ops vhost_scsi_ops;
|
||||||
static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
|
|
||||||
|
|
||||||
static struct workqueue_struct *vhost_scsi_workqueue;
|
static struct workqueue_struct *vhost_scsi_workqueue;
|
||||||
|
|
||||||
/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
|
/* 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);
|
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 *
|
static struct se_node_acl *
|
||||||
vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg)
|
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,
|
static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
|
@ -2155,7 +2202,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn,
|
||||||
tpg->tport = tport;
|
tpg->tport = tport;
|
||||||
tpg->tport_tpgt = tpgt;
|
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);
|
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(tpg);
|
kfree(tpg);
|
||||||
|
@ -2277,6 +2324,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct target_core_fabric_ops vhost_scsi_ops = {
|
static struct target_core_fabric_ops vhost_scsi_ops = {
|
||||||
|
.module = THIS_MODULE,
|
||||||
|
.name = "vhost",
|
||||||
.get_fabric_name = vhost_scsi_get_fabric_name,
|
.get_fabric_name = vhost_scsi_get_fabric_name,
|
||||||
.get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
|
.get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = vhost_scsi_get_fabric_wwn,
|
.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_cache = vhost_scsi_check_true,
|
||||||
.tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
|
.tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
|
||||||
.tpg_check_prod_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_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl,
|
||||||
.tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
|
.tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
|
||||||
.tpg_get_inst_index = vhost_scsi_tpg_get_inst_index,
|
.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_drop_np = NULL,
|
||||||
.fabric_make_nodeacl = vhost_scsi_make_nodeacl,
|
.fabric_make_nodeacl = vhost_scsi_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
|
.fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
|
||||||
};
|
|
||||||
|
|
||||||
static int vhost_scsi_register_configfs(void)
|
.tfc_wwn_attrs = vhost_scsi_wwn_attrs,
|
||||||
{
|
.tfc_tpg_base_attrs = vhost_scsi_tpg_attrs,
|
||||||
struct target_fabric_configfs *fabric;
|
.tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs,
|
||||||
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");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init vhost_scsi_init(void)
|
static int __init vhost_scsi_init(void)
|
||||||
{
|
{
|
||||||
int ret = -ENOMEM;
|
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
|
* Use our own dedicated workqueue for submitting I/O into
|
||||||
* target core to avoid contention within system_wq.
|
* target core to avoid contention within system_wq.
|
||||||
|
@ -2396,7 +2396,7 @@ static int __init vhost_scsi_init(void)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_destroy_workqueue;
|
goto out_destroy_workqueue;
|
||||||
|
|
||||||
ret = vhost_scsi_register_configfs();
|
ret = target_register_template(&vhost_scsi_ops);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_vhost_scsi_deregister;
|
goto out_vhost_scsi_deregister;
|
||||||
|
|
||||||
|
@ -2412,7 +2412,7 @@ out:
|
||||||
|
|
||||||
static void vhost_scsi_exit(void)
|
static void vhost_scsi_exit(void)
|
||||||
{
|
{
|
||||||
vhost_scsi_deregister_configfs();
|
target_unregister_template(&vhost_scsi_ops);
|
||||||
vhost_scsi_deregister();
|
vhost_scsi_deregister();
|
||||||
destroy_workqueue(vhost_scsi_workqueue);
|
destroy_workqueue(vhost_scsi_workqueue);
|
||||||
};
|
};
|
||||||
|
|
|
@ -204,8 +204,7 @@ static LIST_HEAD(scsiback_free_pages);
|
||||||
static DEFINE_MUTEX(scsiback_mutex);
|
static DEFINE_MUTEX(scsiback_mutex);
|
||||||
static LIST_HEAD(scsiback_list);
|
static LIST_HEAD(scsiback_list);
|
||||||
|
|
||||||
/* Local pointer to allocated TCM configfs fabric module */
|
static const struct target_core_fabric_ops scsiback_ops;
|
||||||
static struct target_fabric_configfs *scsiback_fabric_configfs;
|
|
||||||
|
|
||||||
static void scsiback_get(struct vscsibk_info *info)
|
static void scsiback_get(struct vscsibk_info *info)
|
||||||
{
|
{
|
||||||
|
@ -1902,7 +1901,7 @@ scsiback_make_tpg(struct se_wwn *wwn,
|
||||||
tpg->tport = tport;
|
tpg->tport = tport;
|
||||||
tpg->tport_tpgt = tpgt;
|
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);
|
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(tpg);
|
kfree(tpg);
|
||||||
|
@ -1944,7 +1943,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg)
|
||||||
return 0;
|
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_name = scsiback_get_fabric_name,
|
||||||
.get_fabric_proto_ident = scsiback_get_fabric_proto_ident,
|
.get_fabric_proto_ident = scsiback_get_fabric_proto_ident,
|
||||||
.tpg_get_wwn = scsiback_get_fabric_wwn,
|
.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_make_nodeacl = scsiback_make_nodeacl,
|
||||||
.fabric_drop_nodeacl = scsiback_drop_nodeacl,
|
.fabric_drop_nodeacl = scsiback_drop_nodeacl,
|
||||||
#endif
|
#endif
|
||||||
};
|
|
||||||
|
|
||||||
static int scsiback_register_configfs(void)
|
.tfc_wwn_attrs = scsiback_wwn_attrs,
|
||||||
{
|
.tfc_tpg_base_attrs = scsiback_tpg_attrs,
|
||||||
struct target_fabric_configfs *fabric;
|
.tfc_tpg_param_attrs = scsiback_param_attrs,
|
||||||
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");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct xenbus_device_id scsiback_ids[] = {
|
static const struct xenbus_device_id scsiback_ids[] = {
|
||||||
|
@ -2078,6 +2027,9 @@ static int __init scsiback_init(void)
|
||||||
if (!xen_domain())
|
if (!xen_domain())
|
||||||
return -ENODEV;
|
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",
|
scsiback_cachep = kmem_cache_create("vscsiif_cache",
|
||||||
sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
|
sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
|
||||||
if (!scsiback_cachep)
|
if (!scsiback_cachep)
|
||||||
|
@ -2087,7 +2039,7 @@ static int __init scsiback_init(void)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_cache_destroy;
|
goto out_cache_destroy;
|
||||||
|
|
||||||
ret = scsiback_register_configfs();
|
ret = target_register_template(&scsiback_ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unregister_xenbus;
|
goto out_unregister_xenbus;
|
||||||
|
|
||||||
|
@ -2110,7 +2062,7 @@ static void __exit scsiback_exit(void)
|
||||||
BUG();
|
BUG();
|
||||||
gnttab_free_pages(1, &page);
|
gnttab_free_pages(1, &page);
|
||||||
}
|
}
|
||||||
scsiback_deregister_configfs();
|
target_unregister_template(&scsiback_ops);
|
||||||
xenbus_unregister_driver(&scsiback_driver);
|
xenbus_unregister_driver(&scsiback_driver);
|
||||||
kmem_cache_destroy(scsiback_cachep);
|
kmem_cache_destroy(scsiback_cachep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#define ISCSIT_MIN_TAGS 16
|
#define ISCSIT_MIN_TAGS 16
|
||||||
#define ISCSIT_EXTRA_TAGS 8
|
#define ISCSIT_EXTRA_TAGS 8
|
||||||
#define ISCSIT_TCP_BACKLOG 256
|
#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 */
|
/* struct iscsi_node_attrib sanity values */
|
||||||
#define NA_DATAOUT_TIMEOUT 3
|
#define NA_DATAOUT_TIMEOUT 3
|
||||||
|
@ -60,6 +62,7 @@
|
||||||
#define TA_CACHE_CORE_NPS 0
|
#define TA_CACHE_CORE_NPS 0
|
||||||
/* T10 protection information disabled by default */
|
/* T10 protection information disabled by default */
|
||||||
#define TA_DEFAULT_T10_PI 0
|
#define TA_DEFAULT_T10_PI 0
|
||||||
|
#define TA_DEFAULT_FABRIC_PROT_TYPE 0
|
||||||
|
|
||||||
#define ISCSI_IOV_DATA_BUFFER 5
|
#define ISCSI_IOV_DATA_BUFFER 5
|
||||||
|
|
||||||
|
@ -600,8 +603,11 @@ struct iscsi_conn {
|
||||||
struct iscsi_tpg_np *tpg_np;
|
struct iscsi_tpg_np *tpg_np;
|
||||||
/* Pointer to parent session */
|
/* Pointer to parent session */
|
||||||
struct iscsi_session *sess;
|
struct iscsi_session *sess;
|
||||||
/* Pointer to thread_set in use for this conn's threads */
|
int bitmap_id;
|
||||||
struct iscsi_thread_set *thread_set;
|
int rx_thread_active;
|
||||||
|
struct task_struct *rx_thread;
|
||||||
|
int tx_thread_active;
|
||||||
|
struct task_struct *tx_thread;
|
||||||
/* list_head for session connection list */
|
/* list_head for session connection list */
|
||||||
struct list_head conn_list;
|
struct list_head conn_list;
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
@ -767,6 +773,7 @@ struct iscsi_tpg_attrib {
|
||||||
u32 demo_mode_discovery;
|
u32 demo_mode_discovery;
|
||||||
u32 default_erl;
|
u32 default_erl;
|
||||||
u8 t10_pi;
|
u8 t10_pi;
|
||||||
|
u32 fabric_prot_type;
|
||||||
struct iscsi_portal_group *tpg;
|
struct iscsi_portal_group *tpg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -871,10 +878,10 @@ struct iscsit_global {
|
||||||
/* Unique identifier used for the authentication daemon */
|
/* Unique identifier used for the authentication daemon */
|
||||||
u32 auth_id;
|
u32 auth_id;
|
||||||
u32 inactive_ts;
|
u32 inactive_ts;
|
||||||
/* Thread Set bitmap count */
|
#define ISCSIT_BITMAP_BITS 262144
|
||||||
int ts_bitmap_count;
|
|
||||||
/* Thread Set bitmap pointer */
|
/* Thread Set bitmap pointer */
|
||||||
unsigned long *ts_bitmap;
|
unsigned long *ts_bitmap;
|
||||||
|
spinlock_t ts_bitmap_lock;
|
||||||
/* Used for iSCSI discovery session authentication */
|
/* Used for iSCSI discovery session authentication */
|
||||||
struct iscsi_node_acl discovery_acl;
|
struct iscsi_node_acl discovery_acl;
|
||||||
struct iscsi_portal_group *discovery_tpg;
|
struct iscsi_portal_group *discovery_tpg;
|
||||||
|
|
|
@ -165,10 +165,8 @@ enum se_cmd_flags_table {
|
||||||
SCF_SEND_DELAYED_TAS = 0x00004000,
|
SCF_SEND_DELAYED_TAS = 0x00004000,
|
||||||
SCF_ALUA_NON_OPTIMIZED = 0x00008000,
|
SCF_ALUA_NON_OPTIMIZED = 0x00008000,
|
||||||
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
|
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
|
||||||
SCF_ACK_KREF = 0x00040000,
|
|
||||||
SCF_COMPARE_AND_WRITE = 0x00080000,
|
SCF_COMPARE_AND_WRITE = 0x00080000,
|
||||||
SCF_COMPARE_AND_WRITE_POST = 0x00100000,
|
SCF_COMPARE_AND_WRITE_POST = 0x00100000,
|
||||||
SCF_CMD_XCOPY_PASSTHROUGH = 0x00200000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
|
/* 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 list_head se_cmd_list;
|
||||||
struct completion cmd_wait_comp;
|
struct completion cmd_wait_comp;
|
||||||
struct kref cmd_kref;
|
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_cmd)(struct se_cmd *);
|
||||||
sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *,
|
sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *,
|
||||||
u32, enum dma_data_direction);
|
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;
|
||||||
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
|
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
|
||||||
|
@ -591,6 +589,7 @@ struct se_node_acl {
|
||||||
bool acl_stop:1;
|
bool acl_stop:1;
|
||||||
u32 queue_depth;
|
u32 queue_depth;
|
||||||
u32 acl_index;
|
u32 acl_index;
|
||||||
|
enum target_prot_type saved_prot_type;
|
||||||
#define MAX_ACL_TAG_SIZE 64
|
#define MAX_ACL_TAG_SIZE 64
|
||||||
char acl_tag[MAX_ACL_TAG_SIZE];
|
char acl_tag[MAX_ACL_TAG_SIZE];
|
||||||
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
|
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
|
||||||
|
@ -616,6 +615,7 @@ struct se_session {
|
||||||
unsigned sess_tearing_down:1;
|
unsigned sess_tearing_down:1;
|
||||||
u64 sess_bin_isid;
|
u64 sess_bin_isid;
|
||||||
enum target_prot_op sup_prot_ops;
|
enum target_prot_op sup_prot_ops;
|
||||||
|
enum target_prot_type sess_prot_type;
|
||||||
struct se_node_acl *se_node_acl;
|
struct se_node_acl *se_node_acl;
|
||||||
struct se_portal_group *se_tpg;
|
struct se_portal_group *se_tpg;
|
||||||
void *fabric_sess_ptr;
|
void *fabric_sess_ptr;
|
||||||
|
@ -890,7 +890,7 @@ struct se_portal_group {
|
||||||
/* List of TCM sessions associated wth this TPG */
|
/* List of TCM sessions associated wth this TPG */
|
||||||
struct list_head tpg_sess_list;
|
struct list_head tpg_sess_list;
|
||||||
/* Pointer to $FABRIC_MOD dependent code */
|
/* 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 se_wwn *se_tpg_wwn;
|
||||||
struct config_group tpg_group;
|
struct config_group tpg_group;
|
||||||
struct config_group *tpg_default_groups[7];
|
struct config_group *tpg_default_groups[7];
|
||||||
|
|
|
@ -5,12 +5,6 @@
|
||||||
#define TARGET_CORE_NAME_MAX_LEN 64
|
#define TARGET_CORE_NAME_MAX_LEN 64
|
||||||
#define TARGET_FABRIC_NAME_SIZE 32
|
#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 target_fabric_configfs_template {
|
||||||
struct config_item_type tfc_discovery_cit;
|
struct config_item_type tfc_discovery_cit;
|
||||||
struct config_item_type tfc_wwn_cit;
|
struct config_item_type tfc_wwn_cit;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define TARGET_CORE_FABRIC_H
|
#define TARGET_CORE_FABRIC_H
|
||||||
|
|
||||||
struct target_core_fabric_ops {
|
struct target_core_fabric_ops {
|
||||||
|
struct module *module;
|
||||||
|
const char *name;
|
||||||
struct configfs_subsystem *tf_subsys;
|
struct configfs_subsystem *tf_subsys;
|
||||||
char *(*get_fabric_name)(void);
|
char *(*get_fabric_name)(void);
|
||||||
u8 (*get_fabric_proto_ident)(struct se_portal_group *);
|
u8 (*get_fabric_proto_ident)(struct se_portal_group *);
|
||||||
|
@ -27,6 +29,14 @@ struct target_core_fabric_ops {
|
||||||
* inquiry response
|
* inquiry response
|
||||||
*/
|
*/
|
||||||
int (*tpg_check_demo_mode_login_only)(struct se_portal_group *);
|
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_node_acl *(*tpg_alloc_fabric_acl)(
|
||||||
struct se_portal_group *);
|
struct se_portal_group *);
|
||||||
void (*tpg_release_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 se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *,
|
||||||
struct config_group *, const char *);
|
struct config_group *, const char *);
|
||||||
void (*fabric_drop_nodeacl)(struct se_node_acl *);
|
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);
|
struct se_session *transport_init_session(enum target_prot_op);
|
||||||
int transport_alloc_session_tags(struct se_session *, unsigned int,
|
int transport_alloc_session_tags(struct se_session *, unsigned int,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
|
@ -95,13 +120,15 @@ void transport_register_session(struct se_portal_group *,
|
||||||
struct se_node_acl *, struct se_session *, void *);
|
struct se_node_acl *, struct se_session *, void *);
|
||||||
void target_get_session(struct se_session *);
|
void target_get_session(struct se_session *);
|
||||||
void target_put_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 transport_free_session(struct se_session *);
|
||||||
void target_put_nacl(struct se_node_acl *);
|
void target_put_nacl(struct se_node_acl *);
|
||||||
void transport_deregister_session_configfs(struct se_session *);
|
void transport_deregister_session_configfs(struct se_session *);
|
||||||
void transport_deregister_session(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 *);
|
struct se_session *, u32, int, int, unsigned char *);
|
||||||
sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
|
sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
|
||||||
sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
|
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);
|
unsigned char *, u32, int);
|
||||||
int core_tpg_set_initiator_node_tag(struct se_portal_group *,
|
int core_tpg_set_initiator_node_tag(struct se_portal_group *,
|
||||||
struct se_node_acl *, const char *);
|
struct se_node_acl *, const char *);
|
||||||
int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *,
|
int core_tpg_register(const struct target_core_fabric_ops *,
|
||||||
struct se_portal_group *, void *, int);
|
struct se_wwn *, struct se_portal_group *, void *, int);
|
||||||
int core_tpg_deregister(struct se_portal_group *);
|
int core_tpg_deregister(struct se_portal_group *);
|
||||||
|
|
||||||
/* SAS helpers */
|
/* SAS helpers */
|
||||||
|
|
|
@ -90,6 +90,11 @@ static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
|
||||||
_fabric##_tpg_store_##_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);
|
CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs);
|
||||||
#define TF_WWN_ATTR(_fabric, _name, _mode) \
|
#define TF_WWN_ATTR(_fabric, _name, _mode) \
|
||||||
static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
|
static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
|
|
||||||
#define TCMU_VERSION "1.0"
|
#define TCMU_VERSION "2.0"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ring Design
|
* Ring Design
|
||||||
|
@ -39,9 +39,13 @@
|
||||||
* should process the next packet the same way, and so on.
|
* 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 */
|
#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 {
|
struct tcmu_mailbox {
|
||||||
__u16 version;
|
__u16 version;
|
||||||
__u16 flags;
|
__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.
|
* Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode.
|
||||||
*/
|
*/
|
||||||
struct tcmu_cmd_entry_hdr {
|
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;
|
} __packed;
|
||||||
|
|
||||||
#define TCMU_OP_MASK 0x7
|
#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;
|
*len_op &= ~TCMU_OP_MASK;
|
||||||
hdr->len_op |= (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;
|
*len_op &= TCMU_OP_MASK;
|
||||||
hdr->len_op |= len;
|
*len_op |= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently the same as SCSI_SENSE_BUFFERSIZE */
|
/* 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 {
|
||||||
struct tcmu_cmd_entry_hdr hdr;
|
struct tcmu_cmd_entry_hdr hdr;
|
||||||
|
|
||||||
uint16_t cmd_id;
|
|
||||||
uint16_t __pad1;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
|
uint32_t iov_cnt;
|
||||||
|
uint32_t iov_bidi_cnt;
|
||||||
|
uint32_t iov_dif_cnt;
|
||||||
uint64_t cdb_off;
|
uint64_t cdb_off;
|
||||||
uint64_t iov_cnt;
|
uint64_t __pad1;
|
||||||
|
uint64_t __pad2;
|
||||||
struct iovec iov[0];
|
struct iovec iov[0];
|
||||||
} req;
|
} req;
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Reference in New Issue