diff --git a/.gitignore b/.gitignore
index 6cefd1b..99836e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@
 /qemu-2.10.0-rc3.tar.xz
 /qemu-2.10.0-rc4.tar.xz
 /qemu-2.10.0.tar.xz
+/qemu-2.10.1.tar.xz
diff --git a/0001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch b/0001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
new file mode 100644
index 0000000..a2d6dc1
--- /dev/null
+++ b/0001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
@@ -0,0 +1,380 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Wed, 30 Aug 2017 14:53:59 +0100
+Subject: [PATCH] io: add new qio_channel_{readv, writev, read, write}_all
+ functions
+
+These functions wait until they are able to read / write the full
+requested data buffer(s).
+
+Reviewed-by: Eric Blake <eblake@redhat.com>
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ include/io/channel.h       |  90 +++++++++++++++++++++++++++++++++++++++
+ io/channel.c               |  94 +++++++++++++++++++++++++++++++++++++++++
+ tests/io-channel-helpers.c | 102 ++++-----------------------------------------
+ 3 files changed, 193 insertions(+), 93 deletions(-)
+
+diff --git a/include/io/channel.h b/include/io/channel.h
+index db9bb022a1..e11a62ea50 100644
+--- a/include/io/channel.h
++++ b/include/io/channel.h
+@@ -268,6 +268,58 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
+                                 size_t nfds,
+                                 Error **errp);
+ 
++/**
++ * qio_channel_readv_all:
++ * @ioc: the channel object
++ * @iov: the array of memory regions to read data into
++ * @niov: the length of the @iov array
++ * @errp: pointer to a NULL-initialized error object
++ *
++ * Read data from the IO channel, storing it in the
++ * memory regions referenced by @iov. Each element
++ * in the @iov will be fully populated with data
++ * before the next one is used. The @niov parameter
++ * specifies the total number of elements in @iov.
++ *
++ * The function will wait for all requested data
++ * to be read, yielding from the current coroutine
++ * if required.
++ *
++ * If end-of-file occurs before all requested data
++ * has been read, an error will be reported.
++ *
++ * Returns: 0 if all bytes were read, or -1 on error
++ */
++int qio_channel_readv_all(QIOChannel *ioc,
++                          const struct iovec *iov,
++                          size_t niov,
++                          Error **errp);
++
++
++/**
++ * qio_channel_writev_all:
++ * @ioc: the channel object
++ * @iov: the array of memory regions to write data from
++ * @niov: the length of the @iov array
++ * @errp: pointer to a NULL-initialized error object
++ *
++ * Write data to the IO channel, reading it from the
++ * memory regions referenced by @iov. Each element
++ * in the @iov will be fully sent, before the next
++ * one is used. The @niov parameter specifies the
++ * total number of elements in @iov.
++ *
++ * The function will wait for all requested data
++ * to be written, yielding from the current coroutine
++ * if required.
++ *
++ * Returns: 0 if all bytes were written, or -1 on error
++ */
++int qio_channel_writev_all(QIOChannel *ioc,
++                           const struct iovec *iov,
++                           size_t niov,
++                           Error **erp);
++
+ /**
+  * qio_channel_readv:
+  * @ioc: the channel object
+@@ -330,6 +382,44 @@ ssize_t qio_channel_write(QIOChannel *ioc,
+                           size_t buflen,
+                           Error **errp);
+ 
++/**
++ * qio_channel_read_all:
++ * @ioc: the channel object
++ * @buf: the memory region to read data into
++ * @buflen: the number of bytes to @buf
++ * @errp: pointer to a NULL-initialized error object
++ *
++ * Reads @buflen bytes into @buf, possibly blocking or (if the
++ * channel is non-blocking) yielding from the current coroutine
++ * multiple times until the entire content is read. If end-of-file
++ * occurs it will return an error rather than a short-read. Otherwise
++ * behaves as qio_channel_read().
++ *
++ * Returns: 0 if all bytes were read, or -1 on error
++ */
++int qio_channel_read_all(QIOChannel *ioc,
++                         char *buf,
++                         size_t buflen,
++                         Error **errp);
++/**
++ * qio_channel_write_all:
++ * @ioc: the channel object
++ * @buf: the memory region to write data into
++ * @buflen: the number of bytes to @buf
++ * @errp: pointer to a NULL-initialized error object
++ *
++ * Writes @buflen bytes from @buf, possibly blocking or (if the
++ * channel is non-blocking) yielding from the current coroutine
++ * multiple times until the entire content is written.  Otherwise
++ * behaves as qio_channel_write().
++ *
++ * Returns: 0 if all bytes were written, or -1 on error
++ */
++int qio_channel_write_all(QIOChannel *ioc,
++                          const char *buf,
++                          size_t buflen,
++                          Error **errp);
++
+ /**
+  * qio_channel_set_blocking:
+  * @ioc: the channel object
+diff --git a/io/channel.c b/io/channel.c
+index 1cfb8b33a2..5e8c2f0a91 100644
+--- a/io/channel.c
++++ b/io/channel.c
+@@ -22,6 +22,7 @@
+ #include "io/channel.h"
+ #include "qapi/error.h"
+ #include "qemu/main-loop.h"
++#include "qemu/iov.h"
+ 
+ bool qio_channel_has_feature(QIOChannel *ioc,
+                              QIOChannelFeature feature)
+@@ -85,6 +86,79 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
+ }
+ 
+ 
++
++int qio_channel_readv_all(QIOChannel *ioc,
++                          const struct iovec *iov,
++                          size_t niov,
++                          Error **errp)
++{
++    int ret = -1;
++    struct iovec *local_iov = g_new(struct iovec, niov);
++    struct iovec *local_iov_head = local_iov;
++    unsigned int nlocal_iov = niov;
++
++    nlocal_iov = iov_copy(local_iov, nlocal_iov,
++                          iov, niov,
++                          0, iov_size(iov, niov));
++
++    while (nlocal_iov > 0) {
++        ssize_t len;
++        len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
++        if (len == QIO_CHANNEL_ERR_BLOCK) {
++            qio_channel_wait(ioc, G_IO_IN);
++            continue;
++        } else if (len < 0) {
++            goto cleanup;
++        } else if (len == 0) {
++            error_setg(errp,
++                       "Unexpected end-of-file before all bytes were read");
++            goto cleanup;
++        }
++
++        iov_discard_front(&local_iov, &nlocal_iov, len);
++    }
++
++    ret = 0;
++
++ cleanup:
++    g_free(local_iov_head);
++    return ret;
++}
++
++int qio_channel_writev_all(QIOChannel *ioc,
++                           const struct iovec *iov,
++                           size_t niov,
++                           Error **errp)
++{
++    int ret = -1;
++    struct iovec *local_iov = g_new(struct iovec, niov);
++    struct iovec *local_iov_head = local_iov;
++    unsigned int nlocal_iov = niov;
++
++    nlocal_iov = iov_copy(local_iov, nlocal_iov,
++                          iov, niov,
++                          0, iov_size(iov, niov));
++
++    while (nlocal_iov > 0) {
++        ssize_t len;
++        len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
++        if (len == QIO_CHANNEL_ERR_BLOCK) {
++            qio_channel_wait(ioc, G_IO_OUT);
++            continue;
++        }
++        if (len < 0) {
++            goto cleanup;
++        }
++
++        iov_discard_front(&local_iov, &nlocal_iov, len);
++    }
++
++    ret = 0;
++ cleanup:
++    g_free(local_iov_head);
++    return ret;
++}
++
+ ssize_t qio_channel_readv(QIOChannel *ioc,
+                           const struct iovec *iov,
+                           size_t niov,
+@@ -123,6 +197,26 @@ ssize_t qio_channel_write(QIOChannel *ioc,
+ }
+ 
+ 
++int qio_channel_read_all(QIOChannel *ioc,
++                         char *buf,
++                         size_t buflen,
++                         Error **errp)
++{
++    struct iovec iov = { .iov_base = buf, .iov_len = buflen };
++    return qio_channel_readv_all(ioc, &iov, 1, errp);
++}
++
++
++int qio_channel_write_all(QIOChannel *ioc,
++                          const char *buf,
++                          size_t buflen,
++                          Error **errp)
++{
++    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
++    return qio_channel_writev_all(ioc, &iov, 1, errp);
++}
++
++
+ int qio_channel_set_blocking(QIOChannel *ioc,
+                               bool enabled,
+                               Error **errp)
+diff --git a/tests/io-channel-helpers.c b/tests/io-channel-helpers.c
+index 05e5579cf8..5430e1389d 100644
+--- a/tests/io-channel-helpers.c
++++ b/tests/io-channel-helpers.c
+@@ -21,6 +21,7 @@
+ #include "qemu/osdep.h"
+ #include "io-channel-helpers.h"
+ #include "qapi/error.h"
++#include "qemu/iov.h"
+ 
+ struct QIOChannelTest {
+     QIOChannel *src;
+@@ -37,77 +38,17 @@ struct QIOChannelTest {
+ };
+ 
+ 
+-static void test_skip_iovec(struct iovec **iov,
+-                            size_t *niov,
+-                            size_t skip,
+-                            struct iovec *old)
+-{
+-    size_t offset = 0;
+-    size_t i;
+-
+-    for (i = 0; i < *niov; i++) {
+-        if (skip < (*iov)[i].iov_len) {
+-            old->iov_len = (*iov)[i].iov_len;
+-            old->iov_base = (*iov)[i].iov_base;
+-
+-            (*iov)[i].iov_len -= skip;
+-            (*iov)[i].iov_base += skip;
+-            break;
+-        } else {
+-            skip -= (*iov)[i].iov_len;
+-
+-            if (i == 0 && old->iov_base) {
+-                (*iov)[i].iov_len = old->iov_len;
+-                (*iov)[i].iov_base = old->iov_base;
+-                old->iov_len = 0;
+-                old->iov_base = NULL;
+-            }
+-
+-            offset++;
+-        }
+-    }
+-
+-    *iov = *iov + offset;
+-    *niov -= offset;
+-}
+-
+-
+ /* This thread sends all data using iovecs */
+ static gpointer test_io_thread_writer(gpointer opaque)
+ {
+     QIOChannelTest *data = opaque;
+-    struct iovec *iov = data->inputv;
+-    size_t niov = data->niov;
+-    struct iovec old = { 0 };
+ 
+     qio_channel_set_blocking(data->src, data->blocking, NULL);
+ 
+-    while (niov) {
+-        ssize_t ret;
+-        ret = qio_channel_writev(data->src,
+-                                 iov,
+-                                 niov,
+-                                 &data->writeerr);
+-        if (ret == QIO_CHANNEL_ERR_BLOCK) {
+-            if (data->blocking) {
+-                error_setg(&data->writeerr,
+-                           "Unexpected I/O blocking");
+-                break;
+-            } else {
+-                qio_channel_wait(data->src,
+-                                 G_IO_OUT);
+-                continue;
+-            }
+-        } else if (ret < 0) {
+-            break;
+-        } else if (ret == 0) {
+-            error_setg(&data->writeerr,
+-                       "Unexpected zero length write");
+-            break;
+-        }
+-
+-        test_skip_iovec(&iov, &niov, ret, &old);
+-    }
++    qio_channel_writev_all(data->src,
++                           data->inputv,
++                           data->niov,
++                           &data->writeerr);
+ 
+     return NULL;
+ }
+@@ -117,38 +58,13 @@ static gpointer test_io_thread_writer(gpointer opaque)
+ static gpointer test_io_thread_reader(gpointer opaque)
+ {
+     QIOChannelTest *data = opaque;
+-    struct iovec *iov = data->outputv;
+-    size_t niov = data->niov;
+-    struct iovec old = { 0 };
+ 
+     qio_channel_set_blocking(data->dst, data->blocking, NULL);
+ 
+-    while (niov) {
+-        ssize_t ret;
+-
+-        ret = qio_channel_readv(data->dst,
+-                                iov,
+-                                niov,
+-                                &data->readerr);
+-
+-        if (ret == QIO_CHANNEL_ERR_BLOCK) {
+-            if (data->blocking) {
+-                error_setg(&data->readerr,
+-                           "Unexpected I/O blocking");
+-                break;
+-            } else {
+-                qio_channel_wait(data->dst,
+-                                 G_IO_IN);
+-                continue;
+-            }
+-        } else if (ret < 0) {
+-            break;
+-        } else if (ret == 0) {
+-            break;
+-        }
+-
+-        test_skip_iovec(&iov, &niov, ret, &old);
+-    }
++    qio_channel_readv_all(data->dst,
++                          data->outputv,
++                          data->niov,
++                          &data->readerr);
+ 
+     return NULL;
+ }
diff --git a/0002-io-Yield-rather-than-wait-when-already-in-coroutine.patch b/0002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
new file mode 100644
index 0000000..1fc3a1a
--- /dev/null
+++ b/0002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
@@ -0,0 +1,52 @@
+From: Eric Blake <eblake@redhat.com>
+Date: Tue, 5 Sep 2017 14:11:12 -0500
+Subject: [PATCH] io: Yield rather than wait when already in coroutine
+
+The new qio_channel_{read,write}{,v}_all functions are documented
+as yielding until data is available.  When used on a blocking
+channel, this yield is done via qio_channel_wait() which spawns
+a nested event loop under the hood (so it is that secondary loop
+which yields as needed); but if we are already in a coroutine (at
+which point QIO_CHANNEL_ERR_BLOCK is only possible if we are a
+non-blocking channel), we want to yield the current coroutine
+instead of spawning a nested event loop.
+
+Signed-off-by: Eric Blake <eblake@redhat.com>
+Message-Id: <20170905191114.5959-2-eblake@redhat.com>
+Acked-by: Daniel P. Berrange <berrange@redhat.com>
+[commit message updated]
+Signed-off-by: Eric Blake <eblake@redhat.com>
+---
+ io/channel.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/io/channel.c b/io/channel.c
+index 5e8c2f0a91..9e62794cab 100644
+--- a/io/channel.c
++++ b/io/channel.c
+@@ -105,7 +105,11 @@ int qio_channel_readv_all(QIOChannel *ioc,
+         ssize_t len;
+         len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
+         if (len == QIO_CHANNEL_ERR_BLOCK) {
+-            qio_channel_wait(ioc, G_IO_IN);
++            if (qemu_in_coroutine()) {
++                qio_channel_yield(ioc, G_IO_IN);
++            } else {
++                qio_channel_wait(ioc, G_IO_IN);
++            }
+             continue;
+         } else if (len < 0) {
+             goto cleanup;
+@@ -143,7 +147,11 @@ int qio_channel_writev_all(QIOChannel *ioc,
+         ssize_t len;
+         len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
+         if (len == QIO_CHANNEL_ERR_BLOCK) {
+-            qio_channel_wait(ioc, G_IO_OUT);
++            if (qemu_in_coroutine()) {
++                qio_channel_yield(ioc, G_IO_OUT);
++            } else {
++                qio_channel_wait(ioc, G_IO_OUT);
++            }
+             continue;
+         }
+         if (len < 0) {
diff --git a/0003-scsi-Refactor-scsi-sense-interpreting-code.patch b/0003-scsi-Refactor-scsi-sense-interpreting-code.patch
new file mode 100644
index 0000000..a9d91be
--- /dev/null
+++ b/0003-scsi-Refactor-scsi-sense-interpreting-code.patch
@@ -0,0 +1,190 @@
+From: Fam Zheng <famz@redhat.com>
+Date: Mon, 21 Aug 2017 22:10:05 +0800
+Subject: [PATCH] scsi: Refactor scsi sense interpreting code
+
+So that it can be reused outside of iscsi.c.
+
+Also update MAINTAINERS to include the new files in SCSI section.
+
+Signed-off-by: Fam Zheng <famz@redhat.com>
+Message-Id: <20170821141008.19383-2-famz@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ MAINTAINERS         |  2 ++
+ block/iscsi.c       | 45 ++++-----------------------------------------
+ include/scsi/scsi.h | 19 +++++++++++++++++++
+ util/Makefile.objs  |  1 +
+ util/scsi.c         | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 78 insertions(+), 41 deletions(-)
+ create mode 100644 include/scsi/scsi.h
+ create mode 100644 util/scsi.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index ccee28b12d..2a4e5036ae 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -969,7 +969,9 @@ SCSI
+ M: Paolo Bonzini <pbonzini@redhat.com>
+ S: Supported
+ F: include/hw/scsi/*
++F: include/scsi/*
+ F: hw/scsi/*
++F: util/scsi*
+ F: tests/virtio-scsi-test.c
+ T: git git://github.com/bonzini/qemu.git scsi-next
+ 
+diff --git a/block/iscsi.c b/block/iscsi.c
+index d557c99668..4bed63cd6d 100644
+--- a/block/iscsi.c
++++ b/block/iscsi.c
+@@ -40,6 +40,7 @@
+ #include "qmp-commands.h"
+ #include "qapi/qmp/qstring.h"
+ #include "crypto/secret.h"
++#include "scsi/scsi.h"
+ 
+ #include <iscsi/iscsi.h>
+ #include <iscsi/scsi-lowlevel.h>
+@@ -209,47 +210,9 @@ static inline unsigned exp_random(double mean)
+ 
+ static int iscsi_translate_sense(struct scsi_sense *sense)
+ {
+-    int ret;
+-
+-    switch (sense->key) {
+-    case SCSI_SENSE_NOT_READY:
+-        return -EBUSY;
+-    case SCSI_SENSE_DATA_PROTECTION:
+-        return -EACCES;
+-    case SCSI_SENSE_COMMAND_ABORTED:
+-        return -ECANCELED;
+-    case SCSI_SENSE_ILLEGAL_REQUEST:
+-        /* Parse ASCQ */
+-        break;
+-    default:
+-        return -EIO;
+-    }
+-    switch (sense->ascq) {
+-    case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR:
+-    case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE:
+-    case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB:
+-    case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST:
+-        ret = -EINVAL;
+-        break;
+-    case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE:
+-        ret = -ENOSPC;
+-        break;
+-    case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED:
+-        ret = -ENOTSUP;
+-        break;
+-    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT:
+-    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED:
+-    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN:
+-        ret = -ENOMEDIUM;
+-        break;
+-    case SCSI_SENSE_ASCQ_WRITE_PROTECTED:
+-        ret = -EACCES;
+-        break;
+-    default:
+-        ret = -EIO;
+-        break;
+-    }
+-    return ret;
++    return - scsi_sense_to_errno(sense->key,
++                                 (sense->ascq & 0xFF00) >> 8,
++                                 sense->ascq & 0xFF);
+ }
+ 
+ /* Called (via iscsi_service) with QemuMutex held.  */
+diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
+new file mode 100644
+index 0000000000..f894ace4bf
+--- /dev/null
++++ b/include/scsi/scsi.h
+@@ -0,0 +1,19 @@
++/*
++ *  SCSI helpers
++ *
++ *  Copyright 2017 Red Hat, Inc.
++ *
++ *  Authors:
++ *   Fam Zheng <famz@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ */
++#ifndef QEMU_SCSI_H
++#define QEMU_SCSI_H
++
++int scsi_sense_to_errno(int key, int asc, int ascq);
++
++#endif
+diff --git a/util/Makefile.objs b/util/Makefile.objs
+index 50a55ecc75..c9e6c493d3 100644
+--- a/util/Makefile.objs
++++ b/util/Makefile.objs
+@@ -45,3 +45,4 @@ util-obj-y += qht.o
+ util-obj-y += range.o
+ util-obj-y += stats64.o
+ util-obj-y += systemd.o
++util-obj-y += scsi.o
+diff --git a/util/scsi.c b/util/scsi.c
+new file mode 100644
+index 0000000000..a6710799fc
+--- /dev/null
++++ b/util/scsi.c
+@@ -0,0 +1,52 @@
++/*
++ *  SCSI helpers
++ *
++ *  Copyright 2017 Red Hat, Inc.
++ *
++ *  Authors:
++ *   Fam Zheng <famz@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ */
++
++#include "qemu/osdep.h"
++#include "scsi/scsi.h"
++
++int scsi_sense_to_errno(int key, int asc, int ascq)
++{
++    switch (key) {
++    case 0x02: /* NOT READY */
++        return EBUSY;
++    case 0x07: /* DATA PROTECTION */
++        return EACCES;
++    case 0x0b: /* COMMAND ABORTED */
++        return ECANCELED;
++    case 0x05: /* ILLEGAL REQUEST */
++        /* Parse ASCQ */
++        break;
++    default:
++        return EIO;
++    }
++    switch ((asc << 8) | ascq) {
++    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
++    case 0x2000: /* INVALID OPERATION CODE */
++    case 0x2400: /* INVALID FIELD IN CDB */
++    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
++        return EINVAL;
++    case 0x2100: /* LBA OUT OF RANGE */
++        return ENOSPC;
++    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
++        return ENOTSUP;
++    case 0x3a00: /* MEDIUM NOT PRESENT */
++    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
++    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
++        return ENOMEDIUM;
++    case 0x2700: /* WRITE PROTECTED */
++        return EACCES;
++    default:
++        return EIO;
++    }
++}
diff --git a/0004-scsi-Improve-scsi_sense_to_errno.patch b/0004-scsi-Improve-scsi_sense_to_errno.patch
new file mode 100644
index 0000000..4156754
--- /dev/null
+++ b/0004-scsi-Improve-scsi_sense_to_errno.patch
@@ -0,0 +1,57 @@
+From: Fam Zheng <famz@redhat.com>
+Date: Mon, 21 Aug 2017 22:10:06 +0800
+Subject: [PATCH] scsi: Improve scsi_sense_to_errno
+
+Tweak the errno mapping to return more accurate/appropriate values.
+
+Signed-off-by: Fam Zheng <famz@redhat.com>
+Message-Id: <20170821141008.19383-3-famz@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ util/scsi.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/util/scsi.c b/util/scsi.c
+index a6710799fc..472eb5bea5 100644
+--- a/util/scsi.c
++++ b/util/scsi.c
+@@ -18,13 +18,16 @@
+ int scsi_sense_to_errno(int key, int asc, int ascq)
+ {
+     switch (key) {
+-    case 0x02: /* NOT READY */
+-        return EBUSY;
+-    case 0x07: /* DATA PROTECTION */
+-        return EACCES;
++    case 0x00: /* NO SENSE */
++    case 0x01: /* RECOVERED ERROR */
++    case 0x06: /* UNIT ATTENTION */
++        /* These sense keys are not errors */
++        return 0;
+     case 0x0b: /* COMMAND ABORTED */
+         return ECANCELED;
++    case 0x02: /* NOT READY */
+     case 0x05: /* ILLEGAL REQUEST */
++    case 0x07: /* DATA PROTECTION */
+         /* Parse ASCQ */
+         break;
+     default:
+@@ -37,6 +40,7 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
+     case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
+         return EINVAL;
+     case 0x2100: /* LBA OUT OF RANGE */
++    case 0x2707: /* SPACE ALLOC FAILED */
+         return ENOSPC;
+     case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
+         return ENOTSUP;
+@@ -46,6 +50,10 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
+         return ENOMEDIUM;
+     case 0x2700: /* WRITE PROTECTED */
+         return EACCES;
++    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
++        return EAGAIN;
++    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
++        return ENOTCONN;
+     default:
+         return EIO;
+     }
diff --git a/0005-scsi-Introduce-scsi_sense_buf_to_errno.patch b/0005-scsi-Introduce-scsi_sense_buf_to_errno.patch
new file mode 100644
index 0000000..006c73c
--- /dev/null
+++ b/0005-scsi-Introduce-scsi_sense_buf_to_errno.patch
@@ -0,0 +1,64 @@
+From: Fam Zheng <famz@redhat.com>
+Date: Mon, 21 Aug 2017 22:10:07 +0800
+Subject: [PATCH] scsi: Introduce scsi_sense_buf_to_errno
+
+This recognizes the "fixed" and "descriptor" format sense data, extracts
+the sense key/asc/ascq fields then converts them to an errno.
+
+Signed-off-by: Fam Zheng <famz@redhat.com>
+Message-Id: <20170821141008.19383-4-famz@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ include/scsi/scsi.h |  1 +
+ util/scsi.c         | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
+index f894ace4bf..fe330385d8 100644
+--- a/include/scsi/scsi.h
++++ b/include/scsi/scsi.h
+@@ -15,5 +15,6 @@
+ #define QEMU_SCSI_H
+ 
+ int scsi_sense_to_errno(int key, int asc, int ascq);
++int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
+ 
+ #endif
+diff --git a/util/scsi.c b/util/scsi.c
+index 472eb5bea5..472293d59b 100644
+--- a/util/scsi.c
++++ b/util/scsi.c
+@@ -58,3 +58,33 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
+         return EIO;
+     }
+ }
++
++int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
++{
++    int key, asc, ascq;
++    if (sense_size < 1) {
++        return EIO;
++    }
++    switch (sense[0]) {
++    case 0x70: /* Fixed format sense data. */
++        if (sense_size < 14) {
++            return EIO;
++        }
++        key = sense[2] & 0xF;
++        asc = sense[12];
++        ascq = sense[13];
++        break;
++    case 0x72: /* Descriptor format sense data. */
++        if (sense_size < 4) {
++            return EIO;
++        }
++        key = sense[1] & 0xF;
++        asc = sense[2];
++        ascq = sense[3];
++        break;
++    default:
++        return EIO;
++        break;
++    }
++    return scsi_sense_to_errno(key, asc, ascq);
++}
diff --git a/0006-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch b/0006-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
new file mode 100644
index 0000000..eed33b7
--- /dev/null
+++ b/0006-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
@@ -0,0 +1,88 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 09:31:36 +0200
+Subject: [PATCH] scsi: rename scsi_build_sense to scsi_convert_sense
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After introducing the scsi/ subdirectory, there will be a scsi_build_sense
+function that is the same as scsi_req_build_sense but without needing
+a SCSIRequest.  The existing scsi_build_sense function gets in the way,
+remove it.
+
+Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/scsi-bus.c     | 10 +++++-----
+ hw/scsi/scsi-disk.c    |  4 ++--
+ include/hw/scsi/scsi.h |  4 ++--
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
+index ade31c11f5..fac360e20f 100644
+--- a/hw/scsi/scsi-bus.c
++++ b/hw/scsi/scsi-bus.c
+@@ -790,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
+         return 0;
+     }
+ 
+-    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
++    ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
+ 
+     /*
+      * FIXME: clearing unit attention conditions upon autosense should be done
+@@ -811,7 +811,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
+ 
+ int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
+ {
+-    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
++    return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
+ }
+ 
+ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
+@@ -1531,12 +1531,12 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+ };
+ 
+ /*
+- * scsi_build_sense
++ * scsi_convert_sense
+  *
+  * Convert between fixed and descriptor sense buffers
+  */
+-int scsi_build_sense(uint8_t *in_buf, int in_len,
+-                     uint8_t *buf, int len, bool fixed)
++int scsi_convert_sense(uint8_t *in_buf, int in_len,
++                       uint8_t *buf, int len, bool fixed)
+ {
+     bool fixed_in;
+     SCSISense sense;
+diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
+index 5f1e5e8070..0a1f4ef0c7 100644
+--- a/hw/scsi/scsi-disk.c
++++ b/hw/scsi/scsi-disk.c
+@@ -1978,8 +1978,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
+         break;
+     case REQUEST_SENSE:
+         /* Just return "NO SENSE".  */
+-        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
+-                                  (req->cmd.buf[1] & 1) == 0);
++        buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
++                                    (req->cmd.buf[1] & 1) == 0);
+         if (buflen < 0) {
+             goto illegal_request;
+         }
+diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
+index 6b85786dbf..6ef67fb504 100644
+--- a/include/hw/scsi/scsi.h
++++ b/include/hw/scsi/scsi.h
+@@ -244,8 +244,8 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+ uint32_t scsi_data_cdb_xfer(uint8_t *buf);
+ uint32_t scsi_cdb_xfer(uint8_t *buf);
+ int scsi_cdb_length(uint8_t *buf);
+-int scsi_build_sense(uint8_t *in_buf, int in_len,
+-                     uint8_t *buf, int len, bool fixed);
++int scsi_convert_sense(uint8_t *in_buf, int in_len,
++                       uint8_t *buf, int len, bool fixed);
+ 
+ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                             uint32_t tag, uint32_t lun, void *hba_private);
diff --git a/0007-scsi-move-non-emulation-specific-code-to-scsi.patch b/0007-scsi-move-non-emulation-specific-code-to-scsi.patch
new file mode 100644
index 0000000..92650e7
--- /dev/null
+++ b/0007-scsi-move-non-emulation-specific-code-to-scsi.patch
@@ -0,0 +1,1430 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 07:08:27 +0200
+Subject: [PATCH] scsi: move non-emulation specific code to scsi/
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+util/scsi.c includes some SCSI code that is shared by block/iscsi.c and
+hw/scsi, but the introduction of the persistent reservation helper
+will add many more instances of this.  There is also include/block/scsi.h,
+which actually is not part of the core block layer.
+
+The persistent reservation manager will also need a home.  A scsi/
+directory provides one for both the aforementioned shared code and
+the PR manager code.
+
+Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ MAINTAINERS            |   7 +
+ Makefile.objs          |   2 +-
+ block/iscsi.c          |   6 +-
+ hw/scsi/scsi-bus.c     | 397 ---------------------------------------
+ hw/scsi/scsi-generic.c |   8 -
+ include/block/scsi.h   |   2 -
+ include/hw/scsi/scsi.h |  94 +---------
+ include/scsi/scsi.h    |  20 --
+ include/scsi/utils.h   | 119 ++++++++++++
+ scsi/Makefile.objs     |   1 +
+ scsi/utils.c           | 492 +++++++++++++++++++++++++++++++++++++++++++++++++
+ util/Makefile.objs     |   1 -
+ util/scsi.c            |  90 ---------
+ 13 files changed, 626 insertions(+), 613 deletions(-)
+ delete mode 100644 include/scsi/scsi.h
+ create mode 100644 include/scsi/utils.h
+ create mode 100644 scsi/Makefile.objs
+ create mode 100644 scsi/utils.c
+ delete mode 100644 util/scsi.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 2a4e5036ae..074da8c976 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1215,6 +1215,13 @@ F: migration/block*
+ F: include/block/aio.h
+ T: git git://github.com/stefanha/qemu.git block
+ 
++Block SCSI subsystem
++M: Paolo Bonzini <pbonzini@redhat.com>
++L: qemu-block@nongnu.org
++S: Supported
++F: include/scsi/*
++F: scsi/*
++
+ Block Jobs
+ M: Jeff Cody <jcody@redhat.com>
+ L: qemu-block@nongnu.org
+diff --git a/Makefile.objs b/Makefile.objs
+index 24a4ea08b8..f68aa3b60d 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -11,7 +11,7 @@ chardev-obj-y = chardev/
+ 
+ block-obj-y += nbd/
+ block-obj-y += block.o blockjob.o
+-block-obj-y += block/
++block-obj-y += block/ scsi/
+ block-obj-y += qemu-io-cmds.o
+ block-obj-$(CONFIG_REPLICATION) += replication.o
+ 
+diff --git a/block/iscsi.c b/block/iscsi.c
+index 4bed63cd6d..40adc3c493 100644
+--- a/block/iscsi.c
++++ b/block/iscsi.c
+@@ -40,10 +40,14 @@
+ #include "qmp-commands.h"
+ #include "qapi/qmp/qstring.h"
+ #include "crypto/secret.h"
+-#include "scsi/scsi.h"
++#include "scsi/utils.h"
+ 
++/* Conflict between scsi/utils.h and libiscsi! :( */
++#define SCSI_XFER_NONE ISCSI_XFER_NONE
+ #include <iscsi/iscsi.h>
+ #include <iscsi/scsi-lowlevel.h>
++#undef SCSI_XFER_NONE
++QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE);
+ 
+ #ifdef __linux__
+ #include <scsi/sg.h>
+diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
+index fac360e20f..42920d5422 100644
+--- a/hw/scsi/scsi-bus.c
++++ b/hw/scsi/scsi-bus.c
+@@ -956,36 +956,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
+     return xfer * unit;
+ }
+ 
+-uint32_t scsi_data_cdb_xfer(uint8_t *buf)
+-{
+-    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
+-        return 256;
+-    } else {
+-        return scsi_cdb_xfer(buf);
+-    }
+-}
+-
+-uint32_t scsi_cdb_xfer(uint8_t *buf)
+-{
+-    switch (buf[0] >> 5) {
+-    case 0:
+-        return buf[4];
+-        break;
+-    case 1:
+-    case 2:
+-        return lduw_be_p(&buf[7]);
+-        break;
+-    case 4:
+-        return ldl_be_p(&buf[10]) & 0xffffffffULL;
+-        break;
+-    case 5:
+-        return ldl_be_p(&buf[6]) & 0xffffffffULL;
+-        break;
+-    default:
+-        return -1;
+-    }
+-}
+-
+ static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+ {
+     cmd->xfer = scsi_cdb_xfer(buf);
+@@ -1298,53 +1268,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
+     }
+ }
+ 
+-static uint64_t scsi_cmd_lba(SCSICommand *cmd)
+-{
+-    uint8_t *buf = cmd->buf;
+-    uint64_t lba;
+-
+-    switch (buf[0] >> 5) {
+-    case 0:
+-        lba = ldl_be_p(&buf[0]) & 0x1fffff;
+-        break;
+-    case 1:
+-    case 2:
+-    case 5:
+-        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
+-        break;
+-    case 4:
+-        lba = ldq_be_p(&buf[2]);
+-        break;
+-    default:
+-        lba = -1;
+-
+-    }
+-    return lba;
+-}
+-
+-int scsi_cdb_length(uint8_t *buf) {
+-    int cdb_len;
+-
+-    switch (buf[0] >> 5) {
+-    case 0:
+-        cdb_len = 6;
+-        break;
+-    case 1:
+-    case 2:
+-        cdb_len = 10;
+-        break;
+-    case 4:
+-        cdb_len = 16;
+-        break;
+-    case 5:
+-        cdb_len = 12;
+-        break;
+-    default:
+-        cdb_len = -1;
+-    }
+-    return cdb_len;
+-}
+-
+ int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
+ {
+     int rc;
+@@ -1391,326 +1314,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
+     }
+ }
+ 
+-/*
+- * Predefined sense codes
+- */
+-
+-/* No sense data available */
+-const struct SCSISense sense_code_NO_SENSE = {
+-    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
+-};
+-
+-/* LUN not ready, Manual intervention required */
+-const struct SCSISense sense_code_LUN_NOT_READY = {
+-    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
+-};
+-
+-/* LUN not ready, Medium not present */
+-const struct SCSISense sense_code_NO_MEDIUM = {
+-    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
+-};
+-
+-/* LUN not ready, medium removal prevented */
+-const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+-    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
+-};
+-
+-/* Hardware error, internal target failure */
+-const struct SCSISense sense_code_TARGET_FAILURE = {
+-    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
+-};
+-
+-/* Illegal request, invalid command operation code */
+-const struct SCSISense sense_code_INVALID_OPCODE = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
+-};
+-
+-/* Illegal request, LBA out of range */
+-const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
+-};
+-
+-/* Illegal request, Invalid field in CDB */
+-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
+-};
+-
+-/* Illegal request, Saving parameters not supported */
+-const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
+-};
+-
+-/* Illegal request, Incompatible medium installed */
+-const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
+-};
+-
+-/* Illegal request, medium removal prevented */
+-const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
+-};
+-
+-/* Illegal request, Invalid Transfer Tag */
+-const struct SCSISense sense_code_INVALID_TAG = {
+-    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
+-};
+-
+-/* Command aborted, I/O process terminated */
+-const struct SCSISense sense_code_IO_ERROR = {
+-    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
+-};
+-
+-/* Command aborted, I_T Nexus loss occurred */
+-const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
+-    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
+-};
+-
+-/* Command aborted, Logical Unit failure */
+-const struct SCSISense sense_code_LUN_FAILURE = {
+-    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
+-};
+-
+-/* Command aborted, Overlapped Commands Attempted */
+-const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
+-    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
+-};
+-
+-/* Unit attention, Capacity data has changed */
+-const struct SCSISense sense_code_CAPACITY_CHANGED = {
+-    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
+-};
+-
+-/* Unit attention, Power on, reset or bus device reset occurred */
+-const struct SCSISense sense_code_RESET = {
+-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
+-};
+-
+-/* Unit attention, No medium */
+-const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+-    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
+-};
+-
+-/* Unit attention, Medium may have changed */
+-const struct SCSISense sense_code_MEDIUM_CHANGED = {
+-    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
+-};
+-
+-/* Unit attention, Reported LUNs data has changed */
+-const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
+-    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
+-};
+-
+-/* Unit attention, Device internal reset */
+-const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
+-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
+-};
+-
+-/* Data Protection, Write Protected */
+-const struct SCSISense sense_code_WRITE_PROTECTED = {
+-    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
+-};
+-
+-/* Data Protection, Space Allocation Failed Write Protect */
+-const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+-    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+-};
+-
+-/*
+- * scsi_convert_sense
+- *
+- * Convert between fixed and descriptor sense buffers
+- */
+-int scsi_convert_sense(uint8_t *in_buf, int in_len,
+-                       uint8_t *buf, int len, bool fixed)
+-{
+-    bool fixed_in;
+-    SCSISense sense;
+-    if (!fixed && len < 8) {
+-        return 0;
+-    }
+-
+-    if (in_len == 0) {
+-        sense.key = NO_SENSE;
+-        sense.asc = 0;
+-        sense.ascq = 0;
+-    } else {
+-        fixed_in = (in_buf[0] & 2) == 0;
+-
+-        if (fixed == fixed_in) {
+-            memcpy(buf, in_buf, MIN(len, in_len));
+-            return MIN(len, in_len);
+-        }
+-
+-        if (fixed_in) {
+-            sense.key = in_buf[2];
+-            sense.asc = in_buf[12];
+-            sense.ascq = in_buf[13];
+-        } else {
+-            sense.key = in_buf[1];
+-            sense.asc = in_buf[2];
+-            sense.ascq = in_buf[3];
+-        }
+-    }
+-
+-    memset(buf, 0, len);
+-    if (fixed) {
+-        /* Return fixed format sense buffer */
+-        buf[0] = 0x70;
+-        buf[2] = sense.key;
+-        buf[7] = 10;
+-        buf[12] = sense.asc;
+-        buf[13] = sense.ascq;
+-        return MIN(len, SCSI_SENSE_LEN);
+-    } else {
+-        /* Return descriptor format sense buffer */
+-        buf[0] = 0x72;
+-        buf[1] = sense.key;
+-        buf[2] = sense.asc;
+-        buf[3] = sense.ascq;
+-        return 8;
+-    }
+-}
+-
+-const char *scsi_command_name(uint8_t cmd)
+-{
+-    static const char *names[] = {
+-        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
+-        [ REWIND                   ] = "REWIND",
+-        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
+-        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
+-        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
+-        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
+-        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
+-        [ READ_6                   ] = "READ_6",
+-        [ WRITE_6                  ] = "WRITE_6",
+-        [ SET_CAPACITY             ] = "SET_CAPACITY",
+-        [ READ_REVERSE             ] = "READ_REVERSE",
+-        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
+-        [ SPACE                    ] = "SPACE",
+-        [ INQUIRY                  ] = "INQUIRY",
+-        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
+-        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+-        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
+-        [ MODE_SELECT              ] = "MODE_SELECT",
+-        [ RESERVE                  ] = "RESERVE",
+-        [ RELEASE                  ] = "RELEASE",
+-        [ COPY                     ] = "COPY",
+-        [ ERASE                    ] = "ERASE",
+-        [ MODE_SENSE               ] = "MODE_SENSE",
+-        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
+-        /* LOAD_UNLOAD and START_STOP use the same operation code */
+-        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
+-        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
+-        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
+-        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
+-        [ READ_10                  ] = "READ_10",
+-        [ WRITE_10                 ] = "WRITE_10",
+-        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
+-        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
+-        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
+-        [ VERIFY_10                ] = "VERIFY_10",
+-        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
+-        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
+-        [ SEARCH_LOW               ] = "SEARCH_LOW",
+-        [ SET_LIMITS               ] = "SET_LIMITS",
+-        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
+-        /* READ_POSITION and PRE_FETCH use the same operation code */
+-        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
+-        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
+-        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
+-        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
+-        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
+-        [ COMPARE                  ] = "COMPARE",
+-        [ COPY_VERIFY              ] = "COPY_VERIFY",
+-        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
+-        [ READ_BUFFER              ] = "READ_BUFFER",
+-        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
+-        [ READ_LONG_10             ] = "READ_LONG_10",
+-        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
+-        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
+-        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
+-        [ UNMAP                    ] = "UNMAP",
+-        [ READ_TOC                 ] = "READ_TOC",
+-        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+-        [ SANITIZE                 ] = "SANITIZE",
+-        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
+-        [ LOG_SELECT               ] = "LOG_SELECT",
+-        [ LOG_SENSE                ] = "LOG_SENSE",
+-        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
+-        [ RESERVE_10               ] = "RESERVE_10",
+-        [ RELEASE_10               ] = "RELEASE_10",
+-        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
+-        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
+-        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+-        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
+-        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
+-        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
+-        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
+-        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
+-        [ READ_16                  ] = "READ_16",
+-        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
+-        [ WRITE_16                 ] = "WRITE_16",
+-        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+-        [ VERIFY_16                ] = "VERIFY_16",
+-        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
+-        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
+-        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
+-        [ LOCATE_16                ] = "LOCATE_16",
+-        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
+-        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
+-        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
+-        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
+-        [ REPORT_LUNS              ] = "REPORT_LUNS",
+-        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
+-        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+-        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
+-        [ READ_12                  ] = "READ_12",
+-        [ WRITE_12                 ] = "WRITE_12",
+-        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
+-        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
+-        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
+-        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+-        [ VERIFY_12                ] = "VERIFY_12",
+-        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
+-        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
+-        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
+-        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
+-        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
+-        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
+-        [ READ_CD                  ] = "READ_CD",
+-        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
+-        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
+-        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
+-        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
+-        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
+-        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
+-        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
+-        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
+-        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
+-        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
+-        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
+-    };
+-
+-    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
+-        return "*UNKNOWN*";
+-    return names[cmd];
+-}
+-
+ SCSIRequest *scsi_req_ref(SCSIRequest *req)
+ {
+     assert(req->refcount > 0);
+diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
+index 7e1cbab77e..7a8f500934 100644
+--- a/hw/scsi/scsi-generic.c
++++ b/hw/scsi/scsi-generic.c
+@@ -36,14 +36,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+ #include <scsi/sg.h>
+ #include "block/scsi.h"
+ 
+-#define SG_ERR_DRIVER_TIMEOUT  0x06
+-#define SG_ERR_DRIVER_SENSE    0x08
+-
+-#define SG_ERR_DID_OK          0x00
+-#define SG_ERR_DID_NO_CONNECT  0x01
+-#define SG_ERR_DID_BUS_BUSY    0x02
+-#define SG_ERR_DID_TIME_OUT    0x03
+-
+ #ifndef MAX_UINT
+ #define MAX_UINT ((unsigned int)-1)
+ #endif
+diff --git a/include/block/scsi.h b/include/block/scsi.h
+index cdf0a58a07..a141dd71f8 100644
+--- a/include/block/scsi.h
++++ b/include/block/scsi.h
+@@ -150,8 +150,6 @@
+ #define READ_CD               0xbe
+ #define SEND_DVD_STRUCTURE    0xbf
+ 
+-const char *scsi_command_name(uint8_t cmd);
+-
+ /*
+  * SERVICE ACTION IN subcodes
+  */
+diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
+index 6ef67fb504..23a8ee6a7d 100644
+--- a/include/hw/scsi/scsi.h
++++ b/include/hw/scsi/scsi.h
+@@ -4,45 +4,20 @@
+ #include "hw/qdev.h"
+ #include "hw/block/block.h"
+ #include "sysemu/sysemu.h"
++#include "scsi/utils.h"
+ #include "qemu/notify.h"
+ 
+ #define MAX_SCSI_DEVS	255
+ 
+-#define SCSI_CMD_BUF_SIZE      16
+-#define SCSI_SENSE_LEN         18
+-#define SCSI_SENSE_LEN_SCANNER 32
+-#define SCSI_INQUIRY_LEN       36
+-
+ typedef struct SCSIBus SCSIBus;
+ typedef struct SCSIBusInfo SCSIBusInfo;
+-typedef struct SCSICommand SCSICommand;
+ typedef struct SCSIDevice SCSIDevice;
+ typedef struct SCSIRequest SCSIRequest;
+ typedef struct SCSIReqOps SCSIReqOps;
+ 
+-enum SCSIXferMode {
+-    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
+-    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
+-    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
+-};
+-
+-typedef struct SCSISense {
+-    uint8_t key;
+-    uint8_t asc;
+-    uint8_t ascq;
+-} SCSISense;
+-
+ #define SCSI_SENSE_BUF_SIZE_OLD 96
+ #define SCSI_SENSE_BUF_SIZE 252
+ 
+-struct SCSICommand {
+-    uint8_t buf[SCSI_CMD_BUF_SIZE];
+-    int len;
+-    size_t xfer;
+-    uint64_t lba;
+-    enum SCSIXferMode mode;
+-};
+-
+ struct SCSIRequest {
+     SCSIBus           *bus;
+     SCSIDevice        *dev;
+@@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
+ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
+ void scsi_legacy_handle_cmdline(void);
+ 
+-/*
+- * Predefined sense codes
+- */
+-
+-/* No sense data available */
+-extern const struct SCSISense sense_code_NO_SENSE;
+-/* LUN not ready, Manual intervention required */
+-extern const struct SCSISense sense_code_LUN_NOT_READY;
+-/* LUN not ready, Medium not present */
+-extern const struct SCSISense sense_code_NO_MEDIUM;
+-/* LUN not ready, medium removal prevented */
+-extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
+-/* Hardware error, internal target failure */
+-extern const struct SCSISense sense_code_TARGET_FAILURE;
+-/* Illegal request, invalid command operation code */
+-extern const struct SCSISense sense_code_INVALID_OPCODE;
+-/* Illegal request, LBA out of range */
+-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 */
+-extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
+-/* Illegal request, Incompatible format */
+-extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+-/* Illegal request, medium removal prevented */
+-extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
+-/* Illegal request, Invalid Transfer Tag */
+-extern const struct SCSISense sense_code_INVALID_TAG;
+-/* Command aborted, I/O process terminated */
+-extern const struct SCSISense sense_code_IO_ERROR;
+-/* Command aborted, I_T Nexus loss occurred */
+-extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+-/* Command aborted, Logical Unit failure */
+-extern const struct SCSISense sense_code_LUN_FAILURE;
+-/* Command aborted, Overlapped Commands Attempted */
+-extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
+-/* LUN not ready, Capacity data has changed */
+-extern const struct SCSISense sense_code_CAPACITY_CHANGED;
+-/* LUN not ready, Medium not present */
+-extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
+-/* Unit attention, Power on, reset or bus device reset occurred */
+-extern const struct SCSISense sense_code_RESET;
+-/* Unit attention, Medium may have changed*/
+-extern const struct SCSISense sense_code_MEDIUM_CHANGED;
+-/* Unit attention, Reported LUNs data has changed */
+-extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
+-/* Unit attention, Device internal reset */
+-extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
+-/* Data Protection, Write Protected */
+-extern const struct SCSISense sense_code_WRITE_PROTECTED;
+-/* Data Protection, Space Allocation Failed Write Protect */
+-extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+-
+-#define SENSE_CODE(x) sense_code_ ## x
+-
+-uint32_t scsi_data_cdb_xfer(uint8_t *buf);
+-uint32_t scsi_cdb_xfer(uint8_t *buf);
+-int scsi_cdb_length(uint8_t *buf);
+-int scsi_convert_sense(uint8_t *in_buf, int in_len,
+-                       uint8_t *buf, int len, bool fixed);
+-
+ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                             uint32_t tag, uint32_t lun, void *hba_private);
+ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
+deleted file mode 100644
+index fe330385d8..0000000000
+--- a/include/scsi/scsi.h
++++ /dev/null
+@@ -1,20 +0,0 @@
+-/*
+- *  SCSI helpers
+- *
+- *  Copyright 2017 Red Hat, Inc.
+- *
+- *  Authors:
+- *   Fam Zheng <famz@redhat.com>
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the Free
+- * Software Foundation; either version 2 of the License, or (at your option)
+- * any later version.
+- */
+-#ifndef QEMU_SCSI_H
+-#define QEMU_SCSI_H
+-
+-int scsi_sense_to_errno(int key, int asc, int ascq);
+-int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
+-
+-#endif
+diff --git a/include/scsi/utils.h b/include/scsi/utils.h
+new file mode 100644
+index 0000000000..90bf4dce6e
+--- /dev/null
++++ b/include/scsi/utils.h
+@@ -0,0 +1,119 @@
++#ifndef SCSI_UTILS_H
++#define SCSI_UTILS_H 1
++
++#ifdef CONFIG_LINUX
++#include <scsi/sg.h>
++#endif
++
++#define SCSI_CMD_BUF_SIZE      16
++#define SCSI_SENSE_LEN         18
++#define SCSI_SENSE_LEN_SCANNER 32
++#define SCSI_INQUIRY_LEN       36
++
++enum SCSIXferMode {
++    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
++    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
++    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
++};
++
++typedef struct SCSICommand {
++    uint8_t buf[SCSI_CMD_BUF_SIZE];
++    int len;
++    size_t xfer;
++    uint64_t lba;
++    enum SCSIXferMode mode;
++} SCSICommand;
++
++typedef struct SCSISense {
++    uint8_t key;
++    uint8_t asc;
++    uint8_t ascq;
++} SCSISense;
++
++/*
++ * Predefined sense codes
++ */
++
++/* No sense data available */
++extern const struct SCSISense sense_code_NO_SENSE;
++/* LUN not ready, Manual intervention required */
++extern const struct SCSISense sense_code_LUN_NOT_READY;
++/* LUN not ready, Medium not present */
++extern const struct SCSISense sense_code_NO_MEDIUM;
++/* LUN not ready, medium removal prevented */
++extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
++/* Hardware error, internal target failure */
++extern const struct SCSISense sense_code_TARGET_FAILURE;
++/* Illegal request, invalid command operation code */
++extern const struct SCSISense sense_code_INVALID_OPCODE;
++/* Illegal request, LBA out of range */
++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 */
++extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
++/* Illegal request, Incompatible format */
++extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
++/* Illegal request, medium removal prevented */
++extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
++/* Illegal request, Invalid Transfer Tag */
++extern const struct SCSISense sense_code_INVALID_TAG;
++/* Command aborted, I/O process terminated */
++extern const struct SCSISense sense_code_IO_ERROR;
++/* Command aborted, I_T Nexus loss occurred */
++extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
++/* Command aborted, Logical Unit failure */
++extern const struct SCSISense sense_code_LUN_FAILURE;
++/* Command aborted, Overlapped Commands Attempted */
++extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
++/* LUN not ready, Capacity data has changed */
++extern const struct SCSISense sense_code_CAPACITY_CHANGED;
++/* LUN not ready, Medium not present */
++extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
++/* Unit attention, Power on, reset or bus device reset occurred */
++extern const struct SCSISense sense_code_RESET;
++/* Unit attention, Medium may have changed*/
++extern const struct SCSISense sense_code_MEDIUM_CHANGED;
++/* Unit attention, Reported LUNs data has changed */
++extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
++/* Unit attention, Device internal reset */
++extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
++/* Data Protection, Write Protected */
++extern const struct SCSISense sense_code_WRITE_PROTECTED;
++/* Data Protection, Space Allocation Failed Write Protect */
++extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
++
++#define SENSE_CODE(x) sense_code_ ## x
++
++int scsi_sense_to_errno(int key, int asc, int ascq);
++int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
++
++int scsi_convert_sense(uint8_t *in_buf, int in_len,
++                       uint8_t *buf, int len, bool fixed);
++const char *scsi_command_name(uint8_t cmd);
++
++uint64_t scsi_cmd_lba(SCSICommand *cmd);
++uint32_t scsi_data_cdb_xfer(uint8_t *buf);
++uint32_t scsi_cdb_xfer(uint8_t *buf);
++int scsi_cdb_length(uint8_t *buf);
++
++/* Linux SG_IO interface.  */
++#ifdef CONFIG_LINUX
++#define SG_ERR_DRIVER_TIMEOUT  0x06
++#define SG_ERR_DRIVER_SENSE    0x08
++
++#define SG_ERR_DID_OK          0x00
++#define SG_ERR_DID_NO_CONNECT  0x01
++#define SG_ERR_DID_BUS_BUSY    0x02
++#define SG_ERR_DID_TIME_OUT    0x03
++
++#define SG_ERR_DRIVER_SENSE    0x08
++#endif
++
++#endif
+diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
+new file mode 100644
+index 0000000000..31b82a5a36
+--- /dev/null
++++ b/scsi/Makefile.objs
+@@ -0,0 +1 @@
++block-obj-y += utils.o
+diff --git a/scsi/utils.c b/scsi/utils.c
+new file mode 100644
+index 0000000000..2327e06da0
+--- /dev/null
++++ b/scsi/utils.c
+@@ -0,0 +1,492 @@
++/*
++ *  SCSI helpers
++ *
++ *  Copyright 2017 Red Hat, Inc.
++ *
++ *  Authors:
++ *   Fam Zheng <famz@redhat.com>
++ *   Paolo Bonzini <pbonzini@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ */
++
++#include "qemu/osdep.h"
++#include "block/scsi.h"
++#include "scsi/utils.h"
++#include "qemu/bswap.h"
++
++uint32_t scsi_data_cdb_xfer(uint8_t *buf)
++{
++    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
++        return 256;
++    } else {
++        return scsi_cdb_xfer(buf);
++    }
++}
++
++uint32_t scsi_cdb_xfer(uint8_t *buf)
++{
++    switch (buf[0] >> 5) {
++    case 0:
++        return buf[4];
++        break;
++    case 1:
++    case 2:
++        return lduw_be_p(&buf[7]);
++        break;
++    case 4:
++        return ldl_be_p(&buf[10]) & 0xffffffffULL;
++        break;
++    case 5:
++        return ldl_be_p(&buf[6]) & 0xffffffffULL;
++        break;
++    default:
++        return -1;
++    }
++}
++
++uint64_t scsi_cmd_lba(SCSICommand *cmd)
++{
++    uint8_t *buf = cmd->buf;
++    uint64_t lba;
++
++    switch (buf[0] >> 5) {
++    case 0:
++        lba = ldl_be_p(&buf[0]) & 0x1fffff;
++        break;
++    case 1:
++    case 2:
++    case 5:
++        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
++        break;
++    case 4:
++        lba = ldq_be_p(&buf[2]);
++        break;
++    default:
++        lba = -1;
++
++    }
++    return lba;
++}
++
++int scsi_cdb_length(uint8_t *buf)
++{
++    int cdb_len;
++
++    switch (buf[0] >> 5) {
++    case 0:
++        cdb_len = 6;
++        break;
++    case 1:
++    case 2:
++        cdb_len = 10;
++        break;
++    case 4:
++        cdb_len = 16;
++        break;
++    case 5:
++        cdb_len = 12;
++        break;
++    default:
++        cdb_len = -1;
++    }
++    return cdb_len;
++}
++
++/*
++ * Predefined sense codes
++ */
++
++/* No sense data available */
++const struct SCSISense sense_code_NO_SENSE = {
++    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
++};
++
++/* LUN not ready, Manual intervention required */
++const struct SCSISense sense_code_LUN_NOT_READY = {
++    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
++};
++
++/* LUN not ready, Medium not present */
++const struct SCSISense sense_code_NO_MEDIUM = {
++    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
++};
++
++/* LUN not ready, medium removal prevented */
++const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
++    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
++};
++
++/* Hardware error, internal target failure */
++const struct SCSISense sense_code_TARGET_FAILURE = {
++    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
++};
++
++/* Illegal request, invalid command operation code */
++const struct SCSISense sense_code_INVALID_OPCODE = {
++    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
++};
++
++/* Illegal request, LBA out of range */
++const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
++    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
++};
++
++/* Illegal request, Invalid field in CDB */
++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
++};
++
++/* Illegal request, Saving parameters not supported */
++const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
++    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
++};
++
++/* Illegal request, Incompatible medium installed */
++const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
++    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
++};
++
++/* Illegal request, medium removal prevented */
++const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
++    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
++};
++
++/* Illegal request, Invalid Transfer Tag */
++const struct SCSISense sense_code_INVALID_TAG = {
++    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
++};
++
++/* Command aborted, I/O process terminated */
++const struct SCSISense sense_code_IO_ERROR = {
++    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
++};
++
++/* Command aborted, I_T Nexus loss occurred */
++const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
++    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
++};
++
++/* Command aborted, Logical Unit failure */
++const struct SCSISense sense_code_LUN_FAILURE = {
++    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
++};
++
++/* Command aborted, Overlapped Commands Attempted */
++const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
++    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
++};
++
++/* Unit attention, Capacity data has changed */
++const struct SCSISense sense_code_CAPACITY_CHANGED = {
++    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
++};
++
++/* Unit attention, Power on, reset or bus device reset occurred */
++const struct SCSISense sense_code_RESET = {
++    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
++};
++
++/* Unit attention, No medium */
++const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
++    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
++};
++
++/* Unit attention, Medium may have changed */
++const struct SCSISense sense_code_MEDIUM_CHANGED = {
++    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
++};
++
++/* Unit attention, Reported LUNs data has changed */
++const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
++    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
++};
++
++/* Unit attention, Device internal reset */
++const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
++    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
++};
++
++/* Data Protection, Write Protected */
++const struct SCSISense sense_code_WRITE_PROTECTED = {
++    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
++};
++
++/* Data Protection, Space Allocation Failed Write Protect */
++const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
++    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
++};
++
++/*
++ * scsi_convert_sense
++ *
++ * Convert between fixed and descriptor sense buffers
++ */
++int scsi_convert_sense(uint8_t *in_buf, int in_len,
++                       uint8_t *buf, int len, bool fixed)
++{
++    bool fixed_in;
++    SCSISense sense;
++    if (!fixed && len < 8) {
++        return 0;
++    }
++
++    if (in_len == 0) {
++        sense.key = NO_SENSE;
++        sense.asc = 0;
++        sense.ascq = 0;
++    } else {
++        fixed_in = (in_buf[0] & 2) == 0;
++
++        if (fixed == fixed_in) {
++            memcpy(buf, in_buf, MIN(len, in_len));
++            return MIN(len, in_len);
++        }
++
++        if (fixed_in) {
++            sense.key = in_buf[2];
++            sense.asc = in_buf[12];
++            sense.ascq = in_buf[13];
++        } else {
++            sense.key = in_buf[1];
++            sense.asc = in_buf[2];
++            sense.ascq = in_buf[3];
++        }
++    }
++
++    memset(buf, 0, len);
++    if (fixed) {
++        /* Return fixed format sense buffer */
++        buf[0] = 0x70;
++        buf[2] = sense.key;
++        buf[7] = 10;
++        buf[12] = sense.asc;
++        buf[13] = sense.ascq;
++        return MIN(len, SCSI_SENSE_LEN);
++    } else {
++        /* Return descriptor format sense buffer */
++        buf[0] = 0x72;
++        buf[1] = sense.key;
++        buf[2] = sense.asc;
++        buf[3] = sense.ascq;
++        return 8;
++    }
++}
++
++int scsi_sense_to_errno(int key, int asc, int ascq)
++{
++    switch (key) {
++    case 0x00: /* NO SENSE */
++    case 0x01: /* RECOVERED ERROR */
++    case 0x06: /* UNIT ATTENTION */
++        /* These sense keys are not errors */
++        return 0;
++    case 0x0b: /* COMMAND ABORTED */
++        return ECANCELED;
++    case 0x02: /* NOT READY */
++    case 0x05: /* ILLEGAL REQUEST */
++    case 0x07: /* DATA PROTECTION */
++        /* Parse ASCQ */
++        break;
++    default:
++        return EIO;
++    }
++    switch ((asc << 8) | ascq) {
++    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
++    case 0x2000: /* INVALID OPERATION CODE */
++    case 0x2400: /* INVALID FIELD IN CDB */
++    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
++        return EINVAL;
++    case 0x2100: /* LBA OUT OF RANGE */
++    case 0x2707: /* SPACE ALLOC FAILED */
++        return ENOSPC;
++    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
++        return ENOTSUP;
++    case 0x3a00: /* MEDIUM NOT PRESENT */
++    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
++    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
++        return ENOMEDIUM;
++    case 0x2700: /* WRITE PROTECTED */
++        return EACCES;
++    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
++        return EAGAIN;
++    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
++        return ENOTCONN;
++    default:
++        return EIO;
++    }
++}
++
++int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
++{
++    int key, asc, ascq;
++    if (sense_size < 1) {
++        return EIO;
++    }
++    switch (sense[0]) {
++    case 0x70: /* Fixed format sense data. */
++        if (sense_size < 14) {
++            return EIO;
++        }
++        key = sense[2] & 0xF;
++        asc = sense[12];
++        ascq = sense[13];
++        break;
++    case 0x72: /* Descriptor format sense data. */
++        if (sense_size < 4) {
++            return EIO;
++        }
++        key = sense[1] & 0xF;
++        asc = sense[2];
++        ascq = sense[3];
++        break;
++    default:
++        return EIO;
++        break;
++    }
++    return scsi_sense_to_errno(key, asc, ascq);
++}
++
++const char *scsi_command_name(uint8_t cmd)
++{
++    static const char *names[] = {
++        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
++        [ REWIND                   ] = "REWIND",
++        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
++        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
++        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
++        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
++        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
++        [ READ_6                   ] = "READ_6",
++        [ WRITE_6                  ] = "WRITE_6",
++        [ SET_CAPACITY             ] = "SET_CAPACITY",
++        [ READ_REVERSE             ] = "READ_REVERSE",
++        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
++        [ SPACE                    ] = "SPACE",
++        [ INQUIRY                  ] = "INQUIRY",
++        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
++        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
++        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
++        [ MODE_SELECT              ] = "MODE_SELECT",
++        [ RESERVE                  ] = "RESERVE",
++        [ RELEASE                  ] = "RELEASE",
++        [ COPY                     ] = "COPY",
++        [ ERASE                    ] = "ERASE",
++        [ MODE_SENSE               ] = "MODE_SENSE",
++        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
++        /* LOAD_UNLOAD and START_STOP use the same operation code */
++        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
++        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
++        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
++        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
++        [ READ_10                  ] = "READ_10",
++        [ WRITE_10                 ] = "WRITE_10",
++        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
++        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
++        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
++        [ VERIFY_10                ] = "VERIFY_10",
++        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
++        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
++        [ SEARCH_LOW               ] = "SEARCH_LOW",
++        [ SET_LIMITS               ] = "SET_LIMITS",
++        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
++        /* READ_POSITION and PRE_FETCH use the same operation code */
++        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
++        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
++        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
++        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
++        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
++        [ COMPARE                  ] = "COMPARE",
++        [ COPY_VERIFY              ] = "COPY_VERIFY",
++        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
++        [ READ_BUFFER              ] = "READ_BUFFER",
++        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
++        [ READ_LONG_10             ] = "READ_LONG_10",
++        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
++        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
++        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
++        [ UNMAP                    ] = "UNMAP",
++        [ READ_TOC                 ] = "READ_TOC",
++        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
++        [ SANITIZE                 ] = "SANITIZE",
++        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
++        [ LOG_SELECT               ] = "LOG_SELECT",
++        [ LOG_SENSE                ] = "LOG_SENSE",
++        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
++        [ RESERVE_10               ] = "RESERVE_10",
++        [ RELEASE_10               ] = "RELEASE_10",
++        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
++        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
++        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
++        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
++        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
++        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
++        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
++        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
++        [ READ_16                  ] = "READ_16",
++        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
++        [ WRITE_16                 ] = "WRITE_16",
++        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
++        [ VERIFY_16                ] = "VERIFY_16",
++        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
++        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
++        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
++        [ LOCATE_16                ] = "LOCATE_16",
++        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
++        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
++        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
++        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
++        [ REPORT_LUNS              ] = "REPORT_LUNS",
++        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
++        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
++        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
++        [ READ_12                  ] = "READ_12",
++        [ WRITE_12                 ] = "WRITE_12",
++        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
++        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
++        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
++        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
++        [ VERIFY_12                ] = "VERIFY_12",
++        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
++        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
++        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
++        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
++        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
++        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
++        [ READ_CD                  ] = "READ_CD",
++        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
++        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
++        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
++        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
++        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
++        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
++        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
++        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
++        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
++        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
++        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
++    };
++
++    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) {
++        return "*UNKNOWN*";
++    }
++    return names[cmd];
++}
+diff --git a/util/Makefile.objs b/util/Makefile.objs
+index c9e6c493d3..50a55ecc75 100644
+--- a/util/Makefile.objs
++++ b/util/Makefile.objs
+@@ -45,4 +45,3 @@ util-obj-y += qht.o
+ util-obj-y += range.o
+ util-obj-y += stats64.o
+ util-obj-y += systemd.o
+-util-obj-y += scsi.o
+diff --git a/util/scsi.c b/util/scsi.c
+deleted file mode 100644
+index 472293d59b..0000000000
+--- a/util/scsi.c
++++ /dev/null
+@@ -1,90 +0,0 @@
+-/*
+- *  SCSI helpers
+- *
+- *  Copyright 2017 Red Hat, Inc.
+- *
+- *  Authors:
+- *   Fam Zheng <famz@redhat.com>
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the Free
+- * Software Foundation; either version 2 of the License, or (at your option)
+- * any later version.
+- */
+-
+-#include "qemu/osdep.h"
+-#include "scsi/scsi.h"
+-
+-int scsi_sense_to_errno(int key, int asc, int ascq)
+-{
+-    switch (key) {
+-    case 0x00: /* NO SENSE */
+-    case 0x01: /* RECOVERED ERROR */
+-    case 0x06: /* UNIT ATTENTION */
+-        /* These sense keys are not errors */
+-        return 0;
+-    case 0x0b: /* COMMAND ABORTED */
+-        return ECANCELED;
+-    case 0x02: /* NOT READY */
+-    case 0x05: /* ILLEGAL REQUEST */
+-    case 0x07: /* DATA PROTECTION */
+-        /* Parse ASCQ */
+-        break;
+-    default:
+-        return EIO;
+-    }
+-    switch ((asc << 8) | ascq) {
+-    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
+-    case 0x2000: /* INVALID OPERATION CODE */
+-    case 0x2400: /* INVALID FIELD IN CDB */
+-    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
+-        return EINVAL;
+-    case 0x2100: /* LBA OUT OF RANGE */
+-    case 0x2707: /* SPACE ALLOC FAILED */
+-        return ENOSPC;
+-    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
+-        return ENOTSUP;
+-    case 0x3a00: /* MEDIUM NOT PRESENT */
+-    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
+-    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
+-        return ENOMEDIUM;
+-    case 0x2700: /* WRITE PROTECTED */
+-        return EACCES;
+-    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
+-        return EAGAIN;
+-    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
+-        return ENOTCONN;
+-    default:
+-        return EIO;
+-    }
+-}
+-
+-int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
+-{
+-    int key, asc, ascq;
+-    if (sense_size < 1) {
+-        return EIO;
+-    }
+-    switch (sense[0]) {
+-    case 0x70: /* Fixed format sense data. */
+-        if (sense_size < 14) {
+-            return EIO;
+-        }
+-        key = sense[2] & 0xF;
+-        asc = sense[12];
+-        ascq = sense[13];
+-        break;
+-    case 0x72: /* Descriptor format sense data. */
+-        if (sense_size < 4) {
+-            return EIO;
+-        }
+-        key = sense[1] & 0xF;
+-        asc = sense[2];
+-        ascq = sense[3];
+-        break;
+-    default:
+-        return EIO;
+-        break;
+-    }
+-    return scsi_sense_to_errno(key, asc, ascq);
+-}
diff --git a/0008-scsi-introduce-scsi_build_sense.patch b/0008-scsi-introduce-scsi_build_sense.patch
new file mode 100644
index 0000000..e7ce4e3
--- /dev/null
+++ b/0008-scsi-introduce-scsi_build_sense.patch
@@ -0,0 +1,73 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 09:42:59 +0200
+Subject: [PATCH] scsi: introduce scsi_build_sense
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Move more knowledge of sense data format out of hw/scsi/scsi-bus.c
+for reusability.
+
+Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/scsi-bus.c   |  8 +-------
+ include/scsi/utils.h |  2 ++
+ scsi/utils.c         | 11 +++++++++++
+ 3 files changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
+index 42920d5422..652ab046ab 100644
+--- a/hw/scsi/scsi-bus.c
++++ b/hw/scsi/scsi-bus.c
+@@ -818,13 +818,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
+ {
+     trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
+                                sense.key, sense.asc, sense.ascq);
+-    memset(req->sense, 0, 18);
+-    req->sense[0] = 0x70;
+-    req->sense[2] = sense.key;
+-    req->sense[7] = 10;
+-    req->sense[12] = sense.asc;
+-    req->sense[13] = sense.ascq;
+-    req->sense_len = 18;
++    req->sense_len = scsi_build_sense(req->sense, sense);
+ }
+ 
+ static void scsi_req_enqueue_internal(SCSIRequest *req)
+diff --git a/include/scsi/utils.h b/include/scsi/utils.h
+index 90bf4dce6e..b49392d841 100644
+--- a/include/scsi/utils.h
++++ b/include/scsi/utils.h
+@@ -30,6 +30,8 @@ typedef struct SCSISense {
+     uint8_t ascq;
+ } SCSISense;
+ 
++int scsi_build_sense(uint8_t *buf, SCSISense sense);
++
+ /*
+  * Predefined sense codes
+  */
+diff --git a/scsi/utils.c b/scsi/utils.c
+index 2327e06da0..89d9167d9d 100644
+--- a/scsi/utils.c
++++ b/scsi/utils.c
+@@ -96,6 +96,17 @@ int scsi_cdb_length(uint8_t *buf)
+     return cdb_len;
+ }
+ 
++int scsi_build_sense(uint8_t *buf, SCSISense sense)
++{
++    memset(buf, 0, 18);
++    buf[0] = 0x70;
++    buf[2] = sense.key;
++    buf[7] = 10;
++    buf[12] = sense.asc;
++    buf[13] = sense.ascq;
++    return 18;
++}
++
+ /*
+  * Predefined sense codes
+  */
diff --git a/0009-scsi-introduce-sg_io_sense_from_errno.patch b/0009-scsi-introduce-sg_io_sense_from_errno.patch
new file mode 100644
index 0000000..350084a
--- /dev/null
+++ b/0009-scsi-introduce-sg_io_sense_from_errno.patch
@@ -0,0 +1,133 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 09:43:14 +0200
+Subject: [PATCH] scsi: introduce sg_io_sense_from_errno
+
+Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
+reusability.
+
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
+ include/scsi/utils.h   |  3 +++
+ scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 45 insertions(+), 33 deletions(-)
+
+diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
+index 7a8f500934..04c687ee76 100644
+--- a/hw/scsi/scsi-generic.c
++++ b/hw/scsi/scsi-generic.c
+@@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
+ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
+ {
+     int status;
++    SCSISense sense;
+ 
+     assert(r->req.aiocb == NULL);
+ 
+@@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
+         scsi_req_cancel_complete(&r->req);
+         goto done;
+     }
+-    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+-        r->req.sense_len = r->io_header.sb_len_wr;
+-    }
+-
+-    if (ret != 0) {
+-        switch (ret) {
+-        case -EDOM:
+-            status = TASK_SET_FULL;
+-            break;
+-        case -ENOMEM:
+-            status = CHECK_CONDITION;
+-            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
+-            break;
+-        default:
+-            status = CHECK_CONDITION;
+-            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
+-            break;
+-        }
+-    } else {
+-        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
+-            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
+-            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
+-            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
+-            status = BUSY;
+-            BADF("Driver Timeout\n");
+-        } else if (r->io_header.host_status) {
+-            status = CHECK_CONDITION;
+-            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
+-        } else if (r->io_header.status) {
+-            status = r->io_header.status;
+-        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+-            status = CHECK_CONDITION;
++    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
++    if (status == CHECK_CONDITION) {
++        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
++            r->req.sense_len = r->io_header.sb_len_wr;
+         } else {
+-            status = GOOD;
++            scsi_req_build_sense(&r->req, sense);
+         }
+     }
++
+     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
+             r, r->req.tag, status);
+ 
+diff --git a/include/scsi/utils.h b/include/scsi/utils.h
+index b49392d841..d301b31768 100644
+--- a/include/scsi/utils.h
++++ b/include/scsi/utils.h
+@@ -116,6 +116,9 @@ int scsi_cdb_length(uint8_t *buf);
+ #define SG_ERR_DID_TIME_OUT    0x03
+ 
+ #define SG_ERR_DRIVER_SENSE    0x08
++
++int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
++                           SCSISense *sense);
+ #endif
+ 
+ #endif
+diff --git a/scsi/utils.c b/scsi/utils.c
+index 89d9167d9d..6ee9f4095b 100644
+--- a/scsi/utils.c
++++ b/scsi/utils.c
+@@ -501,3 +501,38 @@ const char *scsi_command_name(uint8_t cmd)
+     }
+     return names[cmd];
+ }
++
++#ifdef CONFIG_LINUX
++int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
++                           SCSISense *sense)
++{
++    if (errno_value != 0) {
++        switch (errno_value) {
++        case EDOM:
++            return TASK_SET_FULL;
++        case ENOMEM:
++            *sense = SENSE_CODE(TARGET_FAILURE);
++            return CHECK_CONDITION;
++        default:
++            *sense = SENSE_CODE(IO_ERROR);
++            return CHECK_CONDITION;
++        }
++    } else {
++        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
++            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
++            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
++            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
++            return BUSY;
++        } else if (io_hdr->host_status) {
++            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
++            return CHECK_CONDITION;
++        } else if (io_hdr->status) {
++            return io_hdr->status;
++        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
++            return CHECK_CONDITION;
++        } else {
++            return GOOD;
++        }
++    }
++}
++#endif
diff --git a/0010-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch b/0010-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
new file mode 100644
index 0000000..8bdc71c
--- /dev/null
+++ b/0010-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
@@ -0,0 +1,884 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 09:23:55 +0200
+Subject: [PATCH] scsi: move block/scsi.h to include/scsi/constants.h
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Complete the transition by renaming this header, which was
+shared by block/iscsi.c and the SCSI emulation code.
+
+Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ block/iscsi.c                   |   2 +-
+ hw/block/virtio-blk.c           |   2 +-
+ hw/scsi/megasas.c               |   2 +-
+ hw/scsi/mptendian.c             |   2 +-
+ hw/scsi/mptsas.c                |   2 +-
+ hw/scsi/scsi-bus.c              |   2 +-
+ hw/scsi/scsi-disk.c             |   2 +-
+ hw/scsi/scsi-generic.c          |   2 +-
+ hw/scsi/spapr_vscsi.c           |   2 +-
+ hw/scsi/virtio-scsi-dataplane.c |   2 +-
+ hw/scsi/virtio-scsi.c           |   2 +-
+ hw/scsi/vmw_pvscsi.c            |   2 +-
+ hw/usb/dev-uas.c                |   2 +-
+ include/block/scsi.h            | 314 ----------------------------------------
+ include/hw/ide/internal.h       |   2 +-
+ include/scsi/constants.h        | 314 ++++++++++++++++++++++++++++++++++++++++
+ scsi/utils.c                    |   2 +-
+ tests/virtio-scsi-test.c        |   2 +-
+ 18 files changed, 330 insertions(+), 330 deletions(-)
+ delete mode 100644 include/block/scsi.h
+ create mode 100644 include/scsi/constants.h
+
+diff --git a/block/iscsi.c b/block/iscsi.c
+index 40adc3c493..c4586be720 100644
+--- a/block/iscsi.c
++++ b/block/iscsi.c
+@@ -34,7 +34,7 @@
+ #include "qemu/bitops.h"
+ #include "qemu/bitmap.h"
+ #include "block/block_int.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "qemu/iov.h"
+ #include "qemu/uuid.h"
+ #include "qmp-commands.h"
+diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
+index a16ac75090..05d1440786 100644
+--- a/hw/block/virtio-blk.c
++++ b/hw/block/virtio-blk.c
+@@ -22,7 +22,7 @@
+ #include "sysemu/blockdev.h"
+ #include "hw/virtio/virtio-blk.h"
+ #include "dataplane/virtio-blk.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #ifdef __linux__
+ # include <scsi/sg.h>
+ #endif
+diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
+index 734fdaef90..0db68aacee 100644
+--- a/hw/scsi/megasas.c
++++ b/hw/scsi/megasas.c
+@@ -27,7 +27,7 @@
+ #include "hw/pci/msix.h"
+ #include "qemu/iov.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "trace.h"
+ #include "qapi/error.h"
+ #include "mfi.h"
+diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
+index b7fe2a2a36..3415229b5e 100644
+--- a/hw/scsi/mptendian.c
++++ b/hw/scsi/mptendian.c
+@@ -28,7 +28,7 @@
+ #include "hw/pci/msi.h"
+ #include "qemu/iov.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "trace.h"
+ 
+ #include "mptsas.h"
+diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
+index 765ab53c34..8bae8f543e 100644
+--- a/hw/scsi/mptsas.c
++++ b/hw/scsi/mptsas.c
+@@ -30,7 +30,7 @@
+ #include "hw/pci/msi.h"
+ #include "qemu/iov.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "trace.h"
+ #include "qapi/error.h"
+ #include "mptsas.h"
+diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
+index 652ab046ab..977f7bce1f 100644
+--- a/hw/scsi/scsi-bus.c
++++ b/hw/scsi/scsi-bus.c
+@@ -3,7 +3,7 @@
+ #include "qapi/error.h"
+ #include "qemu/error-report.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "hw/qdev.h"
+ #include "sysemu/block-backend.h"
+ #include "sysemu/blockdev.h"
+diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
+index 0a1f4ef0c7..5faf6682c5 100644
+--- a/hw/scsi/scsi-disk.c
++++ b/hw/scsi/scsi-disk.c
+@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
+ #include "qapi/error.h"
+ #include "qemu/error-report.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "sysemu/sysemu.h"
+ #include "sysemu/block-backend.h"
+ #include "sysemu/blockdev.h"
+diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
+index 04c687ee76..bd0d9ff355 100644
+--- a/hw/scsi/scsi-generic.c
++++ b/hw/scsi/scsi-generic.c
+@@ -34,7 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+ 
+ #include <scsi/sg.h>
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ 
+ #ifndef MAX_UINT
+ #define MAX_UINT ((unsigned int)-1)
+diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
+index 55ee48c4da..360db53ac8 100644
+--- a/hw/scsi/spapr_vscsi.c
++++ b/hw/scsi/spapr_vscsi.c
+@@ -36,7 +36,7 @@
+ #include "cpu.h"
+ #include "hw/hw.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "srp.h"
+ #include "hw/qdev.h"
+ #include "hw/ppc/spapr.h"
+diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
+index 944ea4eb53..add4b3f4a4 100644
+--- a/hw/scsi/virtio-scsi-dataplane.c
++++ b/hw/scsi/virtio-scsi-dataplane.c
+@@ -17,7 +17,7 @@
+ #include "qemu/error-report.h"
+ #include "sysemu/block-backend.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "hw/virtio/virtio-bus.h"
+ #include "hw/virtio/virtio-access.h"
+ 
+diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
+index eb639442d1..823a1e9a42 100644
+--- a/hw/scsi/virtio-scsi.c
++++ b/hw/scsi/virtio-scsi.c
+@@ -21,7 +21,7 @@
+ #include "qemu/iov.h"
+ #include "sysemu/block-backend.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "hw/virtio/virtio-bus.h"
+ #include "hw/virtio/virtio-access.h"
+ 
+diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
+index 77d8b6f9e2..6d3f0bf11d 100644
+--- a/hw/scsi/vmw_pvscsi.c
++++ b/hw/scsi/vmw_pvscsi.c
+@@ -28,7 +28,7 @@
+ #include "qemu/osdep.h"
+ #include "qapi/error.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "hw/pci/msi.h"
+ #include "vmw_pvscsi.h"
+ #include "trace.h"
+diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
+index fffc424396..c218b53f09 100644
+--- a/hw/usb/dev-uas.c
++++ b/hw/usb/dev-uas.c
+@@ -19,7 +19,7 @@
+ #include "hw/usb.h"
+ #include "hw/usb/desc.h"
+ #include "hw/scsi/scsi.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ 
+ /* --------------------------------------------------------------------- */
+ 
+diff --git a/include/block/scsi.h b/include/block/scsi.h
+deleted file mode 100644
+index a141dd71f8..0000000000
+--- a/include/block/scsi.h
++++ /dev/null
+@@ -1,314 +0,0 @@
+-/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+-   This file is part of the GNU C Library.
+-
+-   The GNU C Library is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU Lesser General Public
+-   License as published by the Free Software Foundation; either
+-   version 2.1 of the License, or (at your option) any later version.
+-
+-   The GNU C Library is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   Lesser General Public License for more details.
+-
+-   You should have received a copy of the GNU Lesser General Public
+-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+-*/
+-
+-/*
+- * This header file contains public constants and structures used by
+- * the scsi code for linux.
+- */
+-
+-#ifndef BLOCK_SCSI_H
+-#define BLOCK_SCSI_H
+-
+-/*
+- *      SCSI opcodes
+- */
+-
+-#define TEST_UNIT_READY       0x00
+-#define REWIND                0x01
+-#define REQUEST_SENSE         0x03
+-#define FORMAT_UNIT           0x04
+-#define READ_BLOCK_LIMITS     0x05
+-#define INITIALIZE_ELEMENT_STATUS 0x07
+-#define REASSIGN_BLOCKS       0x07
+-#define READ_6                0x08
+-#define WRITE_6               0x0a
+-#define SET_CAPACITY          0x0b
+-#define READ_REVERSE          0x0f
+-#define WRITE_FILEMARKS       0x10
+-#define SPACE                 0x11
+-#define INQUIRY               0x12
+-#define RECOVER_BUFFERED_DATA 0x14
+-#define MODE_SELECT           0x15
+-#define RESERVE               0x16
+-#define RELEASE               0x17
+-#define COPY                  0x18
+-#define ERASE                 0x19
+-#define MODE_SENSE            0x1a
+-#define LOAD_UNLOAD           0x1b
+-#define SCAN                  0x1b
+-#define START_STOP            0x1b
+-#define RECEIVE_DIAGNOSTIC    0x1c
+-#define SEND_DIAGNOSTIC       0x1d
+-#define ALLOW_MEDIUM_REMOVAL  0x1e
+-#define SET_WINDOW            0x24
+-#define READ_CAPACITY_10      0x25
+-#define GET_WINDOW            0x25
+-#define READ_10               0x28
+-#define WRITE_10              0x2a
+-#define SEND                  0x2a
+-#define SEEK_10               0x2b
+-#define LOCATE_10             0x2b
+-#define POSITION_TO_ELEMENT   0x2b
+-#define WRITE_VERIFY_10       0x2e
+-#define VERIFY_10             0x2f
+-#define SEARCH_HIGH           0x30
+-#define SEARCH_EQUAL          0x31
+-#define OBJECT_POSITION       0x31
+-#define SEARCH_LOW            0x32
+-#define SET_LIMITS            0x33
+-#define PRE_FETCH             0x34
+-#define READ_POSITION         0x34
+-#define GET_DATA_BUFFER_STATUS 0x34
+-#define SYNCHRONIZE_CACHE     0x35
+-#define LOCK_UNLOCK_CACHE     0x36
+-#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
+-#define READ_DEFECT_DATA      0x37
+-#define MEDIUM_SCAN           0x38
+-#define COMPARE               0x39
+-#define COPY_VERIFY           0x3a
+-#define WRITE_BUFFER          0x3b
+-#define READ_BUFFER           0x3c
+-#define UPDATE_BLOCK          0x3d
+-#define READ_LONG_10          0x3e
+-#define WRITE_LONG_10         0x3f
+-#define CHANGE_DEFINITION     0x40
+-#define WRITE_SAME_10         0x41
+-#define UNMAP                 0x42
+-#define READ_TOC              0x43
+-#define REPORT_DENSITY_SUPPORT 0x44
+-#define GET_CONFIGURATION     0x46
+-#define SANITIZE              0x48
+-#define GET_EVENT_STATUS_NOTIFICATION 0x4a
+-#define LOG_SELECT            0x4c
+-#define LOG_SENSE             0x4d
+-#define READ_DISC_INFORMATION 0x51
+-#define RESERVE_TRACK         0x53
+-#define MODE_SELECT_10        0x55
+-#define RESERVE_10            0x56
+-#define RELEASE_10            0x57
+-#define MODE_SENSE_10         0x5a
+-#define SEND_CUE_SHEET        0x5d
+-#define PERSISTENT_RESERVE_IN 0x5e
+-#define PERSISTENT_RESERVE_OUT 0x5f
+-#define VARLENGTH_CDB         0x7f
+-#define WRITE_FILEMARKS_16    0x80
+-#define READ_REVERSE_16       0x81
+-#define ALLOW_OVERWRITE       0x82
+-#define EXTENDED_COPY         0x83
+-#define ATA_PASSTHROUGH_16    0x85
+-#define ACCESS_CONTROL_IN     0x86
+-#define ACCESS_CONTROL_OUT    0x87
+-#define READ_16               0x88
+-#define COMPARE_AND_WRITE     0x89
+-#define WRITE_16              0x8a
+-#define WRITE_VERIFY_16       0x8e
+-#define VERIFY_16             0x8f
+-#define PRE_FETCH_16          0x90
+-#define SPACE_16              0x91
+-#define SYNCHRONIZE_CACHE_16  0x91
+-#define LOCATE_16             0x92
+-#define WRITE_SAME_16         0x93
+-#define ERASE_16              0x93
+-#define SERVICE_ACTION_IN_16  0x9e
+-#define WRITE_LONG_16         0x9f
+-#define REPORT_LUNS           0xa0
+-#define ATA_PASSTHROUGH_12    0xa1
+-#define MAINTENANCE_IN        0xa3
+-#define MAINTENANCE_OUT       0xa4
+-#define MOVE_MEDIUM           0xa5
+-#define EXCHANGE_MEDIUM       0xa6
+-#define SET_READ_AHEAD        0xa7
+-#define READ_12               0xa8
+-#define WRITE_12              0xaa
+-#define SERVICE_ACTION_IN_12  0xab
+-#define ERASE_12              0xac
+-#define READ_DVD_STRUCTURE    0xad
+-#define WRITE_VERIFY_12       0xae
+-#define VERIFY_12             0xaf
+-#define SEARCH_HIGH_12        0xb0
+-#define SEARCH_EQUAL_12       0xb1
+-#define SEARCH_LOW_12         0xb2
+-#define READ_ELEMENT_STATUS   0xb8
+-#define SEND_VOLUME_TAG       0xb6
+-#define READ_DEFECT_DATA_12   0xb7
+-#define SET_CD_SPEED          0xbb
+-#define MECHANISM_STATUS      0xbd
+-#define READ_CD               0xbe
+-#define SEND_DVD_STRUCTURE    0xbf
+-
+-/*
+- * SERVICE ACTION IN subcodes
+- */
+-#define SAI_READ_CAPACITY_16  0x10
+-
+-/*
+- * READ POSITION service action codes
+- */
+-#define SHORT_FORM_BLOCK_ID  0x00
+-#define SHORT_FORM_VENDOR_SPECIFIC 0x01
+-#define LONG_FORM            0x06
+-#define EXTENDED_FORM        0x08
+-
+-/*
+- *  SAM Status codes
+- */
+-
+-#define GOOD                 0x00
+-#define CHECK_CONDITION      0x02
+-#define CONDITION_GOOD       0x04
+-#define BUSY                 0x08
+-#define INTERMEDIATE_GOOD    0x10
+-#define INTERMEDIATE_C_GOOD  0x14
+-#define RESERVATION_CONFLICT 0x18
+-#define COMMAND_TERMINATED   0x22
+-#define TASK_SET_FULL        0x28
+-#define ACA_ACTIVE           0x30
+-#define TASK_ABORTED         0x40
+-
+-#define STATUS_MASK          0x3e
+-
+-/*
+- *  SENSE KEYS
+- */
+-
+-#define NO_SENSE            0x00
+-#define RECOVERED_ERROR     0x01
+-#define NOT_READY           0x02
+-#define MEDIUM_ERROR        0x03
+-#define HARDWARE_ERROR      0x04
+-#define ILLEGAL_REQUEST     0x05
+-#define UNIT_ATTENTION      0x06
+-#define DATA_PROTECT        0x07
+-#define BLANK_CHECK         0x08
+-#define COPY_ABORTED        0x0a
+-#define ABORTED_COMMAND     0x0b
+-#define VOLUME_OVERFLOW     0x0d
+-#define MISCOMPARE          0x0e
+-
+-
+-/*
+- *  DEVICE TYPES
+- */
+-
+-#define TYPE_DISK           0x00
+-#define TYPE_TAPE           0x01
+-#define TYPE_PRINTER        0x02
+-#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+-#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+-#define TYPE_ROM            0x05
+-#define TYPE_SCANNER        0x06
+-#define TYPE_MOD            0x07    /* Magneto-optical disk -
+-				     * - treated as TYPE_DISK */
+-#define TYPE_MEDIUM_CHANGER 0x08
+-#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
+-#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
+-#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
+-#define TYPE_OSD            0x11    /* Object-storage Device */
+-#define TYPE_WLUN           0x1e    /* Well known LUN */
+-#define TYPE_NOT_PRESENT    0x1f
+-#define TYPE_INACTIVE       0x20
+-#define TYPE_NO_LUN         0x7f
+-
+-/* Mode page codes for mode sense/set */
+-#define MODE_PAGE_R_W_ERROR                   0x01
+-#define MODE_PAGE_HD_GEOMETRY                 0x04
+-#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
+-#define MODE_PAGE_CACHING                     0x08
+-#define MODE_PAGE_AUDIO_CTL                   0x0e
+-#define MODE_PAGE_POWER                       0x1a
+-#define MODE_PAGE_FAULT_FAIL                  0x1c
+-#define MODE_PAGE_TO_PROTECT                  0x1d
+-#define MODE_PAGE_CAPABILITIES                0x2a
+-#define MODE_PAGE_ALLS                        0x3f
+-/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
+- * of MODE_PAGE_SENSE_POWER */
+-#define MODE_PAGE_CDROM                       0x0d
+-
+-/* Event notification classes for GET EVENT STATUS NOTIFICATION */
+-#define GESN_NO_EVENTS                0
+-#define GESN_OPERATIONAL_CHANGE       1
+-#define GESN_POWER_MANAGEMENT         2
+-#define GESN_EXTERNAL_REQUEST         3
+-#define GESN_MEDIA                    4
+-#define GESN_MULTIPLE_HOSTS           5
+-#define GESN_DEVICE_BUSY              6
+-
+-/* Event codes for MEDIA event status notification */
+-#define MEC_NO_CHANGE                 0
+-#define MEC_EJECT_REQUESTED           1
+-#define MEC_NEW_MEDIA                 2
+-#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
+-#define MEC_MEDIA_CHANGED             4 /* only for media changers */
+-#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
+-#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
+-
+-#define MS_TRAY_OPEN                  1
+-#define MS_MEDIA_PRESENT              2
+-
+-/*
+- * Based on values from <linux/cdrom.h> but extending CD_MINS
+- * to the maximum common size allowed by the Orange's Book ATIP
+- *
+- * 90 and 99 min CDs are also available but using them as the
+- * upper limit reduces the effectiveness of the heuristic to
+- * detect DVDs burned to less than 25% of their maximum capacity
+- */
+-
+-/* Some generally useful CD-ROM information */
+-#define CD_MINS                       80 /* max. minutes per CD */
+-#define CD_SECS                       60 /* seconds per minute */
+-#define CD_FRAMES                     75 /* frames per second */
+-#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+-#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+-#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+-
+-/*
+- * The MMC values are not IDE specific and might need to be moved
+- * to a common header if they are also needed for the SCSI emulation
+- */
+-
+-/* Profile list from MMC-6 revision 1 table 91 */
+-#define MMC_PROFILE_NONE                0x0000
+-#define MMC_PROFILE_CD_ROM              0x0008
+-#define MMC_PROFILE_CD_R                0x0009
+-#define MMC_PROFILE_CD_RW               0x000A
+-#define MMC_PROFILE_DVD_ROM             0x0010
+-#define MMC_PROFILE_DVD_R_SR            0x0011
+-#define MMC_PROFILE_DVD_RAM             0x0012
+-#define MMC_PROFILE_DVD_RW_RO           0x0013
+-#define MMC_PROFILE_DVD_RW_SR           0x0014
+-#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+-#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+-#define MMC_PROFILE_DVD_RW_DL           0x0017
+-#define MMC_PROFILE_DVD_DDR             0x0018
+-#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+-#define MMC_PROFILE_DVD_PLUS_R          0x001B
+-#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+-#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+-#define MMC_PROFILE_BD_ROM              0x0040
+-#define MMC_PROFILE_BD_R_SRM            0x0041
+-#define MMC_PROFILE_BD_R_RRM            0x0042
+-#define MMC_PROFILE_BD_RE               0x0043
+-#define MMC_PROFILE_HDDVD_ROM           0x0050
+-#define MMC_PROFILE_HDDVD_R             0x0051
+-#define MMC_PROFILE_HDDVD_RAM           0x0052
+-#define MMC_PROFILE_HDDVD_RW            0x0053
+-#define MMC_PROFILE_HDDVD_R_DL          0x0058
+-#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+-#define MMC_PROFILE_INVALID             0xFFFF
+-
+-#endif
+diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
+index 482a9512be..63a99e0366 100644
+--- a/include/hw/ide/internal.h
++++ b/include/hw/ide/internal.h
+@@ -11,7 +11,7 @@
+ #include "sysemu/dma.h"
+ #include "sysemu/sysemu.h"
+ #include "hw/block/block.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ 
+ /* debug IDE devices */
+ //#define DEBUG_IDE
+diff --git a/include/scsi/constants.h b/include/scsi/constants.h
+new file mode 100644
+index 0000000000..a141dd71f8
+--- /dev/null
++++ b/include/scsi/constants.h
+@@ -0,0 +1,314 @@
++/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with this library; if not, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++ * This header file contains public constants and structures used by
++ * the scsi code for linux.
++ */
++
++#ifndef BLOCK_SCSI_H
++#define BLOCK_SCSI_H
++
++/*
++ *      SCSI opcodes
++ */
++
++#define TEST_UNIT_READY       0x00
++#define REWIND                0x01
++#define REQUEST_SENSE         0x03
++#define FORMAT_UNIT           0x04
++#define READ_BLOCK_LIMITS     0x05
++#define INITIALIZE_ELEMENT_STATUS 0x07
++#define REASSIGN_BLOCKS       0x07
++#define READ_6                0x08
++#define WRITE_6               0x0a
++#define SET_CAPACITY          0x0b
++#define READ_REVERSE          0x0f
++#define WRITE_FILEMARKS       0x10
++#define SPACE                 0x11
++#define INQUIRY               0x12
++#define RECOVER_BUFFERED_DATA 0x14
++#define MODE_SELECT           0x15
++#define RESERVE               0x16
++#define RELEASE               0x17
++#define COPY                  0x18
++#define ERASE                 0x19
++#define MODE_SENSE            0x1a
++#define LOAD_UNLOAD           0x1b
++#define SCAN                  0x1b
++#define START_STOP            0x1b
++#define RECEIVE_DIAGNOSTIC    0x1c
++#define SEND_DIAGNOSTIC       0x1d
++#define ALLOW_MEDIUM_REMOVAL  0x1e
++#define SET_WINDOW            0x24
++#define READ_CAPACITY_10      0x25
++#define GET_WINDOW            0x25
++#define READ_10               0x28
++#define WRITE_10              0x2a
++#define SEND                  0x2a
++#define SEEK_10               0x2b
++#define LOCATE_10             0x2b
++#define POSITION_TO_ELEMENT   0x2b
++#define WRITE_VERIFY_10       0x2e
++#define VERIFY_10             0x2f
++#define SEARCH_HIGH           0x30
++#define SEARCH_EQUAL          0x31
++#define OBJECT_POSITION       0x31
++#define SEARCH_LOW            0x32
++#define SET_LIMITS            0x33
++#define PRE_FETCH             0x34
++#define READ_POSITION         0x34
++#define GET_DATA_BUFFER_STATUS 0x34
++#define SYNCHRONIZE_CACHE     0x35
++#define LOCK_UNLOCK_CACHE     0x36
++#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
++#define READ_DEFECT_DATA      0x37
++#define MEDIUM_SCAN           0x38
++#define COMPARE               0x39
++#define COPY_VERIFY           0x3a
++#define WRITE_BUFFER          0x3b
++#define READ_BUFFER           0x3c
++#define UPDATE_BLOCK          0x3d
++#define READ_LONG_10          0x3e
++#define WRITE_LONG_10         0x3f
++#define CHANGE_DEFINITION     0x40
++#define WRITE_SAME_10         0x41
++#define UNMAP                 0x42
++#define READ_TOC              0x43
++#define REPORT_DENSITY_SUPPORT 0x44
++#define GET_CONFIGURATION     0x46
++#define SANITIZE              0x48
++#define GET_EVENT_STATUS_NOTIFICATION 0x4a
++#define LOG_SELECT            0x4c
++#define LOG_SENSE             0x4d
++#define READ_DISC_INFORMATION 0x51
++#define RESERVE_TRACK         0x53
++#define MODE_SELECT_10        0x55
++#define RESERVE_10            0x56
++#define RELEASE_10            0x57
++#define MODE_SENSE_10         0x5a
++#define SEND_CUE_SHEET        0x5d
++#define PERSISTENT_RESERVE_IN 0x5e
++#define PERSISTENT_RESERVE_OUT 0x5f
++#define VARLENGTH_CDB         0x7f
++#define WRITE_FILEMARKS_16    0x80
++#define READ_REVERSE_16       0x81
++#define ALLOW_OVERWRITE       0x82
++#define EXTENDED_COPY         0x83
++#define ATA_PASSTHROUGH_16    0x85
++#define ACCESS_CONTROL_IN     0x86
++#define ACCESS_CONTROL_OUT    0x87
++#define READ_16               0x88
++#define COMPARE_AND_WRITE     0x89
++#define WRITE_16              0x8a
++#define WRITE_VERIFY_16       0x8e
++#define VERIFY_16             0x8f
++#define PRE_FETCH_16          0x90
++#define SPACE_16              0x91
++#define SYNCHRONIZE_CACHE_16  0x91
++#define LOCATE_16             0x92
++#define WRITE_SAME_16         0x93
++#define ERASE_16              0x93
++#define SERVICE_ACTION_IN_16  0x9e
++#define WRITE_LONG_16         0x9f
++#define REPORT_LUNS           0xa0
++#define ATA_PASSTHROUGH_12    0xa1
++#define MAINTENANCE_IN        0xa3
++#define MAINTENANCE_OUT       0xa4
++#define MOVE_MEDIUM           0xa5
++#define EXCHANGE_MEDIUM       0xa6
++#define SET_READ_AHEAD        0xa7
++#define READ_12               0xa8
++#define WRITE_12              0xaa
++#define SERVICE_ACTION_IN_12  0xab
++#define ERASE_12              0xac
++#define READ_DVD_STRUCTURE    0xad
++#define WRITE_VERIFY_12       0xae
++#define VERIFY_12             0xaf
++#define SEARCH_HIGH_12        0xb0
++#define SEARCH_EQUAL_12       0xb1
++#define SEARCH_LOW_12         0xb2
++#define READ_ELEMENT_STATUS   0xb8
++#define SEND_VOLUME_TAG       0xb6
++#define READ_DEFECT_DATA_12   0xb7
++#define SET_CD_SPEED          0xbb
++#define MECHANISM_STATUS      0xbd
++#define READ_CD               0xbe
++#define SEND_DVD_STRUCTURE    0xbf
++
++/*
++ * SERVICE ACTION IN subcodes
++ */
++#define SAI_READ_CAPACITY_16  0x10
++
++/*
++ * READ POSITION service action codes
++ */
++#define SHORT_FORM_BLOCK_ID  0x00
++#define SHORT_FORM_VENDOR_SPECIFIC 0x01
++#define LONG_FORM            0x06
++#define EXTENDED_FORM        0x08
++
++/*
++ *  SAM Status codes
++ */
++
++#define GOOD                 0x00
++#define CHECK_CONDITION      0x02
++#define CONDITION_GOOD       0x04
++#define BUSY                 0x08
++#define INTERMEDIATE_GOOD    0x10
++#define INTERMEDIATE_C_GOOD  0x14
++#define RESERVATION_CONFLICT 0x18
++#define COMMAND_TERMINATED   0x22
++#define TASK_SET_FULL        0x28
++#define ACA_ACTIVE           0x30
++#define TASK_ABORTED         0x40
++
++#define STATUS_MASK          0x3e
++
++/*
++ *  SENSE KEYS
++ */
++
++#define NO_SENSE            0x00
++#define RECOVERED_ERROR     0x01
++#define NOT_READY           0x02
++#define MEDIUM_ERROR        0x03
++#define HARDWARE_ERROR      0x04
++#define ILLEGAL_REQUEST     0x05
++#define UNIT_ATTENTION      0x06
++#define DATA_PROTECT        0x07
++#define BLANK_CHECK         0x08
++#define COPY_ABORTED        0x0a
++#define ABORTED_COMMAND     0x0b
++#define VOLUME_OVERFLOW     0x0d
++#define MISCOMPARE          0x0e
++
++
++/*
++ *  DEVICE TYPES
++ */
++
++#define TYPE_DISK           0x00
++#define TYPE_TAPE           0x01
++#define TYPE_PRINTER        0x02
++#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
++#define TYPE_WORM           0x04    /* Treated as ROM by our system */
++#define TYPE_ROM            0x05
++#define TYPE_SCANNER        0x06
++#define TYPE_MOD            0x07    /* Magneto-optical disk -
++				     * - treated as TYPE_DISK */
++#define TYPE_MEDIUM_CHANGER 0x08
++#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
++#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
++#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
++#define TYPE_OSD            0x11    /* Object-storage Device */
++#define TYPE_WLUN           0x1e    /* Well known LUN */
++#define TYPE_NOT_PRESENT    0x1f
++#define TYPE_INACTIVE       0x20
++#define TYPE_NO_LUN         0x7f
++
++/* Mode page codes for mode sense/set */
++#define MODE_PAGE_R_W_ERROR                   0x01
++#define MODE_PAGE_HD_GEOMETRY                 0x04
++#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
++#define MODE_PAGE_CACHING                     0x08
++#define MODE_PAGE_AUDIO_CTL                   0x0e
++#define MODE_PAGE_POWER                       0x1a
++#define MODE_PAGE_FAULT_FAIL                  0x1c
++#define MODE_PAGE_TO_PROTECT                  0x1d
++#define MODE_PAGE_CAPABILITIES                0x2a
++#define MODE_PAGE_ALLS                        0x3f
++/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
++ * of MODE_PAGE_SENSE_POWER */
++#define MODE_PAGE_CDROM                       0x0d
++
++/* Event notification classes for GET EVENT STATUS NOTIFICATION */
++#define GESN_NO_EVENTS                0
++#define GESN_OPERATIONAL_CHANGE       1
++#define GESN_POWER_MANAGEMENT         2
++#define GESN_EXTERNAL_REQUEST         3
++#define GESN_MEDIA                    4
++#define GESN_MULTIPLE_HOSTS           5
++#define GESN_DEVICE_BUSY              6
++
++/* Event codes for MEDIA event status notification */
++#define MEC_NO_CHANGE                 0
++#define MEC_EJECT_REQUESTED           1
++#define MEC_NEW_MEDIA                 2
++#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
++#define MEC_MEDIA_CHANGED             4 /* only for media changers */
++#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
++#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
++
++#define MS_TRAY_OPEN                  1
++#define MS_MEDIA_PRESENT              2
++
++/*
++ * Based on values from <linux/cdrom.h> but extending CD_MINS
++ * to the maximum common size allowed by the Orange's Book ATIP
++ *
++ * 90 and 99 min CDs are also available but using them as the
++ * upper limit reduces the effectiveness of the heuristic to
++ * detect DVDs burned to less than 25% of their maximum capacity
++ */
++
++/* Some generally useful CD-ROM information */
++#define CD_MINS                       80 /* max. minutes per CD */
++#define CD_SECS                       60 /* seconds per minute */
++#define CD_FRAMES                     75 /* frames per second */
++#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
++#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
++#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
++
++/*
++ * The MMC values are not IDE specific and might need to be moved
++ * to a common header if they are also needed for the SCSI emulation
++ */
++
++/* Profile list from MMC-6 revision 1 table 91 */
++#define MMC_PROFILE_NONE                0x0000
++#define MMC_PROFILE_CD_ROM              0x0008
++#define MMC_PROFILE_CD_R                0x0009
++#define MMC_PROFILE_CD_RW               0x000A
++#define MMC_PROFILE_DVD_ROM             0x0010
++#define MMC_PROFILE_DVD_R_SR            0x0011
++#define MMC_PROFILE_DVD_RAM             0x0012
++#define MMC_PROFILE_DVD_RW_RO           0x0013
++#define MMC_PROFILE_DVD_RW_SR           0x0014
++#define MMC_PROFILE_DVD_R_DL_SR         0x0015
++#define MMC_PROFILE_DVD_R_DL_JR         0x0016
++#define MMC_PROFILE_DVD_RW_DL           0x0017
++#define MMC_PROFILE_DVD_DDR             0x0018
++#define MMC_PROFILE_DVD_PLUS_RW         0x001A
++#define MMC_PROFILE_DVD_PLUS_R          0x001B
++#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
++#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
++#define MMC_PROFILE_BD_ROM              0x0040
++#define MMC_PROFILE_BD_R_SRM            0x0041
++#define MMC_PROFILE_BD_R_RRM            0x0042
++#define MMC_PROFILE_BD_RE               0x0043
++#define MMC_PROFILE_HDDVD_ROM           0x0050
++#define MMC_PROFILE_HDDVD_R             0x0051
++#define MMC_PROFILE_HDDVD_RAM           0x0052
++#define MMC_PROFILE_HDDVD_RW            0x0053
++#define MMC_PROFILE_HDDVD_R_DL          0x0058
++#define MMC_PROFILE_HDDVD_RW_DL         0x005A
++#define MMC_PROFILE_INVALID             0xFFFF
++
++#endif
+diff --git a/scsi/utils.c b/scsi/utils.c
+index 6ee9f4095b..fab60bdf20 100644
+--- a/scsi/utils.c
++++ b/scsi/utils.c
+@@ -14,7 +14,7 @@
+  */
+ 
+ #include "qemu/osdep.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "scsi/utils.h"
+ #include "qemu/bswap.h"
+ 
+diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
+index 87a3b6e81a..082d323541 100644
+--- a/tests/virtio-scsi-test.c
++++ b/tests/virtio-scsi-test.c
+@@ -10,7 +10,7 @@
+ 
+ #include "qemu/osdep.h"
+ #include "libqtest.h"
+-#include "block/scsi.h"
++#include "scsi/constants.h"
+ #include "libqos/libqos-pc.h"
+ #include "libqos/libqos-spapr.h"
+ #include "libqos/virtio.h"
diff --git a/0011-scsi-file-posix-add-support-for-persistent-reservati.patch b/0011-scsi-file-posix-add-support-for-persistent-reservati.patch
new file mode 100644
index 0000000..e747615
--- /dev/null
+++ b/0011-scsi-file-posix-add-support-for-persistent-reservati.patch
@@ -0,0 +1,436 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Mon, 21 Aug 2017 18:58:56 +0200
+Subject: [PATCH] scsi, file-posix: add support for persistent reservation
+ management
+
+It is a common requirement for virtual machine to send persistent
+reservations, but this currently requires either running QEMU with
+CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged
+QEMU bypass Linux's filter on SG_IO commands.
+
+As an alternative mechanism, the next patches will introduce a
+privileged helper to run persistent reservation commands without
+expanding QEMU's attack surface unnecessarily.
+
+The helper is invoked through a "pr-manager" QOM object, to which
+file-posix.c passes SG_IO requests for PERSISTENT RESERVE OUT and
+PERSISTENT RESERVE IN commands.  For example:
+
+  $ qemu-system-x86_64
+      -device virtio-scsi \
+      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
+      -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
+      -device scsi-block,drive=hd
+
+or:
+
+  $ qemu-system-x86_64
+      -device virtio-scsi \
+      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
+      -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
+      -device scsi-block,drive=hd
+
+Multiple pr-manager implementations are conceivable and possible, though
+only one is implemented right now.  For example, a pr-manager could:
+
+- talk directly to the multipath daemon from a privileged QEMU
+  (i.e. QEMU links to libmpathpersist); this makes reservation work
+  properly with multipath, but still requires CAP_SYS_RAWIO
+
+- use the Linux IOC_PR_* ioctls (they require CAP_SYS_ADMIN though)
+
+- more interestingly, implement reservations directly in QEMU
+  through file system locks or a shared database (e.g. sqlite)
+
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ Makefile.objs             |   1 +
+ block/file-posix.c        |  30 +++++++++++++
+ docs/pr-manager.rst       |  51 ++++++++++++++++++++++
+ include/scsi/pr-manager.h |  56 ++++++++++++++++++++++++
+ qapi/block-core.json      |   4 ++
+ scsi/Makefile.objs        |   2 +
+ scsi/pr-manager.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++++
+ scsi/trace-events         |   3 ++
+ vl.c                      |   3 +-
+ 9 files changed, 258 insertions(+), 1 deletion(-)
+ create mode 100644 docs/pr-manager.rst
+ create mode 100644 include/scsi/pr-manager.h
+ create mode 100644 scsi/pr-manager.c
+ create mode 100644 scsi/trace-events
+
+diff --git a/Makefile.objs b/Makefile.objs
+index f68aa3b60d..64bebd05db 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -168,6 +168,7 @@ trace-events-subdirs += qapi
+ trace-events-subdirs += accel/tcg
+ trace-events-subdirs += accel/kvm
+ trace-events-subdirs += nbd
++trace-events-subdirs += scsi
+ 
+ trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
+ 
+diff --git a/block/file-posix.c b/block/file-posix.c
+index cb3bfce147..9cacf06685 100644
+--- a/block/file-posix.c
++++ b/block/file-posix.c
+@@ -34,6 +34,9 @@
+ #include "qapi/util.h"
+ #include "qapi/qmp/qstring.h"
+ 
++#include "scsi/pr-manager.h"
++#include "scsi/constants.h"
++
+ #if defined(__APPLE__) && (__MACH__)
+ #include <paths.h>
+ #include <sys/param.h>
+@@ -156,6 +159,8 @@ typedef struct BDRVRawState {
+     bool page_cache_inconsistent:1;
+     bool has_fallocate;
+     bool needs_alignment;
++
++    PRManager *pr_mgr;
+ } BDRVRawState;
+ 
+ typedef struct BDRVRawReopenState {
+@@ -403,6 +408,11 @@ static QemuOptsList raw_runtime_opts = {
+             .type = QEMU_OPT_STRING,
+             .help = "file locking mode (on/off/auto, default: auto)",
+         },
++        {
++            .name = "pr-manager",
++            .type = QEMU_OPT_STRING,
++            .help = "id of persistent reservation manager object (default: none)",
++        },
+         { /* end of list */ }
+     },
+ };
+@@ -414,6 +424,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
+     QemuOpts *opts;
+     Error *local_err = NULL;
+     const char *filename = NULL;
++    const char *str;
+     BlockdevAioOptions aio, aio_default;
+     int fd, ret;
+     struct stat st;
+@@ -475,6 +486,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
+         abort();
+     }
+ 
++    str = qemu_opt_get(opts, "pr-manager");
++    if (str) {
++        s->pr_mgr = pr_manager_lookup(str, &local_err);
++        if (local_err) {
++            error_propagate(errp, local_err);
++            ret = -EINVAL;
++            goto fail;
++        }
++    }
++
+     s->open_flags = open_flags;
+     raw_parse_flags(bdrv_flags, &s->open_flags);
+ 
+@@ -2597,6 +2618,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
+     if (fd_open(bs) < 0)
+         return NULL;
+ 
++    if (req == SG_IO && s->pr_mgr) {
++        struct sg_io_hdr *io_hdr = buf;
++        if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
++            io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
++            return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
++                                      s->fd, io_hdr, cb, opaque);
++        }
++    }
++
+     acb = g_new(RawPosixAIOData, 1);
+     acb->bs = bs;
+     acb->aio_type = QEMU_AIO_IOCTL;
+diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
+new file mode 100644
+index 0000000000..b6089fb57c
+--- /dev/null
++++ b/docs/pr-manager.rst
+@@ -0,0 +1,51 @@
++======================================
++Persistent reservation managers
++======================================
++
++SCSI persistent Reservations allow restricting access to block devices
++to specific initiators in a shared storage setup.  When implementing
++clustering of virtual machines, it is a common requirement for virtual
++machines to send persistent reservation SCSI commands.  However,
++the operating system restricts sending these commands to unprivileged
++programs because incorrect usage can disrupt regular operation of the
++storage fabric.
++
++For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
++and ``scsi-generic`` (both are only available on Linux) can delegate
++implementation of persistent reservations to a separate object,
++the "persistent reservation manager".  Only PERSISTENT RESERVE OUT and
++PERSISTENT RESERVE IN commands are passed to the persistent reservation
++manager object; other commands are processed by QEMU as usual.
++
++-----------------------------------------
++Defining a persistent reservation manager
++-----------------------------------------
++
++A persistent reservation manager is an instance of a subclass of the
++"pr-manager" QOM class.
++
++Right now only one subclass is defined, ``pr-manager-helper``, which
++forwards the commands to an external privileged helper program
++over Unix sockets.  The helper program only allows sending persistent
++reservation commands to devices for which QEMU has a file descriptor,
++so that QEMU will not be able to effect persistent reservations
++unless it has access to both the socket and the device.
++
++``pr-manager-helper`` has a single string property, ``path``, which
++accepts the path to the helper program's Unix socket.  For example,
++the following command line defines a ``pr-manager-helper`` object and
++attaches it to a SCSI passthrough device::
++
++      $ qemu-system-x86_64
++          -device virtio-scsi \
++          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
++          -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
++          -device scsi-block,drive=hd
++
++Alternatively, using ``-blockdev``::
++
++      $ qemu-system-x86_64
++          -device virtio-scsi \
++          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
++          -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
++          -device scsi-block,drive=hd
+diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h
+new file mode 100644
+index 0000000000..b2b37d63bc
+--- /dev/null
++++ b/include/scsi/pr-manager.h
+@@ -0,0 +1,56 @@
++#ifndef PR_MANAGER_H
++#define PR_MANAGER_H
++
++#include "qom/object.h"
++#include "qapi/qmp/qdict.h"
++#include "qapi/visitor.h"
++#include "qom/object_interfaces.h"
++#include "block/aio.h"
++
++#define TYPE_PR_MANAGER "pr-manager"
++
++#define PR_MANAGER_CLASS(klass) \
++     OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER)
++#define PR_MANAGER_GET_CLASS(obj) \
++     OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER)
++#define PR_MANAGER(obj) \
++     OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER)
++
++struct sg_io_hdr;
++
++typedef struct PRManager {
++    /* <private> */
++    Object parent;
++} PRManager;
++
++/**
++ * PRManagerClass:
++ * @parent_class: the base class
++ * @run: callback invoked in thread pool context
++ */
++typedef struct PRManagerClass {
++    /* <private> */
++    ObjectClass parent_class;
++
++    /* <public> */
++    int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr);
++} PRManagerClass;
++
++BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
++                               AioContext *ctx, int fd,
++                               struct sg_io_hdr *hdr,
++                               BlockCompletionFunc *complete,
++                               void *opaque);
++
++#ifdef CONFIG_LINUX
++PRManager *pr_manager_lookup(const char *id, Error **errp);
++#else
++static inline PRManager *pr_manager_lookup(const char *id, Error **errp)
++{
++    /* The classes do not exist at all!  */
++    error_setg(errp, "No persistent reservation manager with id '%s'", id);
++    return NULL;
++}
++#endif
++
++#endif
+diff --git a/qapi/block-core.json b/qapi/block-core.json
+index 833c602150..1cf6ec8be7 100644
+--- a/qapi/block-core.json
++++ b/qapi/block-core.json
+@@ -2191,6 +2191,9 @@
+ # Driver specific block device options for the file backend.
+ #
+ # @filename:    path to the image file
++# @pr-manager:  the id for the object that will handle persistent reservations
++#               for this device (default: none, forward the commands via SG_IO;
++#               since 2.11)
+ # @aio:         AIO backend (default: threads) (since: 2.8)
+ # @locking:     whether to enable file locking. If set to 'auto', only enable
+ #               when Open File Descriptor (OFD) locking API is available
+@@ -2200,6 +2203,7 @@
+ ##
+ { 'struct': 'BlockdevOptionsFile',
+   'data': { 'filename': 'str',
++            '*pr-manager': 'str',
+             '*locking': 'OnOffAuto',
+             '*aio': 'BlockdevAioOptions' } }
+ 
+diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
+index 31b82a5a36..5496d2ae6a 100644
+--- a/scsi/Makefile.objs
++++ b/scsi/Makefile.objs
+@@ -1 +1,3 @@
+ block-obj-y += utils.o
++
++block-obj-$(CONFIG_LINUX) += pr-manager.o
+diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
+new file mode 100644
+index 0000000000..87c45db5d4
+--- /dev/null
++++ b/scsi/pr-manager.c
+@@ -0,0 +1,109 @@
++/*
++ * Persistent reservation manager abstract class
++ *
++ * Copyright (c) 2017 Red Hat, Inc.
++ *
++ * Author: Paolo Bonzini <pbonzini@redhat.com>
++ *
++ * This code is licensed under the LGPL.
++ *
++ */
++
++#include "qemu/osdep.h"
++#include <scsi/sg.h>
++
++#include "qapi/error.h"
++#include "block/aio.h"
++#include "block/thread-pool.h"
++#include "scsi/pr-manager.h"
++#include "trace.h"
++
++typedef struct PRManagerData {
++    PRManager *pr_mgr;
++    struct sg_io_hdr *hdr;
++    int fd;
++} PRManagerData;
++
++static int pr_manager_worker(void *opaque)
++{
++    PRManagerData *data = opaque;
++    PRManager *pr_mgr = data->pr_mgr;
++    PRManagerClass *pr_mgr_class =
++        PR_MANAGER_GET_CLASS(pr_mgr);
++    struct sg_io_hdr *hdr = data->hdr;
++    int fd = data->fd;
++    int r;
++
++    g_free(data);
++    trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]);
++
++    /* The reference was taken in pr_manager_execute.  */
++    r = pr_mgr_class->run(pr_mgr, fd, hdr);
++    object_unref(OBJECT(pr_mgr));
++    return r;
++}
++
++
++BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
++                               AioContext *ctx, int fd,
++                               struct sg_io_hdr *hdr,
++                               BlockCompletionFunc *complete,
++                               void *opaque)
++{
++    PRManagerData *data = g_new(PRManagerData, 1);
++    ThreadPool *pool = aio_get_thread_pool(ctx);
++
++    trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque);
++    data->pr_mgr = pr_mgr;
++    data->fd = fd;
++    data->hdr = hdr;
++
++    /* The matching object_unref is in pr_manager_worker.  */
++    object_ref(OBJECT(pr_mgr));
++    return thread_pool_submit_aio(pool, pr_manager_worker,
++                                  data, complete, opaque);
++}
++
++static const TypeInfo pr_manager_info = {
++    .parent = TYPE_OBJECT,
++    .name = TYPE_PR_MANAGER,
++    .class_size = sizeof(PRManagerClass),
++    .abstract = true,
++    .interfaces = (InterfaceInfo[]) {
++        { TYPE_USER_CREATABLE },
++        { }
++    }
++};
++
++PRManager *pr_manager_lookup(const char *id, Error **errp)
++{
++    Object *obj;
++    PRManager *pr_mgr;
++
++    obj = object_resolve_path_component(object_get_objects_root(), id);
++    if (!obj) {
++        error_setg(errp, "No persistent reservation manager with id '%s'", id);
++        return NULL;
++    }
++
++    pr_mgr = (PRManager *)
++        object_dynamic_cast(obj,
++                            TYPE_PR_MANAGER);
++    if (!pr_mgr) {
++        error_setg(errp,
++                   "Object with id '%s' is not a persistent reservation manager",
++                   id);
++        return NULL;
++    }
++
++    return pr_mgr;
++}
++
++static void
++pr_manager_register_types(void)
++{
++    type_register_static(&pr_manager_info);
++}
++
++
++type_init(pr_manager_register_types);
+diff --git a/scsi/trace-events b/scsi/trace-events
+new file mode 100644
+index 0000000000..45f5b6e49b
+--- /dev/null
++++ b/scsi/trace-events
+@@ -0,0 +1,3 @@
++# scsi/pr-manager.c
++pr_manager_execute(int fd, int cmd, int sa, void *opaque) "fd=%d cmd=0x%02x service action=0x%02x opaque=%p"
++pr_manager_run(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x"
+diff --git a/vl.c b/vl.c
+index d63269332f..acaf9eab39 100644
+--- a/vl.c
++++ b/vl.c
+@@ -2811,7 +2811,8 @@ static int machine_set_property(void *opaque,
+  */
+ static bool object_create_initial(const char *type)
+ {
+-    if (g_str_equal(type, "rng-egd")) {
++    if (g_str_equal(type, "rng-egd") ||
++        g_str_has_prefix(type, "pr-manager-")) {
+         return false;
+     }
+ 
diff --git a/0012-scsi-build-qemu-pr-helper.patch b/0012-scsi-build-qemu-pr-helper.patch
new file mode 100644
index 0000000..9d97fc7
--- /dev/null
+++ b/0012-scsi-build-qemu-pr-helper.patch
@@ -0,0 +1,1009 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 06:50:18 +0200
+Subject: [PATCH] scsi: build qemu-pr-helper
+
+Introduce a privileged helper to run persistent reservation commands.
+This lets virtual machines send persistent reservations without using
+CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
+and SCM_RIGHTS to restrict access to processes that can access its socket
+and prove that they have an open file descriptor for a raw SCSI device.
+
+The next patch will also correct the usage of persistent reservations
+with multipath devices.
+
+It would also be possible to support for Linux's IOC_PR_* ioctls in
+the future, to support NVMe devices.  For now, however, only SCSI is
+supported.
+
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ Makefile                   |   4 +-
+ configure                  |  14 +-
+ docs/interop/pr-helper.rst |  83 +++++
+ docs/pr-manager.rst        |  33 ++
+ scsi/pr-helper.h           |  41 +++
+ scsi/qemu-pr-helper.c      | 735 +++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 905 insertions(+), 5 deletions(-)
+ create mode 100644 docs/interop/pr-helper.rst
+ create mode 100644 scsi/pr-helper.h
+ create mode 100644 scsi/qemu-pr-helper.c
+
+diff --git a/Makefile b/Makefile
+index 81447b1f08..f07c0d7e9c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -382,6 +382,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
+ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
+ fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
+ 
++scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
++
+ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
+ 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
+ 
+@@ -489,7 +491,7 @@ clean:
+ 	rm -f *.msi
+ 	find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
+ 	rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
+-	rm -f fsdev/*.pod
++	rm -f fsdev/*.pod scsi/*.pod
+ 	rm -f qemu-img-cmds.h
+ 	rm -f ui/shader/*-vert.h ui/shader/*-frag.h
+ 	@# May not be present in GENERATED_FILES
+diff --git a/configure b/configure
+index dd73cce62f..14bdf9bb31 100755
+--- a/configure
++++ b/configure
+@@ -5070,16 +5070,22 @@ if test "$want_tools" = "yes" ; then
+   fi
+ fi
+ if test "$softmmu" = yes ; then
+-  if test "$virtfs" != no ; then
+-    if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
++  if test "$linux" = yes; then
++    if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
+       virtfs=yes
+       tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+     else
+       if test "$virtfs" = yes; then
+-        error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
++        error_exit "VirtFS requires libcap devel and libattr devel"
+       fi
+       virtfs=no
+     fi
++    tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
++  else
++    if test "$virtfs" = yes; then
++      error_exit "VirtFS is supported only on Linux"
++    fi
++    virtfs=no
+   fi
+ fi
+ 
+@@ -6545,7 +6551,7 @@ fi
+ 
+ # build tree in object directory in case the source is not in the current directory
+ DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
+-DIRS="$DIRS docs docs/interop fsdev"
++DIRS="$DIRS docs docs/interop fsdev scsi"
+ DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
+ DIRS="$DIRS roms/seabios roms/vgabios"
+ DIRS="$DIRS qapi-generated"
+diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst
+new file mode 100644
+index 0000000000..9f76d5bcf9
+--- /dev/null
++++ b/docs/interop/pr-helper.rst
+@@ -0,0 +1,83 @@
++..
++
++======================================
++Persistent reservation helper protocol
++======================================
++
++QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
++can delegate implementation of persistent reservations to an external
++(and typically privileged) program.  Persistent Reservations allow
++restricting access to block devices to specific initiators in a shared
++storage setup.
++
++For a more detailed reference please refer the the SCSI Primary
++Commands standard, specifically the section on Reservations and the
++"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
++
++This document describes the socket protocol used between QEMU's
++``pr-manager-helper`` object and the external program.
++
++.. contents::
++
++Connection and initialization
++-----------------------------
++
++All data transmitted on the socket is big-endian.
++
++After connecting to the helper program's socket, the helper starts a simple
++feature negotiation process by writing four bytes corresponding to
++the features it exposes (``supported_features``).  QEMU reads it,
++then writes four bytes corresponding to the desired features of the
++helper program (``requested_features``).
++
++If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
++the corresponding feature is not supported by the helper and the connection
++is closed.  On the other hand, it is acceptable for a bit to be 0 in
++``requested_features`` and 1 in ``supported_features``; in this case,
++the helper will not enable the feature.
++
++Right now no feature is defined, so the two parties always write four
++zero bytes.
++
++Command format
++--------------
++
++It is invalid to send multiple commands concurrently on the same
++socket.  It is however possible to connect multiple sockets to the
++helper and send multiple commands to the helper for one or more
++file descriptors.
++
++A command consists of a request and a response.  A request consists
++of a 16-byte SCSI CDB.  A file descriptor must be passed to the helper
++together with the SCSI CDB using ancillary data.
++
++The CDB has the following limitations:
++
++- the command (stored in the first byte) must be one of 0x5E
++  (PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
++
++- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
++  RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
++  for PERSISTENT RESERVE OUT) is limited to 8 KiB.
++
++For PERSISTENT RESERVE OUT, the parameter list is sent right after the
++CDB.  The length of the parameter list is taken from the CDB itself.
++
++The helper's reply has the following structure:
++
++- 4 bytes for the SCSI status
++
++- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN
++  and only if the SCSI status is 0x00, i.e. GOOD)
++
++- 96 bytes for the SCSI sense data
++
++- if the size is nonzero, the payload follows
++
++The sense data is always sent to keep the protocol simple, even though
++it is only valid if the SCSI status is CHECK CONDITION (0x02).
++
++The payload size is always less than or equal to the allocation length
++specified in the CDB for the PERSISTENT RESERVE IN command.
++
++If the protocol is violated, the helper closes the socket.
+diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
+index b6089fb57c..7107e59fb8 100644
+--- a/docs/pr-manager.rst
++++ b/docs/pr-manager.rst
+@@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``::
+           -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
+           -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
+           -device scsi-block,drive=hd
++
++----------------------------------
++Invoking :program:`qemu-pr-helper`
++----------------------------------
++
++QEMU provides an implementation of the persistent reservation helper,
++called :program:`qemu-pr-helper`.  The helper should be started as a
++system service and supports the following option:
++
++-d, --daemon              run in the background
++-q, --quiet               decrease verbosity
++-f, --pidfile=path        PID file when running as a daemon
++-k, --socket=path         path to the socket
++-T, --trace=trace-opts    tracing options
++
++By default, the socket and PID file are placed in the runtime state
++directory, for example :file:`/var/run/qemu-pr-helper.sock` and
++:file:`/var/run/qemu-pr-helper.pid`.  The PID file is not created
++unless :option:`-d` is passed too.
++
++:program:`qemu-pr-helper` can also use the systemd socket activation
++protocol.  In this case, the systemd socket unit should specify a
++Unix stream socket, like this::
++
++    [Socket]
++    ListenStream=/var/run/qemu-pr-helper.sock
++
++After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
++root privileges, except for those capabilities that are needed for
++its operation.  To do this, add the following options:
++
++-u, --user=user           user to drop privileges to
++-g, --group=group         group to drop privileges to
+diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h
+new file mode 100644
+index 0000000000..96c50a9e5f
+--- /dev/null
++++ b/scsi/pr-helper.h
+@@ -0,0 +1,41 @@
++/* Definitions for QEMU's persistent reservation helper daemon
++ *
++ * Copyright (C) 2017 Red Hat, Inc.
++ *
++ * Author:
++ *   Paolo Bonzini <pbonzini@redhat.com>
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++#ifndef QEMU_PR_HELPER_H
++#define QEMU_PR_HELPER_H 1
++
++#include <stdint.h>
++
++#define PR_HELPER_CDB_SIZE     16
++#define PR_HELPER_SENSE_SIZE   96
++#define PR_HELPER_DATA_SIZE    8192
++
++typedef struct PRHelperResponse {
++    int32_t result;
++    int32_t sz;
++    uint8_t sense[PR_HELPER_SENSE_SIZE];
++} PRHelperResponse;
++
++#endif
+diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
+new file mode 100644
+index 0000000000..e39efbd529
+--- /dev/null
++++ b/scsi/qemu-pr-helper.c
+@@ -0,0 +1,735 @@
++/*
++ * Privileged helper to handle persistent reservation commands for QEMU
++ *
++ * Copyright (C) 2017 Red Hat, Inc. <pbonzini@redhat.com>
++ *
++ * Author: Paolo Bonzini <pbonzini@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; under version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "qemu/osdep.h"
++#include <getopt.h>
++#include <sys/ioctl.h>
++#include <linux/dm-ioctl.h>
++#include <scsi/sg.h>
++
++#ifdef CONFIG_LIBCAP
++#include <cap-ng.h>
++#endif
++#include <pwd.h>
++#include <grp.h>
++
++#include "qapi/error.h"
++#include "qemu-common.h"
++#include "qemu/cutils.h"
++#include "qemu/main-loop.h"
++#include "qemu/error-report.h"
++#include "qemu/config-file.h"
++#include "qemu/bswap.h"
++#include "qemu/log.h"
++#include "qemu/systemd.h"
++#include "qapi/util.h"
++#include "qapi/qmp/qstring.h"
++#include "io/channel-socket.h"
++#include "trace/control.h"
++#include "qemu-version.h"
++
++#include "block/aio.h"
++#include "block/thread-pool.h"
++
++#include "scsi/constants.h"
++#include "scsi/utils.h"
++#include "pr-helper.h"
++
++#define PR_OUT_FIXED_PARAM_SIZE 24
++
++static char *socket_path;
++static char *pidfile;
++static enum { RUNNING, TERMINATE, TERMINATING } state;
++static QIOChannelSocket *server_ioc;
++static int server_watch;
++static int num_active_sockets = 1;
++static int verbose;
++
++#ifdef CONFIG_LIBCAP
++static int uid = -1;
++static int gid = -1;
++#endif
++
++static void usage(const char *name)
++{
++    (printf) (
++"Usage: %s [OPTIONS] FILE\n"
++"Persistent Reservation helper program for QEMU\n"
++"\n"
++"  -h, --help                display this help and exit\n"
++"  -V, --version             output version information and exit\n"
++"\n"
++"  -d, --daemon              run in the background\n"
++"  -f, --pidfile=PATH        PID file when running as a daemon\n"
++"                            (default '%s')\n"
++"  -k, --socket=PATH         path to the unix socket\n"
++"                            (default '%s')\n"
++"  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
++"                            specify tracing options\n"
++#ifdef CONFIG_LIBCAP
++"  -u, --user=USER           user to drop privileges to\n"
++"  -g, --group=GROUP         group to drop privileges to\n"
++#endif
++"\n"
++QEMU_HELP_BOTTOM "\n"
++    , name, pidfile, socket_path);
++}
++
++static void version(const char *name)
++{
++    printf(
++"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
++"Written by Paolo Bonzini.\n"
++"\n"
++QEMU_COPYRIGHT "\n"
++"This is free software; see the source for copying conditions.  There is NO\n"
++"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
++    , name);
++}
++
++static void write_pidfile(void)
++{
++    int pidfd;
++    char pidstr[32];
++
++    pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
++    if (pidfd == -1) {
++        error_report("Cannot open pid file, %s", strerror(errno));
++        exit(EXIT_FAILURE);
++    }
++
++    if (lockf(pidfd, F_TLOCK, 0)) {
++        error_report("Cannot lock pid file, %s", strerror(errno));
++        goto fail;
++    }
++    if (ftruncate(pidfd, 0)) {
++        error_report("Failed to truncate pid file");
++        goto fail;
++    }
++
++    snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
++    if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
++        error_report("Failed to write pid file");
++        goto fail;
++    }
++    return;
++
++fail:
++    unlink(pidfile);
++    close(pidfd);
++    exit(EXIT_FAILURE);
++}
++
++/* SG_IO support */
++
++typedef struct PRHelperSGIOData {
++    int fd;
++    const uint8_t *cdb;
++    uint8_t *sense;
++    uint8_t *buf;
++    int sz;              /* input/output */
++    int dir;
++} PRHelperSGIOData;
++
++static int do_sgio_worker(void *opaque)
++{
++    PRHelperSGIOData *data = opaque;
++    struct sg_io_hdr io_hdr;
++    int ret;
++    int status;
++    SCSISense sense_code;
++
++    memset(data->sense, 0, PR_HELPER_SENSE_SIZE);
++    memset(&io_hdr, 0, sizeof(io_hdr));
++    io_hdr.interface_id = 'S';
++    io_hdr.cmd_len = PR_HELPER_CDB_SIZE;
++    io_hdr.cmdp = (uint8_t *)data->cdb;
++    io_hdr.sbp = data->sense;
++    io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE;
++    io_hdr.timeout = 1;
++    io_hdr.dxfer_direction = data->dir;
++    io_hdr.dxferp = (char *)data->buf;
++    io_hdr.dxfer_len = data->sz;
++    ret = ioctl(data->fd, SG_IO, &io_hdr);
++    status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
++                                    &sense_code);
++    if (status == GOOD) {
++        data->sz -= io_hdr.resid;
++    } else {
++        data->sz = 0;
++    }
++
++    if (status == CHECK_CONDITION &&
++        !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
++        scsi_build_sense(data->sense, sense_code);
++    }
++
++    return status;
++}
++
++static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
++                    uint8_t *buf, int *sz, int dir)
++{
++    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
++    int r;
++
++    PRHelperSGIOData data = {
++        .fd = fd,
++        .cdb = cdb,
++        .sense = sense,
++        .buf = buf,
++        .sz = *sz,
++        .dir = dir,
++    };
++
++    r = thread_pool_submit_co(pool, do_sgio_worker, &data);
++    *sz = data.sz;
++    return r;
++}
++
++static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
++                    uint8_t *data, int *resp_sz)
++{
++    return do_sgio(fd, cdb, sense, data, resp_sz,
++                   SG_DXFER_FROM_DEV);
++}
++
++static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
++                     const uint8_t *param, int sz)
++{
++    int resp_sz = sz;
++    return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz,
++                   SG_DXFER_TO_DEV);
++}
++
++/* Client */
++
++typedef struct PRHelperClient {
++    QIOChannelSocket *ioc;
++    Coroutine *co;
++    int fd;
++    uint8_t data[PR_HELPER_DATA_SIZE];
++} PRHelperClient;
++
++typedef struct PRHelperRequest {
++    int fd;
++    size_t sz;
++    uint8_t cdb[PR_HELPER_CDB_SIZE];
++} PRHelperRequest;
++
++static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz,
++                                 Error **errp)
++{
++    int ret = 0;
++
++    while (sz > 0) {
++        int *fds = NULL;
++        size_t nfds = 0;
++        int i;
++        struct iovec iov;
++        ssize_t n_read;
++
++        iov.iov_base = buf;
++        iov.iov_len = sz;
++        n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
++                                        &fds, &nfds, errp);
++
++        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
++            qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
++            continue;
++        }
++        if (n_read <= 0) {
++            ret = n_read ? n_read : -1;
++            goto err;
++        }
++
++        /* Stash one file descriptor per request.  */
++        if (nfds) {
++            bool too_many = false;
++            for (i = 0; i < nfds; i++) {
++                if (client->fd == -1) {
++                    client->fd = fds[i];
++                } else {
++                    close(fds[i]);
++                    too_many = true;
++                }
++            }
++            g_free(fds);
++            if (too_many) {
++                ret = -1;
++                goto err;
++            }
++        }
++
++        buf += n_read;
++        sz -= n_read;
++    }
++
++    return 0;
++
++err:
++    if (client->fd != -1) {
++        close(client->fd);
++        client->fd = -1;
++    }
++    return ret;
++}
++
++static int coroutine_fn prh_read_request(PRHelperClient *client,
++                                         PRHelperRequest *req,
++                                         PRHelperResponse *resp, Error **errp)
++{
++    uint32_t sz;
++
++    if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) {
++        return -1;
++    }
++
++    if (client->fd == -1) {
++        error_setg(errp, "No file descriptor in request.");
++        return -1;
++    }
++
++    if (req->cdb[0] != PERSISTENT_RESERVE_OUT &&
++        req->cdb[0] != PERSISTENT_RESERVE_IN) {
++        error_setg(errp, "Invalid CDB, closing socket.");
++        goto out_close;
++    }
++
++    sz = scsi_cdb_xfer(req->cdb);
++    if (sz > sizeof(client->data)) {
++        goto out_close;
++    }
++
++    if (req->cdb[0] == PERSISTENT_RESERVE_OUT) {
++        if (qio_channel_read_all(QIO_CHANNEL(client->ioc),
++                                 (char *)client->data, sz,
++                                 errp) < 0) {
++            goto out_close;
++        }
++        if ((fcntl(client->fd, F_GETFL) & O_ACCMODE) == O_RDONLY) {
++            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_OPCODE));
++            sz = 0;
++        } else if (sz < PR_OUT_FIXED_PARAM_SIZE) {
++            /* Illegal request, Parameter list length error.  This isn't fatal;
++             * we have read the data, send an error without closing the socket.
++             */
++            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN));
++            sz = 0;
++        }
++        if (sz == 0) {
++            resp->result = CHECK_CONDITION;
++            close(client->fd);
++            client->fd = -1;
++        }
++    }
++
++    req->fd = client->fd;
++    req->sz = sz;
++    client->fd = -1;
++    return sz;
++
++out_close:
++    close(client->fd);
++    client->fd = -1;
++    return -1;
++}
++
++static int coroutine_fn prh_write_response(PRHelperClient *client,
++                                           PRHelperRequest *req,
++                                           PRHelperResponse *resp, Error **errp)
++{
++    ssize_t r;
++    size_t sz;
++
++    if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) {
++        assert(resp->sz <= req->sz && resp->sz <= sizeof(client->data));
++    } else {
++        assert(resp->sz == 0);
++    }
++
++    sz = resp->sz;
++
++    resp->result = cpu_to_be32(resp->result);
++    resp->sz = cpu_to_be32(resp->sz);
++    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
++                              (char *) resp, sizeof(*resp), errp);
++    if (r < 0) {
++        return r;
++    }
++
++    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
++                              (char *) client->data,
++                              sz, errp);
++    return r < 0 ? r : 0;
++}
++
++static void coroutine_fn prh_co_entry(void *opaque)
++{
++    PRHelperClient *client = opaque;
++    Error *local_err = NULL;
++    uint32_t flags;
++    int r;
++
++    qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
++                             false, NULL);
++    qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc),
++                                   qemu_get_aio_context());
++
++    /* A very simple negotiation for future extensibility.  No features
++     * are defined so write 0.
++     */
++    flags = cpu_to_be32(0);
++    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
++                             (char *) &flags, sizeof(flags), NULL);
++    if (r < 0) {
++        goto out;
++    }
++
++    r = qio_channel_read_all(QIO_CHANNEL(client->ioc),
++                             (char *) &flags, sizeof(flags), NULL);
++    if (be32_to_cpu(flags) != 0 || r < 0) {
++        goto out;
++    }
++
++    while (atomic_read(&state) == RUNNING) {
++        PRHelperRequest req;
++        PRHelperResponse resp;
++        int sz;
++
++        sz = prh_read_request(client, &req, &resp, &local_err);
++        if (sz < 0) {
++            break;
++        }
++
++        if (sz > 0) {
++            num_active_sockets++;
++            if (req.cdb[0] == PERSISTENT_RESERVE_OUT) {
++                r = do_pr_out(req.fd, req.cdb, resp.sense,
++                              client->data, sz);
++                resp.sz = 0;
++            } else {
++                resp.sz = sizeof(client->data);
++                r = do_pr_in(req.fd, req.cdb, resp.sense,
++                             client->data, &resp.sz);
++                resp.sz = MIN(resp.sz, sz);
++            }
++            num_active_sockets--;
++            close(req.fd);
++            if (r == -1) {
++                break;
++            }
++            resp.result = r;
++        }
++
++        if (prh_write_response(client, &req, &resp, &local_err) < 0) {
++            break;
++        }
++    }
++
++    if (local_err) {
++        if (verbose == 0) {
++            error_free(local_err);
++        } else {
++            error_report_err(local_err);
++        }
++    }
++
++out:
++    qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
++    object_unref(OBJECT(client->ioc));
++    g_free(client);
++}
++
++static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
++{
++    QIOChannelSocket *cioc;
++    PRHelperClient *prh;
++
++    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
++                                     NULL);
++    if (!cioc) {
++        return TRUE;
++    }
++
++    prh = g_new(PRHelperClient, 1);
++    prh->ioc = cioc;
++    prh->fd = -1;
++    prh->co = qemu_coroutine_create(prh_co_entry, prh);
++    qemu_coroutine_enter(prh->co);
++
++    return TRUE;
++}
++
++
++/*
++ * Check socket parameters compatibility when socket activation is used.
++ */
++static const char *socket_activation_validate_opts(void)
++{
++    if (socket_path != NULL) {
++        return "Unix socket can't be set when using socket activation";
++    }
++
++    return NULL;
++}
++
++static void compute_default_paths(void)
++{
++    if (!socket_path) {
++        socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock");
++    }
++}
++
++static void termsig_handler(int signum)
++{
++    atomic_cmpxchg(&state, RUNNING, TERMINATE);
++    qemu_notify_event();
++}
++
++static void close_server_socket(void)
++{
++    assert(server_ioc);
++
++    g_source_remove(server_watch);
++    server_watch = -1;
++    object_unref(OBJECT(server_ioc));
++    num_active_sockets--;
++}
++
++#ifdef CONFIG_LIBCAP
++static int drop_privileges(void)
++{
++    /* clear all capabilities */
++    capng_clear(CAPNG_SELECT_BOTH);
++
++    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
++                     CAP_SYS_RAWIO) < 0) {
++        return -1;
++    }
++
++    /* Change user/group id, retaining the capabilities.  Because file descriptors
++     * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
++     * fact the helper can run as "nobody").
++     */
++    if (capng_change_id(uid != -1 ? uid : getuid(),
++                        gid != -1 ? gid : getgid(),
++                        CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) {
++        return -1;
++    }
++
++    return 0;
++}
++#endif
++
++int main(int argc, char **argv)
++{
++    const char *sopt = "hVk:fdT:u:g:q";
++    struct option lopt[] = {
++        { "help", no_argument, NULL, 'h' },
++        { "version", no_argument, NULL, 'V' },
++        { "socket", required_argument, NULL, 'k' },
++        { "pidfile", no_argument, NULL, 'f' },
++        { "daemon", no_argument, NULL, 'd' },
++        { "trace", required_argument, NULL, 'T' },
++        { "user", required_argument, NULL, 'u' },
++        { "group", required_argument, NULL, 'g' },
++        { "quiet", no_argument, NULL, 'q' },
++        { NULL, 0, NULL, 0 }
++    };
++    int opt_ind = 0;
++    int quiet = 0;
++    char ch;
++    Error *local_err = NULL;
++    char *trace_file = NULL;
++    bool daemonize = false;
++    unsigned socket_activation;
++
++    struct sigaction sa_sigterm;
++    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
++    sa_sigterm.sa_handler = termsig_handler;
++    sigaction(SIGTERM, &sa_sigterm, NULL);
++    sigaction(SIGINT, &sa_sigterm, NULL);
++    sigaction(SIGHUP, &sa_sigterm, NULL);
++
++    signal(SIGPIPE, SIG_IGN);
++
++    module_call_init(MODULE_INIT_TRACE);
++    module_call_init(MODULE_INIT_QOM);
++    qemu_add_opts(&qemu_trace_opts);
++    qemu_init_exec_dir(argv[0]);
++
++    pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid");
++
++    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
++        switch (ch) {
++        case 'k':
++            socket_path = optarg;
++            if (socket_path[0] != '/') {
++                error_report("socket path must be absolute");
++                exit(EXIT_FAILURE);
++            }
++            break;
++        case 'f':
++            pidfile = optarg;
++            break;
++#ifdef CONFIG_LIBCAP
++        case 'u': {
++            unsigned long res;
++            struct passwd *userinfo = getpwnam(optarg);
++            if (userinfo) {
++                uid = userinfo->pw_uid;
++            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
++                       (uid_t)res == res) {
++                uid = res;
++            } else {
++                error_report("invalid user '%s'", optarg);
++                exit(EXIT_FAILURE);
++            }
++            break;
++        }
++        case 'g': {
++            unsigned long res;
++            struct group *groupinfo = getgrnam(optarg);
++            if (groupinfo) {
++                gid = groupinfo->gr_gid;
++            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
++                       (gid_t)res == res) {
++                gid = res;
++            } else {
++                error_report("invalid group '%s'", optarg);
++                exit(EXIT_FAILURE);
++            }
++            break;
++        }
++#else
++        case 'u':
++        case 'g':
++            error_report("-%c not supported by this %s", ch, argv[0]);
++            exit(1);
++#endif
++        case 'd':
++            daemonize = true;
++            break;
++        case 'q':
++            quiet = 1;
++            break;
++        case 'T':
++            g_free(trace_file);
++            trace_file = trace_opt_parse(optarg);
++            break;
++        case 'V':
++            version(argv[0]);
++            exit(EXIT_SUCCESS);
++            break;
++        case 'h':
++            usage(argv[0]);
++            exit(EXIT_SUCCESS);
++            break;
++        case '?':
++            error_report("Try `%s --help' for more information.", argv[0]);
++            exit(EXIT_FAILURE);
++        }
++    }
++
++    /* set verbosity */
++    verbose = !quiet;
++
++    if (!trace_init_backends()) {
++        exit(EXIT_FAILURE);
++    }
++    trace_init_file(trace_file);
++    qemu_set_log(LOG_TRACE);
++
++    socket_activation = check_socket_activation();
++    if (socket_activation == 0) {
++        SocketAddress saddr;
++        compute_default_paths();
++        saddr = (SocketAddress){
++            .type = SOCKET_ADDRESS_TYPE_UNIX,
++            .u.q_unix.path = g_strdup(socket_path)
++        };
++        server_ioc = qio_channel_socket_new();
++        if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {
++            object_unref(OBJECT(server_ioc));
++            error_report_err(local_err);
++            return 1;
++        }
++        g_free(saddr.u.q_unix.path);
++    } else {
++        /* Using socket activation - check user didn't use -p etc. */
++        const char *err_msg = socket_activation_validate_opts();
++        if (err_msg != NULL) {
++            error_report("%s", err_msg);
++            exit(EXIT_FAILURE);
++        }
++
++        /* Can only listen on a single socket.  */
++        if (socket_activation > 1) {
++            error_report("%s does not support socket activation with LISTEN_FDS > 1",
++                         argv[0]);
++            exit(EXIT_FAILURE);
++        }
++        server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
++                                               &local_err);
++        if (server_ioc == NULL) {
++            error_report("Failed to use socket activation: %s",
++                         error_get_pretty(local_err));
++            exit(EXIT_FAILURE);
++        }
++        socket_path = NULL;
++    }
++
++    if (qemu_init_main_loop(&local_err)) {
++        error_report_err(local_err);
++        exit(EXIT_FAILURE);
++    }
++
++    server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
++                                         G_IO_IN,
++                                         accept_client,
++                                         NULL, NULL);
++
++#ifdef CONFIG_LIBCAP
++    if (drop_privileges() < 0) {
++        error_report("Failed to drop privileges: %s", strerror(errno));
++        exit(EXIT_FAILURE);
++    }
++#endif
++
++    if (daemonize) {
++        if (daemon(0, 0) < 0) {
++            error_report("Failed to daemonize: %s", strerror(errno));
++            exit(EXIT_FAILURE);
++        }
++        write_pidfile();
++    }
++
++    state = RUNNING;
++    do {
++        main_loop_wait(false);
++        if (state == TERMINATE) {
++            state = TERMINATING;
++            close_server_socket();
++        }
++    } while (num_active_sockets > 0);
++
++    exit(EXIT_SUCCESS);
++}
diff --git a/0013-scsi-add-multipath-support-to-qemu-pr-helper.patch b/0013-scsi-add-multipath-support-to-qemu-pr-helper.patch
new file mode 100644
index 0000000..46ab354
--- /dev/null
+++ b/0013-scsi-add-multipath-support-to-qemu-pr-helper.patch
@@ -0,0 +1,675 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 22 Aug 2017 06:50:55 +0200
+Subject: [PATCH] scsi: add multipath support to qemu-pr-helper
+
+Proper support of persistent reservation for multipath devices requires
+communication with the multipath daemon, so that the reservation is
+registered and applied when a path comes up.  The device mapper
+utilities provide a library to do so; this patch makes qemu-pr-helper.c
+detect multipath devices and, when one is found, delegate the operation
+to libmpathpersist.
+
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ Makefile              |   3 +
+ configure             |  54 ++++++++
+ docs/pr-manager.rst   |  27 ++++
+ include/scsi/utils.h  |   4 +
+ scsi/qemu-pr-helper.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ scsi/utils.c          |  10 ++
+ 6 files changed, 452 insertions(+), 3 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index f07c0d7e9c..060c089af9 100644
+--- a/Makefile
++++ b/Makefile
+@@ -383,6 +383,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
+ fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
+ 
+ scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
++ifdef CONFIG_MPATH
++scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
++endif
+ 
+ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
+ 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
+diff --git a/configure b/configure
+index 14bdf9bb31..9eeb3ebf70 100755
+--- a/configure
++++ b/configure
+@@ -286,6 +286,7 @@ pixman=""
+ sdl=""
+ sdlabi=""
+ virtfs=""
++mpath=""
+ vnc="yes"
+ sparse="no"
+ vde=""
+@@ -948,6 +949,10 @@ for opt do
+   ;;
+   --enable-virtfs) virtfs="yes"
+   ;;
++  --disable-mpath) mpath="no"
++  ;;
++  --enable-mpath) mpath="yes"
++  ;;
+   --disable-vnc) vnc="no"
+   ;;
+   --enable-vnc) vnc="yes"
+@@ -1491,6 +1496,7 @@ disabled with --disable-FEATURE, default is enabled if available:
+   vnc-png         PNG compression for VNC server
+   cocoa           Cocoa UI (Mac OS X only)
+   virtfs          VirtFS
++  mpath           Multipath persistent reservation passthrough
+   xen             xen backend driver support
+   xen-pci-passthrough
+   brlapi          BrlAPI (Braile)
+@@ -3335,6 +3341,38 @@ else
+   pixman_libs="-L\$(BUILD_DIR)/pixman/pixman/.libs -lpixman-1"
+ fi
+ 
++##########################################
++# libmpathpersist probe
++
++if test "$mpath" != "no" ; then
++  cat > $TMPC <<EOF
++#include <libudev.h>
++#include <mpath_persist.h>
++unsigned mpath_mx_alloc_len = 1024;
++int logsink;
++static struct config *multipath_conf;
++extern struct udev *udev;
++extern struct config *get_multipath_config(void);
++extern void put_multipath_config(struct config *conf);
++struct udev *udev;
++struct config *get_multipath_config(void) { return multipath_conf; }
++void put_multipath_config(struct config *conf) { }
++
++int main(void) {
++    udev = udev_new();
++    multipath_conf = mpath_lib_init();
++    return 0;
++}
++EOF
++  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
++    mpathpersist=yes
++  else
++    mpathpersist=no
++  fi
++else
++  mpathpersist=no
++fi
++
+ ##########################################
+ # libcap probe
+ 
+@@ -5080,12 +5118,24 @@ if test "$softmmu" = yes ; then
+       fi
+       virtfs=no
+     fi
++    if test "$mpath" != no && test "$mpathpersist" = yes ; then
++      mpath=yes
++    else
++      if test "$mpath" = yes; then
++        error_exit "Multipath requires libmpathpersist devel"
++      fi
++      mpath=no
++    fi
+     tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
+   else
+     if test "$virtfs" = yes; then
+       error_exit "VirtFS is supported only on Linux"
+     fi
+     virtfs=no
++    if test "$mpath" = yes; then
++      error_exit "Multipath is supported only on Linux"
++    fi
++    mpath=no
+   fi
+ fi
+ 
+@@ -5332,6 +5382,7 @@ echo "Audio drivers     $audio_drv_list"
+ echo "Block whitelist (rw) $block_drv_rw_whitelist"
+ echo "Block whitelist (ro) $block_drv_ro_whitelist"
+ echo "VirtFS support    $virtfs"
++echo "Multipath support $mpath"
+ echo "VNC support       $vnc"
+ if test "$vnc" = "yes" ; then
+     echo "VNC SASL support  $vnc_sasl"
+@@ -5779,6 +5830,9 @@ fi
+ if test "$virtfs" = "yes" ; then
+   echo "CONFIG_VIRTFS=y" >> $config_host_mak
+ fi
++if test "$mpath" = "yes" ; then
++  echo "CONFIG_MPATH=y" >> $config_host_mak
++fi
+ if test "$vhost_scsi" = "yes" ; then
+   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
+ fi
+diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
+index 7107e59fb8..9b1de198b1 100644
+--- a/docs/pr-manager.rst
++++ b/docs/pr-manager.rst
+@@ -60,6 +60,7 @@ system service and supports the following option:
+ 
+ -d, --daemon              run in the background
+ -q, --quiet               decrease verbosity
++-v, --verbose             increase verbosity
+ -f, --pidfile=path        PID file when running as a daemon
+ -k, --socket=path         path to the socket
+ -T, --trace=trace-opts    tracing options
+@@ -82,3 +83,29 @@ its operation.  To do this, add the following options:
+ 
+ -u, --user=user           user to drop privileges to
+ -g, --group=group         group to drop privileges to
++
++---------------------------------------------
++Multipath devices and persistent reservations
++---------------------------------------------
++
++Proper support of persistent reservation for multipath devices requires
++communication with the multipath daemon, so that the reservation is
++registered and applied when a path is newly discovered or becomes online
++again.  :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
++library was available on the system at build time.
++
++As of August 2017, a reservation key must be specified in ``multipath.conf``
++for ``multipathd`` to check for persistent reservation for newly
++discovered paths or reinstated paths.  The attribute can be added
++to the ``defaults`` section or the ``multipaths`` section; for example::
++
++    multipaths {
++        multipath {
++            wwid   XXXXXXXXXXXXXXXX
++            alias      yellow
++            reservation_key  0x123abc
++        }
++    }
++
++Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
++its usage on regular SCSI devices.
+diff --git a/include/scsi/utils.h b/include/scsi/utils.h
+index d301b31768..00a4bdb080 100644
+--- a/include/scsi/utils.h
++++ b/include/scsi/utils.h
+@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR;
+ extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+ /* Command aborted, Logical Unit failure */
+ extern const struct SCSISense sense_code_LUN_FAILURE;
++/* Command aborted, LUN Communication failure */
++extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
+ /* Command aborted, Overlapped Commands Attempted */
+ extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
+ /* LUN not ready, Capacity data has changed */
+ extern const struct SCSISense sense_code_CAPACITY_CHANGED;
++/* Unit attention, SCSI bus reset */
++extern const struct SCSISense sense_code_SCSI_BUS_RESET;
+ /* LUN not ready, Medium not present */
+ extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
+ /* Unit attention, Power on, reset or bus device reset occurred */
+diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
+index e39efbd529..be6d1fbade 100644
+--- a/scsi/qemu-pr-helper.c
++++ b/scsi/qemu-pr-helper.c
+@@ -30,6 +30,12 @@
+ #include <pwd.h>
+ #include <grp.h>
+ 
++#ifdef CONFIG_MPATH
++#include <libudev.h>
++#include <mpath_cmd.h>
++#include <mpath_persist.h>
++#endif
++
+ #include "qapi/error.h"
+ #include "qemu-common.h"
+ #include "qemu/cutils.h"
+@@ -60,6 +66,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state;
+ static QIOChannelSocket *server_ioc;
+ static int server_watch;
+ static int num_active_sockets = 1;
++static int noisy;
+ static int verbose;
+ 
+ #ifdef CONFIG_LIBCAP
+@@ -204,9 +211,327 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
+     return r;
+ }
+ 
++/* Device mapper interface */
++
++#ifdef CONFIG_MPATH
++#define CONTROL_PATH "/dev/mapper/control"
++
++typedef struct DMData {
++    struct dm_ioctl dm;
++    uint8_t data[1024];
++} DMData;
++
++static int control_fd;
++
++static void *dm_ioctl(int ioc, struct dm_ioctl *dm)
++{
++    static DMData d;
++    memcpy(&d.dm, dm, sizeof(d.dm));
++    QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec));
++
++    d.dm.version[0] = DM_VERSION_MAJOR;
++    d.dm.version[1] = 0;
++    d.dm.version[2] = 0;
++    d.dm.data_size = 1024;
++    d.dm.data_start = offsetof(DMData, data);
++    if (ioctl(control_fd, ioc, &d) < 0) {
++        return NULL;
++    }
++    memcpy(dm, &d.dm, sizeof(d.dm));
++    return &d.data;
++}
++
++static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm)
++{
++    struct stat st;
++    int r;
++
++    r = fstat(fd, &st);
++    if (r < 0) {
++        perror("fstat");
++        exit(1);
++    }
++
++    dm->dev = st.st_rdev;
++    return dm_ioctl(ioc, dm);
++}
++
++static void dm_init(void)
++{
++    control_fd = open(CONTROL_PATH, O_RDWR);
++    if (control_fd < 0) {
++        perror("Cannot open " CONTROL_PATH);
++        exit(1);
++    }
++    struct dm_ioctl dm = { 0 };
++    if (!dm_ioctl(DM_VERSION, &dm)) {
++        perror("ioctl");
++        exit(1);
++    }
++    if (dm.version[0] != DM_VERSION_MAJOR) {
++        fprintf(stderr, "Unsupported device mapper interface");
++        exit(1);
++    }
++}
++
++/* Variables required by libmultipath and libmpathpersist.  */
++QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN);
++static struct config *multipath_conf;
++unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE;
++int logsink;
++struct udev *udev;
++
++extern struct config *get_multipath_config(void);
++struct config *get_multipath_config(void)
++{
++    return multipath_conf;
++}
++
++extern void put_multipath_config(struct config *conf);
++void put_multipath_config(struct config *conf)
++{
++}
++
++static void multipath_pr_init(void)
++{
++    udev = udev_new();
++    multipath_conf = mpath_lib_init();
++}
++
++static int is_mpath(int fd)
++{
++    struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG };
++    struct dm_target_spec *tgt;
++
++    tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm);
++    if (!tgt) {
++        if (errno == ENXIO) {
++            return 0;
++        }
++        perror("ioctl");
++        exit(EXIT_FAILURE);
++    }
++    return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME);
++}
++
++static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
++{
++    switch (r) {
++    case MPATH_PR_SUCCESS:
++        return GOOD;
++    case MPATH_PR_SENSE_NOT_READY:
++    case MPATH_PR_SENSE_MEDIUM_ERROR:
++    case MPATH_PR_SENSE_HARDWARE_ERROR:
++    case MPATH_PR_SENSE_ABORTED_COMMAND:
++        {
++            /* libmpathpersist ate the exact sense.  Try to find it by
++             * issuing TEST UNIT READY.
++             */
++            uint8_t cdb[6] = { TEST_UNIT_READY };
++            int sz = 0;
++            return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE);
++        }
++
++    case MPATH_PR_SENSE_UNIT_ATTENTION:
++        /* Congratulations libmpathpersist, you ruined the Unit Attention...
++         * Return a heavyweight one.
++         */
++        scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET));
++        return CHECK_CONDITION;
++    case MPATH_PR_SENSE_INVALID_OP:
++        /* Only one valid sense.  */
++        scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
++        return CHECK_CONDITION;
++    case MPATH_PR_ILLEGAL_REQ:
++        /* Guess.  */
++        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
++        return CHECK_CONDITION;
++    case MPATH_PR_NO_SENSE:
++        scsi_build_sense(sense, SENSE_CODE(NO_SENSE));
++        return CHECK_CONDITION;
++
++    case MPATH_PR_RESERV_CONFLICT:
++        return RESERVATION_CONFLICT;
++
++    case MPATH_PR_OTHER:
++    default:
++        scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE));
++        return CHECK_CONDITION;
++    }
++}
++
++static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
++                           uint8_t *data, int sz)
++{
++    int rq_servact = cdb[1];
++    struct prin_resp resp;
++    size_t written;
++    int r;
++
++    switch (rq_servact) {
++    case MPATH_PRIN_RKEY_SA:
++    case MPATH_PRIN_RRES_SA:
++    case MPATH_PRIN_RCAP_SA:
++        break;
++    case MPATH_PRIN_RFSTAT_SA:
++        /* Nobody implements it anyway, so bail out. */
++    default:
++        /* Cannot parse any other output.  */
++        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
++        return CHECK_CONDITION;
++    }
++
++    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
++    if (r == MPATH_PR_SUCCESS) {
++        switch (rq_servact) {
++        case MPATH_PRIN_RKEY_SA:
++        case MPATH_PRIN_RRES_SA: {
++            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
++            assert(sz >= 8);
++            written = MIN(out->additional_length + 8, sz);
++            stl_be_p(&data[0], out->prgeneration);
++            stl_be_p(&data[4], out->additional_length);
++            memcpy(&data[8], out->key_list, written - 8);
++            break;
++        }
++        case MPATH_PRIN_RCAP_SA: {
++            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
++            assert(sz >= 6);
++            written = 6;
++            stw_be_p(&data[0], out->length);
++            data[2] = out->flags[0];
++            data[3] = out->flags[1];
++            stw_be_p(&data[4], out->pr_type_mask);
++            break;
++        }
++        default:
++            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
++            return CHECK_CONDITION;
++        }
++        assert(written <= sz);
++        memset(data + written, 0, sz - written);
++    }
++
++    return mpath_reconstruct_sense(fd, r, sense);
++}
++
++static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
++                            const uint8_t *param, int sz)
++{
++    int rq_servact = cdb[1];
++    int rq_scope = cdb[2] >> 4;
++    int rq_type = cdb[2] & 0xf;
++    struct prout_param_descriptor paramp;
++    char transportids[PR_HELPER_DATA_SIZE];
++    int r;
++
++    switch (rq_servact) {
++    case MPATH_PROUT_REG_SA:
++    case MPATH_PROUT_RES_SA:
++    case MPATH_PROUT_REL_SA:
++    case MPATH_PROUT_CLEAR_SA:
++    case MPATH_PROUT_PREE_SA:
++    case MPATH_PROUT_PREE_AB_SA:
++    case MPATH_PROUT_REG_IGN_SA:
++        break;
++    case MPATH_PROUT_REG_MOV_SA:
++        /* Not supported by struct prout_param_descriptor.  */
++    default:
++        /* Cannot parse any other input.  */
++        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
++        return CHECK_CONDITION;
++    }
++
++    /* Convert input data, especially transport IDs, to the structs
++     * used by libmpathpersist (which, of course, will immediately
++     * do the opposite).
++     */
++    memset(&paramp, 0, sizeof(paramp));
++    memcpy(&paramp.key, &param[0], 8);
++    memcpy(&paramp.sa_key, &param[8], 8);
++    paramp.sa_flags = param[10];
++    if (sz > PR_OUT_FIXED_PARAM_SIZE) {
++        size_t transportid_len;
++        int i, j;
++        if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) {
++            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN));
++            return CHECK_CONDITION;
++        }
++        transportid_len = ldl_be_p(&param[24]) + PR_OUT_FIXED_PARAM_SIZE + 4;
++        if (transportid_len > sz) {
++            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
++            return CHECK_CONDITION;
++        }
++        for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) {
++            struct transportid *id = (struct transportid *) &transportids[j];
++            int len;
++
++            id->format_code = param[i] & 0xc0;
++            id->protocol_id = param[i] & 0x0f;
++            switch (param[i] & 0xcf) {
++            case 0:
++                /* FC transport.  */
++                if (i + 24 > transportid_len) {
++                    goto illegal_req;
++                }
++                memcpy(id->n_port_name, &param[i + 8], 8);
++                j += offsetof(struct transportid, n_port_name[8]);
++                i += 24;
++                break;
++            case 3:
++            case 0x43:
++                /* iSCSI transport.  */
++                len = lduw_be_p(&param[i + 2]);
++                if (len > 252 || (len & 3) || i + len + 4 > transportid_len) {
++                    /* For format code 00, the standard says the maximum is 223
++                     * plus the NUL terminator.  For format code 01 there is no
++                     * maximum length, but libmpathpersist ignores the first
++                     * byte of id->iscsi_name so our maximum is 252.
++                     */
++                    goto illegal_req;
++                }
++                if (memchr(&param[i + 4], 0, len) == NULL) {
++                    goto illegal_req;
++                }
++                memcpy(id->iscsi_name, &param[i + 2], len + 2);
++                j += offsetof(struct transportid, iscsi_name[len + 2]);
++                i += len + 4;
++                break;
++            case 6:
++                /* SAS transport.  */
++                if (i + 24 > transportid_len) {
++                    goto illegal_req;
++                }
++                memcpy(id->sas_address, &param[i + 4], 8);
++                j += offsetof(struct transportid, sas_address[8]);
++                i += 24;
++                break;
++            default:
++            illegal_req:
++                scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
++                return CHECK_CONDITION;
++            }
++
++            paramp.trnptid_list[paramp.num_transportid++] = id;
++        }
++    }
++
++    r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type,
++                                     &paramp, noisy, verbose);
++    return mpath_reconstruct_sense(fd, r, sense);
++}
++#endif
++
+ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
+                     uint8_t *data, int *resp_sz)
+ {
++#ifdef CONFIG_MPATH
++    if (is_mpath(fd)) {
++        /* multipath_pr_in fills the whole input buffer.  */
++        return multipath_pr_in(fd, cdb, sense, data, *resp_sz);
++    }
++#endif
++
+     return do_sgio(fd, cdb, sense, data, resp_sz,
+                    SG_DXFER_FROM_DEV);
+ }
+@@ -214,7 +539,14 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
+ static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
+                      const uint8_t *param, int sz)
+ {
+-    int resp_sz = sz;
++    int resp_sz;
++#ifdef CONFIG_MPATH
++    if (is_mpath(fd)) {
++        return multipath_pr_out(fd, cdb, sense, param, sz);
++    }
++#endif
++
++    resp_sz = sz;
+     return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz,
+                    SG_DXFER_TO_DEV);
+ }
+@@ -525,6 +857,14 @@ static int drop_privileges(void)
+         return -1;
+     }
+ 
++#ifdef CONFIG_MPATH
++    /* For /dev/mapper/control ioctls */
++    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
++                     CAP_SYS_ADMIN) < 0) {
++        return -1;
++    }
++#endif
++
+     /* Change user/group id, retaining the capabilities.  Because file descriptors
+      * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
+      * fact the helper can run as "nobody").
+@@ -541,7 +881,7 @@ static int drop_privileges(void)
+ 
+ int main(int argc, char **argv)
+ {
+-    const char *sopt = "hVk:fdT:u:g:q";
++    const char *sopt = "hVk:fdT:u:g:vq";
+     struct option lopt[] = {
+         { "help", no_argument, NULL, 'h' },
+         { "version", no_argument, NULL, 'V' },
+@@ -551,10 +891,12 @@ int main(int argc, char **argv)
+         { "trace", required_argument, NULL, 'T' },
+         { "user", required_argument, NULL, 'u' },
+         { "group", required_argument, NULL, 'g' },
++        { "verbose", no_argument, NULL, 'v' },
+         { "quiet", no_argument, NULL, 'q' },
+         { NULL, 0, NULL, 0 }
+     };
+     int opt_ind = 0;
++    int loglevel = 1;
+     int quiet = 0;
+     char ch;
+     Error *local_err = NULL;
+@@ -631,6 +973,9 @@ int main(int argc, char **argv)
+         case 'q':
+             quiet = 1;
+             break;
++        case 'v':
++            ++loglevel;
++            break;
+         case 'T':
+             g_free(trace_file);
+             trace_file = trace_opt_parse(optarg);
+@@ -650,7 +995,8 @@ int main(int argc, char **argv)
+     }
+ 
+     /* set verbosity */
+-    verbose = !quiet;
++    noisy = !quiet && (loglevel >= 3);
++    verbose = quiet ? 0 : MIN(loglevel, 3);
+ 
+     if (!trace_init_backends()) {
+         exit(EXIT_FAILURE);
+@@ -658,6 +1004,11 @@ int main(int argc, char **argv)
+     trace_init_file(trace_file);
+     qemu_set_log(LOG_TRACE);
+ 
++#ifdef CONFIG_MPATH
++    dm_init();
++    multipath_pr_init();
++#endif
++
+     socket_activation = check_socket_activation();
+     if (socket_activation == 0) {
+         SocketAddress saddr;
+diff --git a/scsi/utils.c b/scsi/utils.c
+index fab60bdf20..5684951b12 100644
+--- a/scsi/utils.c
++++ b/scsi/utils.c
+@@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
+     .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
+ };
+ 
++/* Command aborted, LUN Communication Failure */
++const struct SCSISense sense_code_LUN_COMM_FAILURE = {
++    .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
++};
++
+ /* Unit attention, Capacity data has changed */
+ const struct SCSISense sense_code_CAPACITY_CHANGED = {
+     .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
+@@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET = {
+     .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
+ };
+ 
++/* Unit attention, SCSI bus reset */
++const struct SCSISense sense_code_SCSI_BUS_RESET = {
++    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02
++};
++
+ /* Unit attention, No medium */
+ const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+     .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
diff --git a/0014-scsi-add-persistent-reservation-manager-using-qemu-p.patch b/0014-scsi-add-persistent-reservation-manager-using-qemu-p.patch
new file mode 100644
index 0000000..af6ecc9
--- /dev/null
+++ b/0014-scsi-add-persistent-reservation-manager-using-qemu-p.patch
@@ -0,0 +1,330 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Mon, 21 Aug 2017 18:58:56 +0200
+Subject: [PATCH] scsi: add persistent reservation manager using qemu-pr-helper
+
+This adds a concrete subclass of pr-manager that talks to qemu-pr-helper.
+
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ scsi/Makefile.objs       |   2 +-
+ scsi/pr-manager-helper.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 303 insertions(+), 1 deletion(-)
+ create mode 100644 scsi/pr-manager-helper.c
+
+diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
+index 5496d2ae6a..4d25e476cf 100644
+--- a/scsi/Makefile.objs
++++ b/scsi/Makefile.objs
+@@ -1,3 +1,3 @@
+ block-obj-y += utils.o
+ 
+-block-obj-$(CONFIG_LINUX) += pr-manager.o
++block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o
+diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c
+new file mode 100644
+index 0000000000..82ff6b6123
+--- /dev/null
++++ b/scsi/pr-manager-helper.c
+@@ -0,0 +1,302 @@
++/*
++ * Persistent reservation manager that talks to qemu-pr-helper
++ *
++ * Copyright (c) 2017 Red Hat, Inc.
++ *
++ * Author: Paolo Bonzini <pbonzini@redhat.com>
++ *
++ * This code is licensed under the LGPL v2.1 or later.
++ *
++ */
++
++#include "qemu/osdep.h"
++#include "qapi/error.h"
++#include "scsi/constants.h"
++#include "scsi/pr-manager.h"
++#include "scsi/utils.h"
++#include "io/channel.h"
++#include "io/channel-socket.h"
++#include "pr-helper.h"
++
++#include <scsi/sg.h>
++
++#define PR_MAX_RECONNECT_ATTEMPTS 5
++
++#define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
++
++#define PR_MANAGER_HELPER(obj) \
++     OBJECT_CHECK(PRManagerHelper, (obj), \
++                  TYPE_PR_MANAGER_HELPER)
++
++typedef struct PRManagerHelper {
++    /* <private> */
++    PRManager parent;
++
++    char *path;
++
++    QemuMutex lock;
++    QIOChannel *ioc;
++} PRManagerHelper;
++
++/* Called with lock held.  */
++static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
++                                  void *buf, int sz, Error **errp)
++{
++    ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
++
++    if (r < 0) {
++        object_unref(OBJECT(pr_mgr->ioc));
++        pr_mgr->ioc = NULL;
++        return -EINVAL;
++    }
++
++    return 0;
++}
++
++/* Called with lock held.  */
++static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
++                                   int fd,
++                                   const void *buf, int sz, Error **errp)
++{
++    size_t nfds = (fd != -1);
++    while (sz > 0) {
++        struct iovec iov;
++        ssize_t n_written;
++
++        iov.iov_base = (void *)buf;
++        iov.iov_len = sz;
++        n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
++                                            nfds ? &fd : NULL, nfds, errp);
++
++        if (n_written <= 0) {
++            assert(n_written != QIO_CHANNEL_ERR_BLOCK);
++            object_unref(OBJECT(pr_mgr->ioc));
++            return n_written < 0 ? -EINVAL : 0;
++        }
++
++        nfds = 0;
++        buf += n_written;
++        sz -= n_written;
++    }
++
++    return 0;
++}
++
++/* Called with lock held.  */
++static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
++                                        Error **errp)
++{
++    char *path = g_strdup(pr_mgr->path);
++    SocketAddress saddr = {
++        .type = SOCKET_ADDRESS_TYPE_UNIX,
++        .u.q_unix.path = path
++    };
++    QIOChannelSocket *sioc = qio_channel_socket_new();
++    Error *local_err = NULL;
++
++    uint32_t flags;
++    int r;
++
++    assert(!pr_mgr->ioc);
++    qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
++    qio_channel_socket_connect_sync(sioc,
++                                    &saddr,
++                                    &local_err);
++    g_free(path);
++    if (local_err) {
++        object_unref(OBJECT(sioc));
++        error_propagate(errp, local_err);
++        return -ENOTCONN;
++    }
++
++    qio_channel_set_delay(QIO_CHANNEL(sioc), false);
++    pr_mgr->ioc = QIO_CHANNEL(sioc);
++
++    /* A simple feature negotation protocol, even though there is
++     * no optional feature right now.
++     */
++    r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp);
++    if (r < 0) {
++        goto out_close;
++    }
++
++    flags = 0;
++    r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp);
++    if (r < 0) {
++        goto out_close;
++    }
++
++    return 0;
++
++out_close:
++    object_unref(OBJECT(pr_mgr->ioc));
++    pr_mgr->ioc = NULL;
++    return r;
++}
++
++static int pr_manager_helper_run(PRManager *p,
++                                 int fd, struct sg_io_hdr *io_hdr)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
++
++    uint32_t len;
++    PRHelperResponse resp;
++    int ret;
++    int expected_dir;
++    int attempts;
++    uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
++
++    if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
++        return -EINVAL;
++    }
++
++    memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
++    assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
++    expected_dir =
++        (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
++    if (io_hdr->dxfer_direction != expected_dir) {
++        return -EINVAL;
++    }
++
++    len = scsi_cdb_xfer(cdb);
++    if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
++        return -EINVAL;
++    }
++
++    qemu_mutex_lock(&pr_mgr->lock);
++
++    /* Try to reconnect while sending the CDB.  */
++    for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
++        if (!pr_mgr->ioc) {
++            ret = pr_manager_helper_initialize(pr_mgr, NULL);
++            if (ret < 0) {
++                qemu_mutex_unlock(&pr_mgr->lock);
++                g_usleep(G_USEC_PER_SEC);
++                qemu_mutex_lock(&pr_mgr->lock);
++                continue;
++            }
++        }
++
++        ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL);
++        if (ret >= 0) {
++            break;
++        }
++    }
++    if (ret < 0) {
++        goto out;
++    }
++
++    /* After sending the CDB, any communications failure causes the
++     * command to fail.  The failure is transient, retrying the command
++     * will invoke pr_manager_helper_initialize again.
++     */
++    if (expected_dir == SG_DXFER_TO_DEV) {
++        io_hdr->resid = io_hdr->dxfer_len - len;
++        ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL);
++        if (ret < 0) {
++            goto out;
++        }
++    }
++    ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL);
++    if (ret < 0) {
++        goto out;
++    }
++
++    resp.result = be32_to_cpu(resp.result);
++    resp.sz = be32_to_cpu(resp.sz);
++    if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) {
++        assert(resp.sz <= io_hdr->dxfer_len);
++        ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL);
++        if (ret < 0) {
++            goto out;
++        }
++        io_hdr->resid = io_hdr->dxfer_len - resp.sz;
++    } else {
++        assert(resp.sz == 0);
++    }
++
++    io_hdr->status = resp.result;
++    if (resp.result == CHECK_CONDITION) {
++        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
++        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
++        memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
++    }
++
++out:
++    if (ret < 0) {
++        int sense_len = scsi_build_sense(io_hdr->sbp,
++                                         SENSE_CODE(LUN_COMM_FAILURE));
++        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
++        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
++        io_hdr->status = CHECK_CONDITION;
++    }
++    qemu_mutex_unlock(&pr_mgr->lock);
++    return ret;
++}
++
++static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
++
++    qemu_mutex_lock(&pr_mgr->lock);
++    pr_manager_helper_initialize(pr_mgr, errp);
++    qemu_mutex_unlock(&pr_mgr->lock);
++}
++
++static char *get_path(Object *obj, Error **errp)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
++
++    return g_strdup(pr_mgr->path);
++}
++
++static void set_path(Object *obj, const char *str, Error **errp)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
++
++    g_free(pr_mgr->path);
++    pr_mgr->path = g_strdup(str);
++}
++
++static void pr_manager_helper_instance_finalize(Object *obj)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
++
++    object_unref(OBJECT(pr_mgr->ioc));
++    qemu_mutex_destroy(&pr_mgr->lock);
++}
++
++static void pr_manager_helper_instance_init(Object *obj)
++{
++    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
++
++    qemu_mutex_init(&pr_mgr->lock);
++}
++
++static void pr_manager_helper_class_init(ObjectClass *klass,
++                                         void *class_data G_GNUC_UNUSED)
++{
++    PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
++    UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
++
++    object_class_property_add_str(klass, "path", get_path, set_path,
++                                  &error_abort);
++    uc_klass->complete = pr_manager_helper_complete;
++    prmgr_klass->run = pr_manager_helper_run;
++}
++
++static const TypeInfo pr_manager_helper_info = {
++    .parent = TYPE_PR_MANAGER,
++    .name = TYPE_PR_MANAGER_HELPER,
++    .instance_size = sizeof(PRManagerHelper),
++    .instance_init = pr_manager_helper_instance_init,
++    .instance_finalize = pr_manager_helper_instance_finalize,
++    .class_init = pr_manager_helper_class_init,
++};
++
++static void pr_manager_helper_register_types(void)
++{
++    type_register_static(&pr_manager_helper_info);
++}
++
++type_init(pr_manager_helper_register_types);
diff --git a/0101-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch b/0101-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
new file mode 100644
index 0000000..8a8b374
--- /dev/null
+++ b/0101-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
@@ -0,0 +1,30 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Tue, 29 Aug 2017 17:03:30 +0100
+Subject: [PATCH] crypto: fix test cert generation to not use SHA1 algorithm
+
+GNUTLS 3.6.0 marked SHA1 as untrusted for certificates.
+Unfortunately the gnutls_x509_crt_sign() method we are
+using to create certificates in the test suite is fixed
+to always use SHA1. We must switch to a different method
+and explicitly ask for SHA256.
+
+Reviewed-by: Eric Blake <eblake@redhat.com>
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ tests/crypto-tls-x509-helpers.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tests/crypto-tls-x509-helpers.c b/tests/crypto-tls-x509-helpers.c
+index 64073d3bd3..173d4e28fb 100644
+--- a/tests/crypto-tls-x509-helpers.c
++++ b/tests/crypto-tls-x509-helpers.c
+@@ -406,7 +406,8 @@ test_tls_generate_cert(QCryptoTLSTestCertReq *req,
+      * If no 'ca' is set then we are self signing
+      * the cert. This is done for the root CA certs
+      */
+-    err = gnutls_x509_crt_sign(crt, ca ? ca : crt, privkey);
++    err = gnutls_x509_crt_sign2(crt, ca ? ca : crt, privkey,
++                                GNUTLS_DIG_SHA256, 0);
+     if (err < 0) {
+         g_critical("Failed to sign certificate %s",
+                    gnutls_strerror(err));
diff --git a/0102-io-fix-check-for-handshake-completion-in-TLS-test.patch b/0102-io-fix-check-for-handshake-completion-in-TLS-test.patch
new file mode 100644
index 0000000..261cb76
--- /dev/null
+++ b/0102-io-fix-check-for-handshake-completion-in-TLS-test.patch
@@ -0,0 +1,30 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Tue, 29 Aug 2017 17:04:52 +0100
+Subject: [PATCH] io: fix check for handshake completion in TLS test
+
+The TLS I/O channel test had mistakenly used && instead
+of || when checking for handshake completion. As a
+result it could terminate the handshake process before
+it had actually completed. This was harmless before but
+changes in GNUTLS 3.6.0 exposed this bug and caused the
+test suite to fail.
+
+Reviewed-by: Eric Blake <eblake@redhat.com>
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ tests/test-io-channel-tls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
+index 8eaa208e1b..e7c80f46cf 100644
+--- a/tests/test-io-channel-tls.c
++++ b/tests/test-io-channel-tls.c
+@@ -218,7 +218,7 @@ static void test_io_channel_tls(const void *opaque)
+     mainloop = g_main_context_default();
+     do {
+         g_main_context_iteration(mainloop, TRUE);
+-    } while (!clientHandshake.finished &&
++    } while (!clientHandshake.finished ||
+              !serverHandshake.finished);
+ 
+     g_assert(clientHandshake.failed == data->expectClientFail);
diff --git a/0103-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch b/0103-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
new file mode 100644
index 0000000..744ca56
--- /dev/null
+++ b/0103-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
@@ -0,0 +1,30 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Fri, 21 Jul 2017 12:47:39 +0100
+Subject: [PATCH] io: fix temp directory used by test-io-channel-tls test
+
+The test-io-channel-tls test was mistakenly using two of the
+same directories as test-crypto-tlssession. This causes a
+sporadic failure when using make -j$BIGNUM.
+
+Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ tests/test-io-channel-tls.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
+index e7c80f46cf..a210d01ba5 100644
+--- a/tests/test-io-channel-tls.c
++++ b/tests/test-io-channel-tls.c
+@@ -127,8 +127,8 @@ static void test_io_channel_tls(const void *opaque)
+     /* We'll use this for our fake client-server connection */
+     g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);
+ 
+-#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
+-#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
++#define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/"
++#define SERVER_CERT_DIR "tests/test-io-channel-tls-server/"
+     mkdir(CLIENT_CERT_DIR, 0700);
+     mkdir(SERVER_CERT_DIR, 0700);
+ 
diff --git a/0104-spapr-fallback-to-raw-mode-if-best-compat-mode-canno.patch b/0104-spapr-fallback-to-raw-mode-if-best-compat-mode-canno.patch
new file mode 100644
index 0000000..8e8b6fc
--- /dev/null
+++ b/0104-spapr-fallback-to-raw-mode-if-best-compat-mode-canno.patch
@@ -0,0 +1,76 @@
+From: Greg Kurz <groug@kaod.org>
+Date: Thu, 17 Aug 2017 13:23:50 +0200
+Subject: [PATCH] spapr: fallback to raw mode if best compat mode cannot be set
+ during CAS
+
+KVM PR doesn't allow to set a compat mode. This causes ppc_set_compat_all()
+to fail and we return H_HARDWARE to the guest right away.
+
+This is excessive: even if we favor compat mode since commit 152ef803ceb19,
+we should at least fallback to raw mode if the guest supports it.
+
+This patch modifies cas_check_pvr() so that it also reports that the real
+PVR was found in the table supplied by the guest. Note that this is only
+makes sense if raw mode isn't explicitely disabled (ie, the user didn't
+set the machine "max-cpu-compat" property). If this is the case, we can
+simply ignore ppc_set_compat_all() failures, and let the guest run in raw
+mode.
+
+Signed-off-by: Greg Kurz <groug@kaod.org>
+Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
+(cherry picked from commit cc7b35b169e96600c09947a31c610c84a3eda3ff)
+---
+ hw/ppc/spapr_hcall.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
+index 07b3da8dc4..2f4c4f59e1 100644
+--- a/hw/ppc/spapr_hcall.c
++++ b/hw/ppc/spapr_hcall.c
+@@ -1441,7 +1441,8 @@ static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
+ }
+ 
+ static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+-                              target_ulong *addr, Error **errp)
++                              target_ulong *addr, bool *raw_mode_supported,
++                              Error **errp)
+ {
+     bool explicit_match = false; /* Matched the CPU's real PVR */
+     uint32_t max_compat = spapr->max_compat_pvr;
+@@ -1481,6 +1482,8 @@ static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+         return 0;
+     }
+ 
++    *raw_mode_supported = explicit_match;
++
+     /* Parsing finished */
+     trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
+ 
+@@ -1499,8 +1502,9 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
+     sPAPROptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
+     bool guest_radix;
+     Error *local_err = NULL;
++    bool raw_mode_supported = false;
+ 
+-    cas_pvr = cas_check_pvr(spapr, cpu, &addr, &local_err);
++    cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err);
+     if (local_err) {
+         error_report_err(local_err);
+         return H_HARDWARE;
+@@ -1510,8 +1514,14 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
+     if (cpu->compat_pvr != cas_pvr) {
+         ppc_set_compat_all(cas_pvr, &local_err);
+         if (local_err) {
+-            error_report_err(local_err);
+-            return H_HARDWARE;
++            /* We fail to set compat mode (likely because running with KVM PR),
++             * but maybe we can fallback to raw mode if the guest supports it.
++             */
++            if (!raw_mode_supported) {
++                error_report_err(local_err);
++                return H_HARDWARE;
++            }
++            local_err = NULL;
+         }
+     }
+ 
diff --git a/0105-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch b/0105-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
new file mode 100644
index 0000000..a187fe8
--- /dev/null
+++ b/0105-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
@@ -0,0 +1,40 @@
+From: Prasad J Pandit <pjp@fedoraproject.org>
+Date: Mon, 16 Oct 2017 14:21:59 +0200
+Subject: [PATCH] 9pfs: use g_malloc0 to allocate space for xattr
+
+9p back-end first queries the size of an extended attribute,
+allocates space for it via g_malloc() and then retrieves its
+value into allocated buffer. Race between querying attribute
+size and retrieving its could lead to memory bytes disclosure.
+Use g_malloc0() to avoid it.
+
+Reported-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+Signed-off-by: Greg Kurz <groug@kaod.org>
+(cherry picked from commit 7bd92756303f2158a68d5166264dc30139b813b6)
+---
+ hw/9pfs/9p.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
+index 8e9490c5f5..c41c0eb106 100644
+--- a/hw/9pfs/9p.c
++++ b/hw/9pfs/9p.c
+@@ -3236,7 +3236,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
+         xattr_fidp->fid_type = P9_FID_XATTR;
+         xattr_fidp->fs.xattr.xattrwalk_fid = true;
+         if (size) {
+-            xattr_fidp->fs.xattr.value = g_malloc(size);
++            xattr_fidp->fs.xattr.value = g_malloc0(size);
+             err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
+                                      xattr_fidp->fs.xattr.value,
+                                      xattr_fidp->fs.xattr.len);
+@@ -3269,7 +3269,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
+         xattr_fidp->fid_type = P9_FID_XATTR;
+         xattr_fidp->fs.xattr.xattrwalk_fid = true;
+         if (size) {
+-            xattr_fidp->fs.xattr.value = g_malloc(size);
++            xattr_fidp->fs.xattr.value = g_malloc0(size);
+             err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
+                                     &name, xattr_fidp->fs.xattr.value,
+                                     xattr_fidp->fs.xattr.len);
diff --git a/0106-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch b/0106-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
new file mode 100644
index 0000000..252e76a
--- /dev/null
+++ b/0106-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
@@ -0,0 +1,51 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Mon, 9 Oct 2017 14:43:42 +0100
+Subject: [PATCH] io: monitor encoutput buffer size from websocket GSource
+
+The websocket GSource is monitoring the size of the rawoutput
+buffer to determine if the channel can accepts more writes.
+The rawoutput buffer, however, is merely a temporary staging
+buffer before data is copied into the encoutput buffer. Thus
+its size will always be zero when the GSource runs.
+
+This flaw causes the encoutput buffer to grow without bound
+if the other end of the underlying data channel doesn't
+read data being sent. This can be seen with VNC if a client
+is on a slow WAN link and the guest OS is sending many screen
+updates. A malicious VNC client can act like it is on a slow
+link by playing a video in the guest and then reading data
+very slowly, causing QEMU host memory to expand arbitrarily.
+
+This issue is assigned CVE-2017-15268, publically reported in
+
+  https://bugs.launchpad.net/qemu/+bug/1718964
+
+Reviewed-by: Eric Blake <eblake@redhat.com>
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+(cherry picked from commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493)
+---
+ io/channel-websock.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/io/channel-websock.c b/io/channel-websock.c
+index 5a3badbec2..c02c2a66c9 100644
+--- a/io/channel-websock.c
++++ b/io/channel-websock.c
+@@ -26,7 +26,7 @@
+ #include "trace.h"
+ 
+ 
+-/* Max amount to allow in rawinput/rawoutput buffers */
++/* Max amount to allow in rawinput/encoutput buffers */
+ #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192
+ 
+ #define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24
+@@ -1006,7 +1006,7 @@ qio_channel_websock_source_prepare(GSource *source,
+     if (wsource->wioc->rawinput.offset) {
+         cond |= G_IO_IN;
+     }
+-    if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
++    if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
+         cond |= G_IO_OUT;
+     }
+ 
diff --git a/1001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch b/1001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
deleted file mode 100644
index f4d92ab..0000000
--- a/1001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
+++ /dev/null
@@ -1,384 +0,0 @@
-From 758d848ef10835108a75187d1a1a0418167f04b2 Mon Sep 17 00:00:00 2001
-From: "Daniel P. Berrange" <berrange@redhat.com>
-Date: Wed, 30 Aug 2017 14:53:59 +0100
-Subject: [PATCH 01/15] io: add new qio_channel_{readv, writev, read,
- write}_all functions
-
-These functions wait until they are able to read / write the full
-requested data buffer(s).
-
-Reviewed-by: Eric Blake <eblake@redhat.com>
-Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
----
- include/io/channel.h       |  90 +++++++++++++++++++++++++++++++++++++++
- io/channel.c               |  94 +++++++++++++++++++++++++++++++++++++++++
- tests/io-channel-helpers.c | 102 ++++-----------------------------------------
- 3 files changed, 193 insertions(+), 93 deletions(-)
-
-diff --git a/include/io/channel.h b/include/io/channel.h
-index db9bb022a1..e11a62ea50 100644
---- a/include/io/channel.h
-+++ b/include/io/channel.h
-@@ -269,6 +269,58 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
-                                 Error **errp);
- 
- /**
-+ * qio_channel_readv_all:
-+ * @ioc: the channel object
-+ * @iov: the array of memory regions to read data into
-+ * @niov: the length of the @iov array
-+ * @errp: pointer to a NULL-initialized error object
-+ *
-+ * Read data from the IO channel, storing it in the
-+ * memory regions referenced by @iov. Each element
-+ * in the @iov will be fully populated with data
-+ * before the next one is used. The @niov parameter
-+ * specifies the total number of elements in @iov.
-+ *
-+ * The function will wait for all requested data
-+ * to be read, yielding from the current coroutine
-+ * if required.
-+ *
-+ * If end-of-file occurs before all requested data
-+ * has been read, an error will be reported.
-+ *
-+ * Returns: 0 if all bytes were read, or -1 on error
-+ */
-+int qio_channel_readv_all(QIOChannel *ioc,
-+                          const struct iovec *iov,
-+                          size_t niov,
-+                          Error **errp);
-+
-+
-+/**
-+ * qio_channel_writev_all:
-+ * @ioc: the channel object
-+ * @iov: the array of memory regions to write data from
-+ * @niov: the length of the @iov array
-+ * @errp: pointer to a NULL-initialized error object
-+ *
-+ * Write data to the IO channel, reading it from the
-+ * memory regions referenced by @iov. Each element
-+ * in the @iov will be fully sent, before the next
-+ * one is used. The @niov parameter specifies the
-+ * total number of elements in @iov.
-+ *
-+ * The function will wait for all requested data
-+ * to be written, yielding from the current coroutine
-+ * if required.
-+ *
-+ * Returns: 0 if all bytes were written, or -1 on error
-+ */
-+int qio_channel_writev_all(QIOChannel *ioc,
-+                           const struct iovec *iov,
-+                           size_t niov,
-+                           Error **erp);
-+
-+/**
-  * qio_channel_readv:
-  * @ioc: the channel object
-  * @iov: the array of memory regions to read data into
-@@ -331,6 +383,44 @@ ssize_t qio_channel_write(QIOChannel *ioc,
-                           Error **errp);
- 
- /**
-+ * qio_channel_read_all:
-+ * @ioc: the channel object
-+ * @buf: the memory region to read data into
-+ * @buflen: the number of bytes to @buf
-+ * @errp: pointer to a NULL-initialized error object
-+ *
-+ * Reads @buflen bytes into @buf, possibly blocking or (if the
-+ * channel is non-blocking) yielding from the current coroutine
-+ * multiple times until the entire content is read. If end-of-file
-+ * occurs it will return an error rather than a short-read. Otherwise
-+ * behaves as qio_channel_read().
-+ *
-+ * Returns: 0 if all bytes were read, or -1 on error
-+ */
-+int qio_channel_read_all(QIOChannel *ioc,
-+                         char *buf,
-+                         size_t buflen,
-+                         Error **errp);
-+/**
-+ * qio_channel_write_all:
-+ * @ioc: the channel object
-+ * @buf: the memory region to write data into
-+ * @buflen: the number of bytes to @buf
-+ * @errp: pointer to a NULL-initialized error object
-+ *
-+ * Writes @buflen bytes from @buf, possibly blocking or (if the
-+ * channel is non-blocking) yielding from the current coroutine
-+ * multiple times until the entire content is written.  Otherwise
-+ * behaves as qio_channel_write().
-+ *
-+ * Returns: 0 if all bytes were written, or -1 on error
-+ */
-+int qio_channel_write_all(QIOChannel *ioc,
-+                          const char *buf,
-+                          size_t buflen,
-+                          Error **errp);
-+
-+/**
-  * qio_channel_set_blocking:
-  * @ioc: the channel object
-  * @enabled: the blocking flag state
-diff --git a/io/channel.c b/io/channel.c
-index 1cfb8b33a2..5e8c2f0a91 100644
---- a/io/channel.c
-+++ b/io/channel.c
-@@ -22,6 +22,7 @@
- #include "io/channel.h"
- #include "qapi/error.h"
- #include "qemu/main-loop.h"
-+#include "qemu/iov.h"
- 
- bool qio_channel_has_feature(QIOChannel *ioc,
-                              QIOChannelFeature feature)
-@@ -85,6 +86,79 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
- }
- 
- 
-+
-+int qio_channel_readv_all(QIOChannel *ioc,
-+                          const struct iovec *iov,
-+                          size_t niov,
-+                          Error **errp)
-+{
-+    int ret = -1;
-+    struct iovec *local_iov = g_new(struct iovec, niov);
-+    struct iovec *local_iov_head = local_iov;
-+    unsigned int nlocal_iov = niov;
-+
-+    nlocal_iov = iov_copy(local_iov, nlocal_iov,
-+                          iov, niov,
-+                          0, iov_size(iov, niov));
-+
-+    while (nlocal_iov > 0) {
-+        ssize_t len;
-+        len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
-+        if (len == QIO_CHANNEL_ERR_BLOCK) {
-+            qio_channel_wait(ioc, G_IO_IN);
-+            continue;
-+        } else if (len < 0) {
-+            goto cleanup;
-+        } else if (len == 0) {
-+            error_setg(errp,
-+                       "Unexpected end-of-file before all bytes were read");
-+            goto cleanup;
-+        }
-+
-+        iov_discard_front(&local_iov, &nlocal_iov, len);
-+    }
-+
-+    ret = 0;
-+
-+ cleanup:
-+    g_free(local_iov_head);
-+    return ret;
-+}
-+
-+int qio_channel_writev_all(QIOChannel *ioc,
-+                           const struct iovec *iov,
-+                           size_t niov,
-+                           Error **errp)
-+{
-+    int ret = -1;
-+    struct iovec *local_iov = g_new(struct iovec, niov);
-+    struct iovec *local_iov_head = local_iov;
-+    unsigned int nlocal_iov = niov;
-+
-+    nlocal_iov = iov_copy(local_iov, nlocal_iov,
-+                          iov, niov,
-+                          0, iov_size(iov, niov));
-+
-+    while (nlocal_iov > 0) {
-+        ssize_t len;
-+        len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
-+        if (len == QIO_CHANNEL_ERR_BLOCK) {
-+            qio_channel_wait(ioc, G_IO_OUT);
-+            continue;
-+        }
-+        if (len < 0) {
-+            goto cleanup;
-+        }
-+
-+        iov_discard_front(&local_iov, &nlocal_iov, len);
-+    }
-+
-+    ret = 0;
-+ cleanup:
-+    g_free(local_iov_head);
-+    return ret;
-+}
-+
- ssize_t qio_channel_readv(QIOChannel *ioc,
-                           const struct iovec *iov,
-                           size_t niov,
-@@ -123,6 +197,26 @@ ssize_t qio_channel_write(QIOChannel *ioc,
- }
- 
- 
-+int qio_channel_read_all(QIOChannel *ioc,
-+                         char *buf,
-+                         size_t buflen,
-+                         Error **errp)
-+{
-+    struct iovec iov = { .iov_base = buf, .iov_len = buflen };
-+    return qio_channel_readv_all(ioc, &iov, 1, errp);
-+}
-+
-+
-+int qio_channel_write_all(QIOChannel *ioc,
-+                          const char *buf,
-+                          size_t buflen,
-+                          Error **errp)
-+{
-+    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
-+    return qio_channel_writev_all(ioc, &iov, 1, errp);
-+}
-+
-+
- int qio_channel_set_blocking(QIOChannel *ioc,
-                               bool enabled,
-                               Error **errp)
-diff --git a/tests/io-channel-helpers.c b/tests/io-channel-helpers.c
-index 05e5579cf8..5430e1389d 100644
---- a/tests/io-channel-helpers.c
-+++ b/tests/io-channel-helpers.c
-@@ -21,6 +21,7 @@
- #include "qemu/osdep.h"
- #include "io-channel-helpers.h"
- #include "qapi/error.h"
-+#include "qemu/iov.h"
- 
- struct QIOChannelTest {
-     QIOChannel *src;
-@@ -37,77 +38,17 @@ struct QIOChannelTest {
- };
- 
- 
--static void test_skip_iovec(struct iovec **iov,
--                            size_t *niov,
--                            size_t skip,
--                            struct iovec *old)
--{
--    size_t offset = 0;
--    size_t i;
--
--    for (i = 0; i < *niov; i++) {
--        if (skip < (*iov)[i].iov_len) {
--            old->iov_len = (*iov)[i].iov_len;
--            old->iov_base = (*iov)[i].iov_base;
--
--            (*iov)[i].iov_len -= skip;
--            (*iov)[i].iov_base += skip;
--            break;
--        } else {
--            skip -= (*iov)[i].iov_len;
--
--            if (i == 0 && old->iov_base) {
--                (*iov)[i].iov_len = old->iov_len;
--                (*iov)[i].iov_base = old->iov_base;
--                old->iov_len = 0;
--                old->iov_base = NULL;
--            }
--
--            offset++;
--        }
--    }
--
--    *iov = *iov + offset;
--    *niov -= offset;
--}
--
--
- /* This thread sends all data using iovecs */
- static gpointer test_io_thread_writer(gpointer opaque)
- {
-     QIOChannelTest *data = opaque;
--    struct iovec *iov = data->inputv;
--    size_t niov = data->niov;
--    struct iovec old = { 0 };
- 
-     qio_channel_set_blocking(data->src, data->blocking, NULL);
- 
--    while (niov) {
--        ssize_t ret;
--        ret = qio_channel_writev(data->src,
--                                 iov,
--                                 niov,
--                                 &data->writeerr);
--        if (ret == QIO_CHANNEL_ERR_BLOCK) {
--            if (data->blocking) {
--                error_setg(&data->writeerr,
--                           "Unexpected I/O blocking");
--                break;
--            } else {
--                qio_channel_wait(data->src,
--                                 G_IO_OUT);
--                continue;
--            }
--        } else if (ret < 0) {
--            break;
--        } else if (ret == 0) {
--            error_setg(&data->writeerr,
--                       "Unexpected zero length write");
--            break;
--        }
--
--        test_skip_iovec(&iov, &niov, ret, &old);
--    }
-+    qio_channel_writev_all(data->src,
-+                           data->inputv,
-+                           data->niov,
-+                           &data->writeerr);
- 
-     return NULL;
- }
-@@ -117,38 +58,13 @@ static gpointer test_io_thread_writer(gpointer opaque)
- static gpointer test_io_thread_reader(gpointer opaque)
- {
-     QIOChannelTest *data = opaque;
--    struct iovec *iov = data->outputv;
--    size_t niov = data->niov;
--    struct iovec old = { 0 };
- 
-     qio_channel_set_blocking(data->dst, data->blocking, NULL);
- 
--    while (niov) {
--        ssize_t ret;
--
--        ret = qio_channel_readv(data->dst,
--                                iov,
--                                niov,
--                                &data->readerr);
--
--        if (ret == QIO_CHANNEL_ERR_BLOCK) {
--            if (data->blocking) {
--                error_setg(&data->readerr,
--                           "Unexpected I/O blocking");
--                break;
--            } else {
--                qio_channel_wait(data->dst,
--                                 G_IO_IN);
--                continue;
--            }
--        } else if (ret < 0) {
--            break;
--        } else if (ret == 0) {
--            break;
--        }
--
--        test_skip_iovec(&iov, &niov, ret, &old);
--    }
-+    qio_channel_readv_all(data->dst,
-+                          data->outputv,
-+                          data->niov,
-+                          &data->readerr);
- 
-     return NULL;
- }
--- 
-2.13.5
-
diff --git a/1002-io-Yield-rather-than-wait-when-already-in-coroutine.patch b/1002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
deleted file mode 100644
index db73177..0000000
--- a/1002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 5171f2cd3612ce2772b272e4dd8119fdb0c06124 Mon Sep 17 00:00:00 2001
-From: Eric Blake <eblake@redhat.com>
-Date: Tue, 5 Sep 2017 14:11:12 -0500
-Subject: [PATCH 02/15] io: Yield rather than wait when already in coroutine
-
-The new qio_channel_{read,write}{,v}_all functions are documented
-as yielding until data is available.  When used on a blocking
-channel, this yield is done via qio_channel_wait() which spawns
-a nested event loop under the hood (so it is that secondary loop
-which yields as needed); but if we are already in a coroutine (at
-which point QIO_CHANNEL_ERR_BLOCK is only possible if we are a
-non-blocking channel), we want to yield the current coroutine
-instead of spawning a nested event loop.
-
-Signed-off-by: Eric Blake <eblake@redhat.com>
-Message-Id: <20170905191114.5959-2-eblake@redhat.com>
-Acked-by: Daniel P. Berrange <berrange@redhat.com>
-[commit message updated]
-Signed-off-by: Eric Blake <eblake@redhat.com>
----
- io/channel.c | 12 ++++++++++--
- 1 file changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/io/channel.c b/io/channel.c
-index 5e8c2f0a91..9e62794cab 100644
---- a/io/channel.c
-+++ b/io/channel.c
-@@ -105,7 +105,11 @@ int qio_channel_readv_all(QIOChannel *ioc,
-         ssize_t len;
-         len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
-         if (len == QIO_CHANNEL_ERR_BLOCK) {
--            qio_channel_wait(ioc, G_IO_IN);
-+            if (qemu_in_coroutine()) {
-+                qio_channel_yield(ioc, G_IO_IN);
-+            } else {
-+                qio_channel_wait(ioc, G_IO_IN);
-+            }
-             continue;
-         } else if (len < 0) {
-             goto cleanup;
-@@ -143,7 +147,11 @@ int qio_channel_writev_all(QIOChannel *ioc,
-         ssize_t len;
-         len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
-         if (len == QIO_CHANNEL_ERR_BLOCK) {
--            qio_channel_wait(ioc, G_IO_OUT);
-+            if (qemu_in_coroutine()) {
-+                qio_channel_yield(ioc, G_IO_OUT);
-+            } else {
-+                qio_channel_wait(ioc, G_IO_OUT);
-+            }
-             continue;
-         }
-         if (len < 0) {
--- 
-2.13.5
-
diff --git a/1003-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch b/1003-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch
deleted file mode 100644
index a2af733..0000000
--- a/1003-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From b07725e3e5e05610691815ee921a6b3307685815 Mon Sep 17 00:00:00 2001
-From: Hannes Reinecke <hare@suse.de>
-Date: Fri, 18 Aug 2017 11:37:02 +0200
-Subject: [PATCH 03/15] scsi-bus: correct responses for INQUIRY and REQUEST
- SENSE
-
-According to SPC-3 INQUIRY and REQUEST SENSE should return GOOD
-even on unsupported LUNS.
-
-Signed-off-by: Hannes Reinecke <hare@suse.com>
-Message-Id: <1503049022-14749-1-git-send-email-hare@suse.de>
-Reported-by: Laszlo Ersek <lersek@redhat.com>
-Fixes: ded6ddc5a7b95217557fa360913d1213e12d4a6d
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Hannes Reinecke <hare@suse.de>
----
- hw/scsi/scsi-bus.c | 29 +++++++++++++++++++++++++----
- 1 file changed, 25 insertions(+), 4 deletions(-)
-
-diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
-index e364410a23..ade31c11f5 100644
---- a/hw/scsi/scsi-bus.c
-+++ b/hw/scsi/scsi-bus.c
-@@ -516,8 +516,10 @@ static size_t scsi_sense_len(SCSIRequest *req)
- static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
- {
-     SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-+    int fixed_sense = (req->cmd.buf[1] & 1) == 0;
- 
--    if (req->lun != 0) {
-+    if (req->lun != 0 &&
-+        buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) {
-         scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
-         scsi_req_complete(req, CHECK_CONDITION);
-         return 0;
-@@ -535,9 +537,28 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
-         break;
-     case REQUEST_SENSE:
-         scsi_target_alloc_buf(&r->req, scsi_sense_len(req));
--        r->len = scsi_device_get_sense(r->req.dev, r->buf,
--                                       MIN(req->cmd.xfer, r->buf_len),
--                                       (req->cmd.buf[1] & 1) == 0);
-+        if (req->lun != 0) {
-+            const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED);
-+
-+            if (fixed_sense) {
-+                r->buf[0] = 0x70;
-+                r->buf[2] = sense.key;
-+                r->buf[10] = 10;
-+                r->buf[12] = sense.asc;
-+                r->buf[13] = sense.ascq;
-+                r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN);
-+            } else {
-+                r->buf[0] = 0x72;
-+                r->buf[1] = sense.key;
-+                r->buf[2] = sense.asc;
-+                r->buf[3] = sense.ascq;
-+                r->len = 8;
-+            }
-+        } else {
-+            r->len = scsi_device_get_sense(r->req.dev, r->buf,
-+                                           MIN(req->cmd.xfer, r->buf_len),
-+                                           fixed_sense);
-+        }
-         if (r->req.dev->sense_is_ua) {
-             scsi_device_unit_attention_reported(req->dev);
-             r->req.dev->sense_len = 0;
--- 
-2.13.5
-
diff --git a/1004-scsi-Refactor-scsi-sense-interpreting-code.patch b/1004-scsi-Refactor-scsi-sense-interpreting-code.patch
deleted file mode 100644
index f1e02f5..0000000
--- a/1004-scsi-Refactor-scsi-sense-interpreting-code.patch
+++ /dev/null
@@ -1,194 +0,0 @@
-From f35ef58b2bac932bbd379602fe23e7a190530075 Mon Sep 17 00:00:00 2001
-From: Fam Zheng <famz@redhat.com>
-Date: Mon, 21 Aug 2017 22:10:05 +0800
-Subject: [PATCH 04/15] scsi: Refactor scsi sense interpreting code
-
-So that it can be reused outside of iscsi.c.
-
-Also update MAINTAINERS to include the new files in SCSI section.
-
-Signed-off-by: Fam Zheng <famz@redhat.com>
-Message-Id: <20170821141008.19383-2-famz@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- MAINTAINERS         |  2 ++
- block/iscsi.c       | 45 ++++-----------------------------------------
- include/scsi/scsi.h | 19 +++++++++++++++++++
- util/Makefile.objs  |  1 +
- util/scsi.c         | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- 5 files changed, 78 insertions(+), 41 deletions(-)
- create mode 100644 include/scsi/scsi.h
- create mode 100644 util/scsi.c
-
-diff --git a/MAINTAINERS b/MAINTAINERS
-index ccee28b12d..2a4e5036ae 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -969,7 +969,9 @@ SCSI
- M: Paolo Bonzini <pbonzini@redhat.com>
- S: Supported
- F: include/hw/scsi/*
-+F: include/scsi/*
- F: hw/scsi/*
-+F: util/scsi*
- F: tests/virtio-scsi-test.c
- T: git git://github.com/bonzini/qemu.git scsi-next
- 
-diff --git a/block/iscsi.c b/block/iscsi.c
-index d557c99668..4bed63cd6d 100644
---- a/block/iscsi.c
-+++ b/block/iscsi.c
-@@ -40,6 +40,7 @@
- #include "qmp-commands.h"
- #include "qapi/qmp/qstring.h"
- #include "crypto/secret.h"
-+#include "scsi/scsi.h"
- 
- #include <iscsi/iscsi.h>
- #include <iscsi/scsi-lowlevel.h>
-@@ -209,47 +210,9 @@ static inline unsigned exp_random(double mean)
- 
- static int iscsi_translate_sense(struct scsi_sense *sense)
- {
--    int ret;
--
--    switch (sense->key) {
--    case SCSI_SENSE_NOT_READY:
--        return -EBUSY;
--    case SCSI_SENSE_DATA_PROTECTION:
--        return -EACCES;
--    case SCSI_SENSE_COMMAND_ABORTED:
--        return -ECANCELED;
--    case SCSI_SENSE_ILLEGAL_REQUEST:
--        /* Parse ASCQ */
--        break;
--    default:
--        return -EIO;
--    }
--    switch (sense->ascq) {
--    case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR:
--    case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE:
--    case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB:
--    case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST:
--        ret = -EINVAL;
--        break;
--    case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE:
--        ret = -ENOSPC;
--        break;
--    case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED:
--        ret = -ENOTSUP;
--        break;
--    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT:
--    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED:
--    case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN:
--        ret = -ENOMEDIUM;
--        break;
--    case SCSI_SENSE_ASCQ_WRITE_PROTECTED:
--        ret = -EACCES;
--        break;
--    default:
--        ret = -EIO;
--        break;
--    }
--    return ret;
-+    return - scsi_sense_to_errno(sense->key,
-+                                 (sense->ascq & 0xFF00) >> 8,
-+                                 sense->ascq & 0xFF);
- }
- 
- /* Called (via iscsi_service) with QemuMutex held.  */
-diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
-new file mode 100644
-index 0000000000..f894ace4bf
---- /dev/null
-+++ b/include/scsi/scsi.h
-@@ -0,0 +1,19 @@
-+/*
-+ *  SCSI helpers
-+ *
-+ *  Copyright 2017 Red Hat, Inc.
-+ *
-+ *  Authors:
-+ *   Fam Zheng <famz@redhat.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the Free
-+ * Software Foundation; either version 2 of the License, or (at your option)
-+ * any later version.
-+ */
-+#ifndef QEMU_SCSI_H
-+#define QEMU_SCSI_H
-+
-+int scsi_sense_to_errno(int key, int asc, int ascq);
-+
-+#endif
-diff --git a/util/Makefile.objs b/util/Makefile.objs
-index 50a55ecc75..c9e6c493d3 100644
---- a/util/Makefile.objs
-+++ b/util/Makefile.objs
-@@ -45,3 +45,4 @@ util-obj-y += qht.o
- util-obj-y += range.o
- util-obj-y += stats64.o
- util-obj-y += systemd.o
-+util-obj-y += scsi.o
-diff --git a/util/scsi.c b/util/scsi.c
-new file mode 100644
-index 0000000000..a6710799fc
---- /dev/null
-+++ b/util/scsi.c
-@@ -0,0 +1,52 @@
-+/*
-+ *  SCSI helpers
-+ *
-+ *  Copyright 2017 Red Hat, Inc.
-+ *
-+ *  Authors:
-+ *   Fam Zheng <famz@redhat.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the Free
-+ * Software Foundation; either version 2 of the License, or (at your option)
-+ * any later version.
-+ */
-+
-+#include "qemu/osdep.h"
-+#include "scsi/scsi.h"
-+
-+int scsi_sense_to_errno(int key, int asc, int ascq)
-+{
-+    switch (key) {
-+    case 0x02: /* NOT READY */
-+        return EBUSY;
-+    case 0x07: /* DATA PROTECTION */
-+        return EACCES;
-+    case 0x0b: /* COMMAND ABORTED */
-+        return ECANCELED;
-+    case 0x05: /* ILLEGAL REQUEST */
-+        /* Parse ASCQ */
-+        break;
-+    default:
-+        return EIO;
-+    }
-+    switch ((asc << 8) | ascq) {
-+    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
-+    case 0x2000: /* INVALID OPERATION CODE */
-+    case 0x2400: /* INVALID FIELD IN CDB */
-+    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
-+        return EINVAL;
-+    case 0x2100: /* LBA OUT OF RANGE */
-+        return ENOSPC;
-+    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
-+        return ENOTSUP;
-+    case 0x3a00: /* MEDIUM NOT PRESENT */
-+    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
-+    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
-+        return ENOMEDIUM;
-+    case 0x2700: /* WRITE PROTECTED */
-+        return EACCES;
-+    default:
-+        return EIO;
-+    }
-+}
--- 
-2.13.5
-
diff --git a/1005-scsi-Improve-scsi_sense_to_errno.patch b/1005-scsi-Improve-scsi_sense_to_errno.patch
deleted file mode 100644
index 07f9cb5..0000000
--- a/1005-scsi-Improve-scsi_sense_to_errno.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From a7dc92dac7cedb3ba6b6d724c7579f05399e2f2e Mon Sep 17 00:00:00 2001
-From: Fam Zheng <famz@redhat.com>
-Date: Mon, 21 Aug 2017 22:10:06 +0800
-Subject: [PATCH 05/15] scsi: Improve scsi_sense_to_errno
-
-Tweak the errno mapping to return more accurate/appropriate values.
-
-Signed-off-by: Fam Zheng <famz@redhat.com>
-Message-Id: <20170821141008.19383-3-famz@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- util/scsi.c | 16 ++++++++++++----
- 1 file changed, 12 insertions(+), 4 deletions(-)
-
-diff --git a/util/scsi.c b/util/scsi.c
-index a6710799fc..472eb5bea5 100644
---- a/util/scsi.c
-+++ b/util/scsi.c
-@@ -18,13 +18,16 @@
- int scsi_sense_to_errno(int key, int asc, int ascq)
- {
-     switch (key) {
--    case 0x02: /* NOT READY */
--        return EBUSY;
--    case 0x07: /* DATA PROTECTION */
--        return EACCES;
-+    case 0x00: /* NO SENSE */
-+    case 0x01: /* RECOVERED ERROR */
-+    case 0x06: /* UNIT ATTENTION */
-+        /* These sense keys are not errors */
-+        return 0;
-     case 0x0b: /* COMMAND ABORTED */
-         return ECANCELED;
-+    case 0x02: /* NOT READY */
-     case 0x05: /* ILLEGAL REQUEST */
-+    case 0x07: /* DATA PROTECTION */
-         /* Parse ASCQ */
-         break;
-     default:
-@@ -37,6 +40,7 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
-     case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
-         return EINVAL;
-     case 0x2100: /* LBA OUT OF RANGE */
-+    case 0x2707: /* SPACE ALLOC FAILED */
-         return ENOSPC;
-     case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
-         return ENOTSUP;
-@@ -46,6 +50,10 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
-         return ENOMEDIUM;
-     case 0x2700: /* WRITE PROTECTED */
-         return EACCES;
-+    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
-+        return EAGAIN;
-+    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
-+        return ENOTCONN;
-     default:
-         return EIO;
-     }
--- 
-2.13.5
-
diff --git a/1006-scsi-Introduce-scsi_sense_buf_to_errno.patch b/1006-scsi-Introduce-scsi_sense_buf_to_errno.patch
deleted file mode 100644
index 4aa499c..0000000
--- a/1006-scsi-Introduce-scsi_sense_buf_to_errno.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From eadabcbc81d44ee0bc0d0d80697cc1142df61178 Mon Sep 17 00:00:00 2001
-From: Fam Zheng <famz@redhat.com>
-Date: Mon, 21 Aug 2017 22:10:07 +0800
-Subject: [PATCH 06/15] scsi: Introduce scsi_sense_buf_to_errno
-
-This recognizes the "fixed" and "descriptor" format sense data, extracts
-the sense key/asc/ascq fields then converts them to an errno.
-
-Signed-off-by: Fam Zheng <famz@redhat.com>
-Message-Id: <20170821141008.19383-4-famz@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- include/scsi/scsi.h |  1 +
- util/scsi.c         | 30 ++++++++++++++++++++++++++++++
- 2 files changed, 31 insertions(+)
-
-diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
-index f894ace4bf..fe330385d8 100644
---- a/include/scsi/scsi.h
-+++ b/include/scsi/scsi.h
-@@ -15,5 +15,6 @@
- #define QEMU_SCSI_H
- 
- int scsi_sense_to_errno(int key, int asc, int ascq);
-+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
- 
- #endif
-diff --git a/util/scsi.c b/util/scsi.c
-index 472eb5bea5..472293d59b 100644
---- a/util/scsi.c
-+++ b/util/scsi.c
-@@ -58,3 +58,33 @@ int scsi_sense_to_errno(int key, int asc, int ascq)
-         return EIO;
-     }
- }
-+
-+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
-+{
-+    int key, asc, ascq;
-+    if (sense_size < 1) {
-+        return EIO;
-+    }
-+    switch (sense[0]) {
-+    case 0x70: /* Fixed format sense data. */
-+        if (sense_size < 14) {
-+            return EIO;
-+        }
-+        key = sense[2] & 0xF;
-+        asc = sense[12];
-+        ascq = sense[13];
-+        break;
-+    case 0x72: /* Descriptor format sense data. */
-+        if (sense_size < 4) {
-+            return EIO;
-+        }
-+        key = sense[1] & 0xF;
-+        asc = sense[2];
-+        ascq = sense[3];
-+        break;
-+    default:
-+        return EIO;
-+        break;
-+    }
-+    return scsi_sense_to_errno(key, asc, ascq);
-+}
--- 
-2.13.5
-
diff --git a/1007-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch b/1007-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
deleted file mode 100644
index 3607e2f..0000000
--- a/1007-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From ba83805030e07cade8d17b5d1b4bd1d296caff1b Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 09:31:36 +0200
-Subject: [PATCH 07/15] scsi: rename scsi_build_sense to scsi_convert_sense
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-After introducing the scsi/ subdirectory, there will be a scsi_build_sense
-function that is the same as scsi_req_build_sense but without needing
-a SCSIRequest.  The existing scsi_build_sense function gets in the way,
-remove it.
-
-Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- hw/scsi/scsi-bus.c     | 10 +++++-----
- hw/scsi/scsi-disk.c    |  4 ++--
- include/hw/scsi/scsi.h |  4 ++--
- 3 files changed, 9 insertions(+), 9 deletions(-)
-
-diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
-index ade31c11f5..fac360e20f 100644
---- a/hw/scsi/scsi-bus.c
-+++ b/hw/scsi/scsi-bus.c
-@@ -790,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
-         return 0;
-     }
- 
--    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
-+    ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
- 
-     /*
-      * FIXME: clearing unit attention conditions upon autosense should be done
-@@ -811,7 +811,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
- 
- int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
- {
--    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
-+    return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
- }
- 
- void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
-@@ -1531,12 +1531,12 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
- };
- 
- /*
-- * scsi_build_sense
-+ * scsi_convert_sense
-  *
-  * Convert between fixed and descriptor sense buffers
-  */
--int scsi_build_sense(uint8_t *in_buf, int in_len,
--                     uint8_t *buf, int len, bool fixed)
-+int scsi_convert_sense(uint8_t *in_buf, int in_len,
-+                       uint8_t *buf, int len, bool fixed)
- {
-     bool fixed_in;
-     SCSISense sense;
-diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
-index 5f1e5e8070..0a1f4ef0c7 100644
---- a/hw/scsi/scsi-disk.c
-+++ b/hw/scsi/scsi-disk.c
-@@ -1978,8 +1978,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
-         break;
-     case REQUEST_SENSE:
-         /* Just return "NO SENSE".  */
--        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
--                                  (req->cmd.buf[1] & 1) == 0);
-+        buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
-+                                    (req->cmd.buf[1] & 1) == 0);
-         if (buflen < 0) {
-             goto illegal_request;
-         }
-diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
-index 6b85786dbf..6ef67fb504 100644
---- a/include/hw/scsi/scsi.h
-+++ b/include/hw/scsi/scsi.h
-@@ -244,8 +244,8 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
- uint32_t scsi_data_cdb_xfer(uint8_t *buf);
- uint32_t scsi_cdb_xfer(uint8_t *buf);
- int scsi_cdb_length(uint8_t *buf);
--int scsi_build_sense(uint8_t *in_buf, int in_len,
--                     uint8_t *buf, int len, bool fixed);
-+int scsi_convert_sense(uint8_t *in_buf, int in_len,
-+                       uint8_t *buf, int len, bool fixed);
- 
- SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
-                             uint32_t tag, uint32_t lun, void *hba_private);
--- 
-2.13.5
-
diff --git a/1008-scsi-move-non-emulation-specific-code-to-scsi.patch b/1008-scsi-move-non-emulation-specific-code-to-scsi.patch
deleted file mode 100644
index c1bb72b..0000000
--- a/1008-scsi-move-non-emulation-specific-code-to-scsi.patch
+++ /dev/null
@@ -1,1434 +0,0 @@
-From 6949ca76b864b54a0ef1d2aa321c3df4dc102c90 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 07:08:27 +0200
-Subject: [PATCH 08/15] scsi: move non-emulation specific code to scsi/
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-util/scsi.c includes some SCSI code that is shared by block/iscsi.c and
-hw/scsi, but the introduction of the persistent reservation helper
-will add many more instances of this.  There is also include/block/scsi.h,
-which actually is not part of the core block layer.
-
-The persistent reservation manager will also need a home.  A scsi/
-directory provides one for both the aforementioned shared code and
-the PR manager code.
-
-Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- MAINTAINERS            |   7 +
- Makefile.objs          |   2 +-
- block/iscsi.c          |   6 +-
- hw/scsi/scsi-bus.c     | 397 ---------------------------------------
- hw/scsi/scsi-generic.c |   8 -
- include/block/scsi.h   |   2 -
- include/hw/scsi/scsi.h |  94 +---------
- include/scsi/scsi.h    |  20 --
- include/scsi/utils.h   | 119 ++++++++++++
- scsi/Makefile.objs     |   1 +
- scsi/utils.c           | 492 +++++++++++++++++++++++++++++++++++++++++++++++++
- util/Makefile.objs     |   1 -
- util/scsi.c            |  90 ---------
- 13 files changed, 626 insertions(+), 613 deletions(-)
- delete mode 100644 include/scsi/scsi.h
- create mode 100644 include/scsi/utils.h
- create mode 100644 scsi/Makefile.objs
- create mode 100644 scsi/utils.c
- delete mode 100644 util/scsi.c
-
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 2a4e5036ae..074da8c976 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -1215,6 +1215,13 @@ F: migration/block*
- F: include/block/aio.h
- T: git git://github.com/stefanha/qemu.git block
- 
-+Block SCSI subsystem
-+M: Paolo Bonzini <pbonzini@redhat.com>
-+L: qemu-block@nongnu.org
-+S: Supported
-+F: include/scsi/*
-+F: scsi/*
-+
- Block Jobs
- M: Jeff Cody <jcody@redhat.com>
- L: qemu-block@nongnu.org
-diff --git a/Makefile.objs b/Makefile.objs
-index 24a4ea08b8..f68aa3b60d 100644
---- a/Makefile.objs
-+++ b/Makefile.objs
-@@ -11,7 +11,7 @@ chardev-obj-y = chardev/
- 
- block-obj-y += nbd/
- block-obj-y += block.o blockjob.o
--block-obj-y += block/
-+block-obj-y += block/ scsi/
- block-obj-y += qemu-io-cmds.o
- block-obj-$(CONFIG_REPLICATION) += replication.o
- 
-diff --git a/block/iscsi.c b/block/iscsi.c
-index 4bed63cd6d..40adc3c493 100644
---- a/block/iscsi.c
-+++ b/block/iscsi.c
-@@ -40,10 +40,14 @@
- #include "qmp-commands.h"
- #include "qapi/qmp/qstring.h"
- #include "crypto/secret.h"
--#include "scsi/scsi.h"
-+#include "scsi/utils.h"
- 
-+/* Conflict between scsi/utils.h and libiscsi! :( */
-+#define SCSI_XFER_NONE ISCSI_XFER_NONE
- #include <iscsi/iscsi.h>
- #include <iscsi/scsi-lowlevel.h>
-+#undef SCSI_XFER_NONE
-+QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE);
- 
- #ifdef __linux__
- #include <scsi/sg.h>
-diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
-index fac360e20f..42920d5422 100644
---- a/hw/scsi/scsi-bus.c
-+++ b/hw/scsi/scsi-bus.c
-@@ -956,36 +956,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
-     return xfer * unit;
- }
- 
--uint32_t scsi_data_cdb_xfer(uint8_t *buf)
--{
--    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
--        return 256;
--    } else {
--        return scsi_cdb_xfer(buf);
--    }
--}
--
--uint32_t scsi_cdb_xfer(uint8_t *buf)
--{
--    switch (buf[0] >> 5) {
--    case 0:
--        return buf[4];
--        break;
--    case 1:
--    case 2:
--        return lduw_be_p(&buf[7]);
--        break;
--    case 4:
--        return ldl_be_p(&buf[10]) & 0xffffffffULL;
--        break;
--    case 5:
--        return ldl_be_p(&buf[6]) & 0xffffffffULL;
--        break;
--    default:
--        return -1;
--    }
--}
--
- static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
- {
-     cmd->xfer = scsi_cdb_xfer(buf);
-@@ -1298,53 +1268,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
-     }
- }
- 
--static uint64_t scsi_cmd_lba(SCSICommand *cmd)
--{
--    uint8_t *buf = cmd->buf;
--    uint64_t lba;
--
--    switch (buf[0] >> 5) {
--    case 0:
--        lba = ldl_be_p(&buf[0]) & 0x1fffff;
--        break;
--    case 1:
--    case 2:
--    case 5:
--        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
--        break;
--    case 4:
--        lba = ldq_be_p(&buf[2]);
--        break;
--    default:
--        lba = -1;
--
--    }
--    return lba;
--}
--
--int scsi_cdb_length(uint8_t *buf) {
--    int cdb_len;
--
--    switch (buf[0] >> 5) {
--    case 0:
--        cdb_len = 6;
--        break;
--    case 1:
--    case 2:
--        cdb_len = 10;
--        break;
--    case 4:
--        cdb_len = 16;
--        break;
--    case 5:
--        cdb_len = 12;
--        break;
--    default:
--        cdb_len = -1;
--    }
--    return cdb_len;
--}
--
- int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
- {
-     int rc;
-@@ -1391,326 +1314,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
-     }
- }
- 
--/*
-- * Predefined sense codes
-- */
--
--/* No sense data available */
--const struct SCSISense sense_code_NO_SENSE = {
--    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
--};
--
--/* LUN not ready, Manual intervention required */
--const struct SCSISense sense_code_LUN_NOT_READY = {
--    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
--};
--
--/* LUN not ready, Medium not present */
--const struct SCSISense sense_code_NO_MEDIUM = {
--    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
--};
--
--/* LUN not ready, medium removal prevented */
--const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
--    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
--};
--
--/* Hardware error, internal target failure */
--const struct SCSISense sense_code_TARGET_FAILURE = {
--    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
--};
--
--/* Illegal request, invalid command operation code */
--const struct SCSISense sense_code_INVALID_OPCODE = {
--    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
--};
--
--/* Illegal request, LBA out of range */
--const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
--    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
--};
--
--/* Illegal request, Invalid field in CDB */
--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
--};
--
--/* Illegal request, Saving parameters not supported */
--const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
--    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
--};
--
--/* Illegal request, Incompatible medium installed */
--const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
--    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
--};
--
--/* Illegal request, medium removal prevented */
--const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
--    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
--};
--
--/* Illegal request, Invalid Transfer Tag */
--const struct SCSISense sense_code_INVALID_TAG = {
--    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
--};
--
--/* Command aborted, I/O process terminated */
--const struct SCSISense sense_code_IO_ERROR = {
--    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
--};
--
--/* Command aborted, I_T Nexus loss occurred */
--const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
--    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
--};
--
--/* Command aborted, Logical Unit failure */
--const struct SCSISense sense_code_LUN_FAILURE = {
--    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
--};
--
--/* Command aborted, Overlapped Commands Attempted */
--const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
--    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
--};
--
--/* Unit attention, Capacity data has changed */
--const struct SCSISense sense_code_CAPACITY_CHANGED = {
--    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
--};
--
--/* Unit attention, Power on, reset or bus device reset occurred */
--const struct SCSISense sense_code_RESET = {
--    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
--};
--
--/* Unit attention, No medium */
--const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
--    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
--};
--
--/* Unit attention, Medium may have changed */
--const struct SCSISense sense_code_MEDIUM_CHANGED = {
--    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
--};
--
--/* Unit attention, Reported LUNs data has changed */
--const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
--    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
--};
--
--/* Unit attention, Device internal reset */
--const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
--    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
--};
--
--/* Data Protection, Write Protected */
--const struct SCSISense sense_code_WRITE_PROTECTED = {
--    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
--};
--
--/* Data Protection, Space Allocation Failed Write Protect */
--const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
--    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
--};
--
--/*
-- * scsi_convert_sense
-- *
-- * Convert between fixed and descriptor sense buffers
-- */
--int scsi_convert_sense(uint8_t *in_buf, int in_len,
--                       uint8_t *buf, int len, bool fixed)
--{
--    bool fixed_in;
--    SCSISense sense;
--    if (!fixed && len < 8) {
--        return 0;
--    }
--
--    if (in_len == 0) {
--        sense.key = NO_SENSE;
--        sense.asc = 0;
--        sense.ascq = 0;
--    } else {
--        fixed_in = (in_buf[0] & 2) == 0;
--
--        if (fixed == fixed_in) {
--            memcpy(buf, in_buf, MIN(len, in_len));
--            return MIN(len, in_len);
--        }
--
--        if (fixed_in) {
--            sense.key = in_buf[2];
--            sense.asc = in_buf[12];
--            sense.ascq = in_buf[13];
--        } else {
--            sense.key = in_buf[1];
--            sense.asc = in_buf[2];
--            sense.ascq = in_buf[3];
--        }
--    }
--
--    memset(buf, 0, len);
--    if (fixed) {
--        /* Return fixed format sense buffer */
--        buf[0] = 0x70;
--        buf[2] = sense.key;
--        buf[7] = 10;
--        buf[12] = sense.asc;
--        buf[13] = sense.ascq;
--        return MIN(len, SCSI_SENSE_LEN);
--    } else {
--        /* Return descriptor format sense buffer */
--        buf[0] = 0x72;
--        buf[1] = sense.key;
--        buf[2] = sense.asc;
--        buf[3] = sense.ascq;
--        return 8;
--    }
--}
--
--const char *scsi_command_name(uint8_t cmd)
--{
--    static const char *names[] = {
--        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
--        [ REWIND                   ] = "REWIND",
--        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
--        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
--        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
--        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
--        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
--        [ READ_6                   ] = "READ_6",
--        [ WRITE_6                  ] = "WRITE_6",
--        [ SET_CAPACITY             ] = "SET_CAPACITY",
--        [ READ_REVERSE             ] = "READ_REVERSE",
--        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
--        [ SPACE                    ] = "SPACE",
--        [ INQUIRY                  ] = "INQUIRY",
--        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
--        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
--        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
--        [ MODE_SELECT              ] = "MODE_SELECT",
--        [ RESERVE                  ] = "RESERVE",
--        [ RELEASE                  ] = "RELEASE",
--        [ COPY                     ] = "COPY",
--        [ ERASE                    ] = "ERASE",
--        [ MODE_SENSE               ] = "MODE_SENSE",
--        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
--        /* LOAD_UNLOAD and START_STOP use the same operation code */
--        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
--        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
--        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
--        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
--        [ READ_10                  ] = "READ_10",
--        [ WRITE_10                 ] = "WRITE_10",
--        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
--        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
--        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
--        [ VERIFY_10                ] = "VERIFY_10",
--        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
--        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
--        [ SEARCH_LOW               ] = "SEARCH_LOW",
--        [ SET_LIMITS               ] = "SET_LIMITS",
--        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
--        /* READ_POSITION and PRE_FETCH use the same operation code */
--        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
--        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
--        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
--        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
--        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
--        [ COMPARE                  ] = "COMPARE",
--        [ COPY_VERIFY              ] = "COPY_VERIFY",
--        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
--        [ READ_BUFFER              ] = "READ_BUFFER",
--        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
--        [ READ_LONG_10             ] = "READ_LONG_10",
--        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
--        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
--        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
--        [ UNMAP                    ] = "UNMAP",
--        [ READ_TOC                 ] = "READ_TOC",
--        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
--        [ SANITIZE                 ] = "SANITIZE",
--        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
--        [ LOG_SELECT               ] = "LOG_SELECT",
--        [ LOG_SENSE                ] = "LOG_SENSE",
--        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
--        [ RESERVE_10               ] = "RESERVE_10",
--        [ RELEASE_10               ] = "RELEASE_10",
--        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
--        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
--        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
--        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
--        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
--        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
--        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
--        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
--        [ READ_16                  ] = "READ_16",
--        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
--        [ WRITE_16                 ] = "WRITE_16",
--        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
--        [ VERIFY_16                ] = "VERIFY_16",
--        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
--        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
--        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
--        [ LOCATE_16                ] = "LOCATE_16",
--        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
--        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
--        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
--        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
--        [ REPORT_LUNS              ] = "REPORT_LUNS",
--        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
--        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
--        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
--        [ READ_12                  ] = "READ_12",
--        [ WRITE_12                 ] = "WRITE_12",
--        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
--        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
--        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
--        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
--        [ VERIFY_12                ] = "VERIFY_12",
--        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
--        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
--        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
--        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
--        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
--        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
--        [ READ_CD                  ] = "READ_CD",
--        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
--        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
--        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
--        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
--        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
--        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
--        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
--        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
--        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
--        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
--        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
--    };
--
--    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
--        return "*UNKNOWN*";
--    return names[cmd];
--}
--
- SCSIRequest *scsi_req_ref(SCSIRequest *req)
- {
-     assert(req->refcount > 0);
-diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
-index 7e1cbab77e..7a8f500934 100644
---- a/hw/scsi/scsi-generic.c
-+++ b/hw/scsi/scsi-generic.c
-@@ -36,14 +36,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
- #include <scsi/sg.h>
- #include "block/scsi.h"
- 
--#define SG_ERR_DRIVER_TIMEOUT  0x06
--#define SG_ERR_DRIVER_SENSE    0x08
--
--#define SG_ERR_DID_OK          0x00
--#define SG_ERR_DID_NO_CONNECT  0x01
--#define SG_ERR_DID_BUS_BUSY    0x02
--#define SG_ERR_DID_TIME_OUT    0x03
--
- #ifndef MAX_UINT
- #define MAX_UINT ((unsigned int)-1)
- #endif
-diff --git a/include/block/scsi.h b/include/block/scsi.h
-index cdf0a58a07..a141dd71f8 100644
---- a/include/block/scsi.h
-+++ b/include/block/scsi.h
-@@ -150,8 +150,6 @@
- #define READ_CD               0xbe
- #define SEND_DVD_STRUCTURE    0xbf
- 
--const char *scsi_command_name(uint8_t cmd);
--
- /*
-  * SERVICE ACTION IN subcodes
-  */
-diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
-index 6ef67fb504..23a8ee6a7d 100644
---- a/include/hw/scsi/scsi.h
-+++ b/include/hw/scsi/scsi.h
-@@ -4,45 +4,20 @@
- #include "hw/qdev.h"
- #include "hw/block/block.h"
- #include "sysemu/sysemu.h"
-+#include "scsi/utils.h"
- #include "qemu/notify.h"
- 
- #define MAX_SCSI_DEVS	255
- 
--#define SCSI_CMD_BUF_SIZE      16
--#define SCSI_SENSE_LEN         18
--#define SCSI_SENSE_LEN_SCANNER 32
--#define SCSI_INQUIRY_LEN       36
--
- typedef struct SCSIBus SCSIBus;
- typedef struct SCSIBusInfo SCSIBusInfo;
--typedef struct SCSICommand SCSICommand;
- typedef struct SCSIDevice SCSIDevice;
- typedef struct SCSIRequest SCSIRequest;
- typedef struct SCSIReqOps SCSIReqOps;
- 
--enum SCSIXferMode {
--    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
--    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
--    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
--};
--
--typedef struct SCSISense {
--    uint8_t key;
--    uint8_t asc;
--    uint8_t ascq;
--} SCSISense;
--
- #define SCSI_SENSE_BUF_SIZE_OLD 96
- #define SCSI_SENSE_BUF_SIZE 252
- 
--struct SCSICommand {
--    uint8_t buf[SCSI_CMD_BUF_SIZE];
--    int len;
--    size_t xfer;
--    uint64_t lba;
--    enum SCSIXferMode mode;
--};
--
- struct SCSIRequest {
-     SCSIBus           *bus;
-     SCSIDevice        *dev;
-@@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
- void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
- void scsi_legacy_handle_cmdline(void);
- 
--/*
-- * Predefined sense codes
-- */
--
--/* No sense data available */
--extern const struct SCSISense sense_code_NO_SENSE;
--/* LUN not ready, Manual intervention required */
--extern const struct SCSISense sense_code_LUN_NOT_READY;
--/* LUN not ready, Medium not present */
--extern const struct SCSISense sense_code_NO_MEDIUM;
--/* LUN not ready, medium removal prevented */
--extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
--/* Hardware error, internal target failure */
--extern const struct SCSISense sense_code_TARGET_FAILURE;
--/* Illegal request, invalid command operation code */
--extern const struct SCSISense sense_code_INVALID_OPCODE;
--/* Illegal request, LBA out of range */
--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 */
--extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
--/* Illegal request, Incompatible format */
--extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
--/* Illegal request, medium removal prevented */
--extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
--/* Illegal request, Invalid Transfer Tag */
--extern const struct SCSISense sense_code_INVALID_TAG;
--/* Command aborted, I/O process terminated */
--extern const struct SCSISense sense_code_IO_ERROR;
--/* Command aborted, I_T Nexus loss occurred */
--extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
--/* Command aborted, Logical Unit failure */
--extern const struct SCSISense sense_code_LUN_FAILURE;
--/* Command aborted, Overlapped Commands Attempted */
--extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
--/* LUN not ready, Capacity data has changed */
--extern const struct SCSISense sense_code_CAPACITY_CHANGED;
--/* LUN not ready, Medium not present */
--extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
--/* Unit attention, Power on, reset or bus device reset occurred */
--extern const struct SCSISense sense_code_RESET;
--/* Unit attention, Medium may have changed*/
--extern const struct SCSISense sense_code_MEDIUM_CHANGED;
--/* Unit attention, Reported LUNs data has changed */
--extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
--/* Unit attention, Device internal reset */
--extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
--/* Data Protection, Write Protected */
--extern const struct SCSISense sense_code_WRITE_PROTECTED;
--/* Data Protection, Space Allocation Failed Write Protect */
--extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
--
--#define SENSE_CODE(x) sense_code_ ## x
--
--uint32_t scsi_data_cdb_xfer(uint8_t *buf);
--uint32_t scsi_cdb_xfer(uint8_t *buf);
--int scsi_cdb_length(uint8_t *buf);
--int scsi_convert_sense(uint8_t *in_buf, int in_len,
--                       uint8_t *buf, int len, bool fixed);
--
- SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
-                             uint32_t tag, uint32_t lun, void *hba_private);
- SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
-diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
-deleted file mode 100644
-index fe330385d8..0000000000
---- a/include/scsi/scsi.h
-+++ /dev/null
-@@ -1,20 +0,0 @@
--/*
-- *  SCSI helpers
-- *
-- *  Copyright 2017 Red Hat, Inc.
-- *
-- *  Authors:
-- *   Fam Zheng <famz@redhat.com>
-- *
-- * This program is free software; you can redistribute it and/or modify it
-- * under the terms of the GNU General Public License as published by the Free
-- * Software Foundation; either version 2 of the License, or (at your option)
-- * any later version.
-- */
--#ifndef QEMU_SCSI_H
--#define QEMU_SCSI_H
--
--int scsi_sense_to_errno(int key, int asc, int ascq);
--int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
--
--#endif
-diff --git a/include/scsi/utils.h b/include/scsi/utils.h
-new file mode 100644
-index 0000000000..90bf4dce6e
---- /dev/null
-+++ b/include/scsi/utils.h
-@@ -0,0 +1,119 @@
-+#ifndef SCSI_UTILS_H
-+#define SCSI_UTILS_H 1
-+
-+#ifdef CONFIG_LINUX
-+#include <scsi/sg.h>
-+#endif
-+
-+#define SCSI_CMD_BUF_SIZE      16
-+#define SCSI_SENSE_LEN         18
-+#define SCSI_SENSE_LEN_SCANNER 32
-+#define SCSI_INQUIRY_LEN       36
-+
-+enum SCSIXferMode {
-+    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
-+    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
-+    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
-+};
-+
-+typedef struct SCSICommand {
-+    uint8_t buf[SCSI_CMD_BUF_SIZE];
-+    int len;
-+    size_t xfer;
-+    uint64_t lba;
-+    enum SCSIXferMode mode;
-+} SCSICommand;
-+
-+typedef struct SCSISense {
-+    uint8_t key;
-+    uint8_t asc;
-+    uint8_t ascq;
-+} SCSISense;
-+
-+/*
-+ * Predefined sense codes
-+ */
-+
-+/* No sense data available */
-+extern const struct SCSISense sense_code_NO_SENSE;
-+/* LUN not ready, Manual intervention required */
-+extern const struct SCSISense sense_code_LUN_NOT_READY;
-+/* LUN not ready, Medium not present */
-+extern const struct SCSISense sense_code_NO_MEDIUM;
-+/* LUN not ready, medium removal prevented */
-+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
-+/* Hardware error, internal target failure */
-+extern const struct SCSISense sense_code_TARGET_FAILURE;
-+/* Illegal request, invalid command operation code */
-+extern const struct SCSISense sense_code_INVALID_OPCODE;
-+/* Illegal request, LBA out of range */
-+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 */
-+extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
-+/* Illegal request, Incompatible format */
-+extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
-+/* Illegal request, medium removal prevented */
-+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
-+/* Illegal request, Invalid Transfer Tag */
-+extern const struct SCSISense sense_code_INVALID_TAG;
-+/* Command aborted, I/O process terminated */
-+extern const struct SCSISense sense_code_IO_ERROR;
-+/* Command aborted, I_T Nexus loss occurred */
-+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
-+/* Command aborted, Logical Unit failure */
-+extern const struct SCSISense sense_code_LUN_FAILURE;
-+/* Command aborted, Overlapped Commands Attempted */
-+extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
-+/* LUN not ready, Capacity data has changed */
-+extern const struct SCSISense sense_code_CAPACITY_CHANGED;
-+/* LUN not ready, Medium not present */
-+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
-+/* Unit attention, Power on, reset or bus device reset occurred */
-+extern const struct SCSISense sense_code_RESET;
-+/* Unit attention, Medium may have changed*/
-+extern const struct SCSISense sense_code_MEDIUM_CHANGED;
-+/* Unit attention, Reported LUNs data has changed */
-+extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
-+/* Unit attention, Device internal reset */
-+extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
-+/* Data Protection, Write Protected */
-+extern const struct SCSISense sense_code_WRITE_PROTECTED;
-+/* Data Protection, Space Allocation Failed Write Protect */
-+extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
-+
-+#define SENSE_CODE(x) sense_code_ ## x
-+
-+int scsi_sense_to_errno(int key, int asc, int ascq);
-+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
-+
-+int scsi_convert_sense(uint8_t *in_buf, int in_len,
-+                       uint8_t *buf, int len, bool fixed);
-+const char *scsi_command_name(uint8_t cmd);
-+
-+uint64_t scsi_cmd_lba(SCSICommand *cmd);
-+uint32_t scsi_data_cdb_xfer(uint8_t *buf);
-+uint32_t scsi_cdb_xfer(uint8_t *buf);
-+int scsi_cdb_length(uint8_t *buf);
-+
-+/* Linux SG_IO interface.  */
-+#ifdef CONFIG_LINUX
-+#define SG_ERR_DRIVER_TIMEOUT  0x06
-+#define SG_ERR_DRIVER_SENSE    0x08
-+
-+#define SG_ERR_DID_OK          0x00
-+#define SG_ERR_DID_NO_CONNECT  0x01
-+#define SG_ERR_DID_BUS_BUSY    0x02
-+#define SG_ERR_DID_TIME_OUT    0x03
-+
-+#define SG_ERR_DRIVER_SENSE    0x08
-+#endif
-+
-+#endif
-diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
-new file mode 100644
-index 0000000000..31b82a5a36
---- /dev/null
-+++ b/scsi/Makefile.objs
-@@ -0,0 +1 @@
-+block-obj-y += utils.o
-diff --git a/scsi/utils.c b/scsi/utils.c
-new file mode 100644
-index 0000000000..2327e06da0
---- /dev/null
-+++ b/scsi/utils.c
-@@ -0,0 +1,492 @@
-+/*
-+ *  SCSI helpers
-+ *
-+ *  Copyright 2017 Red Hat, Inc.
-+ *
-+ *  Authors:
-+ *   Fam Zheng <famz@redhat.com>
-+ *   Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the Free
-+ * Software Foundation; either version 2 of the License, or (at your option)
-+ * any later version.
-+ */
-+
-+#include "qemu/osdep.h"
-+#include "block/scsi.h"
-+#include "scsi/utils.h"
-+#include "qemu/bswap.h"
-+
-+uint32_t scsi_data_cdb_xfer(uint8_t *buf)
-+{
-+    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
-+        return 256;
-+    } else {
-+        return scsi_cdb_xfer(buf);
-+    }
-+}
-+
-+uint32_t scsi_cdb_xfer(uint8_t *buf)
-+{
-+    switch (buf[0] >> 5) {
-+    case 0:
-+        return buf[4];
-+        break;
-+    case 1:
-+    case 2:
-+        return lduw_be_p(&buf[7]);
-+        break;
-+    case 4:
-+        return ldl_be_p(&buf[10]) & 0xffffffffULL;
-+        break;
-+    case 5:
-+        return ldl_be_p(&buf[6]) & 0xffffffffULL;
-+        break;
-+    default:
-+        return -1;
-+    }
-+}
-+
-+uint64_t scsi_cmd_lba(SCSICommand *cmd)
-+{
-+    uint8_t *buf = cmd->buf;
-+    uint64_t lba;
-+
-+    switch (buf[0] >> 5) {
-+    case 0:
-+        lba = ldl_be_p(&buf[0]) & 0x1fffff;
-+        break;
-+    case 1:
-+    case 2:
-+    case 5:
-+        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
-+        break;
-+    case 4:
-+        lba = ldq_be_p(&buf[2]);
-+        break;
-+    default:
-+        lba = -1;
-+
-+    }
-+    return lba;
-+}
-+
-+int scsi_cdb_length(uint8_t *buf)
-+{
-+    int cdb_len;
-+
-+    switch (buf[0] >> 5) {
-+    case 0:
-+        cdb_len = 6;
-+        break;
-+    case 1:
-+    case 2:
-+        cdb_len = 10;
-+        break;
-+    case 4:
-+        cdb_len = 16;
-+        break;
-+    case 5:
-+        cdb_len = 12;
-+        break;
-+    default:
-+        cdb_len = -1;
-+    }
-+    return cdb_len;
-+}
-+
-+/*
-+ * Predefined sense codes
-+ */
-+
-+/* No sense data available */
-+const struct SCSISense sense_code_NO_SENSE = {
-+    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
-+};
-+
-+/* LUN not ready, Manual intervention required */
-+const struct SCSISense sense_code_LUN_NOT_READY = {
-+    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
-+};
-+
-+/* LUN not ready, Medium not present */
-+const struct SCSISense sense_code_NO_MEDIUM = {
-+    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
-+};
-+
-+/* LUN not ready, medium removal prevented */
-+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
-+    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
-+};
-+
-+/* Hardware error, internal target failure */
-+const struct SCSISense sense_code_TARGET_FAILURE = {
-+    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
-+};
-+
-+/* Illegal request, invalid command operation code */
-+const struct SCSISense sense_code_INVALID_OPCODE = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
-+};
-+
-+/* Illegal request, LBA out of range */
-+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
-+};
-+
-+/* Illegal request, Invalid field in CDB */
-+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
-+};
-+
-+/* Illegal request, Saving parameters not supported */
-+const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
-+};
-+
-+/* Illegal request, Incompatible medium installed */
-+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
-+};
-+
-+/* Illegal request, medium removal prevented */
-+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
-+};
-+
-+/* Illegal request, Invalid Transfer Tag */
-+const struct SCSISense sense_code_INVALID_TAG = {
-+    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
-+};
-+
-+/* Command aborted, I/O process terminated */
-+const struct SCSISense sense_code_IO_ERROR = {
-+    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
-+};
-+
-+/* Command aborted, I_T Nexus loss occurred */
-+const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
-+    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
-+};
-+
-+/* Command aborted, Logical Unit failure */
-+const struct SCSISense sense_code_LUN_FAILURE = {
-+    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
-+};
-+
-+/* Command aborted, Overlapped Commands Attempted */
-+const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
-+    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
-+};
-+
-+/* Unit attention, Capacity data has changed */
-+const struct SCSISense sense_code_CAPACITY_CHANGED = {
-+    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-+};
-+
-+/* Unit attention, Power on, reset or bus device reset occurred */
-+const struct SCSISense sense_code_RESET = {
-+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
-+};
-+
-+/* Unit attention, No medium */
-+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
-+    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-+};
-+
-+/* Unit attention, Medium may have changed */
-+const struct SCSISense sense_code_MEDIUM_CHANGED = {
-+    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
-+};
-+
-+/* Unit attention, Reported LUNs data has changed */
-+const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
-+    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
-+};
-+
-+/* Unit attention, Device internal reset */
-+const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
-+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
-+};
-+
-+/* Data Protection, Write Protected */
-+const struct SCSISense sense_code_WRITE_PROTECTED = {
-+    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
-+};
-+
-+/* Data Protection, Space Allocation Failed Write Protect */
-+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
-+    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
-+};
-+
-+/*
-+ * scsi_convert_sense
-+ *
-+ * Convert between fixed and descriptor sense buffers
-+ */
-+int scsi_convert_sense(uint8_t *in_buf, int in_len,
-+                       uint8_t *buf, int len, bool fixed)
-+{
-+    bool fixed_in;
-+    SCSISense sense;
-+    if (!fixed && len < 8) {
-+        return 0;
-+    }
-+
-+    if (in_len == 0) {
-+        sense.key = NO_SENSE;
-+        sense.asc = 0;
-+        sense.ascq = 0;
-+    } else {
-+        fixed_in = (in_buf[0] & 2) == 0;
-+
-+        if (fixed == fixed_in) {
-+            memcpy(buf, in_buf, MIN(len, in_len));
-+            return MIN(len, in_len);
-+        }
-+
-+        if (fixed_in) {
-+            sense.key = in_buf[2];
-+            sense.asc = in_buf[12];
-+            sense.ascq = in_buf[13];
-+        } else {
-+            sense.key = in_buf[1];
-+            sense.asc = in_buf[2];
-+            sense.ascq = in_buf[3];
-+        }
-+    }
-+
-+    memset(buf, 0, len);
-+    if (fixed) {
-+        /* Return fixed format sense buffer */
-+        buf[0] = 0x70;
-+        buf[2] = sense.key;
-+        buf[7] = 10;
-+        buf[12] = sense.asc;
-+        buf[13] = sense.ascq;
-+        return MIN(len, SCSI_SENSE_LEN);
-+    } else {
-+        /* Return descriptor format sense buffer */
-+        buf[0] = 0x72;
-+        buf[1] = sense.key;
-+        buf[2] = sense.asc;
-+        buf[3] = sense.ascq;
-+        return 8;
-+    }
-+}
-+
-+int scsi_sense_to_errno(int key, int asc, int ascq)
-+{
-+    switch (key) {
-+    case 0x00: /* NO SENSE */
-+    case 0x01: /* RECOVERED ERROR */
-+    case 0x06: /* UNIT ATTENTION */
-+        /* These sense keys are not errors */
-+        return 0;
-+    case 0x0b: /* COMMAND ABORTED */
-+        return ECANCELED;
-+    case 0x02: /* NOT READY */
-+    case 0x05: /* ILLEGAL REQUEST */
-+    case 0x07: /* DATA PROTECTION */
-+        /* Parse ASCQ */
-+        break;
-+    default:
-+        return EIO;
-+    }
-+    switch ((asc << 8) | ascq) {
-+    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
-+    case 0x2000: /* INVALID OPERATION CODE */
-+    case 0x2400: /* INVALID FIELD IN CDB */
-+    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
-+        return EINVAL;
-+    case 0x2100: /* LBA OUT OF RANGE */
-+    case 0x2707: /* SPACE ALLOC FAILED */
-+        return ENOSPC;
-+    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
-+        return ENOTSUP;
-+    case 0x3a00: /* MEDIUM NOT PRESENT */
-+    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
-+    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
-+        return ENOMEDIUM;
-+    case 0x2700: /* WRITE PROTECTED */
-+        return EACCES;
-+    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
-+        return EAGAIN;
-+    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
-+        return ENOTCONN;
-+    default:
-+        return EIO;
-+    }
-+}
-+
-+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
-+{
-+    int key, asc, ascq;
-+    if (sense_size < 1) {
-+        return EIO;
-+    }
-+    switch (sense[0]) {
-+    case 0x70: /* Fixed format sense data. */
-+        if (sense_size < 14) {
-+            return EIO;
-+        }
-+        key = sense[2] & 0xF;
-+        asc = sense[12];
-+        ascq = sense[13];
-+        break;
-+    case 0x72: /* Descriptor format sense data. */
-+        if (sense_size < 4) {
-+            return EIO;
-+        }
-+        key = sense[1] & 0xF;
-+        asc = sense[2];
-+        ascq = sense[3];
-+        break;
-+    default:
-+        return EIO;
-+        break;
-+    }
-+    return scsi_sense_to_errno(key, asc, ascq);
-+}
-+
-+const char *scsi_command_name(uint8_t cmd)
-+{
-+    static const char *names[] = {
-+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
-+        [ REWIND                   ] = "REWIND",
-+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
-+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
-+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
-+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
-+        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
-+        [ READ_6                   ] = "READ_6",
-+        [ WRITE_6                  ] = "WRITE_6",
-+        [ SET_CAPACITY             ] = "SET_CAPACITY",
-+        [ READ_REVERSE             ] = "READ_REVERSE",
-+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
-+        [ SPACE                    ] = "SPACE",
-+        [ INQUIRY                  ] = "INQUIRY",
-+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
-+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
-+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
-+        [ MODE_SELECT              ] = "MODE_SELECT",
-+        [ RESERVE                  ] = "RESERVE",
-+        [ RELEASE                  ] = "RELEASE",
-+        [ COPY                     ] = "COPY",
-+        [ ERASE                    ] = "ERASE",
-+        [ MODE_SENSE               ] = "MODE_SENSE",
-+        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
-+        /* LOAD_UNLOAD and START_STOP use the same operation code */
-+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
-+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
-+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
-+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
-+        [ READ_10                  ] = "READ_10",
-+        [ WRITE_10                 ] = "WRITE_10",
-+        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
-+        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
-+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
-+        [ VERIFY_10                ] = "VERIFY_10",
-+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
-+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
-+        [ SEARCH_LOW               ] = "SEARCH_LOW",
-+        [ SET_LIMITS               ] = "SET_LIMITS",
-+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
-+        /* READ_POSITION and PRE_FETCH use the same operation code */
-+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
-+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
-+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
-+        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
-+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
-+        [ COMPARE                  ] = "COMPARE",
-+        [ COPY_VERIFY              ] = "COPY_VERIFY",
-+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
-+        [ READ_BUFFER              ] = "READ_BUFFER",
-+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
-+        [ READ_LONG_10             ] = "READ_LONG_10",
-+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
-+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
-+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
-+        [ UNMAP                    ] = "UNMAP",
-+        [ READ_TOC                 ] = "READ_TOC",
-+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
-+        [ SANITIZE                 ] = "SANITIZE",
-+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
-+        [ LOG_SELECT               ] = "LOG_SELECT",
-+        [ LOG_SENSE                ] = "LOG_SENSE",
-+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
-+        [ RESERVE_10               ] = "RESERVE_10",
-+        [ RELEASE_10               ] = "RELEASE_10",
-+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
-+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
-+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
-+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
-+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
-+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
-+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
-+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
-+        [ READ_16                  ] = "READ_16",
-+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
-+        [ WRITE_16                 ] = "WRITE_16",
-+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
-+        [ VERIFY_16                ] = "VERIFY_16",
-+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
-+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
-+        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
-+        [ LOCATE_16                ] = "LOCATE_16",
-+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
-+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
-+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
-+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
-+        [ REPORT_LUNS              ] = "REPORT_LUNS",
-+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
-+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
-+        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
-+        [ READ_12                  ] = "READ_12",
-+        [ WRITE_12                 ] = "WRITE_12",
-+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
-+        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
-+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
-+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
-+        [ VERIFY_12                ] = "VERIFY_12",
-+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
-+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
-+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
-+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
-+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
-+        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
-+        [ READ_CD                  ] = "READ_CD",
-+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
-+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
-+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
-+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
-+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
-+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
-+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
-+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
-+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
-+        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
-+        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
-+    };
-+
-+    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) {
-+        return "*UNKNOWN*";
-+    }
-+    return names[cmd];
-+}
-diff --git a/util/Makefile.objs b/util/Makefile.objs
-index c9e6c493d3..50a55ecc75 100644
---- a/util/Makefile.objs
-+++ b/util/Makefile.objs
-@@ -45,4 +45,3 @@ util-obj-y += qht.o
- util-obj-y += range.o
- util-obj-y += stats64.o
- util-obj-y += systemd.o
--util-obj-y += scsi.o
-diff --git a/util/scsi.c b/util/scsi.c
-deleted file mode 100644
-index 472293d59b..0000000000
---- a/util/scsi.c
-+++ /dev/null
-@@ -1,90 +0,0 @@
--/*
-- *  SCSI helpers
-- *
-- *  Copyright 2017 Red Hat, Inc.
-- *
-- *  Authors:
-- *   Fam Zheng <famz@redhat.com>
-- *
-- * This program is free software; you can redistribute it and/or modify it
-- * under the terms of the GNU General Public License as published by the Free
-- * Software Foundation; either version 2 of the License, or (at your option)
-- * any later version.
-- */
--
--#include "qemu/osdep.h"
--#include "scsi/scsi.h"
--
--int scsi_sense_to_errno(int key, int asc, int ascq)
--{
--    switch (key) {
--    case 0x00: /* NO SENSE */
--    case 0x01: /* RECOVERED ERROR */
--    case 0x06: /* UNIT ATTENTION */
--        /* These sense keys are not errors */
--        return 0;
--    case 0x0b: /* COMMAND ABORTED */
--        return ECANCELED;
--    case 0x02: /* NOT READY */
--    case 0x05: /* ILLEGAL REQUEST */
--    case 0x07: /* DATA PROTECTION */
--        /* Parse ASCQ */
--        break;
--    default:
--        return EIO;
--    }
--    switch ((asc << 8) | ascq) {
--    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
--    case 0x2000: /* INVALID OPERATION CODE */
--    case 0x2400: /* INVALID FIELD IN CDB */
--    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
--        return EINVAL;
--    case 0x2100: /* LBA OUT OF RANGE */
--    case 0x2707: /* SPACE ALLOC FAILED */
--        return ENOSPC;
--    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
--        return ENOTSUP;
--    case 0x3a00: /* MEDIUM NOT PRESENT */
--    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
--    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
--        return ENOMEDIUM;
--    case 0x2700: /* WRITE PROTECTED */
--        return EACCES;
--    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
--        return EAGAIN;
--    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
--        return ENOTCONN;
--    default:
--        return EIO;
--    }
--}
--
--int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
--{
--    int key, asc, ascq;
--    if (sense_size < 1) {
--        return EIO;
--    }
--    switch (sense[0]) {
--    case 0x70: /* Fixed format sense data. */
--        if (sense_size < 14) {
--            return EIO;
--        }
--        key = sense[2] & 0xF;
--        asc = sense[12];
--        ascq = sense[13];
--        break;
--    case 0x72: /* Descriptor format sense data. */
--        if (sense_size < 4) {
--            return EIO;
--        }
--        key = sense[1] & 0xF;
--        asc = sense[2];
--        ascq = sense[3];
--        break;
--    default:
--        return EIO;
--        break;
--    }
--    return scsi_sense_to_errno(key, asc, ascq);
--}
--- 
-2.13.5
-
diff --git a/1009-scsi-introduce-scsi_build_sense.patch b/1009-scsi-introduce-scsi_build_sense.patch
deleted file mode 100644
index 8b16369..0000000
--- a/1009-scsi-introduce-scsi_build_sense.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 82e922c8be1b32eeb0c8c22165cdeff39e12d3ef Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 09:42:59 +0200
-Subject: [PATCH 09/15] scsi: introduce scsi_build_sense
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Move more knowledge of sense data format out of hw/scsi/scsi-bus.c
-for reusability.
-
-Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
-Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- hw/scsi/scsi-bus.c   |  8 +-------
- include/scsi/utils.h |  2 ++
- scsi/utils.c         | 11 +++++++++++
- 3 files changed, 14 insertions(+), 7 deletions(-)
-
-diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
-index 42920d5422..652ab046ab 100644
---- a/hw/scsi/scsi-bus.c
-+++ b/hw/scsi/scsi-bus.c
-@@ -818,13 +818,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
- {
-     trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
-                                sense.key, sense.asc, sense.ascq);
--    memset(req->sense, 0, 18);
--    req->sense[0] = 0x70;
--    req->sense[2] = sense.key;
--    req->sense[7] = 10;
--    req->sense[12] = sense.asc;
--    req->sense[13] = sense.ascq;
--    req->sense_len = 18;
-+    req->sense_len = scsi_build_sense(req->sense, sense);
- }
- 
- static void scsi_req_enqueue_internal(SCSIRequest *req)
-diff --git a/include/scsi/utils.h b/include/scsi/utils.h
-index 90bf4dce6e..b49392d841 100644
---- a/include/scsi/utils.h
-+++ b/include/scsi/utils.h
-@@ -30,6 +30,8 @@ typedef struct SCSISense {
-     uint8_t ascq;
- } SCSISense;
- 
-+int scsi_build_sense(uint8_t *buf, SCSISense sense);
-+
- /*
-  * Predefined sense codes
-  */
-diff --git a/scsi/utils.c b/scsi/utils.c
-index 2327e06da0..89d9167d9d 100644
---- a/scsi/utils.c
-+++ b/scsi/utils.c
-@@ -96,6 +96,17 @@ int scsi_cdb_length(uint8_t *buf)
-     return cdb_len;
- }
- 
-+int scsi_build_sense(uint8_t *buf, SCSISense sense)
-+{
-+    memset(buf, 0, 18);
-+    buf[0] = 0x70;
-+    buf[2] = sense.key;
-+    buf[7] = 10;
-+    buf[12] = sense.asc;
-+    buf[13] = sense.ascq;
-+    return 18;
-+}
-+
- /*
-  * Predefined sense codes
-  */
--- 
-2.13.5
-
diff --git a/1010-scsi-introduce-sg_io_sense_from_errno.patch b/1010-scsi-introduce-sg_io_sense_from_errno.patch
deleted file mode 100644
index 7cb02e1..0000000
--- a/1010-scsi-introduce-sg_io_sense_from_errno.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From 1ebf7935eca7f2a1f5a1376ee3b234f4fce98023 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 09:43:14 +0200
-Subject: [PATCH 10/15] scsi: introduce sg_io_sense_from_errno
-
-Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
-reusability.
-
-Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
- include/scsi/utils.h   |  3 +++
- scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
- 3 files changed, 45 insertions(+), 33 deletions(-)
-
-diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
-index 7a8f500934..04c687ee76 100644
---- a/hw/scsi/scsi-generic.c
-+++ b/hw/scsi/scsi-generic.c
-@@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
- static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
- {
-     int status;
-+    SCSISense sense;
- 
-     assert(r->req.aiocb == NULL);
- 
-@@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
-         scsi_req_cancel_complete(&r->req);
-         goto done;
-     }
--    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
--        r->req.sense_len = r->io_header.sb_len_wr;
--    }
--
--    if (ret != 0) {
--        switch (ret) {
--        case -EDOM:
--            status = TASK_SET_FULL;
--            break;
--        case -ENOMEM:
--            status = CHECK_CONDITION;
--            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
--            break;
--        default:
--            status = CHECK_CONDITION;
--            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
--            break;
--        }
--    } else {
--        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
--            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
--            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
--            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
--            status = BUSY;
--            BADF("Driver Timeout\n");
--        } else if (r->io_header.host_status) {
--            status = CHECK_CONDITION;
--            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
--        } else if (r->io_header.status) {
--            status = r->io_header.status;
--        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
--            status = CHECK_CONDITION;
-+    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
-+    if (status == CHECK_CONDITION) {
-+        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-+            r->req.sense_len = r->io_header.sb_len_wr;
-         } else {
--            status = GOOD;
-+            scsi_req_build_sense(&r->req, sense);
-         }
-     }
-+
-     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
-             r, r->req.tag, status);
- 
-diff --git a/include/scsi/utils.h b/include/scsi/utils.h
-index b49392d841..d301b31768 100644
---- a/include/scsi/utils.h
-+++ b/include/scsi/utils.h
-@@ -116,6 +116,9 @@ int scsi_cdb_length(uint8_t *buf);
- #define SG_ERR_DID_TIME_OUT    0x03
- 
- #define SG_ERR_DRIVER_SENSE    0x08
-+
-+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
-+                           SCSISense *sense);
- #endif
- 
- #endif
-diff --git a/scsi/utils.c b/scsi/utils.c
-index 89d9167d9d..6ee9f4095b 100644
---- a/scsi/utils.c
-+++ b/scsi/utils.c
-@@ -501,3 +501,38 @@ const char *scsi_command_name(uint8_t cmd)
-     }
-     return names[cmd];
- }
-+
-+#ifdef CONFIG_LINUX
-+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
-+                           SCSISense *sense)
-+{
-+    if (errno_value != 0) {
-+        switch (errno_value) {
-+        case EDOM:
-+            return TASK_SET_FULL;
-+        case ENOMEM:
-+            *sense = SENSE_CODE(TARGET_FAILURE);
-+            return CHECK_CONDITION;
-+        default:
-+            *sense = SENSE_CODE(IO_ERROR);
-+            return CHECK_CONDITION;
-+        }
-+    } else {
-+        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
-+            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
-+            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
-+            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
-+            return BUSY;
-+        } else if (io_hdr->host_status) {
-+            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
-+            return CHECK_CONDITION;
-+        } else if (io_hdr->status) {
-+            return io_hdr->status;
-+        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
-+            return CHECK_CONDITION;
-+        } else {
-+            return GOOD;
-+        }
-+    }
-+}
-+#endif
--- 
-2.13.5
-
diff --git a/1011-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch b/1011-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
deleted file mode 100644
index 1541323..0000000
--- a/1011-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
+++ /dev/null
@@ -1,250 +0,0 @@
-From e2b560d9f9966d7256488d0a359200c65c2c07f8 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 09:23:55 +0200
-Subject: [PATCH 11/15] scsi: move block/scsi.h to include/scsi/constants.h
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Complete the transition by renaming this header, which was
-shared by block/iscsi.c and the SCSI emulation code.
-
-Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
-Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- block/iscsi.c                              | 2 +-
- hw/block/virtio-blk.c                      | 2 +-
- hw/scsi/megasas.c                          | 2 +-
- hw/scsi/mptendian.c                        | 2 +-
- hw/scsi/mptsas.c                           | 2 +-
- hw/scsi/scsi-bus.c                         | 2 +-
- hw/scsi/scsi-disk.c                        | 2 +-
- hw/scsi/scsi-generic.c                     | 2 +-
- hw/scsi/spapr_vscsi.c                      | 2 +-
- hw/scsi/virtio-scsi-dataplane.c            | 2 +-
- hw/scsi/virtio-scsi.c                      | 2 +-
- hw/scsi/vmw_pvscsi.c                       | 2 +-
- hw/usb/dev-uas.c                           | 2 +-
- include/hw/ide/internal.h                  | 2 +-
- include/{block/scsi.h => scsi/constants.h} | 0
- scsi/utils.c                               | 2 +-
- tests/virtio-scsi-test.c                   | 2 +-
- 17 files changed, 16 insertions(+), 16 deletions(-)
- rename include/{block/scsi.h => scsi/constants.h} (100%)
-
-diff --git a/block/iscsi.c b/block/iscsi.c
-index 40adc3c493..c4586be720 100644
---- a/block/iscsi.c
-+++ b/block/iscsi.c
-@@ -34,7 +34,7 @@
- #include "qemu/bitops.h"
- #include "qemu/bitmap.h"
- #include "block/block_int.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "qemu/iov.h"
- #include "qemu/uuid.h"
- #include "qmp-commands.h"
-diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
-index a16ac75090..05d1440786 100644
---- a/hw/block/virtio-blk.c
-+++ b/hw/block/virtio-blk.c
-@@ -22,7 +22,7 @@
- #include "sysemu/blockdev.h"
- #include "hw/virtio/virtio-blk.h"
- #include "dataplane/virtio-blk.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #ifdef __linux__
- # include <scsi/sg.h>
- #endif
-diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
-index 734fdaef90..0db68aacee 100644
---- a/hw/scsi/megasas.c
-+++ b/hw/scsi/megasas.c
-@@ -27,7 +27,7 @@
- #include "hw/pci/msix.h"
- #include "qemu/iov.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "trace.h"
- #include "qapi/error.h"
- #include "mfi.h"
-diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
-index b7fe2a2a36..3415229b5e 100644
---- a/hw/scsi/mptendian.c
-+++ b/hw/scsi/mptendian.c
-@@ -28,7 +28,7 @@
- #include "hw/pci/msi.h"
- #include "qemu/iov.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "trace.h"
- 
- #include "mptsas.h"
-diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
-index 765ab53c34..8bae8f543e 100644
---- a/hw/scsi/mptsas.c
-+++ b/hw/scsi/mptsas.c
-@@ -30,7 +30,7 @@
- #include "hw/pci/msi.h"
- #include "qemu/iov.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "trace.h"
- #include "qapi/error.h"
- #include "mptsas.h"
-diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
-index 652ab046ab..977f7bce1f 100644
---- a/hw/scsi/scsi-bus.c
-+++ b/hw/scsi/scsi-bus.c
-@@ -3,7 +3,7 @@
- #include "qapi/error.h"
- #include "qemu/error-report.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "hw/qdev.h"
- #include "sysemu/block-backend.h"
- #include "sysemu/blockdev.h"
-diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
-index 0a1f4ef0c7..5faf6682c5 100644
---- a/hw/scsi/scsi-disk.c
-+++ b/hw/scsi/scsi-disk.c
-@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
- #include "qapi/error.h"
- #include "qemu/error-report.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "sysemu/sysemu.h"
- #include "sysemu/block-backend.h"
- #include "sysemu/blockdev.h"
-diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
-index 04c687ee76..bd0d9ff355 100644
---- a/hw/scsi/scsi-generic.c
-+++ b/hw/scsi/scsi-generic.c
-@@ -34,7 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
- do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
- 
- #include <scsi/sg.h>
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- 
- #ifndef MAX_UINT
- #define MAX_UINT ((unsigned int)-1)
-diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
-index 55ee48c4da..360db53ac8 100644
---- a/hw/scsi/spapr_vscsi.c
-+++ b/hw/scsi/spapr_vscsi.c
-@@ -36,7 +36,7 @@
- #include "cpu.h"
- #include "hw/hw.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "srp.h"
- #include "hw/qdev.h"
- #include "hw/ppc/spapr.h"
-diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
-index 944ea4eb53..add4b3f4a4 100644
---- a/hw/scsi/virtio-scsi-dataplane.c
-+++ b/hw/scsi/virtio-scsi-dataplane.c
-@@ -17,7 +17,7 @@
- #include "qemu/error-report.h"
- #include "sysemu/block-backend.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "hw/virtio/virtio-bus.h"
- #include "hw/virtio/virtio-access.h"
- 
-diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
-index eb639442d1..823a1e9a42 100644
---- a/hw/scsi/virtio-scsi.c
-+++ b/hw/scsi/virtio-scsi.c
-@@ -21,7 +21,7 @@
- #include "qemu/iov.h"
- #include "sysemu/block-backend.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "hw/virtio/virtio-bus.h"
- #include "hw/virtio/virtio-access.h"
- 
-diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
-index 77d8b6f9e2..6d3f0bf11d 100644
---- a/hw/scsi/vmw_pvscsi.c
-+++ b/hw/scsi/vmw_pvscsi.c
-@@ -28,7 +28,7 @@
- #include "qemu/osdep.h"
- #include "qapi/error.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "hw/pci/msi.h"
- #include "vmw_pvscsi.h"
- #include "trace.h"
-diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
-index fffc424396..c218b53f09 100644
---- a/hw/usb/dev-uas.c
-+++ b/hw/usb/dev-uas.c
-@@ -19,7 +19,7 @@
- #include "hw/usb.h"
- #include "hw/usb/desc.h"
- #include "hw/scsi/scsi.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- 
- /* --------------------------------------------------------------------- */
- 
-diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
-index 482a9512be..63a99e0366 100644
---- a/include/hw/ide/internal.h
-+++ b/include/hw/ide/internal.h
-@@ -11,7 +11,7 @@
- #include "sysemu/dma.h"
- #include "sysemu/sysemu.h"
- #include "hw/block/block.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- 
- /* debug IDE devices */
- //#define DEBUG_IDE
-diff --git a/include/block/scsi.h b/include/scsi/constants.h
-similarity index 100%
-rename from include/block/scsi.h
-rename to include/scsi/constants.h
-diff --git a/scsi/utils.c b/scsi/utils.c
-index 6ee9f4095b..fab60bdf20 100644
---- a/scsi/utils.c
-+++ b/scsi/utils.c
-@@ -14,7 +14,7 @@
-  */
- 
- #include "qemu/osdep.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "scsi/utils.h"
- #include "qemu/bswap.h"
- 
-diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
-index 87a3b6e81a..082d323541 100644
---- a/tests/virtio-scsi-test.c
-+++ b/tests/virtio-scsi-test.c
-@@ -10,7 +10,7 @@
- 
- #include "qemu/osdep.h"
- #include "libqtest.h"
--#include "block/scsi.h"
-+#include "scsi/constants.h"
- #include "libqos/libqos-pc.h"
- #include "libqos/libqos-spapr.h"
- #include "libqos/virtio.h"
--- 
-2.13.5
-
diff --git a/1012-scsi-file-posix-add-support-for-persistent-reservati.patch b/1012-scsi-file-posix-add-support-for-persistent-reservati.patch
deleted file mode 100644
index 2780bb3..0000000
--- a/1012-scsi-file-posix-add-support-for-persistent-reservati.patch
+++ /dev/null
@@ -1,440 +0,0 @@
-From 5c4a4b825189c2e9f322c8673104add7f76e38d5 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Mon, 21 Aug 2017 18:58:56 +0200
-Subject: [PATCH 12/15] scsi, file-posix: add support for persistent
- reservation management
-
-It is a common requirement for virtual machine to send persistent
-reservations, but this currently requires either running QEMU with
-CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged
-QEMU bypass Linux's filter on SG_IO commands.
-
-As an alternative mechanism, the next patches will introduce a
-privileged helper to run persistent reservation commands without
-expanding QEMU's attack surface unnecessarily.
-
-The helper is invoked through a "pr-manager" QOM object, to which
-file-posix.c passes SG_IO requests for PERSISTENT RESERVE OUT and
-PERSISTENT RESERVE IN commands.  For example:
-
-  $ qemu-system-x86_64
-      -device virtio-scsi \
-      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-      -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
-      -device scsi-block,drive=hd
-
-or:
-
-  $ qemu-system-x86_64
-      -device virtio-scsi \
-      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-      -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
-      -device scsi-block,drive=hd
-
-Multiple pr-manager implementations are conceivable and possible, though
-only one is implemented right now.  For example, a pr-manager could:
-
-- talk directly to the multipath daemon from a privileged QEMU
-  (i.e. QEMU links to libmpathpersist); this makes reservation work
-  properly with multipath, but still requires CAP_SYS_RAWIO
-
-- use the Linux IOC_PR_* ioctls (they require CAP_SYS_ADMIN though)
-
-- more interestingly, implement reservations directly in QEMU
-  through file system locks or a shared database (e.g. sqlite)
-
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- Makefile.objs             |   1 +
- block/file-posix.c        |  30 +++++++++++++
- docs/pr-manager.rst       |  51 ++++++++++++++++++++++
- include/scsi/pr-manager.h |  56 ++++++++++++++++++++++++
- qapi/block-core.json      |   4 ++
- scsi/Makefile.objs        |   2 +
- scsi/pr-manager.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++++
- scsi/trace-events         |   3 ++
- vl.c                      |   3 +-
- 9 files changed, 258 insertions(+), 1 deletion(-)
- create mode 100644 docs/pr-manager.rst
- create mode 100644 include/scsi/pr-manager.h
- create mode 100644 scsi/pr-manager.c
- create mode 100644 scsi/trace-events
-
-diff --git a/Makefile.objs b/Makefile.objs
-index f68aa3b60d..64bebd05db 100644
---- a/Makefile.objs
-+++ b/Makefile.objs
-@@ -168,6 +168,7 @@ trace-events-subdirs += qapi
- trace-events-subdirs += accel/tcg
- trace-events-subdirs += accel/kvm
- trace-events-subdirs += nbd
-+trace-events-subdirs += scsi
- 
- trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
- 
-diff --git a/block/file-posix.c b/block/file-posix.c
-index cb3bfce147..9cacf06685 100644
---- a/block/file-posix.c
-+++ b/block/file-posix.c
-@@ -34,6 +34,9 @@
- #include "qapi/util.h"
- #include "qapi/qmp/qstring.h"
- 
-+#include "scsi/pr-manager.h"
-+#include "scsi/constants.h"
-+
- #if defined(__APPLE__) && (__MACH__)
- #include <paths.h>
- #include <sys/param.h>
-@@ -156,6 +159,8 @@ typedef struct BDRVRawState {
-     bool page_cache_inconsistent:1;
-     bool has_fallocate;
-     bool needs_alignment;
-+
-+    PRManager *pr_mgr;
- } BDRVRawState;
- 
- typedef struct BDRVRawReopenState {
-@@ -403,6 +408,11 @@ static QemuOptsList raw_runtime_opts = {
-             .type = QEMU_OPT_STRING,
-             .help = "file locking mode (on/off/auto, default: auto)",
-         },
-+        {
-+            .name = "pr-manager",
-+            .type = QEMU_OPT_STRING,
-+            .help = "id of persistent reservation manager object (default: none)",
-+        },
-         { /* end of list */ }
-     },
- };
-@@ -414,6 +424,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
-     QemuOpts *opts;
-     Error *local_err = NULL;
-     const char *filename = NULL;
-+    const char *str;
-     BlockdevAioOptions aio, aio_default;
-     int fd, ret;
-     struct stat st;
-@@ -475,6 +486,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
-         abort();
-     }
- 
-+    str = qemu_opt_get(opts, "pr-manager");
-+    if (str) {
-+        s->pr_mgr = pr_manager_lookup(str, &local_err);
-+        if (local_err) {
-+            error_propagate(errp, local_err);
-+            ret = -EINVAL;
-+            goto fail;
-+        }
-+    }
-+
-     s->open_flags = open_flags;
-     raw_parse_flags(bdrv_flags, &s->open_flags);
- 
-@@ -2597,6 +2618,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
-     if (fd_open(bs) < 0)
-         return NULL;
- 
-+    if (req == SG_IO && s->pr_mgr) {
-+        struct sg_io_hdr *io_hdr = buf;
-+        if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
-+            io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
-+            return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
-+                                      s->fd, io_hdr, cb, opaque);
-+        }
-+    }
-+
-     acb = g_new(RawPosixAIOData, 1);
-     acb->bs = bs;
-     acb->aio_type = QEMU_AIO_IOCTL;
-diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
-new file mode 100644
-index 0000000000..b6089fb57c
---- /dev/null
-+++ b/docs/pr-manager.rst
-@@ -0,0 +1,51 @@
-+======================================
-+Persistent reservation managers
-+======================================
-+
-+SCSI persistent Reservations allow restricting access to block devices
-+to specific initiators in a shared storage setup.  When implementing
-+clustering of virtual machines, it is a common requirement for virtual
-+machines to send persistent reservation SCSI commands.  However,
-+the operating system restricts sending these commands to unprivileged
-+programs because incorrect usage can disrupt regular operation of the
-+storage fabric.
-+
-+For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
-+and ``scsi-generic`` (both are only available on Linux) can delegate
-+implementation of persistent reservations to a separate object,
-+the "persistent reservation manager".  Only PERSISTENT RESERVE OUT and
-+PERSISTENT RESERVE IN commands are passed to the persistent reservation
-+manager object; other commands are processed by QEMU as usual.
-+
-+-----------------------------------------
-+Defining a persistent reservation manager
-+-----------------------------------------
-+
-+A persistent reservation manager is an instance of a subclass of the
-+"pr-manager" QOM class.
-+
-+Right now only one subclass is defined, ``pr-manager-helper``, which
-+forwards the commands to an external privileged helper program
-+over Unix sockets.  The helper program only allows sending persistent
-+reservation commands to devices for which QEMU has a file descriptor,
-+so that QEMU will not be able to effect persistent reservations
-+unless it has access to both the socket and the device.
-+
-+``pr-manager-helper`` has a single string property, ``path``, which
-+accepts the path to the helper program's Unix socket.  For example,
-+the following command line defines a ``pr-manager-helper`` object and
-+attaches it to a SCSI passthrough device::
-+
-+      $ qemu-system-x86_64
-+          -device virtio-scsi \
-+          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-+          -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
-+          -device scsi-block,drive=hd
-+
-+Alternatively, using ``-blockdev``::
-+
-+      $ qemu-system-x86_64
-+          -device virtio-scsi \
-+          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-+          -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
-+          -device scsi-block,drive=hd
-diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h
-new file mode 100644
-index 0000000000..b2b37d63bc
---- /dev/null
-+++ b/include/scsi/pr-manager.h
-@@ -0,0 +1,56 @@
-+#ifndef PR_MANAGER_H
-+#define PR_MANAGER_H
-+
-+#include "qom/object.h"
-+#include "qapi/qmp/qdict.h"
-+#include "qapi/visitor.h"
-+#include "qom/object_interfaces.h"
-+#include "block/aio.h"
-+
-+#define TYPE_PR_MANAGER "pr-manager"
-+
-+#define PR_MANAGER_CLASS(klass) \
-+     OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER)
-+#define PR_MANAGER_GET_CLASS(obj) \
-+     OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER)
-+#define PR_MANAGER(obj) \
-+     OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER)
-+
-+struct sg_io_hdr;
-+
-+typedef struct PRManager {
-+    /* <private> */
-+    Object parent;
-+} PRManager;
-+
-+/**
-+ * PRManagerClass:
-+ * @parent_class: the base class
-+ * @run: callback invoked in thread pool context
-+ */
-+typedef struct PRManagerClass {
-+    /* <private> */
-+    ObjectClass parent_class;
-+
-+    /* <public> */
-+    int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr);
-+} PRManagerClass;
-+
-+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
-+                               AioContext *ctx, int fd,
-+                               struct sg_io_hdr *hdr,
-+                               BlockCompletionFunc *complete,
-+                               void *opaque);
-+
-+#ifdef CONFIG_LINUX
-+PRManager *pr_manager_lookup(const char *id, Error **errp);
-+#else
-+static inline PRManager *pr_manager_lookup(const char *id, Error **errp)
-+{
-+    /* The classes do not exist at all!  */
-+    error_setg(errp, "No persistent reservation manager with id '%s'", id);
-+    return NULL;
-+}
-+#endif
-+
-+#endif
-diff --git a/qapi/block-core.json b/qapi/block-core.json
-index 833c602150..1cf6ec8be7 100644
---- a/qapi/block-core.json
-+++ b/qapi/block-core.json
-@@ -2191,6 +2191,9 @@
- # Driver specific block device options for the file backend.
- #
- # @filename:    path to the image file
-+# @pr-manager:  the id for the object that will handle persistent reservations
-+#               for this device (default: none, forward the commands via SG_IO;
-+#               since 2.11)
- # @aio:         AIO backend (default: threads) (since: 2.8)
- # @locking:     whether to enable file locking. If set to 'auto', only enable
- #               when Open File Descriptor (OFD) locking API is available
-@@ -2200,6 +2203,7 @@
- ##
- { 'struct': 'BlockdevOptionsFile',
-   'data': { 'filename': 'str',
-+            '*pr-manager': 'str',
-             '*locking': 'OnOffAuto',
-             '*aio': 'BlockdevAioOptions' } }
- 
-diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
-index 31b82a5a36..5496d2ae6a 100644
---- a/scsi/Makefile.objs
-+++ b/scsi/Makefile.objs
-@@ -1 +1,3 @@
- block-obj-y += utils.o
-+
-+block-obj-$(CONFIG_LINUX) += pr-manager.o
-diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
-new file mode 100644
-index 0000000000..87c45db5d4
---- /dev/null
-+++ b/scsi/pr-manager.c
-@@ -0,0 +1,109 @@
-+/*
-+ * Persistent reservation manager abstract class
-+ *
-+ * Copyright (c) 2017 Red Hat, Inc.
-+ *
-+ * Author: Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * This code is licensed under the LGPL.
-+ *
-+ */
-+
-+#include "qemu/osdep.h"
-+#include <scsi/sg.h>
-+
-+#include "qapi/error.h"
-+#include "block/aio.h"
-+#include "block/thread-pool.h"
-+#include "scsi/pr-manager.h"
-+#include "trace.h"
-+
-+typedef struct PRManagerData {
-+    PRManager *pr_mgr;
-+    struct sg_io_hdr *hdr;
-+    int fd;
-+} PRManagerData;
-+
-+static int pr_manager_worker(void *opaque)
-+{
-+    PRManagerData *data = opaque;
-+    PRManager *pr_mgr = data->pr_mgr;
-+    PRManagerClass *pr_mgr_class =
-+        PR_MANAGER_GET_CLASS(pr_mgr);
-+    struct sg_io_hdr *hdr = data->hdr;
-+    int fd = data->fd;
-+    int r;
-+
-+    g_free(data);
-+    trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]);
-+
-+    /* The reference was taken in pr_manager_execute.  */
-+    r = pr_mgr_class->run(pr_mgr, fd, hdr);
-+    object_unref(OBJECT(pr_mgr));
-+    return r;
-+}
-+
-+
-+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
-+                               AioContext *ctx, int fd,
-+                               struct sg_io_hdr *hdr,
-+                               BlockCompletionFunc *complete,
-+                               void *opaque)
-+{
-+    PRManagerData *data = g_new(PRManagerData, 1);
-+    ThreadPool *pool = aio_get_thread_pool(ctx);
-+
-+    trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque);
-+    data->pr_mgr = pr_mgr;
-+    data->fd = fd;
-+    data->hdr = hdr;
-+
-+    /* The matching object_unref is in pr_manager_worker.  */
-+    object_ref(OBJECT(pr_mgr));
-+    return thread_pool_submit_aio(pool, pr_manager_worker,
-+                                  data, complete, opaque);
-+}
-+
-+static const TypeInfo pr_manager_info = {
-+    .parent = TYPE_OBJECT,
-+    .name = TYPE_PR_MANAGER,
-+    .class_size = sizeof(PRManagerClass),
-+    .abstract = true,
-+    .interfaces = (InterfaceInfo[]) {
-+        { TYPE_USER_CREATABLE },
-+        { }
-+    }
-+};
-+
-+PRManager *pr_manager_lookup(const char *id, Error **errp)
-+{
-+    Object *obj;
-+    PRManager *pr_mgr;
-+
-+    obj = object_resolve_path_component(object_get_objects_root(), id);
-+    if (!obj) {
-+        error_setg(errp, "No persistent reservation manager with id '%s'", id);
-+        return NULL;
-+    }
-+
-+    pr_mgr = (PRManager *)
-+        object_dynamic_cast(obj,
-+                            TYPE_PR_MANAGER);
-+    if (!pr_mgr) {
-+        error_setg(errp,
-+                   "Object with id '%s' is not a persistent reservation manager",
-+                   id);
-+        return NULL;
-+    }
-+
-+    return pr_mgr;
-+}
-+
-+static void
-+pr_manager_register_types(void)
-+{
-+    type_register_static(&pr_manager_info);
-+}
-+
-+
-+type_init(pr_manager_register_types);
-diff --git a/scsi/trace-events b/scsi/trace-events
-new file mode 100644
-index 0000000000..45f5b6e49b
---- /dev/null
-+++ b/scsi/trace-events
-@@ -0,0 +1,3 @@
-+# scsi/pr-manager.c
-+pr_manager_execute(int fd, int cmd, int sa, void *opaque) "fd=%d cmd=0x%02x service action=0x%02x opaque=%p"
-+pr_manager_run(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x"
-diff --git a/vl.c b/vl.c
-index 8e247cc2a2..af0e6576ab 100644
---- a/vl.c
-+++ b/vl.c
-@@ -2811,7 +2811,8 @@ static int machine_set_property(void *opaque,
-  */
- static bool object_create_initial(const char *type)
- {
--    if (g_str_equal(type, "rng-egd")) {
-+    if (g_str_equal(type, "rng-egd") ||
-+        g_str_has_prefix(type, "pr-manager-")) {
-         return false;
-     }
- 
--- 
-2.13.5
-
diff --git a/1013-scsi-build-qemu-pr-helper.patch b/1013-scsi-build-qemu-pr-helper.patch
deleted file mode 100644
index 795bb75..0000000
--- a/1013-scsi-build-qemu-pr-helper.patch
+++ /dev/null
@@ -1,1013 +0,0 @@
-From 226e00649123536737dcd20ccb5bd3d54d074338 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 06:50:18 +0200
-Subject: [PATCH 13/15] scsi: build qemu-pr-helper
-
-Introduce a privileged helper to run persistent reservation commands.
-This lets virtual machines send persistent reservations without using
-CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
-and SCM_RIGHTS to restrict access to processes that can access its socket
-and prove that they have an open file descriptor for a raw SCSI device.
-
-The next patch will also correct the usage of persistent reservations
-with multipath devices.
-
-It would also be possible to support for Linux's IOC_PR_* ioctls in
-the future, to support NVMe devices.  For now, however, only SCSI is
-supported.
-
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- Makefile                   |   4 +-
- configure                  |  14 +-
- docs/interop/pr-helper.rst |  83 +++++
- docs/pr-manager.rst        |  33 ++
- scsi/pr-helper.h           |  41 +++
- scsi/qemu-pr-helper.c      | 735 +++++++++++++++++++++++++++++++++++++++++++++
- 6 files changed, 905 insertions(+), 5 deletions(-)
- create mode 100644 docs/interop/pr-helper.rst
- create mode 100644 scsi/pr-helper.h
- create mode 100644 scsi/qemu-pr-helper.c
-
-diff --git a/Makefile b/Makefile
-index eb831b98d1..8406aeb8cb 100644
---- a/Makefile
-+++ b/Makefile
-@@ -372,6 +372,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
- fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
- fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
- 
-+scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
-+
- qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
- 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
- 
-@@ -488,7 +490,7 @@ clean:
- 	rm -f *.msi
- 	find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
- 	rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
--	rm -f fsdev/*.pod
-+	rm -f fsdev/*.pod scsi/*.pod
- 	rm -f qemu-img-cmds.h
- 	rm -f ui/shader/*-vert.h ui/shader/*-frag.h
- 	@# May not be present in GENERATED_FILES
-diff --git a/configure b/configure
-index cb0f7ed0ab..becc21a0fe 100755
---- a/configure
-+++ b/configure
-@@ -5034,16 +5034,22 @@ if test "$want_tools" = "yes" ; then
-   fi
- fi
- if test "$softmmu" = yes ; then
--  if test "$virtfs" != no ; then
--    if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
-+  if test "$linux" = yes; then
-+    if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
-       virtfs=yes
-       tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
-     else
-       if test "$virtfs" = yes; then
--        error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
-+        error_exit "VirtFS requires libcap devel and libattr devel"
-       fi
-       virtfs=no
-     fi
-+    tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
-+  else
-+    if test "$virtfs" = yes; then
-+      error_exit "VirtFS is supported only on Linux"
-+    fi
-+    virtfs=no
-   fi
- fi
- 
-@@ -6506,7 +6512,7 @@ fi
- 
- # build tree in object directory in case the source is not in the current directory
- DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
--DIRS="$DIRS docs docs/interop fsdev"
-+DIRS="$DIRS docs docs/interop fsdev scsi"
- DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
- DIRS="$DIRS roms/seabios roms/vgabios"
- DIRS="$DIRS qapi-generated"
-diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst
-new file mode 100644
-index 0000000000..9f76d5bcf9
---- /dev/null
-+++ b/docs/interop/pr-helper.rst
-@@ -0,0 +1,83 @@
-+..
-+
-+======================================
-+Persistent reservation helper protocol
-+======================================
-+
-+QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
-+can delegate implementation of persistent reservations to an external
-+(and typically privileged) program.  Persistent Reservations allow
-+restricting access to block devices to specific initiators in a shared
-+storage setup.
-+
-+For a more detailed reference please refer the the SCSI Primary
-+Commands standard, specifically the section on Reservations and the
-+"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
-+
-+This document describes the socket protocol used between QEMU's
-+``pr-manager-helper`` object and the external program.
-+
-+.. contents::
-+
-+Connection and initialization
-+-----------------------------
-+
-+All data transmitted on the socket is big-endian.
-+
-+After connecting to the helper program's socket, the helper starts a simple
-+feature negotiation process by writing four bytes corresponding to
-+the features it exposes (``supported_features``).  QEMU reads it,
-+then writes four bytes corresponding to the desired features of the
-+helper program (``requested_features``).
-+
-+If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
-+the corresponding feature is not supported by the helper and the connection
-+is closed.  On the other hand, it is acceptable for a bit to be 0 in
-+``requested_features`` and 1 in ``supported_features``; in this case,
-+the helper will not enable the feature.
-+
-+Right now no feature is defined, so the two parties always write four
-+zero bytes.
-+
-+Command format
-+--------------
-+
-+It is invalid to send multiple commands concurrently on the same
-+socket.  It is however possible to connect multiple sockets to the
-+helper and send multiple commands to the helper for one or more
-+file descriptors.
-+
-+A command consists of a request and a response.  A request consists
-+of a 16-byte SCSI CDB.  A file descriptor must be passed to the helper
-+together with the SCSI CDB using ancillary data.
-+
-+The CDB has the following limitations:
-+
-+- the command (stored in the first byte) must be one of 0x5E
-+  (PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
-+
-+- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
-+  RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
-+  for PERSISTENT RESERVE OUT) is limited to 8 KiB.
-+
-+For PERSISTENT RESERVE OUT, the parameter list is sent right after the
-+CDB.  The length of the parameter list is taken from the CDB itself.
-+
-+The helper's reply has the following structure:
-+
-+- 4 bytes for the SCSI status
-+
-+- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN
-+  and only if the SCSI status is 0x00, i.e. GOOD)
-+
-+- 96 bytes for the SCSI sense data
-+
-+- if the size is nonzero, the payload follows
-+
-+The sense data is always sent to keep the protocol simple, even though
-+it is only valid if the SCSI status is CHECK CONDITION (0x02).
-+
-+The payload size is always less than or equal to the allocation length
-+specified in the CDB for the PERSISTENT RESERVE IN command.
-+
-+If the protocol is violated, the helper closes the socket.
-diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
-index b6089fb57c..7107e59fb8 100644
---- a/docs/pr-manager.rst
-+++ b/docs/pr-manager.rst
-@@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``::
-           -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-           -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
-           -device scsi-block,drive=hd
-+
-+----------------------------------
-+Invoking :program:`qemu-pr-helper`
-+----------------------------------
-+
-+QEMU provides an implementation of the persistent reservation helper,
-+called :program:`qemu-pr-helper`.  The helper should be started as a
-+system service and supports the following option:
-+
-+-d, --daemon              run in the background
-+-q, --quiet               decrease verbosity
-+-f, --pidfile=path        PID file when running as a daemon
-+-k, --socket=path         path to the socket
-+-T, --trace=trace-opts    tracing options
-+
-+By default, the socket and PID file are placed in the runtime state
-+directory, for example :file:`/var/run/qemu-pr-helper.sock` and
-+:file:`/var/run/qemu-pr-helper.pid`.  The PID file is not created
-+unless :option:`-d` is passed too.
-+
-+:program:`qemu-pr-helper` can also use the systemd socket activation
-+protocol.  In this case, the systemd socket unit should specify a
-+Unix stream socket, like this::
-+
-+    [Socket]
-+    ListenStream=/var/run/qemu-pr-helper.sock
-+
-+After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
-+root privileges, except for those capabilities that are needed for
-+its operation.  To do this, add the following options:
-+
-+-u, --user=user           user to drop privileges to
-+-g, --group=group         group to drop privileges to
-diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h
-new file mode 100644
-index 0000000000..96c50a9e5f
---- /dev/null
-+++ b/scsi/pr-helper.h
-@@ -0,0 +1,41 @@
-+/* Definitions for QEMU's persistent reservation helper daemon
-+ *
-+ * Copyright (C) 2017 Red Hat, Inc.
-+ *
-+ * Author:
-+ *   Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this software and associated documentation files (the "Software"), to
-+ * deal in the Software without restriction, including without limitation the
-+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-+ * sell copies of the Software, and to permit persons to whom the Software is
-+ * furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+#ifndef QEMU_PR_HELPER_H
-+#define QEMU_PR_HELPER_H 1
-+
-+#include <stdint.h>
-+
-+#define PR_HELPER_CDB_SIZE     16
-+#define PR_HELPER_SENSE_SIZE   96
-+#define PR_HELPER_DATA_SIZE    8192
-+
-+typedef struct PRHelperResponse {
-+    int32_t result;
-+    int32_t sz;
-+    uint8_t sense[PR_HELPER_SENSE_SIZE];
-+} PRHelperResponse;
-+
-+#endif
-diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
-new file mode 100644
-index 0000000000..e39efbd529
---- /dev/null
-+++ b/scsi/qemu-pr-helper.c
-@@ -0,0 +1,735 @@
-+/*
-+ * Privileged helper to handle persistent reservation commands for QEMU
-+ *
-+ * Copyright (C) 2017 Red Hat, Inc. <pbonzini@redhat.com>
-+ *
-+ * Author: Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; under version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "qemu/osdep.h"
-+#include <getopt.h>
-+#include <sys/ioctl.h>
-+#include <linux/dm-ioctl.h>
-+#include <scsi/sg.h>
-+
-+#ifdef CONFIG_LIBCAP
-+#include <cap-ng.h>
-+#endif
-+#include <pwd.h>
-+#include <grp.h>
-+
-+#include "qapi/error.h"
-+#include "qemu-common.h"
-+#include "qemu/cutils.h"
-+#include "qemu/main-loop.h"
-+#include "qemu/error-report.h"
-+#include "qemu/config-file.h"
-+#include "qemu/bswap.h"
-+#include "qemu/log.h"
-+#include "qemu/systemd.h"
-+#include "qapi/util.h"
-+#include "qapi/qmp/qstring.h"
-+#include "io/channel-socket.h"
-+#include "trace/control.h"
-+#include "qemu-version.h"
-+
-+#include "block/aio.h"
-+#include "block/thread-pool.h"
-+
-+#include "scsi/constants.h"
-+#include "scsi/utils.h"
-+#include "pr-helper.h"
-+
-+#define PR_OUT_FIXED_PARAM_SIZE 24
-+
-+static char *socket_path;
-+static char *pidfile;
-+static enum { RUNNING, TERMINATE, TERMINATING } state;
-+static QIOChannelSocket *server_ioc;
-+static int server_watch;
-+static int num_active_sockets = 1;
-+static int verbose;
-+
-+#ifdef CONFIG_LIBCAP
-+static int uid = -1;
-+static int gid = -1;
-+#endif
-+
-+static void usage(const char *name)
-+{
-+    (printf) (
-+"Usage: %s [OPTIONS] FILE\n"
-+"Persistent Reservation helper program for QEMU\n"
-+"\n"
-+"  -h, --help                display this help and exit\n"
-+"  -V, --version             output version information and exit\n"
-+"\n"
-+"  -d, --daemon              run in the background\n"
-+"  -f, --pidfile=PATH        PID file when running as a daemon\n"
-+"                            (default '%s')\n"
-+"  -k, --socket=PATH         path to the unix socket\n"
-+"                            (default '%s')\n"
-+"  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
-+"                            specify tracing options\n"
-+#ifdef CONFIG_LIBCAP
-+"  -u, --user=USER           user to drop privileges to\n"
-+"  -g, --group=GROUP         group to drop privileges to\n"
-+#endif
-+"\n"
-+QEMU_HELP_BOTTOM "\n"
-+    , name, pidfile, socket_path);
-+}
-+
-+static void version(const char *name)
-+{
-+    printf(
-+"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
-+"Written by Paolo Bonzini.\n"
-+"\n"
-+QEMU_COPYRIGHT "\n"
-+"This is free software; see the source for copying conditions.  There is NO\n"
-+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
-+    , name);
-+}
-+
-+static void write_pidfile(void)
-+{
-+    int pidfd;
-+    char pidstr[32];
-+
-+    pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
-+    if (pidfd == -1) {
-+        error_report("Cannot open pid file, %s", strerror(errno));
-+        exit(EXIT_FAILURE);
-+    }
-+
-+    if (lockf(pidfd, F_TLOCK, 0)) {
-+        error_report("Cannot lock pid file, %s", strerror(errno));
-+        goto fail;
-+    }
-+    if (ftruncate(pidfd, 0)) {
-+        error_report("Failed to truncate pid file");
-+        goto fail;
-+    }
-+
-+    snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
-+    if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
-+        error_report("Failed to write pid file");
-+        goto fail;
-+    }
-+    return;
-+
-+fail:
-+    unlink(pidfile);
-+    close(pidfd);
-+    exit(EXIT_FAILURE);
-+}
-+
-+/* SG_IO support */
-+
-+typedef struct PRHelperSGIOData {
-+    int fd;
-+    const uint8_t *cdb;
-+    uint8_t *sense;
-+    uint8_t *buf;
-+    int sz;              /* input/output */
-+    int dir;
-+} PRHelperSGIOData;
-+
-+static int do_sgio_worker(void *opaque)
-+{
-+    PRHelperSGIOData *data = opaque;
-+    struct sg_io_hdr io_hdr;
-+    int ret;
-+    int status;
-+    SCSISense sense_code;
-+
-+    memset(data->sense, 0, PR_HELPER_SENSE_SIZE);
-+    memset(&io_hdr, 0, sizeof(io_hdr));
-+    io_hdr.interface_id = 'S';
-+    io_hdr.cmd_len = PR_HELPER_CDB_SIZE;
-+    io_hdr.cmdp = (uint8_t *)data->cdb;
-+    io_hdr.sbp = data->sense;
-+    io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE;
-+    io_hdr.timeout = 1;
-+    io_hdr.dxfer_direction = data->dir;
-+    io_hdr.dxferp = (char *)data->buf;
-+    io_hdr.dxfer_len = data->sz;
-+    ret = ioctl(data->fd, SG_IO, &io_hdr);
-+    status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
-+                                    &sense_code);
-+    if (status == GOOD) {
-+        data->sz -= io_hdr.resid;
-+    } else {
-+        data->sz = 0;
-+    }
-+
-+    if (status == CHECK_CONDITION &&
-+        !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
-+        scsi_build_sense(data->sense, sense_code);
-+    }
-+
-+    return status;
-+}
-+
-+static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
-+                    uint8_t *buf, int *sz, int dir)
-+{
-+    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
-+    int r;
-+
-+    PRHelperSGIOData data = {
-+        .fd = fd,
-+        .cdb = cdb,
-+        .sense = sense,
-+        .buf = buf,
-+        .sz = *sz,
-+        .dir = dir,
-+    };
-+
-+    r = thread_pool_submit_co(pool, do_sgio_worker, &data);
-+    *sz = data.sz;
-+    return r;
-+}
-+
-+static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
-+                    uint8_t *data, int *resp_sz)
-+{
-+    return do_sgio(fd, cdb, sense, data, resp_sz,
-+                   SG_DXFER_FROM_DEV);
-+}
-+
-+static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
-+                     const uint8_t *param, int sz)
-+{
-+    int resp_sz = sz;
-+    return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz,
-+                   SG_DXFER_TO_DEV);
-+}
-+
-+/* Client */
-+
-+typedef struct PRHelperClient {
-+    QIOChannelSocket *ioc;
-+    Coroutine *co;
-+    int fd;
-+    uint8_t data[PR_HELPER_DATA_SIZE];
-+} PRHelperClient;
-+
-+typedef struct PRHelperRequest {
-+    int fd;
-+    size_t sz;
-+    uint8_t cdb[PR_HELPER_CDB_SIZE];
-+} PRHelperRequest;
-+
-+static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz,
-+                                 Error **errp)
-+{
-+    int ret = 0;
-+
-+    while (sz > 0) {
-+        int *fds = NULL;
-+        size_t nfds = 0;
-+        int i;
-+        struct iovec iov;
-+        ssize_t n_read;
-+
-+        iov.iov_base = buf;
-+        iov.iov_len = sz;
-+        n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
-+                                        &fds, &nfds, errp);
-+
-+        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
-+            qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
-+            continue;
-+        }
-+        if (n_read <= 0) {
-+            ret = n_read ? n_read : -1;
-+            goto err;
-+        }
-+
-+        /* Stash one file descriptor per request.  */
-+        if (nfds) {
-+            bool too_many = false;
-+            for (i = 0; i < nfds; i++) {
-+                if (client->fd == -1) {
-+                    client->fd = fds[i];
-+                } else {
-+                    close(fds[i]);
-+                    too_many = true;
-+                }
-+            }
-+            g_free(fds);
-+            if (too_many) {
-+                ret = -1;
-+                goto err;
-+            }
-+        }
-+
-+        buf += n_read;
-+        sz -= n_read;
-+    }
-+
-+    return 0;
-+
-+err:
-+    if (client->fd != -1) {
-+        close(client->fd);
-+        client->fd = -1;
-+    }
-+    return ret;
-+}
-+
-+static int coroutine_fn prh_read_request(PRHelperClient *client,
-+                                         PRHelperRequest *req,
-+                                         PRHelperResponse *resp, Error **errp)
-+{
-+    uint32_t sz;
-+
-+    if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) {
-+        return -1;
-+    }
-+
-+    if (client->fd == -1) {
-+        error_setg(errp, "No file descriptor in request.");
-+        return -1;
-+    }
-+
-+    if (req->cdb[0] != PERSISTENT_RESERVE_OUT &&
-+        req->cdb[0] != PERSISTENT_RESERVE_IN) {
-+        error_setg(errp, "Invalid CDB, closing socket.");
-+        goto out_close;
-+    }
-+
-+    sz = scsi_cdb_xfer(req->cdb);
-+    if (sz > sizeof(client->data)) {
-+        goto out_close;
-+    }
-+
-+    if (req->cdb[0] == PERSISTENT_RESERVE_OUT) {
-+        if (qio_channel_read_all(QIO_CHANNEL(client->ioc),
-+                                 (char *)client->data, sz,
-+                                 errp) < 0) {
-+            goto out_close;
-+        }
-+        if ((fcntl(client->fd, F_GETFL) & O_ACCMODE) == O_RDONLY) {
-+            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_OPCODE));
-+            sz = 0;
-+        } else if (sz < PR_OUT_FIXED_PARAM_SIZE) {
-+            /* Illegal request, Parameter list length error.  This isn't fatal;
-+             * we have read the data, send an error without closing the socket.
-+             */
-+            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN));
-+            sz = 0;
-+        }
-+        if (sz == 0) {
-+            resp->result = CHECK_CONDITION;
-+            close(client->fd);
-+            client->fd = -1;
-+        }
-+    }
-+
-+    req->fd = client->fd;
-+    req->sz = sz;
-+    client->fd = -1;
-+    return sz;
-+
-+out_close:
-+    close(client->fd);
-+    client->fd = -1;
-+    return -1;
-+}
-+
-+static int coroutine_fn prh_write_response(PRHelperClient *client,
-+                                           PRHelperRequest *req,
-+                                           PRHelperResponse *resp, Error **errp)
-+{
-+    ssize_t r;
-+    size_t sz;
-+
-+    if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) {
-+        assert(resp->sz <= req->sz && resp->sz <= sizeof(client->data));
-+    } else {
-+        assert(resp->sz == 0);
-+    }
-+
-+    sz = resp->sz;
-+
-+    resp->result = cpu_to_be32(resp->result);
-+    resp->sz = cpu_to_be32(resp->sz);
-+    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
-+                              (char *) resp, sizeof(*resp), errp);
-+    if (r < 0) {
-+        return r;
-+    }
-+
-+    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
-+                              (char *) client->data,
-+                              sz, errp);
-+    return r < 0 ? r : 0;
-+}
-+
-+static void coroutine_fn prh_co_entry(void *opaque)
-+{
-+    PRHelperClient *client = opaque;
-+    Error *local_err = NULL;
-+    uint32_t flags;
-+    int r;
-+
-+    qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
-+                             false, NULL);
-+    qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc),
-+                                   qemu_get_aio_context());
-+
-+    /* A very simple negotiation for future extensibility.  No features
-+     * are defined so write 0.
-+     */
-+    flags = cpu_to_be32(0);
-+    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
-+                             (char *) &flags, sizeof(flags), NULL);
-+    if (r < 0) {
-+        goto out;
-+    }
-+
-+    r = qio_channel_read_all(QIO_CHANNEL(client->ioc),
-+                             (char *) &flags, sizeof(flags), NULL);
-+    if (be32_to_cpu(flags) != 0 || r < 0) {
-+        goto out;
-+    }
-+
-+    while (atomic_read(&state) == RUNNING) {
-+        PRHelperRequest req;
-+        PRHelperResponse resp;
-+        int sz;
-+
-+        sz = prh_read_request(client, &req, &resp, &local_err);
-+        if (sz < 0) {
-+            break;
-+        }
-+
-+        if (sz > 0) {
-+            num_active_sockets++;
-+            if (req.cdb[0] == PERSISTENT_RESERVE_OUT) {
-+                r = do_pr_out(req.fd, req.cdb, resp.sense,
-+                              client->data, sz);
-+                resp.sz = 0;
-+            } else {
-+                resp.sz = sizeof(client->data);
-+                r = do_pr_in(req.fd, req.cdb, resp.sense,
-+                             client->data, &resp.sz);
-+                resp.sz = MIN(resp.sz, sz);
-+            }
-+            num_active_sockets--;
-+            close(req.fd);
-+            if (r == -1) {
-+                break;
-+            }
-+            resp.result = r;
-+        }
-+
-+        if (prh_write_response(client, &req, &resp, &local_err) < 0) {
-+            break;
-+        }
-+    }
-+
-+    if (local_err) {
-+        if (verbose == 0) {
-+            error_free(local_err);
-+        } else {
-+            error_report_err(local_err);
-+        }
-+    }
-+
-+out:
-+    qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
-+    object_unref(OBJECT(client->ioc));
-+    g_free(client);
-+}
-+
-+static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
-+{
-+    QIOChannelSocket *cioc;
-+    PRHelperClient *prh;
-+
-+    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
-+                                     NULL);
-+    if (!cioc) {
-+        return TRUE;
-+    }
-+
-+    prh = g_new(PRHelperClient, 1);
-+    prh->ioc = cioc;
-+    prh->fd = -1;
-+    prh->co = qemu_coroutine_create(prh_co_entry, prh);
-+    qemu_coroutine_enter(prh->co);
-+
-+    return TRUE;
-+}
-+
-+
-+/*
-+ * Check socket parameters compatibility when socket activation is used.
-+ */
-+static const char *socket_activation_validate_opts(void)
-+{
-+    if (socket_path != NULL) {
-+        return "Unix socket can't be set when using socket activation";
-+    }
-+
-+    return NULL;
-+}
-+
-+static void compute_default_paths(void)
-+{
-+    if (!socket_path) {
-+        socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock");
-+    }
-+}
-+
-+static void termsig_handler(int signum)
-+{
-+    atomic_cmpxchg(&state, RUNNING, TERMINATE);
-+    qemu_notify_event();
-+}
-+
-+static void close_server_socket(void)
-+{
-+    assert(server_ioc);
-+
-+    g_source_remove(server_watch);
-+    server_watch = -1;
-+    object_unref(OBJECT(server_ioc));
-+    num_active_sockets--;
-+}
-+
-+#ifdef CONFIG_LIBCAP
-+static int drop_privileges(void)
-+{
-+    /* clear all capabilities */
-+    capng_clear(CAPNG_SELECT_BOTH);
-+
-+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
-+                     CAP_SYS_RAWIO) < 0) {
-+        return -1;
-+    }
-+
-+    /* Change user/group id, retaining the capabilities.  Because file descriptors
-+     * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
-+     * fact the helper can run as "nobody").
-+     */
-+    if (capng_change_id(uid != -1 ? uid : getuid(),
-+                        gid != -1 ? gid : getgid(),
-+                        CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) {
-+        return -1;
-+    }
-+
-+    return 0;
-+}
-+#endif
-+
-+int main(int argc, char **argv)
-+{
-+    const char *sopt = "hVk:fdT:u:g:q";
-+    struct option lopt[] = {
-+        { "help", no_argument, NULL, 'h' },
-+        { "version", no_argument, NULL, 'V' },
-+        { "socket", required_argument, NULL, 'k' },
-+        { "pidfile", no_argument, NULL, 'f' },
-+        { "daemon", no_argument, NULL, 'd' },
-+        { "trace", required_argument, NULL, 'T' },
-+        { "user", required_argument, NULL, 'u' },
-+        { "group", required_argument, NULL, 'g' },
-+        { "quiet", no_argument, NULL, 'q' },
-+        { NULL, 0, NULL, 0 }
-+    };
-+    int opt_ind = 0;
-+    int quiet = 0;
-+    char ch;
-+    Error *local_err = NULL;
-+    char *trace_file = NULL;
-+    bool daemonize = false;
-+    unsigned socket_activation;
-+
-+    struct sigaction sa_sigterm;
-+    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
-+    sa_sigterm.sa_handler = termsig_handler;
-+    sigaction(SIGTERM, &sa_sigterm, NULL);
-+    sigaction(SIGINT, &sa_sigterm, NULL);
-+    sigaction(SIGHUP, &sa_sigterm, NULL);
-+
-+    signal(SIGPIPE, SIG_IGN);
-+
-+    module_call_init(MODULE_INIT_TRACE);
-+    module_call_init(MODULE_INIT_QOM);
-+    qemu_add_opts(&qemu_trace_opts);
-+    qemu_init_exec_dir(argv[0]);
-+
-+    pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid");
-+
-+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
-+        switch (ch) {
-+        case 'k':
-+            socket_path = optarg;
-+            if (socket_path[0] != '/') {
-+                error_report("socket path must be absolute");
-+                exit(EXIT_FAILURE);
-+            }
-+            break;
-+        case 'f':
-+            pidfile = optarg;
-+            break;
-+#ifdef CONFIG_LIBCAP
-+        case 'u': {
-+            unsigned long res;
-+            struct passwd *userinfo = getpwnam(optarg);
-+            if (userinfo) {
-+                uid = userinfo->pw_uid;
-+            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
-+                       (uid_t)res == res) {
-+                uid = res;
-+            } else {
-+                error_report("invalid user '%s'", optarg);
-+                exit(EXIT_FAILURE);
-+            }
-+            break;
-+        }
-+        case 'g': {
-+            unsigned long res;
-+            struct group *groupinfo = getgrnam(optarg);
-+            if (groupinfo) {
-+                gid = groupinfo->gr_gid;
-+            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
-+                       (gid_t)res == res) {
-+                gid = res;
-+            } else {
-+                error_report("invalid group '%s'", optarg);
-+                exit(EXIT_FAILURE);
-+            }
-+            break;
-+        }
-+#else
-+        case 'u':
-+        case 'g':
-+            error_report("-%c not supported by this %s", ch, argv[0]);
-+            exit(1);
-+#endif
-+        case 'd':
-+            daemonize = true;
-+            break;
-+        case 'q':
-+            quiet = 1;
-+            break;
-+        case 'T':
-+            g_free(trace_file);
-+            trace_file = trace_opt_parse(optarg);
-+            break;
-+        case 'V':
-+            version(argv[0]);
-+            exit(EXIT_SUCCESS);
-+            break;
-+        case 'h':
-+            usage(argv[0]);
-+            exit(EXIT_SUCCESS);
-+            break;
-+        case '?':
-+            error_report("Try `%s --help' for more information.", argv[0]);
-+            exit(EXIT_FAILURE);
-+        }
-+    }
-+
-+    /* set verbosity */
-+    verbose = !quiet;
-+
-+    if (!trace_init_backends()) {
-+        exit(EXIT_FAILURE);
-+    }
-+    trace_init_file(trace_file);
-+    qemu_set_log(LOG_TRACE);
-+
-+    socket_activation = check_socket_activation();
-+    if (socket_activation == 0) {
-+        SocketAddress saddr;
-+        compute_default_paths();
-+        saddr = (SocketAddress){
-+            .type = SOCKET_ADDRESS_TYPE_UNIX,
-+            .u.q_unix.path = g_strdup(socket_path)
-+        };
-+        server_ioc = qio_channel_socket_new();
-+        if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {
-+            object_unref(OBJECT(server_ioc));
-+            error_report_err(local_err);
-+            return 1;
-+        }
-+        g_free(saddr.u.q_unix.path);
-+    } else {
-+        /* Using socket activation - check user didn't use -p etc. */
-+        const char *err_msg = socket_activation_validate_opts();
-+        if (err_msg != NULL) {
-+            error_report("%s", err_msg);
-+            exit(EXIT_FAILURE);
-+        }
-+
-+        /* Can only listen on a single socket.  */
-+        if (socket_activation > 1) {
-+            error_report("%s does not support socket activation with LISTEN_FDS > 1",
-+                         argv[0]);
-+            exit(EXIT_FAILURE);
-+        }
-+        server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
-+                                               &local_err);
-+        if (server_ioc == NULL) {
-+            error_report("Failed to use socket activation: %s",
-+                         error_get_pretty(local_err));
-+            exit(EXIT_FAILURE);
-+        }
-+        socket_path = NULL;
-+    }
-+
-+    if (qemu_init_main_loop(&local_err)) {
-+        error_report_err(local_err);
-+        exit(EXIT_FAILURE);
-+    }
-+
-+    server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
-+                                         G_IO_IN,
-+                                         accept_client,
-+                                         NULL, NULL);
-+
-+#ifdef CONFIG_LIBCAP
-+    if (drop_privileges() < 0) {
-+        error_report("Failed to drop privileges: %s", strerror(errno));
-+        exit(EXIT_FAILURE);
-+    }
-+#endif
-+
-+    if (daemonize) {
-+        if (daemon(0, 0) < 0) {
-+            error_report("Failed to daemonize: %s", strerror(errno));
-+            exit(EXIT_FAILURE);
-+        }
-+        write_pidfile();
-+    }
-+
-+    state = RUNNING;
-+    do {
-+        main_loop_wait(false);
-+        if (state == TERMINATE) {
-+            state = TERMINATING;
-+            close_server_socket();
-+        }
-+    } while (num_active_sockets > 0);
-+
-+    exit(EXIT_SUCCESS);
-+}
--- 
-2.13.5
-
diff --git a/1014-scsi-add-multipath-support-to-qemu-pr-helper.patch b/1014-scsi-add-multipath-support-to-qemu-pr-helper.patch
deleted file mode 100644
index b1de8c1..0000000
--- a/1014-scsi-add-multipath-support-to-qemu-pr-helper.patch
+++ /dev/null
@@ -1,679 +0,0 @@
-From 43fedb8ae2c2b3bbb43023c118be708226e38179 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Tue, 22 Aug 2017 06:50:55 +0200
-Subject: [PATCH 14/15] scsi: add multipath support to qemu-pr-helper
-
-Proper support of persistent reservation for multipath devices requires
-communication with the multipath daemon, so that the reservation is
-registered and applied when a path comes up.  The device mapper
-utilities provide a library to do so; this patch makes qemu-pr-helper.c
-detect multipath devices and, when one is found, delegate the operation
-to libmpathpersist.
-
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- Makefile              |   3 +
- configure             |  46 +++++++
- docs/pr-manager.rst   |  27 ++++
- include/scsi/utils.h  |   4 +
- scsi/qemu-pr-helper.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++-
- scsi/utils.c          |  10 ++
- 6 files changed, 433 insertions(+), 3 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 8406aeb8cb..4eb40376d2 100644
---- a/Makefile
-+++ b/Makefile
-@@ -373,6 +373,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
- fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
- 
- scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
-+ifdef CONFIG_MPATH
-+scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
-+endif
- 
- qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
- 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
-diff --git a/configure b/configure
-index becc21a0fe..f6edc2a33f 100755
---- a/configure
-+++ b/configure
-@@ -290,6 +290,7 @@ netmap="no"
- sdl=""
- sdlabi=""
- virtfs=""
-+mpath=""
- vnc="yes"
- sparse="no"
- vde=""
-@@ -936,6 +937,10 @@ for opt do
-   ;;
-   --enable-virtfs) virtfs="yes"
-   ;;
-+  --disable-mpath) mpath="no"
-+  ;;
-+  --enable-mpath) mpath="yes"
-+  ;;
-   --disable-vnc) vnc="no"
-   ;;
-   --enable-vnc) vnc="yes"
-@@ -1479,6 +1484,7 @@ disabled with --disable-FEATURE, default is enabled if available:
-   vnc-png         PNG compression for VNC server
-   cocoa           Cocoa UI (Mac OS X only)
-   virtfs          VirtFS
-+  mpath           Multipath persistent reservation passthrough
-   xen             xen backend driver support
-   xen-pci-passthrough
-   brlapi          BrlAPI (Braile)
-@@ -3300,6 +3306,38 @@ else
- fi
- 
- ##########################################
-+# libmpathpersist probe
-+
-+if test "$mpath" != "no" ; then
-+  cat > $TMPC <<EOF
-+#include <libudev.h>
-+#include <mpath_persist.h>
-+unsigned mpath_mx_alloc_len = 1024;
-+int logsink;
-+static struct config *multipath_conf;
-+extern struct udev *udev;
-+extern struct config *get_multipath_config(void);
-+extern void put_multipath_config(struct config *conf);
-+struct udev *udev;
-+struct config *get_multipath_config(void) { return multipath_conf; }
-+void put_multipath_config(struct config *conf) { }
-+
-+int main(void) {
-+    udev = udev_new();
-+    multipath_conf = mpath_lib_init();
-+    return 0;
-+}
-+EOF
-+  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
-+    mpathpersist=yes
-+  else
-+    mpathpersist=no
-+  fi
-+else
-+  mpathpersist=no
-+fi
-+
-+##########################################
- # libcap probe
- 
- if test "$cap" != "no" ; then
-@@ -5044,12 +5074,24 @@ if test "$softmmu" = yes ; then
-       fi
-       virtfs=no
-     fi
-+    if test "$mpath" != no && test "$mpathpersist" = yes ; then
-+      mpath=yes
-+    else
-+      if test "$mpath" = yes; then
-+        error_exit "Multipath requires libmpathpersist devel"
-+      fi
-+      mpath=no
-+    fi
-     tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
-   else
-     if test "$virtfs" = yes; then
-       error_exit "VirtFS is supported only on Linux"
-     fi
-     virtfs=no
-+    if test "$mpath" = yes; then
-+      error_exit "Multipath is supported only on Linux"
-+    fi
-+    mpath=no
-   fi
- fi
- 
-@@ -5295,6 +5337,7 @@ echo "Audio drivers     $audio_drv_list"
- echo "Block whitelist (rw) $block_drv_rw_whitelist"
- echo "Block whitelist (ro) $block_drv_ro_whitelist"
- echo "VirtFS support    $virtfs"
-+echo "Multipath support $mpath"
- echo "VNC support       $vnc"
- if test "$vnc" = "yes" ; then
-     echo "VNC SASL support  $vnc_sasl"
-@@ -5738,6 +5781,9 @@ fi
- if test "$virtfs" = "yes" ; then
-   echo "CONFIG_VIRTFS=y" >> $config_host_mak
- fi
-+if test "$mpath" = "yes" ; then
-+  echo "CONFIG_MPATH=y" >> $config_host_mak
-+fi
- if test "$vhost_scsi" = "yes" ; then
-   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
- fi
-diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
-index 7107e59fb8..9b1de198b1 100644
---- a/docs/pr-manager.rst
-+++ b/docs/pr-manager.rst
-@@ -60,6 +60,7 @@ system service and supports the following option:
- 
- -d, --daemon              run in the background
- -q, --quiet               decrease verbosity
-+-v, --verbose             increase verbosity
- -f, --pidfile=path        PID file when running as a daemon
- -k, --socket=path         path to the socket
- -T, --trace=trace-opts    tracing options
-@@ -82,3 +83,29 @@ its operation.  To do this, add the following options:
- 
- -u, --user=user           user to drop privileges to
- -g, --group=group         group to drop privileges to
-+
-+---------------------------------------------
-+Multipath devices and persistent reservations
-+---------------------------------------------
-+
-+Proper support of persistent reservation for multipath devices requires
-+communication with the multipath daemon, so that the reservation is
-+registered and applied when a path is newly discovered or becomes online
-+again.  :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
-+library was available on the system at build time.
-+
-+As of August 2017, a reservation key must be specified in ``multipath.conf``
-+for ``multipathd`` to check for persistent reservation for newly
-+discovered paths or reinstated paths.  The attribute can be added
-+to the ``defaults`` section or the ``multipaths`` section; for example::
-+
-+    multipaths {
-+        multipath {
-+            wwid   XXXXXXXXXXXXXXXX
-+            alias      yellow
-+            reservation_key  0x123abc
-+        }
-+    }
-+
-+Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
-+its usage on regular SCSI devices.
-diff --git a/include/scsi/utils.h b/include/scsi/utils.h
-index d301b31768..00a4bdb080 100644
---- a/include/scsi/utils.h
-+++ b/include/scsi/utils.h
-@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR;
- extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
- /* Command aborted, Logical Unit failure */
- extern const struct SCSISense sense_code_LUN_FAILURE;
-+/* Command aborted, LUN Communication failure */
-+extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
- /* Command aborted, Overlapped Commands Attempted */
- extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
- /* LUN not ready, Capacity data has changed */
- extern const struct SCSISense sense_code_CAPACITY_CHANGED;
-+/* Unit attention, SCSI bus reset */
-+extern const struct SCSISense sense_code_SCSI_BUS_RESET;
- /* LUN not ready, Medium not present */
- extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
- /* Unit attention, Power on, reset or bus device reset occurred */
-diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
-index e39efbd529..5f77c873e1 100644
---- a/scsi/qemu-pr-helper.c
-+++ b/scsi/qemu-pr-helper.c
-@@ -30,6 +30,12 @@
- #include <pwd.h>
- #include <grp.h>
- 
-+#ifdef CONFIG_MPATH
-+#include <libudev.h>
-+#include <mpath_cmd.h>
-+#include <mpath_persist.h>
-+#endif
-+
- #include "qapi/error.h"
- #include "qemu-common.h"
- #include "qemu/cutils.h"
-@@ -60,6 +66,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state;
- static QIOChannelSocket *server_ioc;
- static int server_watch;
- static int num_active_sockets = 1;
-+static int noisy;
- static int verbose;
- 
- #ifdef CONFIG_LIBCAP
-@@ -204,9 +211,327 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
-     return r;
- }
- 
-+/* Device mapper interface */
-+
-+#ifdef CONFIG_MPATH
-+#define CONTROL_PATH "/dev/mapper/control"
-+
-+typedef struct DMData {
-+    struct dm_ioctl dm;
-+    uint8_t data[1024];
-+} DMData;
-+
-+static int control_fd;
-+
-+static void *dm_ioctl(int ioc, struct dm_ioctl *dm)
-+{
-+    static DMData d;
-+    memcpy(&d.dm, dm, sizeof(d.dm));
-+    QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec));
-+
-+    d.dm.version[0] = DM_VERSION_MAJOR;
-+    d.dm.version[1] = 0;
-+    d.dm.version[2] = 0;
-+    d.dm.data_size = 1024;
-+    d.dm.data_start = offsetof(DMData, data);
-+    if (ioctl(control_fd, ioc, &d) < 0) {
-+        return NULL;
-+    }
-+    memcpy(dm, &d.dm, sizeof(d.dm));
-+    return &d.data;
-+}
-+
-+static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm)
-+{
-+    struct stat st;
-+    int r;
-+
-+    r = fstat(fd, &st);
-+    if (r < 0) {
-+        perror("fstat");
-+        exit(1);
-+    }
-+
-+    dm->dev = st.st_rdev;
-+    return dm_ioctl(ioc, dm);
-+}
-+
-+static void dm_init(void)
-+{
-+    control_fd = open(CONTROL_PATH, O_RDWR);
-+    if (control_fd < 0) {
-+        perror("Cannot open " CONTROL_PATH);
-+        exit(1);
-+    }
-+    struct dm_ioctl dm = { 0 };
-+    if (!dm_ioctl(DM_VERSION, &dm)) {
-+        perror("ioctl");
-+        exit(1);
-+    }
-+    if (dm.version[0] != DM_VERSION_MAJOR) {
-+        fprintf(stderr, "Unsupported device mapper interface");
-+        exit(1);
-+    }
-+}
-+
-+/* Variables required by libmultipath and libmpathpersist.  */
-+QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN);
-+static struct config *multipath_conf;
-+unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE;
-+int logsink;
-+struct udev *udev;
-+
-+extern struct config *get_multipath_config(void);
-+struct config *get_multipath_config(void)
-+{
-+    return multipath_conf;
-+}
-+
-+extern void put_multipath_config(struct config *conf);
-+void put_multipath_config(struct config *conf)
-+{
-+}
-+
-+static void multipath_pr_init(void)
-+{
-+    udev = udev_new();
-+    multipath_conf = mpath_lib_init();
-+}
-+
-+static int is_mpath(int fd)
-+{
-+    struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG };
-+    struct dm_target_spec *tgt;
-+
-+    tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm);
-+    if (!tgt) {
-+        if (errno == ENXIO) {
-+            return 0;
-+        }
-+        perror("ioctl");
-+        exit(EXIT_FAILURE);
-+    }
-+    return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME);
-+}
-+
-+static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
-+{
-+    switch (r) {
-+    case MPATH_PR_SUCCESS:
-+        return GOOD;
-+    case MPATH_PR_SENSE_NOT_READY:
-+    case MPATH_PR_SENSE_MEDIUM_ERROR:
-+    case MPATH_PR_SENSE_HARDWARE_ERROR:
-+    case MPATH_PR_SENSE_ABORTED_COMMAND:
-+        {
-+            /* libmpathpersist ate the exact sense.  Try to find it by
-+             * issuing TEST UNIT READY.
-+             */
-+            uint8_t cdb[6] = { TEST_UNIT_READY };
-+            int sz = 0;
-+            return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE);
-+        }
-+
-+    case MPATH_PR_SENSE_UNIT_ATTENTION:
-+        /* Congratulations libmpathpersist, you ruined the Unit Attention...
-+         * Return a heavyweight one.
-+         */
-+        scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET));
-+        return CHECK_CONDITION;
-+    case MPATH_PR_SENSE_INVALID_OP:
-+        /* Only one valid sense.  */
-+        scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
-+        return CHECK_CONDITION;
-+    case MPATH_PR_ILLEGAL_REQ:
-+        /* Guess.  */
-+        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
-+        return CHECK_CONDITION;
-+    case MPATH_PR_NO_SENSE:
-+        scsi_build_sense(sense, SENSE_CODE(NO_SENSE));
-+        return CHECK_CONDITION;
-+
-+    case MPATH_PR_RESERV_CONFLICT:
-+        return RESERVATION_CONFLICT;
-+
-+    case MPATH_PR_OTHER:
-+    default:
-+        scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE));
-+        return CHECK_CONDITION;
-+    }
-+}
-+
-+static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
-+                           uint8_t *data, int sz)
-+{
-+    int rq_servact = cdb[1];
-+    struct prin_resp resp;
-+    size_t written;
-+    int r;
-+
-+    switch (rq_servact) {
-+    case MPATH_PRIN_RKEY_SA:
-+    case MPATH_PRIN_RRES_SA:
-+    case MPATH_PRIN_RCAP_SA:
-+        break;
-+    case MPATH_PRIN_RFSTAT_SA:
-+        /* Nobody implements it anyway, so bail out. */
-+    default:
-+        /* Cannot parse any other output.  */
-+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
-+        return CHECK_CONDITION;
-+    }
-+
-+    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
-+    if (r == MPATH_PR_SUCCESS) {
-+        switch (rq_servact) {
-+        case MPATH_PRIN_RKEY_SA:
-+        case MPATH_PRIN_RRES_SA: {
-+            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
-+            assert(sz >= 8);
-+            written = MIN(out->additional_length + 8, sz);
-+            stl_be_p(&data[0], out->prgeneration);
-+            stl_be_p(&data[4], out->additional_length);
-+            memcpy(&data[8], out->key_list, written - 8);
-+            break;
-+        }
-+        case MPATH_PRIN_RCAP_SA: {
-+            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
-+            assert(sz >= 6);
-+            written = 6;
-+            stw_be_p(&data[0], out->length);
-+            data[2] = out->flags[0];
-+            data[3] = out->flags[1];
-+            stw_be_p(&data[4], out->pr_type_mask);
-+            break;
-+        }
-+        default:
-+            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
-+            return CHECK_CONDITION;
-+        }
-+        assert(written <= sz);
-+        memset(data + written, 0, sz - written);
-+    }
-+
-+    return mpath_reconstruct_sense(fd, r, sense);
-+}
-+
-+static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
-+                            const uint8_t *param, int sz)
-+{
-+    int rq_servact = cdb[1];
-+    int rq_scope = cdb[2] >> 4;
-+    int rq_type = cdb[2] & 0xf;
-+    struct prout_param_descriptor paramp;
-+    char transportids[PR_HELPER_DATA_SIZE];
-+    int r;
-+
-+    switch (rq_servact) {
-+    case MPATH_PROUT_REG_SA:
-+    case MPATH_PROUT_RES_SA:
-+    case MPATH_PROUT_REL_SA:
-+    case MPATH_PROUT_CLEAR_SA:
-+    case MPATH_PROUT_PREE_SA:
-+    case MPATH_PROUT_PREE_AB_SA:
-+    case MPATH_PROUT_REG_IGN_SA:
-+        break;
-+    case MPATH_PROUT_REG_MOV_SA:
-+        /* Not supported by struct prout_param_descriptor.  */
-+    default:
-+        /* Cannot parse any other input.  */
-+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
-+        return CHECK_CONDITION;
-+    }
-+
-+    /* Convert input data, especially transport IDs, to the structs
-+     * used by libmpathpersist (which, of course, will immediately
-+     * do the opposite).
-+     */
-+    memset(&paramp, 0, sizeof(paramp));
-+    memcpy(&paramp.key, &param[0], 8);
-+    memcpy(&paramp.sa_key, &param[8], 8);
-+    paramp.sa_flags = param[10];
-+    if (sz > PR_OUT_FIXED_PARAM_SIZE) {
-+        size_t transportid_len;
-+        int i, j;
-+        if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) {
-+            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN));
-+            return CHECK_CONDITION;
-+        }
-+        transportid_len = ldl_be_p(&param[24]) + PR_OUT_FIXED_PARAM_SIZE + 4;
-+        if (transportid_len > sz) {
-+            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
-+            return CHECK_CONDITION;
-+        }
-+        for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) {
-+            struct transportid *id = (struct transportid *) &transportids[j];
-+            int len;
-+
-+            id->format_code = param[i] & 0xc0;
-+            id->protocol_id = param[i] & 0x0f;
-+            switch (param[i] & 0xcf) {
-+            case 0:
-+                /* FC transport.  */
-+                if (i + 24 > transportid_len) {
-+                    goto illegal_req;
-+                }
-+                memcpy(id->n_port_name, &param[i + 8], 8);
-+                j += offsetof(struct transportid, n_port_name[8]);
-+                i += 24;
-+                break;
-+            case 3:
-+            case 0x43:
-+                /* iSCSI transport.  */
-+                len = lduw_be_p(&param[i + 2]);
-+                if (len > 252 || (len & 3) || i + len + 4 > transportid_len) {
-+                    /* For format code 00, the standard says the maximum is 223
-+                     * plus the NUL terminator.  For format code 01 there is no
-+                     * maximum length, but libmpathpersist ignores the first
-+                     * byte of id->iscsi_name so our maximum is 252.
-+                     */
-+                    goto illegal_req;
-+                }
-+                if (memchr(&param[i + 4], 0, len) == NULL) {
-+                    goto illegal_req;
-+                }
-+                memcpy(id->iscsi_name, &param[i + 2], len + 2);
-+                j += offsetof(struct transportid, iscsi_name[len + 2]);
-+                i += len + 4;
-+                break;
-+            case 6:
-+                /* SAS transport.  */
-+                if (i + 24 > transportid_len) {
-+                    goto illegal_req;
-+                }
-+                memcpy(id->sas_address, &param[i + 4], 8);
-+                j += offsetof(struct transportid, sas_address[8]);
-+                i += 24;
-+                break;
-+            default:
-+            illegal_req:
-+                scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
-+                return CHECK_CONDITION;
-+            }
-+
-+            paramp.trnptid_list[paramp.num_transportid++] = id;
-+        }
-+    }
-+
-+    r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type,
-+                                     &paramp, noisy, verbose);
-+    return mpath_reconstruct_sense(fd, r, sense);
-+}
-+#endif
-+
- static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
-                     uint8_t *data, int *resp_sz)
- {
-+#ifdef CONFIG_MPATH
-+    if (is_mpath(fd)) {
-+        /* multipath_pr_in fills the whole input buffer.  */
-+        return multipath_pr_in(fd, cdb, sense, data, *resp_sz);
-+    }
-+#endif
-+
-     return do_sgio(fd, cdb, sense, data, resp_sz,
-                    SG_DXFER_FROM_DEV);
- }
-@@ -214,7 +528,14 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
- static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
-                      const uint8_t *param, int sz)
- {
--    int resp_sz = sz;
-+    int resp_sz;
-+#ifdef CONFIG_MPATH
-+    if (is_mpath(fd)) {
-+        return multipath_pr_out(fd, cdb, sense, param, sz);
-+    }
-+#endif
-+
-+    resp_sz = sz;
-     return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz,
-                    SG_DXFER_TO_DEV);
- }
-@@ -525,6 +846,14 @@ static int drop_privileges(void)
-         return -1;
-     }
- 
-+#ifdef CONFIG_MPATH
-+    /* For /dev/mapper/control ioctls */
-+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
-+                     CAP_SYS_ADMIN) < 0) {
-+        return -1;
-+    }
-+#endif
-+
-     /* Change user/group id, retaining the capabilities.  Because file descriptors
-      * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
-      * fact the helper can run as "nobody").
-@@ -541,7 +870,7 @@ static int drop_privileges(void)
- 
- int main(int argc, char **argv)
- {
--    const char *sopt = "hVk:fdT:u:g:q";
-+    const char *sopt = "hVk:fdT:u:g:vq";
-     struct option lopt[] = {
-         { "help", no_argument, NULL, 'h' },
-         { "version", no_argument, NULL, 'V' },
-@@ -551,10 +880,12 @@ int main(int argc, char **argv)
-         { "trace", required_argument, NULL, 'T' },
-         { "user", required_argument, NULL, 'u' },
-         { "group", required_argument, NULL, 'g' },
-+        { "verbose", no_argument, NULL, 'v' },
-         { "quiet", no_argument, NULL, 'q' },
-         { NULL, 0, NULL, 0 }
-     };
-     int opt_ind = 0;
-+    int loglevel = 1;
-     int quiet = 0;
-     char ch;
-     Error *local_err = NULL;
-@@ -631,6 +962,9 @@ int main(int argc, char **argv)
-         case 'q':
-             quiet = 1;
-             break;
-+        case 'v':
-+            ++loglevel;
-+            break;
-         case 'T':
-             g_free(trace_file);
-             trace_file = trace_opt_parse(optarg);
-@@ -650,7 +984,8 @@ int main(int argc, char **argv)
-     }
- 
-     /* set verbosity */
--    verbose = !quiet;
-+    noisy = !quiet && (loglevel >= 3);
-+    verbose = quiet ? 0 : MIN(loglevel, 3);
- 
-     if (!trace_init_backends()) {
-         exit(EXIT_FAILURE);
-@@ -658,6 +993,11 @@ int main(int argc, char **argv)
-     trace_init_file(trace_file);
-     qemu_set_log(LOG_TRACE);
- 
-+#ifdef CONFIG_MPATH
-+    dm_init();
-+    multipath_pr_init();
-+#endif
-+
-     socket_activation = check_socket_activation();
-     if (socket_activation == 0) {
-         SocketAddress saddr;
-diff --git a/scsi/utils.c b/scsi/utils.c
-index fab60bdf20..5684951b12 100644
---- a/scsi/utils.c
-+++ b/scsi/utils.c
-@@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
-     .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
- };
- 
-+/* Command aborted, LUN Communication Failure */
-+const struct SCSISense sense_code_LUN_COMM_FAILURE = {
-+    .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
-+};
-+
- /* Unit attention, Capacity data has changed */
- const struct SCSISense sense_code_CAPACITY_CHANGED = {
-     .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-@@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET = {
-     .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
- };
- 
-+/* Unit attention, SCSI bus reset */
-+const struct SCSISense sense_code_SCSI_BUS_RESET = {
-+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02
-+};
-+
- /* Unit attention, No medium */
- const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
-     .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
--- 
-2.13.5
-
diff --git a/1015-scsi-add-persistent-reservation-manager-using-qemu-p.patch b/1015-scsi-add-persistent-reservation-manager-using-qemu-p.patch
deleted file mode 100644
index acc9e7f..0000000
--- a/1015-scsi-add-persistent-reservation-manager-using-qemu-p.patch
+++ /dev/null
@@ -1,335 +0,0 @@
-From 3caf122d29ecc3317671a9f651a236e8d02e2e90 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Mon, 21 Aug 2017 18:58:56 +0200
-Subject: [PATCH 15/15] scsi: add persistent reservation manager using
- qemu-pr-helper
-
-This adds a concrete subclass of pr-manager that talks to qemu-pr-helper.
-
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- scsi/Makefile.objs       |   2 +-
- scsi/pr-manager-helper.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 303 insertions(+), 1 deletion(-)
- create mode 100644 scsi/pr-manager-helper.c
-
-diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
-index 5496d2ae6a..4d25e476cf 100644
---- a/scsi/Makefile.objs
-+++ b/scsi/Makefile.objs
-@@ -1,3 +1,3 @@
- block-obj-y += utils.o
- 
--block-obj-$(CONFIG_LINUX) += pr-manager.o
-+block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o
-diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c
-new file mode 100644
-index 0000000000..82ff6b6123
---- /dev/null
-+++ b/scsi/pr-manager-helper.c
-@@ -0,0 +1,302 @@
-+/*
-+ * Persistent reservation manager that talks to qemu-pr-helper
-+ *
-+ * Copyright (c) 2017 Red Hat, Inc.
-+ *
-+ * Author: Paolo Bonzini <pbonzini@redhat.com>
-+ *
-+ * This code is licensed under the LGPL v2.1 or later.
-+ *
-+ */
-+
-+#include "qemu/osdep.h"
-+#include "qapi/error.h"
-+#include "scsi/constants.h"
-+#include "scsi/pr-manager.h"
-+#include "scsi/utils.h"
-+#include "io/channel.h"
-+#include "io/channel-socket.h"
-+#include "pr-helper.h"
-+
-+#include <scsi/sg.h>
-+
-+#define PR_MAX_RECONNECT_ATTEMPTS 5
-+
-+#define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
-+
-+#define PR_MANAGER_HELPER(obj) \
-+     OBJECT_CHECK(PRManagerHelper, (obj), \
-+                  TYPE_PR_MANAGER_HELPER)
-+
-+typedef struct PRManagerHelper {
-+    /* <private> */
-+    PRManager parent;
-+
-+    char *path;
-+
-+    QemuMutex lock;
-+    QIOChannel *ioc;
-+} PRManagerHelper;
-+
-+/* Called with lock held.  */
-+static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
-+                                  void *buf, int sz, Error **errp)
-+{
-+    ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
-+
-+    if (r < 0) {
-+        object_unref(OBJECT(pr_mgr->ioc));
-+        pr_mgr->ioc = NULL;
-+        return -EINVAL;
-+    }
-+
-+    return 0;
-+}
-+
-+/* Called with lock held.  */
-+static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
-+                                   int fd,
-+                                   const void *buf, int sz, Error **errp)
-+{
-+    size_t nfds = (fd != -1);
-+    while (sz > 0) {
-+        struct iovec iov;
-+        ssize_t n_written;
-+
-+        iov.iov_base = (void *)buf;
-+        iov.iov_len = sz;
-+        n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
-+                                            nfds ? &fd : NULL, nfds, errp);
-+
-+        if (n_written <= 0) {
-+            assert(n_written != QIO_CHANNEL_ERR_BLOCK);
-+            object_unref(OBJECT(pr_mgr->ioc));
-+            return n_written < 0 ? -EINVAL : 0;
-+        }
-+
-+        nfds = 0;
-+        buf += n_written;
-+        sz -= n_written;
-+    }
-+
-+    return 0;
-+}
-+
-+/* Called with lock held.  */
-+static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
-+                                        Error **errp)
-+{
-+    char *path = g_strdup(pr_mgr->path);
-+    SocketAddress saddr = {
-+        .type = SOCKET_ADDRESS_TYPE_UNIX,
-+        .u.q_unix.path = path
-+    };
-+    QIOChannelSocket *sioc = qio_channel_socket_new();
-+    Error *local_err = NULL;
-+
-+    uint32_t flags;
-+    int r;
-+
-+    assert(!pr_mgr->ioc);
-+    qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
-+    qio_channel_socket_connect_sync(sioc,
-+                                    &saddr,
-+                                    &local_err);
-+    g_free(path);
-+    if (local_err) {
-+        object_unref(OBJECT(sioc));
-+        error_propagate(errp, local_err);
-+        return -ENOTCONN;
-+    }
-+
-+    qio_channel_set_delay(QIO_CHANNEL(sioc), false);
-+    pr_mgr->ioc = QIO_CHANNEL(sioc);
-+
-+    /* A simple feature negotation protocol, even though there is
-+     * no optional feature right now.
-+     */
-+    r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp);
-+    if (r < 0) {
-+        goto out_close;
-+    }
-+
-+    flags = 0;
-+    r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp);
-+    if (r < 0) {
-+        goto out_close;
-+    }
-+
-+    return 0;
-+
-+out_close:
-+    object_unref(OBJECT(pr_mgr->ioc));
-+    pr_mgr->ioc = NULL;
-+    return r;
-+}
-+
-+static int pr_manager_helper_run(PRManager *p,
-+                                 int fd, struct sg_io_hdr *io_hdr)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
-+
-+    uint32_t len;
-+    PRHelperResponse resp;
-+    int ret;
-+    int expected_dir;
-+    int attempts;
-+    uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
-+
-+    if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
-+        return -EINVAL;
-+    }
-+
-+    memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
-+    assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
-+    expected_dir =
-+        (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
-+    if (io_hdr->dxfer_direction != expected_dir) {
-+        return -EINVAL;
-+    }
-+
-+    len = scsi_cdb_xfer(cdb);
-+    if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
-+        return -EINVAL;
-+    }
-+
-+    qemu_mutex_lock(&pr_mgr->lock);
-+
-+    /* Try to reconnect while sending the CDB.  */
-+    for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
-+        if (!pr_mgr->ioc) {
-+            ret = pr_manager_helper_initialize(pr_mgr, NULL);
-+            if (ret < 0) {
-+                qemu_mutex_unlock(&pr_mgr->lock);
-+                g_usleep(G_USEC_PER_SEC);
-+                qemu_mutex_lock(&pr_mgr->lock);
-+                continue;
-+            }
-+        }
-+
-+        ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL);
-+        if (ret >= 0) {
-+            break;
-+        }
-+    }
-+    if (ret < 0) {
-+        goto out;
-+    }
-+
-+    /* After sending the CDB, any communications failure causes the
-+     * command to fail.  The failure is transient, retrying the command
-+     * will invoke pr_manager_helper_initialize again.
-+     */
-+    if (expected_dir == SG_DXFER_TO_DEV) {
-+        io_hdr->resid = io_hdr->dxfer_len - len;
-+        ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL);
-+        if (ret < 0) {
-+            goto out;
-+        }
-+    }
-+    ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL);
-+    if (ret < 0) {
-+        goto out;
-+    }
-+
-+    resp.result = be32_to_cpu(resp.result);
-+    resp.sz = be32_to_cpu(resp.sz);
-+    if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) {
-+        assert(resp.sz <= io_hdr->dxfer_len);
-+        ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL);
-+        if (ret < 0) {
-+            goto out;
-+        }
-+        io_hdr->resid = io_hdr->dxfer_len - resp.sz;
-+    } else {
-+        assert(resp.sz == 0);
-+    }
-+
-+    io_hdr->status = resp.result;
-+    if (resp.result == CHECK_CONDITION) {
-+        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
-+        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
-+        memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
-+    }
-+
-+out:
-+    if (ret < 0) {
-+        int sense_len = scsi_build_sense(io_hdr->sbp,
-+                                         SENSE_CODE(LUN_COMM_FAILURE));
-+        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
-+        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
-+        io_hdr->status = CHECK_CONDITION;
-+    }
-+    qemu_mutex_unlock(&pr_mgr->lock);
-+    return ret;
-+}
-+
-+static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
-+
-+    qemu_mutex_lock(&pr_mgr->lock);
-+    pr_manager_helper_initialize(pr_mgr, errp);
-+    qemu_mutex_unlock(&pr_mgr->lock);
-+}
-+
-+static char *get_path(Object *obj, Error **errp)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
-+
-+    return g_strdup(pr_mgr->path);
-+}
-+
-+static void set_path(Object *obj, const char *str, Error **errp)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
-+
-+    g_free(pr_mgr->path);
-+    pr_mgr->path = g_strdup(str);
-+}
-+
-+static void pr_manager_helper_instance_finalize(Object *obj)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
-+
-+    object_unref(OBJECT(pr_mgr->ioc));
-+    qemu_mutex_destroy(&pr_mgr->lock);
-+}
-+
-+static void pr_manager_helper_instance_init(Object *obj)
-+{
-+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
-+
-+    qemu_mutex_init(&pr_mgr->lock);
-+}
-+
-+static void pr_manager_helper_class_init(ObjectClass *klass,
-+                                         void *class_data G_GNUC_UNUSED)
-+{
-+    PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
-+    UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
-+
-+    object_class_property_add_str(klass, "path", get_path, set_path,
-+                                  &error_abort);
-+    uc_klass->complete = pr_manager_helper_complete;
-+    prmgr_klass->run = pr_manager_helper_run;
-+}
-+
-+static const TypeInfo pr_manager_helper_info = {
-+    .parent = TYPE_PR_MANAGER,
-+    .name = TYPE_PR_MANAGER_HELPER,
-+    .instance_size = sizeof(PRManagerHelper),
-+    .instance_init = pr_manager_helper_instance_init,
-+    .instance_finalize = pr_manager_helper_instance_finalize,
-+    .class_init = pr_manager_helper_class_init,
-+};
-+
-+static void pr_manager_helper_register_types(void)
-+{
-+    type_register_static(&pr_manager_helper_info);
-+}
-+
-+type_init(pr_manager_helper_register_types);
--- 
-2.13.5
-
diff --git a/1016-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch b/1016-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
deleted file mode 100644
index 7815618..0000000
--- a/1016-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 23c1595b0297e6ca8f37559af6f0b8533aa1fd99 Mon Sep 17 00:00:00 2001
-From: "Daniel P. Berrange" <berrange@redhat.com>
-Date: Tue, 29 Aug 2017 17:03:30 +0100
-Subject: [PATCH] crypto: fix test cert generation to not use SHA1 algorithm
-
-GNUTLS 3.6.0 marked SHA1 as untrusted for certificates.
-Unfortunately the gnutls_x509_crt_sign() method we are
-using to create certificates in the test suite is fixed
-to always use SHA1. We must switch to a different method
-and explicitly ask for SHA256.
-
-Reviewed-by: Eric Blake <eblake@redhat.com>
-Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
----
- tests/crypto-tls-x509-helpers.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/tests/crypto-tls-x509-helpers.c b/tests/crypto-tls-x509-helpers.c
-index 64073d3bd3..173d4e28fb 100644
---- a/tests/crypto-tls-x509-helpers.c
-+++ b/tests/crypto-tls-x509-helpers.c
-@@ -406,7 +406,8 @@ test_tls_generate_cert(QCryptoTLSTestCertReq *req,
-      * If no 'ca' is set then we are self signing
-      * the cert. This is done for the root CA certs
-      */
--    err = gnutls_x509_crt_sign(crt, ca ? ca : crt, privkey);
-+    err = gnutls_x509_crt_sign2(crt, ca ? ca : crt, privkey,
-+                                GNUTLS_DIG_SHA256, 0);
-     if (err < 0) {
-         g_critical("Failed to sign certificate %s",
-                    gnutls_strerror(err));
--- 
-2.13.5
-
diff --git a/1017-io-fix-check-for-handshake-completion-in-TLS-test.patch b/1017-io-fix-check-for-handshake-completion-in-TLS-test.patch
deleted file mode 100644
index 536119d..0000000
--- a/1017-io-fix-check-for-handshake-completion-in-TLS-test.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 689ed13e73bdb5a5ca3366524475e3065fae854a Mon Sep 17 00:00:00 2001
-From: "Daniel P. Berrange" <berrange@redhat.com>
-Date: Tue, 29 Aug 2017 17:04:52 +0100
-Subject: [PATCH] io: fix check for handshake completion in TLS test
-
-The TLS I/O channel test had mistakenly used && instead
-of || when checking for handshake completion. As a
-result it could terminate the handshake process before
-it had actually completed. This was harmless before but
-changes in GNUTLS 3.6.0 exposed this bug and caused the
-test suite to fail.
-
-Reviewed-by: Eric Blake <eblake@redhat.com>
-Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
----
- tests/test-io-channel-tls.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
-index ff96877323..a210d01ba5 100644
---- a/tests/test-io-channel-tls.c
-+++ b/tests/test-io-channel-tls.c
-@@ -218,7 +218,7 @@ static void test_io_channel_tls(const void *opaque)
-     mainloop = g_main_context_default();
-     do {
-         g_main_context_iteration(mainloop, TRUE);
--    } while (!clientHandshake.finished &&
-+    } while (!clientHandshake.finished ||
-              !serverHandshake.finished);
- 
-     g_assert(clientHandshake.failed == data->expectClientFail);
--- 
-2.13.5
-
diff --git a/1018-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch b/1018-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
deleted file mode 100644
index d4718ea..0000000
--- a/1018-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From d4adf9675801cd90e66ecfcd6a54ca1abc5a6698 Mon Sep 17 00:00:00 2001
-From: "Daniel P. Berrange" <berrange@redhat.com>
-Date: Fri, 21 Jul 2017 12:47:39 +0100
-Subject: [PATCH] io: fix temp directory used by test-io-channel-tls test
-
-The test-io-channel-tls test was mistakenly using two of the
-same directories as test-crypto-tlssession. This causes a
-sporadic failure when using make -j$BIGNUM.
-
-Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
-Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
-Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
----
- tests/test-io-channel-tls.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
-index 8eaa208e1b..ff96877323 100644
---- a/tests/test-io-channel-tls.c
-+++ b/tests/test-io-channel-tls.c
-@@ -127,8 +127,8 @@ static void test_io_channel_tls(const void *opaque)
-     /* We'll use this for our fake client-server connection */
-     g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);
- 
--#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
--#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
-+#define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/"
-+#define SERVER_CERT_DIR "tests/test-io-channel-tls-server/"
-     mkdir(CLIENT_CERT_DIR, 0700);
-     mkdir(SERVER_CERT_DIR, 0700);
- 
--- 
-2.13.5
-
diff --git a/qemu.spec b/qemu.spec
index e87fbb0..6b0dafb 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -106,8 +106,8 @@ Requires: %{name}-block-ssh = %{epoch}:%{version}-%{release}
 
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
-Version: 2.10.0
-Release: 7%{?rcrel}%{?dist}
+Version: 2.10.1
+Release: 1%{?rcrel}%{?dist}
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
 Group: Development/Tools
@@ -142,24 +142,34 @@ Source21: 50-kvm-s390x.conf
 # /etc/security/limits.d/95-kvm-ppc64-memlock.conf
 Source22: 95-kvm-ppc64-memlock.conf
 
-Patch1001: 1001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
-Patch1002: 1002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
-Patch1003: 1003-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch
-Patch1004: 1004-scsi-Refactor-scsi-sense-interpreting-code.patch
-Patch1005: 1005-scsi-Improve-scsi_sense_to_errno.patch
-Patch1006: 1006-scsi-Introduce-scsi_sense_buf_to_errno.patch
-Patch1007: 1007-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
-Patch1008: 1008-scsi-move-non-emulation-specific-code-to-scsi.patch
-Patch1009: 1009-scsi-introduce-scsi_build_sense.patch
-Patch1010: 1010-scsi-introduce-sg_io_sense_from_errno.patch
-Patch1011: 1011-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
-Patch1012: 1012-scsi-file-posix-add-support-for-persistent-reservati.patch
-Patch1013: 1013-scsi-build-qemu-pr-helper.patch
-Patch1014: 1014-scsi-add-multipath-support-to-qemu-pr-helper.patch
-Patch1015: 1015-scsi-add-persistent-reservation-manager-using-qemu-p.patch
-Patch1016: 1016-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
-Patch1017: 1017-io-fix-check-for-handshake-completion-in-TLS-test.patch
-Patch1018: 1018-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
+# Backport persistent reservation manager in preparation for SELinux work
+Patch0001: 0001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch
+Patch0002: 0002-io-Yield-rather-than-wait-when-already-in-coroutine.patch
+Patch0003: 0003-scsi-Refactor-scsi-sense-interpreting-code.patch
+Patch0004: 0004-scsi-Improve-scsi_sense_to_errno.patch
+Patch0005: 0005-scsi-Introduce-scsi_sense_buf_to_errno.patch
+Patch0006: 0006-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch
+Patch0007: 0007-scsi-move-non-emulation-specific-code-to-scsi.patch
+Patch0008: 0008-scsi-introduce-scsi_build_sense.patch
+Patch0009: 0009-scsi-introduce-sg_io_sense_from_errno.patch
+Patch0010: 0010-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch
+Patch0011: 0011-scsi-file-posix-add-support-for-persistent-reservati.patch
+Patch0012: 0012-scsi-build-qemu-pr-helper.patch
+Patch0013: 0013-scsi-add-multipath-support-to-qemu-pr-helper.patch
+Patch0014: 0014-scsi-add-persistent-reservation-manager-using-qemu-p.patch
+
+# Add patches from git master to fix TLS test suite with new GNUTLS
+Patch0101: 0101-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch
+Patch0102: 0102-io-fix-check-for-handshake-completion-in-TLS-test.patch
+Patch0103: 0103-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch
+# Fix ppc64 KVM failure (bz #1501936)
+Patch0104: 0104-spapr-fallback-to-raw-mode-if-best-compat-mode-canno.patch
+# CVE-2017-15038: 9p: information disclosure when reading extended
+# attributes (bz #1499111)
+Patch0105: 0105-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
+# CVE-2017-15268: potential memory exhaustion via websock connection to VNC
+# (bz #1496882)
+Patch0106: 0106-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
 
 # documentation deps
 BuildRequires: texinfo
@@ -2029,6 +2039,13 @@ getent passwd qemu >/dev/null || \
 
 
 %changelog
+* Thu Oct 19 2017 Cole Robinson <crobinso@redhat.com> - 2:2.10.1-1
+- Fix ppc64 KVM failure (bz #1501936)
+- CVE-2017-15038: 9p: information disclosure when reading extended
+  attributes (bz #1499111)
+- CVE-2017-15268: potential memory exhaustion via websock connection to VNC
+  (bz #1496882)
+
 * Tue Oct 17 2017 Paolo Bonzini <pbonzini@redhat.com> - 2:2.10.0-7
 - Update patch 1014 for new libmultipath/libmpathpersist API
 - Force build to fail if multipath is not available
diff --git a/sources b/sources
index 34ef406..fa076e8 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (qemu-2.10.0.tar.xz) = 67891e78a0df8538838c5fc6d5208e1e0c23f608013818ea8f2f6b7dcbf80404113559b4d33aea32daf25bd43c2d8b5befbebf9fab16adf74a50218239cead53
+SHA512 (qemu-2.10.1.tar.xz) = 62e9717ede71a49f3ffd9b86c321470f64c90e575be1a9da01078cfc9466b0aeb08adf5d05bab7ee1e89dfce75def7b276af01f77b7151d406999e7af21b6711