peterdelevoryas / rpms / qemu

Forked from rpms/qemu 2 years ago
Clone

Blame 0013-scsi-add-multipath-support-to-qemu-pr-helper.patch

Paolo Bonzini 0fb2b2
From: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini 0fb2b2
Date: Tue, 22 Aug 2017 06:50:55 +0200
59eb7a
Subject: [PATCH] scsi: add multipath support to qemu-pr-helper
Paolo Bonzini 0fb2b2
Paolo Bonzini 0fb2b2
Proper support of persistent reservation for multipath devices requires
Paolo Bonzini 0fb2b2
communication with the multipath daemon, so that the reservation is
Paolo Bonzini 0fb2b2
registered and applied when a path comes up.  The device mapper
Paolo Bonzini 0fb2b2
utilities provide a library to do so; this patch makes qemu-pr-helper.c
Paolo Bonzini 0fb2b2
detect multipath devices and, when one is found, delegate the operation
Paolo Bonzini 0fb2b2
to libmpathpersist.
Paolo Bonzini 0fb2b2
Paolo Bonzini 0fb2b2
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini 0fb2b2
---
Paolo Bonzini 0fb2b2
 Makefile              |   3 +
59eb7a
 configure             |  54 ++++++++
Paolo Bonzini 0fb2b2
 docs/pr-manager.rst   |  27 ++++
Paolo Bonzini 0fb2b2
 include/scsi/utils.h  |   4 +
59eb7a
 scsi/qemu-pr-helper.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++-
Paolo Bonzini 0fb2b2
 scsi/utils.c          |  10 ++
59eb7a
 6 files changed, 452 insertions(+), 3 deletions(-)
Paolo Bonzini 0fb2b2
Paolo Bonzini 0fb2b2
diff --git a/Makefile b/Makefile
59eb7a
index f07c0d7e9c..060c089af9 100644
Paolo Bonzini 0fb2b2
--- a/Makefile
Paolo Bonzini 0fb2b2
+++ b/Makefile
59eb7a
@@ -383,6 +383,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
Paolo Bonzini 0fb2b2
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
Paolo Bonzini 0fb2b2
+ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
Paolo Bonzini 0fb2b2
+endif
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
Paolo Bonzini 0fb2b2
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
Paolo Bonzini 0fb2b2
diff --git a/configure b/configure
59eb7a
index 14bdf9bb31..9eeb3ebf70 100755
Paolo Bonzini 0fb2b2
--- a/configure
Paolo Bonzini 0fb2b2
+++ b/configure
59eb7a
@@ -286,6 +286,7 @@ pixman=""
Paolo Bonzini 0fb2b2
 sdl=""
Paolo Bonzini 0fb2b2
 sdlabi=""
Paolo Bonzini 0fb2b2
 virtfs=""
Paolo Bonzini 0fb2b2
+mpath=""
Paolo Bonzini 0fb2b2
 vnc="yes"
Paolo Bonzini 0fb2b2
 sparse="no"
Paolo Bonzini 0fb2b2
 vde=""
59eb7a
@@ -948,6 +949,10 @@ for opt do
Paolo Bonzini 0fb2b2
   ;;
Paolo Bonzini 0fb2b2
   --enable-virtfs) virtfs="yes"
Paolo Bonzini 0fb2b2
   ;;
Paolo Bonzini 0fb2b2
+  --disable-mpath) mpath="no"
Paolo Bonzini 0fb2b2
+  ;;
Paolo Bonzini 0fb2b2
+  --enable-mpath) mpath="yes"
Paolo Bonzini 0fb2b2
+  ;;
Paolo Bonzini 0fb2b2
   --disable-vnc) vnc="no"
Paolo Bonzini 0fb2b2
   ;;
Paolo Bonzini 0fb2b2
   --enable-vnc) vnc="yes"
59eb7a
@@ -1491,6 +1496,7 @@ disabled with --disable-FEATURE, default is enabled if available:
Paolo Bonzini 0fb2b2
   vnc-png         PNG compression for VNC server
Paolo Bonzini 0fb2b2
   cocoa           Cocoa UI (Mac OS X only)
Paolo Bonzini 0fb2b2
   virtfs          VirtFS
Paolo Bonzini 0fb2b2
+  mpath           Multipath persistent reservation passthrough
Paolo Bonzini 0fb2b2
   xen             xen backend driver support
Paolo Bonzini 0fb2b2
   xen-pci-passthrough
Paolo Bonzini 0fb2b2
   brlapi          BrlAPI (Braile)
59eb7a
@@ -3335,6 +3341,38 @@ else
59eb7a
   pixman_libs="-L\$(BUILD_DIR)/pixman/pixman/.libs -lpixman-1"
Paolo Bonzini 0fb2b2
 fi
Paolo Bonzini 0fb2b2
 
