qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH RFC v3 4/5] ATAPI-SCSI bridge functions created an c


From: Alexander Bezzubikov
Subject: [Qemu-devel] [PATCH RFC v3 4/5] ATAPI-SCSI bridge functions created an can be used by bridge
Date: Wed, 19 Aug 2015 13:57:22 +0300

ide: bridge functions created
ide: Makefile corrected due to bridge creation
scsi: added function to enable bridge send SCSI requests
ide: bridge can now forward requests to SCSI
ide: bridge functions assigned to SCSIBusInfo
Signed-off-by: Alexander Bezzubikov <address@hidden>
---
 hw/ide/Makefile.objs   |   2 +-
 hw/ide/atapi.c         |  16 +++++++
 hw/ide/bridge.c        | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ide/bridge.h        |   1 +
 hw/ide/internal.h      |   2 +
 hw/ide/qdev.c          |   4 +-
 hw/scsi/scsi-disk.c    |  43 +++++++++++++++++++
 include/hw/scsi/scsi.h |   3 ++
 8 files changed, 182 insertions(+), 3 deletions(-)
 create mode 100644 hw/ide/bridge.c

diff --git a/hw/ide/Makefile.objs b/hw/ide/Makefile.objs
index 729e9bd..f54f275 100644
--- a/hw/ide/Makefile.objs
+++ b/hw/ide/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-$(CONFIG_IDE_CORE) += core.o atapi.o
+common-obj-$(CONFIG_IDE_CORE) += core.o atapi.o bridge.o
 common-obj-$(CONFIG_IDE_QDEV) += qdev.o
 common-obj-$(CONFIG_IDE_PCI) += pci.o
 common-obj-$(CONFIG_IDE_ISA) += isa.o
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f6135e1..3eb56e2 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -1253,6 +1253,22 @@ void ide_atapi_cmd(IDEState *s)
         return;
     }
 
+    if (s->drive_kind == IDE_BRIDGE) {
+        IDEDevice *dev = s->bus->master;
+        SCSIDevice *scsi_dev = scsi_device_find(&dev->scsi_bus, 0, 0, 0);
+        s->cur_req = scsi_new_request_from_bridge(scsi_dev, 0, 0, buf, NULL);
+
+        /* Necessary to prevent ide from reading while data isn't ready */
+        if (buf[0] == READ_10) {
+            s->status |= BUSY_STAT;
+        }
+
+        if (scsi_req_enqueue(s->cur_req)) {
+            scsi_req_continue(s->cur_req);
+        }
+        return;
+    }
+
     /* Execute the command */
     if (atapi_cmd_table[s->io_buffer[0]].handler) {
         atapi_cmd_table[s->io_buffer[0]].handler(s, buf);
diff --git a/hw/ide/bridge.c b/hw/ide/bridge.c
new file mode 100644
index 0000000..2e93311
--- /dev/null
+++ b/hw/ide/bridge.c
@@ -0,0 +1,114 @@
+#include "hw/ide/bridge.h"
+
+void ide_bridge_do_transfer(IDEState *s)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, s->cur_req);
+
+    if (r->buflen > 0) {
+        int size = r->buflen;
+
+        int byte_count_limit = s->lcyl | (s->hcyl << 8);
+        if (byte_count_limit == 0xffff) {
+            byte_count_limit--;
+        }
+        if (size > byte_count_limit) {
+            /* byte count limit must be even if this case */
+            if (byte_count_limit & 1) {
+                byte_count_limit--;
+            }
+            size = byte_count_limit;
+        }
+        s->lcyl = size;
+        s->hcyl = size >> 8;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
+
+        int offset = (r->buflen == r->qiov.size) ? 0 : r->qiov.size - 
r->buflen;
+        r->buflen -= size;
+
+        ide_transfer_start(s, s->io_buffer + offset, size,
+                           ide_bridge_do_transfer);
+        ide_set_irq(s->bus);
+    } else {
+        scsi_req_complete(s->cur_req, GOOD);
+    }
+}
+
+static void ide_bridge_dma_complete(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+
+    s->io_buffer_size = s->bus->dma->iov.iov_len;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    s->bus->dma->ops->rw_buf(s->bus->dma, 1);
+    scsi_req_complete(s->cur_req, GOOD);
+
+    s->status = READY_STAT | SEEK_STAT;
+
+    ide_set_irq(s->bus);
+    ide_set_inactive(s, false);
+}
+
+void ide_bridge_start_transfer(SCSIRequest *req, uint32_t len)
+{
+    IDEDevice *dev = IDE_DEVICE(req->bus->qbus.parent);
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
+    IDEState *s = bus->ifs;
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    int cmd = req->cmd.buf[0];
+    if (cmd == READ_10) {
+        if (s->feature & 1) {
+            s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+            qemu_iovec_clone(&s->bus->dma->qiov, &r->qiov, NULL);
+            qemu_iovec_to_buf(&r->qiov, 0, s->io_buffer, r->qiov.size);
+        } else {
+            qemu_iovec_to_buf(&r->qiov, 0, s->io_buffer, r->qiov.size);
+        }
+    } else {
+        if (cmd == INQUIRY) {
+            len = 36;
+        }
+        r->iov.iov_len = len;
+        qemu_iovec_concat_iov(&r->qiov, &r->iov, len, 0, len);
+        qemu_iovec_to_buf(&r->qiov, 0, s->io_buffer, r->qiov.size);
+    }
+
+    s->io_buffer_index = 0;
+    s->status = READY_STAT | SEEK_STAT;
+
+    if (cmd != TEST_UNIT_READY && cmd != ALLOW_MEDIUM_REMOVAL) {
+        if (s->feature & 1) {
+            s->io_buffer_index = 0;
+            s->bus->retry_unit = s->unit;
+            s->bus->retry_sector_num = ide_get_sector(s);
+            s->bus->retry_nsector = s->nsector;
+
+            s->bus->dma->iov.iov_base = (void *)(s->io_buffer);
+            s->bus->dma->iov.iov_len = r->qiov.size;
+
+            if (cmd != READ_10) {
+                s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
+            }
+
+            if (s->bus->dma->ops->start_dma) {
+                s->bus->dma->ops->start_dma(s->bus->dma, s,
+                                            ide_bridge_dma_complete);
+            }
+        } else {
+            r->buflen = r->qiov.size;
+            ide_bridge_do_transfer(s);
+        }
+    } else {
+        scsi_req_complete(req, GOOD);
+    }
+}
+
+void ide_bridge_complete(SCSIRequest *req, uint32_t status, size_t resid)
+{
+    IDEDevice *dev = IDE_DEVICE(req->bus->qbus.parent);
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
+    IDEState *s = bus->ifs;
+
+    ide_atapi_cmd_ok(s);
+    ide_set_irq(s->bus);
+}
diff --git a/hw/ide/bridge.h b/hw/ide/bridge.h
index dca5d73..59f2f25 100644
--- a/hw/ide/bridge.h
+++ b/hw/ide/bridge.h
@@ -5,5 +5,6 @@
 
 void ide_bridge_start_transfer(SCSIRequest *req, uint32_t len);
 void ide_bridge_complete(SCSIRequest *req, uint32_t status, size_t resid);
