From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KEFwb-0005zW-TL for qemu-devel@nongnu.org; Wed, 02 Jul 2008 23:57:17 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KEFwa-0005yU-VC for qemu-devel@nongnu.org; Wed, 02 Jul 2008 23:57:17 -0400 Received: from [199.232.76.173] (port=55950 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KEFwa-0005yL-MC for qemu-devel@nongnu.org; Wed, 02 Jul 2008 23:57:16 -0400 Received: from savannah.gnu.org ([199.232.41.3]:35809 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KEFwa-0003z5-7u for qemu-devel@nongnu.org; Wed, 02 Jul 2008 23:57:16 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1KEFwZ-0005rp-5U for qemu-devel@nongnu.org; Thu, 03 Jul 2008 03:57:15 +0000 Received: from ths by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1KEFwY-0005rl-Pa for qemu-devel@nongnu.org; Thu, 03 Jul 2008 03:57:15 +0000 MIME-Version: 1.0 Errors-To: ths Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Thiemo Seufer Message-Id: Date: Thu, 03 Jul 2008 03:57:14 +0000 Subject: [Qemu-devel] [4831] Fix ATAPI read drive structure command, by Alex Williamson. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 4831 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4831 Author: ths Date: 2008-07-03 03:57:14 +0000 (Thu, 03 Jul 2008) Log Message: ----------- Fix ATAPI read drive structure command, by Alex Williamson. Modified Paths: -------------- trunk/hw/ide.c Modified: trunk/hw/ide.c =================================================================== --- trunk/hw/ide.c 2008-07-02 21:25:53 UTC (rev 4830) +++ trunk/hw/ide.c 2008-07-03 03:57:14 UTC (rev 4831) @@ -351,6 +351,7 @@ #define ASC_ILLEGAL_OPCODE 0x20 #define ASC_LOGICAL_BLOCK_OOR 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 @@ -434,6 +435,22 @@ int media_changed; } IDEState; +/* XXX: DVDs that could fit on a CD will be reported as a CD */ +static inline int media_present(IDEState *s) +{ + return (s->nb_sectors > 0); +} + +static inline int media_is_dvd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS); +} + +static inline int media_is_cd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS); +} + #define BM_STATUS_DMAING 0x01 #define BM_STATUS_ERROR 0x02 #define BM_STATUS_INT 0x04 @@ -1364,6 +1381,93 @@ return 4; } +static int ide_dvd_read_structure(IDEState *s, int format, + const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + cpu_to_ube32(buf + 8, 0); /* start sector */ + cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */ + cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 4 + 2); + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4); + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4); + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4); + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4); + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 16 + 2); + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1651,42 +1755,48 @@ case GPCMD_READ_DVD_STRUCTURE: { int media = packet[1]; - int layer = packet[6]; - int format = packet[2]; - uint64_t total_sectors; + int format = packet[7]; + int ret; - if (media != 0 || layer != 0) - { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); + max_len = ube16_to_cpu(packet + 8); + + if (format < 0xff) { + if (media_is_cd(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INCOMPATIBLE_FORMAT); + break; + } else if (!media_present(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } } + memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? + IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); + switch (format) { - case 0: - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = ide_dvd_read_structure(s, format, packet, buf); + + if (ret < 0) + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); + else + ide_atapi_cmd_reply(s, ret, max_len); + break; } + /* TODO: BD support, fall through for now */ - memset(buf, 0, 2052); - - buf[4] = 1; // DVD-ROM, part version 1 - buf[5] = 0xf; // 120mm disc, maximum rate unspecified - buf[6] = 0; // one layer, embossed data - buf[7] = 0; - - cpu_to_ube32(buf + 8, 0); - cpu_to_ube32(buf + 12, total_sectors - 1); - cpu_to_ube32(buf + 16, total_sectors - 1); - - cpu_to_be16wu((uint16_t *)buf, 2048 + 4); - - ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4); - break; - + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); @@ -1741,16 +1851,11 @@ /* * the number of sectors from the media tells us which profile * to use as current. 0 means there is no media - * - * XXX: fails to detect correctly DVDs with less data burned - * than what a CD can hold */ - if (s -> nb_sectors) { - if (s -> nb_sectors > CD_MAX_SECTORS) - cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); - else - cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); - } + if (media_is_dvd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); + else if (media_is_cd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); buf[10] = 0x02 | 0x01; /* persistent and current */ len = 12; /* headers: 8 + 4 */