@@ -31,6 +31,10 @@
#include "target_core_ua.h"
extern struct se_device *g_lun0_dev;
+static u16 g_tpg_count;
+static u16 g_tpg_rtpi_counter = 1;
+static LIST_HEAD(g_tpg_list);
+static DEFINE_SPINLOCK(g_tpg_lock);
/* __core_tpg_get_initiator_node_acl():
*
@@ -439,6 +443,57 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
complete(&lun->lun_shutdown_comp);
}
+static int core_tpg_register_rtpi(struct se_portal_group *se_tpg)
+{
+ struct se_portal_group *tpg;
+
+ /*
+ * Allocate the next RELATIVE TARGET PORT IDENTIFIER.
+ * Here is the table from SPC-4 4.3.4:
+ *
+ * Table 34 -- Relative target port identifier values
+ *
+ * Value Description
+ * 0h Reserved
+ * 1h Relative port 1, historically known as port A
+ * 2h Relative port 2, historically known as port B
+ * 3h to FFFFh Relative port 3 through 65 535
+ */
+ spin_lock(&g_tpg_lock);
+
+ if (g_tpg_count == 0xffff) {
+ spin_unlock(&g_tpg_lock);
+ pr_warn("Reached g_tpg_count == 0xffff\n");
+ return -ENOSPC;
+ }
+again:
+ se_tpg->tpg_rtpi = g_tpg_rtpi_counter++;
+ if (!se_tpg->tpg_rtpi)
+ goto again;
+
+ list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+ /*
+ * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
+ * for 16-bit wrap..
+ */
+ if (se_tpg->tpg_rtpi == tpg->tpg_rtpi)
+ goto again;
+ }
+ list_add(&se_tpg->tpg_list, &g_tpg_list);
+ g_tpg_count++;
+ spin_unlock(&g_tpg_lock);
+
+ return 0;
+}
+
+static void core_tpg_deregister_rtpi(struct se_portal_group *se_tpg)
+{
+ spin_lock(&g_tpg_lock);
+ list_del(&se_tpg->tpg_list);
+ g_tpg_count--;
+ spin_unlock(&g_tpg_lock);
+}
+
/* Does not change se_wwn->priv. */
int core_tpg_register(
struct se_wwn *se_wwn,
@@ -471,6 +526,7 @@ int core_tpg_register(
se_tpg->proto_id = proto_id;
se_tpg->se_tpg_wwn = se_wwn;
atomic_set(&se_tpg->tpg_pr_ref_count, 0);
+ INIT_LIST_HEAD(&se_tpg->tpg_list);
INIT_LIST_HEAD(&se_tpg->acl_node_list);
INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
spin_lock_init(&se_tpg->session_lock);
@@ -478,9 +534,15 @@ int core_tpg_register(
mutex_init(&se_tpg->acl_node_mutex);
if (se_tpg->proto_id >= 0) {
+ ret = core_tpg_register_rtpi(se_tpg);
+ if (ret < 0)
+ return ret;
+
se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0);
- if (IS_ERR(se_tpg->tpg_virt_lun0))
- return PTR_ERR(se_tpg->tpg_virt_lun0);
+ if (IS_ERR(se_tpg->tpg_virt_lun0)) {
+ ret = PTR_ERR(se_tpg->tpg_virt_lun0);
+ goto out_deregister_rtpi;
+ }
ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
true, g_lun0_dev);
@@ -488,16 +550,20 @@ int core_tpg_register(
goto out_free_lun0;
}
- pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
- "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name,
+ pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, Proto: %d, Portal Tag: %u, RTPI: %#2x\n",
+ se_tpg->se_tpg_tfo->fabric_name,
se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ?
se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL,
- se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
+ se_tpg->proto_id,
+ se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg),
+ se_tpg->tpg_rtpi);
return 0;
out_free_lun0:
kfree(se_tpg->tpg_virt_lun0);
+out_deregister_rtpi:
+ core_tpg_deregister_rtpi(se_tpg);
return ret;
}
EXPORT_SYMBOL(core_tpg_register);
@@ -535,6 +601,8 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
if (se_tpg->proto_id >= 0) {
core_tpg_remove_lun(se_tpg, se_tpg->tpg_virt_lun0);
kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head);
+
+ core_tpg_deregister_rtpi(se_tpg);
}
return 0;
@@ -904,6 +904,8 @@ struct se_portal_group {
*/
int proto_id;
bool enabled;
+ /* RELATIVE TARGET PORT IDENTIFIER */
+ u16 tpg_rtpi;
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
atomic_t tpg_pr_ref_count;
/* Spinlock for adding/removing ACLed Nodes */
@@ -911,6 +913,8 @@ struct se_portal_group {
/* Spinlock for adding/removing sessions */
spinlock_t session_lock;
struct mutex tpg_lun_mutex;
+ /* List of all SCSI target ports */
+ struct list_head tpg_list;
/* linked list for initiator ACL list */
struct list_head acl_node_list;
struct hlist_head tpg_lun_hlist;