All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache
@ 2012-07-10 14:15 Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 1/8] scsi-disk: make discard asynchronous Paolo Bonzini
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

This series extracts some pending patches I had lying around
that refactor scsi-disk to be more table-driven and enable support
for emulated requests where data flows _to_ the SCSI device.  This
is then used to support MODE SELECT and in particular toggling the
write cache.

Paolo

Paolo Bonzini (8):
  scsi-disk: make discard asynchronous
  scsi-disk: move all non-DMA commands to scsi_disk_emulate_command
  scsi-disk: split scsi-disk reqops
  scsi-disk: separate read_data/write_data implementation for emulate_reqops
  scsi-disk: support emulated TO_DEV requests
  scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR
  scsi-disk: parse MODE SELECT commands and parameters
  scsi-disk: support toggling the write cache

 hw/scsi-bus.c  |   10 ++
 hw/scsi-disk.c |  550 +++++++++++++++++++++++++++++++++++++++-----------------
 hw/scsi.h      |    4 +
 3 files changed, 402 insertions(+), 162 deletions(-)

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 1/8] scsi-disk: make discard asynchronous
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 2/8] scsi-disk: move all non-DMA commands to scsi_disk_emulate_command Paolo Bonzini
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

By making discard asynchronous, we can reuse all the error handling
code that is used for other commands.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
        Not really related to this series, but it is yet another patch
        I had around and it had a lot of conflicts with the ones that
        follow, so it's easier to include it.

 hw/scsi-disk.c |   22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1e0e80a..016413c 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -168,7 +168,7 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 }
 
-static void scsi_flush_complete(void * opaque, int ret)
+static void scsi_aio_complete(void *opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -221,7 +221,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
 
     if (scsi_is_cmd_fua(&r->req.cmd)) {
         bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
         return;
     }
 
@@ -1547,7 +1547,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         /* The request is used as the AIO opaque value, so add a ref.  */
         scsi_req_ref(&r->req);
         bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
         return 0;
     case READ_6:
     case READ_10:
@@ -1624,15 +1624,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
             goto fail;
         }
 
-        rc = bdrv_discard(s->qdev.conf.bs,
-                          r->req.cmd.lba * (s->qdev.blocksize / 512),
-                          len * (s->qdev.blocksize / 512));
-        if (rc < 0) {
-            /* XXX: better error code ?*/
-            goto fail;
-        }
-
-        break;
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+                                        r->req.cmd.lba * (s->qdev.blocksize / 512),
+                                        len * (s->qdev.blocksize / 512),
+                                        scsi_aio_complete, r);
+        return 0;
     default:
         DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 2/8] scsi-disk: move all non-DMA commands to scsi_disk_emulate_command
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 1/8] scsi-disk: make discard asynchronous Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 3/8] scsi-disk: split scsi-disk reqops Paolo Bonzini
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

We want to use separate SCSIReqOps for emulated commands needing an
allocated buffer vs. those that are zerocopy when the HBA supports
S/G lists.  Ensure that all of the former are in scsi_disk_emulate_command.

Commands that do not have any parameters are more similar to emulated
commands, so also move them, even if they do I/O.

Finally, MODE SELECT and MODE SELECT(10) are broken because we do not
yet support passing parameter data _to_ emulated commands, so disable
them.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |  152 ++++++++++++++++++++++++--------------------------------
 1 file changed, 66 insertions(+), 86 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 016413c..15285f4 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1452,10 +1452,65 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         }
         DPRINTF("Unsupported Service Action In\n");
         goto illegal_request;
