qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support
@ 2019-11-08  9:35 Yaowei Bai
  2019-11-08  9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08  9:35 UTC (permalink / raw)
  To: pbonzini, fam, dillaman, kwolf, mreitz
  Cc: baiyaowei, yangjun, qemu-devel, qemu-block

Recently ceph/librbd added several interfaces to handle SCSI commands like
COMPARE_AND_WRITE directly. However they were only be used in special
scenarios, i.e. ISCSI. That involves more software components which makes
the IO path longer and could bring more potential issues. Actually we're
maintaining several ceph clusters with ISCSI protocal being used which,
i have to say, is not an easy job.

So supporting COMPARE_AND_WRITE in scsi-disk would be a reasonable solution
and easy to implement with the help of the SCSI handlers in librbd, which
could leave alone the ISCSI stuff and make the IO path shorter.

This patchset implements it by reusing the blk_aio_pwritev interface and
introducing a new BDRV_REQ_COMPARE_AND_WRITE element into BdrvRequestFlags
to indicate a COMPARE_AND_WRITE request, rather than adding a new interface
into block-backend.c.

The FUA support is implemented in the blk_aio_pwritev's callback function
similar to its emulation in scsi_write_do_fua function, maybe through
BDRV_REQ_FUA is another doable way.

This patchset is tested with the method of sg_compare_and_write.txt from
sg3_utils. Link below:

https://github.com/hreinecke/sg3_utils/blob/master/examples/sg_compare_and_write.txt

v1->v2: fix checkpatch script complaints and cleanup

Yaowei Bai (4):
  block: add SCSI COMPARE_AND_WRITE support
  block/rbd: implement bdrv_aio_compare_and_write interface
  hw/scsi: add SCSI COMPARE_AND_WRITE support
  scsi-disk: add FUA support for COMPARE_AND_WRITE

 block/io.c                  | 20 +++++++++
 block/raw-format.c          |  3 +-
 block/rbd.c                 | 45 ++++++++++++++++++++-
 hw/scsi/emulation.c         |  1 +
 hw/scsi/scsi-bus.c          |  4 ++
 hw/scsi/scsi-disk.c         | 98 +++++++++++++++++++++++++++++++++++++++++++++
 hw/scsi/trace-events        |  1 +
 include/block/block.h       |  5 ++-
 include/block/block_int.h   |  3 ++
 include/hw/scsi/emulation.h |  3 ++
 include/scsi/utils.h        |  2 +
 scsi/utils.c                |  5 +++
 12 files changed, 185 insertions(+), 5 deletions(-)

-- 
1.8.3.1





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

