diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2023-03-16 23:41:00 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2023-03-16 23:41:00 -0400 |
commit | c5797fda210fc852f876f0660e959b5e9db604d8 (patch) | |
tree | e97e2e4e94345990e174dae9ab6e76611b852454 /drivers/target | |
parent | e943e97ca9b94fc7d222465c48598dd417b599d8 (diff) | |
parent | 075a5d356103b32bc7023b03ede60a2f183bcfb3 (diff) |
Merge patch series "add virtual remote fabric"
Dmitry Bogdanov <d.bogdanov@yadro.com> says:
The patchset is based on 6.4/scsi-staging branch.
The first 11 patches are just a refactoring to reduce code duplication
in fabric drivers. They make several callouts be optional in fabric
ops. Make a default implementation of the optional ops and remove
such implementations in the fabric drivers.
The last patch is a new virtual remote fabric driver. It has a
valueble sence with patchset "scsi: target: make RTPI an TPG
identifier" to configure RPTI on remote/tpgt_x same as on tpgt_y on
other nodes in a storage cluster. That allows to report the same ports
in RTPG from each node and to have a clusterwide tpg/acl/lun view in
kernel.
Link: https://lore.kernel.org/r/20230313181110.20566-1-d.bogdanov@yadro.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/Kconfig | 1 | ||||
-rw-r--r-- | drivers/target/Makefile | 1 | ||||
-rw-r--r-- | drivers/target/loopback/tcm_loop.c | 41 | ||||
-rw-r--r-- | drivers/target/sbp/sbp_target.c | 31 | ||||
-rw-r--r-- | drivers/target/target_core_configfs.c | 94 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 1 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 5 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_conf.c | 15 | ||||
-rw-r--r-- | drivers/target/tcm_remote/Kconfig | 8 | ||||
-rw-r--r-- | drivers/target/tcm_remote/Makefile | 2 | ||||
-rw-r--r-- | drivers/target/tcm_remote/tcm_remote.c | 268 | ||||
-rw-r--r-- | drivers/target/tcm_remote/tcm_remote.h | 20 |
12 files changed, 361 insertions, 126 deletions
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 72171ea3dd53..92641d39126a 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -47,5 +47,6 @@ source "drivers/target/loopback/Kconfig" source "drivers/target/tcm_fc/Kconfig" source "drivers/target/iscsi/Kconfig" source "drivers/target/sbp/Kconfig" +source "drivers/target/tcm_remote/Kconfig" endif diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 45634747377e..431b84abfb94 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ obj-$(CONFIG_TCM_FC) += tcm_fc/ obj-$(CONFIG_ISCSI_TARGET) += iscsi/ obj-$(CONFIG_SBP_TARGET) += sbp/ +obj-$(CONFIG_REMOTE_TARGET) += tcm_remote/ diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 139031ccb700..5c8646c2d4e9 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -480,30 +480,6 @@ static int tcm_loop_check_demo_mode(struct se_portal_group *se_tpg) return 1; } -static int tcm_loop_check_demo_mode_cache(struct se_portal_group *se_tpg) -{ - return 0; -} - -/* - * Allow I_T Nexus full READ-WRITE access without explict Initiator Node ACLs for - * local virtual Linux/SCSI LLD passthrough into VM hypervisor guest - */ -static int tcm_loop_check_demo_mode_write_protect(struct se_portal_group *se_tpg) -{ - return 0; -} - -/* - * Because TCM_Loop does not use explict ACLs and MappedLUNs, this will - * never be called for TCM_Loop by target_core_fabric_configfs.c code. - * It has been added here as a nop for target_fabric_tf_ops_check() - */ -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, @@ -511,21 +487,11 @@ static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg) return tl_tpg->tl_fabric_prot_type; } -static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 tcm_loop_sess_get_index(struct se_session *se_sess) { return 1; } -static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) -{ - return; -} - static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) { struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, @@ -1124,18 +1090,11 @@ static const struct target_core_fabric_ops loop_ops = { .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, .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_get_inst_index = tcm_loop_get_inst_index, .check_stop_free = tcm_loop_check_stop_free, .release_cmd = tcm_loop_release_cmd, .sess_get_index = tcm_loop_sess_get_index, .write_pending = tcm_loop_write_pending, - .set_default_node_attributes = tcm_loop_set_default_node_attributes, .get_cmd_state = tcm_loop_get_cmd_state, .queue_data_in = tcm_loop_queue_data_in, .queue_status = tcm_loop_queue_status, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 504670994fb4..2a761bc09193 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1673,11 +1673,6 @@ static int sbp_check_true(struct se_portal_group *se_tpg) return 1; } -static int sbp_check_false(struct se_portal_group *se_tpg) -{ - return 0; -} - static char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg) { struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); @@ -1692,11 +1687,6 @@ static u16 sbp_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg) -{ - return 1; -} - static void sbp_release_cmd(struct se_cmd *se_cmd) { struct sbp_target_request *req = container_of(se_cmd, @@ -1705,11 +1695,6 @@ static void sbp_release_cmd(struct se_cmd *se_cmd) sbp_free_request(req); } -static u32 sbp_sess_get_index(struct se_session *se_sess) -{ - return 0; -} - static int sbp_write_pending(struct se_cmd *se_cmd) { struct sbp_target_request *req = container_of(se_cmd, @@ -1733,16 +1718,6 @@ static int sbp_write_pending(struct se_cmd *se_cmd) return 0; } -static void sbp_set_default_node_attrs(struct se_node_acl *nacl) -{ - return; -} - -static int sbp_get_cmd_state(struct se_cmd *se_cmd) -{ - return 0; -} - static int sbp_queue_data_in(struct se_cmd *se_cmd) { struct sbp_target_request *req = container_of(se_cmd, @@ -2281,14 +2256,8 @@ static const struct target_core_fabric_ops sbp_ops = { .tpg_get_tag = sbp_get_tag, .tpg_check_demo_mode = sbp_check_true, .tpg_check_demo_mode_cache = sbp_check_true, - .tpg_check_demo_mode_write_protect = sbp_check_false, - .tpg_check_prod_mode_write_protect = sbp_check_false, - .tpg_get_inst_index = sbp_tpg_get_inst_index, .release_cmd = sbp_release_cmd, - .sess_get_index = sbp_sess_get_index, .write_pending = sbp_write_pending, - .set_default_node_attributes = sbp_set_default_node_attrs, - .get_cmd_state = sbp_get_cmd_state, .queue_data_in = sbp_queue_data_in, .queue_status = sbp_queue_status, .queue_tm_rsp = sbp_queue_tm_rsp, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 611b0424e305..74b67c346dfe 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -335,6 +335,29 @@ EXPORT_SYMBOL(target_undepend_item); /*############################################################################## // Start functions called by external Target Fabrics Modules //############################################################################*/ +static int target_disable_feature(struct se_portal_group *se_tpg) +{ + return 0; +} + +static u32 target_default_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} + +static u32 target_default_sess_get_index(struct se_session *se_sess) +{ + return 0; +} + +static void target_set_default_node_attributes(struct se_node_acl *se_acl) +{ +} + +static int target_default_get_cmd_state(struct se_cmd *se_cmd) +{ + return 0; +} static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) { @@ -362,46 +385,14 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_get_tag()\n"); return -EINVAL; } - if (!tfo->tpg_check_demo_mode) { - pr_err("Missing tfo->tpg_check_demo_mode()\n"); - return -EINVAL; - } - if (!tfo->tpg_check_demo_mode_cache) { - pr_err("Missing tfo->tpg_check_demo_mode_cache()\n"); - return -EINVAL; - } - if (!tfo->tpg_check_demo_mode_write_protect) { - pr_err("Missing tfo->tpg_check_demo_mode_write_protect()\n"); - return -EINVAL; - } - if (!tfo->tpg_check_prod_mode_write_protect) { - pr_err("Missing tfo->tpg_check_prod_mode_write_protect()\n"); - return -EINVAL; - } - if (!tfo->tpg_get_inst_index) { - pr_err("Missing tfo->tpg_get_inst_index()\n"); - return -EINVAL; - } if (!tfo->release_cmd) { pr_err("Missing tfo->release_cmd()\n"); return -EINVAL; } - if (!tfo->sess_get_index) { - pr_err("Missing tfo->sess_get_index()\n"); - return -EINVAL; - } if (!tfo->write_pending) { pr_err("Missing tfo->write_pending()\n"); return -EINVAL; } - if (!tfo->set_default_node_attributes) { - pr_err("Missing tfo->set_default_node_attributes()\n"); - return -EINVAL; - } - if (!tfo->get_cmd_state) { - pr_err("Missing tfo->get_cmd_state()\n"); - return -EINVAL; - } if (!tfo->queue_data_in) { pr_err("Missing tfo->queue_data_in()\n"); return -EINVAL; @@ -447,8 +438,36 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) return 0; } +static void target_set_default_ops(struct target_core_fabric_ops *tfo) +{ + if (!tfo->tpg_check_demo_mode) + tfo->tpg_check_demo_mode = target_disable_feature; + + if (!tfo->tpg_check_demo_mode_cache) + tfo->tpg_check_demo_mode_cache = target_disable_feature; + + if (!tfo->tpg_check_demo_mode_write_protect) + tfo->tpg_check_demo_mode_write_protect = target_disable_feature; + + if (!tfo->tpg_check_prod_mode_write_protect) + tfo->tpg_check_prod_mode_write_protect = target_disable_feature; + + if (!tfo->tpg_get_inst_index) + tfo->tpg_get_inst_index = target_default_get_inst_index; + + if (!tfo->sess_get_index) + tfo->sess_get_index = target_default_sess_get_index; + + if (!tfo->set_default_node_attributes) + tfo->set_default_node_attributes = target_set_default_node_attributes; + + if (!tfo->get_cmd_state) + tfo->get_cmd_state = target_default_get_cmd_state; +} + int target_register_template(const struct target_core_fabric_ops *fo) { + struct target_core_fabric_ops *tfo; struct target_fabric_configfs *tf; int ret; @@ -461,10 +480,18 @@ int target_register_template(const struct target_core_fabric_ops *fo) pr_err("%s: could not allocate memory!\n", __func__); return -ENOMEM; } + tfo = kzalloc(sizeof(struct target_core_fabric_ops), GFP_KERNEL); + if (!tfo) { + kfree(tf); + pr_err("%s: could not allocate memory!\n", __func__); + return -ENOMEM; + } + memcpy(tfo, fo, sizeof(*tfo)); + target_set_default_ops(tfo); INIT_LIST_HEAD(&tf->tf_list); atomic_set(&tf->tf_access_cnt, 0); - tf->tf_ops = fo; + tf->tf_ops = tfo; target_fabric_setup_cits(tf); mutex_lock(&g_tf_lock); @@ -492,6 +519,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo) */ rcu_barrier(); kfree(t->tf_tpg_base_cit.ct_attrs); + kfree(t->tf_ops); kfree(t); return; } diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 2ff716d8cbdd..00e5573c6296 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -146,7 +146,6 @@ void ft_release_cmd(struct se_cmd *); int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); int ft_write_pending(struct se_cmd *); -int ft_get_cmd_state(struct se_cmd *); void ft_queue_tm_resp(struct se_cmd *); void ft_aborted_task(struct se_cmd *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 410b723f9d79..21783cd71c15 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -223,11 +223,6 @@ int ft_write_pending(struct se_cmd *se_cmd) return 0; } -int ft_get_cmd_state(struct se_cmd *se_cmd) -{ - return 0; -} - /* * FC sequence response handler for follow-on sequences (data) and aborts. */ diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 1a38c98f681b..6ac3fc1a7d39 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -398,15 +398,6 @@ static u16 ft_get_tag(struct se_portal_group *se_tpg) return ft_tpg(se_tpg)->index; } -static int ft_check_false(struct se_portal_group *se_tpg) -{ - return 0; -} - -static void ft_set_default_node_attr(struct se_node_acl *se_nacl) -{ -} - static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) { return ft_tpg(se_tpg)->index; @@ -418,10 +409,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .node_acl_size = sizeof(struct ft_node_acl), .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, - .tpg_check_demo_mode = ft_check_false, - .tpg_check_demo_mode_cache = ft_check_false, - .tpg_check_demo_mode_write_protect = ft_check_false, - .tpg_check_prod_mode_write_protect = ft_check_false, .tpg_get_inst_index = ft_tpg_get_inst_index, .check_stop_free = ft_check_stop_free, .release_cmd = ft_release_cmd, @@ -429,8 +416,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .sess_get_index = ft_sess_get_index, .sess_get_initiator_sid = NULL, .write_pending = ft_write_pending, - .set_default_node_attributes = ft_set_default_node_attr, - .get_cmd_state = ft_get_cmd_state, .queue_data_in = ft_queue_data_in, .queue_status = ft_queue_status, .queue_tm_rsp = ft_queue_tm_resp, diff --git a/drivers/target/tcm_remote/Kconfig b/drivers/target/tcm_remote/Kconfig new file mode 100644 index 000000000000..e6bebb5fe6f1 --- /dev/null +++ b/drivers/target/tcm_remote/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +config REMOTE_TARGET + tristate "TCM Virtual Remote target" + depends on SCSI + help + Say Y here to enable the TCM Virtual Remote fabric + That fabric is a dummy fabric to tell TCM about configuration + of TPG/ACL/LUN on peer nodes in a cluster. diff --git a/drivers/target/tcm_remote/Makefile b/drivers/target/tcm_remote/Makefile new file mode 100644 index 000000000000..5818ffd0b0fa --- /dev/null +++ b/drivers/target/tcm_remote/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_REMOTE_TARGET) += tcm_remote.o diff --git a/drivers/target/tcm_remote/tcm_remote.c b/drivers/target/tcm_remote/tcm_remote.c new file mode 100644 index 000000000000..cb8db2558056 --- /dev/null +++ b/drivers/target/tcm_remote/tcm_remote.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/configfs.h> +#include <scsi/scsi.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_cmnd.h> + +#include <target/target_core_base.h> +#include <target/target_core_fabric.h> + +#include "tcm_remote.h" + +static inline struct tcm_remote_tpg *remote_tpg(struct se_portal_group *se_tpg) +{ + return container_of(se_tpg, struct tcm_remote_tpg, remote_se_tpg); +} + +static char *tcm_remote_get_endpoint_wwn(struct se_portal_group *se_tpg) +{ + /* + * Return the passed NAA identifier for the Target Port + */ + return &remote_tpg(se_tpg)->remote_hba->remote_wwn_address[0]; +} + +static u16 tcm_remote_get_tag(struct se_portal_group *se_tpg) +{ + /* + * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 + * to represent the SCSI Target Port. + */ + return remote_tpg(se_tpg)->remote_tpgt; +} + +static int tcm_remote_dummy_cmd_fn(struct se_cmd *se_cmd) +{ + return 0; +} + +static void tcm_remote_dummy_cmd_void_fn(struct se_cmd *se_cmd) +{ + +} + +static char *tcm_remote_dump_proto_id(struct tcm_remote_hba *remote_hba) +{ + switch (remote_hba->remote_proto_id) { + case SCSI_PROTOCOL_SAS: + return "SAS"; + case SCSI_PROTOCOL_SRP: + return "SRP"; + case SCSI_PROTOCOL_FCP: + return "FCP"; + case SCSI_PROTOCOL_ISCSI: + return "iSCSI"; + default: + break; + } + + return "Unknown"; +} + +static int tcm_remote_port_link( + struct se_portal_group *se_tpg, + struct se_lun *lun) +{ + pr_debug("TCM_Remote_ConfigFS: Port Link LUN %lld Successful\n", + lun->unpacked_lun); + return 0; +} + +static void tcm_remote_port_unlink( + struct se_portal_group *se_tpg, + struct se_lun *lun) +{ + pr_debug("TCM_Remote_ConfigFS: Port Unlink LUN %lld Successful\n", + lun->unpacked_lun); +} + +static struct se_portal_group *tcm_remote_make_tpg( + struct se_wwn *wwn, + const char *name) +{ + struct tcm_remote_hba *remote_hba = container_of(wwn, + struct tcm_remote_hba, remote_hba_wwn); + struct tcm_remote_tpg *remote_tpg; + unsigned long tpgt; + int ret; + + if (strstr(name, "tpgt_") != name) { + pr_err("Unable to locate \"tpgt_#\" directory group\n"); + return ERR_PTR(-EINVAL); + } + if (kstrtoul(name + 5, 10, &tpgt)) + return ERR_PTR(-EINVAL); + + if (tpgt >= 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); + } + remote_tpg = &remote_hba->remote_hba_tpgs[tpgt]; + remote_tpg->remote_hba = remote_hba; + remote_tpg->remote_tpgt = tpgt; + /* + * Register the remote_tpg as a emulated TCM Target Endpoint + */ + ret = core_tpg_register(wwn, &remote_tpg->remote_se_tpg, + remote_hba->remote_proto_id); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + pr_debug("TCM_Remote_ConfigFS: Allocated Emulated %s Target Port %s,t,0x%04lx\n", + tcm_remote_dump_proto_id(remote_hba), + config_item_name(&wwn->wwn_group.cg_item), tpgt); + return &remote_tpg->remote_se_tpg; +} + +static void tcm_remote_drop_tpg(struct se_portal_group *se_tpg) +{ + struct se_wwn *wwn = se_tpg->se_tpg_wwn; + struct tcm_remote_tpg *remote_tpg = container_of(se_tpg, + struct tcm_remote_tpg, remote_se_tpg); + struct tcm_remote_hba *remote_hba; + unsigned short tpgt; + + remote_hba = remote_tpg->remote_hba; + tpgt = remote_tpg->remote_tpgt; + + /* + * Deregister the remote_tpg as a emulated TCM Target Endpoint + */ + core_tpg_deregister(se_tpg); + + remote_tpg->remote_hba = NULL; + remote_tpg->remote_tpgt = 0; + + pr_debug("TCM_Remote_ConfigFS: Deallocated Emulated %s Target Port %s,t,0x%04x\n", + tcm_remote_dump_proto_id(remote_hba), + config_item_name(&wwn->wwn_group.cg_item), tpgt); +} + +static struct se_wwn *tcm_remote_make_wwn( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct tcm_remote_hba *remote_hba; + char *ptr; + int ret, off = 0; + + remote_hba = kzalloc(sizeof(*remote_hba), GFP_KERNEL); + if (!remote_hba) + return ERR_PTR(-ENOMEM); + + /* + * Determine the emulated Protocol Identifier and Target Port Name + * based on the incoming configfs directory name. + */ + ptr = strstr(name, "naa."); + if (ptr) { + remote_hba->remote_proto_id = SCSI_PROTOCOL_SAS; + goto check_len; + } + ptr = strstr(name, "fc."); + if (ptr) { + remote_hba->remote_proto_id = SCSI_PROTOCOL_FCP; + off = 3; /* Skip over "fc." */ + goto check_len; + } + ptr = strstr(name, "0x"); + if (ptr) { + remote_hba->remote_proto_id = SCSI_PROTOCOL_SRP; + off = 2; /* Skip over "0x" */ + goto check_len; + } + ptr = strstr(name, "iqn."); + if (!ptr) { + pr_err("Unable to locate prefix for emulated Target Port: %s\n", + name); + ret = -EINVAL; + goto out; + } + remote_hba->remote_proto_id = SCSI_PROTOCOL_ISCSI; + +check_len: + if (strlen(name) >= TL_WWN_ADDR_LEN) { + pr_err("Emulated NAA %s Address: %s, exceeds max: %d\n", + name, tcm_remote_dump_proto_id(remote_hba), TL_WWN_ADDR_LEN); + ret = -EINVAL; + goto out; + } + snprintf(&remote_hba->remote_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); + + pr_debug("TCM_Remote_ConfigFS: Allocated emulated Target %s Address: %s\n", + tcm_remote_dump_proto_id(remote_hba), name); + return &remote_hba->remote_hba_wwn; +out: + kfree(remote_hba); + return ERR_PTR(ret); +} + +static void tcm_remote_drop_wwn(struct se_wwn *wwn) +{ + struct tcm_remote_hba *remote_hba = container_of(wwn, + struct tcm_remote_hba, remote_hba_wwn); + + pr_debug("TCM_Remote_ConfigFS: Deallocating emulated Target %s Address: %s\n", + tcm_remote_dump_proto_id(remote_hba), + remote_hba->remote_wwn_address); + kfree(remote_hba); +} + +static ssize_t tcm_remote_wwn_version_show(struct config_item *item, char *page) +{ + return sprintf(page, "TCM Remote Fabric module %s\n", TCM_REMOTE_VERSION); +} + +CONFIGFS_ATTR_RO(tcm_remote_wwn_, version); + +static struct configfs_attribute *tcm_remote_wwn_attrs[] = { + &tcm_remote_wwn_attr_version, + NULL, +}; + +static const struct target_core_fabric_ops remote_ops = { + .module = THIS_MODULE, + .fabric_name = "remote", + .tpg_get_wwn = tcm_remote_get_endpoint_wwn, + .tpg_get_tag = tcm_remote_get_tag, + .check_stop_free = tcm_remote_dummy_cmd_fn, + .release_cmd = tcm_remote_dummy_cmd_void_fn, + .write_pending = tcm_remote_dummy_cmd_fn, + .queue_data_in = tcm_remote_dummy_cmd_fn, + .queue_status = tcm_remote_dummy_cmd_fn, + .queue_tm_rsp = tcm_remote_dummy_cmd_void_fn, + .aborted_task = tcm_remote_dummy_cmd_void_fn, + .fabric_make_wwn = tcm_remote_make_wwn, + .fabric_drop_wwn = tcm_remote_drop_wwn, + .fabric_make_tpg = tcm_remote_make_tpg, + .fabric_drop_tpg = tcm_remote_drop_tpg, + .fabric_post_link = tcm_remote_port_link, + .fabric_pre_unlink = tcm_remote_port_unlink, + .tfc_wwn_attrs = tcm_remote_wwn_attrs, +}; + +static int __init tcm_remote_fabric_init(void) +{ + return target_register_template(&remote_ops); +} + +static void __exit tcm_remote_fabric_exit(void) +{ + target_unregister_template(&remote_ops); +} + +MODULE_DESCRIPTION("TCM virtual remote target"); +MODULE_AUTHOR("Dmitry Bogdanov <d.bogdanov@yadro.com>"); +MODULE_LICENSE("GPL"); +module_init(tcm_remote_fabric_init); +module_exit(tcm_remote_fabric_exit); diff --git a/drivers/target/tcm_remote/tcm_remote.h b/drivers/target/tcm_remote/tcm_remote.h new file mode 100644 index 000000000000..913d1a6eb3a2 --- /dev/null +++ b/drivers/target/tcm_remote/tcm_remote.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/types.h> +#include <linux/device.h> + +#define TCM_REMOTE_VERSION "v0.1" +#define TL_WWN_ADDR_LEN 256 +#define TL_TPGS_PER_HBA 32 + +struct tcm_remote_tpg { + unsigned short remote_tpgt; + struct se_portal_group remote_se_tpg; + struct tcm_remote_hba *remote_hba; +}; + +struct tcm_remote_hba { + u8 remote_proto_id; + unsigned char remote_wwn_address[TL_WWN_ADDR_LEN]; + struct tcm_remote_tpg remote_hba_tpgs[TL_TPGS_PER_HBA]; + struct se_wwn remote_hba_wwn; +}; |