summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/ata/ata_da.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 7418e1e..f918956 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -115,10 +115,11 @@ struct disk_params {
};
#define TRIM_MAX_BLOCKS 4
-#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64
+#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64)
+#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 8)
struct trim_request {
uint8_t data[TRIM_MAX_RANGES * 8];
- struct bio *bps[TRIM_MAX_RANGES];
+ struct bio *bps[TRIM_MAX_BIOS];
};
struct ada_softc {
@@ -1067,7 +1068,8 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
(bp = bioq_first(&softc->trim_queue)) != 0) {
struct trim_request *req = &softc->trim_req;
struct bio *bp1;
- int bps = 0, ranges = 0;
+ uint64_t lastlba = (uint64_t)-1;
+ int bps = 0, c, lastcount = 0, off, ranges = 0;
softc->trim_running = 1;
bzero(req, sizeof(*req));
@@ -1078,10 +1080,22 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
softc->params.secsize;
bioq_remove(&softc->trim_queue, bp1);
- while (count > 0) {
- int c = min(count, 0xffff);
- int off = ranges * 8;
+ /* Try to extend the previous range. */
+ if (lba == lastlba) {
+ c = min(count, 0xffff - lastcount);
+ lastcount += c;
+ off = (ranges - 1) * 8;
+ req->data[off + 6] = lastcount & 0xff;
+ req->data[off + 7] =
+ (lastcount >> 8) & 0xff;
+ count -= c;
+ lba += c;
+ }
+
+ while (count > 0) {
+ c = min(count, 0xffff);
+ off = ranges * 8;
req->data[off + 0] = lba & 0xff;
req->data[off + 1] = (lba >> 8) & 0xff;
req->data[off + 2] = (lba >> 16) & 0xff;
@@ -1092,11 +1106,14 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
req->data[off + 7] = (c >> 8) & 0xff;
lba += c;
count -= c;
+ lastcount = c;
ranges++;
}
+ lastlba = lba;
req->bps[bps++] = bp1;
bp1 = bioq_first(&softc->trim_queue);
- if (bp1 == NULL ||
+ if (bps >= TRIM_MAX_BIOS ||
+ bp1 == NULL ||
bp1->bio_bcount / softc->params.secsize >
(softc->trim_max_ranges - ranges) * 0xffff)
break;
@@ -1370,8 +1387,7 @@ adadone(struct cam_periph *periph, union ccb *done_ccb)
(struct trim_request *)ataio->data_ptr;
int i;
- for (i = 1; i < softc->trim_max_ranges &&
- req->bps[i]; i++) {
+ for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) {
struct bio *bp1 = req->bps[i];
bp1->bio_resid = bp->bio_resid;
OpenPOWER on IntegriCloud