Example #1
0
static sense_reason_t
rd_execute_rw(struct se_cmd *cmd)
{
	struct scatterlist *sgl = cmd->t_data_sg;
	u32 sgl_nents = cmd->t_data_nents;
	enum dma_data_direction data_direction = cmd->data_direction;
	struct se_device *se_dev = cmd->se_dev;
	struct rd_dev *dev = RD_DEV(se_dev);
	struct rd_dev_sg_table *table;
	struct scatterlist *rd_sg;
	struct sg_mapping_iter m;
	u32 rd_offset;
	u32 rd_size;
	u32 rd_page;
	u32 src_len;
	u64 tmp;

	if (dev->rd_flags & RDF_NULLIO) {
		target_complete_cmd(cmd, SAM_STAT_GOOD);
		return 0;
	}

	tmp = cmd->t_task_lba * se_dev->dev_attrib.block_size;
	rd_offset = do_div(tmp, PAGE_SIZE);
	rd_page = tmp;
	rd_size = cmd->data_length;

	table = rd_get_sg_table(dev, rd_page);
	if (!table)
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;

	rd_sg = &table->sg_table[rd_page - table->page_start_offset];

	pr_debug("RD[%u]: %s LBA: %llu, Size: %u Page: %u, Offset: %u\n",
			dev->rd_dev_id,
			data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
			cmd->t_task_lba, rd_size, rd_page, rd_offset);

	src_len = PAGE_SIZE - rd_offset;
	sg_miter_start(&m, sgl, sgl_nents,
			data_direction == DMA_FROM_DEVICE ?
				SG_MITER_TO_SG : SG_MITER_FROM_SG);
	while (rd_size) {
		u32 len;
		void *rd_addr;

		sg_miter_next(&m);
		if (!(u32)m.length) {
			pr_debug("RD[%u]: invalid sgl %p len %zu\n",
				 dev->rd_dev_id, m.addr, m.length);
			sg_miter_stop(&m);
			return TCM_INCORRECT_AMOUNT_OF_DATA;
		}
		len = min((u32)m.length, src_len);
		if (len > rd_size) {
			pr_debug("RD[%u]: size underrun page %d offset %d "
				 "size %d\n", dev->rd_dev_id,
				 rd_page, rd_offset, rd_size);
			len = rd_size;
		}
		m.consumed = len;

		rd_addr = sg_virt(rd_sg) + rd_offset;

		if (data_direction == DMA_FROM_DEVICE)
			memcpy(m.addr, rd_addr, len);
		else
			memcpy(rd_addr, m.addr, len);

		rd_size -= len;
		if (!rd_size)
			continue;

		src_len -= len;
		if (src_len) {
			rd_offset += len;
			continue;
		}

		/* rd page completed, next one please */
		rd_page++;
		rd_offset = 0;
		src_len = PAGE_SIZE;
		if (rd_page <= table->page_end_offset) {
			rd_sg++;
			continue;
		}

		table = rd_get_sg_table(dev, rd_page);
		if (!table) {
			sg_miter_stop(&m);
			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
		}

		/* since we increment, the first sg entry is correct */
		rd_sg = table->sg_table;
	}
	sg_miter_stop(&m);

	target_complete_cmd(cmd, SAM_STAT_GOOD);
	return 0;
}
Example #2
0
/*	rd_MEMCPY_write():
 *
 *
 */
