From: Denis Mukhin <[email protected]> 

Add bootdev_hunt_fallthrough() test to verify that 'bootflow scan -l'
falls back to a lower-priority bootdev when a higher-priority hunter
fails.

Introduce a simple 'sandbox-bootdev' device for the test. The new
bootdev can be configured to produce an error at the hunting stage.

Introduce new host_set_flags_by_label() API and a flags field to
'host_sb_plat' to simulate a bootdev hunter failure for the test.

Adjust boot{dev,flow} tests which depend on bootdev hunters.

Signed-off-by: Denis Mukhin <[email protected]>
---
Changes since v4:
- addresses feedback from Simon:
  
https://lore.kernel.org/u-boot/CAFLszThk7mWg+7LrVcN9xY5owrpUwhCTLdf=xhi0k-m-upk...@mail.gmail.com/

Changes since v3:
- addressed feedback from Simon:
  
https://lore.kernel.org/u-boot/caflsztgu3x2gutny3og3+hxauukrgu9di7-ogbm3xap8zrv...@mail.gmail.com/

Changes since v2:
- dropped 'flags' from 'host_priv'
- added description for 'flags' in host_sb_plat
- switched to log_xxx() calls in sandbox-bootdev.c
- corrected sandbox_bootdev_hunt()
- updated boot{dev,flow} tests which depend on bootdev hunters

Changes since v1:
- new patch
---
 drivers/block/Makefile          |  2 +-
 drivers/block/host-uclass.c     | 15 +++++++
 drivers/block/sandbox-bootdev.c | 73 +++++++++++++++++++++++++++++++++
 include/sandbox_host.h          | 18 ++++++++
 test/boot/bootdev.c             | 23 ++++++-----
 test/boot/bootflow.c            | 47 +++++++++++++++++++++
 test/boot/bootstd_common.h      |  5 ++-
 7 files changed, 170 insertions(+), 13 deletions(-)
 create mode 100644 drivers/block/sandbox-bootdev.c

diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index f5a9d8637a3c..c827fa81a2d8 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -13,7 +13,7 @@ ifndef CONFIG_XPL_BUILD
 obj-$(CONFIG_IDE) += ide.o
 obj-$(CONFIG_RKMTD) += rkmtd.o
 endif
-obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o
+obj-$(CONFIG_SANDBOX) += sandbox.o sandbox-bootdev.o host-uclass.o host_dev.o
 obj-$(CONFIG_$(PHASE_)BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap.o
 obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap_helper.o
diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c
index cf42bd1e07ac..95b0b0b2ffea 100644
--- a/drivers/block/host-uclass.c
+++ b/drivers/block/host-uclass.c
@@ -150,6 +150,21 @@ struct udevice *host_find_by_label(const char *label)
        return NULL;
 }
 
