static struct config_group *target_fabric_make_wwn(
	struct config_group *group,
	const char *name)
{
	struct target_fabric_configfs *tf = container_of(group,
				struct target_fabric_configfs, tf_group);
	struct se_wwn *wwn;

	if (!tf->tf_ops.fabric_make_wwn) {
		pr_err("tf->tf_ops.fabric_make_wwn is NULL\n");
		return ERR_PTR(-ENOSYS);
	}

	wwn = tf->tf_ops.fabric_make_wwn(tf, group, name);
	if (!wwn || IS_ERR(wwn))
		return ERR_PTR(-EINVAL);

	wwn->wwn_tf = tf;
	/*
	 * Setup default groups from pre-allocated wwn->wwn_default_groups
	 */
	wwn->wwn_group.default_groups = wwn->wwn_default_groups;
	wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group;
	wwn->wwn_group.default_groups[1] = NULL;

	config_group_init_type_name(&wwn->wwn_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_cit);
	config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics",
			&TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit);

	return &wwn->wwn_group;
}
static struct config_group *target_fabric_make_lun(
	struct config_group *group,
	const char *name)
{
	struct se_lun *lun;
	struct se_portal_group *se_tpg = container_of(group,
			struct se_portal_group, tpg_lun_group);
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	struct config_group *lun_cg = NULL, *port_stat_grp = NULL;
	unsigned long unpacked_lun;
	int errno;

	if (strstr(name, "lun_") != name) {
		pr_err("Unable to locate \'_\" in"
				" \"lun_$LUN_NUMBER\"\n");
		return ERR_PTR(-EINVAL);
	}
	errno = kstrtoul(name + 4, 0, &unpacked_lun);
	if (errno)
		return ERR_PTR(errno);
	if (unpacked_lun > UINT_MAX)
		return ERR_PTR(-EINVAL);

	lun = core_get_lun_from_tpg(se_tpg, unpacked_lun);
	if (!lun)
		return ERR_PTR(-EINVAL);

	lun_cg = &lun->lun_group;
	lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
				GFP_KERNEL);
	if (!lun_cg->default_groups) {
		pr_err("Unable to allocate lun_cg->default_groups\n");
		return ERR_PTR(-ENOMEM);
	}

	config_group_init_type_name(&lun->lun_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_port_cit);
	config_group_init_type_name(&lun->port_stat_grps.stat_group,
			"statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit);
	lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group;
	lun_cg->default_groups[1] = NULL;

	port_stat_grp = &lun->port_stat_grps.stat_group;
	port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group) * 3,
				GFP_KERNEL);
	if (!port_stat_grp->default_groups) {
		pr_err("Unable to allocate port_stat_grp->default_groups\n");
		errno = -ENOMEM;
		goto out;
	}
	target_stat_setup_port_default_groups(lun);

	return &lun->lun_group;
