diff mbox series

[RESEND,v2,14/18] xen: pvblock: Read XenStore configuration and initialize

Message ID 20200806094301.4999-15-vicooodin@gmail.com
State Accepted
Commit 17c96f885134922f660e6c78519a4df73ae3c738
Delegated to: Tom Rini
Headers show
Series Add new board: Xen guest for ARM64 | expand

Commit Message

Anastasiia Lukianenko Aug. 6, 2020, 9:42 a.m. UTC
From: Anastasiia Lukianenko <anastasiia_lukianenko@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_andrushchenko@epam.com>
Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>
---

Changes since v1:
 - add comments
 - correct code style

 drivers/xen/pvblock.c | 285 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 284 insertions(+), 1 deletion(-)

Comments

Tom Rini Aug. 14, 2020, 7:51 p.m. UTC | #1
On Thu, Aug 06, 2020 at 12:42:57PM +0300, Anastasiia Lukianenko wrote:

> From: Anastasiia Lukianenko <anastasiia_lukianenko@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_andrushchenko@epam.com>
> Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>

Applied to u-boot/master, thanks!
diff mbox series

Patch

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;
 }