From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JhzcO-0001F8-4N for qemu-devel@nongnu.org; Sat, 05 Apr 2008 00:03:04 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JhzcN-0001EH-IU for qemu-devel@nongnu.org; Sat, 05 Apr 2008 00:03:03 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JhzcN-0001E7-8i for qemu-devel@nongnu.org; Sat, 05 Apr 2008 00:03:03 -0400 Received: from e2.ny.us.ibm.com ([32.97.182.142]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1JhzcM-0002nu-LZ for qemu-devel@nongnu.org; Sat, 05 Apr 2008 00:03:02 -0400 Received: from d01relay02.pok.ibm.com (d01relay02.pok.ibm.com [9.56.227.234]) by e2.ny.us.ibm.com (8.13.8/8.13.8) with ESMTP id m35431Kv032112 for ; Sat, 5 Apr 2008 00:03:01 -0400 Received: from d01av02.pok.ibm.com (d01av02.pok.ibm.com [9.56.224.216]) by d01relay02.pok.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m35431Gl232028 for ; Sat, 5 Apr 2008 00:03:01 -0400 Received: from d01av02.pok.ibm.com (loopback [127.0.0.1]) by d01av02.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m354305W012784 for ; Sat, 5 Apr 2008 00:03:01 -0400 From: Anthony Liguori Date: Fri, 4 Apr 2008 23:02:54 -0500 Message-Id: <1207368175-19476-5-git-send-email-aliguori@us.ibm.com> In-Reply-To: <1207368175-19476-4-git-send-email-aliguori@us.ibm.com> References: <1207368175-19476-1-git-send-email-aliguori@us.ibm.com> <1207368175-19476-2-git-send-email-aliguori@us.ibm.com> <1207368175-19476-3-git-send-email-aliguori@us.ibm.com> <1207368175-19476-4-git-send-email-aliguori@us.ibm.com> Subject: [Qemu-devel] [PATCH 5/6] virtio block driver (v2) Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Anthony Liguori , kvm-devel@lists.sourceforge.net, Marcelo Tosatti , Paul Brook , Aurelien Jarno This patch implements the virtio block driver backend. Since v1, I've updated the patch based on the IOVector refactoring and fixed an endianness bug in the config space. Signed-off-by: Anthony Liguori diff --git a/Makefile.target b/Makefile.target index 3ea40d1..f9fe660 100644 --- a/Makefile.target +++ b/Makefile.target @@ -535,7 +535,7 @@ OBJS += rtl8139.o OBJS += e1000.o # virtio devices -OBJS += virtio.o virtio-net.o +OBJS += virtio.o virtio-net.o virtio-blk.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support diff --git a/hw/pc.c b/hw/pc.c index 4fec2d4..2da9413 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1011,6 +1011,18 @@ static void pc_init1(int ram_size, int vga_ram_size, } } } + + /* Add virtio block devices */ + if (pci_enabled) { + int index; + int unit_id = 0; + + while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { + virtio_blk_init(pci_bus, drives_table[index].bdrv); + unit_id++; + } + } + } static void pc_init_pci(int ram_size, int vga_ram_size, diff --git a/hw/pc.h b/hw/pc.h index 9f83050..c828cda 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -143,4 +143,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd); +/* virtio-blk.c */ +void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs); + #endif diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c new file mode 100644 index 0000000..887ea49 --- /dev/null +++ b/hw/virtio-blk.c @@ -0,0 +1,112 @@ +/* + * Virtio Block Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "virtio.h" +#include "block.h" +#include "block_int.h" +#include "pc.h" +#include "virtio-blk.h" + +typedef struct VirtIOBlock +{ + VirtIODevice vdev; + BlockDriverState *bs; +} VirtIOBlock; + +static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) +{ + return (VirtIOBlock *)vdev; +} + +static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOBlock *s = to_virtio_blk(vdev); + VirtQueueElement *elem; + + while ((elem = virtqueue_pop(vq)) != 0) { + struct virtio_blk_outhdr out; + struct virtio_blk_inhdr in; + unsigned int wlen; + size_t in_size, out_size; + + out_size = iovector_size(elem->virt_out); + in_size = iovector_size(elem->virt_in); + + memcpy_from_iovector(&out, 0, sizeof(out), elem->virt_out); + + if (out.type & VIRTIO_BLK_T_SCSI_CMD) { + wlen = sizeof(in); + in.status = VIRTIO_BLK_S_UNSUPP; + } else if (out.type & VIRTIO_BLK_T_OUT) { + IOVector *sg; + + sg = iovector_trim(elem->virt_out, sizeof(out), + out_size - sizeof(out)); + bdrv_writev(s->bs, out.sector, sg); + qemu_free(sg); + + wlen = sizeof(in); + in.status = VIRTIO_BLK_S_OK; + } else { + IOVector *sg; + + sg = iovector_trim(elem->virt_in, 0, in_size - sizeof(in)); + bdrv_readv(s->bs, out.sector, sg); + qemu_free(sg); + + wlen = in_size; + in.status = VIRTIO_BLK_S_OK; + } + + memcpy_to_iovector(elem->virt_in, in_size - sizeof(in), + sizeof(in), &in); + + virtqueue_push(vq, elem, wlen); + virtio_notify(vdev, vq); + } +} + +static void virtio_blk_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOBlock *s = to_virtio_blk(vdev); + struct virtio_blk_config blkcfg; + int64_t capacity; + + bdrv_get_geometry(s->bs, &capacity); + blkcfg.capacity = cpu_to_le64(capacity); + blkcfg.seg_max = cpu_to_le32(128 - 2); + memcpy(config, &blkcfg, sizeof(blkcfg)); +} + +static uint32_t virtio_blk_get_features(VirtIODevice *vdev) +{ + return (1 << VIRTIO_BLK_F_SEG_MAX); +} + +void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs) +{ + VirtIOBlock *s; + + s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", 6900, 0x1001, + 0, VIRTIO_ID_BLOCK, + 0x01, 0x80, 0x00, + 16, sizeof(VirtIOBlock)); + + s->vdev.get_config = virtio_blk_get_config; + s->vdev.get_features = virtio_blk_get_features; + s->bs = bs; + + virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); + + return s; +} diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h new file mode 100644 index 0000000..290ff5b --- /dev/null +++ b/hw/virtio-blk.h @@ -0,0 +1,66 @@ +/* + * Virtio Support + * + * Copyright IBM, Corp. 2007-2008 + * + * Authors: + * Anthony Liguori + * Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_BLK_H +#define _QEMU_VIRTIO_BLK_H + +/* from Linux's linux/virtio_blk.h */ + +/* The ID for virtio_block */ +#define VIRTIO_ID_BLOCK 2 + +/* Feature bits */ +#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ +#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ + +struct virtio_blk_config +{ + uint64_t capacity; + uint32_t size_max; + uint32_t seg_max; +}; + +/* 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 + +/* 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* */ + uint32_t type; + /* io priority. */ + uint32_t ioprio; + /* Sector (ie. 512 byte offset) */ + uint64_t sector; +}; + +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 + +/* This is the first element of the write scatter-gather list */ +struct virtio_blk_inhdr +{ + unsigned char status; +}; + +#endif diff --git a/sysemu.h b/sysemu.h index 0f18e04..0078190 100644 --- a/sysemu.h +++ b/sysemu.h @@ -119,7 +119,7 @@ extern unsigned int nb_prom_envs; #endif typedef enum { - IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO } BlockInterfaceType; typedef struct DriveInfo { diff --git a/vl.c b/vl.c index 342ef79..4b9e850 100644 --- a/vl.c +++ b/vl.c @@ -5050,6 +5050,9 @@ static int drive_init(struct drive_opt *arg, int snapshot, } else if (!strcmp(buf, "sd")) { type = IF_SD; max_devs = 0; + } else if (!strcmp(buf, "virtio")) { + type = IF_VIRTIO; + max_devs = 0; } else { fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); return -1; @@ -5241,6 +5244,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, break; case IF_PFLASH: case IF_MTD: + case IF_VIRTIO: break; } if (!file[0])