Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ata Add a ata_queue_idle() function, which freeze a ...



details:   https://anonhg.NetBSD.org/src/rev/706a357309c6
branches:  trunk
changeset: 580948:706a357309c6
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon May 16 21:43:33 2005 +0000

description:
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:

 sys/dev/ata/ata.c    |  52 ++++++++++++++++++++++++++++++++++------------------
 sys/dev/ata/atavar.h |   6 ++++--
 2 files changed, 38 insertions(+), 20 deletions(-)

diffs (144 lines):

diff -r 315022568cc0 -r 706a357309c6 sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Mon May 16 21:35:32 2005 +0000
+++ b/sys/dev/ata/ata.c Mon May 16 21:43:33 2005 +0000
@@ -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 @@
 
        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 @@
        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 @@
        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 @@
 }
 
 /*
+ * 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 @@
                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 @@
        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 -r 315022568cc0 -r 706a357309c6 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Mon May 16 21:35:32 2005 +0000
+++ b/sys/dev/ata/atavar.h      Mon May 16 21:43:33 2005 +0000
@@ -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 @@
        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 @@
        int sc_flags;
 #define ATABUSCF_OPEN  0x01
        void *sc_powerhook;
-       int sc_sleeping;
 };
 
 /*
@@ -441,6 +442,7 @@
 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_ */



Home | Main Index | Thread Index | Old Index