VirtualBox

Changeset 40841 in vbox for trunk/src


Ignore:
Timestamp:
Apr 10, 2012 8:22:56 AM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
77360
Message:

Storage/ATA: Fix CD/DVD passthrough and Session At Once (SAO) recording by saving the CUE sheet and determining the correct sector sizes during recording

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

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

    r40774 r40841  
    303303    /** The revision string for SCSI INQUIRY commands. */
    304304    char                                szInquiryRevision[ATAPI_INQUIRY_REVISION_LENGTH+1];
    305 
    306     uint8_t                             abAlignment3[7];
     305    /** Size of the current CUE sheet in bytes. */
     306    uint32_t                            cbCueSheet;
     307    /** Align pbCueSheet correctly. */
     308    uint32_t                            u32Alignment3;
     309    /** The current CUE Sheet if passthrough is used. */
     310    R3PTRTYPE(uint8_t *)                pbCueSheet;
     311
     312    uint8_t                             abAlignment4[HC_ARCH_BITS == 64 ? 7 : 3];
    307313} ATADevState;
    308314AssertCompileMemberAlignment(ATADevState, cTotalSectors, 8);
     
    11271133}
    11281134
     1135/**
     1136 * Compares two MSF values.
     1137 *
     1138 * @returns 1  if the first value is greater than the second value.
     1139 *          0  if both are equal
     1140 *          -1 if the first value is smaller than the second value.
     1141 */
     1142DECLINLINE(int) atapiCmpMSF(const uint8_t *pbMSF1, const uint8_t *pbMSF2)
     1143{
     1144    int iRes = 0;
     1145
     1146    for (unsigned i = 0; i < 3; i++)
     1147    {
     1148        if (pbMSF1[i] < pbMSF2[i])
     1149        {
     1150            iRes = -1;
     1151            break;
     1152        }
     1153        else if (pbMSF1[i] > pbMSF2[i])
     1154        {
     1155            iRes = 1;
     1156            break;
     1157        }
     1158    }
     1159
     1160    return iRes;
     1161}
     1162
     1163/**
     1164 * Return the correct sector size from the given LBA.
     1165 *
     1166 * @returns Sector size.
     1167 * @param   s            ATA Device state.
     1168 * @param   iATAPILBA    The LBA.
     1169 */
     1170static size_t atapiGetSectorSizeFromLba(ATADevState *s, uint32_t iATAPILBA)
     1171{
     1172    size_t cbATAPISector = 2048;
     1173
     1174    /*
     1175     * Check if there is a valid CUE Sheet we can use,
     1176     * otherwise we just return the standard sector size.
     1177     */
     1178    if (s->pbCueSheet)
     1179    {
     1180        uint8_t *pbCueSheetEntry = NULL;
     1181        uint8_t iMSF[3];
     1182
     1183        /*
     1184         * Convert the LBA to the MSF format so we can look it up in the cue sheet.
     1185         * Note that it is possible to have negative LBA values for the Lead-In area.
     1186         * See MMC6 spec chapter 6.46.3.3 for more details.
     1187         */
     1188        LogFlowFunc(("iATAPILBA=%#x (signed: %d unsigned: %u)\n",
     1189                     iATAPILBA, (int32_t)iATAPILBA, iATAPILBA));
     1190
     1191        if (   iATAPILBA > UINT32_C(0xffff4fa1)
     1192            && (int32_t)iATAPILBA < -150)
     1193        {
     1194            /* Lead-In area, this is always the first entry in the cue sheet. */
     1195            pbCueSheetEntry = s->pbCueSheet;
     1196            LogFlowFunc(("Selected Lead-In area\n"));
     1197        }
     1198        else
     1199        {
     1200            iATAPILBA += 150;
     1201            iMSF[0] = (iATAPILBA / 75) / 60;
     1202            iMSF[1] = (iATAPILBA / 75) % 60;
     1203            iMSF[2] = iATAPILBA % 75;
     1204
     1205            pbCueSheetEntry = s->pbCueSheet + 8; /* Start after the Lead-in track. */
     1206
     1207            /* Go through the CUE sheet and find the correct entry. */
     1208            for (unsigned i = 0; i < (s->cbCueSheet / 8) - 2; i++)
     1209            {
     1210                if (   atapiCmpMSF(&pbCueSheetEntry[5], iMSF) != 1
     1211                    && atapiCmpMSF(&pbCueSheetEntry[8+5], iMSF) == 1)
     1212                    break;
     1213                pbCueSheetEntry += 8;
     1214            }
     1215            LogFlowFunc(("Selected CUE sheet entry iMin=%u iSec=%u iFrame=%u\n",
     1216                         pbCueSheetEntry[5], pbCueSheetEntry[6], pbCueSheetEntry[7]));
     1217        }
     1218
     1219        if (pbCueSheetEntry)
     1220        {
     1221            /* Determine size of main data based on the data form field. */
     1222            switch (pbCueSheetEntry[3] & 0x3f)
     1223            {
     1224                case 0x00: /* CD-DA with data. */
     1225                case 0x11: /* CD-ROM mode 1 */
     1226                case 0x13:
     1227                case 0x21: /* CD-ROM XA, CD-I */
     1228                case 0x23:
     1229                case 0x31: /* CD-ROM Mode 2 */
     1230                case 0x33:
     1231                    cbATAPISector = 2352;
     1232                    break;
     1233                case 0x01: /* CD-DA without data (used for pauses between tracks). */
     1234                case 0x14:
     1235                case 0x24:
     1236                case 0x34:
     1237                    cbATAPISector = 0;
     1238                    break;
     1239                case 0x10: /* CD-ROM mode 1 */
     1240                case 0x12:
     1241                    cbATAPISector = 2048;
     1242                    break;
     1243                case 0x20: /* CD-ROM XA, CD-I */
     1244                case 0x22:
     1245                case 0x30: /* CD-ROM Mode 2 */
     1246                case 0x32:
     1247                    cbATAPISector = 2336;
     1248                    break;
     1249                default: /* Reserved, invalid mode. Log and leave default sector size. */
     1250                    LogRel(("ATA: Invalid data form mode %u for current CUE sheet\n",
     1251                            pbCueSheetEntry[3] & 0x3f));
     1252            }
     1253
     1254            /* Determine size of sub channel data based on data form field. */
     1255            switch ((pbCueSheetEntry[3] & 0xc0) >> 6)
     1256            {
     1257                case 0x00: /* Sub channel all zeroes, autogenerated by the drive. */
     1258                    break;
     1259                case 0x01:
     1260                case 0x03:
     1261                    cbATAPISector += 96;
     1262                    break;
     1263                default:
     1264                    LogRel(("ATA: Invalid sub-channel data form mode %u for current CUE sheet\n",
     1265                            pbCueSheetEntry[3] & 0xc0));
     1266            }
     1267        }
     1268    }
     1269
     1270    LogFlowFunc(("cbATAPISector=%zu\n", cbATAPISector));
     1271    return cbATAPISector;
     1272}
    11291273
    11301274static void ataCmdOK(ATADevState *s, uint8_t status)
     
    19172061    PDMCritSectLeave(&pCtl->lock);
    19182062
     2063#if defined(LOG_ENABLED)
     2064    char szBuf[1024];
     2065
     2066    memset(szBuf, 0, sizeof(szBuf));
     2067
     2068    switch (s->aATAPICmd[0])
     2069    {
     2070        case SCSI_MODE_SELECT_10:
     2071        {
     2072            size_t cbBlkDescLength = ataBE2H_U16(&s->CTX_SUFF(pbIOBuffer)[6]);
     2073
     2074            SCSILogModePage(szBuf, sizeof(szBuf) - 1,
     2075                            s->CTX_SUFF(pbIOBuffer) + 8 + cbBlkDescLength,
     2076                            cbTransfer - 8 - cbBlkDescLength);
     2077            break;
     2078        }
     2079        case SCSI_SEND_CUE_SHEET:
     2080        {
     2081            SCSILogCueSheet(szBuf, sizeof(szBuf) - 1,
     2082                            s->CTX_SUFF(pbIOBuffer), cbTransfer);
     2083            break;
     2084        }
     2085        default:
     2086            break;
     2087    }
     2088
     2089    Log2(("%s\n", szBuf));
     2090#endif
     2091
    19192092    if (pProf) { STAM_PROFILE_ADV_START(pProf, b); }
    19202093    if (   cbTransfer > SCSI_MAX_BUFFER_SIZE
     
    20632236    if (RT_SUCCESS(rc))
    20642237    {
     2238        /* Do post processing for certain commands. */
     2239        switch (s->aATAPICmd[0])
     2240        {
     2241            case SCSI_SEND_CUE_SHEET:
     2242            {
     2243                /* Save the CUE sheet to determine sector sizes during writes */
     2244                if (s->pbCueSheet)
     2245                {
     2246                    s->cbCueSheet = 0;
     2247                    RTMemFree(s->pbCueSheet);
     2248                }
     2249
     2250                s->pbCueSheet = (uint8_t *)RTMemAllocZ(s->cbElementaryTransfer);
     2251                if (s->pbCueSheet)
     2252                {
     2253                    s->cbCueSheet = s->cbElementaryTransfer;
     2254                    memcpy(s->pbCueSheet, s->CTX_SUFF(pbIOBuffer), s->cbElementaryTransfer);
     2255                }
     2256                else if (s->cErrors++ < MAX_LOG_REL_ERRORS)
     2257                    LogRel(("ATA: Out of memory while saving the CUE sheet, burning disc might fail\n"));
     2258                break;
     2259            }
     2260            case SCSI_SYNCHRONIZE_CACHE:
     2261            {
     2262                /* Free the current CUE sheet after session at once recording. */
     2263                if (s->pbCueSheet)
     2264                {
     2265                    s->cbCueSheet = 0;
     2266                    RTMemFree(s->pbCueSheet);
     2267                }
     2268                break;
     2269            }
     2270        }
     2271
    20652272        if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
    20662273        {
     
    35573764            goto sendcmd;
    35583765        case SCSI_WRITE_10:
     3766        case SCSI_WRITE_AND_VERIFY_10:
    35593767            iATAPILBA = ataBE2H_U32(pbPacket + 2);
    35603768            cSectors = ataBE2H_U16(pbPacket + 7);
    3561             Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
    3562 #if 0
    3563             /* The sector size is determined by the async I/O thread. */
    3564             s->cbATAPISector = 0;
    3565             /* Preliminary, will be corrected once the sector size is known. */
    3566             cbTransfer = cSectors;
    3567 #else
    3568             s->cbATAPISector = 2048; /**< @todo this size is not always correct */
     3769            s->cbATAPISector = atapiGetSectorSizeFromLba(s, iATAPILBA);
     3770            Log2(("ATAPI PT: lba %d sectors %d sector size %d\n", iATAPILBA, cSectors, s->cbATAPISector));
    35693771            cbTransfer = cSectors * s->cbATAPISector;
    3570 #endif
    35713772            uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
    35723773            goto sendcmd;
     
    35743775            iATAPILBA = ataBE2H_U32(pbPacket + 2);
    35753776            cSectors = ataBE2H_U32(pbPacket + 6);
    3576             Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
    3577 #if 0
    3578             /* The sector size is determined by the async I/O thread. */
    3579             s->cbATAPISector = 0;
    3580             /* Preliminary, will be corrected once the sector size is known. */
    3581             cbTransfer = cSectors;
    3582 #else
    3583             s->cbATAPISector = 2048; /**< @todo this size is not always correct */
     3777            s->cbATAPISector = atapiGetSectorSizeFromLba(s, iATAPILBA);
     3778            Log2(("ATAPI PT: lba %d sectors %d sector size %d\n", iATAPILBA, cSectors, s->cbATAPISector));
    35843779            cbTransfer = cSectors * s->cbATAPISector;
    3585 #endif
    3586             uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
    3587             goto sendcmd;
    3588         case SCSI_WRITE_AND_VERIFY_10:
    3589             iATAPILBA = ataBE2H_U32(pbPacket + 2);
    3590             cSectors = ataBE2H_U16(pbPacket + 7);
    3591             Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
    3592             /* The sector size is determined by the async I/O thread. */
    3593             s->cbATAPISector = 0;
    3594             /* Preliminary, will be corrected once the sector size is known. */
    3595             cbTransfer = cSectors;
    35963780            uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
    35973781            goto sendcmd;
     
    48235007            {
    48245008                dmalen = RT_MIN(cbBuffer, iIOBufferEnd - iIOBufferCur);
    4825                 Log2(("%s: DMA desc %#010x: addr=%#010x size=%#010x\n", __FUNCTION__,
    4826                        (int)pDesc, pBuffer, cbBuffer));
     5009                Log2(("%s: DMA desc %#010x: addr=%#010x size=%#010x orig_size=%#010x\n", __FUNCTION__,
     5010                       (int)pDesc, pBuffer, cbBuffer, RT_LE2H_U32(DMADesc.cbBuffer) & 0xfffe));
    48275011                if (uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
    48285012                    PDMDevHlpPhysWrite(pDevIns, pBuffer, s->CTX_SUFF(pbIOBuffer) + iIOBufferCur, dmalen);
     
    61086292                LogRel(("PIIX3 ATA Dtor: Ctl#%u actually completed.\n", i));
    61096293            }
     6294        }
     6295
     6296        for (uint32_t iIf = 0; iIf < RT_ELEMENTS(pThis->aCts[i].aIfs); iIf++)
     6297        {
     6298            if (pThis->aCts[i].aIfs[iIf].pbCueSheet)
     6299                RTMemFree(pThis->aCts[i].aIfs[iIf].pbCueSheet);
    61106300        }
    61116301    }
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r40040 r40841  
    811811    GEN_CHECK_OFF(ATADevState, szInquiryRevision);
    812812    GEN_CHECK_OFF(ATADevState, szInquiryRevision[ATAPI_INQUIRY_REVISION_LENGTH]);
     813    GEN_CHECK_OFF(ATADevState, cbCueSheet);
     814    GEN_CHECK_OFF(ATADevState, pbCueSheet);
    813815    GEN_CHECK_SIZE(ATATransferRequest);
    814816    GEN_CHECK_OFF(ATATransferRequest, iIf);
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