@@ -490,6 +490,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
* fabric driver unload of TFO->module to proceed.
*/
rcu_barrier();
+ kfree(t->tf_tpg_base_cit.ct_attrs);
kfree(t);
return;
}
@@ -815,8 +815,38 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
.release = target_fabric_tpg_release,
};
-TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL);
+static int
+target_fabric_setup_tpg_base_cit(struct target_fabric_configfs *tf)
+{
+ int i, k, len = 0;
+ struct config_item_type *cit = &tf->tf_tpg_base_cit;
+ struct configfs_attribute **attrs;
+
+ for (i = 0; core_tpg_base_attrs[i]; i++)
+ len += sizeof(struct configfs_attribute *);
+ if (tf->tf_ops->tfc_tpg_base_attrs)
+ for (i = 0; tf->tf_ops->tfc_tpg_base_attrs[i]; i++)
+ len += sizeof(struct configfs_attribute *);
+ len += sizeof(struct configfs_attribute *);
+
+ attrs = kzalloc(len, GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ for (i = 0; core_tpg_base_attrs[i]; i++)
+ attrs[i] = core_tpg_base_attrs[i];
+ if (tf->tf_ops->tfc_tpg_base_attrs)
+ for (k = 0; tf->tf_ops->tfc_tpg_base_attrs[k]; k++, i++)
+ attrs[i] = tf->tf_ops->tfc_tpg_base_attrs[k];
+ attrs[i] = NULL;
+
+ cit->ct_item_ops = &target_fabric_tpg_base_item_ops;
+ cit->ct_attrs = attrs;
+ cit->ct_owner = tf->tf_ops->module;
+ pr_debug("Setup generic tpg_base\n");
+ return 0;
+}
/* End of tfc_tpg_base_cit */
/* Start of tfc_tpg_cit */
@@ -971,11 +1001,15 @@ TF_CIT_SETUP_DRV(discovery, NULL, NULL);
int target_fabric_setup_cits(struct target_fabric_configfs *tf)
{
+ int ret;
+
target_fabric_setup_discovery_cit(tf);
target_fabric_setup_wwn_cit(tf);
target_fabric_setup_wwn_fabric_stats_cit(tf);
target_fabric_setup_tpg_cit(tf);
- target_fabric_setup_tpg_base_cit(tf);
+ ret = target_fabric_setup_tpg_base_cit(tf);
+ if (ret)
+ return ret;
target_fabric_setup_tpg_port_cit(tf);
target_fabric_setup_tpg_port_stat_cit(tf);
target_fabric_setup_tpg_lun_cit(tf);
@@ -117,6 +117,7 @@ int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
/* target_core_tpg.c */
extern struct se_device *g_lun0_dev;
+extern struct configfs_attribute *core_tpg_base_attrs[];
struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
const char *);
@@ -650,3 +650,45 @@ void core_tpg_remove_lun(
percpu_ref_exit(&lun->lun_ref);
}
+
+
+static ssize_t core_tpg_base_enable_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "%d\n", to_tpg(item)->enabled);
+}
+
+static ssize_t core_tpg_base_enable_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ int ret;
+ u32 op;
+
+ ret = kstrtou32(page, 0, &op);
+ if (ret)
+ return ret;
+ if ((op != 1) && (op != 0)) {
+ pr_err("Illegal value for tpg_enable: %u\n", op);
+ return -EINVAL;
+ }
+
+ if (se_tpg->enabled == op)
+ return count;
+
+ if (se_tpg->se_tpg_tfo->fabric_enable_tpg)
+ ret = se_tpg->se_tpg_tfo->fabric_enable_tpg(se_tpg, op);
+
+ if (ret)
+ return ret;
+
+ se_tpg->enabled = op;
+
+ return count;
+}
+
+CONFIGFS_ATTR(core_tpg_base_, enable);
+
+struct configfs_attribute *core_tpg_base_attrs[] = {
+ &core_tpg_base_attr_enable,
+ NULL,
+};
@@ -885,6 +885,7 @@ struct se_portal_group {
* Negative values can be used by fabric drivers for internal use TPGs.
*/
int proto_id;
+ bool enabled;
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
atomic_t tpg_pr_ref_count;
/* Spinlock for adding/removing ACLed Nodes */
@@ -89,6 +89,7 @@ struct target_core_fabric_ops {
void (*add_wwn_groups)(struct se_wwn *);
struct se_portal_group *(*fabric_make_tpg)(struct se_wwn *,
const char *);
+ int (*fabric_enable_tpg)(struct se_portal_group *se_tpg, bool enable);
void (*fabric_drop_tpg)(struct se_portal_group *);
int (*fabric_post_link)(struct se_portal_group *,
struct se_lun *);