From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Jfj2X-0002Hq-LL for qemu-devel@nongnu.org; Sat, 29 Mar 2008 17:56:41 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Jfj2V-0002GA-VM for qemu-devel@nongnu.org; Sat, 29 Mar 2008 17:56:41 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Jfj2V-0002Fz-HN for qemu-devel@nongnu.org; Sat, 29 Mar 2008 17:56:39 -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 1Jfj2V-00011j-9E for qemu-devel@nongnu.org; Sat, 29 Mar 2008 17:56:39 -0400 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e2.ny.us.ibm.com (8.13.8/8.13.8) with ESMTP id m2TLuCwj031542 for ; Sat, 29 Mar 2008 17:56:12 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m2TLuCsp315068 for ; Sat, 29 Mar 2008 17:56:12 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m2TLuCbP006561 for ; Sat, 29 Mar 2008 17:56:12 -0400 From: Anthony Liguori Date: Sat, 29 Mar 2008 16:55:59 -0500 Message-Id: <1206827760-4566-5-git-send-email-aliguori@us.ibm.com> In-Reply-To: <1206827760-4566-1-git-send-email-aliguori@us.ibm.com> References: <1206827760-4566-1-git-send-email-aliguori@us.ibm.com> Subject: [Qemu-devel] [PATCH 5/6] virtio block driver 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: kvm-devel@lists.sourceforge.net, Marcelo Tosatti , Anthony Liguori , Aurelien Jarno This patch implements the virtio block driver backend. 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..a2662c6 --- /dev/null +++ b/hw/virtio-blk.c @@ -0,0 +1,127 @@ +/* + * 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; + off_t off; + int i; + + out_size = iovector_size(elem->virt_out); + in_size = iovector_size(elem->virt_in); + + memcpy_from_iovector(&out, 0, sizeof(out), elem->virt_out); + + off = out.sector; + + 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)); + + wlen = sizeof(in); + + for (i = 0; i < sg->num; i++) { + bdrv_write(s->bs, off, sg->sg[i].base, sg->sg[i].len / 512); + off += sg->sg[i].len / 512; + } + + qemu_free(sg); + in.status = VIRTIO_BLK_S_OK; + } else { + IOVector *sg; + + sg = iovector_trim(elem->virt_in, 0, in_size - sizeof(in)); + + wlen = sizeof(in); + + for (i = 0; i < sg->num; i++) { + bdrv_read(s->bs, off, sg->sg[i].base, sg->sg[i].len / 512); + off += sg->sg[i].len / 512; + wlen += sg->sg[i].len; + } + + qemu_free(sg); + in.status = VIRTIO_BLK_S_OK; + } + + memcpy_to_iovector(&in, in_size - sizeof(in), + sizeof(in), elem->virt_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 = capacity; + blkcfg.seg_max = 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 61eb191..9b614e9 100644 --- a/vl.c +++ b/vl.c @@ -5034,6 +5034,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; @@ -5225,6 +5228,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])