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,6 +351,7 @@ | ||
| 351 | #define ASC_ILLEGAL_OPCODE 0x20 | 351 | #define ASC_ILLEGAL_OPCODE 0x20 |
| 352 | #define ASC_LOGICAL_BLOCK_OOR 0x21 | 352 | #define ASC_LOGICAL_BLOCK_OOR 0x21 |
| 353 | #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 | 353 | #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 |
| 354 | +#define ASC_INCOMPATIBLE_FORMAT 0x30 | ||
| 354 | #define ASC_MEDIUM_NOT_PRESENT 0x3a | 355 | #define ASC_MEDIUM_NOT_PRESENT 0x3a |
| 355 | #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 | 356 | #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 |
| 356 | 357 | ||
| @@ -434,6 +435,22 @@ typedef struct IDEState { | @@ -434,6 +435,22 @@ typedef struct IDEState { | ||
| 434 | int media_changed; | 435 | int media_changed; |
| 435 | } IDEState; | 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 | #define BM_STATUS_DMAING 0x01 | 454 | #define BM_STATUS_DMAING 0x01 |
| 438 | #define BM_STATUS_ERROR 0x02 | 455 | #define BM_STATUS_ERROR 0x02 |
| 439 | #define BM_STATUS_INT 0x04 | 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,6 +1381,93 @@ static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, | ||
| 1364 | return 4; | 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 | static void ide_atapi_cmd(IDEState *s) | 1471 | static void ide_atapi_cmd(IDEState *s) |
| 1368 | { | 1472 | { |
| 1369 | const uint8_t *packet; | 1473 | const uint8_t *packet; |
| @@ -1651,42 +1755,48 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1651,42 +1755,48 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1651 | case GPCMD_READ_DVD_STRUCTURE: | 1755 | case GPCMD_READ_DVD_STRUCTURE: |
| 1652 | { | 1756 | { |
| 1653 | int media = packet[1]; | 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 | default: | 1800 | default: |
| 1691 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | 1801 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
| 1692 | ASC_INV_FIELD_IN_CMD_PACKET); | 1802 | ASC_INV_FIELD_IN_CMD_PACKET); |
| @@ -1741,16 +1851,11 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1741,16 +1851,11 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1741 | /* | 1851 | /* |
| 1742 | * the number of sectors from the media tells us which profile | 1852 | * the number of sectors from the media tells us which profile |
| 1743 | * to use as current. 0 means there is no media | 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 | buf[10] = 0x02 | 0x01; /* persistent and current */ | 1860 | buf[10] = 0x02 | 0x01; /* persistent and current */ |
| 1756 | len = 12; /* headers: 8 + 4 */ | 1861 | len = 12; /* headers: 8 + 4 */ |