On Wed, 2025-12-10 at 15:54 -0500, [email protected] wrote:
> From: Jared Rossi <[email protected]>
> 
> Separate the CCW specific virtio routines and create generic wrappers for 
> easier
> reuse of existing virtio functions with non-CCW devices.
> 
> Signed-off-by: Jared Rossi <[email protected]>
> ---
>  pc-bios/s390-ccw/s390-ccw.h      |   3 -
>  pc-bios/s390-ccw/virtio-ccw.h    |  24 +++
>  pc-bios/s390-ccw/virtio-scsi.h   |   2 +-
>  pc-bios/s390-ccw/virtio.h        |   7 +-
>  pc-bios/s390-ccw/main.c          |  10 +-
>  pc-bios/s390-ccw/netmain.c       |   2 +-
>  pc-bios/s390-ccw/virtio-blkdev.c |  15 +-
>  pc-bios/s390-ccw/virtio-ccw.c    | 242 +++++++++++++++++++++++++++++++
>  pc-bios/s390-ccw/virtio-net.c    |   5 +-
>  pc-bios/s390-ccw/virtio-scsi.c   |   6 +-
>  pc-bios/s390-ccw/virtio.c        | 237 +++++-------------------------
>  pc-bios/s390-ccw/Makefile        |   3 +-
>  12 files changed, 334 insertions(+), 222 deletions(-)
>  create mode 100644 pc-bios/s390-ccw/virtio-ccw.h
>  create mode 100644 pc-bios/s390-ccw/virtio-ccw.c
> 
> diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
> index 47ea66bd4d..ccd68ff0a4 100644
> --- a/pc-bios/s390-ccw/s390-ccw.h
> +++ b/pc-bios/s390-ccw/s390-ccw.h
> @@ -66,9 +66,6 @@ void sclp_setup(void);
>  void sclp_get_loadparm_ascii(char *loadparm);
>  int sclp_read(char *str, size_t count);
>  
> -/* virtio.c */
> -bool virtio_is_supported(SubChannelId schid);
> -
>  /* bootmap.c */
>  void zipl_load(void);
>  
> diff --git a/pc-bios/s390-ccw/virtio-ccw.h b/pc-bios/s390-ccw/virtio-ccw.h
> new file mode 100644
> index 0000000000..cdf6a55dc8
> --- /dev/null
> +++ b/pc-bios/s390-ccw/virtio-ccw.h
> @@ -0,0 +1,24 @@
> +/*
> + * Virtio definitions for CCW devices
> + *
> + * Copyright 2025 IBM Corp.
> + * Author(s): Jared Rossi <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef VIRTIO_CCW_H
> +#define VIRTIO_CCW_H
> +
> +/* main.c */
> +extern SubChannelId blk_schid;
> +
> +/* virtio-ccw.c */
> +int drain_irqs_ccw(SubChannelId schid);
> +bool virtio_ccw_is_supported(SubChannelId schid);
> +int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd);
> +long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie);
> +int virtio_ccw_setup(VDev *vdev);
> +int virtio_ccw_reset(VDev *vdev);
> +
> +#endif
> diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h
> index c5612e16a2..7a37f8b45a 100644
> --- a/pc-bios/s390-ccw/virtio-scsi.h
> +++ b/pc-bios/s390-ccw/virtio-scsi.h
> @@ -69,6 +69,6 @@ static inline bool virtio_scsi_response_ok(const 
> VirtioScsiCmdResp *r)
>  
>  int virtio_scsi_read_many(VDev *vdev,
>                            unsigned long sector, void *load_addr, int 
> sec_num);
> -int virtio_scsi_setup_device(SubChannelId schid);
> +int virtio_scsi_setup_device(void);
>  
>  #endif /* VIRTIO_SCSI_H */
> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
> index d557a4a90e..e747891a2c 100644
> --- a/pc-bios/s390-ccw/virtio.h
> +++ b/pc-bios/s390-ccw/virtio.h
> @@ -109,6 +109,7 @@ struct VRing {
>  };
>  typedef struct VRing VRing;
>  
> +char *virtio_get_ring_area(void);
>  
>  /***********************************************
>   *               Virtio block                  *
> @@ -270,8 +271,10 @@ struct VirtioCmd {
>  };
>  typedef struct VirtioCmd VirtioCmd;
>  
> +void vring_init(VRing *vr, VqInfo *info);
> +bool virtio_is_supported(VDev *vdev);
>  bool vring_notify(VRing *vr);
> -int drain_irqs(SubChannelId schid);
> +int drain_irqs(VRing *vr);
>  void vring_send_buf(VRing *vr, void *p, int len, int flags);
>  int vr_poll(VRing *vr);
>  int vring_wait_reply(void);
> @@ -284,7 +287,7 @@ int virtio_net_init(void *mac_addr);
>  void virtio_net_deinit(void);
>  
>  /* virtio-blkdev.c */
> -int virtio_blk_setup_device(SubChannelId schid);
> +int virtio_blk_setup_device(void);
>  int virtio_read(unsigned long sector, void *load_addr);
>  unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long 
> rec_list2,
>                                   void *load_addr);
> diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
> index fef192c934..e82d60bbb7 100644
> --- a/pc-bios/s390-ccw/main.c
> +++ b/pc-bios/s390-ccw/main.c
> @@ -72,6 +72,7 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
>      Schib schib;
>      int r;
>  
> +    VDev *vdev = virtio_get_device();

