From 700f126a07f7cf5d6a40365917f6ee6cb48849c2 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Nov 20 2017 11:41:22 +0000 Subject: Update to qemu-2.11.0-rc1 --- diff --git a/.gitignore b/.gitignore index 99836e4..07cc0fb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ /qemu-2.10.0-rc4.tar.xz /qemu-2.10.0.tar.xz /qemu-2.10.1.tar.xz +/qemu-2.11.0-rc1.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 deleted file mode 100644 index a2d6dc1..0000000 --- a/0001-io-add-new-qio_channel_-readv-writev-read-write-_all.patch +++ /dev/null @@ -1,380 +0,0 @@ -From: "Daniel P. Berrange" -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 -Signed-off-by: Daniel P. Berrange ---- - 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 deleted file mode 100644 index 1fc3a1a..0000000 --- a/0002-io-Yield-rather-than-wait-when-already-in-coroutine.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Eric Blake -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 -Message-Id: <20170905191114.5959-2-eblake@redhat.com> -Acked-by: Daniel P. Berrange -[commit message updated] -Signed-off-by: Eric Blake ---- - 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 deleted file mode 100644 index a9d91be..0000000 --- a/0003-scsi-Refactor-scsi-sense-interpreting-code.patch +++ /dev/null @@ -1,190 +0,0 @@ -From: Fam Zheng -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 -Message-Id: <20170821141008.19383-2-famz@redhat.com> -Signed-off-by: Paolo Bonzini ---- - 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 - 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 - #include -@@ -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 -+ * -+ * 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 -+ * -+ * 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 deleted file mode 100644 index 4156754..0000000 --- a/0004-scsi-Improve-scsi_sense_to_errno.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Fam Zheng -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 -Message-Id: <20170821141008.19383-3-famz@redhat.com> -Signed-off-by: Paolo Bonzini ---- - 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 deleted file mode 100644 index 006c73c..0000000 --- a/0005-scsi-Introduce-scsi_sense_buf_to_errno.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Fam Zheng -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 -Message-Id: <20170821141008.19383-4-famz@redhat.com> -Signed-off-by: Paolo Bonzini ---- - 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 deleted file mode 100644 index eed33b7..0000000 --- a/0006-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch +++ /dev/null @@ -1,88 +0,0 @@ -From: Paolo Bonzini -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é -Signed-off-by: Paolo Bonzini ---- - 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 deleted file mode 100644 index 92650e7..0000000 --- a/0007-scsi-move-non-emulation-specific-code-to-scsi.patch +++ /dev/null @@ -1,1430 +0,0 @@ -From: Paolo Bonzini -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é -Signed-off-by: Paolo Bonzini ---- - 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 -+L: qemu-block@nongnu.org -+S: Supported -+F: include/scsi/* -+F: scsi/* -+ - Block Jobs - M: Jeff Cody - 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 - #include -+#undef SCSI_XFER_NONE -+QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE); - - #ifdef __linux__ - #include -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 - #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 -- * -- * 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 -+#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 -+ * Paolo Bonzini -+ * -+ * 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 -- * -- * 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 deleted file mode 100644 index e7ce4e3..0000000 --- a/0008-scsi-introduce-scsi_build_sense.patch +++ /dev/null @@ -1,73 +0,0 @@ -From: Paolo Bonzini -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é -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini ---- - 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 deleted file mode 100644 index 350084a..0000000 --- a/0009-scsi-introduce-sg_io_sense_from_errno.patch +++ /dev/null @@ -1,133 +0,0 @@ -From: Paolo Bonzini -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 -Signed-off-by: Paolo Bonzini ---- - 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 deleted file mode 100644 index 8bdc71c..0000000 --- a/0010-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch +++ /dev/null @@ -1,884 +0,0 @@ -From: Paolo Bonzini -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é -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini ---- - 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 - #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 --#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 . --*/ -- --/* -- * 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 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 . -+*/ -+ -+/* -+ * 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 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 deleted file mode 100644 index e747615..0000000 --- a/0011-scsi-file-posix-add-support-for-persistent-reservati.patch +++ /dev/null @@ -1,436 +0,0 @@ -From: Paolo Bonzini -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 ---- - 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 - #include -@@ -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 { -+ /* */ -+ Object parent; -+} PRManager; -+ -+/** -+ * PRManagerClass: -+ * @parent_class: the base class -+ * @run: callback invoked in thread pool context -+ */ -+typedef struct PRManagerClass { -+ /* */ -+ ObjectClass parent_class; -+ -+ /* */ -+ 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 -+ * -+ * This code is licensed under the LGPL. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#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 deleted file mode 100644 index 9d97fc7..0000000 --- a/0012-scsi-build-qemu-pr-helper.patch +++ /dev/null @@ -1,1009 +0,0 @@ -From: Paolo Bonzini -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 ---- - 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 -+ * -+ * 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 -+ -+#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. -+ * -+ * Author: Paolo Bonzini -+ * -+ * 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 . -+ */ -+ -+#include "qemu/osdep.h" -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_LIBCAP -+#include -+#endif -+#include -+#include -+ -+#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=]][,events=][,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 deleted file mode 100644 index 46ab354..0000000 --- a/0013-scsi-add-multipath-support-to-qemu-pr-helper.patch +++ /dev/null @@ -1,675 +0,0 @@ -From: Paolo Bonzini -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 ---- - 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 < -+#include -+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 - #include - -+#ifdef CONFIG_MPATH -+#include -+#include -+#include -+#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(¶mp, 0, sizeof(paramp)); -+ memcpy(¶mp.key, ¶m[0], 8); -+ memcpy(¶mp.sa_key, ¶m[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(¶m[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, ¶m[i + 8], 8); -+ j += offsetof(struct transportid, n_port_name[8]); -+ i += 24; -+ break; -+ case 3: -+ case 0x43: -+ /* iSCSI transport. */ -+ len = lduw_be_p(¶m[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(¶m[i + 4], 0, len) == NULL) { -+ goto illegal_req; -+ } -+ memcpy(id->iscsi_name, ¶m[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, ¶m[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, -+ ¶mp, 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 deleted file mode 100644 index af6ecc9..0000000 --- a/0014-scsi-add-persistent-reservation-manager-using-qemu-p.patch +++ /dev/null @@ -1,330 +0,0 @@ -From: Paolo Bonzini -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 ---- - 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 -+ * -+ * 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 -+ -+#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 { -+ /* */ -+ 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 deleted file mode 100644 index 8a8b374..0000000 --- a/0101-crypto-fix-test-cert-generation-to-not-use-SHA1-algo.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: "Daniel P. Berrange" -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 -Signed-off-by: Daniel P. Berrange ---- - 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 deleted file mode 100644 index 261cb76..0000000 --- a/0102-io-fix-check-for-handshake-completion-in-TLS-test.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: "Daniel P. Berrange" -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 -Signed-off-by: Daniel P. Berrange ---- - 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 deleted file mode 100644 index 744ca56..0000000 --- a/0103-io-fix-temp-directory-used-by-test-io-channel-tls-te.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: "Daniel P. Berrange" -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 -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Daniel P. Berrange ---- - 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 deleted file mode 100644 index 8e8b6fc..0000000 --- a/0104-spapr-fallback-to-raw-mode-if-best-compat-mode-canno.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Greg Kurz -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 -Signed-off-by: David Gibson -(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 deleted file mode 100644 index a187fe8..0000000 --- a/0105-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Prasad J Pandit -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 -Signed-off-by: Prasad J Pandit -Signed-off-by: Greg Kurz -(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 deleted file mode 100644 index 252e76a..0000000 --- a/0106-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch +++ /dev/null @@ -1,51 +0,0 @@ -From: "Daniel P. Berrange" -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 -Signed-off-by: Daniel P. Berrange -(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/qemu.spec b/qemu.spec index d625ed5..ba3f367 100644 --- a/qemu.spec +++ b/qemu.spec @@ -97,7 +97,7 @@ Requires: %{name}-block-ssh = %{epoch}:%{version}-%{release} %undefine _hardened_build # Release candidate version tracking -# global rcver rc4 +%global rcver rc1 %if 0%{?rcver:1} %global rcrel .%{rcver} %global rcstr -%{rcver} @@ -106,8 +106,8 @@ Requires: %{name}-block-ssh = %{epoch}:%{version}-%{release} Summary: QEMU is a FAST! processor emulator Name: qemu -Version: 2.10.1 -Release: 1%{?rcrel}%{?dist} +Version: 2.11.0 +Release: 0.1%{?rcrel}%{?dist} Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD URL: http://www.qemu.org/ @@ -141,35 +141,6 @@ Source21: 50-kvm-s390x.conf # /etc/security/limits.d/95-kvm-ppc64-memlock.conf Source22: 95-kvm-ppc64-memlock.conf -# 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 # For /usr/bin/pod2man @@ -293,6 +264,8 @@ BuildRequires: libcacard-devel >= 2.5.0 BuildRequires: virglrenderer-devel # qemu 2.6: Needed for gtk GL support BuildRequires: mesa-libgbm-devel +# qemu 2.11: preferred disassembler for TCG +BuildRequires: capstone-devel BuildRequires: glibc-static pcre-static glib2-static zlib-static @@ -1140,7 +1113,8 @@ run_configure \ --disable-cap-ng \ --disable-brlapi \ --disable-mpath \ - --disable-libnfs + --disable-libnfs \ + --disable-capstone make V=1 %{?_smp_mflags} $buildldflags @@ -1235,6 +1209,9 @@ ln -sf qemu.1.gz %{buildroot}%{_mandir}/man1/qemu-kvm.1.gz install -D -p -m 0644 qemu.sasl %{buildroot}%{_sysconfdir}/sasl2/qemu.conf +# XXX With qemu 2.11 we can probably drop this symlinking with use of +# configure --firmwarepath, see qemu git 3d5eecab4 + # Provided by package openbios rm -rf %{buildroot}%{_datadir}/%{name}/openbios-ppc rm -rf %{buildroot}%{_datadir}/%{name}/openbios-sparc32 @@ -1490,9 +1467,11 @@ getent passwd qemu >/dev/null || \ %{_datadir}/%{name}/efi-vmxnet3.rom %{_mandir}/man1/qemu.1* %{_mandir}/man1/virtfs-proxy-helper.1* +%{_mandir}/man7/qemu-block-drivers.7* %{_mandir}/man7/qemu-ga-ref.7* %{_mandir}/man7/qemu-qmp-ref.7* %{_bindir}/virtfs-proxy-helper +%{_bindir}/qemu-keymap %{_bindir}/qemu-pr-helper %{_unitdir}/qemu-pr-helper.service %{_unitdir}/qemu-pr-helper.socket diff --git a/sources b/sources index fa076e8..e7cec53 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (qemu-2.10.1.tar.xz) = 62e9717ede71a49f3ffd9b86c321470f64c90e575be1a9da01078cfc9466b0aeb08adf5d05bab7ee1e89dfce75def7b276af01f77b7151d406999e7af21b6711 +SHA512 (qemu-2.11.0-rc1.tar.xz) = 1cfe3c4fe60aa7d4bb54d8a510035aeae3bd6dcd6077b3af5ce4569c863a2a82d5bc27b4291aa9429c40f66dd16757a48720dc5c85d152c101c96c5efda8bb37