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 */ | ... | ... |