+    case SYNCHRONIZE_CACHE:
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
+        return 0;
+    case SEEK_10:
+        DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
+        if (r->req.cmd.lba > s->qdev.max_lba) {
+            goto illegal_lba;
+        }
+        break;
+#if 0
+    case MODE_SELECT:
+        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (r->req.cmd.xfer > 12) {
+            goto illegal_request;
+        }
+        break;
+    case MODE_SELECT_10:
+        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (r->req.cmd.xfer > 16) {
+            goto illegal_request;
+        }
+        break;
+#endif
+    case WRITE_SAME_10:
+        nb_sectors = lduw_be_p(&req->cmd.buf[7]);
+        goto write_same;
+    case WRITE_SAME_16:
+        nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL;
+    write_same:
+        if (r->req.cmd.lba > s->qdev.max_lba) {
+            goto illegal_lba;
+        }
+
+        /*
+         * We only support WRITE SAME with the unmap bit set for now.
+         */
+        if (!(req->cmd.buf[1] & 0x8)) {
+            goto illegal_request;
+        }
+
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+                                        r->req.cmd.lba * (s->qdev.blocksize / 512),
+                                        nb_sectors * (s->qdev.blocksize / 512),
+                                        scsi_aio_complete, r);
+        return 0;
     default:
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
         return -1;
     }
+    assert(r->sector_count == 0);
     buflen = MIN(buflen, req->cmd.xfer);
     return buflen;
 
@@ -1464,6 +1519,10 @@ illegal_request:
         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
     }
     return -1;
+
+illegal_lba:
+    scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+    return 0;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -1517,38 +1576,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     }
 
     switch (command) {
-    case TEST_UNIT_READY:
-    case INQUIRY:
-    case MODE_SENSE:
-    case MODE_SENSE_10:
-    case RESERVE:
-    case RESERVE_10:
-    case RELEASE:
-    case RELEASE_10:
-    case START_STOP:
-    case ALLOW_MEDIUM_REMOVAL:
-    case READ_CAPACITY_10:
-    case READ_TOC:
-    case READ_DISC_INFORMATION:
-    case READ_DVD_STRUCTURE:
-    case GET_CONFIGURATION:
-    case GET_EVENT_STATUS_NOTIFICATION:
-    case MECHANISM_STATUS:
-    case SERVICE_ACTION_IN_16:
-    case REQUEST_SENSE:
-        rc = scsi_disk_emulate_command(r);
-        if (rc < 0) {
-            return 0;
-        }
-
-        r->iov.iov_len = rc;
-        break;
-    case SYNCHRONIZE_CACHE:
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
-        return 0;
     case READ_6:
     case READ_10:
     case READ_12:
@@ -1581,63 +1608,16 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
         r->sector_count = len * (s->qdev.blocksize / 512);
         break;
-    case MODE_SELECT:
-        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
-        /* We don't support mode parameter changes.
-           Allow the mode parameter header + block descriptors only. */
-        if (r->req.cmd.xfer > 12) {
-            goto fail;
-        }
-        break;
-    case MODE_SELECT_10:
-        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
-        /* We don't support mode parameter changes.
-           Allow the mode parameter header + block descriptors only. */
-        if (r->req.cmd.xfer > 16) {
-            goto fail;
+    default:
+        rc = scsi_disk_emulate_command(r);
+        if (rc < 0) {
+            return 0;
         }
-        break;
-    case SEEK_10:
-        DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
-        if (r->req.cmd.lba > s->qdev.max_lba) {
-            goto illegal_lba;
+        if (r->req.aiocb) {
+            return 0;
         }
+        r->iov.iov_len = rc;
         break;
-    case WRITE_SAME_10:
-        len = lduw_be_p(&buf[7]);
-        goto write_same;
-    case WRITE_SAME_16:
-        len = ldl_be_p(&buf[10]) & 0xffffffffULL;
-    write_same:
-
-        DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n",
-                r->req.cmd.lba, len);
-
-        if (r->req.cmd.lba > s->qdev.max_lba) {
-            goto illegal_lba;
-        }
-
-        /*
-         * We only support WRITE SAME with the unmap bit set for now.
-         */
-        if (!(buf[1] & 0x8)) {
-            goto fail;
-        }
-
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
-                                        r->req.cmd.lba * (s->qdev.blocksize / 512),
-                                        len * (s->qdev.blocksize / 512),
-                                        scsi_aio_complete, r);
-        return 0;
-    default:
-        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
-        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-        return 0;
-    fail:
-        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-        return 0;
     illegal_lba:
         scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
         return 0;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 3/8] scsi-disk: split scsi-disk reqops
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 1/8] scsi-disk: make discard asynchronous Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 2/8] scsi-disk: move all non-DMA commands to scsi_disk_emulate_command Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 4/8] scsi-disk: separate read_data/write_data implementation for emulate_reqops Paolo Bonzini
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

