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:
Linus Torvalds 2015-04-24 10:22:09 -07:00
commit c6668726d2
50 changed files with 1703 additions and 2289 deletions

View File

@ -237,8 +237,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
buf += "/* Local pointer to allocated TCM configfs fabric module */\n"
buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n"
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n"
buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
buf += " struct se_portal_group *se_tpg,\n"
@ -309,8 +308,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " }\n"
buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n"
buf += " &tpg->se_tpg, (void *)tpg,\n"
buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
buf += " &tpg->se_tpg, tpg,\n"
buf += " TRANSPORT_TPG_TYPE_NORMAL);\n"
buf += " if (ret < 0) {\n"
buf += " kfree(tpg);\n"
@ -370,7 +369,10 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " NULL,\n"
buf += "};\n\n"
buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
buf += " .module = THIS_MODULE,\n"
buf += " .name = " + fabric_mod_name + ",\n"
buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n"
buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n"
buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n"
buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n"
@ -413,75 +415,18 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " .fabric_drop_np = NULL,\n"
buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n"
buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n"
buf += "};\n\n"
buf += "static int " + fabric_mod_name + "_register_configfs(void)\n"
buf += "{\n"
buf += " struct target_fabric_configfs *fabric;\n"
buf += " int ret;\n\n"
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
buf += " utsname()->machine);\n"
buf += " /*\n"
buf += " * Register the top level struct config_item_type with TCM core\n"
buf += " */\n"
buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n"
buf += " if (IS_ERR(fabric)) {\n"
buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
buf += " return PTR_ERR(fabric);\n"
buf += " }\n"
buf += " /*\n"
buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n"
buf += " */\n"
buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n"
buf += " /*\n"
buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n"
buf += " */\n"
buf += " fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n"
buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n"
buf += " /*\n"
buf += " * Register the fabric for use within TCM\n"
buf += " */\n"
buf += " ret = target_fabric_configfs_register(fabric);\n"
buf += " if (ret < 0) {\n"
buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n"
buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n"
buf += " return ret;\n"
buf += " }\n"
buf += " /*\n"
buf += " * Setup our local pointer to *fabric\n"
buf += " */\n"
buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n"
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n"
buf += " return 0;\n"
buf += "};\n\n"
buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n"
buf += "{\n"
buf += " if (!" + fabric_mod_name + "_fabric_configfs)\n"
buf += " return;\n\n"
buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n"
buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n"
buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n"
buf += "\n"
buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
buf += "};\n\n"
buf += "static int __init " + fabric_mod_name + "_init(void)\n"
buf += "{\n"
buf += " int ret;\n\n"
buf += " ret = " + fabric_mod_name + "_register_configfs();\n"
buf += " if (ret < 0)\n"
buf += " return ret;\n\n"
buf += " return 0;\n"
buf += " return target_register_template(" + fabric_mod_name + "_ops);\n"
buf += "};\n\n"
buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
buf += "{\n"
buf += " " + fabric_mod_name + "_deregister_configfs();\n"
buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n"
buf += "};\n\n"
buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"

View File