59eb7a
+##########################################
Paolo Bonzini 0fb2b2
+# libmpathpersist probe
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+if test "$mpath" != "no" ; then
Paolo Bonzini 0fb2b2
+  cat > $TMPC <
Paolo Bonzini 0fb2b2
+#include <libudev.h>
Paolo Bonzini 0fb2b2
+#include <mpath_persist.h>
Paolo Bonzini 0fb2b2
+unsigned mpath_mx_alloc_len = 1024;
Paolo Bonzini 0fb2b2
+int logsink;
Paolo Bonzini b0a774
+static struct config *multipath_conf;
Paolo Bonzini b0a774
+extern struct udev *udev;
Paolo Bonzini b0a774
+extern struct config *get_multipath_config(void);
Paolo Bonzini b0a774
+extern void put_multipath_config(struct config *conf);
Paolo Bonzini b0a774
+struct udev *udev;
Paolo Bonzini b0a774
+struct config *get_multipath_config(void) { return multipath_conf; }
Paolo Bonzini b0a774
+void put_multipath_config(struct config *conf) { }
Paolo Bonzini b0a774
+
Paolo Bonzini 0fb2b2
+int main(void) {
Paolo Bonzini b0a774
+    udev = udev_new();
Paolo Bonzini b0a774
+    multipath_conf = mpath_lib_init();
Paolo Bonzini 0fb2b2
+    return 0;
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+EOF
Paolo Bonzini 0fb2b2
+  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
Paolo Bonzini 0fb2b2
+    mpathpersist=yes
Paolo Bonzini 0fb2b2
+  else
Paolo Bonzini 0fb2b2
+    mpathpersist=no
Paolo Bonzini 0fb2b2
+  fi
Paolo Bonzini 0fb2b2
+else
Paolo Bonzini 0fb2b2
+  mpathpersist=no
Paolo Bonzini 0fb2b2
+fi
Paolo Bonzini 0fb2b2
+
59eb7a
 ##########################################
Paolo Bonzini 0fb2b2
 # libcap probe
Paolo Bonzini 0fb2b2
 
59eb7a
@@ -5080,12 +5118,24 @@ if test "$softmmu" = yes ; then
Paolo Bonzini 0fb2b2
       fi
Paolo Bonzini 0fb2b2
       virtfs=no
Paolo Bonzini 0fb2b2
     fi
Paolo Bonzini 0fb2b2
+    if test "$mpath" != no && test "$mpathpersist" = yes ; then
Paolo Bonzini 0fb2b2
+      mpath=yes
Paolo Bonzini 0fb2b2
+    else
Paolo Bonzini 0fb2b2
+      if test "$mpath" = yes; then
Paolo Bonzini 0fb2b2
+        error_exit "Multipath requires libmpathpersist devel"
Paolo Bonzini 0fb2b2
+      fi
Paolo Bonzini 0fb2b2
+      mpath=no
Paolo Bonzini 0fb2b2
+    fi
Paolo Bonzini 0fb2b2
     tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
Paolo Bonzini 0fb2b2
   else
Paolo Bonzini 0fb2b2
     if test "$virtfs" = yes; then
Paolo Bonzini 0fb2b2
       error_exit "VirtFS is supported only on Linux"
Paolo Bonzini 0fb2b2
     fi
Paolo Bonzini 0fb2b2
     virtfs=no
Paolo Bonzini 0fb2b2
+    if test "$mpath" = yes; then
Paolo Bonzini 0fb2b2
+      error_exit "Multipath is supported only on Linux"
Paolo Bonzini 0fb2b2
+    fi
Paolo Bonzini 0fb2b2
+    mpath=no
Paolo Bonzini 0fb2b2
   fi
Paolo Bonzini 0fb2b2
 fi
Paolo Bonzini 0fb2b2
 
59eb7a
@@ -5332,6 +5382,7 @@ echo "Audio drivers     $audio_drv_list"
Paolo Bonzini 0fb2b2
 echo "Block whitelist (rw) $block_drv_rw_whitelist"
Paolo Bonzini 0fb2b2
 echo "Block whitelist (ro) $block_drv_ro_whitelist"
Paolo Bonzini 0fb2b2
 echo "VirtFS support    $virtfs"
Paolo Bonzini 0fb2b2
+echo "Multipath support $mpath"
Paolo Bonzini 0fb2b2
 echo "VNC support       $vnc"
Paolo Bonzini 0fb2b2
 if test "$vnc" = "yes" ; then
Paolo Bonzini 0fb2b2
     echo "VNC SASL support  $vnc_sasl"
59eb7a
@@ -5779,6 +5830,9 @@ fi
Paolo Bonzini 0fb2b2
 if test "$virtfs" = "yes" ; then
Paolo Bonzini 0fb2b2
   echo "CONFIG_VIRTFS=y" >> $config_host_mak
Paolo Bonzini 0fb2b2
 fi
Paolo Bonzini 0fb2b2
+if test "$mpath" = "yes" ; then
Paolo Bonzini 0fb2b2
+  echo "CONFIG_MPATH=y" >> $config_host_mak
Paolo Bonzini 0fb2b2
+fi
Paolo Bonzini 0fb2b2
 if test "$vhost_scsi" = "yes" ; then
Paolo Bonzini 0fb2b2
   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
Paolo Bonzini 0fb2b2
 fi
Paolo Bonzini 0fb2b2
diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
Paolo Bonzini 0fb2b2
index 7107e59fb8..9b1de198b1 100644
Paolo Bonzini 0fb2b2
--- a/docs/pr-manager.rst
Paolo Bonzini 0fb2b2
+++ b/docs/pr-manager.rst
Paolo Bonzini 0fb2b2
@@ -60,6 +60,7 @@ system service and supports the following option:
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 -d, --daemon              run in the background
Paolo Bonzini 0fb2b2
 -q, --quiet               decrease verbosity
Paolo Bonzini 0fb2b2
+-v, --verbose             increase verbosity
Paolo Bonzini 0fb2b2
 -f, --pidfile=path        PID file when running as a daemon
Paolo Bonzini 0fb2b2
 -k, --socket=path         path to the socket
Paolo Bonzini 0fb2b2
 -T, --trace=trace-opts    tracing options
Paolo Bonzini 0fb2b2
@@ -82,3 +83,29 @@ its operation.  To do this, add the following options:
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 -u, --user=user           user to drop privileges to
Paolo Bonzini 0fb2b2
 -g, --group=group         group to drop privileges to
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+---------------------------------------------
Paolo Bonzini 0fb2b2
+Multipath devices and persistent reservations
Paolo Bonzini 0fb2b2
+---------------------------------------------
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+Proper support of persistent reservation for multipath devices requires
Paolo Bonzini 0fb2b2
+communication with the multipath daemon, so that the reservation is
Paolo Bonzini 0fb2b2
+registered and applied when a path is newly discovered or becomes online
Paolo Bonzini 0fb2b2
+again.  :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
Paolo Bonzini 0fb2b2
+library was available on the system at build time.
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+As of August 2017, a reservation key must be specified in ``multipath.conf``
Paolo Bonzini 0fb2b2
+for ``multipathd`` to check for persistent reservation for newly
Paolo Bonzini 0fb2b2
+discovered paths or reinstated paths.  The attribute can be added
Paolo Bonzini 0fb2b2
+to the ``defaults`` section or the ``multipaths`` section; for example::
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    multipaths {
Paolo Bonzini 0fb2b2
+        multipath {
Paolo Bonzini 0fb2b2
+            wwid   XXXXXXXXXXXXXXXX
Paolo Bonzini 0fb2b2
+            alias      yellow
Paolo Bonzini 0fb2b2
+            reservation_key  0x123abc
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
Paolo Bonzini 0fb2b2
+its usage on regular SCSI devices.
Paolo Bonzini 0fb2b2
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
Paolo Bonzini 0fb2b2
index d301b31768..00a4bdb080 100644
Paolo Bonzini 0fb2b2
--- a/include/scsi/utils.h
Paolo Bonzini 0fb2b2
+++ b/include/scsi/utils.h
Paolo Bonzini 0fb2b2
@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR;
Paolo Bonzini 0fb2b2
 extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
Paolo Bonzini 0fb2b2
 /* Command aborted, Logical Unit failure */
Paolo Bonzini 0fb2b2
 extern const struct SCSISense sense_code_LUN_FAILURE;
Paolo Bonzini 0fb2b2
+/* Command aborted, LUN Communication failure */
Paolo Bonzini 0fb2b2
+extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
Paolo Bonzini 0fb2b2
 /* Command aborted, Overlapped Commands Attempted */
Paolo Bonzini 0fb2b2
 extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
Paolo Bonzini 0fb2b2
 /* LUN not ready, Capacity data has changed */
Paolo Bonzini 0fb2b2
 extern const struct SCSISense sense_code_CAPACITY_CHANGED;
Paolo Bonzini 0fb2b2
+/* Unit attention, SCSI bus reset */
Paolo Bonzini 0fb2b2
+extern const struct SCSISense sense_code_SCSI_BUS_RESET;
Paolo Bonzini 0fb2b2
 /* LUN not ready, Medium not present */
Paolo Bonzini 0fb2b2
 extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
Paolo Bonzini 0fb2b2
 /* Unit attention, Power on, reset or bus device reset occurred */
Paolo Bonzini 0fb2b2
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
59eb7a
index e39efbd529..be6d1fbade 100644
Paolo Bonzini 0fb2b2
--- a/scsi/qemu-pr-helper.c
Paolo Bonzini 0fb2b2
+++ b/scsi/qemu-pr-helper.c
Paolo Bonzini 0fb2b2
@@ -30,6 +30,12 @@
Paolo Bonzini 0fb2b2
 #include <pwd.h>
Paolo Bonzini 0fb2b2
 #include <grp.h>
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+#include <libudev.h>
Paolo Bonzini 0fb2b2
+#include <mpath_cmd.h>
Paolo Bonzini 0fb2b2
+#include <mpath_persist.h>
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
 #include "qapi/error.h"
Paolo Bonzini 0fb2b2
 #include "qemu-common.h"
Paolo Bonzini 0fb2b2
 #include "qemu/cutils.h"
Paolo Bonzini 0fb2b2
@@ -60,6 +66,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state;
Paolo Bonzini 0fb2b2
 static QIOChannelSocket *server_ioc;
Paolo Bonzini 0fb2b2
 static int server_watch;
Paolo Bonzini 0fb2b2
 static int num_active_sockets = 1;
Paolo Bonzini 0fb2b2
+static int noisy;
Paolo Bonzini 0fb2b2
 static int verbose;
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 #ifdef CONFIG_LIBCAP
Paolo Bonzini b0a774
@@ -204,9 +211,327 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
     return r;
Paolo Bonzini 0fb2b2
 }
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+/* Device mapper interface */
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+#define CONTROL_PATH "/dev/mapper/control"
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+typedef struct DMData {
Paolo Bonzini 0fb2b2
+    struct dm_ioctl dm;
Paolo Bonzini 0fb2b2
+    uint8_t data[1024];
Paolo Bonzini 0fb2b2
+} DMData;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static int control_fd;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static void *dm_ioctl(int ioc, struct dm_ioctl *dm)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    static DMData d;
Paolo Bonzini 0fb2b2
+    memcpy(&d.dm, dm, sizeof(d.dm));
Paolo Bonzini 0fb2b2
+    QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec));
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    d.dm.version[0] = DM_VERSION_MAJOR;
Paolo Bonzini 0fb2b2
+    d.dm.version[1] = 0;
Paolo Bonzini 0fb2b2
+    d.dm.version[2] = 0;
Paolo Bonzini 0fb2b2
+    d.dm.data_size = 1024;
Paolo Bonzini 0fb2b2
+    d.dm.data_start = offsetof(DMData, data);
Paolo Bonzini 0fb2b2
+    if (ioctl(control_fd, ioc, &d) < 0) {
Paolo Bonzini 0fb2b2
+        return NULL;
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+    memcpy(dm, &d.dm, sizeof(d.dm));
Paolo Bonzini 0fb2b2
+    return &d.data;
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    struct stat st;
Paolo Bonzini 0fb2b2
+    int r;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    r = fstat(fd, &st);
Paolo Bonzini 0fb2b2
+    if (r < 0) {
Paolo Bonzini 0fb2b2
+        perror("fstat");
Paolo Bonzini 0fb2b2
+        exit(1);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    dm->dev = st.st_rdev;
Paolo Bonzini 0fb2b2
+    return dm_ioctl(ioc, dm);
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static void dm_init(void)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    control_fd = open(CONTROL_PATH, O_RDWR);
Paolo Bonzini 0fb2b2
+    if (control_fd < 0) {
Paolo Bonzini 0fb2b2
+        perror("Cannot open " CONTROL_PATH);
Paolo Bonzini 0fb2b2
+        exit(1);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+    struct dm_ioctl dm = { 0 };
Paolo Bonzini 0fb2b2
+    if (!dm_ioctl(DM_VERSION, &dm)) {
Paolo Bonzini 0fb2b2
+        perror("ioctl");
Paolo Bonzini 0fb2b2
+        exit(1);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+    if (dm.version[0] != DM_VERSION_MAJOR) {
Paolo Bonzini 0fb2b2
+        fprintf(stderr, "Unsupported device mapper interface");
Paolo Bonzini 0fb2b2
+        exit(1);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+/* Variables required by libmultipath and libmpathpersist.  */
Paolo Bonzini 0fb2b2
+QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN);
Paolo Bonzini b0a774
+static struct config *multipath_conf;
Paolo Bonzini 0fb2b2
+unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE;
Paolo Bonzini 0fb2b2
+int logsink;
Paolo Bonzini b0a774
+struct udev *udev;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini b0a774
+extern struct config *get_multipath_config(void);
Paolo Bonzini b0a774
+struct config *get_multipath_config(void)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini b0a774
+    return multipath_conf;
Paolo Bonzini b0a774
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini b0a774
+extern void put_multipath_config(struct config *conf);
Paolo Bonzini b0a774
+void put_multipath_config(struct config *conf)
Paolo Bonzini b0a774
+{
Paolo Bonzini b0a774
+}
Paolo Bonzini b0a774
+
Paolo Bonzini b0a774
+static void multipath_pr_init(void)
Paolo Bonzini b0a774
+{
Paolo Bonzini 0fb2b2
+    udev = udev_new();
Paolo Bonzini b0a774
+    multipath_conf = mpath_lib_init();
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static int is_mpath(int fd)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG };
Paolo Bonzini 0fb2b2
+    struct dm_target_spec *tgt;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm;;
Paolo Bonzini 0fb2b2
+    if (!tgt) {
Paolo Bonzini 0fb2b2
+        if (errno == ENXIO) {
Paolo Bonzini 0fb2b2
+            return 0;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        perror("ioctl");
Paolo Bonzini 0fb2b2
+        exit(EXIT_FAILURE);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+    return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME);
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    switch (r) {
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SUCCESS:
Paolo Bonzini 0fb2b2
+        return GOOD;
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_NOT_READY:
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_MEDIUM_ERROR:
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_HARDWARE_ERROR:
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_ABORTED_COMMAND:
Paolo Bonzini 0fb2b2
+        {
Paolo Bonzini 0fb2b2
+            /* libmpathpersist ate the exact sense.  Try to find it by
Paolo Bonzini 0fb2b2
+             * issuing TEST UNIT READY.
Paolo Bonzini 0fb2b2
+             */
Paolo Bonzini 0fb2b2
+            uint8_t cdb[6] = { TEST_UNIT_READY };
Paolo Bonzini 0fb2b2
+            int sz = 0;
Paolo Bonzini 0fb2b2
+            return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE);
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_UNIT_ATTENTION:
Paolo Bonzini 0fb2b2
+        /* Congratulations libmpathpersist, you ruined the Unit Attention...
Paolo Bonzini 0fb2b2
+         * Return a heavyweight one.
Paolo Bonzini 0fb2b2
+         */
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    case MPATH_PR_SENSE_INVALID_OP:
Paolo Bonzini 0fb2b2
+        /* Only one valid sense.  */
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    case MPATH_PR_ILLEGAL_REQ:
Paolo Bonzini 0fb2b2
+        /* Guess.  */
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    case MPATH_PR_NO_SENSE:
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(NO_SENSE));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    case MPATH_PR_RESERV_CONFLICT:
Paolo Bonzini 0fb2b2
+        return RESERVATION_CONFLICT;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    case MPATH_PR_OTHER:
Paolo Bonzini 0fb2b2
+    default:
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
+                           uint8_t *data, int sz)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    int rq_servact = cdb[1];
Paolo Bonzini 0fb2b2
+    struct prin_resp resp;
Paolo Bonzini 0fb2b2
+    size_t written;
Paolo Bonzini 0fb2b2
+    int r;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    switch (rq_servact) {
Paolo Bonzini 0fb2b2
+    case MPATH_PRIN_RKEY_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PRIN_RRES_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PRIN_RCAP_SA:
Paolo Bonzini 0fb2b2
+        break;
Paolo Bonzini 0fb2b2
+    case MPATH_PRIN_RFSTAT_SA:
Paolo Bonzini 0fb2b2
+        /* Nobody implements it anyway, so bail out. */
Paolo Bonzini 0fb2b2
+    default:
Paolo Bonzini 0fb2b2
+        /* Cannot parse any other output.  */
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
Paolo Bonzini 0fb2b2
+    if (r == MPATH_PR_SUCCESS) {
Paolo Bonzini 0fb2b2
+        switch (rq_servact) {
Paolo Bonzini 0fb2b2
+        case MPATH_PRIN_RKEY_SA:
Paolo Bonzini 0fb2b2
+        case MPATH_PRIN_RRES_SA: {
Paolo Bonzini 0fb2b2
+            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
Paolo Bonzini 0fb2b2
+            assert(sz >= 8);
Paolo Bonzini 0fb2b2
+            written = MIN(out->additional_length + 8, sz);
Paolo Bonzini 0fb2b2
+            stl_be_p(&data[0], out->prgeneration);
Paolo Bonzini 0fb2b2
+            stl_be_p(&data[4], out->additional_length);
Paolo Bonzini 0fb2b2
+            memcpy(&data[8], out->key_list, written - 8);
Paolo Bonzini 0fb2b2
+            break;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        case MPATH_PRIN_RCAP_SA: {
Paolo Bonzini 0fb2b2
+            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
Paolo Bonzini 0fb2b2
+            assert(sz >= 6);
Paolo Bonzini 0fb2b2
+            written = 6;
Paolo Bonzini 0fb2b2
+            stw_be_p(&data[0], out->length);
Paolo Bonzini 0fb2b2
+            data[2] = out->flags[0];
Paolo Bonzini 0fb2b2
+            data[3] = out->flags[1];
Paolo Bonzini 0fb2b2
+            stw_be_p(&data[4], out->pr_type_mask);
Paolo Bonzini 0fb2b2
+            break;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        default:
Paolo Bonzini 0fb2b2
+            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
Paolo Bonzini 0fb2b2
+            return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        assert(written <= sz);
Paolo Bonzini 0fb2b2
+        memset(data + written, 0, sz - written);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    return mpath_reconstruct_sense(fd, r, sense);
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
+                            const uint8_t *param, int sz)
Paolo Bonzini 0fb2b2
+{
Paolo Bonzini 0fb2b2
+    int rq_servact = cdb[1];
Paolo Bonzini 0fb2b2
+    int rq_scope = cdb[2] >> 4;
Paolo Bonzini 0fb2b2
+    int rq_type = cdb[2] & 0xf;
Paolo Bonzini 0fb2b2
+    struct prout_param_descriptor paramp;
Paolo Bonzini 0fb2b2
+    char transportids[PR_HELPER_DATA_SIZE];
Paolo Bonzini 0fb2b2
+    int r;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    switch (rq_servact) {
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_REG_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_RES_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_REL_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_CLEAR_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_PREE_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_PREE_AB_SA:
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_REG_IGN_SA:
Paolo Bonzini 0fb2b2
+        break;
Paolo Bonzini 0fb2b2
+    case MPATH_PROUT_REG_MOV_SA:
Paolo Bonzini 0fb2b2
+        /* Not supported by struct prout_param_descriptor.  */
Paolo Bonzini 0fb2b2
+    default:
Paolo Bonzini 0fb2b2
+        /* Cannot parse any other input.  */
Paolo Bonzini 0fb2b2
+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
Paolo Bonzini 0fb2b2
+        return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    /* Convert input data, especially transport IDs, to the structs
Paolo Bonzini 0fb2b2
+     * used by libmpathpersist (which, of course, will immediately
Paolo Bonzini 0fb2b2
+     * do the opposite).
Paolo Bonzini 0fb2b2
+     */
Paolo Bonzini 0fb2b2
+    memset(&paramp, 0, sizeof(paramp));
Paolo Bonzini 0fb2b2
+    memcpy(&paramp.key, &param[0], 8);
Paolo Bonzini 0fb2b2
+    memcpy(&paramp.sa_key, &param[8], 8);
Paolo Bonzini 0fb2b2
+    paramp.sa_flags = param[10];
Paolo Bonzini 0fb2b2
+    if (sz > PR_OUT_FIXED_PARAM_SIZE) {
Paolo Bonzini 0fb2b2
+        size_t transportid_len;
Paolo Bonzini 0fb2b2
+        int i, j;
Paolo Bonzini 0fb2b2
+        if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) {
Paolo Bonzini 0fb2b2
+            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN));
Paolo Bonzini 0fb2b2
+            return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        transportid_len = ldl_be_p(&param[24]) + PR_OUT_FIXED_PARAM_SIZE + 4;
Paolo Bonzini 0fb2b2
+        if (transportid_len > sz) {
Paolo Bonzini 0fb2b2
+            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
Paolo Bonzini 0fb2b2
+            return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+        for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) {
Paolo Bonzini 0fb2b2
+            struct transportid *id = (struct transportid *) &transportids[j];
Paolo Bonzini 0fb2b2
+            int len;
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+            id->format_code = param[i] & 0xc0;
Paolo Bonzini 0fb2b2
+            id->protocol_id = param[i] & 0x0f;
Paolo Bonzini 0fb2b2
+            switch (param[i] & 0xcf) {
Paolo Bonzini 0fb2b2
+            case 0:
Paolo Bonzini 0fb2b2
+                /* FC transport.  */
Paolo Bonzini 0fb2b2
+                if (i + 24 > transportid_len) {
Paolo Bonzini 0fb2b2
+                    goto illegal_req;
Paolo Bonzini 0fb2b2
+                }
Paolo Bonzini 0fb2b2
+                memcpy(id->n_port_name, &param[i + 8], 8);
Paolo Bonzini 0fb2b2
+                j += offsetof(struct transportid, n_port_name[8]);
Paolo Bonzini 0fb2b2
+                i += 24;
Paolo Bonzini 0fb2b2
+                break;
Paolo Bonzini 0fb2b2
+            case 3:
Paolo Bonzini 0fb2b2
+            case 0x43:
Paolo Bonzini 0fb2b2
+                /* iSCSI transport.  */
Paolo Bonzini 0fb2b2
+                len = lduw_be_p(&param[i + 2]);
Paolo Bonzini 0fb2b2
+                if (len > 252 || (len & 3) || i + len + 4 > transportid_len) {
Paolo Bonzini 0fb2b2
+                    /* For format code 00, the standard says the maximum is 223
Paolo Bonzini 0fb2b2
+                     * plus the NUL terminator.  For format code 01 there is no
Paolo Bonzini 0fb2b2
+                     * maximum length, but libmpathpersist ignores the first
Paolo Bonzini 0fb2b2
+                     * byte of id->iscsi_name so our maximum is 252.
Paolo Bonzini 0fb2b2
+                     */
Paolo Bonzini 0fb2b2
+                    goto illegal_req;
Paolo Bonzini 0fb2b2
+                }
Paolo Bonzini 0fb2b2
+                if (memchr(&param[i + 4], 0, len) == NULL) {
Paolo Bonzini 0fb2b2
+                    goto illegal_req;
Paolo Bonzini 0fb2b2
+                }
Paolo Bonzini 0fb2b2
+                memcpy(id->iscsi_name, &param[i + 2], len + 2);
Paolo Bonzini 0fb2b2
+                j += offsetof(struct transportid, iscsi_name[len + 2]);
Paolo Bonzini 0fb2b2
+                i += len + 4;
Paolo Bonzini 0fb2b2
+                break;
Paolo Bonzini 0fb2b2
+            case 6:
Paolo Bonzini 0fb2b2
+                /* SAS transport.  */
Paolo Bonzini 0fb2b2
+                if (i + 24 > transportid_len) {
Paolo Bonzini 0fb2b2
+                    goto illegal_req;
Paolo Bonzini 0fb2b2
+                }
Paolo Bonzini 0fb2b2
+                memcpy(id->sas_address, &param[i + 4], 8);
Paolo Bonzini 0fb2b2
+                j += offsetof(struct transportid, sas_address[8]);
Paolo Bonzini 0fb2b2
+                i += 24;
Paolo Bonzini 0fb2b2
+                break;
Paolo Bonzini 0fb2b2
+            default:
Paolo Bonzini 0fb2b2
+            illegal_req:
Paolo Bonzini 0fb2b2
+                scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
Paolo Bonzini 0fb2b2
+                return CHECK_CONDITION;
Paolo Bonzini 0fb2b2
+            }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+            paramp.trnptid_list[paramp.num_transportid++] = id;
Paolo Bonzini 0fb2b2
+        }
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type,
Paolo Bonzini 0fb2b2
+                                     &paramp, noisy, verbose);
Paolo Bonzini 0fb2b2
+    return mpath_reconstruct_sense(fd, r, sense);
Paolo Bonzini 0fb2b2
+}
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
 static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
                     uint8_t *data, int *resp_sz)
Paolo Bonzini 0fb2b2
 {
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+    if (is_mpath(fd)) {
Paolo Bonzini 0fb2b2
+        /* multipath_pr_in fills the whole input buffer.  */
Paolo Bonzini 0fb2b2
+        return multipath_pr_in(fd, cdb, sense, data, *resp_sz);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
     return do_sgio(fd, cdb, sense, data, resp_sz,
Paolo Bonzini 0fb2b2
                    SG_DXFER_FROM_DEV);
Paolo Bonzini 0fb2b2
 }
59eb7a
@@ -214,7 +539,14 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
 static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
Paolo Bonzini 0fb2b2
                      const uint8_t *param, int sz)
Paolo Bonzini 0fb2b2
 {
Paolo Bonzini 0fb2b2
-    int resp_sz = sz;
Paolo Bonzini 0fb2b2
+    int resp_sz;
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+    if (is_mpath(fd)) {
Paolo Bonzini 0fb2b2
+        return multipath_pr_out(fd, cdb, sense, param, sz);
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
+    resp_sz = sz;
Paolo Bonzini 0fb2b2
     return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz,
Paolo Bonzini 0fb2b2
                    SG_DXFER_TO_DEV);
Paolo Bonzini 0fb2b2
 }
59eb7a
@@ -525,6 +857,14 @@ static int drop_privileges(void)
Paolo Bonzini 0fb2b2
         return -1;
Paolo Bonzini 0fb2b2
     }
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+    /* For /dev/mapper/control ioctls */
Paolo Bonzini 0fb2b2
+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
Paolo Bonzini 0fb2b2
+                     CAP_SYS_ADMIN) < 0) {
Paolo Bonzini 0fb2b2
+        return -1;
Paolo Bonzini 0fb2b2
+    }
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
     /* Change user/group id, retaining the capabilities.  Because file descriptors
Paolo Bonzini 0fb2b2
      * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
Paolo Bonzini 0fb2b2
      * fact the helper can run as "nobody").
59eb7a
@@ -541,7 +881,7 @@ static int drop_privileges(void)
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
 int main(int argc, char **argv)
Paolo Bonzini 0fb2b2
 {
Paolo Bonzini 0fb2b2
-    const char *sopt = "hVk:fdT:u:g:q";
Paolo Bonzini 0fb2b2
+    const char *sopt = "hVk:fdT:u:g:vq";
Paolo Bonzini 0fb2b2
     struct option lopt[] = {
Paolo Bonzini 0fb2b2
         { "help", no_argument, NULL, 'h' },
Paolo Bonzini 0fb2b2
         { "version", no_argument, NULL, 'V' },
59eb7a
@@ -551,10 +891,12 @@ int main(int argc, char **argv)
Paolo Bonzini 0fb2b2
         { "trace", required_argument, NULL, 'T' },
Paolo Bonzini 0fb2b2
         { "user", required_argument, NULL, 'u' },
Paolo Bonzini 0fb2b2
         { "group", required_argument, NULL, 'g' },
Paolo Bonzini 0fb2b2
+        { "verbose", no_argument, NULL, 'v' },
Paolo Bonzini 0fb2b2
         { "quiet", no_argument, NULL, 'q' },
Paolo Bonzini 0fb2b2
         { NULL, 0, NULL, 0 }
Paolo Bonzini 0fb2b2
     };
Paolo Bonzini 0fb2b2
     int opt_ind = 0;
Paolo Bonzini 0fb2b2
+    int loglevel = 1;
Paolo Bonzini 0fb2b2
     int quiet = 0;
Paolo Bonzini 0fb2b2
     char ch;
Paolo Bonzini 0fb2b2
     Error *local_err = NULL;
59eb7a
@@ -631,6 +973,9 @@ int main(int argc, char **argv)
Paolo Bonzini 0fb2b2
         case 'q':
Paolo Bonzini 0fb2b2
             quiet = 1;
Paolo Bonzini 0fb2b2
             break;
Paolo Bonzini 0fb2b2
+        case 'v':
Paolo Bonzini 0fb2b2
+            ++loglevel;
Paolo Bonzini 0fb2b2
+            break;
Paolo Bonzini 0fb2b2
         case 'T':
Paolo Bonzini 0fb2b2
             g_free(trace_file);
Paolo Bonzini 0fb2b2
             trace_file = trace_opt_parse(optarg);
59eb7a
@@ -650,7 +995,8 @@ int main(int argc, char **argv)
Paolo Bonzini 0fb2b2
     }
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
     /* set verbosity */
Paolo Bonzini 0fb2b2
-    verbose = !quiet;
Paolo Bonzini 0fb2b2
+    noisy = !quiet && (loglevel >= 3);
Paolo Bonzini 0fb2b2
+    verbose = quiet ? 0 : MIN(loglevel, 3);
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
     if (!trace_init_backends()) {
Paolo Bonzini 0fb2b2
         exit(EXIT_FAILURE);
59eb7a
@@ -658,6 +1004,11 @@ int main(int argc, char **argv)
Paolo Bonzini 0fb2b2
     trace_init_file(trace_file);
Paolo Bonzini 0fb2b2
     qemu_set_log(LOG_TRACE);
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+#ifdef CONFIG_MPATH
Paolo Bonzini 0fb2b2
+    dm_init();
Paolo Bonzini 0fb2b2
+    multipath_pr_init();
Paolo Bonzini 0fb2b2
+#endif
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
     socket_activation = check_socket_activation();
Paolo Bonzini 0fb2b2
     if (socket_activation == 0) {
Paolo Bonzini 0fb2b2
         SocketAddress saddr;
Paolo Bonzini 0fb2b2
diff --git a/scsi/utils.c b/scsi/utils.c
Paolo Bonzini 0fb2b2
index fab60bdf20..5684951b12 100644
Paolo Bonzini 0fb2b2
--- a/scsi/utils.c
Paolo Bonzini 0fb2b2
+++ b/scsi/utils.c
Paolo Bonzini 0fb2b2
@@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
Paolo Bonzini 0fb2b2
     .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
Paolo Bonzini 0fb2b2
 };
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+/* Command aborted, LUN Communication Failure */
Paolo Bonzini 0fb2b2
+const struct SCSISense sense_code_LUN_COMM_FAILURE = {
Paolo Bonzini 0fb2b2
+    .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
Paolo Bonzini 0fb2b2
+};
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
 /* Unit attention, Capacity data has changed */
Paolo Bonzini 0fb2b2
 const struct SCSISense sense_code_CAPACITY_CHANGED = {
Paolo Bonzini 0fb2b2
     .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
Paolo Bonzini 0fb2b2
@@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET = {
Paolo Bonzini 0fb2b2
     .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
Paolo Bonzini 0fb2b2
 };
Paolo Bonzini 0fb2b2
 
Paolo Bonzini 0fb2b2
+/* Unit attention, SCSI bus reset */
Paolo Bonzini 0fb2b2
+const struct SCSISense sense_code_SCSI_BUS_RESET = {
Paolo Bonzini 0fb2b2
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02
Paolo Bonzini 0fb2b2
+};
Paolo Bonzini 0fb2b2
+
Paolo Bonzini 0fb2b2
 /* Unit attention, No medium */
Paolo Bonzini 0fb2b2
 const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
Paolo Bonzini 0fb2b2
     .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00