summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2006-10-31 21:19:25 +0000
committerpjd <pjd@FreeBSD.org>2006-10-31 21:19:25 +0000
commit4ed49f81f813686d8a7faf0c75dc006bb0632cf8 (patch)
treee7596b419a359a5488cd4aa3c109c1d642056b40 /sys/dev/ata
parent67c00d09c15829fc438fdaf3ed5b6bb694301114 (diff)
downloadFreeBSD-src-4ed49f81f813686d8a7faf0c75dc006bb0632cf8.zip
FreeBSD-src-4ed49f81f813686d8a7faf0c75dc006bb0632cf8.tar.gz
Implement BIO_FLUSH handling for da(4), amr(4), ata(4) and ataraid(4).
Sponsored by: home.pl
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-disk.c13
-rw-r--r--sys/dev/ata/ata-raid.c69
2 files changed, 82 insertions, 0 deletions
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index acdb37a..f82c098 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -159,6 +159,8 @@ ad_attach(device_t dev)
adp->disk->d_fwsectors = adp->sectors;
adp->disk->d_fwheads = adp->heads;
adp->disk->d_unit = device_get_unit(dev);
+ if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+ adp->disk->d_flags = DISKFLAG_CANFLUSHCACHE;
disk_create(adp->disk, DISK_VERSION);
device_add_child(dev, "subdisk", device_get_unit(dev));
ad_firmware_geom_adjust(dev, adp->disk);
@@ -269,6 +271,17 @@ ad_strategy(struct bio *bp)
else
request->u.ata.command = ATA_WRITE;
break;
+ case BIO_FLUSH:
+ request->u.ata.lba = 0;
+ request->u.ata.count = 0;
+ request->u.ata.feature = 0;
+ request->bytecount = 0;
+ request->transfersize = 0;
+ request->timeout = 1;
+ request->retries = 0;
+ request->flags = ATA_R_CONTROL;
+ request->u.ata.command = ATA_FLUSHCACHE;
+ break;
default:
device_printf(dev, "FAILURE - unknown BIO operation\n");
ata_free_request(request);
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c
index 78afd7b..7574cd2 100644
--- a/sys/dev/ata/ata-raid.c
+++ b/sys/dev/ata/ata-raid.c
@@ -146,6 +146,21 @@ ata_raid_attach(struct ar_softc *rdp, int writeback)
rdp->disk->d_maxsize = 128 * DEV_BSIZE;
rdp->disk->d_drv1 = rdp;
rdp->disk->d_unit = rdp->lun;
+ /* we support flushing cache if all components support it */
+ /* XXX: not all components can be connected at this point */
+ rdp->disk->d_flags = DISKFLAG_CANFLUSHCACHE;
+ for (disk = 0; disk < rdp->total_disks; disk++) {
+ struct ata_device *atadev;
+
+ if (rdp->disks[disk].dev == NULL)
+ continue;
+ if ((atadev = device_get_softc(rdp->disks[disk].dev)) == NULL)
+ continue;
+ if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+ continue;
+ rdp->disk->d_flags = 0;
+ break;
+ }
disk_create(rdp->disk, DISK_VERSION);
printf("ar%d: %juMB <%s %s%s> status: %s\n", rdp->lun,
@@ -229,6 +244,39 @@ ata_raid_ioctl(u_long cmd, caddr_t data)
return error;
}
+static int
+ata_raid_flush(struct bio *bp)
+{
+ struct ar_softc *rdp = bp->bio_disk->d_drv1;
+ struct ata_request *request;
+ device_t dev;
+ int disk, error;
+
+ error = 0;
+ bp->bio_pflags = 0;
+
+ for (disk = 0; disk < rdp->total_disks; disk++) {
+ if ((dev = rdp->disks[disk].dev) != NULL)
+ bp->bio_pflags++;
+ }
+ for (disk = 0; disk < rdp->total_disks; disk++) {
+ if ((dev = rdp->disks[disk].dev) == NULL)
+ continue;
+ if (!(request = ata_raid_init_request(rdp, bp)))
+ return ENOMEM;
+ request->dev = dev;
+ request->u.ata.command = ATA_FLUSHCACHE;
+ request->u.ata.lba = 0;
+ request->u.ata.count = 0;
+ request->u.ata.feature = 0;
+ request->timeout = 1;
+ request->retries = 0;
+ request->flags |= ATA_R_ORDERED | ATA_R_DIRECT;
+ ata_queue_request(request);
+ }
+ return 0;
+}
+
static void
ata_raid_strategy(struct bio *bp)
{
@@ -238,6 +286,15 @@ ata_raid_strategy(struct bio *bp)
u_int64_t blkno, lba, blk = 0;
int count, chunk, drv, par = 0, change = 0;
+ if (bp->bio_cmd == BIO_FLUSH) {
+ int error;
+
+ error = ata_raid_flush(bp);
+ if (error != 0)
+ biofinish(bp, NULL, error);
+ return;
+ }
+
if (!(rdp->status & AR_S_READY) ||
(bp->bio_cmd != BIO_READ && bp->bio_cmd != BIO_WRITE)) {
biofinish(bp, NULL, EIO);
@@ -554,6 +611,15 @@ ata_raid_done(struct ata_request *request)
struct bio *bp = request->bio;
int i, mirror, finished = 0;
+ if (bp->bio_cmd == BIO_FLUSH) {
+ if (bp->bio_error == 0)
+ bp->bio_error = request->result;
+ ata_free_request(request);
+ if (--bp->bio_pflags == 0)
+ biodone(bp);
+ return;
+ }
+
switch (rdp->type) {
case AR_T_JBOD:
case AR_T_SPAN:
@@ -3957,6 +4023,9 @@ ata_raid_init_request(struct ar_softc *rdp, struct bio *bio)
case BIO_WRITE:
request->flags = ATA_R_WRITE;
break;
+ case BIO_FLUSH:
+ request->flags = ATA_R_CONTROL;
+ break;
}
return request;
}
OpenPOWER on IntegriCloud