Patchwork [RFC,v7,7/8] virtio-pci-blk : Switch to new API.

login
register
mail settings
Submitter fred.konrad@greensocs.com
Date Dec. 10, 2012, 4:45 p.m.
Message ID <1355157952-2321-8-git-send-email-fred.konrad@greensocs.com>
Download mbox | patch
Permalink /patch/205005/
State New
Headers show

Comments

fred.konrad@greensocs.com - Dec. 10, 2012, 4:45 p.m.
From: KONRAD Frederic <fred.konrad@greensocs.com>

Here the virtio-blk-pci is modified for the new API. The device virtio-pci-blk
extends virtio-pci. It creates and connects a virtio-blk during the init.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/virtio-pci.c | 113 +++++++++++++++++++++++---------------------------------
 hw/virtio-pci.h |  14 ++++++-
 2 files changed, 59 insertions(+), 68 deletions(-)
Peter Maydell - Dec. 11, 2012, 5:50 p.m.
On 10 December 2012 16:45,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> Here the virtio-blk-pci is modified for the new API. The device virtio-pci-blk
> extends virtio-pci. It creates and connects a virtio-blk during the init.

Did you check whether this maintains backwards compatibility
for vmstate migration information and device properties?
(haven't investigated myself yet, just asking whether you have)

-- PMM
Peter Maydell - Dec. 12, 2012, 2:25 p.m.
On 10 December 2012 16:45,  <fred.konrad@greensocs.com> wrote:
> -static void virtio_blk_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> -
> -    k->init = virtio_blk_init_pci;
> -    k->exit = virtio_blk_exit_pci;
> -    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> -    k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
> -    k->revision = VIRTIO_PCI_ABI_VERSION;
> -    k->class_id = PCI_CLASS_STORAGE_SCSI;
> -    dc->reset = virtio_pci_reset;
> -    dc->props = virtio_blk_properties;
> -}

This hunk removes the setting of the PCI vendor and device IDs
but I can't see where they are set in the new code.

