xen: pvblock: Read XenStore configuration and initialize
authorAnastasiia Lukianenko <anastasiia_lukianenko@epam.com>
Thu, 6 Aug 2020 09:42:57 +0000 (12:42 +0300)
committerTom Rini <trini@konsulko.com>
Fri, 14 Aug 2020 19:18:30 +0000 (15:18 -0400)
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_andrushchenko@epam.com>
Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>
drivers/xen/pvblock.c

index 3ed62ca..e247ce3 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
+ * (C) 2007-2008 Samuel Thibault.
  * (C) Copyright 2020 EPAM Systems Inc.
  */
 #include <blk.h>
 #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;
 }