drivers/target/target_core_sbc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/target/target_core_sbc.c
Extension
.c
Size
37802 bytes
Lines
1450
Domain
Driver Families
Bucket
drivers/target
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (!dev->dev_attrib.emulate_tpws) {
			pr_err("Got WRITE_SAME w/ UNMAP=1, but backend device"
			       " has emulate_tpws disabled\n");
			return TCM_UNSUPPORTED_SCSI_OPCODE;
		}
		cmd->execute_cmd = sbc_execute_write_same_unmap;
		return 0;
	}
	if (!ops->execute_write_same)
		return TCM_UNSUPPORTED_SCSI_OPCODE;

	ret = sbc_check_prot(dev, cmd, flags >> 5, sectors, true);
	if (ret)
		return ret;

	cmd->execute_cmd = ops->execute_write_same;
	return 0;
}

static sense_reason_t
sbc_execute_rw(struct se_cmd *cmd)
{
	struct exec_cmd_ops *ops = cmd->protocol_data;

	return ops->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents,
			       cmd->data_direction);
}

static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success,
					     int *post_ret)
{
	struct se_device *dev = cmd->se_dev;
	sense_reason_t ret = TCM_NO_SENSE;

	spin_lock_irq(&cmd->t_state_lock);
	if (success) {
		*post_ret = 1;

		if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
	}
	spin_unlock_irq(&cmd->t_state_lock);

	/*
	 * Unlock ->caw_sem originally obtained during sbc_compare_and_write()
	 * before the original READ I/O submission.
	 */
	up(&dev->caw_sem);

	return ret;
}

/*
 * compare @cmp_len bytes of @read_sgl with @cmp_sgl. On miscompare, fill
 * @miscmp_off and return TCM_MISCOMPARE_VERIFY.
 */
static sense_reason_t
compare_and_write_do_cmp(struct scatterlist *read_sgl, unsigned int read_nents,
			 struct scatterlist *cmp_sgl, unsigned int cmp_nents,
			 unsigned int cmp_len, unsigned int *miscmp_off)
{
	unsigned char *buf = NULL;
	struct scatterlist *sg;
	sense_reason_t ret;
	unsigned int offset;
	size_t rc;
	int sg_cnt;

	buf = kzalloc(cmp_len, GFP_KERNEL);
	if (!buf) {
		ret = TCM_OUT_OF_RESOURCES;
		goto out;
	}

	rc = sg_copy_to_buffer(cmp_sgl, cmp_nents, buf, cmp_len);
	if (!rc) {
		pr_err("sg_copy_to_buffer() failed for compare_and_write\n");
		ret = TCM_OUT_OF_RESOURCES;
		goto out;
	}
	/*
	 * Compare SCSI READ payload against verify payload
	 */
	offset = 0;
	ret = TCM_NO_SENSE;
	for_each_sg(read_sgl, sg, read_nents, sg_cnt) {
		unsigned int len = min(sg->length, cmp_len);
		unsigned char *addr = kmap_atomic(sg_page(sg));

		if (memcmp(addr, buf + offset, len)) {

Annotation

Implementation Notes