out:
	if (lun_cg)
		kfree(lun_cg->default_groups);
	return ERR_PTR(errno);
}
static struct config_group *target_fabric_make_lun(
	struct config_group *group,
	const char *name)
{
	struct se_lun *lun;
	struct se_portal_group *se_tpg = container_of(group,
			struct se_portal_group, tpg_lun_group);
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	unsigned long unpacked_lun;

	if (strstr(name, "lun_") != name) {
		printk(KERN_ERR "Unable to locate \'_\" in"
				" \"lun_$LUN_NUMBER\"\n");
		return ERR_PTR(-EINVAL);
	}
	if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX)
		return ERR_PTR(-EINVAL);

	lun = core_get_lun_from_tpg(se_tpg, unpacked_lun);
	if (!(lun))
		return ERR_PTR(-EINVAL);

	config_group_init_type_name(&lun->lun_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_port_cit);

	return &lun->lun_group;
}
static struct config_group *target_fabric_make_mappedlun(
	struct config_group *group,
	const char *name)
{
	struct se_node_acl *se_nacl = container_of(group,
			struct se_node_acl, acl_group);
	struct se_portal_group *se_tpg = se_nacl->se_tpg;
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	struct se_lun_acl *lacl;
	struct config_item *acl_ci;
	char *buf;
	unsigned long mapped_lun;
	int ret = 0;

	acl_ci = &group->cg_item;
	if (!(acl_ci)) {
		printk(KERN_ERR "Unable to locatel acl_ci\n");
		return NULL;
	}

	buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
	if (!(buf)) {
		printk(KERN_ERR "Unable to allocate memory for name buf\n");
		return ERR_PTR(-ENOMEM);
	}
	snprintf(buf, strlen(name) + 1, "%s", name);
	/*
	 * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID.
	 */
	if (strstr(buf, "lun_") != buf) {
		printk(KERN_ERR "Unable to locate \"lun_\" from buf: %s"
			" name: %s\n", buf, name);
		ret = -EINVAL;
		goto out;
	}
	/*
	 * Determine the Mapped LUN value.  This is what the SCSI Initiator
	 * Port will actually see.
	 */
	if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) {
		ret = -EINVAL;
		goto out;
	}

	lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun,
			config_item_name(acl_ci), &ret);
	if (!(lacl))
		goto out;

	config_group_init_type_name(&lacl->se_lun_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit);

	kfree(buf);
	return &lacl->se_lun_group;
