virtio-scsi: create VirtIOSCSICommon

This patch refactors existing virtio-scsi code into VirtIOSCSICommon
in order to allow virtio_scsi_init_common() to be used by both internal
virtio_scsi_init() and external vhost-scsi-pci code.

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Asias He <asias@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2013-03-29 01:08:15 +00:00
parent af60314291
commit 292c8e50d5
6 changed files with 211 additions and 149 deletions

View File

@ -560,7 +560,7 @@ static const TypeInfo virtio_s390_device_info = {
}; };
static Property s390_virtio_scsi_properties[] = { static Property s390_virtio_scsi_properties[] = {
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.conf), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.parent_obj.conf),
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -873,7 +873,7 @@ static const TypeInfo virtio_ccw_balloon = {
static Property virtio_ccw_scsi_properties[] = { static Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.conf), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]), DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -19,118 +19,6 @@
#include <block/scsi.h> #include <block/scsi.h>
#include <hw/virtio/virtio-bus.h> #include <hw/virtio/virtio-bus.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
#define VIRTIO_SCSI_T_PARAM_CHANGE 3
/* Reasons for transport reset event */
#define VIRTIO_SCSI_EVT_RESET_HARD 0
#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
#define VIRTIO_SCSI_EVT_RESET_REMOVED 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 VirtIOSCSIReq { typedef struct VirtIOSCSIReq {
VirtIOSCSI *dev; VirtIOSCSI *dev;
VirtQueue *vq; VirtQueue *vq;
@ -237,9 +125,10 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
{ {
VirtIOSCSIReq *req = sreq->hba_private; VirtIOSCSIReq *req = sreq->hba_private;
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev);
uint32_t n = virtio_queue_get_id(req->vq) - 2; uint32_t n = virtio_queue_get_id(req->vq) - 2;
assert(n < req->dev->conf.num_queues); assert(n < vs->conf.num_queues);
qemu_put_be32s(f, &n); qemu_put_be32s(f, &n);
qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
} }
@ -248,14 +137,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
{ {
SCSIBus *bus = sreq->bus; SCSIBus *bus = sreq->bus;
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
VirtIOSCSIReq *req; VirtIOSCSIReq *req;
uint32_t n; uint32_t n;
req = g_malloc(sizeof(*req)); req = g_malloc(sizeof(*req));
qemu_get_be32s(f, &n); qemu_get_be32s(f, &n);
assert(n < s->conf.num_queues); assert(n < vs->conf.num_queues);
qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
virtio_scsi_parse_req(s, s->cmd_vqs[n], req); virtio_scsi_parse_req(s, vs->cmd_vqs[n], req);
scsi_req_ref(sreq); scsi_req_ref(sreq);
req->sreq = sreq; req->sreq = sreq;
@ -457,7 +347,10 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
{ {
/* use non-QOM casts in the data path */
VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSI *s = (VirtIOSCSI *)vdev;
VirtIOSCSICommon *vs = &s->parent_obj;
VirtIOSCSIReq *req; VirtIOSCSIReq *req;
int n; int n;
@ -470,8 +363,8 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
out_size = req->elem.out_sg[0].iov_len; out_size = req->elem.out_sg[0].iov_len;
in_size = req->elem.in_sg[0].iov_len; in_size = req->elem.in_sg[0].iov_len;
if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || if (out_size < sizeof(VirtIOSCSICmdReq) + vs->cdb_size ||
in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) { in_size < sizeof(VirtIOSCSICmdResp) + vs->sense_size) {
virtio_scsi_bad_req(); virtio_scsi_bad_req();
} }
@ -513,7 +406,7 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
uint8_t *config) uint8_t *config)
{ {
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
stl_raw(&scsiconf->num_queues, s->conf.num_queues); stl_raw(&scsiconf->num_queues, s->conf.num_queues);
stl_raw(&scsiconf->seg_max, 128 - 2); stl_raw(&scsiconf->seg_max, 128 - 2);
@ -531,7 +424,7 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
const uint8_t *config) const uint8_t *config)
{ {
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 || if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
(uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) { (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
@ -539,8 +432,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
exit(1); exit(1);
} }
s->sense_size = ldl_raw(&scsiconf->sense_size); vs->sense_size = ldl_raw(&scsiconf->sense_size);
s->cdb_size = ldl_raw(&scsiconf->cdb_size); vs->cdb_size = ldl_raw(&scsiconf->cdb_size);
} }
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
@ -551,14 +444,15 @@ static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
static void virtio_scsi_reset(VirtIODevice *vdev) static void virtio_scsi_reset(VirtIODevice *vdev)
{ {
VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSI *s = VIRTIO_SCSI(vdev);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
s->resetting++; s->resetting++;
qbus_reset_all(&s->bus.qbus); qbus_reset_all(&s->bus.qbus);
s->resetting--; s->resetting--;
s->sense_size = VIRTIO_SCSI_SENSE_SIZE; vs->sense_size = VIRTIO_SCSI_SENSE_SIZE;
s->cdb_size = VIRTIO_SCSI_CDB_SIZE; vs->cdb_size = VIRTIO_SCSI_CDB_SIZE;
s->events_dropped = false; s->events_dropped = false;
} }
@ -586,7 +480,8 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
uint32_t event, uint32_t reason) uint32_t event, uint32_t reason)
{ {
VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq);
VirtIOSCSIEvent *evt; VirtIOSCSIEvent *evt;
VirtIODevice *vdev = VIRTIO_DEVICE(s); VirtIODevice *vdev = VIRTIO_DEVICE(s);
int in_size; int in_size;
@ -692,23 +587,19 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.load_request = virtio_scsi_load_request, .load_request = virtio_scsi_load_request,
}; };
static int virtio_scsi_device_init(VirtIODevice *vdev) int virtio_scsi_common_init(VirtIOSCSICommon *s)
{ {
DeviceState *qdev = DEVICE(vdev); VirtIODevice *vdev = VIRTIO_DEVICE(s);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
static int virtio_scsi_id;
int i; int i;
virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI, virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
sizeof(VirtIOSCSIConfig)); sizeof(VirtIOSCSIConfig));
s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *)); s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
/* TODO set up vdev function pointers */
vdev->get_config = virtio_scsi_get_config; vdev->get_config = virtio_scsi_get_config;
vdev->set_config = virtio_scsi_set_config;
vdev->get_features = virtio_scsi_get_features;
vdev->reset = virtio_scsi_reset;
s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
virtio_scsi_handle_ctrl); virtio_scsi_handle_ctrl);
@ -719,6 +610,26 @@ static int virtio_scsi_device_init(VirtIODevice *vdev)
virtio_scsi_handle_cmd); virtio_scsi_handle_cmd);
} }
return 0;
}
static int virtio_scsi_device_init(VirtIODevice *vdev)
{
DeviceState *qdev = DEVICE(vdev);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
static int virtio_scsi_id;
int ret;
ret = virtio_scsi_common_init(vs);
if (ret < 0) {
return ret;
}
vdev->get_features = virtio_scsi_get_features;
vdev->set_config = virtio_scsi_set_config;
vdev->reset = virtio_scsi_reset;
scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info); scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info);
if (!qdev->hotplugged) { if (!qdev->hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus); scsi_bus_legacy_handle_cmdline(&s->bus);
@ -730,22 +641,36 @@ static int virtio_scsi_device_init(VirtIODevice *vdev)
return 0; return 0;
} }
static int virtio_scsi_device_exit(DeviceState *qdev) int virtio_scsi_common_exit(VirtIOSCSICommon *vs)
{ {
VirtIOSCSI *s = VIRTIO_SCSI(qdev); VirtIODevice *vdev = VIRTIO_DEVICE(vs);
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
unregister_savevm(qdev, "virtio-scsi", s); g_free(vs->cmd_vqs);
g_free(s->cmd_vqs);
virtio_common_cleanup(vdev); virtio_common_cleanup(vdev);
return 0; return 0;
} }
static int virtio_scsi_device_exit(DeviceState *qdev)
{
VirtIOSCSI *s = VIRTIO_SCSI(qdev);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
unregister_savevm(qdev, "virtio-scsi", s);
return virtio_scsi_common_exit(vs);
}
static Property virtio_scsi_properties[] = { static Property virtio_scsi_properties[] = {
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, conf), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
{
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
vdc->get_config = virtio_scsi_get_config;
}
static void virtio_scsi_class_init(ObjectClass *klass, void *data) static void virtio_scsi_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
@ -753,21 +678,28 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
dc->exit = virtio_scsi_device_exit; dc->exit = virtio_scsi_device_exit;
dc->props = virtio_scsi_properties; dc->props = virtio_scsi_properties;
vdc->init = virtio_scsi_device_init; vdc->init = virtio_scsi_device_init;
vdc->get_config = virtio_scsi_get_config;
vdc->set_config = virtio_scsi_set_config; vdc->set_config = virtio_scsi_set_config;
vdc->get_features = virtio_scsi_get_features; vdc->get_features = virtio_scsi_get_features;
vdc->reset = virtio_scsi_reset; vdc->reset = virtio_scsi_reset;
} }
static const TypeInfo virtio_scsi_common_info = {
.name = TYPE_VIRTIO_SCSI_COMMON,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOSCSICommon),
.class_init = virtio_scsi_common_class_init,
};
static const TypeInfo virtio_scsi_info = { static const TypeInfo virtio_scsi_info = {
.name = TYPE_VIRTIO_SCSI, .name = TYPE_VIRTIO_SCSI,
.parent = TYPE_VIRTIO_DEVICE, .parent = TYPE_VIRTIO_SCSI_COMMON,
.instance_size = sizeof(VirtIOSCSI), .instance_size = sizeof(VirtIOSCSI),
.class_init = virtio_scsi_class_init, .class_init = virtio_scsi_class_init,
}; };
static void virtio_register_types(void) static void virtio_register_types(void)
{ {
type_register_static(&virtio_scsi_common_info);
type_register_static(&virtio_scsi_info); type_register_static(&virtio_scsi_info);
} }

