From: Denis V. Lunev <[email protected]>

Add virtio_scsi_submit_command() and virtio_scsi_wait_command() so that
a test can act on the device while a command is still in flight.
virtio_scsi_do_command() becomes a wrapper around the two and its
callers are unchanged.

Signed-off-by: Denis V. Lunev <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Kevin Wolf <[email protected]>
Cc: Hanna Reitz <[email protected]>
Cc: Fabiano Rosas <[email protected]>
Cc: Laurent Vivier <[email protected]>
---
 tests/qtest/virtio-scsi-test.c | 85 +++++++++++++++++++++++-----------
 1 file changed, 59 insertions(+), 26 deletions(-)

diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c
index e2350c52f6..40f1d569d8 100644
--- a/tests/qtest/virtio-scsi-test.c
+++ b/tests/qtest/virtio-scsi-test.c
@@ -59,22 +59,28 @@ static uint64_t qvirtio_scsi_alloc(QVirtioSCSIQueues *vs, 
size_t alloc_size,
     return addr;
 }
 
-static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
-                                      const uint8_t *cdb,
-                                      const uint8_t *data_in,
-                                      size_t data_in_len,
-                                      uint8_t *data_out, size_t data_out_len,
-                                      struct virtio_scsi_cmd_resp *resp_out)
+typedef struct {
+    uint32_t free_head;
+    uint64_t req_addr;
+    uint64_t resp_addr;
+    uint64_t data_in_addr;
+    uint64_t data_out_addr;
+} VirtioSCSICmd;
+
+static void virtio_scsi_submit_command(QVirtioSCSIQueues *vs,
+                                       const uint8_t *cdb,
+                                       const uint8_t *data_in,
+                                       size_t data_in_len,
+                                       uint8_t *data_out, size_t data_out_len,
+                                       VirtioSCSICmd *cmd)
 {
     QVirtQueue *vq;
     struct virtio_scsi_cmd_req req = { { 0 } };
     struct virtio_scsi_cmd_resp resp = { .response = 0xff, .status = 0xff };
-    uint64_t req_addr, resp_addr, data_in_addr = 0, data_out_addr = 0;
-    uint8_t response;
-    uint32_t free_head;
     QTestState *qts = global_qtest;
 
     vq = vs->vq[2];
+    *cmd = (VirtioSCSICmd) { 0 };
 
     req.lun[0] = 1; /* Select LUN */
     req.lun[1] = 1; /* Select target 1 */
@@ -83,41 +89,68 @@ static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
     /* XXX: Fix endian if any multi-byte field in req/resp is used */
 
     /* Add request header */
-    req_addr = qvirtio_scsi_alloc(vs, sizeof(req), &req);
-    free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req), false, true);
+    cmd->req_addr = qvirtio_scsi_alloc(vs, sizeof(req), &req);
+    cmd->free_head = qvirtqueue_add(qts, vq, cmd->req_addr, sizeof(req),
+                                    false, true);
 
     if (data_out_len) {
-        data_out_addr = qvirtio_scsi_alloc(vs, data_out_len, data_out);
-        qvirtqueue_add(qts, vq, data_out_addr, data_out_len, false, true);
+        cmd->data_out_addr = qvirtio_scsi_alloc(vs, data_out_len, data_out);
+        qvirtqueue_add(qts, vq, cmd->data_out_addr, data_out_len, false, true);
     }
 
     /* Add response header */
-    resp_addr = qvirtio_scsi_alloc(vs, sizeof(resp), &resp);
-    qvirtqueue_add(qts, vq, resp_addr, sizeof(resp), true, !!data_in_len);
+    cmd->resp_addr = qvirtio_scsi_alloc(vs, sizeof(resp), &resp);
+    qvirtqueue_add(qts, vq, cmd->resp_addr, sizeof(resp), true,
+                   !!data_in_len);
 
     if (data_in_len) {
-        data_in_addr = qvirtio_scsi_alloc(vs, data_in_len, data_in);
-        qvirtqueue_add(qts, vq, data_in_addr, data_in_len, true, false);
+        cmd->data_in_addr = qvirtio_scsi_alloc(vs, data_in_len, data_in);
+        qvirtqueue_add(qts, vq, cmd->data_in_addr, data_in_len, true, false);
     }
 
-    qvirtqueue_kick(qts, vs->dev, vq, free_head);
-    qvirtio_wait_used_elem(qts, vs->dev, vq, free_head, NULL,
-                           QVIRTIO_SCSI_TIMEOUT_US);
+    qvirtqueue_kick(qts, vs->dev, vq, cmd->free_head);
+}
+
+static uint8_t virtio_scsi_wait_command(QVirtioSCSIQueues *vs,
+                                        VirtioSCSICmd *cmd,
+                                        struct virtio_scsi_cmd_resp *resp_out,
+                                        gint64 timeout_us)
+{
+    uint8_t response;
+    QTestState *qts = global_qtest;
+
+    qvirtio_wait_used_elem(qts, vs->dev, vs->vq[2], cmd->free_head, NULL,
+                           timeout_us);
 
-    response = readb(resp_addr +
+    response = readb(cmd->resp_addr +
                      offsetof(struct virtio_scsi_cmd_resp, response));
 
     if (resp_out) {
-        memread(resp_addr, resp_out, sizeof(*resp_out));
+        memread(cmd->resp_addr, resp_out, sizeof(*resp_out));
     }
 
-    guest_free(alloc, req_addr);
-    guest_free(alloc, resp_addr);
-    guest_free(alloc, data_in_addr);
-    guest_free(alloc, data_out_addr);
+    guest_free(alloc, cmd->req_addr);
+    guest_free(alloc, cmd->resp_addr);
+    guest_free(alloc, cmd->data_in_addr);
+    guest_free(alloc, cmd->data_out_addr);
     return response;
 }
 
+static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
+                                      const uint8_t *cdb,
+                                      const uint8_t *data_in,
+                                      size_t data_in_len,
+                                      uint8_t *data_out, size_t data_out_len,
+                                      struct virtio_scsi_cmd_resp *resp_out)
+{
+    VirtioSCSICmd cmd;
+
+    virtio_scsi_submit_command(vs, cdb, data_in, data_in_len,
+                               data_out, data_out_len, &cmd);
+    return virtio_scsi_wait_command(vs, &cmd, resp_out,
+                                    QVIRTIO_SCSI_TIMEOUT_US);
+}
+
 static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev)
 {
     QVirtioSCSIQueues *vs;
-- 
2.53.0


Reply via email to