static int rd_MEMCPY_write(struct rd_request *req)
{
	struct se_task *task = &req->rd_task;
	struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
	struct rd_dev_sg_table *table;
	struct scatterlist *sg_d, *sg_s;
	void *dst, *src;
	u32 i = 0, j = 0, dst_offset = 0, src_offset = 0;
	u32 length, page_end = 0, table_sg_end;
	u32 rd_offset = req->rd_offset;

	table = rd_get_sg_table(dev, req->rd_page);
	if (!table)
		return -EINVAL;

	table_sg_end = (table->page_end_offset - req->rd_page);
	sg_d = &table->sg_table[req->rd_page - table->page_start_offset];
	sg_s = task->task_sg;

	pr_debug("RD[%d] Write LBA: %llu, Size: %u, Page: %u,"
		" Offset: %u\n", dev->rd_dev_id, task->task_lba, req->rd_size,
		req->rd_page, req->rd_offset);

	dst_offset = rd_offset;

	while (req->rd_size) {
		if ((sg_s[i].length - src_offset) <
		    (sg_d[j].length - dst_offset)) {
			length = (sg_s[i].length - src_offset);

			pr_debug("Step 1 - sg_s[%d]: %p length: %d"
				" offset: %d sg_d[%d].length: %u\n", i,
				&sg_s[i], sg_s[i].length, sg_s[i].offset,
				j, sg_d[j].length);
			pr_debug("Step 1 - length: %u src_offset: %u"
				" dst_offset: %u\n", length, src_offset,
				dst_offset);

			if (length > req->rd_size)
				length = req->rd_size;

			src = sg_virt(&sg_s[i++]) + src_offset;
			BUG_ON(!src);

			dst = sg_virt(&sg_d[j]) + dst_offset;
			BUG_ON(!dst);

			src_offset = 0;
			dst_offset = length;
			page_end = 0;
		} else {
			length = (sg_d[j].length - dst_offset);

			pr_debug("Step 2 - sg_s[%d]: %p length: %d"
				" offset: %d sg_d[%d].length: %u\n", i,
				&sg_s[i], sg_s[i].length, sg_s[i].offset,
				j, sg_d[j].length);
			pr_debug("Step 2 - length: %u src_offset: %u"
				" dst_offset: %u\n", length, src_offset,
				dst_offset);

			if (length > req->rd_size)
				length = req->rd_size;

			src = sg_virt(&sg_s[i]) + src_offset;
			BUG_ON(!src);

			if (sg_s[i].length == length) {
				i++;
				src_offset = 0;
			} else
				src_offset = length;

			dst = sg_virt(&sg_d[j++]) + dst_offset;
			BUG_ON(!dst);

			dst_offset = 0;
			page_end = 1;
		}

		memcpy(dst, src, length);

		pr_debug("page: %u, remaining size: %u, length: %u,"
			" i: %u, j: %u\n", req->rd_page,
			(req->rd_size - length), length, i, j);

		req->rd_size -= length;
		if (!req->rd_size)
			return 0;

		if (!page_end)
			continue;

		if (++req->rd_page <= table->page_end_offset) {
			pr_debug("page: %u in same page table\n",
				req->rd_page);
			continue;
		}

		pr_debug("getting new page table for page: %u\n",
				req->rd_page);

		table = rd_get_sg_table(dev, req->rd_page);
		if (!table)
			return -EINVAL;

		sg_d = &table->sg_table[j = 0];
	}

	return 0;
}
Example #3
0
static int rd_MEMCPY(struct rd_request *req, u32 read_rd)
{
	struct se_task *task = &req->rd_task;
	struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
	struct rd_dev_sg_table *table;
	struct scatterlist *rd_sg;
	struct sg_mapping_iter m;
	u32 rd_offset = req->rd_offset;
	u32 src_len;

	table = rd_get_sg_table(dev, req->rd_page);
	if (!table)
		return -EINVAL;

	rd_sg = &table->sg_table[req->rd_page - table->page_start_offset];

	pr_debug("RD[%u]: %s LBA: %llu, Size: %u Page: %u, Offset: %u\n",
			dev->rd_dev_id, read_rd ? "Read" : "Write",
			task->task_lba, req->rd_size, req->rd_page,
			rd_offset);

	src_len = PAGE_SIZE - rd_offset;
	sg_miter_start(&m, task->task_sg, task->task_sg_nents,
			read_rd ? SG_MITER_TO_SG : SG_MITER_FROM_SG);
	while (req->rd_size) {
		u32 len;
		void *rd_addr;

		sg_miter_next(&m);
		len = min((u32)m.length, src_len);
		m.consumed = len;

		rd_addr = sg_virt(rd_sg) + rd_offset;

		if (read_rd)
			memcpy(m.addr, rd_addr, len);
		else
			memcpy(rd_addr, m.addr, len);

		req->rd_size -= len;
		if (!req->rd_size)
			continue;

		src_len -= len;
		if (src_len) {
			rd_offset += len;
			continue;
		}

		/* rd page completed, next one please */
		req->rd_page++;
		rd_offset = 0;
		src_len = PAGE_SIZE;
		if (req->rd_page <= table->page_end_offset) {
			rd_sg++;
			continue;
		}

		table = rd_get_sg_table(dev, req->rd_page);
		if (!table) {
			sg_miter_stop(&m);
			return -EINVAL;
		}

		/* since we increment, the first sg entry is correct */
		rd_sg = table->sg_table;
	}
	sg_miter_stop(&m);
	return 0;
}