From: Utkarsh Verma <[email protected]> Extend the VOF client interface to support block device I/O through the sPAPR SCSI disk, which is needed by bootloaders such as GRUB during VOF disk boot.
Add BlockBackend and position tracking fields to OfInstance and use them in vof_seek(), vof_write() and vof_read() to extend their functionality to handle block devices as well. In vof_do_open(), detect FDT nodes named "disk@<srp-lun>" and resolve the SRP LUN encoding to the matching SCSIDevice/BlockBackend by scanning id/channel/lun. Add vof_seek() to implement the OpenFirmware "seek" client service, which was previously missing. AI-used-for: code Signed-off-by: Utkarsh Verma <[email protected]> --- hw/ppc/trace-events | 2 + hw/ppc/vof.c | 116 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index dbdcfada26..a61398ecb2 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -78,6 +78,7 @@ vof_error_unknown_service(const char *service, int nargs, int nret) "\"%s\" args vof_error_unknown_method(const char *method) "\"%s\"" vof_error_unknown_ihandle_close(uint32_t ih) "ih=0x%x" vof_error_unknown_path(const char *path) "\"%s\"" +vof_error_seek(uint32_t ih) "ih=0x%x" vof_error_write(uint32_t ih) "ih=0x%x" vof_error_read(uint32_t ih) "ih=0x%x" vof_finddevice(const char *path, uint32_t ph) "\"%s\" => ph=0x%x" @@ -92,6 +93,7 @@ vof_interpret(const char *cmd, uint32_t param1, uint32_t param2, uint32_t ret, u vof_package_to_path(uint32_t ph, const char *tmp, int ret) "ph=0x%x => %s len=%d" vof_instance_to_path(uint32_t ih, uint32_t ph, const char *tmp, int ret) "ih=0x%x ph=0x%x => %s len=%d" vof_instance_to_package(uint32_t ih, uint32_t ph) "ih=0x%x => ph=0x%x" +vof_seek(uint32_t ih, uint64_t pos) "ih=0x%x pos=0x%"PRIx64 vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\"" vof_read(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\"" vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64 diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c index 45c197df9f..b1c574aabf 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/timer.h" #include "qemu/range.h" #include "qemu/units.h" @@ -24,6 +25,8 @@ #include "trace.h" #include "hw/ppc/spapr_vio.h" +#include "hw/scsi/scsi.h" +#include "system/block-backend.h" #include <libfdt.h> /* @@ -46,6 +49,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; @@ -449,6 +454,7 @@ static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path) { uint32_t ret = PROM_ERROR; OfInstance *inst = NULL; + const char *node_name; if (vof->of_instance_last == 0xFFFFFFFF) { /* We do not recycle ihandles yet */ @@ -461,10 +467,42 @@ static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path) ++vof->of_instance_last; inst->path = g_strdup(path); + inst->blk = NULL; + inst->pos = 0; inst->vty = NULL; + node_name = fdt_get_name(fdt, offset, NULL); + + if (node_name && strncmp(node_name, "disk@", 5) == 0) { + uint64_t srp_lun; + uint32_t id, channel, lun; + BlockBackend *blk; + + if (qemu_strtou64(node_name + 5, NULL, 16, &srp_lun) == 0) { + id = (srp_lun >> 56) & 0x3f; + channel = (srp_lun >> 53) & 0x7; + lun = (srp_lun >> 48) & 0x1f; + + for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { + DeviceState *attached = blk_get_attached_dev(blk); + SCSIDevice *sdev; + + if (!attached) { + continue; + } + sdev = (SCSIDevice *)object_dynamic_cast(OBJECT(attached), + TYPE_SCSI_DEVICE); + if (sdev && sdev->id == (int)id && + sdev->channel == (int)channel && + sdev->lun == (int)lun) { + inst->blk = blk; + break; + } + } + } + } + #ifdef CONFIG_PSERIES - const char *node_name = fdt_get_name(fdt, offset, NULL); if (node_name && strncmp(node_name, "vty", 3) == 0) { uint8_t discard_buf[VOF_VTY_BUF_SIZE]; MachineState *ms = MACHINE(qdev_get_machine()); @@ -601,6 +639,25 @@ static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf, return PROM_ERROR; } + if (inst->blk) { + g_autofree uint8_t *blkbuf = g_malloc(len); + int ret; + + if (VOF_MEM_READ(buf, blkbuf, len) != MEMTX_OK) { + trace_vof_error_write(ihandle); + return PROM_ERROR; + } + ret = blk_pwrite(inst->blk, inst->pos, len, blkbuf, 0); + if (ret < 0) { + trace_vof_error_write(ihandle); + return PROM_ERROR; + } + blk_flush(inst->blk); + inst->pos += len; + trace_vof_write(ihandle, len, "(disk)"); + return len; + } + #ifdef CONFIG_PSERIES if (inst->vty) { uint32_t total_written = 0; @@ -646,6 +703,26 @@ static uint32_t vof_read(Vof *vof, uint32_t ihandle, uint32_t buf, return PROM_ERROR; } + if (inst->blk) { + g_autofree uint8_t *tmp = g_malloc(len); + int ret; + + ret = blk_pread(inst->blk, inst->pos, len, tmp, 0); + if (ret < 0) { + trace_vof_error_read(ihandle); + return PROM_ERROR; + } + + if (VOF_MEM_WRITE(buf, tmp, len) != MEMTX_OK) { + trace_vof_error_read(ihandle); + return PROM_ERROR; + } + + inst->pos += len; + trace_vof_read(ihandle, len, "(disk)"); + return len; + } + #ifdef CONFIG_PSERIES if (inst->vty) { uint8_t tmp[VOF_VTY_BUF_SIZE]; @@ -675,6 +752,41 @@ static uint32_t vof_read(Vof *vof, uint32_t ihandle, uint32_t buf, return 0; } +static uint32_t vof_seek(Vof *vof, uint32_t ihandle, uint32_t pos_hi, + uint32_t pos_lo) +{ + OfInstance *inst = (OfInstance *) + g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle)); + uint64_t pos = ((uint64_t)pos_hi << 32) | pos_lo; + + if (!inst) { + trace_vof_error_seek(ihandle); + return PROM_ERROR; + } + + if (inst->blk) { + int64_t size = blk_getlength(inst->blk); + + if (size < 0) { + trace_vof_error_seek(ihandle); + return PROM_ERROR; + } + + if (pos > (uint64_t)size) { + trace_vof_error_seek(ihandle); + return PROM_ERROR; + } + + inst->pos = pos; + trace_vof_seek(ihandle, pos); + return 0; + } + + /* VTY and other devices don't support seek */ + trace_vof_error_seek(ihandle); + return PROM_ERROR; +} + static void vof_claimed_dump(GArray *claimed) { int i; @@ -985,6 +1097,8 @@ static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof, ret = vof_package_to_path(fdt, args[0], args[1], args[2]); } else if (cmpserv("instance-to-path", 3, 1)) { ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]); + } else if (cmpserv("seek", 3, 1)) { + ret = vof_seek(vof, args[0], args[1], args[2]); } else if (cmpserv("write", 3, 1)) { ret = vof_write(vof, args[0], args[1], args[2]); } else if (cmpserv("read", 3, 1)) { -- 2.54.0