@ -138,27 +138,40 @@ signals the kernel via a 4-byte write(). When cmd_head equals
cmd_tail, the ring is empty -- no commands are currently waiting to be
processed by userspace.
TCMU commands start with a common header containing "len_op", a 32-bit
value that stores the length, as well as the opcode in the lowest
unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and
TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it
should skip ahead by the bytes in "length". (The kernel inserts PAD
entries to ensure each CMD entry fits contigously into the circular
buffer.)
TCMU commands are 8-byte aligned. They start with a common header
containing "len_op", a 32-bit value that stores the length, as well as
the opcode in the lowest unused bits. It also contains cmd_id and
flags fields for setting by the kernel (kflags) and userspace
(uflags).
When userspace handles a CMD, it finds the SCSI CDB (Command Data
Block) via tcmu_cmd_entry.req.cdb_off. This is an offset from the
start of the overall shared memory region, not the entry. The data
in/out buffers are accessible via tht req.iov[] array. Note that
each iov.iov_base is also an offset from the start of the region.
Currently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD.
TCMU currently does not support BIDI operations.
When the opcode is CMD, the entry in the command ring is a struct
tcmu_cmd_entry. Userspace finds the SCSI CDB (Command Data Block) via
tcmu_cmd_entry.req.cdb_off. This is an offset from the start of the
overall shared memory region, not the entry. The data in/out buffers
are accessible via tht req.iov[] array. iov_cnt contains the number of
entries in iov[] needed to describe either the Data-In or Data-Out
buffers. For bidirectional commands, iov_cnt specifies how many iovec
entries cover the Data-Out area, and iov_bidi_count specifies how many
iovec entries immediately after that in iov[] cover the Data-In
area. Just like other fields, iov.iov_base is an offset from the start
of the region.
When completing a command, userspace sets rsp.scsi_status, and
rsp.sense_buffer if necessary. Userspace then increments
mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the
kernel via the UIO method, a 4-byte write to the file descriptor.
When the opcode is PAD, userspace only updates cmd_tail as above --
it's a no-op. (The kernel inserts PAD entries to ensure each CMD entry
is contiguous within the command ring.)
More opcodes may be added in the future. If userspace encounters an
opcode it does not handle, it must set UNKNOWN_OP bit (bit 0) in
hdr.uflags, update cmd_tail, and proceed with processing additional
commands, if any.
The Data Area:
This is shared-memory space after the command ring. The organization

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,6 @@
#define isert_err(fmt, arg...) \
pr_err(PFX "%s: " fmt, __func__ , ## arg)
#define ISERT_RDMA_LISTEN_BACKLOG 10
#define ISCSI_ISER_SG_TABLESIZE 256
#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
#define ISER_BEACON_WRID 0xfffffffffffffffeULL
@ -160,27 +159,25 @@ struct isert_conn {
u64 login_req_dma;
int login_req_len;
u64 login_rsp_dma;
unsigned int conn_rx_desc_head;
struct iser_rx_desc *conn_rx_descs;
struct ib_recv_wr conn_rx_wr[ISERT_MIN_POSTED_RX];
unsigned int rx_desc_head;
struct iser_rx_desc *rx_descs;
struct ib_recv_wr rx_wr[ISERT_MIN_POSTED_RX];
struct iscsi_conn *conn;
struct list_head conn_accept_node;
struct completion conn_login_comp;
struct list_head accept_node;
struct completion login_comp;
struct completion login_req_comp;
struct iser_tx_desc conn_login_tx_desc;
struct rdma_cm_id *conn_cm_id;
struct ib_pd *conn_pd;
struct ib_mr *conn_mr;
struct ib_qp *conn_qp;
struct isert_device *conn_device;
struct mutex conn_mutex;
struct completion conn_wait;
struct completion conn_wait_comp_err;
struct kref conn_kref;
struct list_head conn_fr_pool;
int conn_fr_pool_size;
struct iser_tx_desc login_tx_desc;
struct rdma_cm_id *cm_id;
struct ib_qp *qp;
struct isert_device *device;
struct mutex mutex;
struct completion wait;
struct completion wait_comp_err;
struct kref kref;
struct list_head fr_pool;
int fr_pool_size;
/* lock to protect fastreg pool */
spinlock_t conn_lock;
spinlock_t pool_lock;
struct work_struct release_work;
struct ib_recv_wr beacon;
bool logout_posted;
@ -211,6 +208,8 @@ struct isert_device {
bool pi_capable;
int refcount;
struct ib_device *ib_device;
struct ib_pd *pd;
struct ib_mr *mr;
struct isert_comp *comps;
int comps_used;
struct list_head dev_node;

View File

@ -93,7 +93,7 @@ MODULE_PARM_DESC(srpt_service_guid,
" instead of using the node_guid of the first HCA.");
static struct ib_client srpt_client;
static struct target_fabric_configfs *srpt_target;
static const struct target_core_fabric_ops srpt_template;
static void srpt_release_channel(struct srpt_rdma_ch *ch);
static int srpt_queue_status(struct se_cmd *cmd);
@ -3845,7 +3845,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
int res;
/* Initialize sport->port_wwn and sport->port_tpg_1 */
res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn,
res = core_tpg_register(&srpt_template, &sport->port_wwn,
&sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL);
if (res)
return ERR_PTR(res);
@ -3913,7 +3913,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = {
NULL,
};
static struct target_core_fabric_ops srpt_template = {
static const struct target_core_fabric_ops srpt_template = {
.module = THIS_MODULE,
.name = "srpt",
.get_fabric_name = srpt_get_fabric_name,
.get_fabric_proto_ident = srpt_get_fabric_proto_ident,
.tpg_get_wwn = srpt_get_fabric_wwn,
@ -3958,6 +3960,10 @@ static struct target_core_fabric_ops srpt_template = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = srpt_make_nodeacl,
.fabric_drop_nodeacl = srpt_drop_nodeacl,
.tfc_wwn_attrs = srpt_wwn_attrs,
.tfc_tpg_base_attrs = srpt_tpg_attrs,
.tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs,
};
/**
@ -3988,33 +3994,9 @@ static int __init srpt_init_module(void)
goto out;
}
srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt");
if (IS_ERR(srpt_target)) {
pr_err("couldn't register\n");
ret = PTR_ERR(srpt_target);
ret = target_register_template(&srpt_template);
if (ret)
goto out;
}
srpt_target->tf_ops = srpt_template;
/*
* Set up default attribute lists.
*/
srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs;
srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs;
srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs;
srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
ret = target_fabric_configfs_register(srpt_target);
if (ret < 0) {
pr_err("couldn't register\n");
goto out_free_target;
}
ret = ib_register_client(&srpt_client);
if (ret) {
@ -4025,11 +4007,7 @@ static int __init srpt_init_module(void)
return 0;
out_unregister_target:
target_fabric_configfs_deregister(srpt_target);
srpt_target = NULL;
out_free_target:
if (srpt_target)
target_fabric_configfs_free(srpt_target);
target_unregister_template(&srpt_template);
out:
return ret;
}
@ -4037,8 +4015,7 @@ static int __init srpt_init_module(void)
static void __exit srpt_cleanup_module(void)
{
ib_unregister_client(&srpt_client);
target_fabric_configfs_deregister(srpt_target);
srpt_target = NULL;
target_unregister_template(&srpt_template);
}
module_init(srpt_init_module);

View File

@ -3065,7 +3065,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
{
struct qla_hw_data *ha = vha->hw;
struct se_cmd *se_cmd;
struct target_core_fabric_ops *tfo;
const struct target_core_fabric_ops *tfo;
struct qla_tgt_cmd *cmd;
if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) {

View File

@ -53,9 +53,8 @@
static struct workqueue_struct *tcm_qla2xxx_free_wq;
static struct workqueue_struct *tcm_qla2xxx_cmd_wq;
/* Local pointer to allocated TCM configfs fabric module */
static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
static const struct target_core_fabric_ops tcm_qla2xxx_ops;
static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops;
/*
* Parse WWN.
@ -336,6 +335,14 @@ static int tcm_qla2xxx_check_demo_mode_login_only(struct se_portal_group *se_tpg
return tpg->tpg_attrib.demo_mode_login_only;
}
static int tcm_qla2xxx_check_prot_fabric_only(struct se_portal_group *se_tpg)
{
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
return tpg->tpg_attrib.fabric_prot_type;
}
static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl(
struct se_portal_group *se_tpg)
{
@ -1082,8 +1089,53 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR);
static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions(
struct se_portal_group *se_tpg,
char *page)
{
return target_show_dynamic_sessions(se_tpg, page);
}
TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions);
static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long val;
int ret = kstrtoul(page, 0, &val);
if (ret) {
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
return ret;
}
if (val != 0 && val != 1 && val != 3) {
pr_err("Invalid qla2xxx fabric_prot_type: %lu\n", val);
return -EINVAL;
}
tpg->tpg_attrib.fabric_prot_type = val;
return count;
}
static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type(
struct se_portal_group *se_tpg,
char *page)
{
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type);
}
TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR);
static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = {
&tcm_qla2xxx_tpg_enable.attr,
&tcm_qla2xxx_tpg_dynamic_sessions.attr,
&tcm_qla2xxx_tpg_fabric_prot_type.attr,
NULL,
};
@ -1124,7 +1176,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
tpg->tpg_attrib.cache_dynamic_acls = 1;
tpg->tpg_attrib.demo_mode_login_only = 1;
ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn,
ret = core_tpg_register(&tcm_qla2xxx_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
@ -1244,7 +1296,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
tpg->tpg_attrib.cache_dynamic_acls = 1;
tpg->tpg_attrib.demo_mode_login_only = 1;
ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
@ -1560,7 +1612,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
se_sess = transport_init_session_tags(num_tags,
sizeof(struct qla_tgt_cmd),
TARGET_PROT_NORMAL);
TARGET_PROT_ALL);
if (IS_ERR(se_sess)) {
pr_err("Unable to initialize struct se_session\n");
return PTR_ERR(se_sess);
@ -1934,7 +1986,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
NULL,
};
static struct target_core_fabric_ops tcm_qla2xxx_ops = {
static const struct target_core_fabric_ops tcm_qla2xxx_ops = {
.module = THIS_MODULE,
.name = "qla2xxx",
.get_fabric_name = tcm_qla2xxx_get_fabric_name,
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
@ -1949,6 +2003,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
tcm_qla2xxx_check_demo_write_protect,
.tpg_check_prod_mode_write_protect =
tcm_qla2xxx_check_prod_write_protect,
.tpg_check_prot_fabric_only = tcm_qla2xxx_check_prot_fabric_only,
.tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
.tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl,
.tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl,
@ -1983,9 +2038,15 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
.fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl,
.tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs,
.tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs,
.tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs,
};
static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.module = THIS_MODULE,
.name = "qla2xxx_npiv",
.get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name,
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
.tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
@ -2033,94 +2094,26 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl,
.fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl,
.tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs,
.tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs,
};
static int tcm_qla2xxx_register_configfs(void)
{
struct target_fabric_configfs *fabric, *npiv_fabric;
int ret;
pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
utsname()->machine);
/*
* Register the top level struct config_item_type with TCM core
*/
fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx");
if (IS_ERR(fabric)) {
pr_err("target_fabric_configfs_init() failed\n");
return PTR_ERR(fabric);
}
/*
* Setup fabric->tf_ops from our local tcm_qla2xxx_ops
*/
fabric->tf_ops = tcm_qla2xxx_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs =
tcm_qla2xxx_tpg_attrib_attrs;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
/*
* Register the fabric for use within TCM
*/
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
return ret;
}
/*
* Setup our local pointer to *fabric
*/
tcm_qla2xxx_fabric_configfs = fabric;
pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n");
/*
* Register the top level struct config_item_type for NPIV with TCM core
*/
npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv");
if (IS_ERR(npiv_fabric)) {
pr_err("target_fabric_configfs_init() failed\n");
ret = PTR_ERR(npiv_fabric);
ret = target_register_template(&tcm_qla2xxx_ops);
if (ret)
return ret;
ret = target_register_template(&tcm_qla2xxx_npiv_ops);
if (ret)
goto out_fabric;
}
/*
* Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops
*/
npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops;
/*
* Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
*/
npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
tcm_qla2xxx_npiv_tpg_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
/*
* Register the npiv_fabric for use within TCM
*/
ret = target_fabric_configfs_register(npiv_fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
goto out_fabric;
}
/*
* Setup our local pointer to *npiv_fabric
*/
tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric;
pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n");
tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free",
WQ_MEM_RECLAIM, 0);
@ -2140,9 +2133,9 @@ static int tcm_qla2xxx_register_configfs(void)
out_free_wq:
destroy_workqueue(tcm_qla2xxx_free_wq);
out_fabric_npiv:
target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
target_unregister_template(&tcm_qla2xxx_npiv_ops);
out_fabric:
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
target_unregister_template(&tcm_qla2xxx_ops);
return ret;
}
@ -2151,13 +2144,8 @@ static void tcm_qla2xxx_deregister_configfs(void)
destroy_workqueue(tcm_qla2xxx_cmd_wq);
destroy_workqueue(tcm_qla2xxx_free_wq);
target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
tcm_qla2xxx_fabric_configfs = NULL;
pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n");
target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
tcm_qla2xxx_npiv_fabric_configfs = NULL;
pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n");
target_unregister_template(&tcm_qla2xxx_ops);
target_unregister_template(&tcm_qla2xxx_npiv_ops);
}
static int __init tcm_qla2xxx_init(void)

View File

@ -33,6 +33,7 @@ struct tcm_qla2xxx_tpg_attrib {
int demo_mode_write_protect;
int prod_mode_write_protect;
int demo_mode_login_only;
int fabric_prot_type;
};
struct tcm_qla2xxx_tpg {

View File

@ -31,12 +31,13 @@ config TCM_PSCSI
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
passthrough access to Linux/SCSI device
config TCM_USER
config TCM_USER2
tristate "TCM/USER Subsystem Plugin for Linux"
depends on UIO && NET
help
Say Y here to enable the TCM/USER subsystem plugin for a userspace
process to handle requests
process to handle requests. This is version 2 of the ABI; version 1
is obsolete.
source "drivers/target/loopback/Kconfig"
source "drivers/target/tcm_fc/Kconfig"

View File

@ -22,7 +22,7 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
obj-$(CONFIG_TCM_USER) += target_core_user.o
obj-$(CONFIG_TCM_USER2) += target_core_user.o
# Fabric modules
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/

View File

@ -1,6 +1,5 @@
iscsi_target_mod-y += iscsi_target_parameters.o \
iscsi_target_seq_pdu_list.o \
iscsi_target_tq.o \
iscsi_target_auth.o \
iscsi_target_datain_values.o \
iscsi_target_device.o \

View File

@ -33,8 +33,6 @@
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
#include "iscsi_target_configfs.h"
#include "iscsi_target_datain_values.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl1.h"
@ -537,7 +535,7 @@ static struct iscsit_transport iscsi_target_transport = {
static int __init iscsi_target_init_module(void)
{
int ret = 0;
int ret = 0, size;
pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
@ -546,24 +544,21 @@ static int __init iscsi_target_init_module(void)
pr_err("Unable to allocate memory for iscsit_global\n");
return -1;
}
spin_lock_init(&iscsit_global->ts_bitmap_lock);
mutex_init(&auth_id_lock);
spin_lock_init(&sess_idr_lock);
idr_init(&tiqn_idr);
idr_init(&sess_idr);
ret = iscsi_target_register_configfs();
if (ret < 0)
ret = target_register_template(&iscsi_ops);
if (ret)
goto out;
ret = iscsi_thread_set_init();
if (ret < 0)
size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
iscsit_global->ts_bitmap = vzalloc(size);
if (!iscsit_global->ts_bitmap) {
pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
goto configfs_out;
if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) !=
TARGET_THREAD_SET_COUNT) {
pr_err("iscsi_allocate_thread_sets() returned"
" unexpected value!\n");
goto ts_out1;
}
lio_qr_cache = kmem_cache_create("lio_qr_cache",
@ -572,7 +567,7 @@ static int __init iscsi_target_init_module(void)
if (!lio_qr_cache) {
pr_err("nable to kmem_cache_create() for"
" lio_qr_cache\n");
goto ts_out2;
goto bitmap_out;
}
lio_dr_cache = kmem_cache_create("lio_dr_cache",
@ -617,12 +612,13 @@ static int __init iscsi_target_init_module(void)
kmem_cache_destroy(lio_dr_cache);
qr_out:
kmem_cache_destroy(lio_qr_cache);
ts_out2:
iscsi_deallocate_thread_sets();
ts_out1:
iscsi_thread_set_free();
bitmap_out:
vfree(iscsit_global->ts_bitmap);
configfs_out:
iscsi_target_deregister_configfs();
/* XXX: this probably wants it to be it's own unwind step.. */
if (iscsit_global->discovery_tpg)
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
target_unregister_template(&iscsi_ops);
out:
kfree(iscsit_global);
return -ENOMEM;
@ -630,8 +626,6 @@ static int __init iscsi_target_init_module(void)
static void __exit iscsi_target_cleanup_module(void)
{
iscsi_deallocate_thread_sets();
iscsi_thread_set_free();
iscsit_release_discovery_tpg();
iscsit_unregister_transport(&iscsi_target_transport);
kmem_cache_destroy(lio_qr_cache);
@ -639,8 +633,15 @@ static void __exit iscsi_target_cleanup_module(void)
kmem_cache_destroy(lio_ooo_cache);
kmem_cache_destroy(lio_r2t_cache);
iscsi_target_deregister_configfs();
/*
* Shutdown discovery sessions and disable discovery TPG
*/
if (iscsit_global->discovery_tpg)
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
target_unregister_template(&iscsi_ops);
vfree(iscsit_global->ts_bitmap);
kfree(iscsit_global);
}
@ -990,7 +991,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
/*
* Initialize struct se_cmd descriptor from target_core_mod infrastructure
*/
transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
conn->sess->se_sess, be32_to_cpu(hdr->data_length),
cmd->data_direction, sam_task_attr,
cmd->sense_buffer + 2);
@ -1805,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
u8 tcm_function;
int ret;
transport_init_se_cmd(&cmd->se_cmd,
&lio_target_fabric_configfs->tf_ops,
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
conn->sess->se_sess, 0, DMA_NONE,
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
@ -2155,7 +2155,6 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->text_in_ptr = NULL;
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
EXPORT_SYMBOL(iscsit_handle_text_cmd);
int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
@ -3715,17 +3714,16 @@ static int iscsit_send_reject(
void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
{
struct iscsi_thread_set *ts = conn->thread_set;
int ord, cpu;
/*
* thread_id is assigned from iscsit_global->ts_bitmap from
* within iscsi_thread_set.c:iscsi_allocate_thread_sets()
* bitmap_id is assigned from iscsit_global->ts_bitmap from
* within iscsit_start_kthreads()
*
* Here we use thread_id to determine which CPU that this
* iSCSI connection's iscsi_thread_set will be scheduled to
* Here we use bitmap_id to determine which CPU that this
* iSCSI connection's RX/TX threads will be scheduled to
* execute upon.
*/
ord = ts->thread_id % cpumask_weight(cpu_online_mask);
ord = conn->bitmap_id % cpumask_weight(cpu_online_mask);
for_each_online_cpu(cpu) {
if (ord-- == 0) {
cpumask_set_cpu(cpu, conn->conn_cpumask);
@ -3914,7 +3912,7 @@ iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
switch (state) {
case ISTATE_SEND_LOGOUTRSP:
if (!iscsit_logout_post_handler(cmd, conn))
goto restart;
return -ECONNRESET;
/* fall through */
case ISTATE_SEND_STATUS:
case ISTATE_SEND_ASYNCMSG:
@ -3942,8 +3940,6 @@ iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
err:
return -1;
restart:
return -EAGAIN;
}
static int iscsit_handle_response_queue(struct iscsi_conn *conn)
@ -3970,21 +3966,13 @@ static int iscsit_handle_response_queue(struct iscsi_conn *conn)
int iscsi_target_tx_thread(void *arg)
{
int ret = 0;
struct iscsi_conn *conn;
struct iscsi_thread_set *ts = arg;
struct iscsi_conn *conn = arg;
/*
* Allow ourselves to be interrupted by SIGINT so that a
* connection recovery / failure event can be triggered externally.
*/
allow_signal(SIGINT);
restart:
conn = iscsi_tx_thread_pre_handler(ts);
if (!conn)
goto out;
ret = 0;
while (!kthread_should_stop()) {
/*
* Ensure that both TX and RX per connection kthreads
@ -3993,11 +3981,9 @@ int iscsi_target_tx_thread(void *arg)
iscsit_thread_check_cpumask(conn, current, 1);
wait_event_interruptible(conn->queues_wq,
!iscsit_conn_all_queues_empty(conn) ||
ts->status == ISCSI_THREAD_SET_RESET);
!iscsit_conn_all_queues_empty(conn));
if ((ts->status == ISCSI_THREAD_SET_RESET) ||
signal_pending(current))
if (signal_pending(current))
goto transport_err;
get_immediate:
@ -4008,15 +3994,14 @@ int iscsi_target_tx_thread(void *arg)
ret = iscsit_handle_response_queue(conn);
if (ret == 1)
goto get_immediate;
else if (ret == -EAGAIN)
goto restart;
else if (ret == -ECONNRESET)
goto out;
else if (ret < 0)
goto transport_err;
}
transport_err:
iscsit_take_action_for_connection_exit(conn);
goto restart;
out:
return 0;
}
@ -4111,8 +4096,7 @@ int iscsi_target_rx_thread(void *arg)
int ret;
u8 buffer[ISCSI_HDR_LEN], opcode;
u32 checksum = 0, digest = 0;
struct iscsi_conn *conn = NULL;
struct iscsi_thread_set *ts = arg;
struct iscsi_conn *conn = arg;
struct kvec iov;
/*
* Allow ourselves to be interrupted by SIGINT so that a
@ -4120,11 +4104,6 @@ int iscsi_target_rx_thread(void *arg)
*/
allow_signal(SIGINT);
restart:
conn = iscsi_rx_thread_pre_handler(ts);
if (!conn)
goto out;
if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
struct completion comp;
int rc;
@ -4134,7 +4113,7 @@ int iscsi_target_rx_thread(void *arg)
if (rc < 0)
goto transport_err;
goto out;
goto transport_err;
}
while (!kthread_should_stop()) {
@ -4210,8 +4189,6 @@ int iscsi_target_rx_thread(void *arg)
if (!signal_pending(current))
atomic_set(&conn->transport_failed, 1);
iscsit_take_action_for_connection_exit(conn);
goto restart;
out:
return 0;
}
@ -4273,7 +4250,24 @@ int iscsit_close_connection(
if (conn->conn_transport->transport_type == ISCSI_TCP)
complete(&conn->conn_logout_comp);
iscsi_release_thread_set(conn);
if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) {
if (conn->tx_thread &&
cmpxchg(&conn->tx_thread_active, true, false)) {
send_sig(SIGINT, conn->tx_thread, 1);
kthread_stop(conn->tx_thread);
}
} else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) {
if (conn->rx_thread &&
cmpxchg(&conn->rx_thread_active, true, false)) {
send_sig(SIGINT, conn->rx_thread, 1);
kthread_stop(conn->rx_thread);
}
}
spin_lock(&iscsit_global->ts_bitmap_lock);
bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
get_order(1));
spin_unlock(&iscsit_global->ts_bitmap_lock);
iscsit_stop_timers_for_cmds(conn);
iscsit_stop_nopin_response_timer(conn);
@ -4383,8 +4377,6 @@ int iscsit_close_connection(
iscsit_put_transport(conn->conn_transport);
conn->thread_set = NULL;
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
conn->conn_state = TARG_CONN_STATE_FREE;
kfree(conn);
@ -4551,15 +4543,13 @@ static void iscsit_logout_post_handler_closesession(
struct iscsi_conn *conn)
{
struct iscsi_session *sess = conn->sess;
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
atomic_set(&conn->conn_logout_remove, 0);
complete(&conn->conn_logout_comp);
iscsit_dec_conn_usage_count(conn);
iscsit_stop_session(sess, 1, 1);
iscsit_stop_session(sess, sleep, sleep);
iscsit_dec_session_usage_count(sess);
target_put_session(sess->se_sess);
}
@ -4567,13 +4557,12 @@ static void iscsit_logout_post_handler_closesession(
static void iscsit_logout_post_handler_samecid(
struct iscsi_conn *conn)
{
iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
int sleep = cmpxchg(&conn->tx_thread_active, true, false);
atomic_set(&conn->conn_logout_remove, 0);
complete(&conn->conn_logout_comp);
iscsit_cause_connection_reinstatement(conn, 1);
iscsit_cause_connection_reinstatement(conn, sleep);
iscsit_dec_conn_usage_count(conn);
}

View File

@ -35,7 +35,7 @@ extern void iscsit_stop_session(struct iscsi_session *, int, int);
extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
extern struct iscsit_global *iscsit_global;
extern struct target_fabric_configfs *lio_target_fabric_configfs;
extern const struct target_core_fabric_ops iscsi_ops;
extern struct kmem_cache *lio_dr_cache;
extern struct kmem_cache *lio_ooo_cache;

View File

@ -37,9 +37,6 @@
#include "iscsi_target_util.h"
#include "iscsi_target.h"
#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_configfs.h"
struct target_fabric_configfs *lio_target_fabric_configfs;
struct lio_target_configfs_attribute {
struct configfs_attribute attr;
@ -1052,6 +1049,11 @@ TPG_ATTR(default_erl, S_IRUGO | S_IWUSR);
*/
DEF_TPG_ATTRIB(t10_pi);
TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR);
/*
* Define iscsi_tpg_attrib_s_fabric_prot_type
*/
DEF_TPG_ATTRIB(fabric_prot_type);
TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR);
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
&iscsi_tpg_attrib_authentication.attr,
@ -1065,6 +1067,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
&iscsi_tpg_attrib_demo_mode_discovery.attr,
&iscsi_tpg_attrib_default_erl.attr,
&iscsi_tpg_attrib_t10_pi.attr,
&iscsi_tpg_attrib_fabric_prot_type.attr,
NULL,
};
@ -1410,8 +1413,18 @@ static ssize_t lio_target_tpg_store_enable(
TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
static ssize_t lio_target_tpg_show_dynamic_sessions(
struct se_portal_group *se_tpg,
char *page)
{
return target_show_dynamic_sessions(se_tpg, page);
}
TF_TPG_BASE_ATTR_RO(lio_target, dynamic_sessions);
static struct configfs_attribute *lio_target_tpg_attrs[] = {
&lio_target_tpg_enable.attr,
&lio_target_tpg_dynamic_sessions.attr,
NULL,
};
@ -1450,10 +1463,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
if (!tpg)
return NULL;
ret = core_tpg_register(
&lio_target_fabric_configfs->tf_ops,
wwn, &tpg->tpg_se_tpg, tpg,
TRANSPORT_TPG_TYPE_NORMAL);
ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg,
tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0)
return NULL;
@ -1872,6 +1883,20 @@ static int lio_tpg_check_prod_mode_write_protect(
return tpg->tpg_attrib.prod_mode_write_protect;
}
static int lio_tpg_check_prot_fabric_only(
struct se_portal_group *se_tpg)
{
struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
/*
* Only report fabric_prot_type if t10_pi has also been enabled
* for incoming ib_isert sessions.
*/
if (!tpg->tpg_attrib.t10_pi)
return 0;
return tpg->tpg_attrib.fabric_prot_type;
}
static void lio_tpg_release_fabric_acl(
struct se_portal_group *se_tpg,
struct se_node_acl *se_acl)
@ -1953,115 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
iscsit_release_cmd(cmd);
}
/* End functions for target_core_fabric_ops */
const struct target_core_fabric_ops iscsi_ops = {
.module = THIS_MODULE,
.name = "iscsi",
.get_fabric_name = iscsi_get_fabric_name,
.get_fabric_proto_ident = iscsi_get_fabric_proto_ident,
.tpg_get_wwn = lio_tpg_get_endpoint_wwn,
.tpg_get_tag = lio_tpg_get_tag,
.tpg_get_default_depth = lio_tpg_get_default_depth,
.tpg_get_pr_transport_id = iscsi_get_pr_transport_id,
.tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len,
.tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id,
.tpg_check_demo_mode = lio_tpg_check_demo_mode,
.tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache,
.tpg_check_demo_mode_write_protect =
lio_tpg_check_demo_mode_write_protect,
.tpg_check_prod_mode_write_protect =
lio_tpg_check_prod_mode_write_protect,
.tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only,
.tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl,
.tpg_release_fabric_acl = lio_tpg_release_fabric_acl,
.tpg_get_inst_index = lio_tpg_get_inst_index,
.check_stop_free = lio_check_stop_free,
.release_cmd = lio_release_cmd,
.shutdown_session = lio_tpg_shutdown_session,
.close_session = lio_tpg_close_session,
.sess_get_index = lio_sess_get_index,
.sess_get_initiator_sid = lio_sess_get_initiator_sid,
.write_pending = lio_write_pending,
.write_pending_status = lio_write_pending_status,
.set_default_node_attributes = lio_set_default_node_attributes,
.get_task_tag = iscsi_get_task_tag,
.get_cmd_state = iscsi_get_cmd_state,
.queue_data_in = lio_queue_data_in,
.queue_status = lio_queue_status,
.queue_tm_rsp = lio_queue_tm_rsp,
.aborted_task = lio_aborted_task,
.fabric_make_wwn = lio_target_call_coreaddtiqn,
.fabric_drop_wwn = lio_target_call_coredeltiqn,
.fabric_make_tpg = lio_target_tiqn_addtpg,
.fabric_drop_tpg = lio_target_tiqn_deltpg,
.fabric_make_np = lio_target_call_addnptotpg,
.fabric_drop_np = lio_target_call_delnpfromtpg,
.fabric_make_nodeacl = lio_target_make_nodeacl,
.fabric_drop_nodeacl = lio_target_drop_nodeacl,
int iscsi_target_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
lio_target_fabric_configfs = NULL;
fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi");
if (IS_ERR(fabric)) {
pr_err("target_fabric_configfs_init() for"
" LIO-Target failed!\n");
return PTR_ERR(fabric);
}
/*
* Setup the fabric API of function pointers used by target_core_mod..
*/
fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name;
fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident;
fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn;
fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag;
fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth;
fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id;
fabric->tf_ops.tpg_get_pr_transport_id_len =
&iscsi_get_pr_transport_id_len;
fabric->tf_ops.tpg_parse_pr_out_transport_id =
&iscsi_parse_pr_out_transport_id;
fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode;
fabric->tf_ops.tpg_check_demo_mode_cache =
&lio_tpg_check_demo_mode_cache;
fabric->tf_ops.tpg_check_demo_mode_write_protect =
&lio_tpg_check_demo_mode_write_protect;
fabric->tf_ops.tpg_check_prod_mode_write_protect =
&lio_tpg_check_prod_mode_write_protect;
fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl;
fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl;
fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index;
fabric->tf_ops.check_stop_free = &lio_check_stop_free,
fabric->tf_ops.release_cmd = &lio_release_cmd;
fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
fabric->tf_ops.close_session = &lio_tpg_close_session;
fabric->tf_ops.sess_get_index = &lio_sess_get_index;
fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid;
fabric->tf_ops.write_pending = &lio_write_pending;
fabric->tf_ops.write_pending_status = &lio_write_pending_status;
fabric->tf_ops.set_default_node_attributes =
&lio_set_default_node_attributes;
fabric->tf_ops.get_task_tag = &iscsi_get_task_tag;
fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state;
fabric->tf_ops.queue_data_in = &lio_queue_data_in;
fabric->tf_ops.queue_status = &lio_queue_status;
fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
fabric->tf_ops.aborted_task = &lio_aborted_task;
/*
* Setup function pointers for generic logic in target_core_fabric_configfs.c
*/
fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn;
fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn;
fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg;
fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg;
fabric->tf_ops.fabric_post_link = NULL;
fabric->tf_ops.fabric_pre_unlink = NULL;
fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg;
fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg;
fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl;
fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
* sturct config_item_type's
*/
fabric->tf_cit_tmpl.tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs;
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
fabric->tf_cit_tmpl.tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs;
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() for"
" LIO-Target failed!\n");
target_fabric_configfs_free(fabric);
return ret;
}
lio_target_fabric_configfs = fabric;
pr_debug("LIO_TARGET[0] - Set fabric ->"
" lio_target_fabric_configfs\n");
return 0;
}
void iscsi_target_deregister_configfs(void)
{
if (!lio_target_fabric_configfs)
return;
/*
* Shutdown discovery sessions and disable discovery TPG
*/
if (iscsit_global->discovery_tpg)
iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
target_fabric_configfs_deregister(lio_target_fabric_configfs);
lio_target_fabric_configfs = NULL;
pr_debug("LIO_TARGET[0] - Cleared"
" lio_target_fabric_configfs\n");
}
.tfc_discovery_attrs = lio_target_discovery_auth_attrs,
.tfc_wwn_attrs = lio_target_wwn_attrs,
.tfc_tpg_base_attrs = lio_target_tpg_attrs,
.tfc_tpg_attrib_attrs = lio_target_tpg_attrib_attrs,
.tfc_tpg_auth_attrs = lio_target_tpg_auth_attrs,
.tfc_tpg_param_attrs = lio_target_tpg_param_attrs,
.tfc_tpg_np_base_attrs = lio_target_portal_attrs,
.tfc_tpg_nacl_base_attrs = lio_target_initiator_attrs,
.tfc_tpg_nacl_attrib_attrs = lio_target_nacl_attrib_attrs,
.tfc_tpg_nacl_auth_attrs = lio_target_nacl_auth_attrs,
.tfc_tpg_nacl_param_attrs = lio_target_nacl_param_attrs,
};

View File

@ -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 */

View File

@ -23,7 +23,6 @@
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl1.h"
#include "iscsi_target_erl2.h"
@ -860,7 +859,10 @@ void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn)
}
spin_unlock_bh(&conn->state_lock);
iscsi_thread_set_force_reinstatement(conn);
if (conn->tx_thread && conn->tx_thread_active)
send_sig(SIGINT, conn->tx_thread, 1);
if (conn->rx_thread && conn->rx_thread_active)
send_sig(SIGINT, conn->rx_thread, 1);
sleep:
wait_for_completion(&conn->conn_wait_rcfr_comp);
@ -885,10 +887,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
return;
}
if (iscsi_thread_set_force_reinstatement(conn) < 0) {
spin_unlock_bh(&conn->state_lock);
return;
}
if (conn->tx_thread && conn->tx_thread_active)
send_sig(SIGINT, conn->tx_thread, 1);
if (conn->rx_thread && conn->rx_thread_active)
send_sig(SIGINT, conn->rx_thread, 1);
atomic_set(&conn->connection_reinstatement, 1);
if (!sleep) {

View File

@ -26,7 +26,6 @@
#include <target/iscsi/iscsi_target_core.h>
#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_tq.h"
#include "iscsi_target_device.h"
#include "iscsi_target_nego.h"
#include "iscsi_target_erl0.h"
@ -699,6 +698,51 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
iscsit_start_nopin_timer(conn);
}
static int iscsit_start_kthreads(struct iscsi_conn *conn)
{
int ret = 0;
spin_lock(&iscsit_global->ts_bitmap_lock);
conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
ISCSIT_BITMAP_BITS, get_order(1));
spin_unlock(&iscsit_global->ts_bitmap_lock);
if (conn->bitmap_id < 0) {
pr_err("bitmap_find_free_region() failed for"
" iscsit_start_kthreads()\n");
return -ENOMEM;
}
conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn,
"%s", ISCSI_TX_THREAD_NAME);
if (IS_ERR(conn->tx_thread)) {
pr_err("Unable to start iscsi_target_tx_thread\n");
ret = PTR_ERR(conn->tx_thread);
goto out_bitmap;
}
conn->tx_thread_active = true;
conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn,
"%s", ISCSI_RX_THREAD_NAME);
if (IS_ERR(conn->rx_thread)) {
pr_err("Unable to start iscsi_target_rx_thread\n");
ret = PTR_ERR(conn->rx_thread);
goto out_tx;
}
conn->rx_thread_active = true;
return 0;
out_tx:
kthread_stop(conn->tx_thread);
conn->tx_thread_active = false;
out_bitmap:
spin_lock(&iscsit_global->ts_bitmap_lock);
bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
get_order(1));
spin_unlock(&iscsit_global->ts_bitmap_lock);
return ret;
}
int iscsi_post_login_handler(
struct iscsi_np *np,
struct iscsi_conn *conn,
@ -709,7 +753,7 @@ int iscsi_post_login_handler(
struct se_session *se_sess = sess->se_sess;
struct iscsi_portal_group *tpg = sess->tpg;
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
struct iscsi_thread_set *ts;
int rc;
iscsit_inc_conn_usage_count(conn);
@ -724,7 +768,6 @@ int iscsi_post_login_handler(
/*
* SCSI Initiator -> SCSI Target Port Mapping
*/
ts = iscsi_get_thread_set();
if (!zero_tsih) {
iscsi_set_session_parameters(sess->sess_ops,
conn->param_list, 0);
@ -751,9 +794,11 @@ int iscsi_post_login_handler(
sess->sess_ops->InitiatorName);
spin_unlock_bh(&sess->conn_lock);
iscsi_post_login_start_timers(conn);
rc = iscsit_start_kthreads(conn);
if (rc)
return rc;
iscsi_activate_thread_set(conn, ts);
iscsi_post_login_start_timers(conn);
/*
* Determine CPU mask to ensure connection's RX and TX kthreads
* are scheduled on the same CPU.
@ -810,8 +855,11 @@ int iscsi_post_login_handler(
" iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
spin_unlock_bh(&se_tpg->session_lock);
rc = iscsit_start_kthreads(conn);
if (rc)
return rc;
iscsi_post_login_start_timers(conn);
iscsi_activate_thread_set(conn, ts);
/*
* Determine CPU mask to ensure connection's RX and TX kthreads
* are scheduled on the same CPU.

View File

@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void)
return -1;
}
ret = core_tpg_register(
&lio_target_fabric_configfs->tf_ops,
NULL, &tpg->tpg_se_tpg, tpg,
TRANSPORT_TPG_TYPE_DISCOVERY);
ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg,
tpg, TRANSPORT_TPG_TYPE_DISCOVERY);
if (ret < 0) {
kfree(tpg);
return -1;
@ -228,6 +226,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY;
a->default_erl = TA_DEFAULT_ERL;
a->t10_pi = TA_DEFAULT_T10_PI;
a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
}
int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
@ -878,3 +877,21 @@ int iscsit_ta_t10_pi(
return 0;
}
int iscsit_ta_fabric_prot_type(
struct iscsi_portal_group *tpg,
u32 prot_type)
{
struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
if ((prot_type != 0) && (prot_type != 1) && (prot_type != 3)) {
pr_err("Illegal value for fabric_prot_type: %u\n", prot_type);
return -EINVAL;
}
a->fabric_prot_type = prot_type;
pr_debug("iSCSI_TPG[%hu] - T10 Fabric Protection Type: %u\n",
tpg->tpgt, prot_type);
return 0;
}

View File

@ -39,5 +39,6 @@ extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32);
extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32);
extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32);
extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
#endif /* ISCSI_TARGET_TPG_H */

View File

@ -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);
}

View File

@ -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 ***/

View File

@ -33,7 +33,6 @@
#include "iscsi_target_erl1.h"
#include "iscsi_target_erl2.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_tq.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"

View File

@ -41,8 +41,7 @@
#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev)
/* Local pointer to allocated TCM configfs fabric module */
static struct target_fabric_configfs *tcm_loop_fabric_configfs;
static const struct target_core_fabric_ops loop_ops;
static struct workqueue_struct *tcm_loop_workqueue;
static struct kmem_cache *tcm_loop_cmd_cache;
@ -108,7 +107,7 @@ static struct device_driver tcm_loop_driverfs = {
/*
* Used with root_device_register() in tcm_loop_alloc_core_bus() below
*/
struct device *tcm_loop_primary;
static struct device *tcm_loop_primary;
static void tcm_loop_submission_work(struct work_struct *work)
{
@ -697,6 +696,13 @@ static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg
return 0;
}
static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
return tl_tpg->tl_fabric_prot_type;
}
static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl(
struct se_portal_group *se_tpg)
{
@ -912,6 +918,46 @@ static void tcm_loop_port_unlink(
/* End items for tcm_loop_port_cit */
static ssize_t tcm_loop_tpg_attrib_show_fabric_prot_type(
struct se_portal_group *se_tpg,
char *page)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
return sprintf(page, "%d\n", tl_tpg->tl_fabric_prot_type);
}
static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
unsigned long val;
int ret = kstrtoul(page, 0, &val);
if (ret) {
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
return ret;
}
if (val != 0 && val != 1 && val != 3) {
pr_err("Invalid qla2xxx fabric_prot_type: %lu\n", val);
return -EINVAL;
}
tl_tpg->tl_fabric_prot_type = val;
return count;
}
TF_TPG_ATTRIB_ATTR(tcm_loop, fabric_prot_type, S_IRUGO | S_IWUSR);
static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = {
&tcm_loop_tpg_attrib_fabric_prot_type.attr,
NULL,
};
/* Start items for tcm_loop_nexus_cit */
static int tcm_loop_make_nexus(
@ -937,7 +983,8 @@ static int tcm_loop_make_nexus(
/*
* Initialize the struct se_session pointer
*/
tl_nexus->se_sess = transport_init_session(TARGET_PROT_ALL);
tl_nexus->se_sess = transport_init_session(
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
if (IS_ERR(tl_nexus->se_sess)) {
ret = PTR_ERR(tl_nexus->se_sess);
goto out;
@ -1165,21 +1212,19 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
struct tcm_loop_hba *tl_hba = container_of(wwn,
struct tcm_loop_hba, tl_hba_wwn);
struct tcm_loop_tpg *tl_tpg;
char *tpgt_str, *end_ptr;
int ret;
unsigned short int tpgt;
unsigned long tpgt;
tpgt_str = strstr(name, "tpgt_");
if (!tpgt_str) {
if (strstr(name, "tpgt_") != name) {
pr_err("Unable to locate \"tpgt_#\" directory"
" group\n");
return ERR_PTR(-EINVAL);
}
tpgt_str += 5; /* Skip ahead of "tpgt_" */
tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
if (kstrtoul(name+5, 10, &tpgt))
return ERR_PTR(-EINVAL);
if (tpgt >= TL_TPGS_PER_HBA) {
pr_err("Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:"
pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA:"
" %u\n", tpgt, TL_TPGS_PER_HBA);
return ERR_PTR(-EINVAL);
}
@ -1189,14 +1234,13 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
/*
* Register the tl_tpg as a emulated SAS TCM Target Endpoint
*/
ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops,
wwn, &tl_tpg->tl_se_tpg, tl_tpg,
ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg,
TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0)
return ERR_PTR(-ENOMEM);
pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s"
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
" Target Port %s,t,0x%04lx\n", tcm_loop_dump_proto_id(tl_hba),
config_item_name(&wwn->wwn_group.cg_item), tpgt);
return &tl_tpg->tl_se_tpg;
@ -1338,127 +1382,51 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
/* End items for tcm_loop_cit */
static int tcm_loop_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
/*
* Set the TCM Loop HBA counter to zero
*/
tcm_loop_hba_no_cnt = 0;
/*
* Register the top level struct config_item_type with TCM core
*/
fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
if (IS_ERR(fabric)) {
pr_err("tcm_loop_register_configfs() failed!\n");
return PTR_ERR(fabric);
}
/*
* Setup the fabric API of function pointers used by target_core_mod
*/
fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
fabric->tf_ops.tpg_get_pr_transport_id_len =
&tcm_loop_get_pr_transport_id_len;
fabric->tf_ops.tpg_parse_pr_out_transport_id =
&tcm_loop_parse_pr_out_transport_id;
fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
fabric->tf_ops.tpg_check_demo_mode_cache =
&tcm_loop_check_demo_mode_cache;
fabric->tf_ops.tpg_check_demo_mode_write_protect =
&tcm_loop_check_demo_mode_write_protect;
fabric->tf_ops.tpg_check_prod_mode_write_protect =
&tcm_loop_check_prod_mode_write_protect;
/*
* The TCM loopback fabric module runs in demo-mode to a local
* virtual SCSI device, so fabric dependent initator ACLs are
* not required.
*/
fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
fabric->tf_ops.tpg_release_fabric_acl =
&tcm_loop_tpg_release_fabric_acl;
fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index;
/*
* Used for setting up remaining TCM resources in process context
*/
fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
fabric->tf_ops.close_session = &tcm_loop_close_session;
fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
fabric->tf_ops.sess_get_initiator_sid = NULL;
fabric->tf_ops.write_pending = &tcm_loop_write_pending;
fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status;
/*
* Not used for TCM loopback
*/
fabric->tf_ops.set_default_node_attributes =
&tcm_loop_set_default_node_attributes;
fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag;
fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state;
fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
fabric->tf_ops.queue_status = &tcm_loop_queue_status;
fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
fabric->tf_ops.aborted_task = &tcm_loop_aborted_task;
/*
* Setup function pointers for generic logic in target_core_fabric_configfs.c
*/
fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba;
fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba;
fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg;
fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg;
/*
* fabric_post_link() and fabric_pre_unlink() are used for
* registration and release of TCM Loop Virtual SCSI LUNs.
*/
fabric->tf_ops.fabric_post_link = &tcm_loop_port_link;
fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink;
fabric->tf_ops.fabric_make_np = NULL;
fabric->tf_ops.fabric_drop_np = NULL;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
/*
* Once fabric->tf_ops has been setup, now register the fabric for
* use within TCM
*/
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() for"
" TCM_Loop failed!\n");
target_fabric_configfs_free(fabric);
return -1;
}
/*
* Setup our local pointer to *fabric.
*/
tcm_loop_fabric_configfs = fabric;
pr_debug("TCM_LOOP[0] - Set fabric ->"
" tcm_loop_fabric_configfs\n");
return 0;
}
static void tcm_loop_deregister_configfs(void)
{
if (!tcm_loop_fabric_configfs)
return;
target_fabric_configfs_deregister(tcm_loop_fabric_configfs);
tcm_loop_fabric_configfs = NULL;
pr_debug("TCM_LOOP[0] - Cleared"
" tcm_loop_fabric_configfs\n");
}
static const struct target_core_fabric_ops loop_ops = {
.module = THIS_MODULE,
.name = "loopback",
.get_fabric_name = tcm_loop_get_fabric_name,
.get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident,
.tpg_get_wwn = tcm_loop_get_endpoint_wwn,
.tpg_get_tag = tcm_loop_get_tag,
.tpg_get_default_depth = tcm_loop_get_default_depth,
.tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id,
.tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len,
.tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id,
.tpg_check_demo_mode = tcm_loop_check_demo_mode,
.tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache,
.tpg_check_demo_mode_write_protect =
tcm_loop_check_demo_mode_write_protect,
.tpg_check_prod_mode_write_protect =
tcm_loop_check_prod_mode_write_protect,
.tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only,
.tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl,
.tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl,
.tpg_get_inst_index = tcm_loop_get_inst_index,
.check_stop_free = tcm_loop_check_stop_free,
.release_cmd = tcm_loop_release_cmd,
.shutdown_session = tcm_loop_shutdown_session,
.close_session = tcm_loop_close_session,
.sess_get_index = tcm_loop_sess_get_index,
.write_pending = tcm_loop_write_pending,
.write_pending_status = tcm_loop_write_pending_status,
.set_default_node_attributes = tcm_loop_set_default_node_attributes,
.get_task_tag = tcm_loop_get_task_tag,
.get_cmd_state = tcm_loop_get_cmd_state,
.queue_data_in = tcm_loop_queue_data_in,
.queue_status = tcm_loop_queue_status,
.queue_tm_rsp = tcm_loop_queue_tm_rsp,
.aborted_task = tcm_loop_aborted_task,
.fabric_make_wwn = tcm_loop_make_scsi_hba,
.fabric_drop_wwn = tcm_loop_drop_scsi_hba,
.fabric_make_tpg = tcm_loop_make_naa_tpg,
.fabric_drop_tpg = tcm_loop_drop_naa_tpg,
.fabric_post_link = tcm_loop_port_link,
.fabric_pre_unlink = tcm_loop_port_unlink,
.tfc_wwn_attrs = tcm_loop_wwn_attrs,
.tfc_tpg_base_attrs = tcm_loop_tpg_attrs,
.tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs,
};
static int __init tcm_loop_fabric_init(void)
{
@ -1482,7 +1450,7 @@ static int __init tcm_loop_fabric_init(void)
if (ret)
goto out_destroy_cache;
ret = tcm_loop_register_configfs();
ret = target_register_template(&loop_ops);
if (ret)
goto out_release_core_bus;
@ -1500,7 +1468,7 @@ static int __init tcm_loop_fabric_init(void)
static void __exit tcm_loop_fabric_exit(void)
{
tcm_loop_deregister_configfs();
target_unregister_template(&loop_ops);
tcm_loop_release_core_bus();
kmem_cache_destroy(tcm_loop_cmd_cache);
destroy_workqueue(tcm_loop_workqueue);

View File

@ -43,6 +43,7 @@ struct tcm_loop_nacl {
struct tcm_loop_tpg {
unsigned short tl_tpgt;
unsigned short tl_transport_status;
enum target_prot_type tl_fabric_prot_type;
atomic_t tl_tpg_port_count;
struct se_portal_group tl_se_tpg;
struct tcm_loop_hba *tl_hba;

View File

@ -42,8 +42,7 @@
#include "sbp_target.h"
/* Local pointer to allocated TCM configfs fabric module */
static struct target_fabric_configfs *sbp_fabric_configfs;
static const struct target_core_fabric_ops sbp_ops;
/* FireWire address region for management and command block address handlers */
static const struct fw_address_region sbp_register_region = {
@ -2215,8 +2214,7 @@ static struct se_portal_group *sbp_make_tpg(
goto out_free_tpg;
}
ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
&tpg->se_tpg, (void *)tpg,
ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg,
TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0)
goto out_unreg_mgt_agt;
@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
NULL,
};
static struct target_core_fabric_ops sbp_ops = {
static const struct target_core_fabric_ops sbp_ops = {
.module = THIS_MODULE,
.name = "sbp",
.get_fabric_name = sbp_get_fabric_name,
.get_fabric_proto_ident = sbp_get_fabric_proto_ident,
.tpg_get_wwn = sbp_get_fabric_wwn,
@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = sbp_make_nodeacl,
.fabric_drop_nodeacl = sbp_drop_nodeacl,
};
static int sbp_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
if (IS_ERR(fabric)) {
pr_err("target_fabric_configfs_init() failed\n");
return PTR_ERR(fabric);
}
fabric->tf_ops = sbp_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() failed for SBP\n");
return ret;
}
sbp_fabric_configfs = fabric;
return 0;
};
static void sbp_deregister_configfs(void)
{
if (!sbp_fabric_configfs)
return;
target_fabric_configfs_deregister(sbp_fabric_configfs);
sbp_fabric_configfs = NULL;
.tfc_wwn_attrs = sbp_wwn_attrs,
.tfc_tpg_base_attrs = sbp_tpg_base_attrs,
.tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs,
};
static int __init sbp_init(void)
{
int ret;
ret = sbp_register_configfs();
if (ret < 0)
return ret;
return 0;
return target_register_template(&sbp_ops);
};
static void __exit sbp_exit(void)
{
sbp_deregister_configfs();
target_unregister_template(&sbp_ops);
};
MODULE_DESCRIPTION("FireWire SBP fabric driver");

View File

@ -142,8 +142,8 @@ static struct config_group *target_core_register_fabric(
tf = target_core_get_fabric(name);
if (!tf) {
pr_err("target_core_register_fabric() trying autoload for %s\n",
name);
pr_debug("target_core_register_fabric() trying autoload for %s\n",
name);
/*
* Below are some hardcoded request_module() calls to automatically
@ -165,8 +165,8 @@ static struct config_group *target_core_register_fabric(
*/
ret = request_module("iscsi_target_mod");
if (ret < 0) {
pr_err("request_module() failed for"
" iscsi_target_mod.ko: %d\n", ret);
pr_debug("request_module() failed for"
" iscsi_target_mod.ko: %d\n", ret);
return ERR_PTR(-EINVAL);
}
} else if (!strncmp(name, "loopback", 8)) {
@ -178,8 +178,8 @@ static struct config_group *target_core_register_fabric(
*/
ret = request_module("tcm_loop");
if (ret < 0) {
pr_err("request_module() failed for"
" tcm_loop.ko: %d\n", ret);
pr_debug("request_module() failed for"
" tcm_loop.ko: %d\n", ret);
return ERR_PTR(-EINVAL);
}
}
@ -188,8 +188,8 @@ static struct config_group *target_core_register_fabric(
}
if (!tf) {
pr_err("target_core_get_fabric() failed for %s\n",
name);
pr_debug("target_core_get_fabric() failed for %s\n",
name);
return ERR_PTR(-EINVAL);
}
pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:"
@ -300,81 +300,17 @@ struct configfs_subsystem *target_core_subsystem[] = {
// Start functions called by external Target Fabrics Modules
//############################################################################*/
/*
* First function called by fabric modules to:
*
* 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer.
* 2) Add struct target_fabric_configfs to g_tf_list
* 3) Return struct target_fabric_configfs to fabric module to be passed
* into target_fabric_configfs_register().
*/
struct target_fabric_configfs *target_fabric_configfs_init(
struct module *fabric_mod,
const char *name)
static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo)
{
struct target_fabric_configfs *tf;
if (!(name)) {
pr_err("Unable to locate passed fabric name\n");
return ERR_PTR(-EINVAL);
if (!tfo->name) {
pr_err("Missing tfo->name\n");
return -EINVAL;
}
if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) {
if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) {
pr_err("Passed name: %s exceeds TARGET_FABRIC"
"_NAME_SIZE\n", name);
return ERR_PTR(-EINVAL);
"_NAME_SIZE\n", tfo->name);
return -EINVAL;
}
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
if (!tf)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&tf->tf_list);
atomic_set(&tf->tf_access_cnt, 0);
/*
* Setup the default generic struct config_item_type's (cits) in
* struct target_fabric_configfs->tf_cit_tmpl
*/
tf->tf_module = fabric_mod;
target_fabric_setup_cits(tf);
tf->tf_subsys = target_core_subsystem[0];
snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name);
mutex_lock(&g_tf_lock);
list_add_tail(&tf->tf_list, &g_tf_list);
mutex_unlock(&g_tf_lock);
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>"
">>>>>>>>>>>>>>\n");
pr_debug("Initialized struct target_fabric_configfs: %p for"
" %s\n", tf, tf->tf_name);
return tf;
}
EXPORT_SYMBOL(target_fabric_configfs_init);
/*
* Called by fabric plugins after FAILED target_fabric_configfs_register() call.
*/
void target_fabric_configfs_free(
struct target_fabric_configfs *tf)
{
mutex_lock(&g_tf_lock);
list_del(&tf->tf_list);
mutex_unlock(&g_tf_lock);
kfree(tf);
}
EXPORT_SYMBOL(target_fabric_configfs_free);
/*
* Perform a sanity check of the passed tf->tf_ops before completing
* TCM fabric module registration.
*/
static int target_fabric_tf_ops_check(
struct target_fabric_configfs *tf)
{
struct target_core_fabric_ops *tfo = &tf->tf_ops;
if (!tfo->get_fabric_name) {
pr_err("Missing tfo->get_fabric_name()\n");
return -EINVAL;
@ -508,77 +444,59 @@ static int target_fabric_tf_ops_check(
return 0;
}
/*
* Called 2nd from fabric module with returned parameter of
* struct target_fabric_configfs * from target_fabric_configfs_init().
*
* Upon a successful registration, the new fabric's struct config_item is
* return. Also, a pointer to this struct is set in the passed
* struct target_fabric_configfs.
*/
int target_fabric_configfs_register(
struct target_fabric_configfs *tf)
int target_register_template(const struct target_core_fabric_ops *fo)
{
struct target_fabric_configfs *tf;
int ret;
if (!tf) {
pr_err("Unable to locate target_fabric_configfs"
" pointer\n");
return -EINVAL;
}
if (!tf->tf_subsys) {
pr_err("Unable to target struct config_subsystem"
" pointer\n");
return -EINVAL;
}
ret = target_fabric_tf_ops_check(tf);
if (ret < 0)
ret = target_fabric_tf_ops_check(fo);
if (ret)
return ret;
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
">>>>>>>>>>\n");
return 0;
}
EXPORT_SYMBOL(target_fabric_configfs_register);
void target_fabric_configfs_deregister(
struct target_fabric_configfs *tf)
{
struct configfs_subsystem *su;
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
if (!tf) {
pr_err("Unable to locate passed target_fabric_"
"configfs\n");
return;
pr_err("%s: could not allocate memory!\n", __func__);
return -ENOMEM;
}
su = tf->tf_subsys;
if (!su) {
pr_err("Unable to locate passed tf->tf_subsys"
" pointer\n");
return;
}
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
">>>>>>>>>>>>\n");
INIT_LIST_HEAD(&tf->tf_list);
atomic_set(&tf->tf_access_cnt, 0);
/*
* Setup the default generic struct config_item_type's (cits) in
* struct target_fabric_configfs->tf_cit_tmpl
*/
tf->tf_module = fo->module;
tf->tf_subsys = target_core_subsystem[0];
snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name);
tf->tf_ops = *fo;
target_fabric_setup_cits(tf);
mutex_lock(&g_tf_lock);
if (atomic_read(&tf->tf_access_cnt)) {
mutex_unlock(&g_tf_lock);
pr_err("Non zero tf->tf_access_cnt for fabric %s\n",
tf->tf_name);
BUG();
}
list_del(&tf->tf_list);
list_add_tail(&tf->tf_list, &g_tf_list);
mutex_unlock(&g_tf_lock);
pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
" %s\n", tf->tf_name);
tf->tf_module = NULL;
tf->tf_subsys = NULL;
kfree(tf);
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
">>>>>\n");
return 0;
}
EXPORT_SYMBOL(target_fabric_configfs_deregister);
EXPORT_SYMBOL(target_register_template);
void target_unregister_template(const struct target_core_fabric_ops *fo)
{
struct target_fabric_configfs *t;
mutex_lock(&g_tf_lock);
list_for_each_entry(t, &g_tf_list, tf_list) {
if (!strcmp(t->tf_name, fo->name)) {
BUG_ON(atomic_read(&t->tf_access_cnt));
list_del(&t->tf_list);
kfree(t);
break;
}
}
mutex_unlock(&g_tf_lock);
}
EXPORT_SYMBOL(target_unregister_template);
/*##############################################################################
// Stop functions called by external Target Fabrics Modules
@ -945,7 +863,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
struct se_lun *lun;
struct se_portal_group *se_tpg;
struct t10_pr_registration *pr_reg;
struct target_core_fabric_ops *tfo;
const struct target_core_fabric_ops *tfo;
ssize_t len = 0;
spin_lock(&dev->dev_reservation_lock);
@ -979,7 +897,7 @@ SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
struct se_device *dev, char *page)
{
struct target_core_fabric_ops *tfo;
const struct target_core_fabric_ops *tfo;
struct t10_pr_registration *pr_reg;
unsigned char buf[384];
char i_buf[PR_REG_ISID_ID_LEN];

View File

@ -56,6 +56,20 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf)
pr_debug("Setup generic %s\n", __stringify(_name)); \
}
#define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \
static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
{ \
struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \
struct config_item_type *cit = &tfc->tfc_##_name##_cit; \
struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \
\
cit->ct_item_ops = _item_ops; \
cit->ct_group_ops = _group_ops; \
cit->ct_attrs = attrs; \
cit->ct_owner = tf->tf_module; \
pr_debug("Setup generic %s\n", __stringify(_name)); \
}
/* Start of tfc_tpg_mappedlun_cit */
static int target_fabric_mappedlun_link(
@ -278,7 +292,7 @@ static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = {
.store_attribute = target_fabric_nacl_attrib_attr_store,
};
TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL);
/* End of tfc_tpg_nacl_attrib_cit */
@ -291,7 +305,7 @@ static struct configfs_item_operations target_fabric_nacl_auth_item_ops = {
.store_attribute = target_fabric_nacl_auth_attr_store,
};
TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL);
/* End of tfc_tpg_nacl_auth_cit */
@ -304,7 +318,7 @@ static struct configfs_item_operations target_fabric_nacl_param_item_ops = {
.store_attribute = target_fabric_nacl_param_attr_store,
};
TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL);
/* End of tfc_tpg_nacl_param_cit */
@ -461,8 +475,8 @@ static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
.drop_item = target_fabric_drop_mappedlun,
};
TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
&target_fabric_nacl_base_group_ops, NULL);
TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
&target_fabric_nacl_base_group_ops);
/* End of tfc_tpg_nacl_base_cit */
@ -570,7 +584,7 @@ static struct configfs_item_operations target_fabric_np_base_item_ops = {
.store_attribute = target_fabric_np_base_attr_store,
};
TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL);
/* End of tfc_tpg_np_base_cit */
@ -966,7 +980,7 @@ static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = {
.store_attribute = target_fabric_tpg_attrib_attr_store,
};
TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL);
/* End of tfc_tpg_attrib_cit */
@ -979,7 +993,7 @@ static struct configfs_item_operations target_fabric_tpg_auth_item_ops = {
.store_attribute = target_fabric_tpg_auth_attr_store,
};
TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL);
/* End of tfc_tpg_attrib_cit */
@ -992,7 +1006,7 @@ static struct configfs_item_operations target_fabric_tpg_param_item_ops = {
.store_attribute = target_fabric_tpg_param_attr_store,
};
TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL);
/* End of tfc_tpg_param_cit */
@ -1018,7 +1032,7 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
.store_attribute = target_fabric_tpg_attr_store,
};
TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL);
/* End of tfc_tpg_base_cit */
@ -1192,7 +1206,7 @@ static struct configfs_item_operations target_fabric_wwn_item_ops = {
.store_attribute = target_fabric_wwn_attr_store,
};
TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL);
TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops);
/* End of tfc_wwn_cit */
@ -1206,7 +1220,7 @@ static struct configfs_item_operations target_fabric_discovery_item_ops = {
.store_attribute = target_fabric_discovery_attr_store,
};
TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL);
TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL);
/* End of tfc_discovery_cit */

