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.
This commit is contained in:
parent
d3f9123bd5
commit
eaa19a67b8
@ -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.
|
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
|
||||||
@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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
|
#ifndef ATADEBUG
|
||||||
#define ATADEBUG
|
#define ATADEBUG
|
||||||
@ -158,6 +158,7 @@ ata_channel_attach(struct ata_channel *chp)
|
|||||||
|
|
||||||
TAILQ_INIT(&chp->ch_queue->queue_xfer);
|
TAILQ_INIT(&chp->ch_queue->queue_xfer);
|
||||||
chp->ch_queue->queue_freeze = 0;
|
chp->ch_queue->queue_freeze = 0;
|
||||||
|
chp->ch_queue->queue_flags = 0;
|
||||||
chp->ch_queue->active_xfer = NULL;
|
chp->ch_queue->active_xfer = NULL;
|
||||||
|
|
||||||
chp->atabus = config_found(&chp->ch_atac->atac_dev, chp, atabusprint);
|
chp->atabus = config_found(&chp->ch_atac->atac_dev, chp, atabusprint);
|
||||||
@ -322,11 +323,7 @@ atabus_thread(void *arg)
|
|||||||
splx(s);
|
splx(s);
|
||||||
|
|
||||||
/* Configure the devices on the bus. */
|
/* Configure the devices on the bus. */
|
||||||
if (sc->sc_sleeping == 1) {
|
atabusconfig(sc);
|
||||||
printf("%s: resuming...\n", sc->sc_dev.dv_xname);
|
|
||||||
sc->sc_sleeping = 0;
|
|
||||||
} else
|
|
||||||
atabusconfig(sc);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
s = splbio();
|
s = splbio();
|
||||||
@ -430,7 +427,6 @@ atabus_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
config_pending_incr();
|
config_pending_incr();
|
||||||
kthread_create(atabus_create_thread, sc);
|
kthread_create(atabus_create_thread, sc);
|
||||||
|
|
||||||
sc->sc_sleeping = 0;
|
|
||||||
sc->sc_powerhook = powerhook_establish(atabus_powerhook, sc);
|
sc->sc_powerhook = powerhook_establish(atabus_powerhook, sc);
|
||||||
if (sc->sc_powerhook == NULL)
|
if (sc->sc_powerhook == NULL)
|
||||||
printf("%s: WARNING: unable to establish power hook\n",
|
printf("%s: WARNING: unable to establish power hook\n",
|
||||||
@ -698,6 +694,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.
|
* Add a command to the queue and start controller.
|
||||||
*
|
*
|
||||||
@ -772,7 +784,11 @@ atastart(struct ata_channel *chp)
|
|||||||
return; /* channel aleady active */
|
return; /* channel aleady active */
|
||||||
}
|
}
|
||||||
if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
|
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
|
* 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) {
|
switch (why) {
|
||||||
case PWR_SOFTSUSPEND:
|
case PWR_SOFTSUSPEND:
|
||||||
case PWR_SOFTSTANDBY:
|
case PWR_SOFTSTANDBY:
|
||||||
sc->sc_sleeping = 1;
|
/* freeze the queue and wait for the controller to be idle */
|
||||||
s = splbio();
|
ata_queue_idle(chp->ch_queue);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
case PWR_RESUME:
|
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;
|
break;
|
||||||
case PWR_SUSPEND:
|
case PWR_SUSPEND:
|
||||||
case PWR_STANDBY:
|
case PWR_STANDBY:
|
||||||
|
@ -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.
|
* Copyright (c) 1998, 2001 Manuel Bouyer.
|
||||||
@ -88,6 +88,8 @@ struct ata_queue {
|
|||||||
TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
|
TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
|
||||||
int queue_freeze; /* freeze count for the queue */
|
int queue_freeze; /* freeze count for the queue */
|
||||||
struct ata_xfer *active_xfer; /* active command */
|
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. */
|
/* ATA bus instance state information. */
|
||||||
@ -97,7 +99,6 @@ struct atabus_softc {
|
|||||||
int sc_flags;
|
int sc_flags;
|
||||||
#define ATABUSCF_OPEN 0x01
|
#define ATABUSCF_OPEN 0x01
|
||||||
void *sc_powerhook;
|
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_probe_caps(struct ata_drive_datas *);
|
||||||
|
|
||||||
void ata_dmaerr(struct ata_drive_datas *, int);
|
void ata_dmaerr(struct ata_drive_datas *, int);
|
||||||
|
void ata_queue_idle(struct ata_queue *);
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
#endif /* _DEV_ATA_ATAVAR_H_ */
|
#endif /* _DEV_ATA_ATAVAR_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user