CFT: TRIM Consolodation on UFS/FFS filesystems

Mark Millard marklmi at
Sun Sep 9 21:00:08 UTC 2018

[I looked up the e.MMC 4.41 information: TRIM was optional back
then. TRIM and DISCARD are Mandatory in e.MMC 4.51 . Also It
looks to me like microsd{hc,xc} cards do not use 
EXT_CSD_INAND_CMD38_TRIM in FreeBSD, instead using

On 2018-Sep-8, at 2:32 AM, Mark Millard <marklmi at> wrote:

> On 2018-Sep-8, at 1:36 AM, Mark Millard <marklmi at> wrote:
>> Just an FYI.
>> I figured out a hack that allows the e.MMC on a microsd card
>> adapter to be used to boot and operate the Pine64+ 2GB, in
>> DDR52 mode at that. (And so shows what was missing in the
>> FreeBSD operation even if the code change is not the
>> proper form of an official fix.)
>> But in the process I discovered that FreeBSD is using
>> (for e.MMC in this tested context):
>> mmc0: REQUEST: CMD38 arg 0x1 flags 0x1d
>> That "0x1" means: TRIM that forces reads of zeros: the true
>> Data Removal command for mmc protocol, a form of erase. 0x3
>> would be DISCARD, the "performance command" that does not
>> guarantee what would be read afterwards: no erase required.
>> TRIM is older (added in e/MCC 4.4). DISCARD is newer (added
>> in e.MMC 4.5). Each is mandatory when the version has the
>> function at all.

I looked up the e.MMC 4.41 information: TRIM was optional back
then. TRIM and DISCARD are Mandatory in e.MMC 4.51 .

Sorry for the error.

>> Does FreeBSD have a policy of preferring erasure when
>> there is also the option to not require it?
> I looked up published SD card material and that command
> set encodes differently for the argument:
> 0x1 is DISCARD (also not requiring an erase)
> 0x2 is FULE when start LBA=LBA0 and end LBA=MaxLBA.
> Otherwise it is ERASE.
> (FreeBSD's mmcsd_delete uses 0x0 for ERASE selection.)
> (I ignore handling violations of start LBA <= end LBA <= Max LBA
> or out of order command sequences. FULE: Full User Area Logical
> Erase.)
> It looks like FreeBSD uses mmcsd_delete for both SD and e.MMC
> and it is coded for SD to be more optimal (DISCARD), not
> differentiating e.MMC from SD for argument values to use.
> In e.MMC 4.5+ 0x2 is a "discard enable" bit in the argument,
> and never a FULE or other such.
> In e.MMC the 0x0 case for CMD38's argument is for performing
> an erase on erase group(s) instead of sector(s).
> (I'm not describing Secure Request or Force Garbage Collect
> being 0x1 for e.MMC: apparently unused by mmcsd_delete .)

[I'll note that on the e.MMC fsck_ffs -E with around 60 GiBytes
of free space, gstat -pd shows it taking a long time doing
deletes for the e.MMC that I have.]

It looks to me like microsd{hc,xc} cards and SD cards in
general do not use EXT_CSD_INAND_CMD38_TRIM. I say that
because . . .

Earlier I looked at what the CMD38 command encoding covered.
But that need not mean that TRIM is always used. So I looked
into that as well.

Example code uses MMCSD_USE_TRIM is:

        use_trim = sc->flags & MMCSD_USE_TRIM;
. . .
        if ((sc->flags & MMCSD_INAND_CMD38) != 0) {
                err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL,
                    EXT_CSD_INAND_CMD38, use_trim == true ?
                    sc->cmd6_time, true);
. . .

But the sc->flags bit involved is based on the mmcsd_attach's:

static int
mmcsd_attach(device_t dev)
        device_t mmcbus;
        struct mmcsd_softc *sc;
        const uint8_t *ext_csd;
        off_t erase_size, sector_size, size, wp_size;
        uintmax_t bytes;
        int err, i;
        uint32_t quirks;
        uint8_t rev;
        bool comp, ro;
        char unit[2];
        sc = device_get_softc(dev);
        sc->dev = dev;
        sc->mmcbus = mmcbus = device_get_parent(dev);
        sc->mode = mmc_get_card_type(dev);
         * Note that in principle with an SDHCI-like re-tuning implementation,
         * the maximum data size can change at runtime due to a device removal/
         * insertion that results in switches to/from a transfer mode involving
         * re-tuning, iff there are multiple devices on a given bus.  Until now
         * mmc(4) lacks support for rescanning already attached buses, however,
         * and sdhci(4) to date has no support for shared buses in the first
         * place either.
        sc->max_data = mmc_get_max_data(dev);
        sc->high_cap = mmc_get_high_cap(dev);
        sc->rca = mmc_get_rca(dev);
        sc->cmd6_time = mmc_get_cmd6_timeout(dev);
        quirks = mmc_get_quirks(dev);

        /* Only MMC >= 4.x devices support EXT_CSD. */
        if (mmc_get_spec_vers(dev) >= 4) {
                MMCBUS_ACQUIRE_BUS(mmcbus, dev);
                err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd);
                MMCBUS_RELEASE_BUS(mmcbus, dev);
                if (err != MMC_ERR_NONE) {
                        device_printf(dev, "Error reading EXT_CSD %s\n",
                        return (ENXIO);
        ext_csd = sc->ext_csd;

        if ((quirks & MMC_QUIRK_INAND_CMD38) != 0) {
                if (mmc_get_spec_vers(dev) < 4) {
                            "MMC_QUIRK_INAND_CMD38 set but no EXT_CSD\n");
                        return (EINVAL);
                sc->flags |= MMCSD_INAND_CMD38;

         * EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN denotes support for both
         * insecure and secure TRIM.
        if ((ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] &
            (quirks & MMC_QUIRK_BROKEN_TRIM) == 0) {
                if (bootverbose)
                        device_printf(dev, "taking advantage of TRIM\n");
                sc->flags |= MMCSD_USE_TRIM;
                sc->erase_sector = 1;
        } else
                sc->erase_sector = mmc_get_erase_sector(dev);
. . .

microsd{hc,xc} cards do not have EXT_CSD and so would not appear
to ever assign sc->flags |= MMCSD_USE_TRIM . [mmc_send_ext_csd
establishes a zero'd area when the operation fails. For SD cards
CMD8 is only valid for the Idle state, which is not the
context here from what I can tell.]

So I get that EXT_CSD_INAND_CMD38_TRIM is only used for
e.MMC, not (micro)SD{hc,xc} cards.

This means my earlier microsdxc card testing was not testing what
I thought it was: instead testing EXT_CSD_INAND_CMD38_ERASE use.

Mark Millard
marklmi at
( went
away in early 2018-Mar)

More information about the freebsd-fs mailing list