View File

@ -264,40 +264,32 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
struct se_device *se_dev = cmd->se_dev;
struct fd_dev *dev = FD_DEV(se_dev);
struct file *prot_fd = dev->fd_prot_file;
struct scatterlist *sg;
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
unsigned char *buf;
u32 prot_size, len, size;
int rc, ret = 1, i;
u32 prot_size;
int rc, ret = 1;
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
se_dev->prot_length;
if (!is_write) {
fd_prot->prot_buf = vzalloc(prot_size);
fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL);
if (!fd_prot->prot_buf) {
pr_err("Unable to allocate fd_prot->prot_buf\n");
return -ENOMEM;
}
buf = fd_prot->prot_buf;
fd_prot->prot_sg_nents = cmd->t_prot_nents;
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
fd_prot->prot_sg_nents, GFP_KERNEL);
fd_prot->prot_sg_nents = 1;
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist),
GFP_KERNEL);
if (!fd_prot->prot_sg) {
pr_err("Unable to allocate fd_prot->prot_sg\n");
vfree(fd_prot->prot_buf);
kfree(fd_prot->prot_buf);
return -ENOMEM;
}
size = prot_size;
for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
len = min_t(u32, PAGE_SIZE, size);
sg_set_buf(sg, buf, len);
size -= len;
buf += len;
}
sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents);
sg_set_buf(fd_prot->prot_sg, buf, prot_size);
}
if (is_write) {
@ -318,7 +310,7 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
if (is_write || ret < 0) {
kfree(fd_prot->prot_sg);
vfree(fd_prot->prot_buf);
kfree(fd_prot->prot_buf);
}
return ret;
@ -331,36 +323,33 @@ static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,
struct fd_dev *dev = FD_DEV(se_dev);
struct file *fd = dev->fd_file;
struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
struct iov_iter iter;
struct bio_vec *bvec;
ssize_t len = 0;
loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);
int ret = 0, i;
iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
if (!iov) {
bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);
if (!bvec) {
pr_err("Unable to allocate fd_do_readv iov[]\n");
return -ENOMEM;
}
for_each_sg(sgl, sg, sgl_nents, i) {
iov[i].iov_len = sg->length;
iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
bvec[i].bv_page = sg_page(sg);
bvec[i].bv_len = sg->length;
bvec[i].bv_offset = sg->offset;
len += sg->length;
}
old_fs = get_fs();
set_fs(get_ds());
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
if (is_write)
ret = vfs_writev(fd, &iov[0], sgl_nents, &pos);
ret = vfs_iter_write(fd, &iter, &pos);
else
ret = vfs_readv(fd, &iov[0], sgl_nents, &pos);
ret = vfs_iter_read(fd, &iter, &pos);
set_fs(old_fs);
for_each_sg(sgl, sg, sgl_nents, i)
kunmap(sg_page(sg));
kfree(iov);
kfree(bvec);
if (is_write) {
if (ret < 0 || ret != cmd->data_length) {
@ -436,59 +425,17 @@ fd_execute_sync_cache(struct se_cmd *cmd)
return 0;
}
static unsigned char *
fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg,
unsigned int len)
{
struct se_device *se_dev = cmd->se_dev;
unsigned int block_size = se_dev->dev_attrib.block_size;
unsigned int i = 0, end;
unsigned char *buf, *p, *kmap_buf;
buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate fd_execute_write_same buf\n");
return NULL;
}
kmap_buf = kmap(sg_page(sg)) + sg->offset;
if (!kmap_buf) {
pr_err("kmap() failed in fd_setup_write_same\n");
kfree(buf);
return NULL;
}
/*
* Fill local *buf to contain multiple WRITE_SAME blocks up to
* min(len, PAGE_SIZE)
*/
p = buf;
end = min_t(unsigned int, len, PAGE_SIZE);
while (i < end) {
memcpy(p, kmap_buf, block_size);
i += block_size;
p += block_size;
}
kunmap(sg_page(sg));
return buf;
}
static sense_reason_t
fd_execute_write_same(struct se_cmd *cmd)
{
struct se_device *se_dev = cmd->se_dev;
struct fd_dev *fd_dev = FD_DEV(se_dev);
struct file *f = fd_dev->fd_file;
struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
sector_t nolb = sbc_get_write_same_sectors(cmd);
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
unsigned int len, len_tmp, iov_num;
int i, rc;
unsigned char *buf;
sector_t nolb = sbc_get_write_same_sectors(cmd);
struct iov_iter iter;
struct bio_vec *bvec;
unsigned int len = 0, i;
ssize_t ret;
if (!nolb) {
target_complete_cmd(cmd, SAM_STAT_GOOD);
@ -499,49 +446,35 @@ fd_execute_write_same(struct se_cmd *cmd)
" backends not supported\n");
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
sg->length != cmd->se_dev->dev_attrib.block_size) {
cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
" block_size: %u\n", cmd->t_data_nents, sg->length,
" block_size: %u\n",
cmd->t_data_nents,
cmd->t_data_sg[0].length,
cmd->se_dev->dev_attrib.block_size);
return TCM_INVALID_CDB_FIELD;
}
len = len_tmp = nolb * se_dev->dev_attrib.block_size;
iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
buf = fd_setup_write_same_buf(cmd, sg, len);
if (!buf)
bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);
if (!bvec)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
iov = vzalloc(sizeof(struct iovec) * iov_num);
if (!iov) {
pr_err("Unable to allocate fd_execute_write_same iovecs\n");
kfree(buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
/*
* Map the single fabric received scatterlist block now populated
* in *buf into each iovec for I/O submission.
*/
for (i = 0; i < iov_num; i++) {
iov[i].iov_base = buf;
iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE);
len_tmp -= iov[i].iov_len;
for (i = 0; i < nolb; i++) {
bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]);
bvec[i].bv_len = cmd->t_data_sg[0].length;
bvec[i].bv_offset = cmd->t_data_sg[0].offset;
len += se_dev->dev_attrib.block_size;
}
old_fs = get_fs();
set_fs(get_ds());
rc = vfs_writev(f, &iov[0], iov_num, &pos);
set_fs(old_fs);
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos);
vfree(iov);
kfree(buf);
if (rc < 0 || rc != len) {
pr_err("vfs_writev() returned %d for write same\n", rc);
kfree(bvec);
if (ret < 0 || ret != len) {
pr_err("vfs_iter_write() returned %zd for write same\n", ret);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
@ -549,6 +482,56 @@ fd_execute_write_same(struct se_cmd *cmd)
return 0;
}
static int
fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb,
void *buf, size_t bufsize)
{
struct fd_dev *fd_dev = FD_DEV(se_dev);
struct file *prot_fd = fd_dev->fd_prot_file;
sector_t prot_length, prot;
loff_t pos = lba * se_dev->prot_length;
if (!prot_fd) {
pr_err("Unable to locate fd_dev->fd_prot_file\n");
return -ENODEV;
}
prot_length = nolb * se_dev->prot_length;
for (prot = 0; prot < prot_length;) {
sector_t len = min_t(sector_t, bufsize, prot_length - prot);
ssize_t ret = kernel_write(prot_fd, buf, len, pos + prot);
if (ret != len) {
pr_err("vfs_write to prot file failed: %zd\n", ret);
return ret < 0 ? ret : -ENODEV;
}
prot += ret;
}
return 0;
}
static int
fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
{
void *buf;
int rc;
buf = (void *)__get_free_page(GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate FILEIO prot buf\n");
return -ENOMEM;
}
memset(buf, 0xff, PAGE_SIZE);
rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE);
free_page((unsigned long)buf);
return rc;
}
static sense_reason_t
fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
{
@ -556,6 +539,12 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
struct inode *inode = file->f_mapping->host;
int ret;
if (cmd->se_dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_unmap(cmd, lba, nolb);
if (ret)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
if (S_ISBLK(inode->i_mode)) {
/* The backend is block device, use discard */
struct block_device *bdev = inode->i_bdev;
@ -595,7 +584,7 @@ fd_execute_write_same_unmap(struct se_cmd *cmd)
struct file *file = fd_dev->fd_file;
sector_t lba = cmd->t_task_lba;
sector_t nolb = sbc_get_write_same_sectors(cmd);
int ret;
sense_reason_t ret;
if (!nolb) {
target_complete_cmd(cmd, SAM_STAT_GOOD);
@ -643,7 +632,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (data_direction == DMA_FROM_DEVICE) {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, false);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@ -651,23 +640,23 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ret = fd_do_rw(cmd, sgl, sgl_nents, 0);
if (ret > 0 && cmd->prot_type) {
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return rc;
}
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
}
} else {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
ret = fd_do_prot_rw(cmd, &fd_prot, false);
@ -678,7 +667,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return rc;
}
}
@ -705,7 +694,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
}
if (ret > 0 && cmd->prot_type) {
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, true);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@ -714,7 +703,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (ret < 0) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
@ -878,48 +867,28 @@ static int fd_init_prot(struct se_device *dev)
static int fd_format_prot(struct se_device *dev)
{
struct fd_dev *fd_dev = FD_DEV(dev);
struct file *prot_fd = fd_dev->fd_prot_file;
sector_t prot_length, prot;
unsigned char *buf;
loff_t pos = 0;
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
int rc, ret = 0, size, len;
int ret;
if (!dev->dev_attrib.pi_prot_type) {
pr_err("Unable to format_prot while pi_prot_type == 0\n");
return -ENODEV;
}
if (!prot_fd) {
pr_err("Unable to locate fd_dev->fd_prot_file\n");
return -ENODEV;
}
buf = vzalloc(unit_size);
if (!buf) {
pr_err("Unable to allocate FILEIO prot buf\n");
return -ENOMEM;
}
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
size = prot_length;
pr_debug("Using FILEIO prot_length: %llu\n",
(unsigned long long)prot_length);
(unsigned long long)(dev->transport->get_blocks(dev) + 1) *
dev->prot_length);
memset(buf, 0xff, unit_size);
for (prot = 0; prot < prot_length; prot += unit_size) {
len = min(unit_size, size);
rc = kernel_write(prot_fd, buf, len, pos);
if (rc != len) {
pr_err("vfs_write to prot file failed: %d\n", rc);
ret = -ENODEV;
goto out;
}
pos += len;
size -= len;
}
out:
ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1,
buf, unit_size);
vfree(buf);
return ret;
}

