VirtualBox

Changeset 38894 in vbox


Ignore:
Timestamp:
Sep 28, 2011 11:23:05 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
74217
Message:

DevATA,ATAController: Add TRIM support

Location:
trunk/src/VBox/Devices/Storage
Files:
3 edited

Legend:

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

    r38838 r38894  
    106106static bool ataWriteSectorsSS(AHCIATADevState *);
    107107static bool ataExecuteDeviceDiagnosticSS(AHCIATADevState *);
     108static bool ataTrimSS(AHCIATADevState *);
    108109static bool ataPacketSS(AHCIATADevState *);
    109110static bool atapiGetConfigurationSS(AHCIATADevState *);
     
    161162    ATAFN_SS_WRITE_SECTORS,
    162163    ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC,
     164    ATAFN_SS_TRIM,
    163165    ATAFN_SS_PACKET,
    164166    ATAFN_SS_ATAPI_GET_CONFIGURATION,
     
    193195    ataWriteSectorsSS,
    194196    ataExecuteDeviceDiagnosticSS,
     197    ataTrimSS,
    195198    ataPacketSS,
    196199    atapiGetConfigurationSS,
     
    740743    p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
    741744    p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
    742     p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
    743     p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
     745    if (s->pDrvBlock->pfnDiscard)
     746    {
     747        p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
     748        p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
     749    }
     750    else
     751    {
     752        p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
     753        p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
     754    }
    744755    p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management,  write cache and look-ahead */
    745756    if (s->cTotalSectors <= (1 << 28) - 1)
     
    763774        p[103] = RT_H2LE_U16(s->cTotalSectors >> 48);
    764775    }
     776    if (s->pDrvBlock->pfnDiscard) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
     777        p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
    765778    if (s->fNonRotational)
    766779        p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
     
    29842997
    29852998
     2999static int ataTrimSectors(AHCIATADevState *s, uint64_t u64Sector, uint32_t cSectors,
     3000                          bool *pfRedo)
     3001{
     3002    RTRANGE TrimRange;
     3003    PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
     3004    int rc;
     3005
     3006    PDMCritSectLeave(&pCtl->lock);
     3007
     3008    TrimRange.offStart = u64Sector * 512;
     3009    TrimRange.cbRange  = cSectors * 512;
     3010
     3011    s->pLed->Asserted.s.fWriting = s->pLed->Actual.s.fWriting = 1;
     3012    rc = s->pDrvBlock->pfnDiscard(s->pDrvBlock, &TrimRange, 1);
     3013    s->pLed->Actual.s.fWriting = 0;
     3014
     3015    if (RT_SUCCESS(rc))
     3016        *pfRedo = false;
     3017    else
     3018        *pfRedo = ataIsRedoSetWarning(s, rc);
     3019
     3020    STAM_PROFILE_START(&pCtl->StatLockWait, a);
     3021    PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
     3022    STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
     3023    return rc;
     3024}
     3025
     3026
     3027static bool ataTrimSS(AHCIATADevState *s)
     3028{
     3029    int rc;
     3030    uint32_t cRangesMax;
     3031    uint64_t *pu64Range = (uint64_t *)s->CTX_SUFF(pbIOBuffer);
     3032    bool fRedo;
     3033
     3034    cRangesMax = s->cbElementaryTransfer / sizeof(uint64_t);
     3035    Assert(cRangesMax);
     3036
     3037    while (cRangesMax-- > 0)
     3038    {
     3039        if (ATA_RANGE_LENGTH_GET(*pu64Range) == 0)
     3040            break;
     3041
     3042        rc = ataTrimSectors(s, *pu64Range & ATA_RANGE_LBA_MASK,
     3043                            ATA_RANGE_LENGTH_GET(*pu64Range), &fRedo);
     3044        if (RT_FAILURE(rc))
     3045            break;
     3046
     3047        pu64Range++;
     3048    }
     3049
     3050    if (RT_SUCCESS(rc))
     3051    {
     3052        s->iSourceSink = ATAFN_SS_NULL;
     3053        ataCmdOK(s, ATA_STAT_SEEK);
     3054    }
     3055    else
     3056    {
     3057        if (fRedo)
     3058            return fRedo;
     3059        if (s->cErrors++ < MAX_LOG_REL_ERRORS)
     3060            LogRel(("PIIX3 ATA: LUN#%d: disk trim error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
     3061                    s->iLUN, rc, *pu64Range & ATA_RANGE_LBA_MASK, ATA_RANGE_LENGTH_GET(*pu64Range)));
     3062
     3063        /*
     3064         * Check if we got interrupted. We don't need to set status variables
     3065         * because the request was aborted.
     3066         */
     3067        if (rc != VERR_INTERRUPTED)
     3068            ataCmdError(s, ID_ERR);
     3069    }
     3070
     3071    return false;
     3072}
     3073
     3074
    29863075static void ataParseCmd(AHCIATADevState *s, uint8_t cmd)
    29873076{
     
    32253314            ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
    32263315            break;
     3316        case ATA_DATA_SET_MANAGEMENT:
     3317            if (!s->pDrvBlock || !s->pDrvBlock->pfnDiscard)
     3318                goto abort_cmd;
     3319            if (   !(s->uATARegFeature & UINT8_C(0x01))
     3320                || (s->uATARegFeature & ~UINT8_C(0x01)))
     3321                goto abort_cmd;
     3322            s->fDMA = true;
     3323            ataStartTransfer(s, (s->uATARegNSectorHOB << 8 | s->uATARegNSector) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_NULL, ATAFN_SS_TRIM, false);
     3324            break;
    32273325        default:
    32283326        abort_cmd:
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r38838 r38894  
    572572static bool ataWriteSectorsSS(ATADevState *);
    573573static bool ataExecuteDeviceDiagnosticSS(ATADevState *);
     574static bool ataTrimSS(ATADevState *);
    574575static bool ataPacketSS(ATADevState *);
    575576static bool atapiGetConfigurationSS(ATADevState *);
     
    628629    ATAFN_SS_WRITE_SECTORS,
    629630    ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC,
     631    ATAFN_SS_TRIM,
    630632    ATAFN_SS_PACKET,
    631633    ATAFN_SS_ATAPI_GET_CONFIGURATION,
     
    661663    ataWriteSectorsSS,
    662664    ataExecuteDeviceDiagnosticSS,
     665    ataTrimSS,
    663666    ataPacketSS,
    664667    atapiGetConfigurationSS,
     
    12171220    p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
    12181221    p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
    1219     p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
    1220     p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
     1222    if (s->pDrvBlock->pfnDiscard)
     1223    {
     1224        p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
     1225        p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
     1226    }
     1227    else
     1228    {
     1229        p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
     1230        p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
     1231    }
    12211232    p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management,  write cache and look-ahead */
    12221233    if (s->cTotalSectors <= (1 << 28) - 1)
     
    12401251        p[103] = RT_H2LE_U16(s->cTotalSectors >> 48);
    12411252    }
     1253    if (s->pDrvBlock->pfnDiscard) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
     1254        p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
    12421255    if (s->fNonRotational)
    12431256        p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
     
    37353748        ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_SEEK);
    37363749    s->uATARegError = 0x01;
     3750    return false;
     3751}
     3752
     3753
     3754static int ataTrimSectors(ATADevState *s, uint64_t u64Sector, uint32_t cSectors,
     3755                          bool *pfRedo)
     3756{
     3757    RTRANGE TrimRange;
     3758    PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
     3759    int rc;
     3760
     3761    PDMCritSectLeave(&pCtl->lock);
     3762
     3763    TrimRange.offStart = u64Sector * 512;
     3764    TrimRange.cbRange  = cSectors * 512;
     3765
     3766    s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
     3767    rc = s->pDrvBlock->pfnDiscard(s->pDrvBlock, &TrimRange, 1);
     3768    s->Led.Actual.s.fWriting = 0;
     3769
     3770    if (RT_SUCCESS(rc))
     3771        *pfRedo = false;
     3772    else
     3773        *pfRedo = ataIsRedoSetWarning(s, rc);
     3774
     3775    STAM_PROFILE_START(&pCtl->StatLockWait, a);
     3776    PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
     3777    STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
     3778    return rc;
     3779}
     3780
     3781
     3782static bool ataTrimSS(ATADevState *s)
     3783{
     3784    int rc;
     3785    uint32_t cRangesMax;
     3786    uint64_t *pu64Range = (uint64_t *)s->CTX_SUFF(pbIOBuffer);
     3787    bool fRedo;
     3788
     3789    cRangesMax = s->cbElementaryTransfer / sizeof(uint64_t);
     3790    Assert(cRangesMax);
     3791
     3792    while (cRangesMax-- > 0)
     3793    {
     3794        if (ATA_RANGE_LENGTH_GET(*pu64Range) == 0)
     3795            break;
     3796
     3797        rc = ataTrimSectors(s, *pu64Range & ATA_RANGE_LBA_MASK,
     3798                            ATA_RANGE_LENGTH_GET(*pu64Range), &fRedo);
     3799        if (RT_FAILURE(rc))
     3800            break;
     3801
     3802        pu64Range++;
     3803    }
     3804
     3805    if (RT_SUCCESS(rc))
     3806    {
     3807        s->iSourceSink = ATAFN_SS_NULL;
     3808        ataCmdOK(s, ATA_STAT_SEEK);
     3809    }
     3810    else
     3811    {
     3812        if (fRedo)
     3813            return fRedo;
     3814        if (s->cErrors++ < MAX_LOG_REL_ERRORS)
     3815            LogRel(("PIIX3 ATA: LUN#%d: disk trim error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
     3816                    s->iLUN, rc, *pu64Range & ATA_RANGE_LBA_MASK, ATA_RANGE_LENGTH_GET(*pu64Range)));
     3817
     3818        /*
     3819         * Check if we got interrupted. We don't need to set status variables
     3820         * because the request was aborted.
     3821         */
     3822        if (rc != VERR_INTERRUPTED)
     3823            ataCmdError(s, ID_ERR);
     3824    }
     3825
    37373826    return false;
    37383827}
     
    39924081            ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
    39934082            break;
     4083        case ATA_DATA_SET_MANAGEMENT:
     4084            if (!s->pDrvBlock || !s->pDrvBlock->pfnDiscard)
     4085                goto abort_cmd;
     4086            if (   !(s->uATARegFeature & UINT8_C(0x01))
     4087                || (s->uATARegFeature & ~UINT8_C(0x01)))
     4088                goto abort_cmd;
     4089            s->fDMA = true;
     4090            ataStartTransfer(s, (s->uATARegNSectorHOB << 8 | s->uATARegNSector) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_NULL, ATAFN_SS_TRIM, false);
     4091            break;
    39944092        default:
    39954093        abort_cmd:
     
    61356233        }
    61366234        LogRel(("PIIX3 ATA: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n", pIf->iLUN, pIf->PCHSGeometry.cCylinders, pIf->PCHSGeometry.cHeads, pIf->PCHSGeometry.cSectors, pIf->cTotalSectors));
     6235
     6236        if (pIf->pDrvBlock->pfnDiscard)
     6237            LogRel(("PIIX3 ATA: LUN#%d: TRIM enabled\n", pIf->iLUN));
    61376238    }
    61386239    return rc;
  • trunk/src/VBox/Devices/Storage/ide.h

    r38622 r38894  
    176176#define ATA_MODEL_NUMBER_LENGTH         40
    177177
     178/** Mask to get the LBA value from a LBA range. */
     179#define ATA_RANGE_LBA_MASK    UINT64_C(0xffffffffffff)
     180/** Mas to get the length value from a LBA range. */
     181#define ATA_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
     182/** Returns the length of the range in sectors. */
     183#define ATA_RANGE_LENGTH_GET(val) (((val) & ATA_RANGE_LENGTH_MASK) >> 48)
    178184
    179185/* ATAPI defines */
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