Only checks for present medium were still done in scsi_send_command
for emulated commands.  So move those to scsi_disk_emulate_command
and return different SCSIReqOps depending on the kind of command.

Checks for present medium can be done unconditionally for the
scsi_disk_dma_reqops case.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |  194 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 126 insertions(+), 68 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 15285f4..136b813 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1266,14 +1266,39 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     return 0;
 }
 
-static int scsi_disk_emulate_command(SCSIDiskReq *r)
+static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
 {
-    SCSIRequest *req = &r->req;
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
     uint8_t *outbuf;
     int buflen = 0;
 
+    switch (req->cmd.buf[0]) {
+    case INQUIRY:
+    case MODE_SENSE:
+    case MODE_SENSE_10:
+    case RESERVE:
+    case RESERVE_10:
+    case RELEASE:
+    case RELEASE_10:
+    case START_STOP:
+    case ALLOW_MEDIUM_REMOVAL:
+    case GET_CONFIGURATION:
+    case GET_EVENT_STATUS_NOTIFICATION:
+    case MECHANISM_STATUS:
+    case REQUEST_SENSE:
+        break;
+
+    default:
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            return 0;
+        }
+        break;
+    }
+
+    assert(req->cmd.mode != SCSI_XFER_TO_DEV);
     if (!r->iov.iov_base) {
         /*
          * FIXME: we shouldn't return anything bigger than 4k, but the code
@@ -1336,7 +1361,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         break;
     case START_STOP:
         if (scsi_disk_emulate_start_stop(r) < 0) {
-            return -1;
+            return 0;
         }
         break;
     case ALLOW_MEDIUM_REMOVAL:
@@ -1507,18 +1532,23 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
                                         scsi_aio_complete, r);
         return 0;
     default:
+        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-        return -1;
+        return 0;
     }
-    assert(r->sector_count == 0);
-    buflen = MIN(buflen, req->cmd.xfer);
-    return buflen;
+    assert(!r->req.aiocb && r->sector_count == 0);
+    r->iov.iov_len = MIN(buflen, req->cmd.xfer);
+    r->sector_count = -1;
+    if (r->iov.iov_len == 0) {
+        scsi_req_complete(&r->req, GOOD);
+    }
+    return r->iov.iov_len;
 
 illegal_request:
     if (r->req.status == -1) {
         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
     }
-    return -1;
+    return 0;
 
 illegal_lba:
     scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
@@ -1530,49 +1560,18 @@ illegal_lba:
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
    and zero if the command does not transfer any data.  */
 
-static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
+static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     int32_t len;
     uint8_t command;
-    int rc;
 
     command = buf[0];
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
-
-#ifdef DEBUG_SCSI
-    {
-        int i;
-        for (i = 1; i < r->req.cmd.len; i++) {
-            printf(" 0x%02x", buf[i]);
-        }
-        printf("\n");
-    }
-#endif
 
-    switch (command) {
-    case INQUIRY:
-    case MODE_SENSE:
-    case MODE_SENSE_10:
-    case RESERVE:
-    case RESERVE_10:
-    case RELEASE:
-    case RELEASE_10:
-    case START_STOP:
-    case ALLOW_MEDIUM_REMOVAL:
-    case GET_CONFIGURATION:
-    case GET_EVENT_STATUS_NOTIFICATION:
-    case MECHANISM_STATUS:
-    case REQUEST_SENSE:
-        break;
-
-    default:
-        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
-            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
-            return 0;
-        }
-        break;
+    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+        return 0;
     }
 
     switch (command) {
@@ -1609,30 +1608,19 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         r->sector_count = len * (s->qdev.blocksize / 512);
         break;
     default:
-        rc = scsi_disk_emulate_command(r);
-        if (rc < 0) {
-            return 0;
-        }
-        if (r->req.aiocb) {
-            return 0;
-        }
-        r->iov.iov_len = rc;
-        break;
+        abort();
     illegal_lba:
         scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
         return 0;
     }
