diff options
author | Anastasiia Lukianenko | 2020-08-06 12:42:56 +0300 |
---|---|---|
committer | Tom Rini | 2020-08-14 15:18:30 -0400 |
commit | a99931319e90229a85e9add500375d0357414cf2 (patch) | |
tree | 2238495af164bf7d54c59282bfb2b4b6e8e89b19 | |
parent | 722bc5b5d901eafb96e8530cc7cf3036bff398a4 (diff) |
xen: pvblock: Enumerate virtual block devices
Enumerate Xen virtual block devices found in XenStore and
instantiate pvblock devices.
Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | drivers/xen/pvblock.c | 112 |
1 files changed, 110 insertions, 2 deletions
diff --git a/drivers/xen/pvblock.c b/drivers/xen/pvblock.c index d2b616bb63b..3ed62cac5d0 100644 --- a/drivers/xen/pvblock.c +++ b/drivers/xen/pvblock.c @@ -6,6 +6,10 @@ #include <common.h> #include <dm.h> #include <dm/device-internal.h> +#include <malloc.h> +#include <part.h> + +#include <xen/xenbus.h> #define DRV_NAME "pvblock" #define DRV_NAME_BLK "pvblock_blk" @@ -14,6 +18,10 @@ struct blkfront_dev { char dummy; }; +struct blkfront_platdata { + unsigned int devid; +}; + static int init_blkfront(unsigned int devid, struct blkfront_dev *dev) { return 0; @@ -37,15 +45,40 @@ ulong pvblock_blk_write(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt, static int pvblock_blk_bind(struct udevice *udev) { + struct blk_desc *desc = dev_get_uclass_platdata(udev); + int devnum; + + desc->if_type = IF_TYPE_PVBLOCK; + /* + * Initialize the devnum to -ENODEV. This is to make sure that + * blk_next_free_devnum() works as expected, since the default + * value 0 is a valid devnum. + */ + desc->devnum = -ENODEV; + devnum = blk_next_free_devnum(IF_TYPE_PVBLOCK); + if (devnum < 0) + return devnum; + desc->devnum = devnum; + desc->part_type = PART_TYPE_UNKNOWN; + desc->bdev = udev; + + strncpy(desc->vendor, "Xen", sizeof(desc->vendor)); + strncpy(desc->revision, "1", sizeof(desc->revision)); + strncpy(desc->product, "Virtual disk", sizeof(desc->product)); + return 0; } static int pvblock_blk_probe(struct udevice *udev) { struct blkfront_dev *blk_dev = dev_get_priv(udev); - int ret; + struct blkfront_platdata *platdata = dev_get_platdata(udev); + int ret, devid; - ret = init_blkfront(0, blk_dev); + devid = platdata->devid; + free(platdata); + + ret = init_blkfront(devid, blk_dev); if (ret < 0) return ret; return 0; @@ -79,6 +112,68 @@ U_BOOT_DRIVER(pvblock_blk) = { * Para-virtual block device class *******************************************************************************/ +typedef int (*enum_vbd_callback)(struct udevice *parent, unsigned int devid); + +static int on_new_vbd(struct udevice *parent, unsigned int devid) +{ + struct driver_info info; + struct udevice *udev; + struct blkfront_platdata *platdata; + int ret; + + debug("New " DRV_NAME_BLK ", device ID %d\n", devid); + + platdata = malloc(sizeof(struct blkfront_platdata)); + if (!platdata) { + printf("Failed to allocate platform data\n"); + return -ENOMEM; + } + + platdata->devid = devid; + + info.name = DRV_NAME_BLK; + info.platdata = platdata; + + ret = device_bind_by_name(parent, false, &info, &udev); + if (ret < 0) { + printf("Failed to bind " DRV_NAME_BLK " to device with ID %d, ret: %d\n", + devid, ret); + free(platdata); + } + return ret; +} + +static int xenbus_enumerate_vbd(struct udevice *udev, enum_vbd_callback clb) +{ + char **dirs, *msg; + int i, ret; + + msg = xenbus_ls(XBT_NIL, "device/vbd", &dirs); + if (msg) { + printf("Failed to read device/vbd directory: %s\n", msg); + free(msg); + return -ENODEV; + } + + for (i = 0; dirs[i]; i++) { + int devid; + + sscanf(dirs[i], "%d", &devid); + ret = clb(udev, devid); + if (ret < 0) + goto fail; + + free(dirs[i]); + } + ret = 0; + +fail: + for (; dirs[i]; i++) + free(dirs[i]); + free(dirs); + return ret; +} + void pvblock_init(void) { struct driver_info info; @@ -105,6 +200,19 @@ void pvblock_init(void) static int pvblock_probe(struct udevice *udev) { + struct uclass *uc; + int ret; + + if (xenbus_enumerate_vbd(udev, on_new_vbd) < 0) + return -ENODEV; + + ret = uclass_get(UCLASS_BLK, &uc); + if (ret) + return ret; + uclass_foreach_dev_probe(UCLASS_BLK, udev) { + if (_ret) + return _ret; + }; return 0; } |