View File

@ -444,7 +444,7 @@ iblock_execute_write_same_unmap(struct se_cmd *cmd)
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
sector_t lba = cmd->t_task_lba;
sector_t nolb = sbc_get_write_same_sectors(cmd);
int ret;
sense_reason_t ret;
ret = iblock_do_unmap(cmd, bdev, lba, nolb);
if (ret)
@ -774,7 +774,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
sg_num--;
}
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
int rc = iblock_alloc_bip(cmd, bio_start);
if (rc)
goto fail_put_bios;

View File

@ -4,7 +4,13 @@
/* target_core_alua.c */
extern struct t10_alua_lu_gp *default_lu_gp;
/* target_core_configfs.c */
extern struct configfs_subsystem *target_core_subsystem[];
/* target_core_device.c */
extern struct mutex g_device_mutex;
extern struct list_head g_device_list;
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
int core_free_device_list_for_node(struct se_node_acl *,
struct se_portal_group *);

View File

@ -78,6 +78,22 @@ enum preempt_type {
static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
struct t10_pr_registration *, int, int);
static int is_reservation_holder(
struct t10_pr_registration *pr_res_holder,
struct t10_pr_registration *pr_reg)
{
int pr_res_type;
if (pr_res_holder) {
pr_res_type = pr_res_holder->pr_res_type;
return pr_res_holder == pr_reg ||
pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG;
}
return 0;
}
static sense_reason_t
target_scsi2_reservation_check(struct se_cmd *cmd)
{
@ -664,7 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
struct se_dev_entry *deve_tmp;
struct se_node_acl *nacl_tmp;
struct se_port *port, *port_tmp;
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
int ret;
/*
@ -963,7 +979,7 @@ int core_scsi3_check_aptpl_registration(
}
static void __core_scsi3_dump_registration(
struct target_core_fabric_ops *tfo,
const struct target_core_fabric_ops *tfo,
struct se_device *dev,
struct se_node_acl *nacl,
struct t10_pr_registration *pr_reg,
@ -1004,7 +1020,7 @@ static void __core_scsi3_add_registration(
enum register_type register_type,
int register_move)
{
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
@ -1220,8 +1236,10 @@ static void __core_scsi3_free_registration(
struct t10_pr_registration *pr_reg,
struct list_head *preempt_and_abort_list,
int dec_holders)
__releases(&pr_tmpl->registration_lock)
__acquires(&pr_tmpl->registration_lock)
{
struct target_core_fabric_ops *tfo =
const struct target_core_fabric_ops *tfo =
pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
char i_buf[PR_REG_ISID_ID_LEN];
@ -1445,7 +1463,7 @@ core_scsi3_decode_spec_i_port(
struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
LIST_HEAD(tid_dest_list);
struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
struct target_core_fabric_ops *tmp_tf_ops;
const struct target_core_fabric_ops *tmp_tf_ops;
unsigned char *buf;
unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
@ -2287,7 +2305,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
spin_lock(&dev->dev_reservation_lock);
pr_res_holder = dev->dev_pr_res_holder;
if (pr_res_holder) {
int pr_res_type = pr_res_holder->pr_res_type;
/*
* From spc4r17 Section 5.7.9: Reserving:
*
@ -2298,9 +2315,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
* the logical unit, then the command shall be completed with
* RESERVATION CONFLICT status.
*/
if ((pr_res_holder != pr_reg) &&
(pr_res_type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
(pr_res_type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
pr_err("SPC-3 PR: Attempted RESERVE from"
" [%s]: %s while reservation already held by"
@ -2409,7 +2424,7 @@ static void __core_scsi3_complete_pro_release(
int explicit,
int unreg)
{
struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
const struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
char i_buf[PR_REG_ISID_ID_LEN];
int pr_res_type = 0, pr_res_scope = 0;
@ -2477,7 +2492,6 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
struct se_lun *se_lun = cmd->se_lun;
struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
int all_reg = 0;
sense_reason_t ret = 0;
if (!se_sess || !se_lun) {
@ -2514,13 +2528,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
spin_unlock(&dev->dev_reservation_lock);
goto out_put_pr_reg;
}
if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
(pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
all_reg = 1;
if ((all_reg == 0) && (pr_res_holder != pr_reg)) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
/*
* Non 'All Registrants' PR Type cases..
* Release request from a registered I_T nexus that is not a
* persistent reservation holder. return GOOD status.
*/
@ -2726,7 +2736,7 @@ static void __core_scsi3_complete_pro_preempt(
enum preempt_type preempt_type)
{
struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
char i_buf[PR_REG_ISID_ID_LEN];
memset(i_buf, 0, PR_REG_ISID_ID_LEN);
@ -3111,7 +3121,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
struct se_port *se_port;
struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
unsigned char *buf;
@ -3375,7 +3385,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
* From spc4r17 section 5.7.8 Table 50 --
* Register behaviors for a REGISTER AND MOVE service action
*/
if (pr_res_holder != pr_reg) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
" Nexus is not reservation holder\n");
spin_unlock(&dev->dev_reservation_lock);

View File

@ -139,10 +139,22 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
unsigned char *p;
while (total_sg_needed) {
unsigned int chain_entry = 0;
sg_per_table = (total_sg_needed > max_sg_per_table) ?
max_sg_per_table : total_sg_needed;
sg = kzalloc(sg_per_table * sizeof(struct scatterlist),
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
/*
* Reserve extra element for chain entry
*/
if (sg_per_table < total_sg_needed)
chain_entry = 1;
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
sg = kcalloc(sg_per_table + chain_entry, sizeof(*sg),
GFP_KERNEL);
if (!sg) {
pr_err("Unable to allocate scatterlist array"
@ -150,7 +162,16 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
return -ENOMEM;
}
sg_init_table(sg, sg_per_table);
sg_init_table(sg, sg_per_table + chain_entry);
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
if (i > 0) {
sg_chain(sg_table[i - 1].sg_table,
max_sg_per_table + 1, sg);
}
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
sg_table[i].sg_table = sg;
sg_table[i].rd_sg_count = sg_per_table;
@ -382,6 +403,76 @@ static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page
return NULL;
}
typedef sense_reason_t (*dif_verify)(struct se_cmd *, sector_t, unsigned int,
unsigned int, struct scatterlist *, int);
static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify)
{
struct se_device *se_dev = cmd->se_dev;
struct rd_dev *dev = RD_DEV(se_dev);
struct rd_dev_sg_table *prot_table;
bool need_to_release = false;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
u32 prot_npages __maybe_unused;
u64 tmp;
sense_reason_t rc = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page -
prot_table->page_start_offset];
#ifndef CONFIG_ARCH_HAS_SG_CHAIN
prot_npages = DIV_ROUND_UP(prot_offset + sectors * se_dev->prot_length,
PAGE_SIZE);
/*
* Allocate temporaly contiguous scatterlist entries if prot pages
* straddles multiple scatterlist tables.
*/
if (prot_table->page_end_offset < prot_page + prot_npages - 1) {
int i;
prot_sg = kcalloc(prot_npages, sizeof(*prot_sg), GFP_KERNEL);
if (!prot_sg)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
need_to_release = true;
sg_init_table(prot_sg, prot_npages);
for (i = 0; i < prot_npages; i++) {
if (prot_page + i > prot_table->page_end_offset) {
prot_table = rd_get_prot_table(dev,
prot_page + i);
if (!prot_table) {
kfree(prot_sg);
return rc;
}
sg_unmark_end(&prot_sg[i - 1]);
}
prot_sg[i] = prot_table->sg_table[prot_page + i -
prot_table->page_start_offset];
}
}
#endif /* !CONFIG_ARCH_HAS_SG_CHAIN */
rc = dif_verify(cmd, cmd->t_task_lba, sectors, 0, prot_sg, prot_offset);
if (need_to_release)
kfree(prot_sg);
return rc;
}
static sense_reason_t
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
enum dma_data_direction data_direction)
@ -419,24 +510,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
cmd->t_task_lba, rd_size, rd_page, rd_offset);
if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
data_direction == DMA_TO_DEVICE) {
rc = rd_do_prot_rw(cmd, sbc_dif_verify_write);
if (rc)
return rc;
}
@ -502,24 +578,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
}
sg_miter_stop(&m);
if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
data_direction == DMA_FROM_DEVICE) {
rc = rd_do_prot_rw(cmd, sbc_dif_verify_read);
if (rc)
return rc;
}

View File

@ -93,6 +93,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
int pi_prot_type = dev->dev_attrib.pi_prot_type;
unsigned char *rbuf;
unsigned char buf[32];
unsigned long long blocks = dev->transport->get_blocks(dev);
@ -114,8 +116,15 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
* Set P_TYPE and PROT_EN bits for DIF support
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
/*
* Only override a device's pi_prot_type if no T10-PI is
* available, and sess_prot_type has been explicitly enabled.
*/
if (!pi_prot_type)
pi_prot_type = sess->sess_prot_type;
if (pi_prot_type)
buf[12] = (pi_prot_type - 1) << 1 | 0x1;
}
if (dev->transport->get_lbppbe)
@ -312,7 +321,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
return 0;
}
static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd)
static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success)
{
unsigned char *buf, *addr;
struct scatterlist *sg;
@ -376,7 +385,7 @@ sbc_execute_rw(struct se_cmd *cmd)
cmd->data_direction);
}
static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
{
struct se_device *dev = cmd->se_dev;
@ -399,7 +408,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
return TCM_NO_SENSE;
}
static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success)
{
struct se_device *dev = cmd->se_dev;
struct scatterlist *write_sg = NULL, *sg;
@ -414,10 +423,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
/*
* Handle early failure in transport_generic_request_failure(),
* which will not have taken ->caw_mutex yet..
* which will not have taken ->caw_sem yet..
*/
if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg))
return TCM_NO_SENSE;
/*
* Handle special case for zero-length COMPARE_AND_WRITE
*/
if (!cmd->data_length)
goto out;
/*
* Immediately exit + release dev->caw_sem if command has already
* been failed with a non-zero SCSI status.
@ -581,12 +595,13 @@ sbc_compare_and_write(struct se_cmd *cmd)
}
static int
sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
sbc_set_prot_op_checks(u8 protect, bool fabric_prot, enum target_prot_type prot_type,
bool is_write, struct se_cmd *cmd)
{
if (is_write) {
cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS :
TARGET_PROT_DOUT_INSERT;
cmd->prot_op = fabric_prot ? TARGET_PROT_DOUT_STRIP :
protect ? TARGET_PROT_DOUT_PASS :
TARGET_PROT_DOUT_INSERT;
switch (protect) {
case 0x0:
case 0x3:
@ -610,8 +625,9 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
return -EINVAL;
}
} else {
cmd->prot_op = protect ? TARGET_PROT_DIN_PASS :
TARGET_PROT_DIN_STRIP;
cmd->prot_op = fabric_prot ? TARGET_PROT_DIN_INSERT :
protect ? TARGET_PROT_DIN_PASS :
TARGET_PROT_DIN_STRIP;
switch (protect) {
case 0x0:
case 0x1:
@ -644,11 +660,15 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
u32 sectors, bool is_write)
{
u8 protect = cdb[1] >> 5;
int sp_ops = cmd->se_sess->sup_prot_ops;
int pi_prot_type = dev->dev_attrib.pi_prot_type;
bool fabric_prot = false;
if (!cmd->t_prot_sg || !cmd->t_prot_nents) {
if (protect && !dev->dev_attrib.pi_prot_type) {
pr_err("CDB contains protect bit, but device does not"
" advertise PROTECT=1 feature bit\n");
if (unlikely(protect &&
!dev->dev_attrib.pi_prot_type && !cmd->se_sess->sess_prot_type)) {
pr_err("CDB contains protect bit, but device + fabric does"
" not advertise PROTECT=1 feature bit\n");
return TCM_INVALID_CDB_FIELD;
}
if (cmd->prot_pto)
@ -669,15 +689,32 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
cmd->reftag_seed = cmd->t_task_lba;
break;
case TARGET_DIF_TYPE0_PROT:
/*
* See if the fabric supports T10-PI, and the session has been
* configured to allow export PROTECT=1 feature bit with backend
* devices that don't support T10-PI.
*/
fabric_prot = is_write ?
!!(sp_ops & (TARGET_PROT_DOUT_PASS | TARGET_PROT_DOUT_STRIP)) :
!!(sp_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DIN_INSERT));
if (fabric_prot && cmd->se_sess->sess_prot_type) {
pi_prot_type = cmd->se_sess->sess_prot_type;
break;
}
if (!protect)
return TCM_NO_SENSE;
/* Fallthrough */
default:
return TCM_NO_SENSE;
pr_err("Unable to determine pi_prot_type for CDB: 0x%02x "
"PROTECT: 0x%02x\n", cdb[0], protect);
return TCM_INVALID_CDB_FIELD;
}
if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type,
is_write, cmd))
if (sbc_set_prot_op_checks(protect, fabric_prot, pi_prot_type, is_write, cmd))
return TCM_INVALID_CDB_FIELD;
cmd->prot_type = dev->dev_attrib.pi_prot_type;
cmd->prot_type = pi_prot_type;
cmd->prot_length = dev->prot_length * sectors;
/**
@ -1166,14 +1203,16 @@ sbc_dif_generate(struct se_cmd *cmd)
sdt = paddr + offset;
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
dev->dev_attrib.block_size));
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT)
sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
sdt->app_tag = 0;
pr_debug("DIF WRITE INSERT sector: %llu guard_tag: 0x%04x"
pr_debug("DIF %s INSERT sector: %llu guard_tag: 0x%04x"
" app_tag: 0x%04x ref_tag: %u\n",
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
(cmd->data_direction == DMA_TO_DEVICE) ?
"WRITE" : "READ", (unsigned long long)sector,
sdt->guard_tag, sdt->app_tag,
be32_to_cpu(sdt->ref_tag));
sector++;
offset += sizeof(struct se_dif_v1_tuple);
@ -1185,12 +1224,16 @@ sbc_dif_generate(struct se_cmd *cmd)
}
static sense_reason_t
sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt,
const void *p, sector_t sector, unsigned int ei_lba)
{
struct se_device *dev = cmd->se_dev;
int block_size = dev->dev_attrib.block_size;
__be16 csum;
if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD))
goto check_ref;
csum = cpu_to_be16(crc_t10dif(p, block_size));
if (sdt->guard_tag != csum) {
@ -1200,7 +1243,11 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT &&
check_ref:
if (!(cmd->prot_checks & TARGET_DIF_CHECK_REFTAG))
return 0;
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT &&
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
" sector MSB: 0x%08x\n", (unsigned long long)sector,
@ -1208,7 +1255,7 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT &&
if (cmd->prot_type == TARGET_DIF_TYPE2_PROT &&
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
" ei_lba: 0x%08x\n", (unsigned long long)sector,
@ -1229,6 +1276,9 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
unsigned int i, len, left;
unsigned int offset = sg_off;
if (!sg)
return;
left = sectors * dev->prot_length;
for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
@ -1292,7 +1342,7 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);
@ -1309,6 +1359,9 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
kunmap_atomic(paddr);
kunmap_atomic(daddr);
}
if (!sg)
return 0;
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
return 0;
@ -1353,7 +1406,7 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
continue;
}
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);

View File

@ -103,10 +103,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
buf[5] |= 0x8;
/*
* Set Protection (PROTECT) bit when DIF has been enabled on the
* device, and the transport supports VERIFY + PASS.
* device, and the fabric supports VERIFY + PASS. Also report
* PROTECT=1 if sess_prot_type has been configured to allow T10-PI
* to unprotected devices.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
if (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)
buf[5] |= 0x1;
}
@ -467,9 +469,11 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
* only for TYPE3 protection.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT ||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
buf[4] = 0x5;
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
buf[4] = 0x4;
}
@ -861,7 +865,7 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p)
* TAG field.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
if (dev->dev_attrib.pi_prot_type || sess->sess_prot_type)
p[5] |= 0x80;
}
@ -1099,7 +1103,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
unsigned char *buf;
unsigned char tbuf[SE_MODE_PAGE_BUF];
int length;
int ret = 0;
sense_reason_t ret = 0;
int i;
if (!cmd->data_length) {

View File

@ -125,8 +125,8 @@ void core_tmr_abort_task(
if (dev != se_cmd->se_dev)
continue;
/* skip se_cmd associated with tmr */
if (tmr->task_cmd == se_cmd)
/* skip task management functions, including tmr->task_cmd */
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
continue;
ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);