-    if (r->sector_count == 0 && r->iov.iov_len == 0) {
+    if (r->sector_count == 0) {
         scsi_req_complete(&r->req, GOOD);
     }
-    len = r->sector_count * 512 + r->iov.iov_len;
+    assert(r->iov.iov_len == 0);
     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        return -len;
+        return -r->sector_count * 512;
     } else {
-        if (!r->sector_count) {
-            r->sector_count = -1;
-        }
-        return len;
+        return r->sector_count * 512;
     }
 }
 
@@ -1801,10 +1789,19 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     }
 }
 
-static const SCSIReqOps scsi_disk_reqops = {
+static const SCSIReqOps scsi_disk_emulate_reqops = {
     .size         = sizeof(SCSIDiskReq),
     .free_req     = scsi_free_request,
-    .send_command = scsi_send_command,
+    .send_command = scsi_disk_emulate_command,
+    .read_data    = scsi_read_data,
+    .write_data   = scsi_write_data,
+    .get_buf      = scsi_get_buf,
+};
+
+static const SCSIReqOps scsi_disk_dma_reqops = {
+    .size         = sizeof(SCSIDiskReq),
+    .free_req     = scsi_free_request,
+    .send_command = scsi_disk_dma_command,
     .read_data    = scsi_read_data,
     .write_data   = scsi_write_data,
     .cancel_io    = scsi_cancel_io,
@@ -1813,13 +1810,75 @@ static const SCSIReqOps scsi_disk_reqops = {
     .save_request = scsi_disk_save_request,
 };
 
+static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
+    [TEST_UNIT_READY]                 = &scsi_disk_emulate_reqops,
+    [INQUIRY]                         = &scsi_disk_emulate_reqops,
+    [MODE_SENSE]                      = &scsi_disk_emulate_reqops,
+    [MODE_SENSE_10]                   = &scsi_disk_emulate_reqops,
+    [RESERVE]                         = &scsi_disk_emulate_reqops,
+    [RESERVE_10]                      = &scsi_disk_emulate_reqops,
+    [RELEASE]                         = &scsi_disk_emulate_reqops,
+    [RELEASE_10]                      = &scsi_disk_emulate_reqops,
+    [START_STOP]                      = &scsi_disk_emulate_reqops,
+    [ALLOW_MEDIUM_REMOVAL]            = &scsi_disk_emulate_reqops,
+    [READ_CAPACITY_10]                = &scsi_disk_emulate_reqops,
+    [READ_TOC]                        = &scsi_disk_emulate_reqops,
+    [READ_DVD_STRUCTURE]              = &scsi_disk_emulate_reqops,
+    [GET_CONFIGURATION]               = &scsi_disk_emulate_reqops,
+    [GET_EVENT_STATUS_NOTIFICATION]   = &scsi_disk_emulate_reqops,
+    [MECHANISM_STATUS]                = &scsi_disk_emulate_reqops,
+    [SERVICE_ACTION_IN_16]            = &scsi_disk_emulate_reqops,
+    [REQUEST_SENSE]                   = &scsi_disk_emulate_reqops,
+    [SYNCHRONIZE_CACHE]               = &scsi_disk_emulate_reqops,
+    [SEEK_10]                         = &scsi_disk_emulate_reqops,
+#if 0
+    [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
+    [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
+#endif
+    [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
+    [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
+
+    [READ_6]                          = &scsi_disk_dma_reqops,
+    [READ_10]                         = &scsi_disk_dma_reqops,
+    [READ_12]                         = &scsi_disk_dma_reqops,
+    [READ_16]                         = &scsi_disk_dma_reqops,
+    [VERIFY_10]                       = &scsi_disk_dma_reqops,
+    [VERIFY_12]                       = &scsi_disk_dma_reqops,
+    [VERIFY_16]                       = &scsi_disk_dma_reqops,
+    [WRITE_6]                         = &scsi_disk_dma_reqops,
+    [WRITE_10]                        = &scsi_disk_dma_reqops,
+    [WRITE_12]                        = &scsi_disk_dma_reqops,
+    [WRITE_16]                        = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_10]                 = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_12]                 = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_16]                 = &scsi_disk_dma_reqops,
+};
+
 static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
                                      uint8_t *buf, void *hba_private)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
     SCSIRequest *req;
+    const SCSIReqOps *ops;
+    uint8_t command;
 
-    req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
+#ifdef DEBUG_SCSI
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, buf[0]);
+    {
+        int i;
+        for (i = 1; i < r->req.cmd.len; i++) {
+            printf(" 0x%02x", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+
+    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);
     return req;
 }
 
@@ -1933,15 +1992,14 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
          * unreliable, too.  It is even possible that reads deliver random data
          * from the host page cache (this is probably a Linux bug).
          *
-         * We might use scsi_disk_reqops as long as no writing commands are
+         * We might use scsi_disk_dma_reqops as long as no writing commands are
          * seen, but performance usually isn't paramount on optical media.  So,
          * just make scsi-block operate the same as scsi-generic for them.
          */
-        if (s->qdev.type == TYPE_ROM) {
-            break;
-	}
-        return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
-                              hba_private);
+        if (s->qdev.type != TYPE_ROM) {
+            return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
+                                  hba_private);
+        }
     }
 
     return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 4/8] scsi-disk: separate read_data/write_data implementation for emulate_reqops
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
                   ` (2 preceding siblings ...)
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 3/8] scsi-disk: split scsi-disk reqops Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 5/8] scsi-disk: support emulated TO_DEV requests Paolo Bonzini
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

The previous patch only separated the send_command callback.
Use different implementations also for read_data and write_data.
The latter is still unreachable, so it aborts for now.

read_data passes the data buffer that was prepared and completes
the command.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |   36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 136b813..a03d200 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -342,13 +342,6 @@ static void scsi_read_data(SCSIRequest *req)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     bool first;
 
-    if (r->sector_count == (uint32_t)-1) {
-        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
-        r->sector_count = 0;
-        r->started = true;
-        scsi_req_data(&r->req, r->iov.iov_len);
-        return;
-    }
     DPRINTF("Read sector_count=%d\n", r->sector_count);
     if (r->sector_count == 0) {
         /* This also clears the sense buffer for REQUEST SENSE.  */
@@ -1266,6 +1259,28 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     return 0;
 }
 
+static void scsi_disk_emulate_read_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    int buflen = r->iov.iov_len;
+
+    if (buflen) {
+        DPRINTF("Read buf_len=%zd\n", buflen);
+        r->iov.iov_len = 0;
+        r->started = true;
+        scsi_req_data(&r->req, buflen);
+        return;
+    }
+
+    /* This also clears the sense buffer for REQUEST SENSE.  */
+    scsi_req_complete(&r->req, GOOD);
+}
+
+static void scsi_disk_emulate_write_data(SCSIRequest *req)
+{
+    abort();
+}
+
 static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1536,9 +1551,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
         return 0;
     }
-    assert(!r->req.aiocb && r->sector_count == 0);
+    assert(!r->req.aiocb);
     r->iov.iov_len = MIN(buflen, req->cmd.xfer);
-    r->sector_count = -1;
     if (r->iov.iov_len == 0) {
         scsi_req_complete(&r->req, GOOD);
     }
@@ -1793,8 +1807,8 @@ static const SCSIReqOps scsi_disk_emulate_reqops = {
     .size         = sizeof(SCSIDiskReq),
     .free_req     = scsi_free_request,
     .send_command = scsi_disk_emulate_command,
-    .read_data    = scsi_read_data,
-    .write_data   = scsi_write_data,
+    .read_data    = scsi_disk_emulate_read_data,
+    .write_data   = scsi_disk_emulate_write_data,
     .get_buf      = scsi_get_buf,
 };
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 5/8] scsi-disk: support emulated TO_DEV requests
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
                   ` (3 preceding siblings ...)
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 4/8] scsi-disk: separate read_data/write_data implementation for emulate_reqops Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 6/8] scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR Paolo Bonzini
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

