/* * Ensure that this tl_tpg reference from the incoming sc->device->id * has already been configured via tcm_loop_make_naa_tpg().
*/ if (!tl_tpg->tl_hba) {
set_host_byte(sc, DID_NO_CONNECT); goto out_done;
} if (tl_tpg->tl_transport_status == TCM_TRANSPORT_OFFLINE) {
set_host_byte(sc, DID_TRANSPORT_DISRUPTED); goto out_done;
}
tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) {
scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus does not exist\n");
set_host_byte(sc, DID_ERROR); goto out_done;
}
transfer_length = scsi_transfer_length(sc); if (!scsi_prot_sg_count(sc) &&
scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) {
se_cmd->prot_pto = true; /* * loopback transport doesn't support * WRITE_GENERATE, READ_STRIP protection * information operations, go ahead unprotected.
*/
transfer_length = scsi_bufflen(sc);
}
/* * ->queuecommand can be and usually is called from interrupt context, so * defer the actual submission to a workqueue.
*/ staticint tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
{ struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
/* * Called from SCSI EH process context to issue a LUN_RESET TMR * to struct scsi_device
*/ staticint tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
u64 lun, int task, enum tcm_tmreq_table tmr)
{ struct se_cmd *se_cmd; struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_cmd *tl_cmd; int ret = TMR_FUNCTION_FAILED, rc;
/* * Locate the tl_nexus and se_sess pointers
*/
tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) {
pr_err("Unable to perform device reset without active I_T Nexus\n"); return ret;
}
tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); if (!tl_cmd) return ret;
/* * Called from SCSI EH process context to issue a LUN_RESET TMR * to struct scsi_device
*/ staticint tcm_loop_device_reset(struct scsi_cmnd *sc)
{ struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; int ret;
/* * Called from tcm_loop_make_scsi_hba() in tcm_loop_configfs.c
*/ staticint tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host_id)
{ int ret;
ret = device_register(&tl_hba->dev); if (ret) {
pr_err("device_register() failed for tl_hba->dev: %d\n", ret);
put_device(&tl_hba->dev); return -ENODEV;
}
return 0;
}
/* * Called from tcm_loop_fabric_init() in tcl_loop_fabric.c to load the emulated * tcm_loop SCSI bus.
*/ staticint tcm_loop_alloc_core_bus(void)
{ int ret;
tcm_loop_primary = root_device_register("tcm_loop_0"); if (IS_ERR(tcm_loop_primary)) {
pr_err("Unable to allocate tcm_loop_primary\n"); return PTR_ERR(tcm_loop_primary);
}
ret = bus_register(&tcm_loop_lld_bus); if (ret) {
pr_err("bus_register() failed for tcm_loop_lld_bus\n"); goto dev_unreg;
}
ret = driver_register(&tcm_loop_driverfs); if (ret) {
pr_err("driver_register() failed for tcm_loop_driverfs\n"); goto bus_unreg;
}
staticchar *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg)
{ /* * Return the passed NAA identifier for the Target Port
*/ return &tl_tpg(se_tpg)->tl_hba->tl_wwn_address[0];
}
static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg)
{ /* * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 * to represent the SCSI Target Port.
*/ return tl_tpg(se_tpg)->tl_tpgt;
}
/* * Returning (1) here allows for target_core_mod struct se_node_acl to be generated * based upon the incoming fabric dependent SCSI Initiator Port
*/ staticint tcm_loop_check_demo_mode(struct se_portal_group *se_tpg)
{ return 1;
}
staticint tcm_loop_write_pending(struct se_cmd *se_cmd)
{ /* * Since Linux/SCSI has already sent down a struct scsi_cmnd * sc->sc_data_direction of DMA_TO_DEVICE with struct scatterlist array * memory, and memory has already been mapped to struct se_cmd->t_mem_list * format with transport_generic_map_mem_to_cmd(). * * We now tell TCM to add this WRITE CDB directly into the TCM storage * object execution queue.
*/
target_execute_cmd(se_cmd); return 0;
}
tl_nexus = tpg->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(tpg->tl_hba),
tl_nexus->se_sess->se_node_acl->initiatorname); /* * Release the SCSI I_T Nexus to the emulated Target Port
*/
target_remove_session(se_sess);
tpg->tl_nexus = NULL;
kfree(tl_nexus); return 0;
}
tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) return -ENODEV;
ret = snprintf(page, PAGE_SIZE, "%s\n",
tl_nexus->se_sess->se_node_acl->initiatorname);
return ret;
}
static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item, constchar *page, size_t count)
{ struct se_portal_group *se_tpg = to_tpg(item); 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; unsignedchar 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;
switch (tl_tpg->tl_transport_status) { case TCM_TRANSPORT_ONLINE:
status = "online"; break; case TCM_TRANSPORT_OFFLINE:
status = "offline"; break; default: break;
}
if (status)
ret = snprintf(page, PAGE_SIZE, "%s\n", status);
tl_hba = tl_tpg->tl_hba;
tpgt = tl_tpg->tl_tpgt; /* * Release the I_T Nexus for the Virtual target link if present
*/
tcm_loop_drop_nexus(tl_tpg); /* * Deregister the tl_tpg as a emulated TCM Target Endpoint
*/
core_tpg_deregister(se_tpg);
/* * 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) return ERR_PTR(ret);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.