There are more operations than a SCSI bus can handle, besides completing
commands. One example, which this series will introduce, is cleaning up
after a request is cancelled.
More long term, a "SCSI bus" can represent the LUNs attached to a
target; in this case, while all commands will ultimately reach a logical
unit, it is the target who is in charge of answering REPORT LUNs.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
*dma_enable = qdev_get_gpio_in(dev, 1);
}
*dma_enable = qdev_get_gpio_in(dev, 1);
}
+static const struct SCSIBusOps esp_scsi_ops = {
+ .complete = esp_command_complete
+};
+
static int esp_init1(SysBusDevice *dev)
{
ESPState *s = FROM_SYSBUS(ESPState, dev);
static int esp_init1(SysBusDevice *dev)
{
ESPState *s = FROM_SYSBUS(ESPState, dev);
qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
- scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
+ scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops);
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
+static const struct SCSIBusOps lsi_scsi_ops = {
+ .complete = lsi_command_complete
+};
+
static int lsi_scsi_init(PCIDevice *dev)
{
LSIState *s = DO_UPCAST(LSIState, dev, dev);
static int lsi_scsi_init(PCIDevice *dev)
{
LSIState *s = DO_UPCAST(LSIState, dev, dev);
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
QTAILQ_INIT(&s->queue);
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
QTAILQ_INIT(&s->queue);
- scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
+ scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
if (!dev->qdev.hotplugged) {
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
if (!dev->qdev.hotplugged) {
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
- scsi_completionfn complete)
{
qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
bus->busnr = next_scsi_bus++;
bus->tcq = tcq;
bus->ndev = ndev;
{
qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
bus->busnr = next_scsi_bus++;
bus->tcq = tcq;
bus->ndev = ndev;
- bus->complete = complete;
bus->qbus.allow_hotplug = 1;
}
bus->qbus.allow_hotplug = 1;
}
void scsi_req_data(SCSIRequest *req, int len)
{
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
void scsi_req_data(SCSIRequest *req, int len)
{
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
- req->bus->complete(req->bus, SCSI_REASON_DATA, req->tag, len);
+ req->bus->ops->complete(req->bus, SCSI_REASON_DATA, req->tag, len);
}
void scsi_req_print(SCSIRequest *req)
}
void scsi_req_print(SCSIRequest *req)
{
assert(req->status != -1);
scsi_req_dequeue(req);
{
assert(req->status != -1);
scsi_req_dequeue(req);
- req->bus->complete(req->bus, SCSI_REASON_DONE,
- req->tag,
- req->status);
+ req->bus->ops->complete(req->bus, SCSI_REASON_DONE,
+ req->tag,
+ req->status);
}
static char *scsibus_get_fw_dev_path(DeviceState *dev)
}
static char *scsibus_get_fw_dev_path(DeviceState *dev)
s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE;
bus = scsi_bus_from_device(d);
s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE;
bus = scsi_bus_from_device(d);
- bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
+ bus->ops->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
};
typedef struct SCSIBus SCSIBus;
};
typedef struct SCSIBus SCSIBus;
+typedef struct SCSIBusOps SCSIBusOps;
typedef struct SCSIDevice SCSIDevice;
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIDevice SCSIDevice;
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
-typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag,
- uint32_t arg);
enum SCSIXferMode {
SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
enum SCSIXferMode {
SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
};
uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
};
-typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
- int unit);
+struct SCSIBusOps {
+ void (*complete)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg);
+};
+
struct SCSIBus {
BusState qbus;
int busnr;
int tcq, ndev;
struct SCSIBus {
BusState qbus;
int busnr;
int tcq, ndev;
- scsi_completionfn complete;
SCSIDevice *devs[MAX_SCSI_DEVS];
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
SCSIDevice *devs[MAX_SCSI_DEVS];
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
- scsi_completionfn complete);
+ const SCSIBusOps *ops);
void scsi_qdev_register(SCSIDeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
void scsi_qdev_register(SCSIDeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
+static const struct SCSIBusOps vscsi_scsi_ops = {
+ .complete = vscsi_command_complete
+};
+
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
- vscsi_command_complete);
if (!dev->qdev.hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus);
}
if (!dev->qdev.hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus);
}
qdev_unplug(&s->dev.qdev);
}
qdev_unplug(&s->dev.qdev);
}
+static const struct SCSIBusOps usb_msd_scsi_ops = {
+ .complete = usb_msd_command_complete
+};
+
static int usb_msd_initfn(USBDevice *dev)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
static int usb_msd_initfn(USBDevice *dev)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
- scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
+ scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;