VirtualBox

Changeset 39100 in vbox


Ignore:
Timestamp:
Oct 24, 2011 9:12:07 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
74532
Message:

DevATA: Implement proper command splitting if the command exceeds the I/O buffer

File:
1 edited

Legend:

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

    r39036 r39100  
    18941894    PSTAMPROFILEADV pProf = NULL;
    18951895
    1896     cbTransfer = s->cbElementaryTransfer;
     1896    cbTransfer = RT_MIN(s->cbElementaryTransfer, s->cbIOBuffer);
    18971897
    18981898    if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
     
    19181918
    19191919    if (pProf) { STAM_PROFILE_ADV_START(pProf, b); }
    1920     if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
     1920    if (   cbTransfer > SCSI_MAX_BUFFER_SIZE
     1921        || s->cbElementaryTransfer > s->cbIOBuffer)
    19211922    {
    19221923        /* Linux accepts commands with up to 100KB of data, but expects
     
    19261927        uint32_t iATAPILBA, cSectors, cReqSectors, cbCurrTX;
    19271928        uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer);
     1929        uint32_t cSectorsMax; /**< Maximum amount of sectors to read without exceeding the I/O buffer. */
     1930
     1931        Assert(s->cbATAPISector);
     1932        cSectorsMax = cbTransfer / s->cbATAPISector;
     1933        Assert(cSectorsMax * s->cbATAPISector <= s->cbIOBuffer);
    19281934
    19291935        switch (s->aATAPICmd[0])
     
    19601966                return false;
    19611967        }
     1968        cSectorsMax = RT_MIN(cSectorsMax, cSectors);
    19621969        memcpy(aATAPICmd, s->aATAPICmd, ATAPI_PACKET_SIZE);
    19631970        cReqSectors = 0;
    1964         for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
     1971        for (uint32_t i = cSectorsMax; i > 0; i -= cReqSectors)
    19651972        {
    19661973            if (i * s->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
     
    19972004            pbBuf += s->cbATAPISector * cReqSectors;
    19982005        }
     2006
     2007        if (RT_SUCCESS(rc))
     2008        {
     2009            /* Adjust ATAPI command for the next call. */
     2010            switch (s->aATAPICmd[0])
     2011            {
     2012                case SCSI_READ_10:
     2013                case SCSI_WRITE_10:
     2014                case SCSI_WRITE_AND_VERIFY_10:
     2015                    ataH2BE_U32(s->aATAPICmd + 2, iATAPILBA);
     2016                    ataH2BE_U16(s->aATAPICmd + 7, cSectors - cSectorsMax);
     2017                    break;
     2018                case SCSI_READ_12:
     2019                case SCSI_WRITE_12:
     2020                    ataH2BE_U32(s->aATAPICmd + 2, iATAPILBA);
     2021                    ataH2BE_U32(s->aATAPICmd + 6, cSectors - cSectorsMax);
     2022                    break;
     2023                case SCSI_READ_CD:
     2024                    ataH2BE_U32(s->aATAPICmd + 2, iATAPILBA);
     2025                    ataH2BE_U24(s->aATAPICmd + 6, cSectors - cSectorsMax);
     2026                    break;
     2027                case SCSI_READ_CD_MSF:
     2028                    ataLBA2MSF(s->aATAPICmd + 3, iATAPILBA);
     2029                    ataLBA2MSF(s->aATAPICmd + 6, iATAPILBA + cSectors - cSectorsMax);
     2030                    break;
     2031                default:
     2032                    AssertMsgFailed(("Don't know how to split command %#04x\n", s->aATAPICmd[0]));
     2033                    if (s->cErrors++ < MAX_LOG_REL_ERRORS)
     2034                        LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough split error\n", s->iLUN));
     2035                    atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     2036                    return false;
     2037            }
     2038        }
    19992039    }
    20002040    else
     
    20262066        {
    20272067            Assert(cbTransfer <= s->cbTotalTransfer);
    2028             /* Reply with the same amount of data as the real drive. */
    2029             s->cbTotalTransfer = cbTransfer;
    2030             /* The initial buffer end value has been set up based on the total
    2031              * transfer size. But the I/O buffer size limits what can actually be
    2032              * done in one transfer, so set the actual value of the buffer end. */
    2033             s->cbElementaryTransfer = cbTransfer;
     2068            /*
     2069             * Reply with the same amount of data as the real drive
     2070             * but only if the command wasn't splitted.
     2071             */
     2072            if (s->cbElementaryTransfer < s->cbIOBuffer)
     2073                s->cbTotalTransfer = cbTransfer;
     2074
    20342075            if (s->aATAPICmd[0] == SCSI_INQUIRY)
    20352076            {
     
    20742115                Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
    20752116        }
    2076         s->iSourceSink = ATAFN_SS_NULL;
    2077         atapiCmdOK(s);
     2117
     2118        /* The initial buffer end value has been set up based on the total
     2119         * transfer size. But the I/O buffer size limits what can actually be
     2120         * done in one transfer, so set the actual value of the buffer end. */
     2121        s->cbElementaryTransfer = cbTransfer;
     2122        if (cbTransfer >= s->cbTotalTransfer)
     2123        {
     2124            s->iSourceSink = ATAFN_SS_NULL;
     2125            atapiCmdOK(s);
     2126        }
    20782127    }
    20792128    else
     
    35823631            break;
    35833632        sendcmd:
    3584             /* Send a command to the drive, passing data in/out as required. */
     3633            /*
     3634             * Send a command to the drive, passing data in/out as required.
     3635             * Commands which exceed the I/O buffer size are splitted below
     3636             * or aborted if splitting is not implemented.
     3637             */
    35853638            Log2(("ATAPI PT: max size %d\n", cbTransfer));
    3586             if (cbTransfer > s->cbIOBuffer)
    3587             {
    3588                 /* Rate limited logging, one log line every 5 seconds. */
    3589                 static uint64_t uLastLogTS = 0;
    3590                 if (RTTimeMilliTS() >= uLastLogTS + 5000)
    3591                 {
    3592                     LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to exceed buffer size, blocked\n", s->iLUN));
    3593                     uLastLogTS = RTTimeMilliTS();
    3594                 }
    3595                 atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    3596             }
    3597             else
    3598             {
    3599                 if (cbTransfer == 0)
    3600                     uTxDir = PDMBLOCKTXDIR_NONE;
    3601                 ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
    3602             }
     3639            if (cbTransfer == 0)
     3640                uTxDir = PDMBLOCKTXDIR_NONE;
     3641            ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
    36033642    }
    36043643}
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