From nobody Sun Apr 13 04:30:37 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.zoho.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 1488314886477335.4789726566281; Tue, 28 Feb 2017 12:48:06 -0800 (PST) Received: from localhost ([::1]:36803 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciogn-0006Zu-51 for importer@patchew.org; Tue, 28 Feb 2017 15:48:05 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45115) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cioWl-00069h-0k for qemu-devel@nongnu.org; Tue, 28 Feb 2017 15:37:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cioWe-0007rF-L4 for qemu-devel@nongnu.org; Tue, 28 Feb 2017 15:37:38 -0500 Received: from mx1.redhat.com ([209.132.183.28]:54034) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cioWY-0007p4-WA; Tue, 28 Feb 2017 15:37:31 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2AF0364A5A; Tue, 28 Feb 2017 20:37:31 +0000 (UTC) Received: from noname.redhat.com (ovpn-116-177.ams2.redhat.com [10.36.116.177]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v1SKapFL021888; Tue, 28 Feb 2017 15:37:29 -0500 From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 28 Feb 2017 21:36:19 +0100 Message-Id: <1488314205-16264-21-git-send-email-kwolf@redhat.com> In-Reply-To: <1488314205-16264-1-git-send-email-kwolf@redhat.com> References: <1488314205-16264-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 28 Feb 2017 20:37:31 +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 20/46] hw/block: Request permissions 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: , Cc: kwolf@redhat.com, qemu-devel@nongnu.org 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" This makes all device emulations with a qdev drive property request permissions on their BlockBackend. The only thing we block at this point is resizing images for some devices that can't support it. Signed-off-by: Kevin Wolf Acked-by: Fam Zheng Reviewed-by: Max Reitz --- hw/block/block.c | 22 +++++++++++++++++++++- hw/block/fdc.c | 25 +++++++++++++++++++++++-- hw/block/m25p80.c | 8 ++++++++ hw/block/nand.c | 7 +++++++ hw/block/nvme.c | 8 +++++++- hw/block/onenand.c | 7 +++++++ hw/block/pflash_cfi01.c | 18 ++++++++++++------ hw/block/pflash_cfi02.c | 19 +++++++++++++------ hw/block/virtio-blk.c | 8 +++++++- hw/core/qdev-properties-system.c | 1 - hw/ide/qdev.c | 8 ++++++-- hw/nvram/spapr_nvram.c | 8 ++++++++ hw/scsi/scsi-disk.c | 9 +++++++-- hw/sd/sd.c | 6 ++++++ hw/usb/dev-storage.c | 6 +++++- include/hw/block/block.h | 3 ++- tests/qemu-iotests/051.pc.out | 6 +++--- 17 files changed, 142 insertions(+), 27 deletions(-) diff --git a/hw/block/block.c b/hw/block/block.c index 8dc9d84..7059ba1 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -51,11 +51,31 @@ void blkconf_blocksizes(BlockConf *conf) } } =20 -void blkconf_apply_backend_options(BlockConf *conf) +void blkconf_apply_backend_options(BlockConf *conf, bool readonly, + bool resizable, Error **errp) { BlockBackend *blk =3D conf->blk; BlockdevOnError rerror, werror; + uint64_t perm, shared_perm; bool wce; + int ret; + + perm =3D BLK_PERM_CONSISTENT_READ; + if (!readonly) { + perm |=3D BLK_PERM_WRITE; + } + + /* TODO Remove BLK_PERM_WRITE unless explicitly configured so */ + shared_perm =3D BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | + BLK_PERM_GRAPH_MOD | BLK_PERM_WRITE; + if (resizable) { + shared_perm |=3D BLK_PERM_RESIZE; + } + + ret =3D blk_set_perm(blk, perm, shared_perm, errp); + if (ret < 0) { + return; + } =20 switch (conf->wce) { case ON_OFF_AUTO_ON: wce =3D true; break; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 5f6c496..a328693 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -186,6 +186,7 @@ typedef enum FDiskFlags { struct FDrive { FDCtrl *fdctrl; BlockBackend *blk; + BlockConf *conf; /* Drive status */ FloppyDriveType drive; /* CMOS drive type */ uint8_t perpendicular; /* 2.88 MB access mode */ @@ -472,6 +473,19 @@ static void fd_revalidate(FDrive *drv) static void fd_change_cb(void *opaque, bool load, Error **errp) { FDrive *drive =3D opaque; + Error *local_err =3D NULL; + + if (!load) { + blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); + } else { + blkconf_apply_backend_options(drive->conf, + blk_is_read_only(drive->blk), false, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } =20 drive->media_changed =3D 1; drive->media_validated =3D false; @@ -508,6 +522,7 @@ static int floppy_drive_init(DeviceState *qdev) FloppyDrive *dev =3D FLOPPY_DRIVE(qdev); FloppyBus *bus =3D FLOPPY_BUS(qdev->parent_bus); FDrive *drive; + Error *local_err =3D NULL; int ret; =20 if (dev->unit =3D=3D -1) { @@ -533,7 +548,6 @@ static int floppy_drive_init(DeviceState *qdev) =20 if (!dev->conf.blk) { /* Anonymous BlockBackend for an empty drive */ - /* FIXME Use real permissions */ dev->conf.blk =3D blk_new(0, BLK_PERM_ALL); ret =3D blk_attach_dev(dev->conf.blk, qdev); assert(ret =3D=3D 0); @@ -552,7 +566,13 @@ static int floppy_drive_init(DeviceState *qdev) * blkconf_apply_backend_options(). */ dev->conf.rerror =3D BLOCKDEV_ON_ERROR_AUTO; dev->conf.werror =3D BLOCKDEV_ON_ERROR_AUTO; - blkconf_apply_backend_options(&dev->conf); + + blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.b= lk), + false, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } =20 /* 'enospc' is the default for -drive, 'report' is what blk_new() give= s us * for empty drives. */ @@ -566,6 +586,7 @@ static int floppy_drive_init(DeviceState *qdev) return -1; } =20 + drive->conf =3D &dev->conf; drive->blk =3D dev->conf.blk; drive->fdctrl =3D bus->fdc; =20 diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 2d6eb46..190573c 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -1215,6 +1215,7 @@ static void m25p80_realize(SSISlave *ss, Error **errp) { Flash *s =3D M25P80(ss); M25P80Class *mc =3D M25P80_GET_CLASS(s); + int ret; =20 s->pi =3D mc->pi; =20 @@ -1222,6 +1223,13 @@ static void m25p80_realize(SSISlave *ss, Error **err= p) s->dirty_page =3D -1; =20 if (s->blk) { + uint64_t perm =3D BLK_PERM_CONSISTENT_READ | + (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); + ret =3D blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } + DB_PRINT_L(0, "Binding to IF_MTD drive\n"); s->storage =3D blk_blockalign(s->blk, s->size); =20 diff --git a/hw/block/nand.c b/hw/block/nand.c index c69e675..0d33ac2 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -373,6 +373,8 @@ static void nand_realize(DeviceState *dev, Error **errp) { int pagesize; NANDFlashState *s =3D NAND(dev); + int ret; + =20 s->buswidth =3D nand_flash_ids[s->chip_id].width >> 3; s->size =3D nand_flash_ids[s->chip_id].size << 20; @@ -407,6 +409,11 @@ static void nand_realize(DeviceState *dev, Error **err= p) error_setg(errp, "Can't use a read-only drive"); return; } + ret =3D blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_W= RITE, + BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } if (blk_getlength(s->blk) >=3D (s->pages << s->page_shift) + (s->pages << s->oob_shift)) { pagesize =3D 0; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index ae91a18..ae303d4 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -835,6 +835,7 @@ static int nvme_init(PCIDevice *pci_dev) int i; int64_t bs_size; uint8_t *pci_conf; + Error *local_err =3D NULL; =20 if (!n->conf.blk) { return -1; @@ -850,7 +851,12 @@ static int nvme_init(PCIDevice *pci_dev) return -1; } blkconf_blocksizes(&n->conf); - blkconf_apply_backend_options(&n->conf); + blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), + false, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } =20 pci_conf =3D pci_dev->config; pci_conf[PCI_INTERRUPT_PIN] =3D 1; diff --git a/hw/block/onenand.c b/hw/block/onenand.c index 8d84227..ddf5492 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -778,6 +778,7 @@ static int onenand_initfn(SysBusDevice *sbd) OneNANDState *s =3D ONE_NAND(dev); uint32_t size =3D 1 << (24 + ((s->id.dev >> 4) & 7)); void *ram; + Error *local_err =3D NULL; =20 s->base =3D (hwaddr)-1; s->rdy =3D NULL; @@ -796,6 +797,12 @@ static int onenand_initfn(SysBusDevice *sbd) error_report("Can't use a read-only drive"); return -1; } + blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } s->blk_cur =3D s->blk; } s->otp =3D memset(g_malloc((64 + 2) << PAGE_SHIFT), diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 71b98a3..594d4cf 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -758,6 +758,18 @@ static void pflash_cfi01_realize(DeviceState *dev, Err= or **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); =20 if (pfl->blk) { + uint64_t perm; + pfl->ro =3D blk_is_read_only(pfl->blk); + perm =3D BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE); + ret =3D blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } + } else { + pfl->ro =3D 0; + } + + if (pfl->blk) { /* read the initial flash content */ ret =3D blk_pread(pfl->blk, 0, pfl->storage, total_len); =20 @@ -768,12 +780,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Err= or **errp) } } =20 - if (pfl->blk) { - pfl->ro =3D blk_is_read_only(pfl->blk); - } else { - pfl->ro =3D 0; - } - /* Default to devices being used at their maximum device width. This w= as * assumed before the device_width support was added. */ diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index ef71322..e6c5c6c 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -632,6 +632,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Err= or **errp) vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl)); pfl->storage =3D memory_region_get_ram_ptr(&pfl->orig_mem); pfl->chip_len =3D chip_len; + + if (pfl->blk) { + uint64_t perm; + pfl->ro =3D blk_is_read_only(pfl->blk); + perm =3D BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE); + ret =3D blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } + } else { + pfl->ro =3D 0; + } + if (pfl->blk) { /* read the initial flash content */ ret =3D blk_pread(pfl->blk, 0, pfl->storage, chip_len); @@ -646,12 +659,6 @@ static void pflash_cfi02_realize(DeviceState *dev, Err= or **errp) pfl->rom_mode =3D 1; sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); =20 - if (pfl->blk) { - pfl->ro =3D blk_is_read_only(pfl->blk); - } else { - pfl->ro =3D 0; - } - pfl->timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->wcycle =3D 0; pfl->cmd =3D 0; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 843bd2f..98c16a7 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -928,7 +928,13 @@ static void virtio_blk_device_realize(DeviceState *dev= , Error **errp) } =20 blkconf_serial(&conf->conf, &conf->serial); - blkconf_apply_backend_options(&conf->conf); + blkconf_apply_backend_options(&conf->conf, + blk_is_read_only(conf->conf.blk), true, + &err); + if (err) { + error_propagate(errp, err); + return; + } s->original_wce =3D blk_enable_write_cache(conf->conf.blk); blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err); if (err) { diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-sys= tem.c index 66ba367..c34be1c 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -79,7 +79,6 @@ static void parse_drive(DeviceState *dev, const char *str= , void **ptr, if (!blk) { BlockDriverState *bs =3D bdrv_lookup_bs(NULL, str, NULL); if (bs) { - /* FIXME Use real permissions */ blk =3D blk_new(0, BLK_PERM_ALL); blk_created =3D true; =20 diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index bb3c377..4383cd1 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -170,7 +170,6 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind = kind) return -1; } else { /* Anonymous BlockBackend for an empty drive */ - /* FIXME Use real permissions */ dev->conf.blk =3D blk_new(0, BLK_PERM_ALL); } } @@ -197,7 +196,12 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind= kind) return -1; } } - blkconf_apply_backend_options(&dev->conf); + blkconf_apply_backend_options(&dev->conf, kind =3D=3D IDE_CD, kind != =3D IDE_CD, + &err); + if (err) { + error_report_err(err); + return -1; + } =20 if (ide_init_drive(s, dev->conf.blk, kind, dev->version, dev->serial, dev->model, dev->wwn, diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 65ba188..aa5d2c1 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -141,9 +141,17 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMac= hineState *spapr, static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp) { sPAPRNVRAM *nvram =3D VIO_SPAPR_NVRAM(dev); + int ret; =20 if (nvram->blk) { nvram->size =3D blk_getlength(nvram->blk); + + ret =3D blk_set_perm(nvram->blk, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } } else { nvram->size =3D DEFAULT_NVRAM_SIZE; } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index c1ccfad..a53f058 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2328,7 +2328,13 @@ static void scsi_realize(SCSIDevice *dev, Error **er= rp) return; } } - blkconf_apply_backend_options(&dev->conf); + blkconf_apply_backend_options(&dev->conf, + blk_is_read_only(s->qdev.conf.blk), + dev->type =3D=3D TYPE_DISK, &err); + if (err) { + error_propagate(errp, err); + return; + } =20 if (s->qdev.conf.discard_granularity =3D=3D -1) { s->qdev.conf.discard_granularity =3D @@ -2380,7 +2386,6 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **= errp) SCSIDiskState *s =3D DO_UPCAST(SCSIDiskState, qdev, dev); =20 if (!dev->conf.blk) { - /* FIXME Use real permissions */ dev->conf.blk =3D blk_new(0, BLK_PERM_ALL); } =20 diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 8e31491..ba47bff 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1887,6 +1887,7 @@ static void sd_instance_finalize(Object *obj) static void sd_realize(DeviceState *dev, Error **errp) { SDState *sd =3D SD_CARD(dev); + int ret; =20 if (sd->blk && blk_is_read_only(sd->blk)) { error_setg(errp, "Cannot use read-only drive as SD card"); @@ -1894,6 +1895,11 @@ static void sd_realize(DeviceState *dev, Error **err= p) } =20 if (sd->blk) { + ret =3D blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_= WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } blk_set_dev_ops(sd->blk, &sd_block_ops, sd); } } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index c607f76..a71b354 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -603,7 +603,11 @@ static void usb_msd_realize_storage(USBDevice *dev, Er= ror **errp) =20 blkconf_serial(&s->conf, &dev->serial); blkconf_blocksizes(&s->conf); - blkconf_apply_backend_options(&s->conf); + blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &= err); + if (err) { + error_propagate(errp, err); + return; + } =20 /* * Hack alert: this pretends to be a block device, but it's really diff --git a/include/hw/block/block.h b/include/hw/block/block.h index df9d207..5d462eb 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -73,7 +73,8 @@ void blkconf_geometry(BlockConf *conf, int *trans, unsigned cyls_max, unsigned heads_max, unsigned secs= _max, Error **errp); void blkconf_blocksizes(BlockConf *conf); -void blkconf_apply_backend_options(BlockConf *conf); +void blkconf_apply_backend_options(BlockConf *conf, bool readonly, + bool resizable, Error **errp); =20 /* Hard disk geometry */ =20 diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index e206ad6..c6f4eef 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -179,7 +179,7 @@ q=1B[K=1B[Dqu=1B[K=1B[D=1B[Dqui=1B[K=1B[D=1B[D=1B[Dquit= =1B[K =20 Testing: -drive file=3DTEST_DIR/t.qcow2,if=3Dide,readonly=3Don QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Can't use a read-only drive +(qemu) QEMU_PROG: Block node is read-only QEMU_PROG: Initialization of device ide-hd failed: Device initialization f= ailed. =20 Testing: -drive file=3DTEST_DIR/t.qcow2,if=3Dscsi,readonly=3Don @@ -201,12 +201,12 @@ QEMU X.Y.Z monitor - type 'help' for more information =20 Testing: -drive file=3DTEST_DIR/t.qcow2,if=3Dnone,id=3Ddisk,readonly=3Don = -device ide-drive,drive=3Ddisk QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-drive,drive=3Ddisk: Can't use a read-only dr= ive +(qemu) QEMU_PROG: -device ide-drive,drive=3Ddisk: Block node is read-only QEMU_PROG: -device ide-drive,drive=3Ddisk: Device initialization failed. =20 Testing: -drive file=3DTEST_DIR/t.qcow2,if=3Dnone,id=3Ddisk,readonly=3Don = -device ide-hd,drive=3Ddisk QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-hd,drive=3Ddisk: Can't use a read-only drive +(qemu) QEMU_PROG: -device ide-hd,drive=3Ddisk: Block node is read-only QEMU_PROG: -device ide-hd,drive=3Ddisk: Device initialization failed. =20 Testing: -drive file=3DTEST_DIR/t.qcow2,if=3Dnone,id=3Ddisk,readonly=3Don = -device lsi53c895a -device scsi-disk,drive=3Ddisk --=20 1.8.3.1