diff options
author | pjd <pjd@FreeBSD.org> | 2006-10-31 21:19:25 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2006-10-31 21:19:25 +0000 |
commit | 4ed49f81f813686d8a7faf0c75dc006bb0632cf8 (patch) | |
tree | e7596b419a359a5488cd4aa3c109c1d642056b40 | |
parent | 67c00d09c15829fc438fdaf3ed5b6bb694301114 (diff) | |
download | FreeBSD-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
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 45 | ||||
-rw-r--r-- | sys/dev/amr/amr.c | 31 | ||||
-rw-r--r-- | sys/dev/amr/amr_disk.c | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 13 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.c | 69 |
5 files changed, 135 insertions, 25 deletions
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index e5dc32d..fc3692b 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -1179,6 +1179,8 @@ daregister(struct cam_periph *periph, void *arg) softc->disk->d_maxsize = DFLTPHYS; /* XXX: probably not arbitrary */ softc->disk->d_unit = periph->unit_number; softc->disk->d_flags = DISKFLAG_NEEDSGIANT; + if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) + softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; disk_create(softc->disk, DISK_VERSION); /* @@ -1250,20 +1252,35 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) } else { tag_code = MSG_SIMPLE_Q_TAG; } - scsi_read_write(&start_ccb->csio, - /*retries*/da_retry_count, - /*cbfcnp*/dadone, - /*tag_action*/tag_code, - /*read_op*/bp->bio_cmd == BIO_READ, - /*byte2*/0, - softc->minimum_cmd_size, - /*lba*/bp->bio_pblkno, - /*block_count*/bp->bio_bcount / - softc->params.secsize, - /*data_ptr*/ bp->bio_data, - /*dxfer_len*/ bp->bio_bcount, - /*sense_len*/SSD_FULL_SIZE, - /*timeout*/da_default_timeout*1000); + switch (bp->bio_cmd) { + case BIO_READ: + case BIO_WRITE: + scsi_read_write(&start_ccb->csio, + /*retries*/da_retry_count, + /*cbfcnp*/dadone, + /*tag_action*/tag_code, + /*read_op*/bp->bio_cmd == BIO_READ, + /*byte2*/0, + softc->minimum_cmd_size, + /*lba*/bp->bio_pblkno, + /*block_count*/bp->bio_bcount / + softc->params.secsize, + /*data_ptr*/ bp->bio_data, + /*dxfer_len*/ bp->bio_bcount, + /*sense_len*/SSD_FULL_SIZE, + /*timeout*/da_default_timeout*1000); + break; + case BIO_FLUSH: + scsi_synchronize_cache(&start_ccb->csio, + /*retries*/1, + /*cbfcnp*/dadone, + MSG_SIMPLE_Q_TAG, + /*begin_lba*/0,/* Cover the whole disk */ + /*lb_count*/0, + SSD_FULL_SIZE, + /*timeout*/da_default_timeout*1000); + break; + } start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO; /* diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c index 52db8fb..3681bae 100644 --- a/sys/dev/amr/amr.c +++ b/sys/dev/amr/amr.c @@ -1287,7 +1287,7 @@ amr_bio_command(struct amr_softc *sc, struct amr_command **acp) int driveno; int cmd; - ac = NULL; + *acp = NULL; error = 0; /* get a command */ @@ -1305,39 +1305,50 @@ amr_bio_command(struct amr_softc *sc, struct amr_command **acp) ac->ac_bio = bio; ac->ac_data = bio->bio_data; ac->ac_length = bio->bio_bcount; - if (bio->bio_cmd == BIO_READ) { + cmd = 0; + switch (bio->bio_cmd) { + case BIO_READ: ac->ac_flags |= AMR_CMD_DATAIN; if (AMR_IS_SG64(sc)) { cmd = AMR_CMD_LREAD64; ac->ac_flags |= AMR_CMD_SG64; } else cmd = AMR_CMD_LREAD; - } else { + break; + case BIO_WRITE: ac->ac_flags |= AMR_CMD_DATAOUT; if (AMR_IS_SG64(sc)) { cmd = AMR_CMD_LWRITE64; ac->ac_flags |= AMR_CMD_SG64; } else cmd = AMR_CMD_LWRITE; + break; + case BIO_FLUSH: + ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; + cmd = AMR_CMD_FLUSH; + break; } amrd = (struct amrd_softc *)bio->bio_disk->d_drv1; driveno = amrd->amrd_drive - sc->amr_drive; blkcount = (bio->bio_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE; ac->ac_mailbox.mb_command = cmd; - ac->ac_mailbox.mb_blkcount = blkcount; - ac->ac_mailbox.mb_lba = bio->bio_pblkno; + if (bio->bio_cmd & (BIO_READ|BIO_WRITE)) { + ac->ac_mailbox.mb_blkcount = blkcount; + ac->ac_mailbox.mb_lba = bio->bio_pblkno; + if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size) { + device_printf(sc->amr_dev, + "I/O beyond end of unit (%lld,%d > %lu)\n", + (long long)bio->bio_pblkno, blkcount, + (u_long)sc->amr_drive[driveno].al_size); + } + } ac->ac_mailbox.mb_drive = driveno; if (sc->amr_state & AMR_STATE_REMAP_LD) ac->ac_mailbox.mb_drive |= 0x80; /* we fill in the s/g related data when the command is mapped */ - if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size) - device_printf(sc->amr_dev, "I/O beyond end of unit (%lld,%d > %lu)\n", - (long long)bio->bio_pblkno, blkcount, - (u_long)sc->amr_drive[driveno].al_size); - *acp = ac; return(error); } diff --git a/sys/dev/amr/amr_disk.c b/sys/dev/amr/amr_disk.c index 91b43c8..44e77c4 100644 --- a/sys/dev/amr/amr_disk.c +++ b/sys/dev/amr/amr_disk.c @@ -236,7 +236,7 @@ amrd_attach(device_t dev) sc->amrd_disk->d_name = "amrd"; sc->amrd_disk->d_dump = (dumper_t *)amrd_dump; sc->amrd_disk->d_unit = sc->amrd_unit; - sc->amrd_disk->d_flags = 0; + sc->amrd_disk->d_flags = DISKFLAG_CANFLUSHCACHE; sc->amrd_disk->d_sectorsize = AMR_BLKSIZE; sc->amrd_disk->d_mediasize = (off_t)sc->amrd_drive->al_size * AMR_BLKSIZE; sc->amrd_disk->d_fwsectors = sc->amrd_drive->al_sectors; 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; } |