From: Anastasiia Lukianenko <anastasiia_lukiane...@epam.com> Read essential virtual block device configuration data from XenStore, initialize front ring and event channel. Update block device description with actual block size.
Use code for XenStore from mini-os. Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushche...@epam.com> Signed-off-by: Anastasiia Lukianenko <anastasiia_lukiane...@epam.com> --- Changes since v1: - add comments - correct code style drivers/xen/pvblock.c | 285 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 1 deletion(-) diff --git a/drivers/xen/pvblock.c b/drivers/xen/pvblock.c index 3ed62cac5d..e247ce33a3 100644 --- a/drivers/xen/pvblock.c +++ b/drivers/xen/pvblock.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * (C) 2007-2008 Samuel Thibault. * (C) Copyright 2020 EPAM Systems Inc. */ #include <blk.h> @@ -9,26 +10,302 @@ #include <malloc.h> #include <part.h> +#include <asm/armv8/mmu.h> +#include <asm/io.h> +#include <asm/xen/system.h> + +#include <linux/compat.h> + +#include <xen/events.h> +#include <xen/gnttab.h> +#include <xen/hvm.h> #include <xen/xenbus.h> +#include <xen/interface/io/ring.h> +#include <xen/interface/io/blkif.h> +#include <xen/interface/io/protocols.h> + #define DRV_NAME "pvblock" #define DRV_NAME_BLK "pvblock_blk" +#define O_RDONLY 00 +#define O_RDWR 02 + +struct blkfront_info { + u64 sectors; + unsigned int sector_size; + int mode; + int info; + int barrier; + int flush; +}; + +/** + * struct blkfront_dev - Struct representing blkfront device + * @dom: Domain id + * @ring: Front_ring structure + * @ring_ref: The grant reference, allowing us to grant access + * to the ring to the other end/domain + * @evtchn: Event channel used to signal ring events + * @handle: Events handle + * @nodename: Device XenStore path in format "device/vbd/" + @devid + * @backend: Backend XenStore path + * @info: Private data + * @devid: Device id + */ struct blkfront_dev { - char dummy; + domid_t dom; + + struct blkif_front_ring ring; + grant_ref_t ring_ref; + evtchn_port_t evtchn; + blkif_vdev_t handle; + + char *nodename; + char *backend; + struct blkfront_info info; + unsigned int devid; }; struct blkfront_platdata { unsigned int devid; }; +static void free_blkfront(struct blkfront_dev *dev) +{ + mask_evtchn(dev->evtchn); + free(dev->backend); + + gnttab_end_access(dev->ring_ref); + free(dev->ring.sring); + + unbind_evtchn(dev->evtchn); + + 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; + char *err = NULL; + char *message = NULL; + struct blkif_sring *s; + int retry = 0; + char *msg = NULL; + char *c; + char nodename[32]; + char path[ARRAY_SIZE(nodename) + strlen("/backend-id") + 1]; + + sprintf(nodename, "device/vbd/%d", devid); + + memset(dev, 0, sizeof(*dev)); + dev->nodename = strdup(nodename); + dev->devid = devid; + + snprintf(path, sizeof(path), "%s/backend-id", nodename); + dev->dom = xenbus_read_integer(path); + evtchn_alloc_unbound(dev->dom, blkfront_handler, dev, &dev->evtchn); + + s = (struct blkif_sring *)memalign(PAGE_SIZE, PAGE_SIZE); + if (!s) { + printf("Failed to allocate shared ring\n"); + goto error; + } + + SHARED_RING_INIT(s); + FRONT_RING_INIT(&dev->ring, s, PAGE_SIZE); + + dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_pfn(s), 0); + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + printf("starting transaction\n"); + free(err); + } + + err = xenbus_printf(xbt, nodename, "ring-ref", "%u", dev->ring_ref); + if (err) { + message = "writing ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, "protocol", "%s", + XEN_IO_PROTO_ABI_NATIVE); + if (err) { + message = "writing protocol"; + goto abort_transaction; + } + + snprintf(path, sizeof(path), "%s/state", nodename); + err = xenbus_switch_state(xbt, path, XenbusStateConnected); + if (err) { + message = "switching state"; + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0, &retry); + free(err); + if (retry) { + goto again; + printf("completing transaction\n"); + } + + goto done; + +abort_transaction: + free(err); + err = xenbus_transaction_end(xbt, 1, &retry); + printf("Abort transaction %s\n", message); + goto error; + +done: + snprintf(path, sizeof(path), "%s/backend", nodename); + msg = xenbus_read(XBT_NIL, path, &dev->backend); + if (msg) { + printf("Error %s when reading the backend path %s\n", + msg, path); + goto error; + } + + dev->handle = strtoul(strrchr(nodename, '/') + 1, NULL, 0); + + { + XenbusState state; + char path[strlen(dev->backend) + + strlen("/feature-flush-cache") + 1]; + + snprintf(path, sizeof(path), "%s/mode", dev->backend); + msg = xenbus_read(XBT_NIL, path, &c); + if (msg) { + printf("Error %s when reading the mode\n", msg); + goto error; + } + if (*c == 'w') + dev->info.mode = O_RDWR; + else + dev->info.mode = O_RDONLY; + free(c); + + snprintf(path, sizeof(path), "%s/state", dev->backend); + + msg = NULL; + state = xenbus_read_integer(path); + while (!msg && state < XenbusStateConnected) + msg = xenbus_wait_for_state_change(path, &state); + if (msg || state != XenbusStateConnected) { + printf("backend not available, state=%d\n", state); + goto error; + } + + snprintf(path, sizeof(path), "%s/info", dev->backend); + dev->info.info = xenbus_read_integer(path); + + snprintf(path, sizeof(path), "%s/sectors", dev->backend); + /* + * FIXME: read_integer returns an int, so disk size + * limited to 1TB for now + */ + dev->info.sectors = xenbus_read_integer(path); + + snprintf(path, sizeof(path), "%s/sector-size", dev->backend); + dev->info.sector_size = xenbus_read_integer(path); + + snprintf(path, sizeof(path), "%s/feature-barrier", + dev->backend); + dev->info.barrier = xenbus_read_integer(path); + + snprintf(path, sizeof(path), "%s/feature-flush-cache", + dev->backend); + dev->info.flush = xenbus_read_integer(path); + } + unmask_evtchn(dev->evtchn); + + debug("%llu sectors of %u bytes\n", + dev->info.sectors, dev->info.sector_size); + return 0; + +error: + free(msg); + free(err); + free_blkfront(dev); + return -ENODEV; } static void shutdown_blkfront(struct blkfront_dev *dev) { + char *err = NULL, *err2; + XenbusState state; + + char path[strlen(dev->backend) + strlen("/state") + 1]; + char nodename[strlen(dev->nodename) + strlen("/event-channel") + 1]; + + debug("Close " DRV_NAME ", device ID %d\n", dev->devid); + + snprintf(path, sizeof(path), "%s/state", dev->backend); + snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename); + + if ((err = xenbus_switch_state(XBT_NIL, nodename, + XenbusStateClosing)) != NULL) { + printf("%s: error changing state to %d: %s\n", __func__, + XenbusStateClosing, err); + goto close; + } + + state = xenbus_read_integer(path); + while (!err && state < XenbusStateClosing) + err = xenbus_wait_for_state_change(path, &state); + free(err); + + if ((err = xenbus_switch_state(XBT_NIL, nodename, + XenbusStateClosed)) != NULL) { + printf("%s: error changing state to %d: %s\n", __func__, + XenbusStateClosed, err); + goto close; + } + + state = xenbus_read_integer(path); + while (state < XenbusStateClosed) { + err = xenbus_wait_for_state_change(path, &state); + free(err); + } + + if ((err = xenbus_switch_state(XBT_NIL, nodename, + XenbusStateInitialising)) != NULL) { + printf("%s: error changing state to %d: %s\n", __func__, + XenbusStateInitialising, err); + goto close; + } + + state = xenbus_read_integer(path); + while (!err && + (state < XenbusStateInitWait || state >= XenbusStateClosed)) + err = xenbus_wait_for_state_change(path, &state); + +close: + free(err); + + snprintf(nodename, sizeof(nodename), "%s/ring-ref", dev->nodename); + err2 = xenbus_rm(XBT_NIL, nodename); + free(err2); + snprintf(nodename, sizeof(nodename), "%s/event-channel", dev->nodename); + err2 = xenbus_rm(XBT_NIL, nodename); + free(err2); + + if (!err) + free_blkfront(dev); } ulong pvblock_blk_read(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt, @@ -73,6 +350,7 @@ static int pvblock_blk_probe(struct udevice *udev) { struct blkfront_dev *blk_dev = dev_get_priv(udev); struct blkfront_platdata *platdata = dev_get_platdata(udev); + struct blk_desc *desc = dev_get_uclass_platdata(udev); int ret, devid; devid = platdata->devid; @@ -81,6 +359,11 @@ static int pvblock_blk_probe(struct udevice *udev) ret = init_blkfront(devid, blk_dev); if (ret < 0) return ret; + + desc->blksz = blk_dev->info.sector_size; + desc->lba = blk_dev->info.sectors; + desc->log2blksz = LOG2(blk_dev->info.sector_size); + return 0; } -- 2.17.1