From: Cornelia Huck <cornelia.huck@de.ibm.com>
To: Alexander Graf <agraf@suse.de>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>,
qemu-devel@nongnu.org, Dominik Dingel <dingel@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device drivers
Date: Tue, 23 Apr 2013 13:24:29 +0200 [thread overview]
Message-ID: <20130423132429.56dac074@gondolin> (raw)
In-Reply-To: <1366658298-9275-8-git-send-email-agraf@suse.de>
On Mon, 22 Apr 2013 21:18:13 +0200
Alexander Graf <agraf@suse.de> 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 <agraf@suse.de>
> ---
> 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 <agraf@suse.de>
> + *
> + * 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 <agraf@suse.de>
> + *
> + * 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 <agraf@suse.de>
> + *
> + * 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 */
next prev parent reply other threads:[~2013-04-23 11:24 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-22 19:18 [Qemu-devel] [PATCH 00/12] S390: Add virtio-ccw firmware Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 01/12] S390: Make IPL reset address dynamic Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 02/12] S390: IPL: Support ELF firmware Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 03/12] S390: IPL: Use different firmware for different machines Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 04/12] S390: ccw firmware: Add start assembly Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 05/12] S390: ccw firmware: Add main program Alexander Graf
2013-04-23 8:43 ` Christian Borntraeger
2013-04-23 8:58 ` Cornelia Huck
2013-04-23 11:35 ` Alexander Graf
2013-04-23 11:51 ` Cornelia Huck
2013-04-22 19:18 ` [Qemu-devel] [PATCH 06/12] S390: ccw firmware: Add sclp output Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 07/12] S390: ccw firmware: Add virtio device drivers Alexander Graf
2013-04-23 11:24 ` Cornelia Huck [this message]
2013-04-22 19:18 ` [Qemu-devel] [PATCH 08/12] S390: ccw firmware: Add glue header Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 09/12] S390: ccw firmware: Add bootmap interpreter Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 10/12] S390: ccw firmware: Add Makefile Alexander Graf
2013-04-23 10:31 ` Christian Borntraeger
2013-04-22 19:18 ` [Qemu-devel] [PATCH 11/12] S390: ccw firmware: Add compiled blob Alexander Graf
2013-04-22 19:18 ` [Qemu-devel] [PATCH 12/12] S390: CCW: Use new, working firmware by default Alexander Graf
2013-04-23 9:20 ` [Qemu-devel] [PATCH 00/12] S390: Add virtio-ccw firmware Christian Borntraeger
2013-04-23 11:38 ` Alexander Graf
2013-04-23 11:23 ` [Qemu-devel] [PATCH 0/4] updates for s390-ccw.img Christian Borntraeger
2013-04-23 11:23 ` [Qemu-devel] [PATCH 1/4] s390-ccw.img: replace while loop with a disabled wait on s390 bios Christian Borntraeger
2013-04-23 11:23 ` [Qemu-devel] [PATCH 2/4] s390-ccw.img: build s390-ccw rom on s3900 system by default Christian Borntraeger
2013-04-23 11:23 ` [Qemu-devel] [PATCH 3/4] s390-ccw.img: Fix compile warning in s390 ccw virtio code Christian Borntraeger
2013-04-23 11:31 ` Alexander Graf
2013-04-23 11:45 ` Christian Borntraeger
2013-04-26 6:38 ` Alexander Graf
2013-04-23 11:23 ` [Qemu-devel] [PATCH 4/4] s390-ccw.img: Take care of the elf->img transition Christian Borntraeger
2013-04-23 11:33 ` [Qemu-devel] [PATCH 0/4] updates for s390-ccw.img Alexander Graf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130423132429.56dac074@gondolin \
--to=cornelia.huck@de.ibm.com \
--cc=agraf@suse.de \
--cc=borntraeger@de.ibm.com \
--cc=dingel@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.