From aed5e907c7e325b24f48c9c9fe31a3d7e995d20f Mon Sep 17 00:00:00 2001
Message-Id: <aed5e907c7e325b24f48c9c9fe31a3d7e995d20f.1346668737.git.minovotn@redhat.com>
In-Reply-To: <d22fc35d1e14760dba012d88bdf0162dd7d0f3c6.1346668737.git.minovotn@redhat.com>
References: <d22fc35d1e14760dba012d88bdf0162dd7d0f3c6.1346668737.git.minovotn@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Mon, 27 Aug 2012 13:42:08 +0200
Subject: [PATCH 05/10] scsi: add support for FUA on writes

RH-Author: Paolo Bonzini <pbonzini@redhat.com>
Message-id: <1346074931-12083-5-git-send-email-pbonzini@redhat.com>
Patchwork-id: 41328
O-Subject: [RHEL 6.4 qemu-kvm PATCH 4/7] scsi: add support for FUA on writes
Bugzilla: 814084
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
RH-Acked-by: Orit Wasserman <owasserm@redhat.com>

Bugzilla: 814084

To force unit access, add a flush operation after the actual write.
WRITE AND VERIFY commands always flush according to SBC, so do it
even though we do not perform the reread.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 7e8c49c56154ab5c45d4f07edf0c22728735da35)
---
 hw/scsi-disk.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file modificato, 47 inserzioni(+), 2 rimozioni(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/scsi-disk.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 05ee81a..69e511a 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -171,6 +171,45 @@ done:
     }
 }
 
+static bool scsi_is_cmd_fua(SCSICommand *cmd)
+{
+    switch (cmd->buf[0]) {
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+        return (cmd->buf[1] & 8) != 0;
+
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        return true;
+
+    case READ_6:
+    case WRITE_6:
+    default:
+        return false;
+    }
+}
+
+static void scsi_write_do_fua(SCSIDiskReq *r)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    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);
+        return;
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
 static void scsi_dma_complete(void *opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -186,7 +225,12 @@ static void scsi_dma_complete(void *opaque, int ret)
 
     r->sector += r->sector_count;
     r->sector_count = 0;
-    scsi_req_complete(&r->req, GOOD);
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        scsi_write_do_fua(r);
+        return;
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
 
 done:
     if (!r->req.io_canceled) {
@@ -342,7 +386,8 @@ static void scsi_write_complete(void * opaque, int ret)
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
-        scsi_req_complete(&r->req, GOOD);
+        scsi_write_do_fua(r);
+        return;
     } else {
         scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
         DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
-- 
1.7.11.4

