drivers/target/loopback/tcm_loop.c

Source file repositories/reference/linux-study-clean/drivers/target/loopback/tcm_loop.c

File Facts

System
Linux kernel
Corpus path
drivers/target/loopback/tcm_loop.c
Extension
.c
Size
30122 bytes
Lines
1142
Domain
Driver Families
Bucket
drivers/target
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct bus_type tcm_loop_lld_bus = {
	.name			= "tcm_loop_bus",
	.probe			= tcm_loop_driver_probe,
	.remove			= tcm_loop_driver_remove,
};

static struct device_driver tcm_loop_driverfs = {
	.name			= "tcm_loop",
	.bus			= &tcm_loop_lld_bus,
};
/*
 * Used with root_device_register() in tcm_loop_alloc_core_bus() below
 */
static struct device *tcm_loop_primary;

static void tcm_loop_target_queue_cmd(struct tcm_loop_cmd *tl_cmd)
{
	struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
	struct scsi_cmnd *sc = tl_cmd->sc;
	struct tcm_loop_nexus *tl_nexus;
	struct tcm_loop_hba *tl_hba;
	struct tcm_loop_tpg *tl_tpg;
	struct scatterlist *sgl_bidi = NULL;
	u32 sgl_bidi_count = 0, transfer_length;

	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];

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

	se_cmd->tag = tl_cmd->sc_cmd_tag;
	target_init_cmd(se_cmd, tl_nexus->se_sess, &tl_cmd->tl_sense_buf[0],
			tl_cmd->sc->device->lun, transfer_length,
			TCM_SIMPLE_TAG, sc->sc_data_direction, 0);

	if (target_submit_prep(se_cmd, sc->cmnd, scsi_sglist(sc),
			       scsi_sg_count(sc), sgl_bidi, sgl_bidi_count,
			       scsi_prot_sglist(sc), scsi_prot_sg_count(sc),
			       GFP_ATOMIC))
		return;

	target_submit(se_cmd);
	return;

out_done:
	scsi_done(sc);
}

/*
 * ->queuecommand can be and usually is called from interrupt context, so
 * defer the actual submission to a workqueue.
 */
static enum scsi_qc_status tcm_loop_queuecommand(struct Scsi_Host *sh,
						 struct scsi_cmnd *sc)
{
	struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);

	pr_debug("%s() %d:%d:%d:%llu got CDB: 0x%02x scsi_buf_len: %u\n",
		 __func__, sc->device->host->host_no, sc->device->id,
		 sc->device->channel, sc->device->lun, sc->cmnd[0],

Annotation

Implementation Notes