View File

@ -672,7 +672,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
}
int core_tpg_register(
struct target_core_fabric_ops *tfo,
const struct target_core_fabric_ops *tfo,
struct se_wwn *se_wwn,
struct se_portal_group *se_tpg,
void *tpg_fabric_ptr,

View File

@ -322,6 +322,7 @@ void __transport_register_session(
struct se_session *se_sess,
void *fabric_sess_ptr)
{
const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo;
unsigned char buf[PR_REG_ISID_LEN];
se_sess->se_tpg = se_tpg;
@ -333,6 +334,21 @@ void __transport_register_session(
* eg: *NOT* discovery sessions.
*/
if (se_nacl) {
/*
*
* Determine if fabric allows for T10-PI feature bits exposed to
* initiators for device backends with !dev->dev_attrib.pi_prot_type.
*
* If so, then always save prot_type on a per se_node_acl node
* basis and re-instate the previous sess_prot_type to avoid
* disabling PI from below any previously initiator side
* registered LUNs.
*/
if (se_nacl->saved_prot_type)
se_sess->sess_prot_type = se_nacl->saved_prot_type;
else if (tfo->tpg_check_prot_fabric_only)
se_sess->sess_prot_type = se_nacl->saved_prot_type =
tfo->tpg_check_prot_fabric_only(se_tpg);
/*
* If the fabric module supports an ISID based TransportID,
* save this value in binary from the fabric I_T Nexus now.
@ -404,6 +420,30 @@ void target_put_session(struct se_session *se_sess)
}
EXPORT_SYMBOL(target_put_session);
ssize_t target_show_dynamic_sessions(struct se_portal_group *se_tpg, char *page)
{
struct se_session *se_sess;
ssize_t len = 0;
spin_lock_bh(&se_tpg->session_lock);
list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
if (!se_sess->se_node_acl)
continue;
if (!se_sess->se_node_acl->dynamic_node_acl)
continue;
if (strlen(se_sess->se_node_acl->initiatorname) + 1 + len > PAGE_SIZE)
break;
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
se_sess->se_node_acl->initiatorname);
len += 1; /* Include NULL terminator */
}
spin_unlock_bh(&se_tpg->session_lock);
return len;
}
EXPORT_SYMBOL(target_show_dynamic_sessions);
static void target_complete_nacl(struct kref *kref)
{
struct se_node_acl *nacl = container_of(kref,
@ -462,7 +502,7 @@ EXPORT_SYMBOL(transport_free_session);
void transport_deregister_session(struct se_session *se_sess)
{
struct se_portal_group *se_tpg = se_sess->se_tpg;
struct target_core_fabric_ops *se_tfo;
const struct target_core_fabric_ops *se_tfo;
struct se_node_acl *se_nacl;
unsigned long flags;
bool comp_nacl = true;
@ -1118,7 +1158,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
*/
void transport_init_se_cmd(
struct se_cmd *cmd,
struct target_core_fabric_ops *tfo,
const struct target_core_fabric_ops *tfo,
struct se_session *se_sess,
u32 data_length,
int data_direction,
@ -1570,6 +1610,8 @@ EXPORT_SYMBOL(target_submit_tmr);
* has completed.
*/
bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
__releases(&cmd->t_state_lock)
__acquires(&cmd->t_state_lock)
{
bool was_active = false;
@ -1615,11 +1657,11 @@ void transport_generic_request_failure(struct se_cmd *cmd,
transport_complete_task_attr(cmd);
/*
* Handle special case for COMPARE_AND_WRITE failure, where the
* callback is expected to drop the per device ->caw_mutex.
* callback is expected to drop the per device ->caw_sem.
*/
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
cmd->transport_complete_callback)
cmd->transport_complete_callback(cmd);
cmd->transport_complete_callback(cmd, false);
switch (sense_reason) {
case TCM_NON_EXISTENT_LUN:
@ -1706,6 +1748,41 @@ void __target_execute_cmd(struct se_cmd *cmd)
}
}
static int target_write_prot_action(struct se_cmd *cmd)
{
u32 sectors;
/*
* Perform WRITE_INSERT of PI using software emulation when backend
* device has PI enabled, if the transport has not already generated
* PI using hardware WRITE_INSERT offload.
*/
switch (cmd->prot_op) {
case TARGET_PROT_DOUT_INSERT:
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
sbc_dif_generate(cmd);
break;
case TARGET_PROT_DOUT_STRIP:
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_STRIP)
break;
sectors = cmd->data_length >> ilog2(cmd->se_dev->dev_attrib.block_size);
cmd->pi_err = sbc_dif_verify_write(cmd, cmd->t_task_lba,
sectors, 0, NULL, 0);
if (unlikely(cmd->pi_err)) {
spin_lock_irq(&cmd->t_state_lock);
cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
spin_unlock_irq(&cmd->t_state_lock);
transport_generic_request_failure(cmd, cmd->pi_err);
return -1;
}
break;
default:
break;
}
return 0;
}
static bool target_handle_task_attr(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
@ -1785,15 +1862,9 @@ void target_execute_cmd(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_PROCESSING;
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
spin_unlock_irq(&cmd->t_state_lock);
/*
* Perform WRITE_INSERT of PI using software emulation when backend
* device has PI enabled, if the transport has not already generated
* PI using hardware WRITE_INSERT offload.
*/
if (cmd->prot_op == TARGET_PROT_DOUT_INSERT) {
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
sbc_dif_generate(cmd);
}
if (target_write_prot_action(cmd))
return;
if (target_handle_task_attr(cmd)) {
spin_lock_irq(&cmd->t_state_lock);
@ -1919,16 +1990,28 @@ static void transport_handle_queue_full(
schedule_work(&cmd->se_dev->qf_work_queue);
}
static bool target_check_read_strip(struct se_cmd *cmd)
static bool target_read_prot_action(struct se_cmd *cmd)
{
sense_reason_t rc;
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
rc = sbc_dif_read_strip(cmd);
if (rc) {
cmd->pi_err = rc;
return true;
switch (cmd->prot_op) {
case TARGET_PROT_DIN_STRIP:
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
rc = sbc_dif_read_strip(cmd);
if (rc) {
cmd->pi_err = rc;
return true;
}
}
break;
case TARGET_PROT_DIN_INSERT:
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_INSERT)
break;
sbc_dif_generate(cmd);
break;
default:
break;
}
return false;
@ -1975,8 +2058,12 @@ static void target_complete_ok_work(struct work_struct *work)
if (cmd->transport_complete_callback) {
sense_reason_t rc;
rc = cmd->transport_complete_callback(cmd);
rc = cmd->transport_complete_callback(cmd, true);
if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) {
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
!cmd->data_length)
goto queue_rsp;
return;
} else if (rc) {
ret = transport_send_check_condition_and_sense(cmd,
@ -1990,6 +2077,7 @@ static void target_complete_ok_work(struct work_struct *work)
}
}
queue_rsp:
switch (cmd->data_direction) {
case DMA_FROM_DEVICE:
spin_lock(&cmd->se_lun->lun_sep_lock);
@ -2003,8 +2091,7 @@ static void target_complete_ok_work(struct work_struct *work)
* backend had PI enabled, if the transport will not be
* performing hardware READ_STRIP offload.
*/
if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
target_check_read_strip(cmd)) {
if (target_read_prot_action(cmd)) {
ret = transport_send_check_condition_and_sense(cmd,
cmd->pi_err, 0);
if (ret == -EAGAIN || ret == -ENOMEM)
@ -2094,6 +2181,16 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd)
static inline void transport_free_pages(struct se_cmd *cmd)
{
if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
/*
* Release special case READ buffer payload required for
* SG_TO_MEM_NOALLOC to function with COMPARE_AND_WRITE
*/
if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) {
transport_free_sgl(cmd->t_bidi_data_sg,
cmd->t_bidi_data_nents);
cmd->t_bidi_data_sg = NULL;
cmd->t_bidi_data_nents = 0;
}
transport_reset_sgl_orig(cmd);
return;
}
@ -2246,6 +2343,7 @@ sense_reason_t
transport_generic_new_cmd(struct se_cmd *cmd)
{
int ret = 0;
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
/*
* Determine is the TCM fabric module has already allocated physical
@ -2254,7 +2352,6 @@ transport_generic_new_cmd(struct se_cmd *cmd)
*/
if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) &&
cmd->data_length) {
bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
if ((cmd->se_cmd_flags & SCF_BIDI) ||
(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) {
@ -2285,6 +2382,20 @@ transport_generic_new_cmd(struct se_cmd *cmd)
cmd->data_length, zero_flag);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
} else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
cmd->data_length) {
/*
* Special case for COMPARE_AND_WRITE with fabrics
* using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC.
*/
u32 caw_length = cmd->t_task_nolb *
cmd->se_dev->dev_attrib.block_size;
ret = target_alloc_sgl(&cmd->t_bidi_data_sg,
&cmd->t_bidi_data_nents,
caw_length, zero_flag);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
/*
* If this command is not a write we can execute it right here,
@ -2376,10 +2487,8 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
* fabric acknowledgement that requires two target_put_sess_cmd()
* invocations before se_cmd descriptor release.
*/
if (ack_kref) {
if (ack_kref)
kref_get(&se_cmd->cmd_kref);
se_cmd->se_cmd_flags |= SCF_ACK_KREF;
}
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
if (se_sess->sess_tearing_down) {
@ -2398,6 +2507,7 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
EXPORT_SYMBOL(target_get_sess_cmd);
static void target_release_cmd_kref(struct kref *kref)
__releases(&se_cmd->se_sess->sess_cmd_lock)
{
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
struct se_session *se_sess = se_cmd->se_sess;

View File

@ -344,8 +344,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
entry = (void *) mb + CMDR_OFF + cmd_head;
tcmu_flush_dcache_range(entry, sizeof(*entry));
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD);
tcmu_hdr_set_len(&entry->hdr, pad_size);
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD);
tcmu_hdr_set_len(&entry->hdr.len_op, pad_size);
entry->hdr.cmd_id = 0; /* not used for PAD */
entry->hdr.kflags = 0;
entry->hdr.uflags = 0;
UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size);
@ -355,9 +358,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
entry = (void *) mb + CMDR_OFF + cmd_head;
tcmu_flush_dcache_range(entry, sizeof(*entry));
tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD);
tcmu_hdr_set_len(&entry->hdr, command_size);
entry->cmd_id = tcmu_cmd->cmd_id;
tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
tcmu_hdr_set_len(&entry->hdr.len_op, command_size);
entry->hdr.cmd_id = tcmu_cmd->cmd_id;
entry->hdr.kflags = 0;
entry->hdr.uflags = 0;
/*
* Fix up iovecs, and handle if allocation in data ring wrapped.
@ -376,7 +381,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
/* Even iov_base is relative to mb_addr */
iov->iov_len = copy_bytes;
iov->iov_base = (void *) udev->data_off + udev->data_head;
iov->iov_base = (void __user *) udev->data_off +
udev->data_head;
iov_cnt++;
iov++;
@ -388,7 +394,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
copy_bytes = sg->length - copy_bytes;
iov->iov_len = copy_bytes;
iov->iov_base = (void *) udev->data_off + udev->data_head;
iov->iov_base = (void __user *) udev->data_off +
udev->data_head;
if (se_cmd->data_direction == DMA_TO_DEVICE) {
to = (void *) mb + udev->data_off + udev->data_head;
@ -405,6 +412,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
kunmap_atomic(from);
}
entry->req.iov_cnt = iov_cnt;
entry->req.iov_bidi_cnt = 0;
entry->req.iov_dif_cnt = 0;
/* All offsets relative to mb_addr, not start of entry! */
cdb_off = CMDR_OFF + cmd_head + base_command_size;
@ -462,6 +471,17 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
return;
}
if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) {
UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size);
pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n",
cmd->se_cmd);
transport_generic_request_failure(cmd->se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
cmd->se_cmd = NULL;
kmem_cache_free(tcmu_cmd_cache, cmd);
return;
}
if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
se_cmd->scsi_sense_length);
@ -540,14 +560,16 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
tcmu_flush_dcache_range(entry, sizeof(*entry));
if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) {
UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size);
if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) {
UPDATE_HEAD(udev->cmdr_last_cleaned,
tcmu_hdr_get_len(entry->hdr.len_op),
udev->cmdr_size);
continue;
}
WARN_ON(tcmu_hdr_get_op(&entry->hdr) != TCMU_OP_CMD);
WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD);
spin_lock(&udev->commands_lock);
cmd = idr_find(&udev->commands, entry->cmd_id);
cmd = idr_find(&udev->commands, entry->hdr.cmd_id);
if (cmd)
idr_remove(&udev->commands, cmd->cmd_id);
spin_unlock(&udev->commands_lock);
@ -560,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
tcmu_handle_completion(cmd, entry);
UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size);
UPDATE_HEAD(udev->cmdr_last_cleaned,
tcmu_hdr_get_len(entry->hdr.len_op),
udev->cmdr_size);
handled++;
}
@ -838,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev)
udev->data_size = TCMU_RING_SIZE - CMDR_SIZE;
mb = udev->mb_addr;
mb->version = 1;
mb->version = TCMU_MAILBOX_VERSION;
mb->cmdr_off = CMDR_OFF;
mb->cmdr_size = udev->cmdr_size;
WARN_ON(!PAGE_ALIGNED(udev->data_off));
WARN_ON(udev->data_size % PAGE_SIZE);
info->version = "1";
info->version = xstr(TCMU_MAILBOX_VERSION);
info->mem[0].name = "tcm-user command & data buffer";
info->mem[0].addr = (phys_addr_t) udev->mb_addr;

