Commit 8114e9e8fd2610b96a808cdf703127eb26eb5278
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 */ | ... | ... |