scsi: convert to QEMU Object Model

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2011-12-15 14:50:08 -06:00
parent d148211c6d
commit b9eea3e6a4
4 changed files with 201 additions and 113 deletions

View File

@ -23,6 +23,42 @@ static struct BusInfo scsi_bus_info = {
};
static int next_scsi_bus;
static int scsi_device_init(SCSIDevice *s)
{
SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
if (sc->init) {
return sc->init(s);
}
return 0;
}
static void scsi_device_destroy(SCSIDevice *s)
{
SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
if (sc->destroy) {
sc->destroy(s);
}
}
static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private)
{
SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
if (sc->alloc_req) {
return sc->alloc_req(s, tag, lun, buf, hba_private);
}
return NULL;
}
static void scsi_device_unit_attention_reported(SCSIDevice *s)
{
SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
if (sc->unit_attention_reported) {
sc->unit_attention_reported(s);
}
}
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
{
@ -81,8 +117,7 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
SCSIDevice *d;
int rc = -1;
@ -126,9 +161,8 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
}
}
dev->info = info;
QTAILQ_INIT(&dev->requests);
rc = dev->info->init(dev);
rc = scsi_device_init(dev);
if (rc == 0) {
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev);
@ -140,24 +174,22 @@ err:
static int scsi_qdev_exit(DeviceState *qdev)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
if (dev->info->destroy) {
dev->info->destroy(dev);
}
scsi_device_destroy(dev);
return 0;
}
void scsi_qdev_register(SCSIDeviceInfo *info)
void scsi_qdev_register(DeviceInfo *info)
{
info->qdev.bus_info = &scsi_bus_info;
info->qdev.init = scsi_qdev_init;
info->qdev.unplug = qdev_simple_unplug_cb;
info->qdev.exit = scsi_qdev_exit;
qdev_register(&info->qdev);
info->bus_info = &scsi_bus_info;
info->init = scsi_qdev_init;
info->unplug = qdev_simple_unplug_cb;
info->exit = scsi_qdev_exit;
qdev_register_subclass(info, TYPE_SCSI_DEVICE);
}
/* handle legacy '-drive if=scsi,...' cmd line args */
@ -182,7 +214,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
}
if (qdev_init(dev) < 0)
return NULL;
return DO_UPCAST(SCSIDevice, qdev, dev);
return SCSI_DEVICE(dev);
}
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
@ -278,7 +310,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
@ -300,7 +332,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
@ -398,9 +430,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
MIN(req->cmd.xfer, sizeof r->buf),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
if (r->req.dev->info->unit_attention_reported) {
r->req.dev->info->unit_attention_reported(req->dev);
}
scsi_device_unit_attention_reported(req->dev);
r->req.dev->sense_len = 0;
r->req.dev->sense_is_ua = false;
}
@ -507,7 +537,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
req = d->info->alloc_req(d, tag, lun, buf, hba_private);
req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
}
}
@ -597,9 +627,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
*/
if (req->dev->sense_is_ua) {
if (req->dev->info->unit_attention_reported) {
req->dev->info->unit_attention_reported(req->dev);
}
scsi_device_unit_attention_reported(req->dev);
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
@ -1367,7 +1395,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
SCSIDevice *d = SCSI_DEVICE(dev);
char path[100];
snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
@ -1382,7 +1410,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
@ -1393,3 +1421,18 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
}
return target_dev;
}
static TypeInfo scsi_device_type_info = {
.name = TYPE_SCSI_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SCSIDevice),
.abstract = true,
.class_size = sizeof(SCSIDeviceClass),
};
static void scsi_register_devices(void)
{
type_register_static(&scsi_device_type_info);
}
device_init(scsi_register_devices);

View File

