Commit 8114e9e8fd2610b96a808cdf703127eb26eb5278

Authored by ths
1 parent 69dd8673

Fix ATAPI read drive structure command, by Alex Williamson.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4831 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 144 additions and 39 deletions
hw/ide.c
... ... @@ -351,6 +351,7 @@
351 351 #define ASC_ILLEGAL_OPCODE 0x20
352 352 #define ASC_LOGICAL_BLOCK_OOR 0x21
353 353 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24
  354 +#define ASC_INCOMPATIBLE_FORMAT 0x30
354 355 #define ASC_MEDIUM_NOT_PRESENT 0x3a
355 356 #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
356 357  
... ... @@ -434,6 +435,22 @@ typedef struct IDEState {
434 435 int media_changed;
435 436 } IDEState;
436 437  
  438 +/* XXX: DVDs that could fit on a CD will be reported as a CD */
  439 +static inline int media_present(IDEState *s)
  440 +{
  441 + return (s->nb_sectors > 0);
  442 +}
  443 +
  444 +static inline int media_is_dvd(IDEState *s)
  445 +{
  446 + return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
  447 +}
  448 +
  449 +static inline int media_is_cd(IDEState *s)
  450 +{
  451 + return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
  452 +}
  453 +
437 454 #define BM_STATUS_DMAING 0x01
438 455 #define BM_STATUS_ERROR 0x02
439 456 #define BM_STATUS_INT 0x04
... ... @@ -1364,6 +1381,93 @@ static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
1364 1381 return 4;
1365 1382 }
1366 1383  
  1384 +static int ide_dvd_read_structure(IDEState *s, int format,
  1385 + const uint8_t *packet, uint8_t *buf)
  1386 +{
  1387 + switch (format) {
  1388 + case 0x0: /* Physical format information */
  1389 + {
  1390 + int layer = packet[6];
  1391 + uint64_t total_sectors;
  1392 +
  1393 + if (layer != 0)
  1394 + return -ASC_INV_FIELD_IN_CMD_PACKET;
  1395 +
  1396 + bdrv_get_geometry(s->bs, &total_sectors);
  1397 + total_sectors >>= 2;
  1398 + if (total_sectors == 0)
  1399 + return -ASC_MEDIUM_NOT_PRESENT;
  1400 +
  1401 + buf[4] = 1; /* DVD-ROM, part version 1 */
  1402 + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
  1403 + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
  1404 + buf[7] = 0; /* default densities */
  1405 +
  1406 + /* FIXME: 0x30000 per spec? */
  1407 + cpu_to_ube32(buf + 8, 0); /* start sector */
  1408 + cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
  1409 + cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
  1410 +
  1411 + /* Size of buffer, not including 2 byte size field */
  1412 + cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
  1413 +
  1414 + /* 2k data + 4 byte header */
  1415 + return (2048 + 4);
  1416 + }
  1417 +
  1418 + case 0x01: /* DVD copyright information */
  1419 + buf[4] = 0; /* no copyright data */
  1420 + buf[5] = 0; /* no region restrictions */
  1421 +
  1422 + /* Size of buffer, not including 2 byte size field */
  1423 + cpu_to_be16wu((uint16_t *)buf, 4 + 2);
  1424 +
  1425 + /* 4 byte header + 4 byte data */
  1426 + return (4 + 4);
  1427 +
  1428 + case 0x03: /* BCA information - invalid field for no BCA info */
  1429 + return -ASC_INV_FIELD_IN_CMD_PACKET;
  1430 +
  1431 + case 0x04: /* DVD disc manufacturing information */
  1432 + /* Size of buffer, not including 2 byte size field */
  1433 + cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
  1434 +
  1435 + /* 2k data + 4 byte header */
  1436 + return (2048 + 4);
  1437 +
  1438 + case 0xff:
  1439 + /*
  1440 + * This lists all the command capabilities above. Add new ones
  1441 + * in order and update the length and buffer return values.
  1442 + */
  1443 +
  1444 + buf[4] = 0x00; /* Physical format */
  1445 + buf[5] = 0x40; /* Not writable, is readable */
  1446 + cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
  1447 +
  1448 + buf[8] = 0x01; /* Copyright info */
  1449 + buf[9] = 0x40; /* Not writable, is readable */
  1450 + cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
  1451 +
  1452 + buf[12] = 0x03; /* BCA info */
  1453 + buf[13] = 0x40; /* Not writable, is readable */
  1454 + cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
  1455 +
  1456 + buf[16] = 0x04; /* Manufacturing info */
  1457 + buf[17] = 0x40; /* Not writable, is readable */
  1458 + cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
  1459 +
  1460 + /* Size of buffer, not including 2 byte size field */
  1461 + cpu_to_be16wu((uint16_t *)buf, 16 + 2);
  1462 +
  1463 + /* data written + 4 byte header */
  1464 + return (16 + 4);
  1465 +
  1466 + default: /* TODO: formats beyond DVD-ROM requires */
  1467 + return -ASC_INV_FIELD_IN_CMD_PACKET;
  1468 + }
  1469 +}
  1470 +
