diff options
author | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-20 13:42:06 +0000 |
---|---|---|
committer | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-20 13:42:06 +0000 |
commit | f22b33ab273d85cd1598cb7ec0056071f5b00ec1 (patch) | |
tree | c46aa4679c32493487b00a151ab8ff24ab8fac59 /sys | |
parent | 10a47ab5a309ab1fb33a49eaff8da0f0ed310676 (diff) |
Basic FLUSH CACHE support.
Note that the ATA spec says we're should retry after error until we see no
more errors. This is not (yet) implemented.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ata/atascsi.c | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c index 4f692795e3d..8386ed92b01 100644 --- a/sys/dev/ata/atascsi.c +++ b/sys/dev/ata/atascsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: atascsi.c,v 1.27 2007/03/20 13:01:04 pascoe Exp $ */ +/* $OpenBSD: atascsi.c,v 1.28 2007/03/20 13:42:05 pascoe Exp $ */ /* * Copyright (c) 2007 David Gwynne <dlg@openbsd.org> @@ -72,6 +72,7 @@ void atascsi_disk_inq_done(struct ata_xfer *); int atascsi_disk_capacity(struct scsi_xfer *); void atascsi_disk_capacity_done(struct ata_xfer *); int atascsi_disk_sync(struct scsi_xfer *); +void atascsi_disk_sync_done(struct ata_xfer *); int atascsi_disk_sense(struct scsi_xfer *); int atascsi_atapi_cmd(struct scsi_xfer *); @@ -441,7 +442,59 @@ atascsi_disk_inq_done(struct ata_xfer *xa) int atascsi_disk_sync(struct scsi_xfer *xs) { - return (atascsi_stuffup(xs)); + struct scsi_link *link = xs->sc_link; + struct atascsi *as = link->adapter_softc; + struct ata_port *ap = as->as_ports[link->target]; + struct ata_xfer *xa; + int s; + + s = splbio(); + xa = ata_get_xfer(ap, xs->flags & SCSI_NOSLEEP); + splx(s); + if (xa == NULL) + return (NO_CCB); + + xa->datalen = 0; + xa->flags = ATA_F_READ; + if (xs->flags & SCSI_POLL) + xa->flags |= ATA_F_POLL; + xa->complete = atascsi_disk_sync_done; + + /* Spec says flush cache can take >30 sec, so give it at least 45. */ + xa->timeout = (xs->timeout < 45000) ? 45000 : xs->timeout; + + xa->cmd.tx->regs[H2D_DEVCTL_OR_COMMAND] = + H2D_DEVCTL_OR_COMMAND_COMMAND; + xa->cmd.tx->regs[H2D_COMMAND] = ATA_C_FLUSH_CACHE; + + return (ata_exec(as, xa)); +} + +void +atascsi_disk_sync_done(struct ata_xfer *xa) +{ + struct scsi_xfer *xs = xa->atascsi_private; + + switch (xa->state) { + case ATA_S_COMPLETE: + xs->error = XS_NOERROR; + break; + + case ATA_S_ERROR: + case ATA_S_TIMEOUT: + xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT : + XS_DRIVER_STUFFUP); + break; + + default: + panic("atascsi_disk_sync_done: unexpected ata_xfer state (%d)", + xa->state); + } + + ata_put_xfer(xa); + + xs->flags |= ITSDONE; + scsi_done(xs); } int |