This adds the implementation of write_data for the emulated
command case.  The first time through it asks for more data,
the second time it finishes the processing of the command.

MODE SELECT and MODE SELECT(10) can now be re-enabled, but they
will not do much.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |   36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a03d200..e64d659 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1278,7 +1278,26 @@ static void scsi_disk_emulate_read_data(SCSIRequest *req)
 
 static void scsi_disk_emulate_write_data(SCSIRequest *req)
 {
-    abort();
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    if (r->iov.iov_len) {
+        int buflen = r->iov.iov_len;
+        DPRINTF("Write buf_len=%zd\n", buflen);
+        r->iov.iov_len = 0;
+        scsi_req_data(&r->req, buflen);
+        return;
+    }
+
+    switch (req->cmd.buf[0]) {
+    case MODE_SELECT:
+    case MODE_SELECT_10:
+        /* This also clears the sense buffer for REQUEST SENSE.  */
+        scsi_req_complete(&r->req, GOOD);
+        break;
+
+    default:
+        abort();
+    }
 }
 
 static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
@@ -1287,7 +1306,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
     uint8_t *outbuf;
-    int buflen = 0;
+    int buflen;
 
     switch (req->cmd.buf[0]) {
     case INQUIRY:
@@ -1313,7 +1332,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         break;
     }
 