View File

@ -34,20 +34,12 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
#include "target_core_internal.h"
#include "target_core_pr.h"
#include "target_core_ua.h"
#include "target_core_xcopy.h"
static struct workqueue_struct *xcopy_wq = NULL;
/*
* From target_core_device.c
*/
extern struct mutex g_device_mutex;
extern struct list_head g_device_list;
/*
* From target_core_configfs.c
*/
extern struct configfs_subsystem *target_core_subsystem[];
static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
{
@ -433,7 +425,7 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
return 0;
}
static struct target_core_fabric_ops xcopy_pt_tfo = {
static const struct target_core_fabric_ops xcopy_pt_tfo = {
.get_fabric_name = xcopy_pt_get_fabric_name,
.get_task_tag = xcopy_pt_get_tag,
.get_cmd_state = xcopy_pt_get_cmd_state,
@ -548,33 +540,22 @@ static void target_xcopy_setup_pt_port(
}
}
static int target_xcopy_init_pt_lun(
struct xcopy_pt_cmd *xpt_cmd,
struct xcopy_op *xop,
struct se_device *se_dev,
struct se_cmd *pt_cmd,
bool remote_port)
static void target_xcopy_init_pt_lun(struct se_device *se_dev,
struct se_cmd *pt_cmd, bool remote_port)
{
/*
* Don't allocate + init an pt_cmd->se_lun if honoring local port for
* reservations. The pt_cmd->se_lun pointer will be setup from within
* target_xcopy_setup_pt_port()
*/
if (!remote_port) {
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
return 0;
if (remote_port) {
pr_debug("Setup emulated se_dev: %p from se_dev\n",
pt_cmd->se_dev);
pt_cmd->se_lun = &se_dev->xcopy_lun;
pt_cmd->se_dev = se_dev;
}
pt_cmd->se_lun = &se_dev->xcopy_lun;
pt_cmd->se_dev = se_dev;
pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev);
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n",
pt_cmd->se_lun->lun_se_dev);
return 0;
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
}
static int target_xcopy_setup_pt_cmd(
@ -592,11 +573,8 @@ static int target_xcopy_setup_pt_cmd(
* Setup LUN+port to honor reservations based upon xop->op_origin for
* X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
*/
rc = target_xcopy_init_pt_lun(xpt_cmd, xop, se_dev, cmd, remote_port);
if (rc < 0) {
ret = rc;
goto out;
}
target_xcopy_init_pt_lun(se_dev, cmd, remote_port);
xpt_cmd->xcopy_op = xop;
target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);

View File

@ -129,7 +129,6 @@ struct ft_cmd {
extern struct mutex ft_lport_lock;
extern struct fc4_prov ft_prov;
extern struct target_fabric_configfs *ft_configfs;
extern unsigned int ft_debug_logging;
/*

View File

@ -48,7 +48,7 @@
#include "tcm_fc.h"
struct target_fabric_configfs *ft_configfs;
static const struct target_core_fabric_ops ft_fabric_ops;
static LIST_HEAD(ft_wwn_list);
DEFINE_MUTEX(ft_lport_lock);
@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg(
return NULL;
}
ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg,
tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
destroy_workqueue(wq);
@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
return tpg->index;
}
static struct target_core_fabric_ops ft_fabric_ops = {
static const struct target_core_fabric_ops ft_fabric_ops = {
.module = THIS_MODULE,
.name = "fc",
.get_fabric_name = ft_get_fabric_name,
.get_fabric_proto_ident = fc_get_fabric_proto_ident,
.tpg_get_wwn = ft_get_fabric_wwn,
@ -552,78 +554,35 @@ static struct target_core_fabric_ops ft_fabric_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = &ft_add_acl,
.fabric_drop_nodeacl = &ft_del_acl,
.tfc_wwn_attrs = ft_wwn_attrs,
.tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
};
static int ft_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
/*
* Register the top level struct config_item_type with TCM core
*/
fabric = target_fabric_configfs_init(THIS_MODULE, "fc");
if (IS_ERR(fabric)) {
pr_err("%s: target_fabric_configfs_init() failed!\n",
__func__);
return PTR_ERR(fabric);
}
fabric->tf_ops = ft_fabric_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs =
ft_nacl_base_attrs;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
/*
* register the fabric for use within TCM
*/
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_debug("target_fabric_configfs_register() for"
" FC Target failed!\n");
target_fabric_configfs_free(fabric);
return -1;
}
/*
* Setup our local pointer to *fabric.
*/
ft_configfs = fabric;
return 0;
}
static void ft_deregister_configfs(void)
{
if (!ft_configfs)
return;
target_fabric_configfs_deregister(ft_configfs);
ft_configfs = NULL;
}
static struct notifier_block ft_notifier = {
.notifier_call = ft_lport_notify
};
static int __init ft_init(void)
{
if (ft_register_configfs())
return -1;
if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) {
ft_deregister_configfs();
return -1;
}
int ret;
ret = target_register_template(&ft_fabric_ops);
if (ret)
goto out;
ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov);
if (ret)
goto out_unregister_template;
blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
fc_lport_iterate(ft_lport_add, NULL);
return 0;
out_unregister_template:
target_unregister_template(&ft_fabric_ops);
out:
return ret;
}
static void __exit ft_exit(void)
@ -632,7 +591,7 @@ static void __exit ft_exit(void)
&ft_notifier);
fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
fc_lport_iterate(ft_lport_del, NULL);
ft_deregister_configfs();
target_unregister_template(&ft_fabric_ops);
synchronize_rcu();
}