+int host_set_flags_by_label(const char *label, unsigned int flags)
+{
+       struct udevice *dev;
+       struct host_sb_plat *plat;
+
+       dev = host_find_by_label(label);
+       if (!dev)
+               return -ENODEV;
+
+       plat = dev_get_plat(dev);
+       plat->flags = flags;
+
+       return 0;
+}
+
 struct udevice *host_get_cur_dev(void)
 {
        struct uclass *uc = uclass_find(UCLASS_HOST);
diff --git a/drivers/block/sandbox-bootdev.c b/drivers/block/sandbox-bootdev.c
new file mode 100644
index 000000000000..15af0c17d1fa
--- /dev/null
+++ b/drivers/block/sandbox-bootdev.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#define LOG_CATEGORY   UCLASS_HOST
+
+#include <bootdev.h>
+#include <dm.h>
+#include <log.h>
+#include <sandbox_host.h>
+
+static int sandbox_bootdev_bind(struct udevice *dev)
+{
+       struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+       ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+       return 0;
+}
+
+/**
+ * sandbox_bootdev_hunt() - Hunt host bootdev.
+ *
+ * Note, this hunter exists for bootdev testing to simulate a failure
+ * mode.  Do not use as an example of a real hunter.
+ *
+ * @info: Hunter details.
+ * @show: Enable extra printouts.
+ *
+ * Returns: 0 if OK, -ve on error (expected by the test)
+ */
+static int sandbox_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int ret;
+
+       uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
+               struct host_sb_plat *plat = dev_get_plat(dev);
+
+               log_debug("hunting %s\n", plat->label);
+
+               if (plat->flags & HOST_FLAG_BROKEN) {
+                       ret = -ETIME;
+                       log_debug("cannot hunt sandbox device '%s': %d\n",
+                                 plat->label, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct bootdev_ops sandbox_bootdev_ops = {
+};
+
+static const struct udevice_id sandbox_bootdev_ids[] = {
+       { .compatible = "u-boot,bootdev-sandbox" },
+       { }
+};
+
+U_BOOT_DRIVER(sandbox_bootdev) = {
+       .name           = "sandbox_bootdev",
+       .id             = UCLASS_BOOTDEV,
+       .ops            = &sandbox_bootdev_ops,
+       .bind           = sandbox_bootdev_bind,
+       .of_match       = sandbox_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(sandbox_bootdev_hunter) = {
+       .prio           = BOOTDEVP_4_SCAN_FAST,
+       .uclass         = UCLASS_HOST,
+       .hunt           = sandbox_bootdev_hunt,
+       .drv            = DM_DRIVER_REF(sandbox_bootdev),
+};
diff --git a/include/sandbox_host.h b/include/sandbox_host.h
index f7a5fc672300..1330358ef7ab 100644
--- a/include/sandbox_host.h
+++ b/include/sandbox_host.h
@@ -8,17 +8,26 @@
 #ifndef __SANDBOX_HOST__
 #define __SANDBOX_HOST__
 
+/**
+ * Device flags.
+ */
+enum host_platform_flags {
+       HOST_FLAG_BROKEN                = BIT(0), /** Simulate broken device */
+};
+
 /**
  * struct host_sb_plat - platform data for a host device
  *
  * @label: Label for this device (allocated)
  * @filename: Name of file this is attached to, or NULL (allocated)
  * @fd: File descriptor of file, or 0 for none (file is not open)
+ * @flags: Device flags (e.g. for unit tests).
  */
 struct host_sb_plat {
        char *label;
        char *filename;
        int fd;
+       unsigned int flags;
 };
 
 /**
@@ -122,4 +131,13 @@ struct udevice *host_get_cur_dev(void);
  */
 void host_set_cur_dev(struct udevice *dev);
 
+/**
+ * host_set_flags_by_label() - Set the host device test flags
+ *
+ * @label: Label of the attachment, e.g. "test1"
+ * @flags: Device flags
+ * Returns: 0 if OK, -ve on error
+ */
+int host_set_flags_by_label(const char *label, unsigned int flags);
+
 #endif /* __SANDBOX_HOST__ */
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c
index 0820bf10ee08..c2eaf0b2c559 100644
--- a/test/boot/bootdev.c
+++ b/test/boot/bootdev.c
@@ -384,19 +384,19 @@ static int bootdev_test_hunter(struct unit_test_state 
*uts)
        ut_assert_nextline("   2        mmc              mmc_bootdev");
        ut_assert_nextline("   4        nvme             nvme_bootdev");
        ut_assert_nextline("   4        qfw              qfw_bootdev");
+       ut_assert_nextline("   4        host             sandbox_bootdev");
        ut_assert_nextline("   4        scsi             scsi_bootdev");
        ut_assert_nextline("   4        spi_flash        sf_bootdev");
        ut_assert_nextline("   5        usb              usb_bootdev");
        ut_assert_nextline("   4        virtio           virtio_bootdev");
-       ut_assert_nextline("(total hunters: 9)");
+       ut_assert_nextline("(total hunters: 10)");
        ut_assert_console_end();
 
        ut_assertok(bootdev_hunt("usb1", false));
        ut_assert_skip_to_line("Bus usb@1: 5 USB Device(s) found");
        ut_assert_console_end();
 
-       /* USB is 8th in the list, so bit 7 */
-       ut_asserteq(BIT(7), std->hunters_used);
+       ut_asserteq(BIT(USB_HUNTER), std->hunters_used);
 
        return 0;
 }
@@ -417,7 +417,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state 
*uts)
        ut_assert_nextline("Prio  Used  Uclass           Hunter");
        ut_assert_nextlinen("----");
        ut_assert_nextline("   6        ethernet         eth_bootdev");
-       ut_assert_skip_to_line("(total hunters: 9)");
+       ut_assert_skip_to_line("(total hunters: 10)");
        ut_assert_console_end();
 
        /* Use the MMC hunter and see that it updates */
@@ -425,7 +425,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state 
*uts)
        ut_assertok(run_command("bootdev hunt -l", 0));
        ut_assert_skip_to_line("   5        ide              ide_bootdev");
        ut_assert_nextline("   2     *  mmc              mmc_bootdev");
-       ut_assert_skip_to_line("(total hunters: 9)");
+       ut_assert_skip_to_line("(total hunters: 10)");
        ut_assert_console_end();
 
        /* Scan all hunters */
@@ -441,6 +441,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state 
*uts)
 
        ut_assert_nextline("Hunting with: nvme");
        ut_assert_nextline("Hunting with: qfw");
+       ut_assert_nextline("Hunting with: host");
        ut_assert_nextline("Hunting with: scsi");
        ut_assert_nextline("scanning bus for devices...");
        ut_assert_skip_to_line("Hunting with: spi_flash");
@@ -458,11 +459,12 @@ static int bootdev_test_cmd_hunt(struct unit_test_state 
*uts)
        ut_assert_nextline("   2     *  mmc              mmc_bootdev");
        ut_assert_nextline("   4     *  nvme             nvme_bootdev");
        ut_assert_nextline("   4     *  qfw              qfw_bootdev");