1367 1471 static void ide_atapi_cmd(IDEState *s)
1368 1472 {
1369 1473 const uint8_t *packet;
... ... @@ -1651,42 +1755,48 @@ static void ide_atapi_cmd(IDEState *s)
1651 1755 case GPCMD_READ_DVD_STRUCTURE:
1652 1756 {
1653 1757 int media = packet[1];
1654   - int layer = packet[6];
1655   - int format = packet[2];
1656   - uint64_t total_sectors;
1657   -
1658   - if (media != 0 || layer != 0)
1659   - {
1660   - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
1661   - ASC_INV_FIELD_IN_CMD_PACKET);
1662   - }
1663   -
1664   - switch (format) {
1665   - case 0:
1666   - bdrv_get_geometry(s->bs, &total_sectors);
1667   - total_sectors >>= 2;
1668   - if (total_sectors == 0) {
1669   - ide_atapi_cmd_error(s, SENSE_NOT_READY,
1670   - ASC_MEDIUM_NOT_PRESENT);
1671   - break;
1672   - }
  1758 + int format = packet[7];
  1759 + int ret;
1673 1760  
1674   - memset(buf, 0, 2052);
  1761 + max_len = ube16_to_cpu(packet + 8);
1675 1762  
1676   - buf[4] = 1; // DVD-ROM, part version 1
1677   - buf[5] = 0xf; // 120mm disc, maximum rate unspecified
1678   - buf[6] = 0; // one layer, embossed data
1679   - buf[7] = 0;
  1763 + if (format < 0xff) {
  1764 + if (media_is_cd(s)) {
  1765 + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
  1766 + ASC_INCOMPATIBLE_FORMAT);
  1767 + break;
  1768 + } else if (!media_present(s)) {
  1769 + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
  1770 + ASC_INV_FIELD_IN_CMD_PACKET);
  1771 + break;
  1772 + }
  1773 + }
1680 1774  
1681   - cpu_to_ube32(buf + 8, 0);
1682   - cpu_to_ube32(buf + 12, total_sectors - 1);
1683   - cpu_to_ube32(buf + 16, total_sectors - 1);
  1775 + memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
  1776 + IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
1684 1777  
1685   - cpu_to_be16wu((uint16_t *)buf, 2048 + 4);
  1778 + switch (format) {
  1779 + case 0x00 ... 0x7f:
  1780 + case 0xff:
  1781 + if (media == 0) {
  1782 + ret = ide_dvd_read_structure(s, format, packet, buf);
1686 1783  
1687   - ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4);
1688   - break;
  1784 + if (ret < 0)
  1785 + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
  1786 + else
  1787 + ide_atapi_cmd_reply(s, ret, max_len);
1689 1788  
  1789 + break;
  1790 + }
  1791 + /* TODO: BD support, fall through for now */
  1792 +
  1793 + /* Generic disk structures */
  1794 + case 0x80: /* TODO: AACS volume identifier */
  1795 + case 0x81: /* TODO: AACS media serial number */
  1796 + case 0x82: /* TODO: AACS media identifier */
  1797 + case 0x83: /* TODO: AACS media key block */
  1798 + case 0x90: /* TODO: List of recognized format layers */
  1799 + case 0xc0: /* TODO: Write protection status */
1690 1800 default:
1691 1801 ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
1692 1802 ASC_INV_FIELD_IN_CMD_PACKET);
... ... @@ -1741,16 +1851,11 @@ static void ide_atapi_cmd(IDEState *s)
1741 1851 /*
1742 1852 * the number of sectors from the media tells us which profile
1743 1853 * to use as current. 0 means there is no media
1744   - *
1745   - * XXX: fails to detect correctly DVDs with less data burned
1746   - * than what a CD can hold
1747 1854 */
1748   - if (s -> nb_sectors) {
1749   - if (s -> nb_sectors > CD_MAX_SECTORS)
1750   - cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
1751   - else
1752   - cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
1753   - }
  1855 + if (media_is_dvd(s))
  1856 + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
  1857 + else if (media_is_cd(s))
  1858 + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
1754 1859  
1755 1860 buf[10] = 0x02 | 0x01; /* persistent and current */
1756 1861 len = 12; /* headers: 8 + 4 */
... ...