View File

@ -29,7 +29,7 @@
USB_GADGET_COMPOSITE_OPTIONS();
static struct target_fabric_configfs *usbg_fabric_configfs;
static const struct target_core_fabric_ops usbg_ops;
static inline struct f_uas *to_f_uas(struct usb_function *f)
{
@ -1572,8 +1572,7 @@ static struct se_portal_group *usbg_make_tpg(
tpg->tport = tport;
tpg->tport_tpgt = tpgt;
ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
&tpg->se_tpg, tpg,
ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg,
TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
destroy_workqueue(tpg->workqueue);
@ -1864,7 +1863,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd)
return 1;
}
static struct target_core_fabric_ops usbg_ops = {
static const struct target_core_fabric_ops usbg_ops = {
.module = THIS_MODULE,
.name = "usb_gadget",
.get_fabric_name = usbg_get_fabric_name,
.get_fabric_proto_ident = usbg_get_fabric_proto_ident,
.tpg_get_wwn = usbg_get_fabric_wwn,
@ -1906,46 +1907,9 @@ static struct target_core_fabric_ops usbg_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = usbg_make_nodeacl,
.fabric_drop_nodeacl = usbg_drop_nodeacl,
};
static int usbg_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
if (IS_ERR(fabric)) {
printk(KERN_ERR "target_fabric_configfs_init() failed\n");
return PTR_ERR(fabric);
}
fabric->tf_ops = usbg_ops;
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
printk(KERN_ERR "target_fabric_configfs_register() failed"
" for usb-gadget\n");
return ret;
}
usbg_fabric_configfs = fabric;
return 0;
};
static void usbg_deregister_configfs(void)
{
if (!(usbg_fabric_configfs))
return;
target_fabric_configfs_deregister(usbg_fabric_configfs);
usbg_fabric_configfs = NULL;
.tfc_wwn_attrs = usbg_wwn_attrs,
.tfc_tpg_base_attrs = usbg_base_attrs,
};
/* Start gadget.c code */
@ -2454,16 +2418,13 @@ static void usbg_detach(struct usbg_tpg *tpg)
static int __init usb_target_gadget_init(void)
{
int ret;
ret = usbg_register_configfs();
return ret;
return target_register_template(&usbg_ops);
}
module_init(usb_target_gadget_init);
static void __exit usb_target_gadget_exit(void)
{
usbg_deregister_configfs();
target_unregister_template(&usbg_ops);
}
module_exit(usb_target_gadget_exit);

View File

