Subject: Re: kern/30194: unrecoverable wd(4) error after suspend/resume
To: None <gnats-bugs@NetBSD.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: netbsd-bugs
Date: 05/16/2005 20:02:05
--17pEHd4RhPHOinZp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
> >Description:
> i am unable to resume from suspend with APM in the kernel. when resuming, the
> system comes up but disk seems to be hung immediately (sometimes the disk
> activity led is constantly on), processes hang in vnlock (sometimes in
> getblk). kernel prints error:
>
> atabus0: resuming...
> atabus1: resuming...
> wd0a: error writing fsbn 15042624 of 15042624-15042655 (wd0 bn 15042687; cn 14923 tn 4 sn 51), retrying
> wd0: (aborted command)
Hi,
can you try the attached patch ? I've not been able to reproduce your problem,
but the atabus power hook needs to be smarter than it is actually.
--
Manuel Bouyer <bouyer@antioche.eu.org>
NetBSD: 26 ans d'experience feront toujours la difference
--
--17pEHd4RhPHOinZp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff
Index: ata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata.c,v
retrieving revision 1.67
diff -u -r1.67 ata.c
--- ata.c 11 Apr 2005 04:24:54 -0000 1.67
+++ ata.c 16 May 2005 17:42:45 -0000
@@ -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,6 +784,10 @@
return; /* channel aleady active */
}
if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
+ if (queue->queue_flags & QF_IDLE_WAIT) {
+ queue->queue_flags &= ~QF_IDLE_WAIT;
+ wakeup(&queue->queue_flags);
+ }
return; /* queue froozen */
}
/*
@@ -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:
Index: atavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
retrieving revision 1.67
diff -u -r1.67 atavar.h
--- atavar.h 27 Feb 2005 00:26:59 -0000 1.67
+++ atavar.h 16 May 2005 17:42:45 -0000
@@ -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_ */
--17pEHd4RhPHOinZp--