mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	xen: pvblock: Implement front-back protocol and do IO
Implement Xen para-virtual frontend to backend communication and actually read/write disk data. This is based on mini-os implementation of the para-virtual block frontend driver. Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>
This commit is contained in:
		
							parent
							
								
									17c96f8851
								
							
						
					
					
						commit
						3a739cc6c9
					
				@ -107,7 +107,7 @@ void unbind_evtchn(evtchn_port_t port)
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (ev_actions[port].handler == default_handler)
 | 
			
		||||
		printf("WARN: No handler for port %d when unbinding\n", port);
 | 
			
		||||
		debug("Default handler for port %d when unbinding\n", port);
 | 
			
		||||
	mask_evtchn(port);
 | 
			
		||||
	clear_evtchn(port);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <asm/xen/system.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/bug.h>
 | 
			
		||||
#include <linux/compat.h>
 | 
			
		||||
 | 
			
		||||
#include <xen/events.h>
 | 
			
		||||
@ -30,6 +31,7 @@
 | 
			
		||||
 | 
			
		||||
#define O_RDONLY	00
 | 
			
		||||
#define O_RDWR		02
 | 
			
		||||
#define WAIT_RING_TO_MS	10
 | 
			
		||||
 | 
			
		||||
struct blkfront_info {
 | 
			
		||||
	u64 sectors;
 | 
			