How will the PCI transport's PCI vendor/device/class IDs be
set (a) when a virtio-blk backend is created and separately
plugged into a virtio-pci transport (b) for the legacy
virtio-pci-blk? [ideally the answer to (b) should be "in the
same way as for (a)"]

-- PMM
Andreas Färber - Dec. 12, 2012, 5:53 p.m.
Am 12.12.2012 15:25, schrieb Peter Maydell:
> How will the PCI transport's PCI vendor/device/class IDs be
> set (a) when a virtio-blk backend is created and separately
> plugged into a virtio-pci transport (b) for the legacy
> virtio-pci-blk? [ideally the answer to (b) should be "in the
> same way as for (a)"]

The obvious answer would be that PCI properties need to be set on the
PCI device, not an a VirtioDevice sitting on a virtio-bus.

I.e., with the proposed refactoring we'd have on the virtio-bus:

- VirtioDevice
  + VirtioBlockDevice
  + VirtioSCSIDevice - has-a scsi-bus
  ...

In turn that means that every VirtioDevice to be exposed as PCI device
to the guest needs it own PCIDevice exposing a private virtio-bus.

- PCIDevice
  - VirtioPCIDevice - has-a virtio-bus
    + virtio-blk-pci - has-a VirtioBlockDevice on its virtio-bus
    + virtio-scsi-pci - has-a VirtioSCSIDevice on its virtio-bus
    ...

This also happens to solve most of the migration compatibility pretty
nicely because the wapping PCI devices would be used almost as before,
some state may need to be forwarded to the VirtioDevice.

Finally supplying a public device_initialize() or so would be helpful
for the latter since VMState cannot cross pointers IIRC. I'll look into
that part since inlining the old qdev functions cripples my Tegra work.

Andreas
Paolo Bonzini - Dec. 12, 2012, 5:56 p.m.
Il 12/12/2012 18:53, Andreas Färber ha scritto:
> Am 12.12.2012 15:25, schrieb Peter Maydell:
>> How will the PCI transport's PCI vendor/device/class IDs be
>> set (a) when a virtio-blk backend is created and separately
>> plugged into a virtio-pci transport (b) for the legacy
>> virtio-pci-blk? [ideally the answer to (b) should be "in the
>> same way as for (a)"]
> 
> The obvious answer would be that PCI properties need to be set on the
> PCI device, not an a VirtioDevice sitting on a virtio-bus.

Yes, but the question is *how*... if there will be no usable "-device
virtio-pci", the value of this refactoring becomes a bit lower...

Paolo

> I.e., with the proposed refactoring we'd have on the virtio-bus:
> 
> - VirtioDevice
>   + VirtioBlockDevice
>   + VirtioSCSIDevice - has-a scsi-bus
>   ...
> 
> In turn that means that every VirtioDevice to be exposed as PCI device
> to the guest needs it own PCIDevice exposing a private virtio-bus.
> 
> - PCIDevice
>   - VirtioPCIDevice - has-a virtio-bus
>     + virtio-blk-pci - has-a VirtioBlockDevice on its virtio-bus
>     + virtio-scsi-pci - has-a VirtioSCSIDevice on its virtio-bus
>     ...
> 
> This also happens to solve most of the migration compatibility pretty
> nicely because the wapping PCI devices would be used almost as before,
> some state may need to be forwarded to the VirtioDevice.
> 
> Finally supplying a public device_initialize() or so would be helpful
> for the latter since VMState cannot cross pointers IIRC. I'll look into
> that part since inlining the old qdev functions cripples my Tegra work.
> 
> Andreas
>
Peter Maydell - Dec. 12, 2012, 5:58 p.m.
On 12 December 2012 17:53, Andreas Färber <afaerber@suse.de> wrote:
> Am 12.12.2012 15:25, schrieb Peter Maydell:
>> How will the PCI transport's PCI vendor/device/class IDs be
>> set (a) when a virtio-blk backend is created and separately
>> plugged into a virtio-pci transport (b) for the legacy
>> virtio-pci-blk? [ideally the answer to (b) should be "in the
>> same way as for (a)"]
>
> The obvious answer would be that PCI properties need to be set on the
> PCI device, not an a VirtioDevice sitting on a virtio-bus.
>
> I.e., with the proposed refactoring we'd have on the virtio-bus:
>
> - VirtioDevice
>   + VirtioBlockDevice
>   + VirtioSCSIDevice - has-a scsi-bus
>   ...
>
> In turn that means that every VirtioDevice to be exposed as PCI device
> to the guest needs it own PCIDevice exposing a private virtio-bus.
>
> - PCIDevice
>   - VirtioPCIDevice - has-a virtio-bus
>     + virtio-blk-pci - has-a VirtioBlockDevice on its virtio-bus
>     + virtio-scsi-pci - has-a VirtioSCSIDevice on its virtio-bus
>     ...

...this bit is only for legacy back-compat. It should be equally
valid to just use the PCI transport plugged into a VirtioDevice,
both of which were created by the user with -device [and for
new transports, separate transport and backend should be the
standard]. That means the virtio-bus interface needs a way for
the backend to announce to the transport what it is so that
the PCI transport can set the right PCI IDs.

-- PMM
Paolo Bonzini - Dec. 12, 2012, 6:03 p.m.
Il 12/12/2012 18:58, Peter Maydell ha scritto:
> It should be equally
> valid to just use the PCI transport plugged into a VirtioDevice,
> both of which were created by the user with -device [and for
> new transports, separate transport and backend should be the
> standard]. That means the virtio-bus interface needs a way for
> the backend to announce to the transport what it is so that
> the PCI transport can set the right PCI IDs.

There is such an interface (the device_id, aka VIRTIO_ID_*).  Then
virtio-pci needs a mapping from the device_id to the (default)
vendor_id/device_id/class tuple.

Paolo
Michael S. Tsirkin - Dec. 12, 2012, 9:22 p.m.
On Wed, Dec 12, 2012 at 07:03:21PM +0100, Paolo Bonzini wrote:
> Il 12/12/2012 18:58, Peter Maydell ha scritto:
> > It should be equally
> > valid to just use the PCI transport plugged into a VirtioDevice,
> > both of which were created by the user with -device [and for
> > new transports, separate transport and backend should be the
> > standard]. That means the virtio-bus interface needs a way for
> > the backend to announce to the transport what it is so that
> > the PCI transport can set the right PCI IDs.
> 
> There is such an interface (the device_id, aka VIRTIO_ID_*).  Then
> virtio-pci needs a mapping from the device_id to the (default)
> vendor_id/device_id/class tuple.
> 
> Paolo

At least device id and vedor id are easy.
fred.konrad@greensocs.com - Dec. 13, 2012, 8:24 a.m.
On 12/12/2012 15:25, Peter Maydell wrote:
> On 10 December 2012 16:45,  <fred.konrad@greensocs.com> wrote:
>> -static void virtio_blk_class_init(ObjectClass *klass, void *data)
>> -{
>> -    DeviceClass *dc = DEVICE_CLASS(klass);
>> -    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> -
>> -    k->init = virtio_blk_init_pci;
>> -    k->exit = virtio_blk_exit_pci;
>> -    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
>> -    k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
>> -    k->revision = VIRTIO_PCI_ABI_VERSION;
>> -    k->class_id = PCI_CLASS_STORAGE_SCSI;
>> -    dc->reset = virtio_pci_reset;
>> -    dc->props = virtio_blk_properties;
>> -}
> This hunk removes the setting of the PCI vendor and device IDs
> but I can't see where they are set in the new code.
>
> How will the PCI transport's PCI vendor/device/class IDs be
> set (a) when a virtio-blk backend is created and separately
> plugged into a virtio-pci transport (b) for the legacy
> virtio-pci-blk? [ideally the answer to (b) should be "in the
> same way as for (a)"]
>
> -- PMM

It's done in the virtio_pci_device_plugged(), ( step 4 )
At this time we have the device ID, so we can put the PCI IDs :

+static void virtio_pci_device_plugged(void *opaque)
+{
+    VirtIOPCIProxy *proxy = VIRTIO_PCI(opaque);
+    uint8_t *config;
+    uint32_t size;
+
+    /* Put the PCI IDs */
+    switch (get_virtio_device_id(proxy->bus)) {
+
+    case VIRTIO_ID_BLOCK:
+        pci_config_set_device_id(proxy->pci_dev.config,
+                                 PCI_DEVICE_ID_VIRTIO_BLOCK);
+        pci_config_set_class(proxy->pci_dev.config, PCI_CLASS_STORAGE_SCSI);
+    break;
+    default:
+        error_report("unknown device id\n");
+    break;
+
+    }

I'll move the "case" to the step 7 as it should be.

Fred
fred.konrad@greensocs.com - Dec. 13, 2012, 8:57 a.m.
On 11/12/2012 18:50, Peter Maydell wrote:
> On 10 December 2012 16:45,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> Here the virtio-blk-pci is modified for the new API. The device virtio-pci-blk
>> extends virtio-pci. It creates and connects a virtio-blk during the init.
> Did you check whether this maintains backwards compatibility
> for vmstate migration information and device properties?
> (haven't investigated myself yet, just asking whether you have)
>
> -- PMM
What do you mean exactly by backwards compatibility for vmstate migration ?

The device properties didn't change.
The virtio-blk-pci creates a virtio-blk device, puts the virtio block 
properties and  inits the virtio-blk.
fred.konrad@greensocs.com - Dec. 13, 2012, 9:24 a.m.
On 12/12/2012 18:58, Peter Maydell wrote:
> On 12 December 2012 17:53, Andreas Färber <afaerber@suse.de> wrote:
>> Am 12.12.2012 15:25, schrieb Peter Maydell:
>>> How will the PCI transport's PCI vendor/device/class IDs be
>>> set (a) when a virtio-blk backend is created and separately
>>> plugged into a virtio-pci transport (b) for the legacy
>>> virtio-pci-blk? [ideally the answer to (b) should be "in the
>>> same way as for (a)"]
>> The obvious answer would be that PCI properties need to be set on the
>> PCI device, not an a VirtioDevice sitting on a virtio-bus.
>>
>> I.e., with the proposed refactoring we'd have on the virtio-bus:
>>
>> - VirtioDevice
>>    + VirtioBlockDevice
>>    + VirtioSCSIDevice - has-a scsi-bus
>>    ...
>>
>> In turn that means that every VirtioDevice to be exposed as PCI device
>> to the guest needs it own PCIDevice exposing a private virtio-bus.
>>
>> - PCIDevice
>>    - VirtioPCIDevice - has-a virtio-bus
>>      + virtio-blk-pci - has-a VirtioBlockDevice on its virtio-bus
>>      + virtio-scsi-pci - has-a VirtioSCSIDevice on its virtio-bus
>>      ...
> ...this bit is only for legacy back-compat. It should be equally
> valid to just use the PCI transport plugged into a VirtioDevice,
> both of which were created by the user with -device [and for
> new transports, separate transport and backend should be the
> standard]. That means the virtio-bus interface needs a way for
> the backend to announce to the transport what it is so that
> the PCI transport can set the right PCI IDs.
>
> -- PMM
Yes, it's done with uint16_t get_virtio_device_id(VirtioBusState *bus) 
function from second step.
Paolo Bonzini - Dec. 13, 2012, 9:37 a.m.
Il 12/12/2012 22:22, Michael S. Tsirkin ha scritto:
> > > It should be equally
> > > valid to just use the PCI transport plugged into a VirtioDevice,
> > > both of which were created by the user with -device [and for
> > > new transports, separate transport and backend should be the
> > > standard]. That means the virtio-bus interface needs a way for
> > > the backend to announce to the transport what it is so that
> > > the PCI transport can set the right PCI IDs.
> > 
> > There is such an interface (the device_id, aka VIRTIO_ID_*).  Then
> > virtio-pci needs a mapping from the device_id to the (default)
> > vendor_id/device_id/class tuple.
> 
> At least device id and vedor id are easy.

Class too, this is a new device virtio-pci so it doesn't need to support
old machine types.

Paolo
fred.konrad@greensocs.com - Dec. 13, 2012, 10:56 a.m.
On 13/12/2012 09:24, KONRAD Frédéric wrote:
> On 12/12/2012 15:25, Peter Maydell wrote:
>> On 10 December 2012 16:45, <fred.konrad@greensocs.com> wrote:
>>> -static void virtio_blk_class_init(ObjectClass *klass, void *data)
>>> -{
>>> -    DeviceClass *dc = DEVICE_CLASS(klass);
>>> -    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>>> -
>>> -    k->init = virtio_blk_init_pci;
>>> -    k->exit = virtio_blk_exit_pci;
>>> -    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
>>> -    k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
>>> -    k->revision = VIRTIO_PCI_ABI_VERSION;
>>> -    k->class_id = PCI_CLASS_STORAGE_SCSI;
>>> -    dc->reset = virtio_pci_reset;
>>> -    dc->props = virtio_blk_properties;
>>> -}
>> This hunk removes the setting of the PCI vendor and device IDs
>> but I can't see where they are set in the new code.
>>
>> How will the PCI transport's PCI vendor/device/class IDs be
>> set (a) when a virtio-blk backend is created and separately
>> plugged into a virtio-pci transport (b) for the legacy
>> virtio-pci-blk? [ideally the answer to (b) should be "in the
>> same way as for (a)"]
>>
>> -- PMM
>
> It's done in the virtio_pci_device_plugged(), ( step 4 )
> At this time we have the device ID, so we can put the PCI IDs :
>
> +static void virtio_pci_device_plugged(void *opaque)
> +{
> +    VirtIOPCIProxy *proxy = VIRTIO_PCI(opaque);
> +    uint8_t *config;
> +    uint32_t size;
> +
> +    /* Put the PCI IDs */
> +    switch (get_virtio_device_id(proxy->bus)) {
> +
> +    case VIRTIO_ID_BLOCK:
> +        pci_config_set_device_id(proxy->pci_dev.config,
> +                                 PCI_DEVICE_ID_VIRTIO_BLOCK);
> +        pci_config_set_class(proxy->pci_dev.config, 
> PCI_CLASS_STORAGE_SCSI);
> +    break;
> +    default:
> +        error_report("unknown device id\n");
> +    break;
> +
> +    }
>
> I'll move the "case" to the step 7 as it should be.
>
I meant step 6* : Add the virtio-blk device.

the virtio-blk-pci set the PCI IDs on the same way as for virtio-blk.

> Fred
>
>
Anthony Liguori - Dec. 13, 2012, 2:51 p.m.
Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 12/12/2012 18:58, Peter Maydell ha scritto:
>> It should be equally
>> valid to just use the PCI transport plugged into a VirtioDevice,
>> both of which were created by the user with -device [and for
>> new transports, separate transport and backend should be the
>> standard]. That means the virtio-bus interface needs a way for
>> the backend to announce to the transport what it is so that
>> the PCI transport can set the right PCI IDs.
>
> There is such an interface (the device_id, aka VIRTIO_ID_*).  Then
> virtio-pci needs a mapping from the device_id to the (default)
> vendor_id/device_id/class tuple.

Why?

I think it's perfectly fine to have to specify a device ID for
virtio-pci.

The way virtio-pci is designed is such that every device that uses
virtio-pci ends up looking like an independent PCI device.

We should always have virtio-blk-pci, virtio-net-pci, etc.  The goal of
this refactoring should not be to eliminate that.

But these devices should be trivial to implement and modelled in a sane
way.

I don't think we should be trying to solve the problem of making
virtio-pci "easy to use".  Why would you say:

  -device virtio-pci,id=foo -device virtio-blk,bus=foo

When you can just say:

  -device virtio-pci-blk

I think we're optimizing for the wrong thing here...

Regards,

Anthony Liguori

>
> Paolo
Michael S. Tsirkin - Dec. 16, 2012, 4:01 p.m.
On Thu, Dec 13, 2012 at 08:51:30AM -0600, Anthony Liguori wrote:
> Paolo Bonzini <pbonzini@redhat.com> writes:
> 
> > Il 12/12/2012 18:58, Peter Maydell ha scritto:
> >> It should be equally
> >> valid to just use the PCI transport plugged into a VirtioDevice,
> >> both of which were created by the user with -device [and for
> >> new transports, separate transport and backend should be the
> >> standard]. That means the virtio-bus interface needs a way for
> >> the backend to announce to the transport what it is so that
> >> the PCI transport can set the right PCI IDs.
> >
> > There is such an interface (the device_id, aka VIRTIO_ID_*).  Then
> > virtio-pci needs a mapping from the device_id to the (default)
> > vendor_id/device_id/class tuple.
> 
> Why?
> 
> I think it's perfectly fine to have to specify a device ID for
> virtio-pci.
> 
> The way virtio-pci is designed is such that every device that uses
> virtio-pci ends up looking like an independent PCI device.
> 
> We should always have virtio-blk-pci, virtio-net-pci, etc.  The goal of
> this refactoring should not be to eliminate that.
> 
> But these devices should be trivial to implement and modelled in a sane
> way.
> 
> I don't think we should be trying to solve the problem of making
> virtio-pci "easy to use".  Why would you say:
> 
>   -device virtio-pci,id=foo -device virtio-blk,bus=foo
> 
> When you can just say:
> 
>   -device virtio-pci-blk
> 
> I think we're optimizing for the wrong thing here...
> 
> Regards,
> 
> Anthony Liguori
> 
> >
> > Paolo


I agree. What I mean is this: virtio has device IDs.
These are not pci specific and are defined in linux/virtio_ids.h
Now it looks like pci device IDs of virtio devices are
pci id = 0x1000 + virtio device ID; so let's pull virtio_ids.h
from linux and write a macro that does + 0x1000 instead of hard-coding
values.

Makes sense?
Andreas Färber - Dec. 16, 2012, 4:41 p.m.
Am 12.12.2012 18:53, schrieb Andreas Färber:
> Finally supplying a public device_initialize() or so would be helpful
> for the latter since VMState cannot cross pointers IIRC. I'll look into
> that part since inlining the old qdev functions cripples my Tegra work.

Investigating this, it turned out that my branch was outdated in still
calling qdev_prop_set_globals(), which some good soul (Paolo?) inlined
into device initfn. So the only step taken by qdev_try_create() that
remains after object_initialize() is qdev_set_parent_bus(), which I
think does not warrant a

device_post_initialize:
-> qdev_set_parent_bus()

qdev_try_create:
-> object_new()
-> device_post_initialize()

qdev_create:
-> qdev_try_create()

device_initialize:
-> object_initialize()
-> device_post_initialize()

construction.

So, given that virtio device states are in (or moved to) a header, they
can already be embedded in a has-a virtio-bus has-a Virtio*Device device
today and initialized with object_initialize(&s->the_device) and
qdev_set_parent_bus(&s->the_device, &s->the_virtio_bus).

Andreas

Patch

diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 8de26fd..776a5b4 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -734,26 +734,6 @@  void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
     proxy->host_features = vdev->get_features(vdev, proxy->host_features);
 }
 
-static int virtio_blk_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    if (proxy->class_code != PCI_CLASS_STORAGE_SCSI &&
-        proxy->class_code != PCI_CLASS_STORAGE_OTHER)
-        proxy->class_code = PCI_CLASS_STORAGE_SCSI;
-
-    vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk);
-    if (!vdev) {
-        return -1;
-    }
-    vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev);
-    /* make the actual value visible */
-    proxy->nvectors = vdev->nvectors;
-    return 0;
-}
-
 static void virtio_exit_pci(PCIDevice *pci_dev)
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
@@ -762,15 +742,6 @@  static void virtio_exit_pci(PCIDevice *pci_dev)
     msix_uninit_exclusive_bar(pci_dev);
 }
 
-static void virtio_blk_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_blk_exit(proxy->vdev);
-    virtio_exit_pci(pci_dev);
-}
-
 static int virtio_serial_init_pci(PCIDevice *pci_dev)
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
@@ -888,43 +859,6 @@  static void virtio_rng_exit_pci(PCIDevice *pci_dev)
     virtio_exit_pci(pci_dev);
 }
 
-static Property virtio_blk_properties[] = {
-    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-    DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
-    DEFINE_BLOCK_CHS_PROPERTIES(VirtIOPCIProxy, blk.conf),
-    DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial),
-#ifdef __linux__
-    DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
-#endif
-    DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true),
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-    DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_blk_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_blk_init_pci;
-    k->exit = virtio_blk_exit_pci;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_STORAGE_SCSI;
-    dc->reset = virtio_pci_reset;
-    dc->props = virtio_blk_properties;
-}
-
-static TypeInfo virtio_blk_info = {
-    .name          = "virtio-blk-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .class_init    = virtio_blk_class_init,
-};
-
 static Property virtio_net_properties[] = {
     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
@@ -1243,6 +1177,51 @@  static const TypeInfo virtio_pci_info = {
     .class_size    = sizeof(VirtioPCIClass),
 };
 
+/* virtio-blk-pci */
+
+static Property virtio_blk_pci_properties[] = {
+    DEFINE_PROP_HEX32("class", VirtIOBlkPCI, parent_obj.class_code, 0),
+    DEFINE_BLOCK_PROPERTIES(VirtIOBlkPCI, blk.conf),
+    DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlkPCI, blk.conf),
+    DEFINE_PROP_STRING("serial", VirtIOBlkPCI, blk.serial),
+#ifdef __linux__
+    DEFINE_PROP_BIT("scsi", VirtIOBlkPCI, blk.scsi, 0, true),
+#endif
+    DEFINE_PROP_BIT("config-wce", VirtIOBlkPCI, blk.config_wce, 0, true),
+    DEFINE_PROP_BIT("ioeventfd", VirtIOBlkPCI, parent_obj.flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOBlkPCI, parent_obj.nvectors, 2),
+    DEFINE_VIRTIO_BLK_FEATURES(VirtIOBlkPCI, parent_obj.host_features),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    DeviceState *vdev;
+    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
+    vdev = qdev_create(BUS(vpci_dev->bus), "virtio-blk");
+    virtio_blk_set_conf(vdev, &(dev->blk));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    dc->props = virtio_blk_pci_properties;
+    k->init = virtio_blk_pci_init;
+}
+
+static const TypeInfo virtio_blk_pci_info = {
+    .name          = TYPE_VIRTIO_BLK_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOBlkPCI),
+    .class_init    = virtio_blk_pci_class_init,
+};
+
 /* virtio-pci-bus */
 
 VirtioBusState *virtio_pci_bus_new(VirtIOPCIProxy *dev)
