summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-02-07 10:49:53 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2022-02-08 12:36:13 +0100
commitb03cba067bd70e472d8ca67160f2928c4d4e2500 (patch)
treeb735330b0eaf7b343244a340c24b0d71bc83327b /drivers
parent80ee6ce0c011b09f39af7627893d395bf0d51e0d (diff)
downloadbarebox-b03cba067bd70e472d8ca67160f2928c4d4e2500.tar.gz
barebox-b03cba067bd70e472d8ca67160f2928c4d4e2500.tar.xz
misc: Add storage-by-uuid driver
This adds a driver which matches to a "barebox,storage-by-uuid" compatible node. The driver looks for a storage device matching the given UUID and when found registers a new cdev for the device. This driver solved a very specific problem. On EFI the storage devices are not connected to any device tree node. barebox-state however expects a node to use as its backend. The obvious solution would be to create a partition with a specific partuuid and use that for state, in our special usecase though the storage device is partitioned with a MBR which doesn't have any space left to create a new partition. As this driver parses the of partition binding we can use that to create a partition in an unallocated are of the disk which is then used for state. This driver has the problem that it depends on storage devices which are not described in the device tree. This means it cannot work with deep probe. This is not a problem on EFI though. It's a special purpose driver, it's not recommended for general use. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Link: https://lore.barebox.org/20220207094953.949868-8-s.hauer@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/Kconfig23
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/storage-by-uuid.c199
3 files changed, 223 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5ab0506cd9..78c9c193d8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -47,4 +47,27 @@ config STARFIVE_PWRSEQ
be accessed over /dev/mem or used from kernels which still depend
on bootloader for initialization.
+config STORAGE_BY_UUID
+ bool "storage by UUID"
+ depends on OFDEVICE
+ help
+ This adds a driver which matches to a "barebox,storage-by-uuid"
+ compatible node. The driver looks for a storage device matching the
+ given UUID and when found registers a new cdev for the device.
+
+ This driver solved a very specific problem. On EFI the storage devices
+ are not connected to any device tree node. barebox-state however expects
+ a node to use as its backend. The obvious solution would be to create
+ a partition with a specific partuuid and use that for state, in our
+ special usecase though the storage device is partitioned with a MBR
+ which doesn't have any space left to create a new partition. As this
+ driver parses the of partition binding we can use that to create
+ a partition in an unallocated are of the disk which is then used for
+ state.
+
+ This driver has the problem that it depends on storage devices which
+ are not described in the device tree. This means it cannot work with
+ deep probe. This is not a problem on EFI though. It's a special purpose
+ driver, it's not recommended for general use.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6326e784fc..986f7b1b38 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_STATE_DRV) += state.o
obj-$(CONFIG_DEV_MEM) += mem.o
obj-$(CONFIG_UBOOTVAR) += ubootvar.o
obj-$(CONFIG_STARFIVE_PWRSEQ) += starfive-pwrseq.o
+obj-$(CONFIG_STORAGE_BY_UUID) += storage-by-uuid.o
diff --git a/drivers/misc/storage-by-uuid.c b/drivers/misc/storage-by-uuid.c
new file mode 100644
index 0000000000..12a06076a2
--- /dev/null
+++ b/drivers/misc/storage-by-uuid.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <malloc.h>
+#include <partition.h>
+#include <envfs.h>
+#include <fs.h>
+
+static LIST_HEAD(sbu_list);
+
+struct sbu {
+ char *uuid;
+ struct device_d *dev;
+ struct cdev *rcdev;
+ struct cdev cdev;
+ struct list_head list;
+};
+
+void storage_by_uuid_check_exist(struct cdev *cdev);
+
+static ssize_t sbu_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_read(sbu->rcdev, buf, count, offset, flags);
+}
+
+static ssize_t sbu_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_write(sbu->rcdev, buf, count, offset, flags);
+}
+
+static int sbu_ioctl(struct cdev *cdev, int request, void *buf)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_ioctl(sbu->rcdev, request, buf);
+}
+
+static int sbu_open(struct cdev *cdev, unsigned long flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_open(sbu->rcdev, flags);
+}
+
+static int sbu_close(struct cdev *cdev)
+{
+ struct sbu *sbu = cdev->priv;
+
+ cdev_close(sbu->rcdev);
+
+ return 0;
+}
+
+static int sbu_flush(struct cdev *cdev)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_flush(sbu->rcdev);
+}
+
+static int sbu_erase(struct cdev *cdev, loff_t count, loff_t offset)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_erase(sbu->rcdev, count, offset);
+}
+
+static int sbu_protect(struct cdev *cdev, size_t count, loff_t offset, int prot)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_protect(sbu->rcdev, count, offset, prot);
+}
+
+static int sbu_discard_range(struct cdev *cdev, loff_t count, loff_t offset)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_discard_range(sbu->rcdev, count, offset);
+}
+
+static int sbu_memmap(struct cdev *cdev, void **map, int flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_memmap(sbu->rcdev, map, flags);
+}
+
+static int sbu_truncate(struct cdev *cdev, size_t size)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_truncate(sbu->rcdev, size);
+}
+
+static struct cdev_operations sbu_ops = {
+ .read = sbu_read,
+ .write = sbu_write,
+ .ioctl = sbu_ioctl,
+ .open = sbu_open,
+ .close = sbu_close,
+ .flush = sbu_flush,
+ .erase = sbu_erase,
+ .protect = sbu_protect,
+ .discard_range = sbu_discard_range,
+ .memmap = sbu_memmap,
+ .truncate = sbu_truncate,
+};
+
+static void storage_by_uuid_add_partitions(struct sbu *sbu, struct cdev *rcdev)
+{
+ int ret;
+
+ if (sbu->rcdev)
+ return;
+
+ sbu->rcdev = rcdev;
+ sbu->cdev.name = sbu->uuid;
+ sbu->cdev.size = rcdev->size;
+ sbu->cdev.ops = &sbu_ops;
+ sbu->cdev.dev = sbu->dev;
+ sbu->cdev.priv = sbu;
+
+ ret = devfs_create(&sbu->cdev);
+ if (ret) {
+ dev_err(sbu->dev, "Failed to create cdev: %s\n", strerror(-ret));
+ return;
+ }
+
+ of_parse_partitions(&sbu->cdev, sbu->dev->device_node);
+}
+
+static void check_exist(struct sbu *sbu)
+{
+ struct cdev *cdev;
+
+ for_each_cdev(cdev) {
+ if (!strcmp(cdev->uuid, sbu->uuid)) {
+ dev_dbg(sbu->dev, "Found %s %s\n", cdev->name, cdev->uuid);
+ storage_by_uuid_add_partitions(sbu, cdev);
+ }
+ }
+}
+
+static int sbu_detect(struct device_d *dev)
+{
+ struct sbu *sbu = dev->priv;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ check_exist(sbu);
+
+ return 0;
+}
+
+static int storage_by_uuid_probe(struct device_d *dev)
+{
+ struct sbu *sbu;
+ int ret;
+ const char *uuid;
+
+ sbu = xzalloc(sizeof(*sbu));
+
+ ret = of_property_read_string(dev->device_node, "uuid", &uuid);
+ if (ret)
+ return ret;
+
+ sbu->dev = dev;
+ sbu->uuid = xstrdup(uuid);
+
+ list_add_tail(&sbu->list, &sbu_list);
+
+ check_exist(sbu);
+ dev->priv = sbu;
+ dev->detect = sbu_detect;
+
+ return 0;
+}
+
+static struct of_device_id storage_by_uuid_dt_ids[] = {
+ {
+ .compatible = "barebox,storage-by-uuid",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d storage_by_uuid_driver = {
+ .name = "storage-by-uuid",
+ .probe = storage_by_uuid_probe,
+ .of_compatible = storage_by_uuid_dt_ids,
+};
+device_platform_driver(storage_by_uuid_driver);