+       ut_assert_nextline("   4     *  host             sandbox_bootdev");
        ut_assert_nextline("   4     *  scsi             scsi_bootdev");
        ut_assert_nextline("   4     *  spi_flash        sf_bootdev");
        ut_assert_nextline("   5     *  usb              usb_bootdev");
        ut_assert_nextline("   4     *  virtio           virtio_bootdev");
-       ut_assert_nextline("(total hunters: 9)");
+       ut_assert_nextline("(total hunters: 10)");
        ut_assert_console_end();
 
        ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used);
@@ -646,8 +648,7 @@ static int bootdev_test_next_label(struct unit_test_state 
*uts)
        ut_asserteq_str("scsi.id0lun0.bootdev", dev->name);
        ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
 
-       /* SCSI is 6th in the list, so bit 5 */
-       ut_asserteq(BIT(MMC_HUNTER) | BIT(5), std->hunters_used);
+       ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER), std->hunters_used);
 
        ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
        ut_assert_console_end();
@@ -657,7 +658,7 @@ static int bootdev_test_next_label(struct unit_test_state 
*uts)
                    mflags);
 
        /* dhcp: Ethernet is first so bit 0 */
-       ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
+       ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), 
std->hunters_used);
 
        ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
        ut_assert_console_end();
@@ -667,7 +668,7 @@ static int bootdev_test_next_label(struct unit_test_state 
*uts)
                    mflags);
 
        /* pxe: Ethernet is first so bit 0 */
-       ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
+       ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), 
std->hunters_used);
 
        mflags = 123;
        ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags));
@@ -675,7 +676,7 @@ static int bootdev_test_next_label(struct unit_test_state 
*uts)
        ut_assert_console_end();
 
        /* no change */
-       ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
+       ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), 
std->hunters_used);
 
        return 0;
 }
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 56ee1952357b..1cc137c97005 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -19,6 +19,8 @@
 #include <mapmem.h>
 #ifdef CONFIG_SANDBOX
 #include <asm/test.h>
+#include <sandbox_host.h>
+#include <os.h>
 #endif
 #include <dm/device-internal.h>
 #include <dm/lists.h>
@@ -1532,3 +1534,48 @@ static int bootstd_images(struct unit_test_state *uts)
        return 0;
 }
 BOOTSTD_TEST(bootstd_images, UTF_CONSOLE);
+
+#if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL)
+/*
+ * Check that bootdev scanning does not stop if higher-priority bootdevs
+ * are failed to be hunted.
+ */
+static int bootdev_hunt_fallthrough(struct unit_test_state *uts)
+{
+       struct bootstd_priv *std;
+       struct udevice *dev;
+
+       ut_assertok(bootstd_get_priv(&std));
+       bootstd_test_drop_bootdev_order(uts);
+       test_set_skip_delays(true);
+       bootstd_reset_usb();
+       console_record_reset_enable();
+
+       /*
+        * Create a sandbox block device (BOOTDEVP_4_SCAN_FAST) and mark it as
+        * broken so that bootdev_hunt_prio() returns an error.
+        */
+       ut_asserteq(0, uclass_id_count(UCLASS_HOST));
+       ut_assertok(host_create_device("test", true, DEFAULT_BLKSZ, &dev));
+       ut_assertok(host_set_flags_by_label("test", HOST_FLAG_BROKEN));
+       ut_asserteq(1, uclass_id_count(UCLASS_HOST));
+
+       /*
+        * Scan with hunting.
+        * The sandbox hunter at priority 4 must fail, but the USB hunter at
+        * priority 5 must still be reached.
+        */
+       ut_assertok(run_command("bootflow scan -l", 0));
+
+       ut_assert(!(std->hunters_used & BIT(HOST_HUNTER)));
+       ut_assert_skip_to_line("Hunting with: host");
+
+       /* USB was hunted despite the sandbox hunter failure */
+       ut_assert(std->hunters_used & BIT(USB_HUNTER));
+       ut_assert_skip_to_line("Bus usb@1: 5 USB Device(s) found");
+
+       return 0;
+}
+BOOTSTD_TEST(bootdev_hunt_fallthrough,
+             UTF_DM | UTF_SCAN_FDT | UTF_SF_BOOTDEV | UTF_CONSOLE);
+#endif /* CONFIG_SANDBOX */
diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h
index dd769313a842..672917454a31 100644
--- a/test/boot/bootstd_common.h
+++ b/test/boot/bootstd_common.h
@@ -21,8 +21,11 @@
 #define TEST_VERNUM            0x00010002
 
 enum {
-       MAX_HUNTER      = 8,
        MMC_HUNTER      = 2,    /* ID of MMC hunter */
+       HOST_HUNTER     = 5,
+       SCSI_HUNTER     = 6,
+       USB_HUNTER      = 8,
+       MAX_HUNTER      = 9,
 };
 
 struct unit_test_state;
-- 
2.54.0

Reply via email to