View File

@ -1236,7 +1236,7 @@ static Property virtio_scsi_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED), DEV_NVECTORS_UNSPECIFIED),
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.conf), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1244,9 +1244,10 @@ static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
{ {
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
vpci_dev->nvectors = dev->vdev.conf.num_queues + 3; vpci_dev->nvectors = vs->conf.num_queues + 3;
} }
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));

View File

@ -18,6 +18,10 @@
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/scsi/scsi.h" #include "hw/scsi/scsi.h"
#define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common"
#define VIRTIO_SCSI_COMMON(obj) \
OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON)
#define TYPE_VIRTIO_SCSI "virtio-scsi-device" #define TYPE_VIRTIO_SCSI "virtio-scsi-device"
#define VIRTIO_SCSI(obj) \ #define VIRTIO_SCSI(obj) \
OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI) OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
@ -31,24 +35,141 @@
#define VIRTIO_SCSI_F_HOTPLUG 1 #define VIRTIO_SCSI_F_HOTPLUG 1
#define VIRTIO_SCSI_F_CHANGE 2 #define VIRTIO_SCSI_F_CHANGE 2
#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
#define VIRTIO_SCSI_T_PARAM_CHANGE 3
/* Reasons for transport reset event */
#define VIRTIO_SCSI_EVT_RESET_HARD 0
#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
#define VIRTIO_SCSI_EVT_RESET_REMOVED 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;
struct VirtIOSCSIConf { struct VirtIOSCSIConf {
uint32_t num_queues; uint32_t num_queues;
uint32_t max_sectors; uint32_t max_sectors;
uint32_t cmd_per_lun; uint32_t cmd_per_lun;
}; };
typedef struct VirtIOSCSI { typedef struct VirtIOSCSICommon {
VirtIODevice parent_obj; VirtIODevice parent_obj;
VirtIOSCSIConf conf; VirtIOSCSIConf conf;
SCSIBus bus;
uint32_t sense_size; uint32_t sense_size;
uint32_t cdb_size; uint32_t cdb_size;
int resetting;
bool events_dropped;
VirtQueue *ctrl_vq; VirtQueue *ctrl_vq;
VirtQueue *event_vq; VirtQueue *event_vq;
VirtQueue **cmd_vqs; VirtQueue **cmd_vqs;
} VirtIOSCSICommon;
typedef struct {
VirtIOSCSICommon parent_obj;
SCSIBus bus;
int resetting;
bool events_dropped;
} VirtIOSCSI; } VirtIOSCSI;
#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field) \ #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field) \
@ -63,4 +184,8 @@ typedef struct VirtIOSCSI {
DEFINE_PROP_BIT("param_change", _state, _feature_field, \ DEFINE_PROP_BIT("param_change", _state, _feature_field, \
VIRTIO_SCSI_F_CHANGE, true) VIRTIO_SCSI_F_CHANGE, true)
int virtio_scsi_common_init(VirtIOSCSICommon *vs);
int virtio_scsi_common_exit(VirtIOSCSICommon *vs);
#endif /* _QEMU_VIRTIO_SCSI_H */ #endif /* _QEMU_VIRTIO_SCSI_H */

View File

@ -67,6 +67,10 @@ typedef signed int int_fast16_t;
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif #endif
#ifndef ROUND_UP
#define ROUND_UP(n,d) (((n) + (d) - 1) & -(d))
#endif
#ifndef DIV_ROUND_UP #ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#endif #endif