RELATIVE TARGET PORT IDENTIFIER can be read and configured via configfs: $ echo 0x10 > $TARGET/tpgt_N/rtpi RTPI can be changed only on disabled target ports. Signed-off-by: Roman Bolshakov <r.bolshakov@xxxxxxxxx> Signed-off-by: Dmitry Bogdanov <d.bogdanov@xxxxxxxxx> --- v5: fix casting from config_item to se_tpg v4: move rtpi file from tpgt_n/attrib to tpgt_n folder revert occasional rename of core_tpg_remove_lun v3: change core_ prefix to target_ v2: do not allow to change RTPI on enabled target port --- drivers/target/target_core_fabric_configfs.c | 39 +++++++++++++++++++- drivers/target/target_core_tpg.c | 19 ++++++++-- include/target/target_core_base.h | 1 + 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 873da49ab704..0ce47e21e0c8 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -844,15 +844,48 @@ static ssize_t target_fabric_tpg_base_enable_store(struct config_item *item, return ret; return count; } +static ssize_t target_fabric_tpg_base_rtpi_show(struct config_item *item, char *page) +{ + struct se_portal_group *se_tpg = to_tpg(item); + + return sysfs_emit(page, "%#x\n", se_tpg->tpg_rtpi); +} + +static ssize_t target_fabric_tpg_base_rtpi_store(struct config_item *item, + const char *page, size_t count) +{ + struct se_portal_group *se_tpg = to_tpg(item); + u16 val; + int ret; + + ret = kstrtou16(page, 0, &val); + if (ret < 0) + return ret; + if (val == 0) + return -EINVAL; + + if (se_tpg->enabled) { + pr_info("%s_TPG[%hu] - Can not change RTPI on enabled TPG", + se_tpg->se_tpg_tfo->fabric_name, + se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); + return -EINVAL; + } + + se_tpg->tpg_rtpi = val; + se_tpg->rtpi_manual = true; + + return count; +} CONFIGFS_ATTR(target_fabric_tpg_base_, enable); +CONFIGFS_ATTR(target_fabric_tpg_base_, rtpi); static int target_fabric_setup_tpg_base_cit(struct target_fabric_configfs *tf) { struct config_item_type *cit = &tf->tf_tpg_base_cit; struct configfs_attribute **attrs = NULL; - size_t nr_attrs = 0; + size_t nr_attrs = 1; int i = 0; if (tf->tf_ops->tfc_tpg_base_attrs) @@ -875,7 +908,9 @@ target_fabric_setup_tpg_base_cit(struct target_fabric_configfs *tf) attrs[i] = tf->tf_ops->tfc_tpg_base_attrs[i]; if (tf->tf_ops->fabric_enable_tpg) - attrs[i] = &target_fabric_tpg_base_attr_enable; + attrs[i++] = &target_fabric_tpg_base_attr_enable; + + attrs[i++] = &target_fabric_tpg_base_attr_rtpi; done: cit->ct_item_ops = &target_fabric_tpg_base_item_ops; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index b1d9383386ec..2e079c6a8e8c 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -445,10 +445,21 @@ static int target_tpg_register_rtpi(struct se_portal_group *se_tpg) u32 val; int ret; - ret = xa_alloc(&tpg_xa, &val, se_tpg, - XA_LIMIT(1, USHRT_MAX), GFP_KERNEL); - if (!ret) - se_tpg->tpg_rtpi = val; + if (se_tpg->rtpi_manual) { + ret = xa_insert(&tpg_xa, se_tpg->tpg_rtpi, se_tpg, GFP_KERNEL); + if (ret) { + pr_info("%s_TPG[%hu] - Can not set RTPI %#x, it is already busy", + se_tpg->se_tpg_tfo->fabric_name, + se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg), + se_tpg->tpg_rtpi); + return -EINVAL; + } + } else { + ret = xa_alloc(&tpg_xa, &val, se_tpg, + XA_LIMIT(1, USHRT_MAX), GFP_KERNEL); + if (!ret) + se_tpg->tpg_rtpi = val; + } return ret; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 008e0e4500d1..e52d0915b3d8 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -918,6 +918,7 @@ struct se_portal_group { bool enabled; /* RELATIVE TARGET PORT IDENTIFIER */ u16 tpg_rtpi; + bool rtpi_manual; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t tpg_pr_ref_count; /* Spinlock for adding/removing ACLed Nodes */ -- 2.25.1