-    assert(req->cmd.mode != SCSI_XFER_TO_DEV);
     if (!r->iov.iov_base) {
         /*
          * FIXME: we shouldn't return anything bigger than 4k, but the code
@@ -1330,6 +1348,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
     }
 
+    buflen = req->cmd.xfer;
     outbuf = r->iov.iov_base;
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
@@ -1504,7 +1523,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
             goto illegal_lba;
         }
         break;
-#if 0
     case MODE_SELECT:
         DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
         /* We don't support mode parameter changes.
@@ -1521,7 +1539,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
             goto illegal_request;
         }
         break;
-#endif
     case WRITE_SAME_10:
         nb_sectors = lduw_be_p(&req->cmd.buf[7]);
         goto write_same;
@@ -1556,7 +1573,12 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
     if (r->iov.iov_len == 0) {
         scsi_req_complete(&r->req, GOOD);
     }
-    return r->iov.iov_len;
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        assert(r->iov.iov_len == req->cmd.xfer);
+        return -r->iov.iov_len;
+    } else {
+        return r->iov.iov_len;
+    }
 
 illegal_request:
     if (r->req.status == -1) {
@@ -1845,10 +1867,8 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
     [REQUEST_SENSE]                   = &scsi_disk_emulate_reqops,
     [SYNCHRONIZE_CACHE]               = &scsi_disk_emulate_reqops,
     [SEEK_10]                         = &scsi_disk_emulate_reqops,
-#if 0
     [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
     [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
-#endif
     [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
     [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 6/8] scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
                   ` (4 preceding siblings ...)
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 5/8] scsi-disk: support emulated TO_DEV requests Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 7/8] scsi-disk: parse MODE SELECT commands and parameters Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 8/8] scsi-disk: support toggling the write cache Paolo Bonzini
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

The changeable values were not all-zeros for this mode page, fix it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index e64d659..a7f1f14 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1058,6 +1058,9 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
 
     case MODE_PAGE_R_W_ERROR:
         p[1] = 10;
+        if (page_control == 1) { /* Changeable Values */
+            break;
+        }
         p[2] = 0x80; /* Automatic Write Reallocation Enabled */
         if (s->qdev.type == TYPE_ROM) {
             p[3] = 0x20; /* Read Retry Count */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 7/8] scsi-disk: parse MODE SELECT commands and parameters
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
                   ` (5 preceding siblings ...)
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 6/8] scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 8/8] scsi-disk: support toggling the write cache Paolo Bonzini
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

This adds the bulk of the parsing code for MODE SELECT, including
breaking out changes to different mode pages, and checking that only
changeable values are modified.

In order to report errors correctly two passes are made through the
parameters; the first only looks for errors, the second actually
applies the changes to the mode page.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-bus.c  |   10 ++++
 hw/scsi-disk.c |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 hw/scsi.h      |    4 ++
 3 files changed, 174 insertions(+), 15 deletions(-)

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 559a815..c1653f8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1116,6 +1116,16 @@ const struct SCSISense sense_code_INVALID_FIELD = {
     .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
 };
 
+/* Illegal request, Invalid field in parameter list */
+const struct SCSISense sense_code_INVALID_PARAM = {
+    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
+};
+
+/* Illegal request, Parameter list length error */
+const struct SCSISense sense_code_INVALID_PARAM_LEN = {
+    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
+};
+
 /* Illegal request, LUN not supported */
 const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
     .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a7f1f14..cd0c389 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -42,6 +42,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
+#define SCSI_MAX_MODE_LEN    256
 
 typedef struct SCSIDiskState SCSIDiskState;
 
@@ -1279,6 +1278,162 @@ static void scsi_disk_emulate_read_data(SCSIRequest *req)
     scsi_req_complete(&r->req, GOOD);
 }
 
+static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
+                                       uint8_t *inbuf, int inlen)
+{
+    uint8_t mode_current[SCSI_MAX_MODE_LEN];
+    uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
+    uint8_t *p;
+    int len, expected_len, changeable_len, i;
+
+    /* The input buffer does not include the page header, so it is
+     * off by 2 bytes.
+     */
+    expected_len = inlen + 2;
+    if (expected_len > SCSI_MAX_MODE_LEN) {
+        return -1;
+    }
+
+    p = mode_current;
+    memset(mode_current, 0, inlen + 2);
+    len = mode_sense_page(s, page, &p, 0);
+    if (len < 0 || len != expected_len) {
+        return -1;
+    }
+
+    p = mode_changeable;
+    memset(mode_changeable, 0, inlen + 2);
+    changeable_len = mode_sense_page(s, page, &p, 1);
+    assert(changeable_len == len);
+
+    /* Check that unchangeable bits are the same as what MODE SENSE
+     * would return.
+     */
+    for (i = 2; i < len; i++) {
+        if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
+{
+}
+
+static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    while (len > 0) {
+        int page, subpage, page_len;
+
+        /* Parse both possible formats for the mode page headers.  */
+        page = p[0] & 0x3f;
+        if (p[0] & 0x40) {
+            if (len < 4) {
+                goto invalid_param_len;
+            }
+            subpage = p[1];
+            page_len = lduw_be_p(&p[2]);
+            p += 4;
+            len -= 4;
+        } else {
+            if (len < 2) {
+                goto invalid_param_len;
+            }
+            subpage = 0;
+            page_len = p[1];
+            p += 2;
+            len -= 2;
+        }
+
+        if (subpage) {
+            goto invalid_param;
+        }
+        if (page_len > len) {
+            goto invalid_param_len;
+        }
+
+        if (!change) {
+            if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) {
+                goto invalid_param;
+            }
+        } else {
+            /* Make sure offsets match those in mode_sense_page.  */
+            p[-2] = page;
+            p[-1] = page_len;
+            scsi_disk_apply_mode_select(s, page, p - 2);
+        }
+
+        p += page_len;
+        len -= page_len;
+    }
+    return 0;
+
+invalid_param:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
+    return -1;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+    return -1;
+}
+
+static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    uint8_t *p = inbuf;
+    int cmd = r->req.cmd.buf[0];
+    int len = r->req.cmd.xfer;
+    int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
+    int bd_len;
+    int pass;
+
+    /* We only support PF=1, SP=0.  */
+    if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
+        goto invalid_field;
+    }
+
+    if (len < hdr_len) {
+        goto invalid_param_len;
+    }
+
+    bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6]));
+    len -= hdr_len;
+    p += hdr_len;
+    if (len < bd_len) {
+        goto invalid_param_len;
+    }
+    if (bd_len != 0 && bd_len != 8) {
+        goto invalid_param;
+    }
+
+    len -= bd_len;
+    p += bd_len;
+
+    /* Ensure no change is made if there is an error!  */
+    for (pass = 0; pass < 2; pass++) {
+        if (mode_select_pages(r, p, len, pass == 1) < 0) {
+            assert(pass == 0);
+            return;
+        }
+    }
+    scsi_req_complete(&r->req, GOOD);
+    return;
+
+invalid_param:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
+    return;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+    return;
+
+invalid_field:
+    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    return;
+}
+
 static void scsi_disk_emulate_write_data(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1295,7 +1450,7 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
     case MODE_SELECT:
     case MODE_SELECT_10:
         /* This also clears the sense buffer for REQUEST SENSE.  */
-        scsi_req_complete(&r->req, GOOD);
+        scsi_disk_emulate_mode_select(r, r->iov.iov_base);
         break;
 
     default:
@@ -1528,19 +1683,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         break;
     case MODE_SELECT:
         DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
-        /* We don't support mode parameter changes.
-           Allow the mode parameter header + block descriptors only. */
-        if (r->req.cmd.xfer > 12) {
-            goto illegal_request;
-        }
         break;
     case MODE_SELECT_10:
         DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
-        /* We don't support mode parameter changes.
-           Allow the mode parameter header + block descriptors only. */
-        if (r->req.cmd.xfer > 16) {
-            goto illegal_request;
-        }
         break;
     case WRITE_SAME_10:
         nb_sectors = lduw_be_p(&req->cmd.buf[7]);
diff --git a/hw/scsi.h b/hw/scsi.h
index dd1cd45..72b281f 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -180,6 +180,10 @@ extern const struct SCSISense sense_code_INVALID_OPCODE;
 extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
 /* Illegal request, Invalid field in CDB */
 extern const struct SCSISense sense_code_INVALID_FIELD;
+/* Illegal request, Invalid field in parameter list */
+extern const struct SCSISense sense_code_INVALID_PARAM;
+/* Illegal request, Parameter list length error */
+extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
 /* Illegal request, LUN not supported */
 extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
 /* Illegal request, Saving parameters not supported */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 8/8] scsi-disk: support toggling the write cache
  2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
                   ` (6 preceding siblings ...)
  2012-07-10 14:15 ` [Qemu-devel] [PATCH 7/8] scsi-disk: parse MODE SELECT commands and parameters Paolo Bonzini
@ 2012-07-10 14:15 ` Paolo Bonzini
  7 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2012-07-10 14:15 UTC (permalink / raw)
  To: qemu-devel

