static struct se_portal_group *tcm_loop_make_naa_tpg( struct se_wwn *wwn, struct config_group *group, const char *name) { struct tcm_loop_hba *tl_hba = container_of(wwn, struct tcm_loop_hba, tl_hba_wwn); struct tcm_loop_tpg *tl_tpg; char *tpgt_str, *end_ptr; int ret; unsigned short int tpgt; tpgt_str = strstr(name, "tpgt_"); if (!tpgt_str) { pr_err("Unable to locate \"tpgt_#\" directory" " group\n"); return ERR_PTR(-EINVAL); } tpgt_str += 5; /* Skip ahead of "tpgt_" */ tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); if (tpgt >= TL_TPGS_PER_HBA) { pr_err("Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:" " %u\n", tpgt, TL_TPGS_PER_HBA); return ERR_PTR(-EINVAL); } tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; tl_tpg->tl_hba = tl_hba; tl_tpg->tl_tpgt = tpgt; /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return ERR_PTR(-ENOMEM); pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s" " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), config_item_name(&wwn->wwn_group.cg_item), tpgt); return &tl_tpg->tl_se_tpg; }
static struct se_portal_group *tcm_loop_make_naa_tpg( struct se_wwn *wwn, struct config_group *group, const char *name) { struct tcm_loop_hba *tl_hba = container_of(wwn, struct tcm_loop_hba, tl_hba_wwn); struct tcm_loop_tpg *tl_tpg; int ret; unsigned long tpgt; if (strstr(name, "tpgt_") != name) { pr_err("Unable to locate \"tpgt_#\" directory" " group\n"); return ERR_PTR(-EINVAL); } if (kstrtoul(name+5, 10, &tpgt)) return ERR_PTR(-EINVAL); if (tpgt >= TL_TPGS_PER_HBA) { pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA:" " %u\n", tpgt, TL_TPGS_PER_HBA); return ERR_PTR(-EINVAL); } tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; tl_tpg->tl_hba = tl_hba; tl_tpg->tl_tpgt = tpgt; /* * Register the tl_tpg as a emulated TCM Target Endpoint */ ret = core_tpg_register(wwn, &tl_tpg->tl_se_tpg, tl_hba->tl_proto_id); if (ret < 0) return ERR_PTR(-ENOMEM); pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s" " Target Port %s,t,0x%04lx\n", tcm_loop_dump_proto_id(tl_hba), config_item_name(&wwn->wwn_group.cg_item), tpgt); return &tl_tpg->tl_se_tpg; }
static int tcm_loop_drop_nexus( struct tcm_loop_tpg *tpg) { struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_hba *tl_hba = tpg->tl_hba; if (!tl_hba) return -ENODEV; tl_nexus = tl_hba->tl_nexus; if (!tl_nexus) return -ENODEV; se_sess = tl_nexus->se_sess; if (!se_sess) return -ENODEV; if (atomic_read(&tpg->tl_tpg_port_count)) { pr_err("Unable to remove TCM_Loop I_T Nexus with" " active TPG port count: %d\n", atomic_read(&tpg->tl_tpg_port_count)); return -EPERM; } pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), tl_nexus->se_sess->se_node_acl->initiatorname); /* * Release the SCSI I_T Nexus to the emulated SAS Target Port */ transport_deregister_session(tl_nexus->se_sess); tpg->tl_hba->tl_nexus = NULL; kfree(tl_nexus); return 0; }
void tcm_loop_drop_naa_tpg( struct se_portal_group *se_tpg) { struct se_wwn *wwn = se_tpg->se_tpg_wwn; struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); struct tcm_loop_hba *tl_hba; unsigned short tpgt; tl_hba = tl_tpg->tl_hba; tpgt = tl_tpg->tl_tpgt; /* * Release the I_T Nexus for the Virtual SAS link if present */ tcm_loop_drop_nexus(tl_tpg); /* * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint */ core_tpg_deregister(se_tpg); pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s" " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), config_item_name(&wwn->wwn_group.cg_item), tpgt); }
struct se_wwn *tcm_loop_make_scsi_hba( struct target_fabric_configfs *tf, struct config_group *group, const char *name) { struct tcm_loop_hba *tl_hba; struct Scsi_Host *sh; char *ptr; int ret, off = 0; tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL); if (!tl_hba) { pr_err("Unable to allocate struct tcm_loop_hba\n"); return ERR_PTR(-ENOMEM); } /* * Determine the emulated Protocol Identifier and Target Port Name * based on the incoming configfs directory name. */ ptr = strstr(name, "naa."); if (ptr) { tl_hba->tl_proto_id = SCSI_PROTOCOL_SAS; goto check_len; } ptr = strstr(name, "fc."); if (ptr) { tl_hba->tl_proto_id = SCSI_PROTOCOL_FCP; off = 3; /* Skip over "fc." */ goto check_len; } ptr = strstr(name, "iqn."); if (!ptr) { pr_err("Unable to locate prefix for emulated Target " "Port: %s\n", name); ret = -EINVAL; goto out; } tl_hba->tl_proto_id = SCSI_PROTOCOL_ISCSI; check_len: if (strlen(name) >= TL_WWN_ADDR_LEN) { pr_err("Emulated NAA %s Address: %s, exceeds" " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), TL_WWN_ADDR_LEN); ret = -EINVAL; goto out; } snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); /* * Call device_register(tl_hba->dev) to register the emulated * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after * device_register() callbacks in tcm_loop_driver_probe() */ ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt); if (ret) goto out; sh = tl_hba->sh; tcm_loop_hba_no_cnt++; pr_debug("TCM_Loop_ConfigFS: Allocated emulated Target" " %s Address: %s at Linux/SCSI Host ID: %d\n", tcm_loop_dump_proto_id(tl_hba), name, sh->host_no); return &tl_hba->tl_hba_wwn; out: kfree(tl_hba); return ERR_PTR(ret); }
static ssize_t tcm_loop_tpg_store_nexus( struct se_portal_group *se_tpg, const char *page, size_t count) { struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; unsigned char i_port[TL_WWN_ADDR_LEN], *ptr, *port_ptr; int ret; /* * Shutdown the active I_T nexus if 'NULL' is passed.. */ if (!strncmp(page, "NULL", 4)) { ret = tcm_loop_drop_nexus(tl_tpg); return (!ret) ? count : ret; } /* * Otherwise make sure the passed virtual Initiator port WWN matches * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call * tcm_loop_make_nexus() */ if (strlen(page) >= TL_WWN_ADDR_LEN) { pr_err("Emulated NAA Sas Address: %s, exceeds" " max: %d\n", page, TL_WWN_ADDR_LEN); return -EINVAL; } snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page); ptr = strstr(i_port, "naa."); if (ptr) { if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) { pr_err("Passed SAS Initiator Port %s does not" " match target port protoid: %s\n", i_port, tcm_loop_dump_proto_id(tl_hba)); return -EINVAL; } port_ptr = &i_port[0]; goto check_newline; } ptr = strstr(i_port, "fc."); if (ptr) { if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) { pr_err("Passed FCP Initiator Port %s does not" " match target port protoid: %s\n", i_port, tcm_loop_dump_proto_id(tl_hba)); return -EINVAL; } port_ptr = &i_port[3]; /* Skip over "fc." */ goto check_newline; } ptr = strstr(i_port, "iqn."); if (ptr) { if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) { pr_err("Passed iSCSI Initiator Port %s does not" " match target port protoid: %s\n", i_port, tcm_loop_dump_proto_id(tl_hba)); return -EINVAL; } port_ptr = &i_port[0]; goto check_newline; } pr_err("Unable to locate prefix for emulated Initiator Port:" " %s\n", i_port); return -EINVAL; /* * Clear any trailing newline for the NAA WWN */ check_newline: if (i_port[strlen(i_port)-1] == '\n') i_port[strlen(i_port)-1] = '\0'; ret = tcm_loop_make_nexus(tl_tpg, port_ptr); if (ret < 0) return ret; return count; }