@ -1712,75 +1712,108 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
DEFINE_PROP_STRING("serial", SCSIDiskState, serial)
static SCSIDeviceInfo scsi_disk_info[] = {
{
.qdev.name = "scsi-hd",
.qdev.fw_name = "disk",
.qdev.desc = "virtual SCSI disk",
.qdev.size = sizeof(SCSIDiskState),
.qdev.reset = scsi_disk_reset,
.init = scsi_hd_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.unit_attention_reported = scsi_disk_unit_attention_reported,
.qdev.props = (Property[]) {
static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
{
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->init = scsi_hd_initfn;
sc->destroy = scsi_destroy;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
}
static DeviceInfo scsi_hd_info = {
.name = "scsi-hd",
.fw_name = "disk",
.desc = "virtual SCSI disk",
.size = sizeof(SCSIDiskState),
.reset = scsi_disk_reset,
.class_init = scsi_hd_class_initfn,
.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
}
},{
.qdev.name = "scsi-cd",
.qdev.fw_name = "disk",
.qdev.desc = "virtual SCSI CD-ROM",
.qdev.size = sizeof(SCSIDiskState),
.qdev.reset = scsi_disk_reset,
.init = scsi_cd_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.unit_attention_reported = scsi_disk_unit_attention_reported,
.qdev.props = (Property[]) {
},
};
static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
{
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->init = scsi_cd_initfn;
sc->destroy = scsi_destroy;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
}
static DeviceInfo scsi_cd_info = {
.name = "scsi-cd",
.fw_name = "disk",
.desc = "virtual SCSI CD-ROM",
.size = sizeof(SCSIDiskState),
.reset = scsi_disk_reset,
.class_init = scsi_cd_class_initfn,
.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_END_OF_LIST(),
},
};
#ifdef __linux__
},{
.qdev.name = "scsi-block",
.qdev.fw_name = "disk",
.qdev.desc = "SCSI block device passthrough",
.qdev.size = sizeof(SCSIDiskState),
.qdev.reset = scsi_disk_reset,
.init = scsi_block_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_block_new_request,
.qdev.props = (Property[]) {
static void scsi_block_class_initfn(ObjectClass *klass, void *data)
{
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->init = scsi_block_initfn;
sc->destroy = scsi_destroy;
sc->alloc_req = scsi_block_new_request;
}
static DeviceInfo scsi_block_info = {
.name = "scsi-block",
.fw_name = "disk",
.desc = "SCSI block device passthrough",
.size = sizeof(SCSIDiskState),
.reset = scsi_disk_reset,
.class_init = scsi_block_class_initfn,
.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_END_OF_LIST(),
},
};
#endif
},{
.qdev.name = "scsi-disk", /* legacy -device scsi-disk */
.qdev.fw_name = "disk",
.qdev.desc = "virtual SCSI disk or CD-ROM (legacy)",
.qdev.size = sizeof(SCSIDiskState),
.qdev.reset = scsi_disk_reset,
.init = scsi_disk_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.unit_attention_reported = scsi_disk_unit_attention_reported,
.qdev.props = (Property[]) {
static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
{
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->init = scsi_disk_initfn;
sc->destroy = scsi_destroy;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
}
static DeviceInfo scsi_disk_info = {
.name = "scsi-disk", /* legacy -device scsi-disk */
.fw_name = "disk",
.desc = "virtual SCSI disk or CD-ROM (legacy)",
.size = sizeof(SCSIDiskState),
.reset = scsi_disk_reset,
.class_init = scsi_disk_class_initfn,
.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
}
}
};
static void scsi_disk_register_devices(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
scsi_qdev_register(&scsi_disk_info[i]);
}
scsi_qdev_register(&scsi_hd_info);
scsi_qdev_register(&scsi_cd_info);
#ifdef __linux__
scsi_qdev_register(&scsi_block_info);
#endif
scsi_qdev_register(&scsi_disk_info);
}
device_init(scsi_disk_register_devices)

View File

@ -357,7 +357,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
static void scsi_generic_reset(DeviceState *dev)
{
SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
SCSIDevice *s = SCSI_DEVICE(dev);
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
@ -457,16 +457,23 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
return req;
}
static SCSIDeviceInfo scsi_generic_info = {
.qdev.name = "scsi-generic",
.qdev.fw_name = "disk",
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
.qdev.size = sizeof(SCSIDevice),
.qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.qdev.props = (Property[]) {
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
{
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->init = scsi_generic_initfn;
sc->destroy = scsi_destroy;
sc->alloc_req = scsi_new_request;
}
static DeviceInfo scsi_generic_info = {
.name = "scsi-generic",
.fw_name = "disk",
.desc = "pass through generic scsi device (/dev/sg*)",
.size = sizeof(SCSIDevice),
.reset = scsi_generic_reset,
.class_init = scsi_generic_class_initfn,
.props = (Property[]) {
DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
DEFINE_PROP_END_OF_LIST(),
},

View File

@ -13,7 +13,6 @@ typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusInfo SCSIBusInfo;
typedef struct SCSICommand SCSICommand;
typedef struct SCSIDevice SCSIDevice;
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIRequest SCSIRequest;
typedef struct SCSIReqOps SCSIReqOps;
@ -58,6 +57,23 @@ struct SCSIRequest {
QTAILQ_ENTRY(SCSIRequest) next;
};
#define TYPE_SCSI_DEVICE "scsi-device"
#define SCSI_DEVICE(obj) \
OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
#define SCSI_DEVICE_CLASS(klass) \
OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
#define SCSI_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
typedef struct SCSIDeviceClass {
DeviceClass parent_class;
int (*init)(SCSIDevice *dev);
void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
} SCSIDeviceClass;
struct SCSIDevice
{
DeviceState qdev;
@ -65,7 +81,6 @@ struct SCSIDevice
QEMUBH *bh;
uint32_t id;
BlockConf conf;
SCSIDeviceInfo *info;
SCSISense unit_attention;
bool sense_is_ua;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
@ -93,16 +108,6 @@ struct SCSIReqOps {
uint8_t *(*get_buf)(SCSIRequest *req);
};
typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
struct SCSIDeviceInfo {
DeviceInfo qdev;
scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
};
struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
@ -120,7 +125,7 @@ struct SCSIBus {
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
void scsi_qdev_register(SCSIDeviceInfo *info);
void scsi_qdev_register(DeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
{