		||||
@ -65,12 +67,42 @@ struct blkfront_dev {
 | 
			
		||||
	char *backend;
 | 
			
		||||
	struct blkfront_info info;
 | 
			
		||||
	unsigned int devid;
 | 
			
		||||
	u8 *bounce_buffer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct blkfront_platdata {
 | 
			
		||||
	unsigned int devid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct blkfront_aiocb - AIO сontrol block
 | 
			
		||||
 * @aio_dev: Blockfront device
 | 
			
		||||
 * @aio_buf: Memory buffer, which must be sector-aligned for
 | 
			
		||||
 *	     @aio_dev sector
 | 
			
		||||
 * @aio_nbytes: Size of AIO, which must be less than @aio_dev
 | 
			
		||||
 *		sector-sized amounts
 | 
			
		||||
 * @aio_offset: Offset, which must not go beyond @aio_dev
 | 
			
		||||
 *		sector-aligned location
 | 
			
		||||
 * @data: Data used to receiving response from ring
 | 
			
		||||
 * @gref: Array of grant references
 | 
			
		||||
 * @n: Number of segments
 | 
			
		||||
 * @aio_cb: Represents one I/O request.
 | 
			
		||||
 */
 | 
			
		||||
struct blkfront_aiocb {
 | 
			
		||||
	struct blkfront_dev *aio_dev;
 | 
			
		||||
	u8 *aio_buf;
 | 
			
		||||
	size_t aio_nbytes;
 | 
			
		||||
	off_t aio_offset;
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	void (*aio_cb)(struct blkfront_aiocb *aiocb, int ret);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void blkfront_sync(struct blkfront_dev *dev);
 | 
			
		||||
 | 
			
		||||
static void free_blkfront(struct blkfront_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	mask_evtchn(dev->evtchn);
 | 
			
		||||
@ -81,16 +113,11 @@ static void free_blkfront(struct blkfront_dev *dev)
 | 
			
		||||
 | 
			
		||||
	unbind_evtchn(dev->evtchn);
 | 
			
		||||
 | 
			
		||||
	free(dev->bounce_buffer);
 | 
			
		||||
	free(dev->nodename);
 | 
			
		||||
	free(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_handler(evtchn_port_t port, struct pt_regs *regs,
 | 
			
		||||
			     void *data)
 | 
			
		||||
{
 | 
			
		||||
	printf("%s [Port %d] - event received\n", __func__, port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int init_blkfront(unsigned int devid, struct blkfront_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	xenbus_transaction_t xbt;
 | 
			
		||||
@ -111,7 +138,7 @@ static int init_blkfront(unsigned int devid, struct blkfront_dev *dev)
 | 
			
		||||
 | 
			
		||||
	snprintf(path, sizeof(path), "%s/backend-id", nodename);
 | 
			
		||||
	dev->dom = xenbus_read_integer(path);
 | 
			
		||||
	evtchn_alloc_unbound(dev->dom, blkfront_handler, dev, &dev->evtchn);
 | 
			
		||||
	evtchn_alloc_unbound(dev->dom, NULL, dev, &dev->evtchn);
 | 
			
		||||
 | 
			
		||||
	s = (struct blkif_sring *)memalign(PAGE_SIZE, PAGE_SIZE);
 | 
			
		||||
	if (!s) {
 | 
			
		||||
@ -232,8 +259,16 @@ done:
 | 
			
		||||
	}
 | 
			
		||||
	unmask_evtchn(dev->evtchn);
 | 
			
		||||
 | 
			
		||||
	debug("%llu sectors of %u bytes\n",
 | 
			
		||||
	      dev->info.sectors, dev->info.sector_size);
 | 
			
		||||
	dev->bounce_buffer = memalign(dev->info.sector_size,
 | 
			
		||||
				      dev->info.sector_size);
 | 
			
		||||
	if (!dev->bounce_buffer) {
 | 
			
		||||
		printf("Failed to allocate bouncing buffer\n");
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	debug("%llu sectors of %u bytes, bounce buffer at %p\n",
 | 
			
		||||
	      dev->info.sectors, dev->info.sector_size,
 | 
			
		||||
	      dev->bounce_buffer);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
@ -254,6 +289,8 @@ static void shutdown_blkfront(struct blkfront_dev *dev)
 | 
			
		||||
 | 
			
		||||
	debug("Close " DRV_NAME ", device ID %d\n", dev->devid);
 | 
			
		||||
 | 
			
		||||
	blkfront_sync(dev);
 | 
			
		||||
 | 
			
		||||
	snprintf(path, sizeof(path), "%s/state", dev->backend);
 | 
			
		||||
	snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
 | 
			
		||||
 | 
			
		||||
@ -308,16 +345,315 @@ close:
 | 
			
		||||
		free_blkfront(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * blkfront_aio_poll() - AIO polling function.
 | 
			
		||||
 * @dev: Blkfront device
 | 
			
		||||
 *
 | 
			
		||||
 * Here we receive response from the ring and check its status. This happens
 | 
			
		||||
 * until we read all data from the ring. We read the data from consumed pointer
 | 
			
		||||
 * to the response pointer. Then increase consumed pointer to make it clear that
 | 
			
		||||
 * the data has been read.
 | 
			
		||||
 *
 | 
			
		||||
 * Return: Number of consumed bytes.
 | 
			
		||||
 */
 | 
			
		||||
static int blkfront_aio_poll(struct blkfront_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	RING_IDX rp, cons;
 | 
			
		||||
	struct blkif_response *rsp;
 | 
			
		||||
	int more;
 | 
			
		||||
	int nr_consumed;
 | 
			
		||||
 | 
			
		||||
moretodo:
 | 
			
		||||
	rp = dev->ring.sring->rsp_prod;
 | 
			
		||||
	rmb(); /* Ensure we see queued responses up to 'rp'. */
 | 
			
		||||
	cons = dev->ring.rsp_cons;
 | 
			
		||||
 | 
			
		||||
	nr_consumed = 0;
 | 
			
		||||
	while ((cons != rp)) {
 | 
			
		||||
		struct blkfront_aiocb *aiocbp;
 | 
			
		||||
		int status;
 | 
			
		||||
 | 
			
		||||
		rsp = RING_GET_RESPONSE(&dev->ring, cons);
 | 
			
		||||
		nr_consumed++;
 | 
			
		||||
 | 
			
		||||
		aiocbp = (void *)(uintptr_t)rsp->id;
 | 
			
		||||
		status = rsp->status;
 | 
			
		||||
 | 
			
		||||
		switch (rsp->operation) {
 | 
			
		||||
		case BLKIF_OP_READ:
 | 
			
		||||
		case BLKIF_OP_WRITE:
 | 
			
		||||
		{
 | 
			
		||||
			int j;
 | 
			
		||||
 | 
			
		||||
			if (status != BLKIF_RSP_OKAY)
 | 
			
		||||
				printf("%s error %d on %s at offset %llu, num bytes %llu\n",
 | 
			
		||||
				       rsp->operation == BLKIF_OP_READ ?
 | 
			
		||||
				       "read" : "write",
 | 
			
		||||
				       status, aiocbp->aio_dev->nodename,
 | 
			
		||||
				       (unsigned long long)aiocbp->aio_offset,
 | 
			
		||||
				       (unsigned long long)aiocbp->aio_nbytes);
 | 
			
		||||
 | 
			
		||||
			for (j = 0; j < aiocbp->n; j++)
 | 
			
		||||
				gnttab_end_access(aiocbp->gref[j]);
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case BLKIF_OP_WRITE_BARRIER:
 | 
			
		||||
			if (status != BLKIF_RSP_OKAY)
 | 
			
		||||
				printf("write barrier error %d\n", status);
 | 
			
		||||
			break;
 | 
			
		||||
		case BLKIF_OP_FLUSH_DISKCACHE:
 | 
			
		||||
			if (status != BLKIF_RSP_OKAY)
 | 
			
		||||
				printf("flush error %d\n", status);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			printf("unrecognized block operation %d response (status %d)\n",
 | 
			
		||||
			       rsp->operation, status);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dev->ring.rsp_cons = ++cons;
 | 
			
		||||
		/* Nota: callback frees aiocbp itself */
 | 
			
		||||
		if (aiocbp && aiocbp->aio_cb)
 | 
			
		||||
			aiocbp->aio_cb(aiocbp, status ? -EIO : 0);
 | 
			
		||||
		if (dev->ring.rsp_cons != cons)
 | 
			
		||||
			/* We reentered, we must not continue here */
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RING_FINAL_CHECK_FOR_RESPONSES(&dev->ring, more);
 | 
			
		||||
	if (more)
 | 
			
		||||
		goto moretodo;
 | 
			
		||||
 | 
			
		||||
	return nr_consumed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_wait_slot(struct blkfront_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* Wait for a slot */
 | 
			
		||||
	if (RING_FULL(&dev->ring)) {
 | 
			
		||||
		while (true) {
 | 
			
		||||
			blkfront_aio_poll(dev);
 | 
			
		||||
			if (!RING_FULL(&dev->ring))
 | 
			
		||||
				break;
 | 
			
		||||
			wait_event_timeout(NULL, !RING_FULL(&dev->ring),
 | 
			
		||||
					   WAIT_RING_TO_MS);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * blkfront_aio_poll() - Issue an aio.
 | 
			
		||||
 * @aiocbp: AIO control block structure
 | 
			
		||||
 * @write: Describes is it read or write operation
 | 
			
		||||
 *	   0 - read
 | 
			
		||||
 *	   1 - write
 | 
			
		||||
 *
 | 
			
		||||
 * We check whether the AIO parameters meet the requirements of the device.
 | 
			
		||||
 * Then receive request from ring and define its arguments. After this we
 | 
			
		||||
 * grant access to the grant references. The last step is notifying about AIO
 | 
			
		||||
 * via event channel.
 | 
			
		||||
 */
 | 
			
		||||
static void blkfront_aio(struct blkfront_aiocb *aiocbp, int write)
 | 
			
		||||
{
 | 
			
		||||
	struct blkfront_dev *dev = aiocbp->aio_dev;
 | 
			
		||||
	struct blkif_request *req;
 | 
			
		||||
	RING_IDX i;
 | 
			
		||||
	int notify;
 | 
			
		||||
	int n, j;
 | 
			
		||||
	uintptr_t start, end;
 | 
			
		||||
 | 
			
		||||
	/* Can't io at non-sector-aligned location */
 | 
			
		||||
	BUG_ON(aiocbp->aio_offset & (dev->info.sector_size - 1));
 | 
			
		||||
	/* Can't io non-sector-sized amounts */
 | 
			
		||||
	BUG_ON(aiocbp->aio_nbytes & (dev->info.sector_size - 1));
 | 
			
		||||
	/* Can't io non-sector-aligned buffer */
 | 
			
		||||
	BUG_ON(((uintptr_t)aiocbp->aio_buf & (dev->info.sector_size - 1)));
 | 
			
		||||
 | 
			
		||||
	start = (uintptr_t)aiocbp->aio_buf & PAGE_MASK;
 | 
			
		||||
	end = ((uintptr_t)aiocbp->aio_buf + aiocbp->aio_nbytes +
 | 
			
		||||
	       PAGE_SIZE - 1) & PAGE_MASK;
 | 
			
		||||
	n = (end - start) / PAGE_SIZE;
 | 
			
		||||
	aiocbp->n = n;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(n > BLKIF_MAX_SEGMENTS_PER_REQUEST);
 | 
			
		||||
 | 
			
		||||
	blkfront_wait_slot(dev);
 | 
			
		||||
	i = dev->ring.req_prod_pvt;
 | 
			
		||||
	req = RING_GET_REQUEST(&dev->ring, i);
 | 
			
		||||
 | 
			
		||||
	req->operation = write ? BLKIF_OP_WRITE : BLKIF_OP_READ;
 | 
			
		||||
	req->nr_segments = n;
 | 
			
		||||
	req->handle = dev->handle;
 | 
			
		||||
	req->id = (uintptr_t)aiocbp;
 | 
			
		||||
	req->sector_number = aiocbp->aio_offset / dev->info.sector_size;
 | 
			
		||||
 | 
			
		||||
	for (j = 0; j < n; j++) {
 | 
			
		||||
		req->seg[j].first_sect = 0;
 | 
			
		||||
		req->seg[j].last_sect = PAGE_SIZE / dev->info.sector_size - 1;
 | 
			
		||||
	}
 | 
			
		||||
	req->seg[0].first_sect = ((uintptr_t)aiocbp->aio_buf & ~PAGE_MASK) /
 | 
			
		||||
		dev->info.sector_size;
 | 
			
		||||
	req->seg[n - 1].last_sect = (((uintptr_t)aiocbp->aio_buf +
 | 
			
		||||
		aiocbp->aio_nbytes - 1) & ~PAGE_MASK) / dev->info.sector_size;
 | 
			
		||||
	for (j = 0; j < n; j++) {
 | 
			
		||||
		uintptr_t data = start + j * PAGE_SIZE;
 | 
			
		||||
 | 
			
		||||
		if (!write) {
 | 
			
		||||
			/* Trigger CoW if needed */
 | 
			
		||||
			*(char *)(data + (req->seg[j].first_sect *
 | 
			
		||||
					  dev->info.sector_size)) = 0;
 | 
			
		||||
			barrier();
 | 
			
		||||
		}
 | 
			
		||||
		req->seg[j].gref = gnttab_grant_access(dev->dom,
 | 
			
		||||
						       virt_to_pfn((void *)data),
 | 
			
		||||
						       write);
 | 
			
		||||
		aiocbp->gref[j] = req->seg[j].gref;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->ring.req_prod_pvt = i + 1;
 | 
			
		||||
 | 
			
		||||
	wmb();
 | 
			
		||||
	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
 | 
			
		||||
 | 
			
		||||
	if (notify)
 | 
			
		||||
		notify_remote_via_evtchn(dev->evtchn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret)
 | 
			
		||||
{
 | 
			
		||||
	aiocbp->data = (void *)1;
 | 
			
		||||
	aiocbp->aio_cb = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_io(struct blkfront_aiocb *aiocbp, int write)
 | 
			
		||||
{
 | 
			
		||||
	aiocbp->aio_cb = blkfront_aio_cb;
 | 
			
		||||
	blkfront_aio(aiocbp, write);
 | 
			
		||||
	aiocbp->data = NULL;
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		blkfront_aio_poll(aiocbp->aio_dev);
 | 
			
		||||
		if (aiocbp->data)
 | 
			
		||||
			break;
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_push_operation(struct blkfront_dev *dev, u8 op,
 | 
			
		||||
				    uint64_t id)
 | 
			
		||||
{
 | 
			
		||||
	struct blkif_request *req;
 | 
			
		||||
	int notify, i;
 | 
			
		||||
 | 
			
		||||
	blkfront_wait_slot(dev);
 | 
			
		||||
	i = dev->ring.req_prod_pvt;
 | 
			
		||||
	req = RING_GET_REQUEST(&dev->ring, i);
 | 
			
		||||
	req->operation = op;
 | 
			
		||||
	req->nr_segments = 0;
 | 
			
		||||
	req->handle = dev->handle;
 | 
			
		||||
	req->id = id;
 | 
			
		||||
	req->sector_number = 0;
 | 
			
		||||
	dev->ring.req_prod_pvt = i + 1;
 | 
			
		||||
	wmb();
 | 
			
		||||
	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
 | 
			
		||||
	if (notify)
 | 
			
		||||
		notify_remote_via_evtchn(dev->evtchn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkfront_sync(struct blkfront_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->info.mode == O_RDWR) {
 | 
			
		||||
		if (dev->info.barrier == 1)
 | 
			
		||||
			blkfront_push_operation(dev,
 | 
			
		||||
						BLKIF_OP_WRITE_BARRIER, 0);
 | 
			
		||||
 | 
			
		||||
		if (dev->info.flush == 1)
 | 
			
		||||
			blkfront_push_operation(dev,
 | 
			
		||||
						BLKIF_OP_FLUSH_DISKCACHE, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		blkfront_aio_poll(dev);
 | 
			
		||||
		if (RING_FREE_REQUESTS(&dev->ring) == RING_SIZE(&dev->ring))
 | 
			
		||||
			break;
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pvblock_iop() - Issue an aio.
 | 
			
		||||
 * @udev: Pvblock device
 | 
			
		||||
 * @blknr: Block number to read from / write to
 | 
			
		||||
 * @blkcnt: Amount of blocks to read / write
 | 
			
		||||
 * @buffer: Memory buffer with data to be read / write
 | 
			
		||||
 * @write: Describes is it read or write operation
 | 
			
		||||
 *	   0 - read
 | 
			
		||||
 *	   1 - write
 | 
			
		||||
 *
 | 
			
		||||
 * Depending on the operation - reading or writing, data is read / written from the
 | 
			
		||||
 * specified address (@buffer) to the sector (@blknr).
 | 
			
		||||
 */
 | 
			
		||||
static ulong pvblock_iop(struct udevice *udev, lbaint_t blknr,
 | 
			
		||||
			 lbaint_t blkcnt, void *buffer, int write)
 | 
			
		||||
{
 | 
			
		||||
	struct blkfront_dev *blk_dev = dev_get_priv(udev);
 | 
			
		||||
	struct blk_desc *desc = dev_get_uclass_platdata(udev);
 | 
			
		||||
	struct blkfront_aiocb aiocb;
 | 
			
		||||
	lbaint_t blocks_todo;
 | 
			
		||||
	bool unaligned;
 | 
			
		||||
 | 
			
		||||
	if (blkcnt == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if ((blknr + blkcnt) > desc->lba) {
 | 
			
		||||
		printf(DRV_NAME ": block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
 | 
			
		||||
		       blknr + blkcnt, desc->lba);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unaligned = (uintptr_t)buffer & (blk_dev->info.sector_size - 1);
 | 
			
		||||
 | 
			
		||||
	aiocb.aio_dev = blk_dev;
 | 
			
		||||
	aiocb.aio_offset = blknr * desc->blksz;
 | 
			
		||||
	aiocb.aio_cb = NULL;
 | 
			
		||||
	aiocb.data = NULL;
 | 
			
		||||
	blocks_todo = blkcnt;
 | 
			
		||||
	do {
 | 
			
		||||
		aiocb.aio_buf = unaligned ? blk_dev->bounce_buffer : buffer;
 | 
			
		||||
 | 
			
		||||
		if (write && unaligned)
 | 
			
		||||
			memcpy(blk_dev->bounce_buffer, buffer, desc->blksz);
 | 
			
		||||
 | 
			
		||||
		aiocb.aio_nbytes = unaligned ? desc->blksz :
 | 
			
		||||
			min((size_t)(BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE),
 | 
			
		||||
			    (size_t)(blocks_todo * desc->blksz));
 | 
			
		||||
 | 
			
		||||
		blkfront_io(&aiocb, write);
 | 
			
		||||
 | 
			
		||||
		if (!write && unaligned)
 | 
			
		||||
			memcpy(buffer, blk_dev->bounce_buffer, desc->blksz);
 | 
			
		||||
 | 
			
		||||
		aiocb.aio_offset += aiocb.aio_nbytes;
 | 
			
		||||
		buffer += aiocb.aio_nbytes;
 | 
			
		||||
		blocks_todo -= aiocb.aio_nbytes / desc->blksz;
 | 
			
		||||
	} while (blocks_todo > 0);
 | 
			
		||||
 | 
			
		||||
	return blkcnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ulong pvblock_blk_read(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
 | 
			
		||||
		       void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
	return pvblock_iop(udev, blknr, blkcnt, buffer, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ulong pvblock_blk_write(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
 | 
			
		||||
			const void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
	return pvblock_iop(udev, blknr, blkcnt, (void *)buffer, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pvblock_blk_bind(struct udevice *udev)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user