From f25a16656ae9f266415abd6108b2aa048fd74f4d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Feb 2012 14:12:06 +0100 Subject: [PATCH 050/109] scsi-disk: support READ DVD STRUCTURE RH-Author: Paolo Bonzini Message-id: <1329919979-20948-50-git-send-email-pbonzini@redhat.com> Patchwork-id: 37530 O-Subject: [RHEL 6.3 qemu-kvm PATCH v2 049/102] scsi-disk: support READ DVD STRUCTURE Bugzilla: 782029 RH-Acked-by: Laszlo Ersek RH-Acked-by: Orit Wasserman RH-Acked-by: Gerd Hoffmann Upstream used st*_be_p functions, which are not available to common code in RHEL6 qemu. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf (cherry picked from ceb792ef299a1bb0144c56fab45631d17c35e7f5) --- hw/scsi-disk.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 109 insertions(+), 1 deletions(-) Signed-off-by: Michal Novotny --- hw/scsi-disk.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 109 insertions(+), 1 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 771721d..20cdb41 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -614,10 +614,118 @@ static inline bool media_is_dvd(SCSIDiskState *s) return nb_sectors > CD_MAX_SECTORS; } +static inline bool media_is_cd(SCSIDiskState *s) +{ + uint64_t nb_sectors; + if (s->qdev.type != TYPE_ROM) { + return false; + } + if (!bdrv_is_inserted(s->bs)) { + return false; + } + bdrv_get_geometry(s->bs, &nb_sectors); + return nb_sectors <= CD_MAX_SECTORS; +} + static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r, uint8_t *outbuf) { - scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); + static const int rds_caps_size[5] = { + [0] = 2048 + 4, + [1] = 4 + 4, + [3] = 188 + 4, + [4] = 2048 + 4, + }; + + uint8_t media = r->req.cmd.buf[1]; + uint8_t layer = r->req.cmd.buf[6]; + uint8_t format = r->req.cmd.buf[7]; + int size = -1; + + if (s->qdev.type != TYPE_ROM) { + return -1; + } + if (media != 0) { + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); + return -1; + } + + if (format != 0xff) { + if (s->tray_open || !bdrv_is_inserted(s->bs)) { + scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); + return -1; + } + if (media_is_cd(s)) { + scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT)); + return -1; + } + if (format >= ARRAY_SIZE(rds_caps_size)) { + return -1; + } + size = rds_caps_size[format]; + memset(outbuf, 0, size); + } + + switch (format) { + case 0x00: { + /* Physical format information */ + uint64_t nb_sectors; + if (layer != 0) { + goto fail; + } + bdrv_get_geometry(s->bs, &nb_sectors); + + outbuf[4] = 1; /* DVD-ROM, part version 1 */ + outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + outbuf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + outbuf[7] = 0; /* default densities */ + + outbuf[12] = ((nb_sectors >> 2) - 1) >> 24; /* end sector */ + outbuf[13] = ((nb_sectors >> 2) - 1) >> 16; + outbuf[14] = ((nb_sectors >> 2) - 1) >> 8; + outbuf[15] = (nb_sectors >> 2) - 1; + outbuf[16] = outbuf[12]; /* l0 end sector */ + outbuf[17] = outbuf[13]; + outbuf[18] = outbuf[14]; + outbuf[19] = outbuf[15]; + break; + } + + case 0x01: /* DVD copyright information, all zeros */ + break; + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -1; + + case 0x04: /* DVD disc manufacturing information, all zeros */ + break; + + case 0xff: { /* List capabilities */ + int i; + size = 4; + for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) { + if (!rds_caps_size[i]) { + continue; + } + outbuf[size] = i; + outbuf[size + 1] = 0x40; /* Not writable, readable */ + outbuf[size + 2] = rds_caps_size[i] >> 8; + outbuf[size + 3] = rds_caps_size[i]; + size += 4; + } + break; + } + + default: + return -1; + } + + /* Size of buffer, not including 2 byte size field */ + outbuf[0] = (size - 2) >> 8; + outbuf[1] = size - 2; + return size; + +fail: return -1; } -- 1.7.7.6