@@ -1282,7 +1261,6 @@  static const TypeInfo virtio_pci_bus_info = {
 
 static void virtio_pci_register_types(void)
 {
-    type_register_static(&virtio_blk_info);
     type_register_static(&virtio_net_info);
     type_register_static(&virtio_serial_info);
     type_register_static(&virtio_balloon_info);
@@ -1290,6 +1268,7 @@  static void virtio_pci_register_types(void)
     type_register_static(&virtio_rng_info);
     type_register_static(&virtio_pci_bus_info);
     type_register_static(&virtio_pci_info);
+    type_register_static(&virtio_blk_pci_info);
 }
 
 type_init(virtio_pci_register_types)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index e840cea..8a68d6e 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -24,6 +24,7 @@ 
 
 /* VirtIOPCIProxy will be renammed VirtioPCIState at the end. */
 typedef struct VirtIOPCIProxy VirtIOPCIProxy;
+typedef struct VirtIOBlkPCI VirtIOBlkPCI;
 
 /* virtio-pci-bus */
 #define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus"
@@ -69,7 +70,6 @@  struct VirtIOPCIProxy {
     uint32_t flags;
     uint32_t class_code;
     uint32_t nvectors;
-    VirtIOBlkConf blk;
     NICConf nic;
     uint32_t host_features;
 #ifdef CONFIG_LINUX
@@ -87,6 +87,18 @@  struct VirtIOPCIProxy {
     /* Nothing more for the moment. */
 };
 
+/*
+ * virtio-blk-pci : This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci"
+#define VIRTIO_BLK_PCI(obj) \
+        OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
+
+struct VirtIOBlkPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOBlkConf blk;
+};
+
 void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
 void virtio_pci_reset(DeviceState *d);