[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device dri
From: |
Cornelia Huck |
Subject: |
Re: [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device drivers |
Date: |
Tue, 23 Apr 2013 13:24:29 +0200 |
On Mon, 22 Apr 2013 21:18:13 +0200
Alexander Graf <address@hidden> wrote:
> In order to boot, we need to be able to access a virtio-blk device through
> the CCW bus. Implement support for this.
>
> Signed-off-by: Alexander Graf <address@hidden>
> ---
> pc-bios/s390-ccw/cio.h | 322
> +++++++++++++++++++++++++++++++++++++++++++++
> pc-bios/s390-ccw/virtio.c | 274 ++++++++++++++++++++++++++++++++++++++
> pc-bios/s390-ccw/virtio.h | 158 ++++++++++++++++++++++
> 3 files changed, 754 insertions(+), 0 deletions(-)
> create mode 100644 pc-bios/s390-ccw/cio.h
> create mode 100644 pc-bios/s390-ccw/virtio.c
> create mode 100644 pc-bios/s390-ccw/virtio.h
>
> diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
> new file mode 100644
> index 0000000..cb5815a
> --- /dev/null
> +++ b/pc-bios/s390-ccw/cio.h
> @@ -0,0 +1,322 @@
> +/*
> + * Channel IO definitions
> + *
> + * Copyright (c) 2013 Alexander Graf <address@hidden>
> + *
> + * Inspired by various s390 headers in Linux 3.9.
> + *
> + * 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.
> + */
> +
> +#ifndef CIO_H
> +#define CIO_H
> +
> +/*
> + * path management control word
> + */
> +struct pmcw {
> + __u32 intparm; /* interruption parameter */
> + __u32 qf : 1; /* qdio facility */
> + __u32 w : 1;
> + __u32 isc : 3; /* interruption sublass */
> + __u32 res5 : 3; /* reserved zeros */
> + __u32 ena : 1; /* enabled */
> + __u32 lm : 2; /* limit mode */
> + __u32 mme : 2; /* measurement-mode enable */
> + __u32 mp : 1; /* multipath mode */
> + __u32 tf : 1; /* timing facility */
> + __u32 dnv : 1; /* device number valid */
> + __u32 dev : 16; /* device number */
> + __u8 lpm; /* logical path mask */
> + __u8 pnom; /* path not operational mask */
> + __u8 lpum; /* last path used mask */
> + __u8 pim; /* path installed mask */
> + __u16 mbi; /* measurement-block index */
> + __u8 pom; /* path operational mask */
> + __u8 pam; /* path available mask */
> + __u8 chpid[8]; /* CHPID 0-7 (if available) */
> + __u32 unused1 : 8; /* reserved zeros */
> + __u32 st : 3; /* subchannel type */
> + __u32 unused2 : 18; /* reserved zeros */
> + __u32 mbfc : 1; /* measurement block format control */
> + __u32 xmwme : 1; /* extended measurement word mode enable */
> + __u32 csense : 1; /* concurrent sense; can be enabled ...*/
> + /* ... per MSCH, however, if facility */
> + /* ... is not installed, this results */
> + /* ... in an operand exception. */
> +} __attribute__ ((packed));
> +
> +/* Target SCHIB configuration. */
> +struct schib_config {
> + __u64 mba;
> + __u32 intparm;
> + __u16 mbi;
> + __u32 isc:3;
> + __u32 ena:1;
> + __u32 mme:2;
> + __u32 mp:1;
> + __u32 csense:1;
> + __u32 mbfc:1;
> +} __attribute__ ((packed));
I'd be surprised if you needed that structure.
> +
> +struct scsw {
> + __u16 flags;
> + __u16 ctrl;
> + __u32 cpa;
> + __u8 dstat;
> + __u8 cstat;
> + __u16 count;
> +} __attribute__ ((packed));
> +
> +#define SCSW_FCTL_CLEAR_FUNC 0x1000
> +#define SCSW_FCTL_HALT_FUNC 0x2000
> +#define SCSW_FCTL_START_FUNC 0x4000
> +
> +/*
> + * subchannel information block
> + */
> +struct schib {
> + struct pmcw pmcw; /* path management control word */
> + struct scsw scsw; /* subchannel status word */
> + __u64 mba; /* measurement block address */
> + __u8 mda[4]; /* model dependent area */
> +} __attribute__ ((packed,aligned(4)));
> +
> +struct subchannel_id {
> + __u32 cssid : 8;
> + __u32 : 4;
> + __u32 m : 1;
> + __u32 ssid : 2;
> + __u32 one : 1;
> + __u32 sch_no : 16;
> +} __attribute__ ((packed, aligned(4)));
> +
> +/*
> + * TPI info structure
> + */
> +struct tpi_info {
> + struct subchannel_id schid;
> + __u32 intparm; /* interruption parameter */
> + __u32 adapter_IO : 1;
> + __u32 reserved2 : 1;
> + __u32 isc : 3;
> + __u32 reserved3 : 12;
> + __u32 int_type : 3;
> + __u32 reserved4 : 12;
> +} __attribute__ ((packed));
> +
> +/* channel command word (type 1) */
> +struct ccw1 {
> + __u8 cmd_code;
> + __u8 flags;
> + __u16 count;
> + __u32 cda;
> +} __attribute__ ((packed));
> +
> +#define CCW_FLAG_DC 0x80
> +#define CCW_FLAG_CC 0x40
> +#define CCW_FLAG_SLI 0x20
> +#define CCW_FLAG_SKIP 0x10
> +#define CCW_FLAG_PCI 0x08
> +#define CCW_FLAG_IDA 0x04
> +#define CCW_FLAG_SUSPEND 0x02
> +
> +#define CCW_CMD_NOOP 0x03
> +#define CCW_CMD_BASIC_SENSE 0x04
> +#define CCW_CMD_TIC 0x08
> +#define CCW_CMD_SENSE_ID 0xe4
> +
> +#define CCW_CMD_SET_VQ 0x13
> +#define CCW_CMD_VDEV_RESET 0x33
> +#define CCW_CMD_READ_FEAT 0x12
> +#define CCW_CMD_WRITE_FEAT 0x11
> +#define CCW_CMD_READ_CONF 0x22
> +#define CCW_CMD_WRITE_CONF 0x21
> +#define CCW_CMD_WRITE_STATUS 0x31
> +#define CCW_CMD_SET_IND 0x43
> +#define CCW_CMD_SET_CONF_IND 0x53
> +#define CCW_CMD_READ_VQ_CONF 0x32
> +
> +/*
> + * Command-mode operation request block
> + */
> +struct cmd_orb {
> + __u32 intparm; /* interruption parameter */
> + __u32 key:4; /* flags, like key, suspend control, etc. */
> + __u32 spnd:1; /* suspend control */
> + __u32 res1:1; /* reserved */
> + __u32 mod:1; /* modification control */
> + __u32 sync:1; /* synchronize control */
> + __u32 fmt:1; /* format control */
> + __u32 pfch:1; /* prefetch control */
> + __u32 isic:1; /* initial-status-interruption control */
> + __u32 alcc:1; /* address-limit-checking control */
> + __u32 ssic:1; /* suppress-suspended-interr. control */
> + __u32 res2:1; /* reserved */
> + __u32 c64:1; /* IDAW/QDIO 64 bit control */
> + __u32 i2k:1; /* IDAW 2/4kB block size control */
> + __u32 lpm:8; /* logical path mask */
> + __u32 ils:1; /* incorrect length */
> + __u32 zero:6; /* reserved zeros */
> + __u32 orbx:1; /* ORB extension control */
> + __u32 cpa; /* channel program address */
> +} __attribute__ ((packed, aligned(4)));
Just make this orb. I doubt we want to emulate transport mode :)
> +
> +struct ciw {
> + __u8 type;
> + __u8 command;
> + __u16 count;
> +};
> +
> +/*
> + * sense-id response buffer layout
> + */
> +struct senseid {
> + /* common part */
> + __u8 reserved; /* always 0x'FF' */
> + __u16 cu_type; /* control unit type */
> + __u8 cu_model; /* control unit model */
> + __u16 dev_type; /* device type */
> + __u8 dev_model; /* device model */
> + __u8 unused; /* padding byte */
> + /* extended part */
> + struct ciw ciw[62];
> +} __attribute__ ((packed, aligned(4)));
> +
> +/* interruption response block */
> +struct irb {
> + struct scsw scsw;
> + __u32 esw[5];
> + __u32 ecw[8];
> + __u32 emw[8];
> +} __attribute__ ((packed, aligned(4)));
> +
> +/*
> + * Some S390 specific IO instructions as inline
> + */
> +
> +static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
> +{
> + register struct subchannel_id reg1 asm ("1") = schid;
> + int ccode = -EIO;
> +
> + asm volatile(
> + " stsch 0(%3)\n"
> + "0: ipm %0\n"
> + " srl %0,28\n"
> + "1:\n"
> + : "+d" (ccode), "=m" (*addr)
> + : "d" (reg1), "a" (addr)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int msch(struct subchannel_id schid, struct schib *addr)
> +{
> + register struct subchannel_id reg1 asm ("1") = schid;
> + int ccode;
> +
> + asm volatile(
> + " msch 0(%2)\n"
> + " ipm %0\n"
> + " srl %0,28"
> + : "=d" (ccode)
> + : "d" (reg1), "a" (addr), "m" (*addr)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int msch_err(struct subchannel_id schid, struct schib *addr)
> +{
> + register struct subchannel_id reg1 asm ("1") = schid;
> + int ccode = -EIO;
> +
> + asm volatile(
> + " msch 0(%2)\n"
> + "0: ipm %0\n"
> + " srl %0,28\n"
> + "1:\n"
> + : "+d" (ccode)
> + : "d" (reg1), "a" (addr), "m" (*addr)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int tsch(struct subchannel_id schid, struct irb *addr)
> +{
> + register struct subchannel_id reg1 asm ("1") = schid;
> + int ccode;
> +
> + asm volatile(
> + " tsch 0(%3)\n"
> + " ipm %0\n"
> + " srl %0,28"
> + : "=d" (ccode), "=m" (*addr)
> + : "d" (reg1), "a" (addr)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int ssch(struct subchannel_id schid, struct cmd_orb *addr)
> +{
> + register struct subchannel_id reg1 asm("1") = schid;
> + int ccode = -EIO;
> +
> + asm volatile(
> + " ssch 0(%2)\n"
> + "0: ipm %0\n"
> + " srl %0,28\n"
> + "1:\n"
> + : "+d" (ccode)
> + : "d" (reg1), "a" (addr), "m" (*addr)
> + : "cc", "memory");
> + return ccode;
> +}
> +
> +static inline int csch(struct subchannel_id schid)
> +{
> + register struct subchannel_id reg1 asm("1") = schid;
> + int ccode;
> +
> + asm volatile(
> + " csch\n"
> + " ipm %0\n"
> + " srl %0,28"
> + : "=d" (ccode)
> + : "d" (reg1)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int tpi(struct tpi_info *addr)
> +{
> + int ccode;
> +
> + asm volatile(
> + " tpi 0(%2)\n"
> + " ipm %0\n"
> + " srl %0,28"
> + : "=d" (ccode), "=m" (*addr)
> + : "a" (addr)
> + : "cc");
> + return ccode;
> +}
> +
> +static inline int chsc(void *chsc_area)
You'll probably won't need chsc, unless you want to support ipling from
subchannel sets > 0.
> +{
> + typedef struct { char _[4096]; } addr_type;
> + int cc;
> +
> + asm volatile(
> + " .insn rre,0xb25f0000,%2,0\n"
> + " ipm %0\n"
> + " srl %0,28\n"
> + : "=d" (cc), "=m" (*(addr_type *) chsc_area)
> + : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
> + : "cc");
> + return cc;
> +}
> +
> +#endif /* CIO_H */
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> new file mode 100644
> index 0000000..79e2941
> --- /dev/null
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -0,0 +1,274 @@
> +/*
> + * Virtio driver bits
> + *
> + * Copyright (c) 2013 Alexander Graf <address@hidden>
> + *
> + * 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 "s390-ccw.h"
> +#include "virtio.h"
> +
> +struct vring block;
> +
> +static long kvm_hypercall(unsigned long nr, unsigned long param1,
> + unsigned long param2)
> +{
> + register ulong r_nr asm("1") = nr;
> + register ulong r_param1 asm("2") = param1;
> + register ulong r_param2 asm("3") = param2;
> + register long retval asm("2");
> +
> + asm volatile ("diag 2,4,0x500"
> + : "=d" (retval)
> + : "d" (r_nr), "0" (r_param1), "r"(r_param2)
> + : "memory", "cc");
> +
> + return retval;
> +}
> +
> +static void virtio_notify(struct subchannel_id schid)
> +{
> + kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32*)&schid, 0);
> +}
> +
> +/***********************************************
> + * Virtio functions *
> + ***********************************************/
> +
> +static void drain_irqs(struct subchannel_id schid)
> +{
> + struct irb irb = {};
> + while (1) {
> + if (tsch(schid, &irb)) {
> + return;
> + }
> + }
> +}
Please convert this to a tpi-loop with tsch on interrupt, and
actually return an error if the irb has an error condition (see the
guest virtio_ccw driver for an example).
> +
> +static int run_ccw(struct subchannel_id schid, int cmd, void *ptr, int len)
> +{
> + struct ccw1 ccw = {};
> + struct cmd_orb orb = {};
> + struct schib schib;
> + int r;
> +
> + /* start command processing */
> + stsch_err(schid, &schib);
> + schib.scsw.ctrl = SCSW_FCTL_START_FUNC;
Not needed.
> + msch(schid, &schib);
Hmm... where do you set pmcw.ena? If you can do I/O on disabled
subchannels, this is a bug in the virtual css :)
> +
> + /* start subchannel command */
> + orb.fmt = 1;
> + orb.cpa = (u32)(long)&ccw;
Is this guaranteed to always work?
> + orb.lpm = 0x80;
> +
> + ccw.cmd_code = cmd;
> + ccw.cda = (long)ptr;
> + ccw.count = len;
> +
> + r = ssch(schid, &orb);
> + /*
> + * XXX Wait until device is done processing the CCW. For now we can
> + * assume that a simple tsch will have finished the CCW processing,
> + * but the architecture allows for asynchronous operation
> + */
And that's why you should use a tpi-loop + tsch :)
> + drain_irqs(schid);
You don't need to collect status if ssch() returned an error, but you
should return errors indicated in the irb as well.
> + return r;
> +}
> +
> +static void virtio_set_status(struct subchannel_id schid,
> + unsigned long dev_addr)
> +{
> + unsigned char status = dev_addr;
> + run_ccw(schid, CCW_CMD_WRITE_STATUS, &status, sizeof(status));
It might be a good idea to do virtio_panic() on error (also some other
callers of run_ccw()).
> +}
> +
> +static void virtio_reset(struct subchannel_id schid)
> +{
> + run_ccw(schid, CCW_CMD_VDEV_RESET, NULL, 0);
> +}
> +
> +static void vring_init(struct vring *vr, unsigned int num, void *p,
> + unsigned long align)
> +{
> + debug_print_addr("init p", p);
> + vr->num = num;
> + vr->desc = p;
> + vr->avail = p + num*sizeof(struct vring_desc);
> + vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
> + & ~(align - 1));
> +
> + /* We're running with interrupts off anyways, so don't bother */
> + vr->used->flags = VRING_USED_F_NO_NOTIFY;
> +
> + debug_print_addr("init vr", vr);
> +}
> +
> +static void vring_notify(struct subchannel_id schid)
> +{
> + virtio_notify(schid);
> +}
> +
> +static void vring_send_buf(struct vring *vr, void *p, int len, int flags)
> +{
> + /* For follow-up chains we need to keep the first entry point */
> + if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
> + vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx;
> + }
> +
> + vr->desc[vr->next_idx].addr = (ulong)p;
> + vr->desc[vr->next_idx].len = len;
> + vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN;
> + vr->desc[vr->next_idx].next = ++vr->next_idx;
> +
> + /* Chains only have a single ID */
> + if (!(flags & VRING_DESC_F_NEXT)) {
> + vr->avail->idx++;
> + }
> +
> + vr->used->idx = vr->next_idx;
> +}
> +
> +static u64 get_clock(void)
> +{
> + u64 r;
> +
> + asm volatile("stck %0" : "=Q" (r) : : "cc");
> + return r;
> +}
> +
> +static ulong get_second(void)
> +{
> + return (get_clock() >> 12) / 1000000;
> +}
> +
> +/*
> + * Wait for the host to reply.
> + *
> + * timeout is in seconds if > 0.
> + *
> + * Returns 0 on success, 1 on timeout.
> + */
> +static int vring_wait_reply(struct vring *vr, int timeout)
> +{
> + ulong target_second = get_second() + timeout;
> + struct subchannel_id schid = vr->schid;
> + int r = 0;
> +
> + while (vr->used->idx == vr->next_idx) {
> + vring_notify(schid);
> + if (timeout && (get_second() >= target_second)) {
> + r = 1;
> + break;
> + }
> + yield();
> + }
> +
> + vr->next_idx = 0;
> + vr->desc[0].len = 0;
> + vr->desc[0].flags = 0;
> +
> + return r;
> +}
> +
> +/***********************************************
> + * Virtio block *
> + ***********************************************/
> +
> +static int virtio_read_many(ulong sector, void *load_addr, int sec_num)
> +{
> + struct virtio_blk_outhdr out_hdr;
> + u8 status;
> +
> + /* Tell the host we want to read */
> + out_hdr.type = VIRTIO_BLK_T_IN;
> + out_hdr.ioprio = 99;
> + out_hdr.sector = sector;
> +
> + vring_send_buf(&block, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
> +
> + /* This is where we want to receive data */
> + vring_send_buf(&block, load_addr, SECTOR_SIZE * sec_num,
> + VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
> + VRING_DESC_F_NEXT);
> +
> + /* status field */
> + vring_send_buf(&block, &status, sizeof(u8), VRING_DESC_F_WRITE |
> + VRING_HIDDEN_IS_CHAIN);
> +
> + /* Now we can tell the host to read */
> + vring_wait_reply(&block, 0);
> +
> + drain_irqs(block.schid);
Collect error from irb?
> +
> + return status;
> +}
> +
> +unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
> + ulong subchan_id, void *load_addr)
> +{
> + u8 status;
> + int sec = rec_list1;
> + int sec_num = (((rec_list2 >> 32)+ 1) & 0xffff);
> + int sec_len = rec_list2 >> 48;
> + ulong addr = (ulong)load_addr;
> +
> + if (sec_len != SECTOR_SIZE) {
> + return -1;
> + }
> +
> + sclp_print(".");
> + status = virtio_read_many(sec, (void*)addr, sec_num);
> + if (status) {
> + virtio_panic("I/O Error");
> + }
> + addr += sec_num * SECTOR_SIZE;
> +
> + return addr;
> +}
> +
> +int virtio_read(ulong sector, void *load_addr)
> +{
> + return virtio_read_many(sector, load_addr, 1);
> +}
> +
> +void virtio_setup_block(struct subchannel_id schid)
> +{
> + struct vq_info_block info;
> +
> + virtio_reset(schid);
> +
> + /* XXX need to fetch the 128 from host */
Please ;)
> + vring_init(&block, 128, (void*)(100 * 1024 * 1024),
> + KVM_S390_VIRTIO_RING_ALIGN);
> +
> + info.queue = (100ULL * 1024ULL* 1024ULL);
> + info.align = KVM_S390_VIRTIO_RING_ALIGN;
> + info.index = 0;
> + info.num = 128;
> + block.schid = schid;
> +
> + run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info));
No host->guest notifications, right? Otherwise you'd be dead without
indicators. (Mental note to self: make sure virtio-ccw handles this
fine.)
> + virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK);
> +}
> +
> +bool virtio_is_blk(struct subchannel_id schid)
> +{
> + int r;
> + struct senseid senseid = {};
> +
> + /* run sense id command */
> + r = run_ccw(schid, CCW_CMD_SENSE_ID, &senseid, sizeof(senseid));
> + if (r) {
> + return false;
> + }
> + if ((senseid.cu_type != 0x3832) || (senseid.cu_model !=
> VIRTIO_ID_BLOCK)) {
> + return false;
> + }
> +
> + return true;
> +}
> +
> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
> new file mode 100644
> index 0000000..a33199d
> --- /dev/null
> +++ b/pc-bios/s390-ccw/virtio.h
> @@ -0,0 +1,158 @@
> +/*
> + * Virtio driver bits
> + *
> + * Copyright (c) 2013 Alexander Graf <address@hidden>
> + *
> + * 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.
> + */
> +
> +#ifndef VIRTIO_H
> +#define VIRTIO_H
> +
> +#include "s390-ccw.h"
> +
> +/* Status byte for guest to report progress, and synchronize features. */
> +/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO)
> */
> +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
> +/* We have found a driver for the device. */
> +#define VIRTIO_CONFIG_S_DRIVER 2
> +/* Driver has used its parts of the config, and is happy */
> +#define VIRTIO_CONFIG_S_DRIVER_OK 4
> +/* We've given up on this device. */
> +#define VIRTIO_CONFIG_S_FAILED 0x80
> +
> +enum virtio_dev_type {
> + VIRTIO_ID_NET = 1,
> + VIRTIO_ID_BLOCK = 2,
> + VIRTIO_ID_CONSOLE = 3,
> + VIRTIO_ID_BALLOON = 5,
> +};
> +
> +struct virtio_dev_header {
> + enum virtio_dev_type type : 8;
> + u8 num_vq;
> + u8 feature_len;
> + u8 config_len;
> + u8 status;
> + u8 vqconfig[];
> +} __attribute__((packed));
> +
> +struct virtio_vqconfig {
> + u64 token;
> + u64 address;
> + u16 num;
> + u8 pad[6];
> +} __attribute__((packed));
> +
> +struct vq_info_block {
> + u64 queue;
> + u32 align;
> + u16 index;
> + u16 num;
> +} __attribute__((packed));
> +
> +struct virtio_dev {
> + struct virtio_dev_header *header;
> + struct virtio_vqconfig *vqconfig;
> + char *host_features;
> + char *guest_features;
> + char *config;
> +};
> +
> +#define KVM_S390_VIRTIO_RING_ALIGN 4096
> +
> +#define VRING_USED_F_NO_NOTIFY 1
> +
> +/* This marks a buffer as continuing via the next field. */
> +#define VRING_DESC_F_NEXT 1
> +/* This marks a buffer as write-only (otherwise read-only). */
> +#define VRING_DESC_F_WRITE 2
> +/* This means the buffer contains a list of buffer descriptors. */
> +#define VRING_DESC_F_INDIRECT 4
> +
> +/* Internal flag to mark follow-up segments as such */
> +#define VRING_HIDDEN_IS_CHAIN 256
> +
> +/* Virtio ring descriptors: 16 bytes. These can chain together via "next".
> */
> +struct vring_desc {
> + /* Address (guest-physical). */
> + u64 addr;
> + /* Length. */
> + u32 len;
> + /* The flags as indicated above. */
> + u16 flags;
> + /* We chain unused descriptors via this, too */
> + u16 next;
> +} __attribute__((packed));
> +
> +struct vring_avail {
> + u16 flags;
> + u16 idx;
> + u16 ring[];
> +} __attribute__((packed));
> +
> +/* u32 is used here for ids for padding reasons. */
> +struct vring_used_elem {
> + /* Index of start of used descriptor chain. */
> + u32 id;
> + /* Total length of the descriptor chain which was used (written to) */
> + u32 len;
> +} __attribute__((packed));
> +
> +struct vring_used {
> + u16 flags;
> + u16 idx;
> + struct vring_used_elem ring[];
> +} __attribute__((packed));
> +
> +struct vring {
> + unsigned int num;
> + int next_idx;
> + struct vring_desc *desc;
> + struct vring_avail *avail;
> + struct vring_used *used;
> + struct subchannel_id schid;
> +};
> +
> +
> +/***********************************************
> + * Virtio block *
> + ***********************************************/
> +
> +/*
> + * Command types
> + *
> + * Usage is a bit tricky as some bits are used as flags and some are not.
> + *
> + * Rules:
> + * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or
> + * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own
> + * and may not be combined with any of the other flags.
> + */
> +
> +/* These two define direction. */
> +#define VIRTIO_BLK_T_IN 0
> +#define VIRTIO_BLK_T_OUT 1
> +
> +/* This bit says it's a scsi command, not an actual read or write. */
> +#define VIRTIO_BLK_T_SCSI_CMD 2
> +
> +/* Cache flush command */
> +#define VIRTIO_BLK_T_FLUSH 4
> +
> +/* Barrier before this op. */
> +#define VIRTIO_BLK_T_BARRIER 0x80000000
> +
> +/* This is the first element of the read scatter-gather list. */
> +struct virtio_blk_outhdr {
> + /* VIRTIO_BLK_T* */
> + u32 type;
> + /* io priority. */
> + u32 ioprio;
> + /* Sector (ie. 512 byte offset) */
> + u64 sector;
> +};
> +
> +#endif /* VIRTIO_H */
- [Qemu-devel] [PATCH 02/12] S390: IPL: Support ELF firmware, (continued)
- [Qemu-devel] [PATCH 02/12] S390: IPL: Support ELF firmware, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 10/12] S390: ccw firmware: Add Makefile, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 12/12] S390: CCW: Use new, working firmware by default, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 11/12] S390: ccw firmware: Add compiled blob, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 08/12] S390: ccw firmware: Add glue header, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 06/12] S390: ccw firmware: Add sclp output, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 09/12] S390: ccw firmware: Add bootmap interpreter, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 03/12] S390: IPL: Use different firmware for different machines, Alexander Graf, 2013/04/22
- [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device drivers, Alexander Graf, 2013/04/22
- Re: [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device drivers,
Cornelia Huck <=
- Re: [Qemu-devel] [PATCH 00/12] S390: Add virtio-ccw firmware, Christian Borntraeger, 2013/04/23
- [Qemu-devel] [PATCH 0/4] updates for s390-ccw.img, Christian Borntraeger, 2013/04/23
- [Qemu-devel] [PATCH 2/4] s390-ccw.img: build s390-ccw rom on s3900 system by default, Christian Borntraeger, 2013/04/23