* [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support
  2019-11-08  9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
@ 2019-11-08  9:35 ` Yaowei Bai
  2019-11-08  9:35 ` [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface Yaowei Bai
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08  9:35 UTC (permalink / raw)
  To: pbonzini, fam, dillaman, kwolf, mreitz
  Cc: baiyaowei, yangjun, qemu-devel, qemu-block

Some storages(i.e. librbd) already have interfaces to handle some SCSI
commands directly. This patch adds COMPARE_AND_WRITE command support
through the write path in the block io layer by introducing a new element
BDRV_REQ_COMPARE_AND_WRITE into BdrvRequestFlags which indicates a
COMPARE_AND_WRITE request. In this way we could easily extend to other
SCSI commands support like WRITE_SAME in the future.

Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
 block/io.c                | 20 ++++++++++++++++++++
 include/block/block.h     |  5 +++--
 include/block/block_int.h |  3 +++
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/block/io.c b/block/io.c
index f75777f..3507d71 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1186,6 +1186,26 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
         goto emulate_flags;
     }
 
+    if (drv->bdrv_aio_compare_and_write &&
+                              (flags & BDRV_REQ_COMPARE_AND_WRITE)) {
+        BlockAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = drv->bdrv_aio_compare_and_write(bs, offset, bytes, qiov,
+                                    flags & bs->supported_write_flags,
+                                    bdrv_co_io_em_complete, &co);
+        flags &= ~bs->supported_write_flags;
+        if (acb == NULL) {
+            ret = -EIO;
+        } else {
+            qemu_coroutine_yield();
+            ret = co.ret;
+        }
+        goto emulate_flags;
+    }
+
     if (drv->bdrv_aio_pwritev) {
         BlockAIOCB *acb;
         CoroutineIOCompletion co = {
diff --git a/include/block/block.h b/include/block/block.h
index 1df9848..f71aa4f 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -92,9 +92,10 @@ typedef enum {
      * on read request and means that caller doesn't really need data to be
      * written to qiov parameter which may be NULL.
      */
-    BDRV_REQ_PREFETCH  = 0x200,
+    BDRV_REQ_PREFETCH           = 0x200,
+    BDRV_REQ_COMPARE_AND_WRITE  = 0x400,
     /* Mask of valid flags */
-    BDRV_REQ_MASK               = 0x3ff,
+    BDRV_REQ_MASK               = 0x7ff,
 } BdrvRequestFlags;
 
 typedef struct BlockSizes {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index dd033d0..96096e0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -189,6 +189,9 @@ struct BlockDriver {
     BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs,
         int64_t offset, int bytes,
         BlockCompletionFunc *cb, void *opaque);
+    BlockAIOCB *(*bdrv_aio_compare_and_write)(BlockDriverState *bs,
+        uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
+        BlockCompletionFunc *cb, void *opaque);
 
     int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
-- 
1.8.3.1





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

* [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface
  2019-11-08  9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
  2019-11-08  9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
@ 2019-11-08  9:35 ` Yaowei Bai
  2019-11-08  9:35 ` [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support Yaowei Bai
  2019-11-08  9:35 ` [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE Yaowei Bai
  3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08  9:35 UTC (permalink / raw)
  To: pbonzini, fam, dillaman, kwolf, mreitz
  Cc: baiyaowei, yangjun, qemu-devel, qemu-block

This patch adds librbd's SCSI COMPARE_AND_WRITE command interface
support with bdrv_aio_compare_and_write function pointer. Note
currently when a miscompare happens a mismatch offset of 0 is
always reported rather than the actual mismatch offset. This
should not be a big issue contemporarily and will be fixed
accordingly in the future.

Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
 block/raw-format.c |  3 ++-
 block/rbd.c        | 45 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/block/raw-format.c b/block/raw-format.c
index 3a76ec7..e87cd44 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -439,7 +439,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
 
     bs->sg = bs->file->bs->sg;
     bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
-        (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
+        (BDRV_REQ_FUA & bs->file->bs->supported_write_flags) |
+        (BDRV_REQ_COMPARE_AND_WRITE & bs->file->bs->supported_write_flags);
     bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
         ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
             bs->file->bs->supported_zero_flags);
diff --git a/block/rbd.c b/block/rbd.c
index 027cbcc..0e45bc3 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,11 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+#define LIBRBD_HAVE_COMPARE_AND_WRITE 1
+#else
+#define LIBRBD_HAVE_COMPARE_AND_WRITE 0
+#endif
+
 typedef enum {
     RBD_AIO_READ,
     RBD_AIO_WRITE,
     RBD_AIO_DISCARD,
-    RBD_AIO_FLUSH
+    RBD_AIO_FLUSH,
+    RBD_AIO_COMPARE_AND_WRITE
 } RBDAIOCmd;
 
 typedef struct RBDAIOCB {
@@ -798,6 +805,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
+    if (LIBRBD_HAVE_COMPARE_AND_WRITE) {
+        bs->supported_write_flags = BDRV_REQ_COMPARE_AND_WRITE;
+    }
+
     r = 0;
     goto out;
 
@@ -933,7 +944,15 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
 
     rcb = g_new(RADOSCB, 1);
 
-    if (!LIBRBD_USE_IOVEC) {
+    if (cmd == RBD_AIO_COMPARE_AND_WRITE) {
+        acb->bounce = qemu_try_blockalign(bs, qiov->size);
+        if (acb->bounce == NULL) {
+            goto failed;
+        }
+
+        qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
+        rcb->buf = acb->bounce;
+    } else if (!LIBRBD_USE_IOVEC) {
         if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
             acb->bounce = NULL;
         } else {
@@ -993,6 +1012,10 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
     case RBD_AIO_FLUSH:
         r = rbd_aio_flush_wrapper(s->image, c);
         break;
+    case RBD_AIO_COMPARE_AND_WRITE:
+        r = rbd_aio_compare_and_write(s->image, off, size / 2, rcb->buf,
+                                     (rcb->buf + size / 2), c, 0, 0);
+        break;
     default:
         r = -EINVAL;
     }
@@ -1056,6 +1079,20 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
 }
 #endif
 
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+static BlockAIOCB *qemu_rbd_aio_compare_and_write(BlockDriverState *bs,
+                                                  uint64_t offset,
+                                                  uint64_t bytes,
+                                                  QEMUIOVector *qiov,
+                                                  int flags,
+                                                  BlockCompletionFunc *cb,
+                                                  void *opaque)
+{
+    return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
+                         RBD_AIO_COMPARE_AND_WRITE);
+}
+#endif
+
 static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BDRVRBDState *s = bs->opaque;
@@ -1310,6 +1347,10 @@ static BlockDriver bdrv_rbd = {
     .bdrv_aio_pdiscard      = qemu_rbd_aio_pdiscard,
 #endif
 
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+    .bdrv_aio_compare_and_write = qemu_rbd_aio_compare_and_write,
+#endif
+
     .bdrv_snapshot_create   = qemu_rbd_snap_create,
     .bdrv_snapshot_delete   = qemu_rbd_snap_remove,
     .bdrv_snapshot_list     = qemu_rbd_snap_list,
-- 
1.8.3.1





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

* [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support
  2019-11-08  9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
  2019-11-08  9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
  2019-11-08  9:35 ` [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface Yaowei Bai
@ 2019-11-08  9:35 ` Yaowei Bai
  2019-11-08  9:35 ` [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE Yaowei Bai
  3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08  9:35 UTC (permalink / raw)
  To: pbonzini, fam, dillaman, kwolf, mreitz
  Cc: baiyaowei, yangjun, qemu-devel, qemu-block

This patch emulates COMPARE_AND_WRITE command with the
BDRV_REQ_COMPARE_AND_WRITE flag introduced by last patch. It matches
the SBC-4 standard except the FUA bit support, it'll be finished in
the next patch.

Note that cmd->xfer is set 2 * the number got by scsi_data_cdb_xfer
so we could touch the least code.

Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
 hw/scsi/emulation.c         |  1 +
 hw/scsi/scsi-bus.c          |  4 +++
 hw/scsi/scsi-disk.c         | 88 +++++++++++++++++++++++++++++++++++++++++++++
 hw/scsi/trace-events        |  1 +
 include/hw/scsi/emulation.h |  3 ++
 include/scsi/utils.h        |  2 ++
 scsi/utils.c                |  5 +++
 7 files changed, 104 insertions(+)

diff --git a/hw/scsi/emulation.c b/hw/scsi/emulation.c
index 06d62f3..1f53c4a 100644
--- a/hw/scsi/emulation.c
+++ b/hw/scsi/emulation.c
@@ -9,6 +9,7 @@ int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl)
     memset(outbuf, 0, 0x3c);
 
     outbuf[0] = bl->wsnz; /* wsnz */
+    outbuf[1] = MAX_COMPARE_AND_WRITE_LENGTH;
 
     if (bl->max_io_sectors) {
         /* optimal transfer length granularity.  This field and the optimal
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 359d50d..a20eb11 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1003,6 +1003,9 @@ static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
     case WRITE_VERIFY_16:
         cmd->xfer *= dev->blocksize;
         break;
+    case COMPARE_AND_WRITE:
+        cmd->xfer *= 2 * dev->blocksize;
+        break;
     case READ_6:
     case READ_REVERSE:
         /* length 0 means 256 blocks */
@@ -1222,6 +1225,7 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
     case PERSISTENT_RESERVE_OUT:
     case MAINTENANCE_OUT:
     case SET_WINDOW:
+    case COMPARE_AND_WRITE:
     case SCAN:
         /* SCAN conflicts with START_STOP.  START_STOP has cmd->xfer set to 0 for
          * non-scanner devices, so we only get here for SCAN and not for START_STOP.
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 07fb5eb..f9a0267 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -478,6 +478,9 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
         case ENOSPC:
             scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
             break;
+        case EILSEQ:
+            scsi_check_condition(r, SENSE_CODE(MISCOMPARE_DURING_VERIFY));
+            break;
         default:
             scsi_check_condition(r, SENSE_CODE(IO_ERROR));
             break;
@@ -1825,6 +1828,84 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
                                    scsi_write_same_complete, data);
 }
 
+typedef struct CompareAndWriteCBData {
+    SCSIDiskReq *r;
+    int64_t sector;
+    int nb_sectors;
+    QEMUIOVector qiov;
+    struct iovec iov;
+} CompareAndWriteCBData;
+
+static void scsi_compare_and_write_complete(void *opaque, int ret)
+{
+    CompareAndWriteCBData *data = opaque;
+    SCSIDiskReq *r = data->r;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
+    if (scsi_disk_req_check_error(r, ret, true)) {
+        goto done;
+    }
+
+    block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    scsi_req_unref(&r->req);
+    qemu_vfree(data->iov.iov_base);
+    g_free(data);
+    aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
+}
+
+static void scsi_disk_emulate_compare_and_write(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
+    CompareAndWriteCBData *data;
+    uint8_t *buf;
+    int i;
+
+    if (nb_sectors > MAX_COMPARE_AND_WRITE_LENGTH) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return;
+    }
+
+    if (blk_is_read_only(s->qdev.conf.blk)) {
+        scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
+        return;
+    }
+
+    if (r->req.cmd.lba > s->qdev.max_lba ||
+                !check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
+        scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+        return;
+    }
+
+    data = g_new0(CompareAndWriteCBData, 1);
+    data->r = r;
+    data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+    data->nb_sectors = r->req.cmd.xfer * (s->qdev.blocksize / 512);
+    data->iov.iov_len = data->nb_sectors;
+    data->iov.iov_base = buf = blk_blockalign(s->qdev.conf.blk,
+                                              data->iov.iov_len);
+    qemu_iovec_init_external(&data->qiov, &data->iov, 1);
+
+    for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) {
+        memcpy(&buf[i], &inbuf[i], s->qdev.blocksize);
+    }
+
+    scsi_req_ref(&r->req);
+    block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
+                     data->iov.iov_len, BLOCK_ACCT_WRITE);
+    r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
+                                   data->sector << BDRV_SECTOR_BITS,
+                                   &data->qiov, BDRV_REQ_COMPARE_AND_WRITE,
+                                   scsi_compare_and_write_complete, data);
+}
+
 static void scsi_disk_emulate_write_data(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1861,6 +1942,9 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
         scsi_disk_emulate_write_same(r, r->iov.iov_base);
         break;
 
+    case COMPARE_AND_WRITE:
+        scsi_disk_emulate_compare_and_write(r, r->iov.iov_base);
+        break;
     default:
         abort();
     }
@@ -2115,6 +2199,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         trace_scsi_disk_emulate_command_WRITE_SAME(
                 req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer);
         break;
+    case COMPARE_AND_WRITE:
+        trace_scsi_disk_emulate_command_COMPARE_AND_WRITE(r->req.cmd.xfer);
+        break;
     default:
         trace_scsi_disk_emulate_command_UNKNOWN(buf[0],
                                                 scsi_command_name(buf[0]));
@@ -2542,6 +2629,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
     [VERIFY_10]                       = &scsi_disk_emulate_reqops,
     [VERIFY_12]                       = &scsi_disk_emulate_reqops,
     [VERIFY_16]                       = &scsi_disk_emulate_reqops,
+    [COMPARE_AND_WRITE]               = &scsi_disk_emulate_reqops,
 
     [READ_6]                          = &scsi_disk_dma_reqops,
     [READ_10]                         = &scsi_disk_dma_reqops,
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index b082005..0783e58 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -317,6 +317,7 @@ scsi_disk_emulate_command_MODE_SELECT_10(size_t xfer) "Mode Select(10) (len %zd)
 scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)"
 scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
 scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)"
+scsi_disk_emulate_command_COMPARE_AND_WRITE(size_t xfer) "COMPARE AND WRITE (len %zd)"
 scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
 scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)"
 scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)"
diff --git a/include/hw/scsi/emulation.h b/include/hw/scsi/emulation.h
index 9521704..2148316 100644
--- a/include/hw/scsi/emulation.h
+++ b/include/hw/scsi/emulation.h
@@ -1,6 +1,9 @@
 #ifndef HW_SCSI_EMULATION_H
 #define HW_SCSI_EMULATION_H
 
+/* maximum compare and write length : 64kb */
+#define MAX_COMPARE_AND_WRITE_LENGTH 128
+
 typedef struct SCSIBlockLimits {
     bool wsnz;
     uint16_t min_io_size;
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index fbc5588..35f554e 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -101,6 +101,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
 extern const struct SCSISense sense_code_WRITE_PROTECTED;
 /* Data Protection, Space Allocation Failed Write Protect */
 extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+/* Miscompare, Miscompare During Verify Operation */
+extern const struct SCSISense sense_code_MISCOMPARE_DURING_VERIFY;
 
 #define SENSE_CODE(x) sense_code_ ## x
 
diff --git a/scsi/utils.c b/scsi/utils.c
index c50e81f..c142a53 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -311,6 +311,11 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
     .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
 };
 
+/* Miscompare, Miscompare During Verify Operation */
+const struct SCSISense sense_code_MISCOMPARE_DURING_VERIFY = {
+    .key = MISCOMPARE, .asc = 0x1d, .ascq = 0x00
+};
+
 /*
  * scsi_convert_sense
  *
-- 
1.8.3.1





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

* [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE
  2019-11-08  9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
                   ` (2 preceding siblings ...)
  2019-11-08  9:35 ` [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support Yaowei Bai
@ 2019-11-08  9:35 ` Yaowei Bai
  3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08  9:35 UTC (permalink / raw)
  To: pbonzini, fam, dillaman, kwolf, mreitz
  Cc: baiyaowei, yangjun, qemu-devel, qemu-block

It is implemented in the blk_aio_pwritev's callback function in a way
similar to its emulation in scsi_write_do_fua function

Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
 hw/scsi/scsi-disk.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index f9a0267..0731a3b 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -229,6 +229,7 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
     case WRITE_10:
     case WRITE_12:
     case WRITE_16:
+    case COMPARE_AND_WRITE:
         return (cmd->buf[1] & 8) != 0;
 
     case VERIFY_10:
@@ -1850,10 +1851,17 @@ static void scsi_compare_and_write_complete(void *opaque, int ret)
     }
 
     block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+    if (r->need_fua_emulation) {
+        block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
+                         BLOCK_ACCT_FLUSH);
+        r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
+        goto free;
+    }
     scsi_req_complete(&r->req, GOOD);
 
 done:
     scsi_req_unref(&r->req);
+free:
     qemu_vfree(data->iov.iov_base);
     g_free(data);
     aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
@@ -1954,6 +1962,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
     uint64_t nb_sectors;
     uint8_t *outbuf;
     int buflen;
@@ -2209,6 +2218,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         return 0;
     }
     assert(!r->req.aiocb);
+    r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd);
     r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
     if (r->iov.iov_len == 0) {
         scsi_req_complete(&r->req, GOOD);
-- 
1.8.3.1





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

end of thread, other threads:[~2019-11-08  9:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-08  9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
2019-11-08  9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
2019-11-08  9:35 ` [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface Yaowei Bai
2019-11-08  9:35 ` [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support Yaowei Bai
2019-11-08  9:35 ` [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE Yaowei Bai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).