@ -131,6 +131,8 @@ struct vhost_scsi_tpg {
int tv_tpg_port_count;
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
int tv_tpg_vhost_count;
/* Used for enabling T10-PI with legacy devices */
int tv_fabric_prot_type;
/* list for vhost_scsi_list */
struct list_head tv_tpg_list;
/* Used to protect access for tpg_nexus */
@ -214,9 +216,7 @@ struct vhost_scsi {
int vs_events_nr; /* num of pending events, protected by vq->mutex */
};
/* Local pointer to allocated TCM configfs fabric module */
static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
static struct target_core_fabric_ops vhost_scsi_ops;
static struct workqueue_struct *vhost_scsi_workqueue;
/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
@ -431,6 +431,14 @@ vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
port_nexus_ptr);
}
static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
{
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
return tpg->tv_fabric_prot_type;
}
static struct se_node_acl *
vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg)
{
@ -1878,6 +1886,45 @@ static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus,
}
}
static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
unsigned long val;
int ret = kstrtoul(page, 0, &val);
if (ret) {
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
return ret;
}
if (val != 0 && val != 1 && val != 3) {
pr_err("Invalid vhost_scsi fabric_prot_type: %lu\n", val);
return -EINVAL;
}
tpg->tv_fabric_prot_type = val;
return count;
}
static ssize_t vhost_scsi_tpg_attrib_show_fabric_prot_type(
struct se_portal_group *se_tpg,
char *page)
{
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
return sprintf(page, "%d\n", tpg->tv_fabric_prot_type);
}
TF_TPG_ATTRIB_ATTR(vhost_scsi, fabric_prot_type, S_IRUGO | S_IWUSR);
static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = {
&vhost_scsi_tpg_attrib_fabric_prot_type.attr,
NULL,
};
static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
const char *name)
{
@ -2155,7 +2202,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn,
tpg->tport = tport;
tpg->tport_tpgt = tpgt;
ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn,
ret = core_tpg_register(&vhost_scsi_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
@ -2277,6 +2324,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
};
static struct target_core_fabric_ops vhost_scsi_ops = {
.module = THIS_MODULE,
.name = "vhost",
.get_fabric_name = vhost_scsi_get_fabric_name,
.get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
.tpg_get_wwn = vhost_scsi_get_fabric_wwn,
@ -2289,6 +2338,7 @@ static struct target_core_fabric_ops vhost_scsi_ops = {
.tpg_check_demo_mode_cache = vhost_scsi_check_true,
.tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
.tpg_check_prod_mode_write_protect = vhost_scsi_check_false,
.tpg_check_prot_fabric_only = vhost_scsi_check_prot_fabric_only,
.tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl,
.tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
.tpg_get_inst_index = vhost_scsi_tpg_get_inst_index,
@ -2320,70 +2370,20 @@ static struct target_core_fabric_ops vhost_scsi_ops = {
.fabric_drop_np = NULL,
.fabric_make_nodeacl = vhost_scsi_make_nodeacl,
.fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
};
static int vhost_scsi_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
pr_debug("vhost-scsi fabric module %s on %s/%s"
" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
/*
* Register the top level struct config_item_type with TCM core
*/
fabric = target_fabric_configfs_init(THIS_MODULE, "vhost");
if (IS_ERR(fabric)) {
pr_err("target_fabric_configfs_init() failed\n");
return PTR_ERR(fabric);
}
/*
* Setup fabric->tf_ops from our local vhost_scsi_ops
*/
fabric->tf_ops = vhost_scsi_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
/*
* Register the fabric for use within TCM
*/
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
pr_err("target_fabric_configfs_register() failed"
" for TCM_VHOST\n");
return ret;
}
/*
* Setup our local pointer to *fabric
*/
vhost_scsi_fabric_configfs = fabric;
pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n");
return 0;
};
static void vhost_scsi_deregister_configfs(void)
{
if (!vhost_scsi_fabric_configfs)
return;
target_fabric_configfs_deregister(vhost_scsi_fabric_configfs);
vhost_scsi_fabric_configfs = NULL;
pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n");
.tfc_wwn_attrs = vhost_scsi_wwn_attrs,
.tfc_tpg_base_attrs = vhost_scsi_tpg_attrs,
.tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs,
};
static int __init vhost_scsi_init(void)
{
int ret = -ENOMEM;
pr_debug("TCM_VHOST fabric module %s on %s/%s"
" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
/*
* Use our own dedicated workqueue for submitting I/O into
* target core to avoid contention within system_wq.
@ -2396,7 +2396,7 @@ static int __init vhost_scsi_init(void)
if (ret < 0)
goto out_destroy_workqueue;
ret = vhost_scsi_register_configfs();
ret = target_register_template(&vhost_scsi_ops);
if (ret < 0)
goto out_vhost_scsi_deregister;
@ -2412,7 +2412,7 @@ static int __init vhost_scsi_init(void)
static void vhost_scsi_exit(void)
{
vhost_scsi_deregister_configfs();
target_unregister_template(&vhost_scsi_ops);
vhost_scsi_deregister();
destroy_workqueue(vhost_scsi_workqueue);
};

View File

@ -204,8 +204,7 @@ static LIST_HEAD(scsiback_free_pages);
static DEFINE_MUTEX(scsiback_mutex);
static LIST_HEAD(scsiback_list);
/* Local pointer to allocated TCM configfs fabric module */
static struct target_fabric_configfs *scsiback_fabric_configfs;
static const struct target_core_fabric_ops scsiback_ops;
static void scsiback_get(struct vscsibk_info *info)
{
@ -1902,7 +1901,7 @@ scsiback_make_tpg(struct se_wwn *wwn,
tpg->tport = tport;
tpg->tport_tpgt = tpgt;
ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn,
ret = core_tpg_register(&scsiback_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
@ -1944,7 +1943,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg)
return 0;
}
static struct target_core_fabric_ops scsiback_ops = {
static const struct target_core_fabric_ops scsiback_ops = {
.module = THIS_MODULE,
.name = "xen-pvscsi",
.get_fabric_name = scsiback_get_fabric_name,
.get_fabric_proto_ident = scsiback_get_fabric_proto_ident,
.tpg_get_wwn = scsiback_get_fabric_wwn,
@ -1991,62 +1992,10 @@ static struct target_core_fabric_ops scsiback_ops = {
.fabric_make_nodeacl = scsiback_make_nodeacl,
.fabric_drop_nodeacl = scsiback_drop_nodeacl,
#endif
};
static int scsiback_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
pr_debug("fabric module %s on %s/%s on "UTS_RELEASE"\n",
VSCSI_VERSION, utsname()->sysname, utsname()->machine);
/*
* Register the top level struct config_item_type with TCM core
*/
fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi");
if (IS_ERR(fabric))
return PTR_ERR(fabric);
/*
* Setup fabric->tf_ops from our local scsiback_ops
*/
fabric->tf_ops = scsiback_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs;
fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
/*
* Register the fabric for use within TCM
*/
ret = target_fabric_configfs_register(fabric);
if (ret < 0) {
target_fabric_configfs_free(fabric);
return ret;
}
/*
* Setup our local pointer to *fabric
*/
scsiback_fabric_configfs = fabric;
pr_debug("Set fabric -> scsiback_fabric_configfs\n");
return 0;
};
static void scsiback_deregister_configfs(void)
{
if (!scsiback_fabric_configfs)
return;
target_fabric_configfs_deregister(scsiback_fabric_configfs);
scsiback_fabric_configfs = NULL;
pr_debug("Cleared scsiback_fabric_configfs\n");
.tfc_wwn_attrs = scsiback_wwn_attrs,
.tfc_tpg_base_attrs = scsiback_tpg_attrs,
.tfc_tpg_param_attrs = scsiback_param_attrs,
};
static const struct xenbus_device_id scsiback_ids[] = {
@ -2078,6 +2027,9 @@ static int __init scsiback_init(void)
if (!xen_domain())
return -ENODEV;
pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n",
VSCSI_VERSION, utsname()->sysname, utsname()->machine);
scsiback_cachep = kmem_cache_create("vscsiif_cache",
sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
if (!scsiback_cachep)
@ -2087,7 +2039,7 @@ static int __init scsiback_init(void)
if (ret)
goto out_cache_destroy;
ret = scsiback_register_configfs();
ret = target_register_template(&scsiback_ops);
if (ret)
goto out_unregister_xenbus;
@ -2110,7 +2062,7 @@ static void __exit scsiback_exit(void)
BUG();
gnttab_free_pages(1, &page);
}
scsiback_deregister_configfs();
target_unregister_template(&scsiback_ops);
xenbus_unregister_driver(&scsiback_driver);
kmem_cache_destroy(scsiback_cachep);
}

View File

@ -20,6 +20,8 @@
#define ISCSIT_MIN_TAGS 16
#define ISCSIT_EXTRA_TAGS 8
#define ISCSIT_TCP_BACKLOG 256
#define ISCSI_RX_THREAD_NAME "iscsi_trx"
#define ISCSI_TX_THREAD_NAME "iscsi_ttx"
/* struct iscsi_node_attrib sanity values */
#define NA_DATAOUT_TIMEOUT 3
@ -60,6 +62,7 @@
#define TA_CACHE_CORE_NPS 0
/* T10 protection information disabled by default */
#define TA_DEFAULT_T10_PI 0
#define TA_DEFAULT_FABRIC_PROT_TYPE 0
#define ISCSI_IOV_DATA_BUFFER 5
@ -600,8 +603,11 @@ struct iscsi_conn {
struct iscsi_tpg_np *tpg_np;
/* Pointer to parent session */
struct iscsi_session *sess;
/* Pointer to thread_set in use for this conn's threads */
struct iscsi_thread_set *thread_set;
int bitmap_id;
int rx_thread_active;
struct task_struct *rx_thread;
int tx_thread_active;
struct task_struct *tx_thread;
/* list_head for session connection list */
struct list_head conn_list;
} ____cacheline_aligned;
@ -767,6 +773,7 @@ struct iscsi_tpg_attrib {
u32 demo_mode_discovery;
u32 default_erl;
u8 t10_pi;
u32 fabric_prot_type;
struct iscsi_portal_group *tpg;
};
@ -871,10 +878,10 @@ struct iscsit_global {
/* Unique identifier used for the authentication daemon */
u32 auth_id;
u32 inactive_ts;
/* Thread Set bitmap count */
int ts_bitmap_count;
#define ISCSIT_BITMAP_BITS 262144
/* Thread Set bitmap pointer */
unsigned long *ts_bitmap;
spinlock_t ts_bitmap_lock;
/* Used for iSCSI discovery session authentication */
struct iscsi_node_acl discovery_acl;
struct iscsi_portal_group *discovery_tpg;

View File

@ -165,10 +165,8 @@ enum se_cmd_flags_table {
SCF_SEND_DELAYED_TAS = 0x00004000,
SCF_ALUA_NON_OPTIMIZED = 0x00008000,
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
SCF_ACK_KREF = 0x00040000,
SCF_COMPARE_AND_WRITE = 0x00080000,
SCF_COMPARE_AND_WRITE_POST = 0x00100000,
SCF_CMD_XCOPY_PASSTHROUGH = 0x00200000,
};
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@ -520,11 +518,11 @@ struct se_cmd {
struct list_head se_cmd_list;
struct completion cmd_wait_comp;
struct kref cmd_kref;
struct target_core_fabric_ops *se_tfo;
const struct target_core_fabric_ops *se_tfo;
sense_reason_t (*execute_cmd)(struct se_cmd *);
sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *,
u32, enum dma_data_direction);
sense_reason_t (*transport_complete_callback)(struct se_cmd *);
sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool);
unsigned char *t_task_cdb;
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
@ -591,6 +589,7 @@ struct se_node_acl {
bool acl_stop:1;
u32 queue_depth;
u32 acl_index;
enum target_prot_type saved_prot_type;
#define MAX_ACL_TAG_SIZE 64
char acl_tag[MAX_ACL_TAG_SIZE];
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
@ -616,6 +615,7 @@ struct se_session {
unsigned sess_tearing_down:1;
u64 sess_bin_isid;
enum target_prot_op sup_prot_ops;
enum target_prot_type sess_prot_type;
struct se_node_acl *se_node_acl;
struct se_portal_group *se_tpg;
void *fabric_sess_ptr;
@ -890,7 +890,7 @@ struct se_portal_group {
/* List of TCM sessions associated wth this TPG */
struct list_head tpg_sess_list;
/* Pointer to $FABRIC_MOD dependent code */
struct target_core_fabric_ops *se_tpg_tfo;
const struct target_core_fabric_ops *se_tpg_tfo;
struct se_wwn *se_tpg_wwn;
struct config_group tpg_group;
struct config_group *tpg_default_groups[7];

View File

@ -5,12 +5,6 @@
#define TARGET_CORE_NAME_MAX_LEN 64
#define TARGET_FABRIC_NAME_SIZE 32
extern struct target_fabric_configfs *target_fabric_configfs_init(
struct module *, const char *);
extern void target_fabric_configfs_free(struct target_fabric_configfs *);
extern int target_fabric_configfs_register(struct target_fabric_configfs *);
extern void target_fabric_configfs_deregister(struct target_fabric_configfs *);
struct target_fabric_configfs_template {
struct config_item_type tfc_discovery_cit;
struct config_item_type tfc_wwn_cit;

View File

@ -2,6 +2,8 @@
#define TARGET_CORE_FABRIC_H
struct target_core_fabric_ops {
struct module *module;
const char *name;
struct configfs_subsystem *tf_subsys;
char *(*get_fabric_name)(void);
u8 (*get_fabric_proto_ident)(struct se_portal_group *);
@ -27,6 +29,14 @@ struct target_core_fabric_ops {
* inquiry response
*/
int (*tpg_check_demo_mode_login_only)(struct se_portal_group *);
/*
* Optionally used as a configfs tunable to determine when
* target-core should signal the PROTECT=1 feature bit for
* backends that don't support T10-PI, so that either fabric
* HW offload or target-core emulation performs the associated
* WRITE_STRIP and READ_INSERT operations.
*/
int (*tpg_check_prot_fabric_only)(struct se_portal_group *);
struct se_node_acl *(*tpg_alloc_fabric_acl)(
struct se_portal_group *);
void (*tpg_release_fabric_acl)(struct se_portal_group *,
@ -82,8 +92,23 @@ struct target_core_fabric_ops {
struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *,
struct config_group *, const char *);
void (*fabric_drop_nodeacl)(struct se_node_acl *);
struct configfs_attribute **tfc_discovery_attrs;
struct configfs_attribute **tfc_wwn_attrs;
struct configfs_attribute **tfc_tpg_base_attrs;
struct configfs_attribute **tfc_tpg_np_base_attrs;
struct configfs_attribute **tfc_tpg_attrib_attrs;
struct configfs_attribute **tfc_tpg_auth_attrs;
struct configfs_attribute **tfc_tpg_param_attrs;
struct configfs_attribute **tfc_tpg_nacl_base_attrs;
struct configfs_attribute **tfc_tpg_nacl_attrib_attrs;
struct configfs_attribute **tfc_tpg_nacl_auth_attrs;
struct configfs_attribute **tfc_tpg_nacl_param_attrs;
};
int target_register_template(const struct target_core_fabric_ops *fo);
void target_unregister_template(const struct target_core_fabric_ops *fo);
struct se_session *transport_init_session(enum target_prot_op);
int transport_alloc_session_tags(struct se_session *, unsigned int,
unsigned int);
@ -95,13 +120,15 @@ void transport_register_session(struct se_portal_group *,
struct se_node_acl *, struct se_session *, void *);
void target_get_session(struct se_session *);
void target_put_session(struct se_session *);
ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *);
void transport_free_session(struct se_session *);
void target_put_nacl(struct se_node_acl *);
void transport_deregister_session_configfs(struct se_session *);
void transport_deregister_session(struct se_session *);
void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
void transport_init_se_cmd(struct se_cmd *,
const struct target_core_fabric_ops *,
struct se_session *, u32, int, int, unsigned char *);
sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
@ -153,8 +180,8 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
unsigned char *, u32, int);
int core_tpg_set_initiator_node_tag(struct se_portal_group *,
struct se_node_acl *, const char *);
int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *,
struct se_portal_group *, void *, int);
int core_tpg_register(const struct target_core_fabric_ops *,
struct se_wwn *, struct se_portal_group *, void *, int);
int core_tpg_deregister(struct se_portal_group *);
/* SAS helpers */

View File

@ -90,6 +90,11 @@ static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
_fabric##_tpg_store_##_name);
#define TF_TPG_BASE_ATTR_RO(_fabric, _name) \
static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
__CONFIGFS_EATTR_RO(_name, \
_fabric##_tpg_show_##_name);
CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs);
#define TF_WWN_ATTR(_fabric, _name, _mode) \
static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \

View File

@ -6,7 +6,7 @@
#include <linux/types.h>
#include <linux/uio.h>
#define TCMU_VERSION "1.0"
#define TCMU_VERSION "2.0"
/*
* Ring Design
@ -39,9 +39,13 @@
* should process the next packet the same way, and so on.
*/
#define TCMU_MAILBOX_VERSION 1
#define TCMU_MAILBOX_VERSION 2
#define ALIGN_SIZE 64 /* Should be enough for most CPUs */
/* See https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */
#define xstr(s) str(s)
#define str(s) #s
struct tcmu_mailbox {
__u16 version;
__u16 flags;
@ -64,31 +68,36 @@ enum tcmu_opcode {
* Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode.
*/
struct tcmu_cmd_entry_hdr {
__u32 len_op;
__u32 len_op;
__u16 cmd_id;
__u8 kflags;
#define TCMU_UFLAG_UNKNOWN_OP 0x1
__u8 uflags;
} __packed;
#define TCMU_OP_MASK 0x7
static inline enum tcmu_opcode tcmu_hdr_get_op(struct tcmu_cmd_entry_hdr *hdr)
static inline enum tcmu_opcode tcmu_hdr_get_op(__u32 len_op)
{
return hdr->len_op & TCMU_OP_MASK;
return len_op & TCMU_OP_MASK;
}
static inline void tcmu_hdr_set_op(struct tcmu_cmd_entry_hdr *hdr, enum tcmu_opcode op)
static inline void tcmu_hdr_set_op(__u32 *len_op, enum tcmu_opcode op)
{
hdr->len_op &= ~TCMU_OP_MASK;
hdr->len_op |= (op & TCMU_OP_MASK);
*len_op &= ~TCMU_OP_MASK;
*len_op |= (op & TCMU_OP_MASK);
}
static inline __u32 tcmu_hdr_get_len(struct tcmu_cmd_entry_hdr *hdr)
static inline __u32 tcmu_hdr_get_len(__u32 len_op)
{
return hdr->len_op & ~TCMU_OP_MASK;
return len_op & ~TCMU_OP_MASK;
}
static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len)
static inline void tcmu_hdr_set_len(__u32 *len_op, __u32 len)
{
hdr->len_op &= TCMU_OP_MASK;
hdr->len_op |= len;
*len_op &= TCMU_OP_MASK;
*len_op |= len;
}
/* Currently the same as SCSI_SENSE_BUFFERSIZE */
@ -97,13 +106,14 @@ static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len)
struct tcmu_cmd_entry {
struct tcmu_cmd_entry_hdr hdr;
uint16_t cmd_id;
uint16_t __pad1;
union {
struct {
uint32_t iov_cnt;
uint32_t iov_bidi_cnt;
uint32_t iov_dif_cnt;
uint64_t cdb_off;
uint64_t iov_cnt;
uint64_t __pad1;
uint64_t __pad2;
struct iovec iov[0];
} req;
struct {