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; }
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); }