diff options
| author | bouyer <bouyer@NetBSD.org> | 2005-05-16 21:43:33 +0000 |
|---|---|---|
| committer | bouyer <bouyer@NetBSD.org> | 2005-05-16 21:43:33 +0000 |
| commit | eaa19a67b88686f14f908f6cb8de78f54c1e949b (patch) | |
| tree | 9e4daf69fcd7287ef3a368bf6193848b81594fc0 /sys/dev | |
| parent | d3f9123bd5382e8e3f42e003748a0e882c63f070 (diff) | |
Add a ata_queue_idle() function, which freeze a queue and tsleep() until the
controller is idle.
Change the powerhook function to call ata_queue_idle() on standby/suspend,
and ata_reset_channel() on resume (to wake up the disks and start from a
clean state).
Fix PR kern/30194 by Lubomir Sedlacik.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ata/ata.c | 52 | ||||
| -rw-r--r-- | sys/dev/ata/atavar.h | 6 |
2 files changed, 38 insertions, 20 deletions
diff --git a/sys/dev/ata/ata.c b/sys/dev/ata/ata.c index a5991d82c50..e6003992206 100644 --- a/sys/dev/ata/ata.c +++ b/sys/dev/ata/ata.c @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.67 2005/04/11 04:24:54 matt Exp $ */ +/* $NetBSD: ata.c,v 1.68 2005/05/16 21:43:33 bouyer Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.67 2005/04/11 04:24:54 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.68 2005/05/16 21:43:33 bouyer Exp $"); #ifndef ATADEBUG #define ATADEBUG @@ -158,6 +158,7 @@ ata_channel_attach(struct ata_channel *chp) TAILQ_INIT(&chp->ch_queue->queue_xfer); chp->ch_queue->queue_freeze = 0; + chp->ch_queue->queue_flags = 0; chp->ch_queue->active_xfer = NULL; chp->atabus = config_found(&chp->ch_atac->atac_dev, chp, atabusprint); @@ -322,11 +323,7 @@ atabus_thread(void *arg) splx(s); /* Configure the devices on the bus. */ - if (sc->sc_sleeping == 1) { - printf("%s: resuming...\n", sc->sc_dev.dv_xname); - sc->sc_sleeping = 0; - } else - atabusconfig(sc); + atabusconfig(sc); for (;;) { s = splbio(); @@ -430,7 +427,6 @@ atabus_attach(struct device *parent, struct device *self, void *aux) config_pending_incr(); kthread_create(atabus_create_thread, sc); - sc->sc_sleeping = 0; sc->sc_powerhook = powerhook_establish(atabus_powerhook, sc); if (sc->sc_powerhook == NULL) printf("%s: WARNING: unable to establish power hook\n", @@ -699,6 +695,22 @@ ata_dmaerr(struct ata_drive_datas *drvp, int flags) } /* + * freeze the queue and wait for the controller to be idle. Caller has to + * unfreeze/restart the queue + */ +void +ata_queue_idle(struct ata_queue *queue) +{ + int s = splbio(); + queue->queue_freeze++; + while (queue->active_xfer != NULL) { + queue->queue_flags |= QF_IDLE_WAIT; + tsleep(&queue->queue_flags, PRIBIO, "qidl", 0); + } + splx(s); +} + +/* * Add a command to the queue and start controller. * * MUST BE CALLED AT splbio()! @@ -772,7 +784,11 @@ atastart(struct ata_channel *chp) return; /* channel aleady active */ } if (__predict_false(chp->ch_queue->queue_freeze > 0)) { - return; /* queue froozen */ + if (chp->ch_queue->queue_flags & QF_IDLE_WAIT) { + chp->ch_queue->queue_flags &= ~QF_IDLE_WAIT; + wakeup(&chp->ch_queue->queue_flags); + } + return; /* queue frozen */ } /* * if someone is waiting for the command to be active, wake it up @@ -1422,17 +1438,17 @@ atabus_powerhook(int why, void *hdl) switch (why) { case PWR_SOFTSUSPEND: case PWR_SOFTSTANDBY: - sc->sc_sleeping = 1; - s = splbio(); - chp->ch_flags = ATACH_SHUTDOWN; - splx(s); - wakeup(&chp->ch_thread); - while (chp->ch_thread != NULL) - (void) tsleep((void *)&chp->ch_flags, PRIBIO, - "atadown", 0); + /* freeze the queue and wait for the controller to be idle */ + ata_queue_idle(chp->ch_queue); break; case PWR_RESUME: - atabus_create_thread(sc); + printf("%s: resuming...\n", sc->sc_dev.dv_xname); + s = splbio(); + KASSERT(chp->ch_queue->queue_freeze > 0); + /* unfreeze the queue and reset drives (to wake them up) */ + chp->ch_queue->queue_freeze--; + ata_reset_channel(chp, AT_WAIT); + splx(s); break; case PWR_SUSPEND: case PWR_STANDBY: diff --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h index 2466134329f..89de9408dd1 100644 --- a/sys/dev/ata/atavar.h +++ b/sys/dev/ata/atavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.67 2005/02/27 00:26:59 perry Exp $ */ +/* $NetBSD: atavar.h,v 1.68 2005/05/16 21:43:33 bouyer Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -88,6 +88,8 @@ struct ata_queue { TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */ int queue_freeze; /* freeze count for the queue */ struct ata_xfer *active_xfer; /* active command */ + int queue_flags; /* flags for this queue */ +#define QF_IDLE_WAIT 0x01 /* someone is wants the controller idle */ }; /* ATA bus instance state information. */ @@ -97,7 +99,6 @@ struct atabus_softc { int sc_flags; #define ATABUSCF_OPEN 0x01 void *sc_powerhook; - int sc_sleeping; }; /* @@ -441,6 +442,7 @@ int ata_downgrade_mode(struct ata_drive_datas *, int); void ata_probe_caps(struct ata_drive_datas *); void ata_dmaerr(struct ata_drive_datas *, int); +void ata_queue_idle(struct ata_queue *); #endif /* _KERNEL */ #endif /* _DEV_ATA_ATAVAR_H_ */ |