+void ide_bridge_do_transfer(IDEState *s);
 
 #endif
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 79c85be..fd385bc 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -429,6 +429,8 @@ struct IDEState {
     uint8_t *smart_selftest_data;
     /* AHCI */
     int ncq_queues;
+    /* ATAPI-SCSI bridge */
+    SCSIRequest *cur_req;
 };
 
 struct IDEDMAOps {
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 2ed0c39..e18d222 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -150,8 +150,8 @@ static const struct SCSIBusInfo atapi_scsi_info = {
     .max_target = 0,
     .max_lun = 0,
 
-    .transfer_data = NULL,
-    .complete = NULL,
+    .transfer_data = ide_bridge_start_transfer,
+    .complete = ide_bridge_complete,
     .cancel = NULL
 };
 
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 8626eba..9d5f0a4 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2428,6 +2428,49 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, 
uint32_t tag, uint32_t lun,
     return req;
 }
 
+SCSIRequest *scsi_new_request_from_bridge(SCSIDevice *d, uint32_t tag,
+                                          uint32_t lun, uint8_t *buf,
+                                          void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+    SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(d);
+    SCSIRequest *req;
+    const SCSIReqOps *ops;
+    uint8_t command;
+
+    command = buf[0];
+    ops = scsi_disk_reqops_dispatch[command];
+    if (!ops) {
+        ops = &scsi_disk_emulate_reqops;
+    }
+    req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
+    memcpy(req->cmd.buf, buf, 16);
+
+    SCSICommand cmd = { .len = 0 };
+
+    if (ops != NULL || !sc->parse_cdb) {
+        scsi_req_parse_cdb(d, &cmd, buf);
+    } else {
+        sc->parse_cdb(d, &cmd, buf, hba_private);
+    }
+
+    req->cmd = cmd;
+    req->resid = req->cmd.xfer;
+
+    #ifdef DEBUG_SCSI
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+    {
+        int i;
+        for (i = 1; i < scsi_cdb_length(buf); i++) {
+            printf(" 0x%02x", buf[i]);
+        }
+        printf("\n");
+    }
+    #endif
+
+    return req;
+}
+
 #ifdef __linux__
 static int get_device_type(SCSIDiskState *s)
 {
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index e25fd70..de0546e 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -262,6 +262,9 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, 
SCSIDevice *d,
                             uint32_t tag, uint32_t lun, void *hba_private);
 SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
                           uint8_t *buf, void *hba_private);
+SCSIRequest *scsi_new_request_from_bridge(SCSIDevice *d, uint32_t tag,
+                                          uint32_t lun, uint8_t *buf,
+                                          void *hba_private);
 int32_t scsi_req_enqueue(SCSIRequest *req);
 void scsi_req_free(SCSIRequest *req);
 SCSIRequest *scsi_req_ref(SCSIRequest *req);
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]