From nobody Tue Nov 4 05:28:56 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1506093772681783.8153744974015; Fri, 22 Sep 2017 08:22:52 -0700 (PDT) Received: from localhost ([::1]:59451 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dvPmv-0002bX-93 for importer@patchew.org; Fri, 22 Sep 2017 11:22:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48702) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dvPV4-0003Us-G2 for qemu-devel@nongnu.org; Fri, 22 Sep 2017 11:04:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dvPV1-0007Tm-O1 for qemu-devel@nongnu.org; Fri, 22 Sep 2017 11:04:18 -0400 Received: from mx1.redhat.com ([209.132.183.28]:42888) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dvPV1-0007Sz-Fr for qemu-devel@nongnu.org; Fri, 22 Sep 2017 11:04:15 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8BE372CE909 for ; Fri, 22 Sep 2017 15:04:14 +0000 (UTC) Received: from donizetti.redhat.com (ovpn-117-77.ams2.redhat.com [10.36.117.77]) by smtp.corp.redhat.com (Postfix) with ESMTP id 92D495D9CB for ; Fri, 22 Sep 2017 15:04:13 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8BE372CE909 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=pbonzini@redhat.com From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 22 Sep 2017 17:04:10 +0200 Message-Id: <20170922150410.20689-3-pbonzini@redhat.com> In-Reply-To: <20170922150410.20689-1-pbonzini@redhat.com> References: <20170922150410.20689-1-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 22 Sep 2017 15:04:14 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 27/32] scsi: add multipath support to qemu-pr-helper X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 | 46 +++++++ docs/pr-manager.rst | 27 ++++ include/scsi/utils.h | 4 + scsi/qemu-pr-helper.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++= +++- scsi/utils.c | 10 ++ 6 files changed, 433 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8406aeb8cb..4eb40376d2 100644 --- a/Makefile +++ b/Makefile @@ -373,6 +373,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-= helper.o fsdev/9p-marshal fsdev/virtfs-proxy-helper$(EXESUF): LIBS +=3D -lcap =20 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 +=3D -ludev -lmultipath -lmpathpersist +endif =20 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@= ") diff --git a/configure b/configure index becc21a0fe..f6edc2a33f 100755 --- a/configure +++ b/configure @@ -290,6 +290,7 @@ netmap=3D"no" sdl=3D"" sdlabi=3D"" virtfs=3D"" +mpath=3D"" vnc=3D"yes" sparse=3D"no" vde=3D"" @@ -936,6 +937,10 @@ for opt do ;; --enable-virtfs) virtfs=3D"yes" ;; + --disable-mpath) mpath=3D"no" + ;; + --enable-mpath) mpath=3D"yes" + ;; --disable-vnc) vnc=3D"no" ;; --enable-vnc) vnc=3D"yes" @@ -1479,6 +1484,7 @@ disabled with --disable-FEATURE, default is enabled i= f available: vnc-png PNG compression for VNC server cocoa Cocoa UI (Mac OS X only) virtfs VirtFS + mpath Multipath persistent reservation passthrough xen xen backend driver support xen-pci-passthrough brlapi BrlAPI (Braile) @@ -3300,6 +3306,30 @@ else fi =20 ########################################## +# libmpathpersist probe + +if test "$mpath" !=3D "no" ; then + cat > $TMPC < +#include +unsigned mpath_mx_alloc_len =3D 1024; +int logsink; +int main(void) { + struct udev *udev =3D udev_new(); + mpath_lib_init(udev); + return 0; +} +EOF + if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then + mpathpersist=3Dyes + else + mpathpersist=3Dno + fi +else + mpathpersist=3Dno +fi + +########################################## # libcap probe =20 if test "$cap" !=3D "no" ; then @@ -5044,12 +5074,24 @@ if test "$softmmu" =3D yes ; then fi virtfs=3Dno fi + if test "$mpath" !=3D no && test "$mpathpersist" =3D yes ; then + mpath=3Dyes + else + if test "$mpath" =3D yes; then + error_exit "Multipath requires libmpathpersist devel" + fi + mpath=3Dno + fi tools=3D"$tools scsi/qemu-pr-helper\$(EXESUF)" else if test "$virtfs" =3D yes; then error_exit "VirtFS is supported only on Linux" fi virtfs=3Dno + if test "$mpath" =3D yes; then + error_exit "Multipath is supported only on Linux" + fi + mpath=3Dno fi fi =20 @@ -5295,6 +5337,7 @@ echo "Audio drivers $audio_drv_list" echo "Block whitelist (rw) $block_drv_rw_whitelist" echo "Block whitelist (ro) $block_drv_ro_whitelist" echo "VirtFS support $virtfs" +echo "Multipath support $mpath" echo "VNC support $vnc" if test "$vnc" =3D "yes" ; then echo "VNC SASL support $vnc_sasl" @@ -5738,6 +5781,9 @@ fi if test "$virtfs" =3D "yes" ; then echo "CONFIG_VIRTFS=3Dy" >> $config_host_mak fi +if test "$mpath" =3D "yes" ; then + echo "CONFIG_MPATH=3Dy" >> $config_host_mak +fi if test "$vhost_scsi" =3D "yes" ; then echo "CONFIG_VHOST_SCSI=3Dy" >> $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: =20 -d, --daemon run in the background -q, --quiet decrease verbosity +-v, --verbose increase verbosity -f, --pidfile=3Dpath PID file when running as a daemon -k, --socket=3Dpath path to the socket -T, --trace=3Dtrace-opts tracing options @@ -82,3 +83,29 @@ its operation. To do this, add the following options: =20 -u, --user=3Duser user to drop privileges to -g, --group=3Dgroup group to drop privileges to + +--------------------------------------------- +Multipath devices and persistent reservations +--------------------------------------------- + +Proper support of persistent reservation for multipath devices requires +communication with the multipath daemon, so that the reservation is +registered and applied when a path is newly discovered or becomes online +again. :command:`qemu-pr-helper` can do this if the ``libmpathpersist`` +library was available on the system at build time. + +As of August 2017, a reservation key must be specified in ``multipath.conf= `` +for ``multipathd`` to check for persistent reservation for newly +discovered paths or reinstated paths. The attribute can be added +to the ``defaults`` section or the ``multipaths`` section; for example:: + + multipaths { + multipath { + wwid XXXXXXXXXXXXXXXX + alias yellow + reservation_key 0x123abc + } + } + +Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede +its usage on regular SCSI devices. diff --git a/include/scsi/utils.h b/include/scsi/utils.h index d301b31768..00a4bdb080 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR; extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; /* Command aborted, Logical Unit failure */ extern const struct SCSISense sense_code_LUN_FAILURE; +/* Command aborted, LUN Communication failure */ +extern const struct SCSISense sense_code_LUN_COMM_FAILURE; /* Command aborted, Overlapped Commands Attempted */ extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; /* LUN not ready, Capacity data has changed */ extern const struct SCSISense sense_code_CAPACITY_CHANGED; +/* Unit attention, SCSI bus reset */ +extern const struct SCSISense sense_code_SCSI_BUS_RESET; /* LUN not ready, Medium not present */ extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; /* Unit attention, Power on, reset or bus device reset occurred */ diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index e39efbd529..5f77c873e1 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -30,6 +30,12 @@ #include #include =20 +#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 =3D 1; +static int noisy; static int verbose; =20 #ifdef CONFIG_LIBCAP @@ -204,9 +211,316 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_= t *sense, return r; } =20 +/* 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] =3D DM_VERSION_MAJOR; + d.dm.version[1] =3D 0; + d.dm.version[2] =3D 0; + d.dm.data_size =3D 1024; + d.dm.data_start =3D 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 =3D fstat(fd, &st); + if (r < 0) { + perror("fstat"); + exit(1); + } + + dm->dev =3D st.st_rdev; + return dm_ioctl(ioc, dm); +} + +static void dm_init(void) +{ + control_fd =3D open(CONTROL_PATH, O_RDWR); + if (control_fd < 0) { + perror("Cannot open " CONTROL_PATH); + exit(1); + } + struct dm_ioctl dm =3D { 0 }; + if (!dm_ioctl(DM_VERSION, &dm)) { + perror("ioctl"); + exit(1); + } + if (dm.version[0] !=3D 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); +unsigned mpath_mx_alloc_len =3D PR_HELPER_DATA_SIZE; +int logsink; + +static void multipath_pr_init(void) +{ + static struct udev *udev; + + udev =3D udev_new(); + mpath_lib_init(udev); +} + +static int is_mpath(int fd) +{ + struct dm_ioctl dm =3D { .flags =3D DM_NOFLUSH_FLAG }; + struct dm_target_spec *tgt; + + tgt =3D dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm); + if (!tgt) { + if (errno =3D=3D 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] =3D { TEST_UNIT_READY }; + int sz =3D 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 =3D 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 =3D mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbos= e); + if (r =3D=3D MPATH_PR_SUCCESS) { + switch (rq_servact) { + case MPATH_PRIN_RKEY_SA: + case MPATH_PRIN_RRES_SA: { + struct prin_readdescr *out =3D &resp.prin_descriptor.prin_read= keys; + assert(sz >=3D 8); + written =3D 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 =3D &resp.prin_descriptor.prin_readc= ap; + assert(sz >=3D 6); + written =3D 6; + stw_be_p(&data[0], out->length); + data[2] =3D out->flags[0]; + data[3] =3D 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 <=3D 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 =3D cdb[1]; + int rq_scope =3D cdb[2] >> 4; + int rq_type =3D 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 =3D 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 =3D 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 =3D PR_OUT_FIXED_PARAM_SIZE + 4, j =3D 0; i < transportid_l= en; ) { + struct transportid *id =3D (struct transportid *) &transportid= s[j]; + int len; + + id->format_code =3D param[i] & 0xc0; + id->protocol_id =3D 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 +=3D offsetof(struct transportid, n_port_name[8]); + i +=3D 24; + break; + case 3: + case 0x43: + /* iSCSI transport. */ + len =3D lduw_be_p(¶m[i + 2]); + if (len > 252 || (len & 3) || i + len + 4 > transportid_le= n) { + /* For format code 00, the standard says the maximum i= s 223 + * plus the NUL terminator. For format code 01 there = is no + * maximum length, but libmpathpersist ignores the fir= st + * byte of id->iscsi_name so our maximum is 252. + */ + goto illegal_req; + } + if (memchr(¶m[i + 4], 0, len) =3D=3D NULL) { + goto illegal_req; + } + memcpy(id->iscsi_name, ¶m[i + 2], len + 2); + j +=3D offsetof(struct transportid, iscsi_name[len + 2]); + i +=3D len + 4; + break; + case 6: + /* SAS transport. */ + if (i + 24 > transportid_len) { + goto illegal_req; + } + memcpy(id->sas_address, ¶m[i + 4], 8); + j +=3D offsetof(struct transportid, sas_address[8]); + i +=3D 24; + break; + default: + illegal_req: + scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); + return CHECK_CONDITION; + } + + paramp.trnptid_list[paramp.num_transportid++] =3D id; + } + } + + r =3D 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 +528,14 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_= t *sense, static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, const uint8_t *param, int sz) { - int resp_sz =3D sz; + int resp_sz; +#ifdef CONFIG_MPATH + if (is_mpath(fd)) { + return multipath_pr_out(fd, cdb, sense, param, sz); + } +#endif + + resp_sz =3D sz; return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz, SG_DXFER_TO_DEV); } @@ -525,6 +846,14 @@ static int drop_privileges(void) return -1; } =20 +#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 des= criptors * are passed via SCM_RIGHTS, we don't need supplementary groups (and = in * fact the helper can run as "nobody"). @@ -541,7 +870,7 @@ static int drop_privileges(void) =20 int main(int argc, char **argv) { - const char *sopt =3D "hVk:fdT:u:g:q"; + const char *sopt =3D "hVk:fdT:u:g:vq"; struct option lopt[] =3D { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, @@ -551,10 +880,12 @@ int main(int argc, char **argv) { "trace", required_argument, NULL, 'T' }, { "user", required_argument, NULL, 'u' }, { "group", required_argument, NULL, 'g' }, + { "verbose", no_argument, NULL, 'v' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 } }; int opt_ind =3D 0; + int loglevel =3D 1; int quiet =3D 0; char ch; Error *local_err =3D NULL; @@ -631,6 +962,9 @@ int main(int argc, char **argv) case 'q': quiet =3D 1; break; + case 'v': + ++loglevel; + break; case 'T': g_free(trace_file); trace_file =3D trace_opt_parse(optarg); @@ -650,7 +984,8 @@ int main(int argc, char **argv) } =20 /* set verbosity */ - verbose =3D !quiet; + noisy =3D !quiet && (loglevel >=3D 3); + verbose =3D quiet ? 0 : MIN(loglevel, 3); =20 if (!trace_init_backends()) { exit(EXIT_FAILURE); @@ -658,6 +993,11 @@ int main(int argc, char **argv) trace_init_file(trace_file); qemu_set_log(LOG_TRACE); =20 +#ifdef CONFIG_MPATH + dm_init(); + multipath_pr_init(); +#endif + socket_activation =3D check_socket_activation(); if (socket_activation =3D=3D 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 = =3D { .key =3D ABORTED_COMMAND, .asc =3D 0x4e, .ascq =3D 0x00 }; =20 +/* Command aborted, LUN Communication Failure */ +const struct SCSISense sense_code_LUN_COMM_FAILURE =3D { + .key =3D ABORTED_COMMAND, .asc =3D 0x08, .ascq =3D 0x00 +}; + /* Unit attention, Capacity data has changed */ const struct SCSISense sense_code_CAPACITY_CHANGED =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x2a, .ascq =3D 0x09 @@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x29, .ascq =3D 0x00 }; =20 +/* Unit attention, SCSI bus reset */ +const struct SCSISense sense_code_SCSI_BUS_RESET =3D { + .key =3D UNIT_ATTENTION, .asc =3D 0x29, .ascq =3D 0x02 +}; + /* Unit attention, No medium */ const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x3a, .ascq =3D 0x00 --=20 2.13.5