qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 8/9] scsi-generic: Factor out response interception


From: Alex Pyrgiotis
Subject: [Qemu-devel] [PATCH 8/9] scsi-generic: Factor out response interception
Date: Wed, 16 Dec 2015 18:55:16 +0200

The interception of read/write responses is currently done in the main
code that handles the read write response. Move the interception logic
in a function of its own, so that it can be reused from the
scatter-gather path.

Also, instead of altering the response buffer directly, use the
scsi_get_buf() function and alter the buffer that it returns. This is
also required for the support of scatter-gather lists.

Signed-off-by: Alex Pyrgiotis <address@hidden>
Signed-off-by: Dimitris Aragiorgis <address@hidden>

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 6c0cfa5..6704861 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -98,6 +98,14 @@ static void scsi_buf_init_io_header(SCSIGenericReq *r, int 
direction)
     r->io_header.flags |= SG_FLAG_DIRECT_IO;
 }
 
+/* Return a pointer to the data buffer.  */
+static uint8_t *scsi_get_buf(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    return r->buf;
+}
+
 static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
 {
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@@ -127,7 +135,7 @@ static void scsi_free_request(SCSIRequest *req)
     g_free(r->buf);
 }
 
-/* Helper function for command completion.  */
+/* Helper function for command completion. */
 static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
 {
     int status;
@@ -191,37 +199,23 @@ static void scsi_command_complete(void *opaque, int ret)
     scsi_command_complete_noio(r, ret);
 }
 
-static void scsi_buf_read_complete(void *opaque, int ret)
+/* Intercept the read response in order to snoop or alter it. */
+static void scsi_intercept_read_response(SCSIGenericReq *r)
 {
-    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    uint8_t *res_buf;
     SCSIDevice *s = r->req.dev;
-    int len;
 
-    assert(r->req.aiocb != NULL);
-    r->req.aiocb = NULL;
-
-    if (ret || r->req.io_canceled) {
-        scsi_command_complete_noio(r, ret);
-        return;
-    }
-
-    len = r->io_header.dxfer_len - r->io_header.resid;
-    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
-
-    if (len == 0) {
-        scsi_command_complete_noio(r, 0);
-        return;
-    }
+    res_buf = scsi_get_buf(&r->req);
 
     /* Snoop READ CAPACITY output to set the blocksize.  */
     if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
-        (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
-        s->blocksize = ldl_be_p(&r->buf[4]);
-        s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
+        (ldl_be_p(&res_buf[0]) != 0xffffffffU || s->max_lba == 0)) {
+        s->blocksize = ldl_be_p(&res_buf[4]);
+        s->max_lba = ldl_be_p(&res_buf[0]) & 0xffffffffULL;
     } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
                (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
-        s->blocksize = ldl_be_p(&r->buf[8]);
-        s->max_lba = ldq_be_p(&r->buf[0]);
+        s->blocksize = ldl_be_p(&res_buf[8]);
+        s->max_lba = ldq_be_p(&res_buf[0]);
     }
     blk_set_guest_block_size(s->conf.blk, s->blocksize);
 
@@ -234,14 +228,54 @@ static void scsi_buf_read_complete(void *opaque, int ret)
          r->req.cmd.buf[0] == MODE_SENSE_10) &&
         (r->req.cmd.buf[1] & 0x8) == 0) {
         if (r->req.cmd.buf[0] == MODE_SENSE) {
-            r->buf[2] |= 0x80;
+            res_buf[2] |= 0x80;
         } else  {
-            r->buf[3] |= 0x80;
+            res_buf[3] |= 0x80;
         }
     }
-    r->synced = 1;
-    scsi_req_data(&r->req, len);
-    scsi_req_unref(&r->req);
+}
+
+/*
+ * Perform some common checks and return the number of bytes read.
+ *
+ * If we encounter an error, return -1.
+ */
+static int scsi_common_read_complete(SCSIGenericReq *r, int ret)
+{
+    int len;
+
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+
+    if (ret || r->req.io_canceled) {
+        scsi_command_complete_noio(r, ret);
+        return -1;
+    }
+
+    len = r->io_header.dxfer_len - r->io_header.resid;
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
+
+    if (len == 0) {
+        scsi_command_complete_noio(r, 0);
+        return 0;
+    }
+
+    scsi_intercept_read_response(r);
+
+    return len;
+}
+
+static void scsi_buf_read_complete(void *opaque, int ret)
+{
+    int len;
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+
+    len = scsi_common_read_complete(r, ret);
+    if (len > 0) {
+        r->synced = 1;
+        scsi_req_data(&r->req, len);
+        scsi_req_unref(&r->req);
+    }
 }
 
 /*
@@ -291,12 +325,26 @@ static void scsi_common_read_data(SCSIRequest *req)
     scsi_buf_read_data(req);
 }
 
-static void scsi_buf_write_complete(void *opaque, int ret)
+/* Intercept the write response in order to snoop or alter it */
+static void scsi_intercept_write_response(SCSIGenericReq *r)
 {
-    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    uint8_t *res_buf;
     SCSIDevice *s = r->req.dev;
 
-    DPRINTF("scsi_write_complete() ret = %d\n", ret);
+    res_buf = scsi_get_buf(&r->req);
+
+    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
+        s->type == TYPE_TAPE) {
+        s->blocksize = (res_buf[9] << 16) | (res_buf[10] << 8) | res_buf[11];
+        DPRINTF("block size %d\n", s->blocksize);
+    }
+}
+
+static void scsi_common_write_complete(void *opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+
+    DPRINTF("scsi_common_write_complete() ret = %d\n", ret);
 
     assert(r->req.aiocb != NULL);
     r->req.aiocb = NULL;
@@ -306,15 +354,17 @@ static void scsi_buf_write_complete(void *opaque, int ret)
         return;
     }
 
-    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
-        s->type == TYPE_TAPE) {
-        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
-        DPRINTF("block size %d\n", s->blocksize);
-    }
+    scsi_intercept_write_response(r);
 
+    r->req.resid = r->io_header.resid;
     scsi_command_complete_noio(r, ret);
 }
 
+static void scsi_buf_write_complete(void *opaque, int ret)
+{
+    scsi_common_write_complete(opaque, ret);
+}
+
 /* Write data to a scsi device.  Returns nonzero on failure.
    The transfer may complete asynchronously.  */
 static void scsi_buf_write_data(SCSIRequest *req)
@@ -344,14 +394,6 @@ static void scsi_common_write_data(SCSIRequest *req)
     scsi_buf_write_data(req);
 }
 
-/* Return a pointer to the data buffer.  */
-static uint8_t *scsi_get_buf(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    return r->buf;
-}
-
 /* Execute a scsi command.  Returns the length of the data expected by the
    command.  This will be Positive for data transfers from the device
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
-- 
2.6.2




reply via email to

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