Newline would need to be after this, but I'm not sure you need the vdev 
definition here.

>      blk_schid.sch_no = sch_no;
>      r = stsch_err(blk_schid, &schib);
>      if (r == 3 || r == -EIO) {
> @@ -91,7 +92,8 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
>       * Note: we always have to run virtio_is_supported() here to make
>       * sure that the vdev.senseid data gets pre-initialized correctly
>       */
> -    is_virtio = virtio_is_supported(blk_schid);
> +    vdev->schid = blk_schid;

You save this in four different places (here, [2a], [2b], and [3])... But maybe 
only need one? In
the ccw path ([3]?) ?

> +    is_virtio = virtio_is_supported(vdev);
>  
>      /* No specific devno given, just return whether the device is possibly 
> bootable */
>      if (dev_no < 0) {
> @@ -254,10 +256,12 @@ static int virtio_setup(void)
>          puts("Network boot device detected");
>          return 0;
>      case VIRTIO_ID_BLOCK:
> -        ret = virtio_blk_setup_device(blk_schid);
> +        vdev->schid = blk_schid;

[2a]

> +        ret = virtio_blk_setup_device();
>          break;
>      case VIRTIO_ID_SCSI:
> -        ret = virtio_scsi_setup_device(blk_schid);
> +        vdev->schid = blk_schid;

[2b]

> +        ret = virtio_scsi_setup_device();
>          break;
>      default:
>          puts("\n! No IPL device available !\n");
> diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
> index a9521dff41..651cedf6ef 100644
> --- a/pc-bios/s390-ccw/netmain.c
> +++ b/pc-bios/s390-ccw/netmain.c
> @@ -500,7 +500,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
>              continue;
>          }
>          enable_subchannel(net_schid);
> -        if (!virtio_is_supported(net_schid)) {
> +        if (!virtio_is_supported(virtio_get_device())) {
>              continue;
>          }
>          if (virtio_get_device_type() != VIRTIO_ID_NET) {
> diff --git a/pc-bios/s390-ccw/virtio-blkdev.c 
> b/pc-bios/s390-ccw/virtio-blkdev.c
> index f40a9407c2..87ab9a9513 100644
> --- a/pc-bios/s390-ccw/virtio-blkdev.c
> +++ b/pc-bios/s390-ccw/virtio-blkdev.c
> @@ -12,6 +12,7 @@
>  #include "s390-ccw.h"
>  #include "virtio.h"
>  #include "virtio-scsi.h"
> +#include "virtio-ccw.h"
>  
>  #define VIRTIO_BLK_F_GEOMETRY   (1 << 4)
>  #define VIRTIO_BLK_F_BLK_SIZE   (1 << 6)
> @@ -42,7 +43,7 @@ static int virtio_blk_read_many(VDev *vdev, unsigned long 
> sector, void *load_add
>      /* Now we can tell the host to read */
>      vring_wait_reply();
>  
> -    if (drain_irqs(vr->schid)) {
> +    if (drain_irqs(vr)) {
> 
>          /* Well, whatever status is supposed to contain... */
>          status = 1;
>      }
> @@ -229,15 +230,19 @@ uint64_t virtio_get_blocks(void)
>      }
>  }
>  
> -int virtio_blk_setup_device(SubChannelId schid)
> +int virtio_blk_setup_device(void)
>  {
>      VDev *vdev = virtio_get_device();
>  
>      vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
> -    vdev->schid = schid;
> -    virtio_setup_ccw(vdev);
>  
>      puts("Using virtio-blk.");
>  
> -    return 0;
> +    switch (virtio_get_device()->ipl_type) {

vdev->ipl_type

> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        return virtio_ccw_setup(vdev);

default:
    return 1;

...instead of...

> +    }
> +
> +    return 1;

...this?

>  }
> diff --git a/pc-bios/s390-ccw/virtio-ccw.c b/pc-bios/s390-ccw/virtio-ccw.c
> new file mode 100644
> index 0000000000..e121826625
> --- /dev/null
> +++ b/pc-bios/s390-ccw/virtio-ccw.c
> @@ -0,0 +1,242 @@
> +/*
> + * Virtio functionality for CCW devices
> + *
> + * Copyright (c) 2013 Alexander Graf <[email protected]>
> + * Copyright 2025 IBM Corp. Author(s): Jared Rossi <[email protected]>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at
> + * your option) any later version. See the COPYING file in the top-level
> + * directory.
> + */
> +
> +#include <string.h>
> +#include "s390-ccw.h"
> +#include "cio.h"
> +#include "virtio.h"
> +#include "virtio-ccw.h"
> +#include "virtio-scsi.h"
> +#include "bswap.h"
> +#include "helper.h"
> +#include "s390-time.h"
> +
> +/* virtio spec v1.0 para 4.3.3.2 */
> +static long kvm_hypercall(unsigned long nr, unsigned long param1,
> +                          unsigned long param2, unsigned long param3)
> +{
> +    register unsigned long r_nr asm("1") = nr;
> +    register unsigned long r_param1 asm("2") = param1;
> +    register unsigned long r_param2 asm("3") = param2;
> +    register unsigned long r_param3 asm("4") = param3;
> +    register long retval asm("2");
> +
> +    asm volatile ("diag %%r2,%%r4,0x500"
> +                  : "=d" (retval)
> +                  : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
> +                  : "memory", "cc");
> +
> +    return retval;
> +}
> +
> +static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
> +{
> +    Ccw1 ccw = {};
> +
> +    ccw.cmd_code = cmd;
> +    ccw.cda = (long)ptr;
> +    ccw.count = len;
> +
> +    if (sli) {
> +        ccw.flags |= CCW_FLAG_SLI;
> +    }
> +
> +    return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), 
> CCW_FMT1);

The previous patch changed vdev->senseid.cu_type to vdev->dev_type, and here 
you're switching it
back. Probably because dev_type is assigned from cu_model, which... Wait does 
that mean the previous
patch would break IPL? (Sorry if I missed that yesterday.)

> +}
> +
> +bool virtio_ccw_is_supported(SubChannelId schid)
> +{
> +    VDev *vdev = virtio_get_device();
> +    vdev->schid = schid;

[3]

> +    memset(&vdev->senseid, 0, sizeof(vdev->senseid));
> +
> +    /*
> +     * Run sense id command.
> +     * The size of the senseid data differs between devices (notably,
> +     * between virtio devices and dasds), so specify the largest possible
> +     * size and suppress the incorrect length indication for smaller sizes.
> +     */
> +    if (run_ccw(vdev, CCW_CMD_SENSE_ID, &vdev->senseid, 
> sizeof(vdev->senseid),
> +                true)) {
> +        return false;
> +    }
> +
> +    vdev->dev_type = vdev->senseid.cu_model;
> +
> +    if (vdev->senseid.cu_type == 0x3832) {
> +        switch (vdev->dev_type) {
> +        case VIRTIO_ID_BLOCK:
> +        case VIRTIO_ID_SCSI:
> +        case VIRTIO_ID_NET:
> +            return true;
> +        default:
> +            return false;
> +        }
> +    }
> +    return false;
> +}
> +
> +int drain_irqs_ccw(SubChannelId schid)
> +{
> +    Irb irb = {};
> +    int r = 0;
> +
> +    while (1) {
> +        /* FIXME: make use of TPI, for that enable subchannel and isc */
> +        if (tsch(schid, &irb)) {
> +            /* Might want to differentiate error codes later on. */
> +            if (irb.scsw.cstat) {
> +                r = -EIO;
> +            } else if (irb.scsw.dstat != 0xc) {
> +                r = -EIO;
> +            }
> +            return r;
> +        }
> +    }
> +}
> +
> +long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie)
> +{
> +    return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
> +                         vq_idx, cookie);
> +}
> +
> +int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd)
> +{
> +    VRing *vr = &vdev->vrings[vqid];
> +    int i = 0;
> +
> +    do {
> +        vring_send_buf(vr, cmd[i].data, cmd[i].size,
> +                       cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
> +    } while (cmd[i++].flags & VRING_DESC_F_NEXT);
> +
> +    vring_wait_reply();
> +    if (drain_irqs(vr)) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +int virtio_ccw_reset(VDev *vdev)
> +{
> +    return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
> +}
> +
> +int virtio_ccw_setup(VDev *vdev)
> +{
> +    int i, cfg_size = 0;
> +    uint8_t status;
> +    struct VirtioFeatureDesc {
> +        uint32_t features;
> +        uint8_t index;
> +    } __attribute__((packed)) feats;
> +
> +    if (!virtio_ccw_is_supported(vdev->schid)) {
> +        puts("Virtio unsupported for this device ID");
> +        return -ENODEV;
> +    }
> +    /* device ID has been established now */
> +
> +    vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
> +    vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> +
> +    virtio_reset(vdev);
> +
> +    status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
> +    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> +        puts("Could not write ACKNOWLEDGE status to host");
> +        return -EIO;
> +    }
> +
> +    switch (vdev->dev_type) {
> +    case VIRTIO_ID_NET:
> +        vdev->nr_vqs = 2;
> +        vdev->cmd_vr_idx = 0;
> +        cfg_size = sizeof(vdev->config.net);
> +        break;
> +    case VIRTIO_ID_BLOCK:
> +        vdev->nr_vqs = 1;
> +        vdev->cmd_vr_idx = 0;
> +        cfg_size = sizeof(vdev->config.blk);
> +        break;
> +    case VIRTIO_ID_SCSI:
> +        vdev->nr_vqs = 3;
> +        vdev->cmd_vr_idx = VR_REQUEST;
> +        cfg_size = sizeof(vdev->config.scsi);
> +        break;
> +    default:
> +        puts("Unsupported virtio device");
> +        return -ENODEV;
> +    }
> +
> +    status |= VIRTIO_CONFIG_S_DRIVER;
> +    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> +        puts("Could not write DRIVER status to host");
> +        return -EIO;
> +    }
> +
> +    /* Feature negotiation */
> +    for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
> +        feats.features = 0;
> +        feats.index = i;
> +        if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
> +            puts("Could not get features bits");
> +            return -EIO;
> +        }
> +
> +        vdev->guest_features[i] &= bswap32(feats.features);
> +        feats.features = bswap32(vdev->guest_features[i]);
> +        if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) 
> {
> +            puts("Could not set features bits");
> +            return -EIO;
> +        }
> +    }
> +
> +    if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
> +        puts("Could not get virtio device configuration");
> +        return -EIO;
> +    }
> +
> +    for (i = 0; i < vdev->nr_vqs; i++) {
> +        VqInfo info = {
> +            .queue = (unsigned long long) virtio_get_ring_area() + (i * 
> VIRTIO_RING_SIZE),
> +            .align = KVM_S390_VIRTIO_RING_ALIGN,
> +            .index = i,
> +            .num = 0,
> +        };
> +        VqConfig config = {
> +            .index = i,
> +            .num = 0,
> +        };
> +
> +        if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
> +                false)) {
> +            puts("Could not get virtio device VQ config");
> +            return -EIO;
> +        }
> +        info.num = config.num;
> +        vring_init(&vdev->vrings[i], &info);
> +        vdev->vrings[i].schid = vdev->schid;
> +        if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
> +            puts("Cannot set VQ info");
> +            return -EIO;
> +        }
> +    }
> +
> +    status |= VIRTIO_CONFIG_S_DRIVER_OK;
> +    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> +        puts("Could not write DRIVER_OK status to host");
> +        return -EIO;
> +    }
> +
> +    return 0;
> +}
> diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
> index 301445bf97..604f1cf003 100644
> --- a/pc-bios/s390-ccw/virtio-net.c
> +++ b/pc-bios/s390-ccw/virtio-net.c
> @@ -19,6 +19,7 @@
>  #include <ethernet.h>
>  #include "s390-ccw.h"
>  #include "virtio.h"
> +#include "virtio-ccw.h"
>  #include "s390-time.h"
>  #include "helper.h"
>  
> @@ -54,7 +55,7 @@ int virtio_net_init(void *mac_addr)
>      rx_last_idx = 0;
>  
>      vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
> -    virtio_setup_ccw(vdev);
> +    virtio_ccw_setup(vdev);
>  
>      if (!(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT)) {
>          puts("virtio-net device does not support the MAC address feature");
> @@ -88,7 +89,7 @@ int send(int fd, const void *buf, int len, int flags)
>      while (!vr_poll(txvq)) {
>          yield();
>      }
> -    if (drain_irqs(txvq->schid)) {
> +    if (drain_irqs(txvq)) {
>          puts("send: drain irqs failed");
>          return -1;
>      }
> diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
> index 71db75ce7b..6ab0f755f2 100644
> --- a/pc-bios/s390-ccw/virtio-scsi.c
> +++ b/pc-bios/s390-ccw/virtio-scsi.c
> @@ -15,6 +15,7 @@
>  #include "virtio.h"
>  #include "scsi.h"
>  #include "virtio-scsi.h"
> +#include "virtio-ccw.h"
>  #include "s390-time.h"
>  #include "helper.h"
>  
> @@ -476,12 +477,11 @@ static int virtio_scsi_setup(VDev *vdev)
>      return 0;
>  }
>  
> -int virtio_scsi_setup_device(SubChannelId schid)
> +int virtio_scsi_setup_device(void)
>  {
>      VDev *vdev = virtio_get_device();
>  
> -    vdev->schid = schid;
> -    virtio_setup_ccw(vdev);
> +    virtio_ccw_setup(vdev);
>  
>      if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
>          puts("Config: sense size mismatch");
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> index 0f4f201038..0488b3a07e 100644
> --- a/pc-bios/s390-ccw/virtio.c
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -2,6 +2,7 @@
>   * Virtio driver bits
>   *
>   * Copyright (c) 2013 Alexander Graf <[email protected]>
> + * Copyright 2025 IBM Corp. Author(s): Jared Rossi <[email protected]>
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2 or (at
>   * your option) any later version. See the COPYING file in the top-level
> @@ -13,6 +14,7 @@
>  #include "cio.h"
>  #include "virtio.h"
>  #include "virtio-scsi.h"
> +#include "virtio-ccw.h"
>  #include "bswap.h"
>  #include "helper.h"
>  #include "s390-time.h"
> @@ -44,69 +46,38 @@ VirtioDevType virtio_get_device_type(void)
>      return vdev.dev_type;
>  }
>  
> -/* virtio spec v1.0 para 4.3.3.2 */
> -static long kvm_hypercall(unsigned long nr, unsigned long param1,
> -                          unsigned long param2, unsigned long param3)
> +char *virtio_get_ring_area(void)
>  {
> -    register unsigned long r_nr asm("1") = nr;
> -    register unsigned long r_param1 asm("2") = param1;
> -    register unsigned long r_param2 asm("3") = param2;
> -    register unsigned long r_param3 asm("4") = param3;
> -    register long retval asm("2");
> -
> -    asm volatile ("diag %%r2,%%r4,0x500"
> -                  : "=d" (retval)
> -                  : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
> -                  : "memory", "cc");
> -
> -    return retval;
> -}
> -
> -static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
> -{
> -    return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
> -                         vq_idx, cookie);
> +    return ring_area;
>  }
>  
>  /***********************************************
>   *             Virtio functions                *
>   ***********************************************/
>  
> -int drain_irqs(SubChannelId schid)
> +int drain_irqs(VRing *vr)
>  {
> -    Irb irb = {};
> -    int r = 0;
> -
> -    while (1) {
> -        /* FIXME: make use of TPI, for that enable subchannel and isc */
> -        if (tsch(schid, &irb)) {
> -            /* Might want to differentiate error codes later on. */
> -            if (irb.scsw.cstat) {
> -                r = -EIO;
> -            } else if (irb.scsw.dstat != 0xc) {
> -                r = -EIO;
> -            }
> -            return r;
> -        }
> +    switch (vdev.ipl_type) {

Wait, we're just accessing the global vdev directly here?

> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        return drain_irqs_ccw(vr->schid);

In that case, what's the point of vr being passed in? Isn't vr->schid == 
vdev->schid?

This makes me think that vr->schid is not needed, and it can just be pulled 
from the vdev.

> +    default:
> +        return 0;
>      }
>  }
>  
> -static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
> +int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
>  {
> -    Ccw1 ccw = {};
> -
> -    ccw.cmd_code = cmd;
> -    ccw.cda = (long)ptr;
> -    ccw.count = len;
> -
> -    if (sli) {
> -        ccw.flags |= CCW_FLAG_SLI;
> +    switch (vdev->ipl_type) {
> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        return virtio_ccw_run(vdev, vqid, cmd);
> +    default:
> +        return -1;
>      }
> -
> -    return do_cio(vdev->schid, vdev->dev_type, ptr2u32(&ccw), CCW_FMT1);
>  }
>  
> -static void vring_init(VRing *vr, VqInfo *info)
> +void vring_init(VRing *vr, VqInfo *info)
>  {
>      void *p = (void *) info->queue;
>  
> @@ -134,7 +105,12 @@ static void vring_init(VRing *vr, VqInfo *info)
>  
>  bool vring_notify(VRing *vr)
>  {
> -    vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
> +    switch (vdev.ipl_type) {
> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        vr->cookie = virtio_ccw_notify(vr->schid, vr->id, vr->cookie);
> +    }
> +
>      return vr->cookie >= 0;
>  }
>  
> @@ -200,165 +176,24 @@ int vring_wait_reply(void)
>      return 1;
>  }
>  
> -int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
> -{
> -    VRing *vr = &vdev->vrings[vqid];
> -    int i = 0;
> -
> -    do {
> -        vring_send_buf(vr, cmd[i].data, cmd[i].size,
> -                       cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
> -    } while (cmd[i++].flags & VRING_DESC_F_NEXT);
> -
> -    vring_wait_reply();
> -    if (drain_irqs(vr->schid)) {
> -        return -1;
> -    }
> -    return 0;
> -}
> -
>  int virtio_reset(VDev *vdev)
>  {
> -    return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
> -}
> -
> -int virtio_setup_ccw(VDev *vdev)
> -{
> -    int i, cfg_size = 0;
> -    uint8_t status;
> -    struct VirtioFeatureDesc {
> -        uint32_t features;
> -        uint8_t index;
> -    } __attribute__((packed)) feats;
> -
> -    if (!virtio_is_supported(vdev->schid)) {
> -        puts("Virtio unsupported for this device ID");
> -        return -ENODEV;
> -    }
> -    /* device ID has been established now */
> -
> -    vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
> -    vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> -
> -    virtio_reset(vdev);
> -
> -    status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
> -    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> -        puts("Could not write ACKNOWLEDGE status to host");
> -        return -EIO;
> -    }
> -
> -    switch (vdev->dev_type) {
> -    case VIRTIO_ID_NET:
> -        vdev->nr_vqs = 2;
> -        vdev->cmd_vr_idx = 0;
> -        cfg_size = sizeof(vdev->config.net);
> -        break;
> -    case VIRTIO_ID_BLOCK:
> -        vdev->nr_vqs = 1;
> -        vdev->cmd_vr_idx = 0;
> -        cfg_size = sizeof(vdev->config.blk);
> -        break;
> -    case VIRTIO_ID_SCSI:
> -        vdev->nr_vqs = 3;
> -        vdev->cmd_vr_idx = VR_REQUEST;
> -        cfg_size = sizeof(vdev->config.scsi);
> -        break;
> +    switch (vdev->ipl_type) {
> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        return virtio_ccw_reset(vdev);
>      default:
> -        puts("Unsupported virtio device");
> -        return -ENODEV;
> -    }
> -
> -    status |= VIRTIO_CONFIG_S_DRIVER;
> -    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> -        puts("Could not write DRIVER status to host");
> -        return -EIO;
> -    }
> -
> -    /* Feature negotiation */
> -    for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
> -        feats.features = 0;
> -        feats.index = i;
> -        if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
> -            puts("Could not get features bits");
> -            return -EIO;
> -        }
> -
> -        vdev->guest_features[i] &= bswap32(feats.features);
> -        feats.features = bswap32(vdev->guest_features[i]);
> -        if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) 
> {
> -            puts("Could not set features bits");
> -            return -EIO;
> -        }
> -    }
> -
> -    if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
> -        puts("Could not get virtio device configuration");
> -        return -EIO;
> -    }
> -
> -    for (i = 0; i < vdev->nr_vqs; i++) {
> -        VqInfo info = {
> -            .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
> -            .align = KVM_S390_VIRTIO_RING_ALIGN,
> -            .index = i,
> -            .num = 0,
> -        };
> -        VqConfig config = {
> -            .index = i,
> -            .num = 0,
> -        };
> -
> -        if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
> -                false)) {
> -            puts("Could not get virtio device VQ config");
> -            return -EIO;
> -        }
> -        info.num = config.num;
> -        vring_init(&vdev->vrings[i], &info);
> -        vdev->vrings[i].schid = vdev->schid;
> -        if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
> -            puts("Cannot set VQ info");
> -            return -EIO;
> -        }
> -    }
> -
> -    status |= VIRTIO_CONFIG_S_DRIVER_OK;
> -    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) 
> {
> -        puts("Could not write DRIVER_OK status to host");
> -        return -EIO;
> +        return -1;
>      }
> -
> -    return 0;
>  }
>  
> -bool virtio_is_supported(SubChannelId schid)
> +bool virtio_is_supported(VDev *vdev)
>  {
> -    vdev.schid = schid;
> -    memset(&vdev.senseid, 0, sizeof(vdev.senseid));
> -
> -    /*
> -     * Run sense id command.
> -     * The size of the senseid data differs between devices (notably,
> -     * between virtio devices and dasds), so specify the largest possible
> -     * size and suppress the incorrect length indication for smaller sizes.
> -     */
> -    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid),
> -                true)) {
> +    switch (vdev->ipl_type) {
> +    case S390_IPL_TYPE_QEMU_SCSI:
> +    case S390_IPL_TYPE_CCW:
> +        return virtio_ccw_is_supported(vdev->schid);
> +    default:
>          return false;
>      }
> -
> -    vdev.dev_type = vdev.senseid.cu_model;
> -
> -    if (vdev.senseid.cu_type == 0x3832) {
> -        switch (vdev.dev_type) {
> -        case VIRTIO_ID_BLOCK:
> -        case VIRTIO_ID_SCSI:
> -        case VIRTIO_ID_NET:
> -            return true;
> -        default:
> -            return false;
> -        }
> -    }
> -    return false;
>  }
> diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
> index a0f24c94a8..259cff09db 100644
> --- a/pc-bios/s390-ccw/Makefile
> +++ b/pc-bios/s390-ccw/Makefile
> @@ -34,7 +34,8 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
>  .PHONY : all clean build-all distclean
>  
>  OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
> -       virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
> +       virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
> +       virtio-ccw.o
>  
>  SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
>  

Reply via email to