VirtualBox

Changeset 66198 in vbox


Ignore:
Timestamp:
Mar 22, 2017 2:23:57 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
114113
Message:

ATA: Support discs with multiple tracks

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r66057 r66198  
    18401840    int rc = VINF_SUCCESS;
    18411841    uint32_t cbTransfer, cSectors;
     1842    uint64_t cbBlockRegion = 0;
    18421843
    18431844    Assert(s->uTxDir == PDMMEDIATXDIR_FROM_DEVICE);
     
    18491850    ataR3LockLeave(pCtl);
    18501851
    1851     STAM_PROFILE_ADV_START(&s->StatReads, r);
    1852     s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
    1853     switch (s->cbATAPISector)
    1854     {
    1855         case 2048:
    1856             rc = s->pDrvMedia->pfnRead(s->pDrvMedia, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTX_SUFF(pbIOBuffer), s->cbATAPISector * cSectors);
    1857             break;
    1858         case 2352:
    1859         {
    1860             uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer);
    1861 
    1862             for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
     1852    rc = s->pDrvMedia->pfnQueryRegionPropertiesForLba(s->pDrvMedia, s->iATAPILBA, NULL, NULL,
     1853                                                      &cbBlockRegion, NULL);
     1854    if (RT_SUCCESS(rc))
     1855    {
     1856        STAM_PROFILE_ADV_START(&s->StatReads, r);
     1857        s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
     1858
     1859        /* If the region block size and requested sector matches we can just pass the request through. */
     1860        if (cbBlockRegion == s->cbATAPISector)
     1861            rc = s->pDrvMedia->pfnRead(s->pDrvMedia, (uint64_t)s->iATAPILBA * s->cbATAPISector,
     1862                                       s->CTX_SUFF(pbIOBuffer), s->cbATAPISector * cSectors);
     1863        else
     1864        {
     1865            if (cbBlockRegion == 2048 && s->cbATAPISector == 2352)
    18631866            {
    1864                 /* Sync bytes, see 4.2.3.8 CD Main Channel Block Formats */
    1865                 *pbBuf++ = 0x00;
    1866                 memset(pbBuf, 0xff, 10);
    1867                 pbBuf += 10;
    1868                 *pbBuf++ = 0x00;
    1869                 /* MSF */
    1870                 scsiLBA2MSF(pbBuf, i);
    1871                 pbBuf += 3;
    1872                 *pbBuf++ = 0x01; /* mode 1 data */
    1873                 /* data */
    1874                 rc = s->pDrvMedia->pfnRead(s->pDrvMedia, (uint64_t)i * 2048, pbBuf, 2048);
    1875                 if (RT_FAILURE(rc))
    1876                     break;
    1877                 pbBuf += 2048;
    1878                 /**
    1879                  * @todo: maybe compute ECC and parity, layout is:
    1880                  * 2072 4   EDC
    1881                  * 2076 172 P parity symbols
    1882                  * 2248 104 Q parity symbols
    1883                  */
    1884                 memset(pbBuf, 0, 280);
    1885                 pbBuf += 280;
     1867                /* Generate the sync bytes. */
     1868                uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer);
     1869
     1870                for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
     1871                {
     1872                    /* Sync bytes, see 4.2.3.8 CD Main Channel Block Formats */
     1873                    *pbBuf++ = 0x00;
     1874                    memset(pbBuf, 0xff, 10);
     1875                    pbBuf += 10;
     1876                    *pbBuf++ = 0x00;
     1877                    /* MSF */
     1878                    scsiLBA2MSF(pbBuf, i);
     1879                    pbBuf += 3;
     1880                    *pbBuf++ = 0x01; /* mode 1 data */
     1881                    /* data */
     1882                    rc = s->pDrvMedia->pfnRead(s->pDrvMedia, (uint64_t)i * 2048, pbBuf, 2048);
     1883                    if (RT_FAILURE(rc))
     1884                        break;
     1885                    pbBuf += 2048;
     1886                    /**
     1887                     * @todo: maybe compute ECC and parity, layout is:
     1888                     * 2072 4   EDC
     1889                     * 2076 172 P parity symbols
     1890                     * 2248 104 Q parity symbols
     1891                     */
     1892                    memset(pbBuf, 0, 280);
     1893                    pbBuf += 280;
     1894                }
    18861895            }
    1887             break;
    1888         }
    1889         default:
    1890             break;
    1891     }
    1892     s->Led.Actual.s.fReading = 0;
    1893     STAM_PROFILE_ADV_STOP(&s->StatReads, r);
     1896            else if (cbBlockRegion == 2352 && s->cbATAPISector == 2048)
     1897            {
     1898                /* Read only the user data portion. */
     1899                uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer);
     1900
     1901                for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
     1902                {
     1903                    uint8_t abTmp[2352];
     1904                    rc = s->pDrvMedia->pfnRead(s->pDrvMedia, (uint64_t)i * 2352, &abTmp[0], 2352);
     1905                    if (RT_FAILURE(rc))
     1906                        break;
     1907
     1908                    memcpy(pbBuf, &abTmp[16], 2048);
     1909                    pbBuf += 2048;
     1910                }
     1911            }
     1912        }
     1913        s->Led.Actual.s.fReading = 0;
     1914        STAM_PROFILE_ADV_STOP(&s->StatReads, r);
     1915    }
    18941916
    18951917    ataR3LockEnter(pCtl);
     
    21812203
    21822204            if (cbTransfer)
    2183                 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
     2205                Log3(("ATAPI PT data read (%d):\n%.*Rhxd\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
    21842206        }
    21852207
     
    24152437    pbBuf[4] = 1; /* number of sessions (LSB) */
    24162438    pbBuf[5] = 1; /* first track number in last session (LSB) */
    2417     pbBuf[6] = 1; /* last track number in last session (LSB) */
     2439    pbBuf[6] = (uint8_t)s->pDrvMedia->pfnGetRegionCount(s->pDrvMedia); /* last track number in last session (LSB) */
    24182440    pbBuf[7] = (0 << 7) | (0 << 6) | (1 << 5) | (0 << 2) | (0 << 0); /* disc id not valid, disc bar code not valid, unrestricted use, not dirty, not RW medium */
    24192441    pbBuf[8] = 0; /* disc type = CD-ROM */
     
    24212443    pbBuf[10] = 0; /* number of sessions (MSB) */
    24222444    pbBuf[11] = 0; /* number of sessions (MSB) */
    2423     scsiH2BE_U32(pbBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
    2424     scsiH2BE_U32(pbBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
     2445    scsiH2BE_U32(pbBuf + 16, 0xffffffff); /* last session lead-in start time is not available */
     2446    scsiH2BE_U32(pbBuf + 20, 0xffffffff); /* last possible start time for lead-out is not available */
    24252447    s->iSourceSink = ATAFN_SS_NULL;
    24262448    atapiR3CmdOK(s);
     
    24322454{
    24332455    uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer);
     2456    uint32_t u32LogAddr = scsiBE2H_U32(&s->aATAPICmd[2]);
     2457    uint8_t u8LogAddrType = s->aATAPICmd[1] & 0x03;
     2458
     2459    int rc = VINF_SUCCESS;
     2460    uint64_t u64LbaStart = 0;
     2461    uint32_t uRegion = 0;
     2462    uint64_t cBlocks = 0;
     2463    uint64_t cbBlock = 0;
     2464    uint8_t u8DataMode = 0xf; /* Unknown data mode. */
     2465    uint8_t u8TrackMode = 0;
     2466    VDREGIONDATAFORM enmDataForm = VDREGIONDATAFORM_INVALID;
    24342467
    24352468    Assert(s->uTxDir == PDMMEDIATXDIR_FROM_DEVICE);
    24362469    Assert(s->cbElementaryTransfer <= 36);
    2437     /* Accept address/number type of 1 only, and only track 1 exists. */
    2438     if ((s->aATAPICmd[1] & 0x03) != 1 || scsiBE2H_U32(&s->aATAPICmd[2]) != 1)
     2470
     2471    switch (u8LogAddrType)
     2472    {
     2473        case 0x00:
     2474            rc = s->pDrvMedia->pfnQueryRegionPropertiesForLba(s->pDrvMedia, u32LogAddr, &uRegion,
     2475                                                              NULL, NULL, NULL);
     2476            if (RT_SUCCESS(rc))
     2477                rc = s->pDrvMedia->pfnQueryRegionProperties(s->pDrvMedia, uRegion, &u64LbaStart,
     2478                                                            &cBlocks, &cbBlock, &enmDataForm);
     2479            break;
     2480        case 0x01:
     2481        {
     2482            if (u32LogAddr >= 1)
     2483            {
     2484                uRegion = u32LogAddr - 1;
     2485                rc = s->pDrvMedia->pfnQueryRegionProperties(s->pDrvMedia, uRegion, &u64LbaStart,
     2486                                                            &cBlocks, &cbBlock, &enmDataForm);
     2487            }
     2488            else
     2489                rc = VERR_NOT_FOUND; /** @todo: Return lead-in information. */
     2490            break;
     2491        }
     2492        case 0x02:
     2493        default:
     2494            atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     2495            return false;
     2496    }
     2497
     2498    if (RT_FAILURE(rc))
    24392499    {
    24402500        atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    24412501        return false;
    24422502    }
     2503
     2504    switch (enmDataForm)
     2505    {
     2506        case VDREGIONDATAFORM_MODE1_2048:
     2507        case VDREGIONDATAFORM_MODE1_2352:
     2508        case VDREGIONDATAFORM_MODE1_0:
     2509            u8DataMode = 1;
     2510            break;
     2511        case VDREGIONDATAFORM_XA_2336:
     2512        case VDREGIONDATAFORM_XA_2352:
     2513        case VDREGIONDATAFORM_XA_0:
     2514        case VDREGIONDATAFORM_MODE2_2336:
     2515        case VDREGIONDATAFORM_MODE2_2352:
     2516        case VDREGIONDATAFORM_MODE2_0:
     2517            u8DataMode = 2;
     2518            break;
     2519        default:
     2520            u8DataMode = 0xf;
     2521    }
     2522
     2523    if (enmDataForm == VDREGIONDATAFORM_CDDA)
     2524        u8TrackMode = 0x0;
     2525    else
     2526        u8TrackMode = 0x4;
     2527
    24432528    memset(pbBuf, '\0', 36);
    24442529    scsiH2BE_U16(pbBuf, 34);
    2445     pbBuf[2] = 1; /* track number (LSB) */
    2446     pbBuf[3] = 1; /* session number (LSB) */
    2447     pbBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
    2448     pbBuf[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
    2449     pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
    2450     scsiH2BE_U32(pbBuf + 8, 0); /* track start address is 0 */
    2451     scsiH2BE_U32(pbBuf + 24, s->cTotalSectors); /* track size */
    2452     pbBuf[32] = 0; /* track number (MSB) */
    2453     pbBuf[33] = 0; /* session number (MSB) */
     2530    pbBuf[2] = uRegion + 1;                                            /* track number (LSB) */
     2531    pbBuf[3] = 1;                                                      /* session number (LSB) */
     2532    pbBuf[5] = (0 << 5) | (0 << 4) | u8TrackMode;                      /* not damaged, primary copy, data track */
     2533    pbBuf[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | u8DataMode; /* not reserved track, not blank, not packet writing, not fixed packet */
     2534    pbBuf[7] = (0 << 1) | (0 << 0);                                    /* last recorded address not valid, next recordable address not valid */
     2535    scsiH2BE_U32(pbBuf + 8, (uint32_t)u64LbaStart);                    /* track start address is 0 */
     2536    scsiH2BE_U32(pbBuf + 24, (uint32_t)cBlocks);                      /* track size */
     2537    pbBuf[32] = 0;                                                     /* track number (MSB) */
     2538    pbBuf[33] = 0;                                                     /* session number (MSB) */
    24542539    s->iSourceSink = ATAFN_SS_NULL;
    24552540    atapiR3CmdOK(s);
     
    24762561}
    24772562
    2478 static uint32_t atapiR3GetConfigurationFillFeatureCore(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2563static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureCore(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    24792564{
    24802565    RT_NOREF1(s);
     
    24922577}
    24932578
    2494 static uint32_t atapiR3GetConfigurationFillFeatureMorphing(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2579static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureMorphing(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    24952580{
    24962581    RT_NOREF1(s);
     
    25072592}
    25082593
    2509 static uint32_t atapiR3GetConfigurationFillFeatureRemovableMedium(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2594static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureRemovableMedium(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    25102595{
    25112596    RT_NOREF1(s);
     
    25232608}
    25242609
    2525 static uint32_t atapiR3GetConfigurationFillFeatureRandomReadable (ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2610static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureRandomReadable (ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    25262611{
    25272612    RT_NOREF1(s);
     
    25402625}
    25412626
    2542 static uint32_t atapiR3GetConfigurationFillFeatureCDRead(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2627static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureCDRead(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    25432628{
    25442629    RT_NOREF1(s);
     
    25552640}
    25562641
    2557 static uint32_t atapiR3GetConfigurationFillFeaturePowerManagement(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2642static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeaturePowerManagement(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    25582643{
    25592644    RT_NOREF1(s);
     
    25682653}
    25692654
    2570 static uint32_t atapiR3GetConfigurationFillFeatureTimeout(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
     2655static DECLCALLBACK(uint32_t) atapiR3GetConfigurationFillFeatureTimeout(ATADevState *s, uint8_t *pbBuf, size_t cbBuf)
    25712656{
    25722657    RT_NOREF1(s);
     
    25822667}
    25832668
     2669/**
     2670 * Callback to fill in the correct data for a feature.
     2671 *
     2672 * @returns Number of bytes written into the buffer.
     2673 * @param   s       The ATA device state.
     2674 * @param   pbBuf   The buffer to fill the data with.
     2675 * @param   cbBuf   Size of the buffer.
     2676 */
     2677typedef DECLCALLBACK(uint32_t) FNATAPIR3FEATUREFILL(ATADevState *s, uint8_t *pbBuf, size_t cbBuf);
     2678/** Pointer to a feature fill callback. */
     2679typedef FNATAPIR3FEATUREFILL *PFNATAPIR3FEATUREFILL;
     2680
     2681/**
     2682 * ATAPI feature descriptor.
     2683 */
     2684typedef struct ATAPIR3FEATDESC
     2685{
     2686    /** The feature number. */
     2687    uint16_t u16Feat;
     2688    /** The callback to fill in the correct data. */
     2689    PFNATAPIR3FEATUREFILL pfnFeatureFill;
     2690} ATAPIR3FEATDESC;
     2691
     2692/**
     2693 * Array of known ATAPI feature descriptors.
     2694 */
     2695static const ATAPIR3FEATDESC s_aAtapiR3Features[] =
     2696{
     2697    { 0x0000, atapiR3GetConfigurationFillFeatureListProfiles},
     2698    { 0x0001, atapiR3GetConfigurationFillFeatureCore},
     2699    { 0x0002, atapiR3GetConfigurationFillFeatureMorphing},
     2700    { 0x0003, atapiR3GetConfigurationFillFeatureRemovableMedium},
     2701    { 0x0010, atapiR3GetConfigurationFillFeatureRandomReadable},
     2702    { 0x001e, atapiR3GetConfigurationFillFeatureCDRead},
     2703    { 0x0100, atapiR3GetConfigurationFillFeaturePowerManagement},
     2704    { 0x0105, atapiR3GetConfigurationFillFeatureTimeout}
     2705};
     2706
    25842707static bool atapiR3GetConfigurationSS(ATADevState *s)
    25852708{
     
    25882711    uint32_t cbCopied = 0;
    25892712    uint16_t u16Sfn = scsiBE2H_U16(&s->aATAPICmd[2]);
     2713    uint8_t u8Rt = s->aATAPICmd[1] & 0x03;
    25902714
    25912715    Assert(s->uTxDir == PDMMEDIATXDIR_FROM_DEVICE);
    25922716    Assert(s->cbElementaryTransfer <= 80);
    2593     /* Accept valid request types only, and only starting feature 0. */
    2594     if ((s->aATAPICmd[1] & 0x03) == 3 || u16Sfn != 0)
     2717    /* Accept valid request types only. */
     2718    if (u8Rt == 3)
    25952719    {
    25962720        atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     
    26072731    pbBuf    += 8;
    26082732
    2609     cbCopied = atapiR3GetConfigurationFillFeatureListProfiles(s, pbBuf, cbBuf);
    2610     cbBuf -= cbCopied;
    2611     pbBuf += cbCopied;
    2612 
    2613     cbCopied = atapiR3GetConfigurationFillFeatureCore(s, pbBuf, cbBuf);
    2614     cbBuf -= cbCopied;
    2615     pbBuf += cbCopied;
    2616 
    2617     cbCopied = atapiR3GetConfigurationFillFeatureMorphing(s, pbBuf, cbBuf);
    2618     cbBuf -= cbCopied;
    2619     pbBuf += cbCopied;
    2620 
    2621     cbCopied = atapiR3GetConfigurationFillFeatureRemovableMedium(s, pbBuf, cbBuf);
    2622     cbBuf -= cbCopied;
    2623     pbBuf += cbCopied;
    2624 
    2625     cbCopied = atapiR3GetConfigurationFillFeatureRandomReadable (s, pbBuf, cbBuf);
    2626     cbBuf -= cbCopied;
    2627     pbBuf += cbCopied;
    2628 
    2629     cbCopied = atapiR3GetConfigurationFillFeatureCDRead(s, pbBuf, cbBuf);
    2630     cbBuf -= cbCopied;
    2631     pbBuf += cbCopied;
    2632 
    2633     cbCopied = atapiR3GetConfigurationFillFeaturePowerManagement(s, pbBuf, cbBuf);
    2634     cbBuf -= cbCopied;
    2635     pbBuf += cbCopied;
    2636 
    2637     cbCopied = atapiR3GetConfigurationFillFeatureTimeout(s, pbBuf, cbBuf);
    2638     cbBuf -= cbCopied;
    2639     pbBuf += cbCopied;
     2733    if (u8Rt == 0x2)
     2734    {
     2735        for (uint32_t i = 0; i < RT_ELEMENTS(s_aAtapiR3Features); i++)
     2736        {
     2737            if (s_aAtapiR3Features[i].u16Feat == u16Sfn)
     2738            {
     2739                cbCopied = s_aAtapiR3Features[i].pfnFeatureFill(s, pbBuf, cbBuf);
     2740                cbBuf -= cbCopied;
     2741                pbBuf += cbCopied;
     2742                break;
     2743            }
     2744        }
     2745    }
     2746    else
     2747    {
     2748        for (uint32_t i = 0; i < RT_ELEMENTS(s_aAtapiR3Features); i++)
     2749        {
     2750            if (s_aAtapiR3Features[i].u16Feat > u16Sfn)
     2751            {
     2752                cbCopied = s_aAtapiR3Features[i].pfnFeatureFill(s, pbBuf, cbBuf);
     2753                cbBuf -= cbCopied;
     2754                pbBuf += cbCopied;
     2755            }
     2756        }
     2757    }
    26402758
    26412759    /* Set data length now - the field is not included in the final length. */
     
    28652983    bool fMSF;
    28662984    uint32_t cbSize;
     2985    uint32_t cTracks = s->pDrvMedia->pfnGetRegionCount(s->pDrvMedia);
    28672986
    28682987    Assert(s->uTxDir == PDMMEDIATXDIR_FROM_DEVICE);
    28692988    fMSF = (s->aATAPICmd[1] >> 1) & 1;
    28702989    iStartTrack = s->aATAPICmd[6];
    2871     if (iStartTrack > 1 && iStartTrack != 0xaa)
     2990    if (iStartTrack == 0)
     2991        iStartTrack = 1;
     2992
     2993    if (iStartTrack > cTracks && iStartTrack != 0xaa)
    28722994    {
    28732995        atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     
    28752997    }
    28762998    q = pbBuf + 2;
    2877     *q++ = 1; /* first session */
    2878     *q++ = 1; /* last session */
    2879     if (iStartTrack <= 1)
    2880     {
    2881         *q++ = 0; /* reserved */
    2882         *q++ = 0x14; /* ADR, control */
    2883         *q++ = 1;    /* track number */
    2884         *q++ = 0; /* reserved */
     2999    *q++ = iStartTrack; /* first track number */
     3000    *q++ = cTracks;     /* last track number */
     3001    for (uint32_t iTrack = iStartTrack; iTrack <= cTracks; iTrack++)
     3002    {
     3003        uint64_t uLbaStart = 0;
     3004        VDREGIONDATAFORM enmDataForm = VDREGIONDATAFORM_MODE1_2048;
     3005
     3006        int rc = s->pDrvMedia->pfnQueryRegionProperties(s->pDrvMedia, iTrack - 1, &uLbaStart,
     3007                                                        NULL, NULL, &enmDataForm);
     3008        AssertRC(rc);
     3009
     3010        *q++ = 0;                  /* reserved */
     3011
     3012        if (enmDataForm == VDREGIONDATAFORM_CDDA)
     3013            *q++ = 0x10;           /* ADR, control */
     3014        else
     3015            *q++ = 0x14;           /* ADR, control */
     3016
     3017        *q++ = (uint8_t)iTrack;    /* track number */
     3018        *q++ = 0;                  /* reserved */
    28853019        if (fMSF)
    28863020        {
    28873021            *q++ = 0; /* reserved */
    2888             scsiLBA2MSF(q, 0);
     3022            scsiLBA2MSF(q, (uint32_t)uLbaStart);
    28893023            q += 3;
    28903024        }
     
    28923026        {
    28933027            /* sector 0 */
    2894             scsiH2BE_U32(q, 0);
     3028            scsiH2BE_U32(q, (uint32_t)uLbaStart);
    28953029            q += 4;
    28963030        }
     
    29013035    *q++ = 0xaa; /* track number */
    29023036    *q++ = 0; /* reserved */
     3037
     3038    /* Query start and length of last track to get the start of the lead out track. */
     3039    uint64_t uLbaStart = 0;
     3040    uint64_t cBlocks = 0;
     3041
     3042    int rc = s->pDrvMedia->pfnQueryRegionProperties(s->pDrvMedia, cTracks - 1, &uLbaStart,
     3043                                                    &cBlocks, NULL, NULL);
     3044    AssertRC(rc);
     3045
     3046    uLbaStart += cBlocks;
    29033047    if (fMSF)
    29043048    {
    29053049        *q++ = 0; /* reserved */
    2906         scsiLBA2MSF(q, s->cTotalSectors);
     3050        scsiLBA2MSF(q, (uint32_t)uLbaStart);
    29073051        q += 3;
    29083052    }
    29093053    else
    29103054    {
    2911         scsiH2BE_U32(q, s->cTotalSectors);
     3055        scsiH2BE_U32(q, (uint32_t)uLbaStart);
    29123056        q += 4;
    29133057    }
     
    29383082    pbBuf[2] = 0x01;
    29393083    pbBuf[3] = 0x01;
    2940     pbBuf[5] = 0x14; /* ADR, control */
     3084
     3085    VDREGIONDATAFORM enmDataForm = VDREGIONDATAFORM_MODE1_2048;
     3086    int rc = s->pDrvMedia->pfnQueryRegionProperties(s->pDrvMedia, 0, NULL,
     3087                                                    NULL, NULL, &enmDataForm);
     3088    AssertRC(rc);
     3089
     3090    if (enmDataForm == VDREGIONDATAFORM_CDDA)
     3091        pbBuf[5] = 0x10;           /* ADR, control */
     3092    else
     3093        pbBuf[5] = 0x14;           /* ADR, control */
     3094
    29413095    pbBuf[6] = 1; /* first track in last complete session */
    29423096    if (fMSF)
     
    31393293                cSectors = scsiBE2H_U32(pbPacket + 6);
    31403294            iATAPILBA = scsiBE2H_U32(pbPacket + 2);
     3295
     3296            /* Check that the sector size is valid. */
     3297            uint64_t cbSector = 2048;
     3298            int rc = s->pDrvMedia->pfnQueryRegionPropertiesForLba(s->pDrvMedia, iATAPILBA,
     3299                                                                  NULL, NULL, &cbSector, NULL);
     3300            AssertRC(rc);
     3301            if (cbSector != 2048)
     3302            {
     3303                uint8_t abATAPISense[ATAPI_SENSE_SIZE];
     3304                RT_ZERO(abATAPISense);
     3305
     3306                abATAPISense[0] = 0x70 | (1 << 7);
     3307                abATAPISense[2] = (SCSI_SENSE_ILLEGAL_REQUEST & 0x0f) | SCSI_SENSE_FLAG_ILI;
     3308                scsiH2BE_U32(&abATAPISense[3], iATAPILBA);
     3309                abATAPISense[7] = 10;
     3310                abATAPISense[12] = SCSI_ASC_ILLEGAL_MODE_FOR_THIS_TRACK;
     3311                atapiR3CmdError(s, &abATAPISense[0], sizeof(abATAPISense));
     3312                break;
     3313            }
     3314
    31413315            if (cSectors == 0)
    31423316            {
     
    31753349            {
    31763350                atapiR3CmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3351                break;
     3352            }
     3353            if ((pbPacket[10] & 0x7) != 0)
     3354            {
     3355                atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    31773356                break;
    31783357            }
     
    31993378                break;
    32003379            }
    3201             switch (pbPacket[9] & 0xf8)
     3380            /*
     3381             * If the LBA is in an audio track we are required to ignore pretty much all
     3382             * of the channel selection values (except 0x00) and map everything to 0x10
     3383             * which means read user data with a sector size of 2352 bytes.
     3384             *
     3385             * (MMC-6 chapter 6.19.2.6)
     3386             */
     3387            uint8_t uChnSel = pbPacket[9] & 0xf8;
     3388            VDREGIONDATAFORM enmDataForm;
     3389            int rc = s->pDrvMedia->pfnQueryRegionPropertiesForLba(s->pDrvMedia, iATAPILBA,
     3390                                                                  NULL, NULL, NULL, &enmDataForm);
     3391            AssertRC(rc);
     3392
     3393            if (enmDataForm == VDREGIONDATAFORM_CDDA)
    32023394            {
    3203                 case 0x00:
     3395                if (uChnSel == 0)
     3396                {
    32043397                    /* nothing */
    32053398                    atapiR3CmdOK(s);
    3206                     break;
    3207                 case 0x10:
    3208                     /* normal read */
    3209                     atapiR3ReadSectors(s, iATAPILBA, cSectors, 2048);
    3210                     break;
    3211                 case 0xf8:
    3212                     /* read all data */
     3399                }
     3400                else
    32133401                    atapiR3ReadSectors(s, iATAPILBA, cSectors, 2352);
    3214                     break;
    3215                 default:
    3216                     LogRel(("PIIX3 ATA: LUN#%d: CD-ROM sector format not supported (%#x)\n", s->iLUN, pbPacket[9] & 0xf8));
    3217                     atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    3218                     break;
     3402            }
     3403            else
     3404            {
     3405                switch (uChnSel)
     3406                {
     3407                    case 0x00:
     3408                        /* nothing */
     3409                        atapiR3CmdOK(s);
     3410                        break;
     3411                    case 0x10:
     3412                        /* normal read */
     3413                        atapiR3ReadSectors(s, iATAPILBA, cSectors, 2048);
     3414                        break;
     3415                    case 0xf8:
     3416                        /* read all data */
     3417                        atapiR3ReadSectors(s, iATAPILBA, cSectors, 2352);
     3418                        break;
     3419                    default:
     3420                        LogRel(("PIIX3 ATA: LUN#%d: CD-ROM sector format not supported (%#x)\n", s->iLUN, pbPacket[9] & 0xf8));
     3421                        atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3422                        break;
     3423                }
    32193424            }
    32203425            break;
     
    35563761        return;
    35573762
    3558     if (pIf->fATAPI)
    3559         pIf->cTotalSectors = pIf->pDrvMedia->pfnGetSize(pIf->pDrvMedia) / 2048;
    3560     else
    3561         pIf->cTotalSectors = pIf->pDrvMedia->pfnGetSize(pIf->pDrvMedia) / pIf->cbSector;
     3763    uint32_t cRegions = pIf->pDrvMedia->pfnGetRegionCount(pIf->pDrvMedia);
     3764    for (uint32_t i = 0; i < cRegions; i++)
     3765    {
     3766        uint64_t cBlocks = 0;
     3767        int rc = pIf->pDrvMedia->pfnQueryRegionProperties(pIf->pDrvMedia, i, NULL, &cBlocks,
     3768                                                          NULL, NULL);
     3769        AssertRC(rc);
     3770        pIf->cTotalSectors += cBlocks;
     3771    }
    35623772
    35633773    LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pIf->iLUN, pIf->cTotalSectors));
     
    61616371     */
    61626372    if (pIf->fATAPI)
    6163         pIf->cbSector = 2048;
     6373        pIf->cbSector = 2048; /* Not required for ATAPI, one medium can have multiple sector sizes. */
    61646374    else
    61656375        pIf->cbSector = pIf->pDrvMedia->pfnGetSectorSize(pIf->pDrvMedia);
     
    61956405     * Init geometry (only for non-CD/DVD media).
    61966406     */
     6407    uint32_t cRegions = pIf->pDrvMedia->pfnGetRegionCount(pIf->pDrvMedia);
     6408    pIf->cTotalSectors = 0;
     6409    for (uint32_t i = 0; i < cRegions; i++)
     6410    {
     6411        uint64_t cBlocks = 0;
     6412        rc = pIf->pDrvMedia->pfnQueryRegionProperties(pIf->pDrvMedia, i, NULL, &cBlocks,
     6413                                                      NULL, NULL);
     6414        AssertRC(rc);
     6415        pIf->cTotalSectors += cBlocks;
     6416    }
     6417
    61976418    if (pIf->fATAPI)
    61986419    {
    6199         pIf->cTotalSectors = pIf->pDrvMedia->pfnGetSize(pIf->pDrvMedia) / pIf->cbSector;
    62006420        pIf->PCHSGeometry.cCylinders = 0; /* dummy */
    62016421        pIf->PCHSGeometry.cHeads     = 0; /* dummy */
     
    62066426    else
    62076427    {
    6208         pIf->cTotalSectors = pIf->pDrvMedia->pfnGetSize(pIf->pDrvMedia) / pIf->cbSector;
    62096428        rc = pIf->pDrvMedia->pfnBiosGetPCHSGeometry(pIf->pDrvMedia, &pIf->PCHSGeometry);
    62106429        if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette