tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

ATA TRIM?



I'm trying to understand TRIM, such as is used on SSDs.

As a first step towards this, I'm trying to do a rudimentary backport
to a 5.2 derivative I'm using - nothing teaches a thing like
implementing it.  I found wd_trim() in 9.2's wd.c and had a stab at
integrating a form of it into my kernel.

It doesn't work, as you can probably infer from my writing this mail.
Userland issues the ioctl I'm using as aan early-stage API, printfs
indicate that my kernel code is running, and...it times out.

I'm writing to ask if there's anyone who knows TRIM well enough to have
a stab at telling what's wrong and is willing to try.

Anyone not interested in details can stop reading now without loss; the
rest of this mail details what I've done and what I got.  I've
presumably made some mistake somewhere, but it's not clear to me.

Here's the code I dropped into wdioctl(), adapted from 9.2's wd_trim().
I also lifted ataparams fields 129 through 208 from 9.2, including
things such as ATA_SUPPORT_DSM_TRIM.  (5.2 has all those fields as a
reserved [80] array.)

        case ATAIOCTRIM:
                         { unsigned char rq[512];
                           struct ata_command cmd;
                           int rv;
                           if (! (flag & FWRITE)) return(EBADF);
                           if (! (wd->sc_params.atap_ata_major & WDC_VER_ATA7))
                            { printf("ATAIOCTRIM: %s: not ATA-7\n",device_xname(wd->sc_dev));
                              return(EINVAL);
                            }
                           if (! (wd->sc_params.support_dsm & ATA_SUPPORT_DSM_TRIM))
                            { printf("ATAIOCTRIM: %s: has no TRIM support\n",device_xname(wd->sc_dev));
                              return(EINVAL);
                            }
                           bcopy(addr,&rq[0],8);
printf("TRIM %s: arg %02x %02x %02x %02x %02x %02x %02x %02x\n",
        device_xname(wd->sc_dev),
        rq[0], rq[1], rq[2], rq[3], rq[4], rq[5], rq[6], rq[7]);
                           bzero(&rq[8],512-8);
                           bzero(&cmd,sizeof(cmd)); // XXX API botch
                           cmd.r_command = ATA_DATA_SET_MANAGEMENT;
                           cmd.r_count = 1;
                           cmd.r_features = ATA_SUPPORT_DSM_TRIM;
                           cmd.r_st_bmask = WDCS_DRDY;
                           cmd.r_st_pmask = WDCS_DRDY;
                           cmd.timeout = 30000;
                           cmd.data = &rq[0];
                           cmd.bcount = 512;
                           cmd.flags |= AT_WRITE | AT_WAIT;
printf("TRIM %s: calling exec\n",device_xname(wd->sc_dev));
                           rv = wd->atabus->ata_exec_command(wd->drvp,&cmd);
printf("TRIM %s: returned %d\n",device_xname(wd->sc_dev),rv);
                           return(0);
                         }
                        break;

When I run my userland program, I get

[ - root] 3> date; ./trim /dev/rwd1d 4 2; date
Wed Dec  7 11:46:43 EST 2022
TRIM wd1: arg 04 00 00 00 00 00 02 00
TRIM wd1: calling exec
piixide1:0:1: lost interrupt
	type: ata tc_bcount: 512 tc_skip: 0
TRIM wd1: returned 1
ATAIOCTRIM workd
wd1: wd_flushcache: status=128<TIMEOU>
Wed Dec  7 11:47:43 EST 2022
[ - root] 4> 

1 is ATACMD_COMPLETE.  (The "ATAIOCTRIM workd" message is coming from
the userland program.)

Then attempting to read the drive times out but recovers:

[ - root] 4> dd if=/dev/rwd1d of=/dev/null bs=512 count=64
piixide1:0:1: wait timed out
wd1d: device timeout reading fsbn 0 (wd1 bn 0; cn 0 tn 0 sn 0), retrying
wd1: soft error (corrected)
64+0 records in
64+0 records out
32768 bytes transferred in 0.008 secs (4096000 bytes/sec)
[ - root] 5> 

Reading the device after that, I find the original contents are still
accessible up through (at least) sector 17, so the TRIM did not
actually work.

wd1 is a Kingston SATA SSD:

wd1 at atabus1 drive 1: <KINGSTON SA400S37120G>
wd1: drive supports 1-sector PIO transfers, LBA48 addressing
wd1: HPA enabled, no protected area
wd1: 111 GB, 232581 cyl, 16 head, 63 sec, 512 bytes/sect x 234441648 sectors
wd1: 32-bit data port
wd1: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 6 (Ultra/133)
wd1: non-rotational device
wd1(piixide1:0:1): using PIO mode 4, Ultra-DMA mode 6 (Ultra/133) (using DMA)

/~\ The ASCII				  Mouse
\ / Ribbon Campaign
 X  Against HTML		mouse%rodents-montreal.org@localhost
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Home | Main Index | Thread Index | Old Index