out:
	kfree(buf);
	return ERR_PTR(ret);
}
static struct config_group *target_fabric_make_nodeacl(
	struct config_group *group,
	const char *name)
{
	struct se_portal_group *se_tpg = container_of(group,
			struct se_portal_group, tpg_acl_group);
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	struct se_node_acl *se_nacl;
	struct config_group *nacl_cg;

	if (!tf->tf_ops.fabric_make_nodeacl) {
		pr_err("tf->tf_ops.fabric_make_nodeacl is NULL\n");
		return ERR_PTR(-ENOSYS);
	}

	se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name);
	if (IS_ERR(se_nacl))
		return ERR_CAST(se_nacl);

	nacl_cg = &se_nacl->acl_group;
	nacl_cg->default_groups = se_nacl->acl_default_groups;
	nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
	nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
	nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
	nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group;
	nacl_cg->default_groups[4] = NULL;

	config_group_init_type_name(&se_nacl->acl_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit);
	config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_attrib_cit);
	config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit);
	config_group_init_type_name(&se_nacl->acl_param_group, "param",
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit);
	config_group_init_type_name(&se_nacl->acl_fabric_stat_group,
			"fabric_statistics",
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit);

	return &se_nacl->acl_group;
}
static struct config_group *target_fabric_make_tpg(
	struct config_group *group,
	const char *name)
{
	struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
	struct target_fabric_configfs *tf = wwn->wwn_tf;
	struct se_portal_group *se_tpg;

	if (!tf->tf_ops.fabric_make_tpg) {
		pr_err("tf->tf_ops.fabric_make_tpg is NULL\n");
		return ERR_PTR(-ENOSYS);
	}

	se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name);
	if (!se_tpg || IS_ERR(se_tpg))
		return ERR_PTR(-EINVAL);
	/*
	 * Setup default groups from pre-allocated se_tpg->tpg_default_groups
	 */
	se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
	se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
	se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
	se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
	se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
	se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
	se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
	se_tpg->tpg_group.default_groups[6] = NULL;

	config_group_init_type_name(&se_tpg->tpg_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_base_cit);
	config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
			&TF_CIT_TMPL(tf)->tfc_tpg_lun_cit);
	config_group_init_type_name(&se_tpg->tpg_np_group, "np",
			&TF_CIT_TMPL(tf)->tfc_tpg_np_cit);
	config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit);
	config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
			&TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit);
	config_group_init_type_name(&se_tpg->tpg_auth_group, "auth",
			&TF_CIT_TMPL(tf)->tfc_tpg_auth_cit);
	config_group_init_type_name(&se_tpg->tpg_param_group, "param",
			&TF_CIT_TMPL(tf)->tfc_tpg_param_cit);

	return &se_tpg->tpg_group;
}
static struct config_group *target_fabric_make_wwn(
	struct config_group *group,
	const char *name)
{
	struct target_fabric_configfs *tf = container_of(group,
				struct target_fabric_configfs, tf_group);
	struct se_wwn *wwn;

	if (!(tf->tf_ops.fabric_make_wwn)) {
		printk(KERN_ERR "tf->tf_ops.fabric_make_wwn is NULL\n");
		return ERR_PTR(-ENOSYS);
	}

	wwn = tf->tf_ops.fabric_make_wwn(tf, group, name);
	if (!(wwn) || IS_ERR(wwn))
		return ERR_PTR(-EINVAL);

	wwn->wwn_tf = tf;
	config_group_init_type_name(&wwn->wwn_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_cit);

	return &wwn->wwn_group;
}
static struct config_group *target_fabric_make_np(
	struct config_group *group,
	const char *name)
{
	struct se_portal_group *se_tpg = container_of(group,
				struct se_portal_group, tpg_np_group);
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	struct se_tpg_np *se_tpg_np;

	if (!tf->tf_ops.fabric_make_np) {
		pr_err("tf->tf_ops.fabric_make_np is NULL\n");
		return ERR_PTR(-ENOSYS);
	}

	se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name);
	if (!se_tpg_np || IS_ERR(se_tpg_np))
		return ERR_PTR(-EINVAL);

	se_tpg_np->tpg_np_parent = se_tpg;
	config_group_init_type_name(&se_tpg_np->tpg_np_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit);

	return &se_tpg_np->tpg_np_group;
}
Example #9
0
static int tcm_loop_register_configfs(void)
{
    struct target_fabric_configfs *fabric;
    struct config_group *tf_cg;
    int ret;
    /*
     * Set the TCM Loop HBA counter to zero
     */
    tcm_loop_hba_no_cnt = 0;
    /*
     * Register the top level struct config_item_type with TCM core
     */
    fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
    if (IS_ERR(fabric)) {
        pr_err("tcm_loop_register_configfs() failed!\n");
        return PTR_ERR(fabric);
    }
    /*
     * Setup the fabric API of function pointers used by target_core_mod
     */
    fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
    fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
    fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
    fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
    fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
    fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
    fabric->tf_ops.tpg_get_pr_transport_id_len =
        &tcm_loop_get_pr_transport_id_len;
    fabric->tf_ops.tpg_parse_pr_out_transport_id =
        &tcm_loop_parse_pr_out_transport_id;
    fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
    fabric->tf_ops.tpg_check_demo_mode_cache =
        &tcm_loop_check_demo_mode_cache;
    fabric->tf_ops.tpg_check_demo_mode_write_protect =
        &tcm_loop_check_demo_mode_write_protect;
    fabric->tf_ops.tpg_check_prod_mode_write_protect =
        &tcm_loop_check_prod_mode_write_protect;
    /*
     * The TCM loopback fabric module runs in demo-mode to a local
     * virtual SCSI device, so fabric dependent initator ACLs are
     * not required.
     */
    fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
    fabric->tf_ops.tpg_release_fabric_acl =
        &tcm_loop_tpg_release_fabric_acl;
    fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index;
    /*
     * Used for setting up remaining TCM resources in process context
     */
    fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map;
    fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
    fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
    fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
    fabric->tf_ops.close_session = &tcm_loop_close_session;
    fabric->tf_ops.stop_session = &tcm_loop_stop_session;
    fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0;
    fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in;
    fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
    fabric->tf_ops.sess_get_initiator_sid = NULL;
    fabric->tf_ops.write_pending = &tcm_loop_write_pending;
    fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status;
    /*
     * Not used for TCM loopback
     */
    fabric->tf_ops.set_default_node_attributes =
        &tcm_loop_set_default_node_attributes;
    fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag;
    fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state;
    fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
    fabric->tf_ops.queue_status = &tcm_loop_queue_status;
    fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
    fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len;
    fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len;
    fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove;

    tf_cg = &fabric->tf_group;
    /*
     * Setup function pointers for generic logic in target_core_fabric_configfs.c
     */
    fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba;
    fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba;
    fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg;
    fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg;
    /*
     * fabric_post_link() and fabric_pre_unlink() are used for
     * registration and release of TCM Loop Virtual SCSI LUNs.
     */
    fabric->tf_ops.fabric_post_link = &tcm_loop_port_link;
    fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink;
    fabric->tf_ops.fabric_make_np = NULL;
    fabric->tf_ops.fabric_drop_np = NULL;
    /*
     * Setup default attribute lists for various fabric->tf_cit_tmpl
     */
    TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs;
    TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs;
    TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
    TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
    TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
    /*
     * Once fabric->tf_ops has been setup, now register the fabric for
     * use within TCM
     */
    ret = target_fabric_configfs_register(fabric);
    if (ret < 0) {
        pr_err("target_fabric_configfs_register() for"
               " TCM_Loop failed!\n");
        target_fabric_configfs_free(fabric);
        return -1;
    }
    /*
     * Setup our local pointer to *fabric.
     */
    tcm_loop_fabric_configfs = fabric;
    pr_debug("TCM_LOOP[0] - Set fabric ->"
             " tcm_loop_fabric_configfs\n");
    return 0;
}
static struct config_group *target_fabric_make_mappedlun(
	struct config_group *group,
	const char *name)
{
	struct se_node_acl *se_nacl = container_of(group,
			struct se_node_acl, acl_group);
	struct se_portal_group *se_tpg = se_nacl->se_tpg;
	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
	struct se_lun_acl *lacl;
	struct config_item *acl_ci;
	struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
	char *buf;
	unsigned long mapped_lun;
	int ret = 0;

	acl_ci = &group->cg_item;
	if (!acl_ci) {
		pr_err("Unable to locatel acl_ci\n");
		return NULL;
	}

	buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
	if (!buf) {
		pr_err("Unable to allocate memory for name buf\n");
		return ERR_PTR(-ENOMEM);
	}
	snprintf(buf, strlen(name) + 1, "%s", name);
	/*
	 * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID.
	 */
	if (strstr(buf, "lun_") != buf) {
		pr_err("Unable to locate \"lun_\" from buf: %s"
			" name: %s\n", buf, name);
		ret = -EINVAL;
		goto out;
	}
	/*
	 * Determine the Mapped LUN value.  This is what the SCSI Initiator
	 * Port will actually see.
	 */
	ret = kstrtoul(buf + 4, 0, &mapped_lun);
	if (ret)
		goto out;
	if (mapped_lun > UINT_MAX) {
		ret = -EINVAL;
		goto out;
	}
	if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
		pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG"
			"-1: %u for Target Portal Group: %u\n", mapped_lun,
			TRANSPORT_MAX_LUNS_PER_TPG-1,
			se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
		ret = -EINVAL;
		goto out;
	}

	lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl,
			mapped_lun, &ret);
	if (!lacl) {
		ret = -EINVAL;
		goto out;
	}

	lacl_cg = &lacl->se_lun_group;
	lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
				GFP_KERNEL);
	if (!lacl_cg->default_groups) {
		pr_err("Unable to allocate lacl_cg->default_groups\n");
		ret = -ENOMEM;
		goto out;
	}

	config_group_init_type_name(&lacl->se_lun_group, name,
			&TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit);
	config_group_init_type_name(&lacl->ml_stat_grps.stat_group,
			"statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit);
	lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group;
	lacl_cg->default_groups[1] = NULL;

	ml_stat_grp = &lacl->ml_stat_grps.stat_group;
	ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3,
				GFP_KERNEL);
	if (!ml_stat_grp->default_groups) {
		pr_err("Unable to allocate ml_stat_grp->default_groups\n");
		ret = -ENOMEM;
		goto out;
	}
	target_stat_setup_mappedlun_default_groups(lacl);

	kfree(buf);
	return &lacl->se_lun_group;
out:
	if (lacl_cg)
		kfree(lacl_cg->default_groups);
	kfree(buf);
	return ERR_PTR(ret);
}