virtio-scsi: Add virtio-scsi stub device
Add a useless virtio SCSI HBA device: qemu -device virtio-scsi-pci Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
43b978b932
commit
973abc7f41
@ -200,6 +200,7 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
|
||||
# need to fix this properly
|
||||
obj-$(CONFIG_NO_PCI) += pci-stub.o
|
||||
obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi.o
|
||||
obj-y += vhost_net.o
|
||||
obj-$(CONFIG_VHOST_NET) += vhost.o
|
||||
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
|
||||
|
@ -1,5 +1,6 @@
|
||||
CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_SCSI=y
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_USB_OHCI=y
|
||||
|
@ -1 +1,2 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_VIRTIO_SCSI=y
|
||||
|
1
hw/pci.h
1
hw/pci.h
@ -75,6 +75,7 @@
|
||||
#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
|
||||
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
|
||||
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
|
||||
#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
|
||||
|
||||
#define FMT_PCIBUS PRIx64
|
||||
|
||||
|
@ -169,6 +169,18 @@ static int s390_virtio_serial_init(VirtIOS390Device *dev)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int s390_virtio_scsi_init(VirtIOS390Device *dev)
|
||||
{
|
||||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_scsi_init((DeviceState *)dev, &dev->scsi);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s390_virtio_device_init(dev, vdev);
|
||||
}
|
||||
|
||||
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
|
||||
{
|
||||
ram_addr_t token_off;
|
||||
@ -433,6 +445,26 @@ static TypeInfo virtio_s390_device_info = {
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static Property s390_virtio_scsi_properties[] = {
|
||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOS390Device, host_features, scsi),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_scsi_init;
|
||||
dc->props = s390_virtio_scsi_properties;
|
||||
}
|
||||
|
||||
static TypeInfo s390_virtio_scsi = {
|
||||
.name = "virtio-scsi-s390",
|
||||
.parent = TYPE_VIRTIO_S390_DEVICE,
|
||||
.instance_size = sizeof(VirtIOS390Device),
|
||||
.class_init = s390_virtio_scsi_class_init,
|
||||
};
|
||||
|
||||
/***************** S390 Virtio Bus Bridge Device *******************/
|
||||
/* Only required to have the virtio bus as child in the system bus */
|
||||
@ -465,6 +497,7 @@ static void s390_virtio_register_types(void)
|
||||
type_register_static(&s390_virtio_serial);
|
||||
type_register_static(&s390_virtio_blk);
|
||||
type_register_static(&s390_virtio_net);
|
||||
type_register_static(&s390_virtio_scsi);
|
||||
type_register_static(&s390_virtio_bridge_info);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
|
||||
#define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */
|
||||
#define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */
|
||||
@ -67,6 +68,7 @@ struct VirtIOS390Device {
|
||||
uint32_t host_features;
|
||||
virtio_serial_conf serial;
|
||||
virtio_net_conf net;
|
||||
VirtIOSCSIConf scsi;
|
||||
};
|
||||
|
||||
typedef struct VirtIOS390Bus {
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "virtio-blk.h"
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
#include "pci.h"
|
||||
#include "qemu-error.h"
|
||||
#include "msix.h"
|
||||
@ -930,12 +931,67 @@ static TypeInfo virtio_balloon_info = {
|
||||
.class_init = virtio_balloon_class_init,
|
||||
};
|
||||
|
||||
static int virtio_scsi_init_pci(PCIDevice *pci_dev)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
|
||||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi);
|
||||
if (!vdev) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vdev->nvectors = proxy->nvectors;
|
||||
virtio_init_pci(proxy, vdev);
|
||||
|
||||
/* make the actual value visible */
|
||||
proxy->nvectors = vdev->nvectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_scsi_exit_pci(PCIDevice *pci_dev)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
|
||||
|
||||
virtio_scsi_exit(proxy->vdev);
|
||||
return virtio_exit_pci(pci_dev);
|
||||
}
|
||||
|
||||
static Property virtio_scsi_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_scsi_init_pci;
|
||||
k->exit = virtio_scsi_exit_pci;
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
|
||||
k->revision = 0x00;
|
||||
k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
dc->reset = virtio_pci_reset;
|
||||
dc->props = virtio_scsi_properties;
|
||||
}
|
||||
|
||||
static TypeInfo virtio_scsi_info = {
|
||||
.name = "virtio-scsi-pci",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(VirtIOPCIProxy),
|
||||
.class_init = virtio_scsi_class_init,
|
||||
};
|
||||
|
||||
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);
|
||||
type_register_static(&virtio_scsi_info);
|
||||
}
|
||||
|
||||
type_init(virtio_pci_register_types)
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
|
||||
/* Performance improves when virtqueue kick processing is decoupled from the
|
||||
* vcpu thread using ioeventfd for some devices. */
|
||||
@ -40,6 +41,7 @@ typedef struct {
|
||||
#endif
|
||||
virtio_serial_conf serial;
|
||||
virtio_net_conf net;
|
||||
VirtIOSCSIConf scsi;
|
||||
bool ioeventfd_disabled;
|
||||
bool ioeventfd_started;
|
||||
} VirtIOPCIProxy;
|
||||
|
228
hw/virtio-scsi.c
Normal file
228
hw/virtio-scsi.c
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Virtio SCSI HBA
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
* Copyright Red Hat, Inc. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "virtio-scsi.h"
|
||||
#include <hw/scsi.h>
|
||||
#include <hw/scsi-defs.h>
|
||||
|
||||
#define VIRTIO_SCSI_VQ_SIZE 128
|
||||
#define VIRTIO_SCSI_CDB_SIZE 32
|
||||
#define VIRTIO_SCSI_SENSE_SIZE 96
|
||||
#define VIRTIO_SCSI_MAX_CHANNEL 0
|
||||
#define VIRTIO_SCSI_MAX_TARGET 255
|
||||
#define VIRTIO_SCSI_MAX_LUN 16383
|
||||
|
||||
/* Response codes */
|
||||
#define VIRTIO_SCSI_S_OK 0
|
||||
#define VIRTIO_SCSI_S_OVERRUN 1
|
||||
#define VIRTIO_SCSI_S_ABORTED 2
|
||||
#define VIRTIO_SCSI_S_BAD_TARGET 3
|
||||
#define VIRTIO_SCSI_S_RESET 4
|
||||
#define VIRTIO_SCSI_S_BUSY 5
|
||||
#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6
|
||||
#define VIRTIO_SCSI_S_TARGET_FAILURE 7
|
||||
#define VIRTIO_SCSI_S_NEXUS_FAILURE 8
|
||||
#define VIRTIO_SCSI_S_FAILURE 9
|
||||
#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10
|
||||
#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11
|
||||
#define VIRTIO_SCSI_S_INCORRECT_LUN 12
|
||||
|
||||
/* Controlq type codes. */
|
||||
#define VIRTIO_SCSI_T_TMF 0
|
||||
#define VIRTIO_SCSI_T_AN_QUERY 1
|
||||
#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2
|
||||
|
||||
/* Valid TMF subtypes. */
|
||||
#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0
|
||||
#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1
|
||||
#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2
|
||||
#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3
|
||||
#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4
|
||||
#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5
|
||||
#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6
|
||||
#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7
|
||||
|
||||
/* Events. */
|
||||
#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000
|
||||
#define VIRTIO_SCSI_T_NO_EVENT 0
|
||||
#define VIRTIO_SCSI_T_TRANSPORT_RESET 1
|
||||
#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
|
||||
|
||||
/* SCSI command request, followed by data-out */
|
||||
typedef struct {
|
||||
uint8_t lun[8]; /* Logical Unit Number */
|
||||
uint64_t tag; /* Command identifier */
|
||||
uint8_t task_attr; /* Task attribute */
|
||||
uint8_t prio;
|
||||
uint8_t crn;
|
||||
uint8_t cdb[];
|
||||
} QEMU_PACKED VirtIOSCSICmdReq;
|
||||
|
||||
/* Response, followed by sense data and data-in */
|
||||
typedef struct {
|
||||
uint32_t sense_len; /* Sense data length */
|
||||
uint32_t resid; /* Residual bytes in data buffer */
|
||||
uint16_t status_qualifier; /* Status qualifier */
|
||||
uint8_t status; /* Command completion status */
|
||||
uint8_t response; /* Response values */
|
||||
uint8_t sense[];
|
||||
} QEMU_PACKED VirtIOSCSICmdResp;
|
||||
|
||||
/* Task Management Request */
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t subtype;
|
||||
uint8_t lun[8];
|
||||
uint64_t tag;
|
||||
} QEMU_PACKED VirtIOSCSICtrlTMFReq;
|
||||
|
||||
typedef struct {
|
||||
uint8_t response;
|
||||
} QEMU_PACKED VirtIOSCSICtrlTMFResp;
|
||||
|
||||
/* Asynchronous notification query/subscription */
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint8_t lun[8];
|
||||
uint32_t event_requested;
|
||||
} QEMU_PACKED VirtIOSCSICtrlANReq;
|
||||
|
||||
typedef struct {
|
||||
uint32_t event_actual;
|
||||
uint8_t response;
|
||||
} QEMU_PACKED VirtIOSCSICtrlANResp;
|
||||
|
||||
typedef struct {
|
||||
uint32_t event;
|
||||
uint8_t lun[8];
|
||||
uint32_t reason;
|
||||
} QEMU_PACKED VirtIOSCSIEvent;
|
||||
|
||||
typedef struct {
|
||||
uint32_t num_queues;
|
||||
uint32_t seg_max;
|
||||
uint32_t max_sectors;
|
||||
uint32_t cmd_per_lun;
|
||||
uint32_t event_info_size;
|
||||
uint32_t sense_size;
|
||||
uint32_t cdb_size;
|
||||
uint16_t max_channel;
|
||||
uint16_t max_target;
|
||||
uint32_t max_lun;
|
||||
} QEMU_PACKED VirtIOSCSIConfig;
|
||||
|
||||
typedef struct {
|
||||
VirtIODevice vdev;
|
||||
DeviceState *qdev;
|
||||
VirtIOSCSIConf *conf;
|
||||
|
||||
VirtQueue *ctrl_vq;
|
||||
VirtQueue *event_vq;
|
||||
VirtQueue *cmd_vq;
|
||||
uint32_t sense_size;
|
||||
uint32_t cdb_size;
|
||||
} VirtIOSCSI;
|
||||
|
||||
static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void virtio_scsi_get_config(VirtIODevice *vdev,
|
||||
uint8_t *config)
|
||||
{
|
||||
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
||||
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
||||
|
||||
stl_raw(&scsiconf->num_queues, s->conf->num_queues);
|
||||
stl_raw(&scsiconf->seg_max, 128 - 2);
|
||||
stl_raw(&scsiconf->max_sectors, s->conf->max_sectors);
|
||||
stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun);
|
||||
stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
||||
stl_raw(&scsiconf->sense_size, s->sense_size);
|
||||
stl_raw(&scsiconf->cdb_size, s->cdb_size);
|
||||
stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
||||
stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
||||
stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
|
||||
}
|
||||
|
||||
static void virtio_scsi_set_config(VirtIODevice *vdev,
|
||||
const uint8_t *config)
|
||||
{
|
||||
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
||||
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
||||
|
||||
if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
|
||||
(uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
|
||||
error_report("bad data written to virtio-scsi configuration space");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s->sense_size = ldl_raw(&scsiconf->sense_size);
|
||||
s->cdb_size = ldl_raw(&scsiconf->cdb_size);
|
||||
}
|
||||
|
||||
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
|
||||
uint32_t requested_features)
|
||||
{
|
||||
return requested_features;
|
||||
}
|
||||
|
||||
static void virtio_scsi_reset(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
||||
|
||||
s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
|
||||
s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
|
||||
}
|
||||
|
||||
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
|
||||
{
|
||||
VirtIOSCSI *s;
|
||||
|
||||
s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
|
||||
sizeof(VirtIOSCSIConfig),
|
||||
sizeof(VirtIOSCSI));
|
||||
|
||||
s->qdev = dev;
|
||||
s->conf = proxyconf;
|
||||
|
||||
/* TODO set up vdev function pointers */
|
||||
s->vdev.get_config = virtio_scsi_get_config;
|
||||
s->vdev.set_config = virtio_scsi_set_config;
|
||||
s->vdev.get_features = virtio_scsi_get_features;
|
||||
s->vdev.reset = virtio_scsi_reset;
|
||||
|
||||
s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||
virtio_scsi_handle_ctrl);
|
||||
s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||
NULL);
|
||||
s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||
virtio_scsi_handle_cmd);
|
||||
|
||||
/* TODO savevm */
|
||||
|
||||
return &s->vdev;
|
||||
}
|
||||
|
||||
void virtio_scsi_exit(VirtIODevice *vdev)
|
||||
{
|
||||
virtio_cleanup(vdev);
|
||||
}
|
36
hw/virtio-scsi.h
Normal file
36
hw/virtio-scsi.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Virtio SCSI HBA
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
||||
*
|
||||
* 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_SCSI_H
|
||||
#define _QEMU_VIRTIO_SCSI_H
|
||||
|
||||
#include "virtio.h"
|
||||
#include "net.h"
|
||||
#include "pci.h"
|
||||
|
||||
/* The ID for virtio_scsi */
|
||||
#define VIRTIO_ID_SCSI 8
|
||||
|
||||
struct VirtIOSCSIConf {
|
||||
uint32_t num_queues;
|
||||
uint32_t max_sectors;
|
||||
uint32_t cmd_per_lun;
|
||||
};
|
||||
|
||||
#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \
|
||||
DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \
|
||||
DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
|
||||
|
||||
#endif /* _QEMU_VIRTIO_SCSI_H */
|
@ -199,6 +199,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
|
||||
typedef struct virtio_serial_conf virtio_serial_conf;
|
||||
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
|
||||
VirtIODevice *virtio_balloon_init(DeviceState *dev);
|
||||
typedef struct VirtIOSCSIConf VirtIOSCSIConf;
|
||||
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
|
||||
#ifdef CONFIG_LINUX
|
||||
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
|
||||
#endif
|
||||
@ -208,6 +210,7 @@ void virtio_net_exit(VirtIODevice *vdev);
|
||||
void virtio_blk_exit(VirtIODevice *vdev);
|
||||
void virtio_serial_exit(VirtIODevice *vdev);
|
||||
void virtio_balloon_exit(VirtIODevice *vdev);
|
||||
void virtio_scsi_exit(VirtIODevice *vdev);
|
||||
|
||||
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
|
||||
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
|
||||
|
Loading…
Reference in New Issue
Block a user