Hello,

On Thu, 8 Oct 2026, Utkarsh Verma wrote:
[...]
diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index 6f6d424347..d4b57b3b46 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -11,6 +11,7 @@

#include CONFIG_DEVICES /* CONFIG_PSERIES */
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "qemu/ctype.h"
#include "qemu/timer.h"
#include "qemu/range.h"
@@ -25,6 +26,9 @@
#include "trace.h"

#include "hw/ppc/spapr_vio.h"
+#include "hw/scsi/scsi.h"
+#include "system/block-backend.h"
+#include "block/block-io.h"
#include <libfdt.h>

/*
@@ -38,6 +42,7 @@
#define VOF_MAX_METHODLEN   256
#define VOF_MAX_FORTHCODE   256
#define VOF_VTY_BUF_SIZE    256
+#define VOF_BLK_BUF_SIZE    (64 * 1024)

* KiB instead of 1024?

Sure, will use KiB and fix it for SPAPR_VOF_PREP_MAX_SIZE in spapr_vof.c as well in v3.

Sorry for taking that long to review which caused you needing to prepare another version but I have little time for QEMU now and generally don't like to be first to review AI generated patches so I hoped somebody else could do a review. Since the list is already high volume, if you agree with a change it's OK to just include it in next version and you don't have to reply for those with "OK, I'll do that" here, unless you have a comment or question about it or answering a question asked.


typedef struct {
    uint64_t start;
@@ -47,6 +52,8 @@ typedef struct {
typedef struct {
    char *path; /* the path used to open the instance */
    uint32_t phandle;
+    BlockBackend *blk;
+    uint64_t pos; /* current position for seek operations */
    void *vty;
} OfInstance;

@@ -138,6 +145,8 @@ static int path_offset(const void *fdt, const char *path)
{
    g_autofree char *p = NULL;
    char *at;
+    char *last_slash;
+    int offset;

    /*
     * https://www.devicetree.org/open-firmware/bindings/ppc/release/ ppc-2_1.html#HDR16 @@ -156,7 +165,76 @@ static int path_offset(const void *fdt, const char *path)
            }
    }

-    return fdt_path_offset(fdt, p);
+    offset = fdt_path_offset(fdt, p);
+    if (offset >= 0) {
+        return offset;
+    }
+
+    /*
+     * Apply the OF wildcard rule for vSCSI disk paths. A path ending in
+     * disk@<srp-lun> has no per-LUN FDT node, instead the FDT contains a single +     * generic "disk" child (no srp-lun appended to the path). The phandle is +     * shared by all LUNs on the adapter, matching the Open Firmware behaviour.
+     */
+    last_slash = strrchr(p, '/');
+    if (last_slash && strncmp(last_slash + 1, "disk@", 5) == 0) {
+        int parent_off;
+
+        *last_slash = '\0';
+        parent_off = fdt_path_offset(fdt, p);
+        if (parent_off >= 0) {
+            int child_off = fdt_subnode_offset(fdt, parent_off, "disk");

I'm not sure how this should work but what if there are multiple disk nodes such as disk@0 disk@1 or similar? Should this look for the original ending of the path instead of just "disk"?

There is only one "disk" child node under the vSCSI adapter regardless of how many physical disks are attached. It seems a little weird that only one disk node is created even for multiple vSCSI disks, but that is the actual open firmware behaviour, I cross checked with the device tree data on a pseries LPAR machine and with the SLOF implementation of it as well. So, the GRUB only searches for a "disk" child node under the vscsi adapter and then calls the vscsi-report-luns method to get the full path of the individual disks and passes the same path to firmware while calling open. So, GRUB doesn't rely on FDT disk data to search the disk, it calls the vscs-report-luns method to get the full disk path. This is why I strip the @<srp-lun> part in the path before searching the FDT, the node it needs to resolve to is always the shared "disk" child node.

We're in in the common vof.c file here which is a generic OpenFirmware implementation and is shared with pegasos (and later could be used by other machines needing OpenFirmware). On pegasos2 for example we can have /pci/ide/disk@0,0, /pci/ide/disk@0,1, /pci/ide/disk@1,0 and /pci/ide/disk@1,1 for 4 IDE disks so this change may break clients accessing those device nodes. So likely you need to avoid changing this function but maybe by moving all the other stuff to spapr_vof.c this will not be needed here any more and can be handled in spapr_vof.c. If you find you're trying to change vof.c for something specific to spapr then think again because anything spapr specific should be in spapr_vof.c.

I've also noticed pegasos1 sets boot-device to /pci/ide/disk@0,0:0 where :0 is showing the partition so that is a generic OF thing that could be handled here in vof.c but that could be fixed later as well. To make it easy to use this block device support by other machines in the future, the functions to be added to VofMachineIfClass should be chosen to do the machine specific mapping between OpenFirmware nodes to generic QEMU constructs and then the code here can work on those without needing to be machine specific. E.g. I'm not sure requiring machines to implement vty_open/read/write is necessary and if it could be done more generically with just one function mapping an OF device node to something that can be used here like for block device the mapping function returns a blk device for an OF device node. That would also make machine code simpler as it does not have to talk to the device just return the QEMU struct to vof and reduce code duplication between machines. But I don't know what would be the right QEMU construct for a vty, maybe a chardev?

Regards,
BALATON Zoltan

Reply via email to