Finally, this uses the "plumbing" in the previous patch to
add support for toggling the WCE bit of the caching mode page.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index cd0c389..d4d3ae6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1048,10 +1049,8 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
     case MODE_PAGE_CACHING:
         p[0] = 8;
         p[1] = 0x12;
-        if (page_control == 1) { /* Changeable Values */
-            break;
-        }
-        if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
+        if (page_control == 1 || /* Changeable Values */
+            bdrv_enable_write_cache(s->qdev.conf.bs)) {
             p[2] = 4; /* WCE */
         }
         break;
@@ -1319,6 +1319,14 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
 
 static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
 {
+    switch (page) {
+    case MODE_PAGE_CACHING:
+        bdrv_set_enable_write_cache(s->qdev.conf.bs, (p[2] & 4) != 0);
+        break;
+
+    default:
+        break;
+    }
 }
 
 static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-07-10 14:16 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-10 14:15 [Qemu-devel] [PATCH 0/9] scsi-disk: support toggling the write cache Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 1/8] scsi-disk: make discard asynchronous Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 2/8] scsi-disk: move all non-DMA commands to scsi_disk_emulate_command Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 3/8] scsi-disk: split scsi-disk reqops Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 4/8] scsi-disk: separate read_data/write_data implementation for emulate_reqops Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 5/8] scsi-disk: support emulated TO_DEV requests Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 6/8] scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 7/8] scsi-disk: parse MODE SELECT commands and parameters Paolo Bonzini
2012-07-10 14:15 ` [Qemu-devel] [PATCH 8/8] scsi-disk: support toggling the write cache Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.