@@ -442,8 +442,23 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
static int core_tpg_register_rtpi(struct se_portal_group *se_tpg)
{
- return xa_alloc(&tpg_xa, &se_tpg->tpg_rtpi, se_tpg,
+ int ret;
+
+ 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, &se_tpg->tpg_rtpi, se_tpg,
XA_LIMIT(1, USHRT_MAX), GFP_KERNEL);
+ }
+
+ return ret;
}
static void core_tpg_deregister_rtpi(struct se_portal_group *se_tpg)
@@ -682,6 +697,42 @@ void core_tpg_remove_lun(
percpu_ref_exit(&lun->lun_ref);
}
+static ssize_t core_tpg_rtpi_show(struct config_item *item, char *page)
+{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
+
+ return sysfs_emit(page, "%#x\n", se_tpg->tpg_rtpi);
+}
+
+static ssize_t core_tpg_rtpi_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_portal_group *se_tpg = attrib_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(core_tpg_, rtpi);
+
struct configfs_attribute *core_tpg_attrib_attrs[] = {
+ &core_tpg_attr_rtpi,
NULL,
};
@@ -901,6 +901,7 @@ struct se_portal_group {
bool enabled;
/* RELATIVE TARGET PORT IDENTIFIER */
u32 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 */