Subject: Re: panic: wdc_exec_command
To: None <sigsegv@rambler.ru>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: port-sparc64
Date: 01/17/2005 15:00:31
--MGYHOYXEY6WxJCY8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Jan 17, 2005 at 01:15:03PM +0000, sigsegv@rambler.ru wrote:
> Manuel Bouyer wrote:
> >On Fri, Jan 14, 2005 at 06:39:19PM +0000, sigsegv@rambler.ru wrote:
> >
> >>Greetings, I built a kernel with various debugging options, this is from 
> >>netbsd-2-0 source tree which I downloaded last night. What I noticed was 
> >>adding 'options DIAGNOSTIC' causes kernel to panic on boot:
> >>
> >>panic: wdc_exec_command: polled command not done
> >>kdb breakpoint at 13ac460
> >>Stopped in pid 5.1 (atabus1) at netbsd:cpu_Debugger+0x4: nop
> >
> >
> >Hum, I though this issue couldn't happen on 2.0. Ca you get a stack trace
> >from here, to see from where this command comes from ?
> >
> 
> I can't, I don't have serial interface set up yet, and when this panic 
> happens the terminal and keyboard are unresponsive. I guess it's because 
> it happens at an early boot up stage :-/

Well, OK. I think I've found the cause of this. Can you try the attached
patch ? It's a back port of a similar change I did in current.

-- 
Manuel Bouyer <bouyer@antioche.eu.org>
     NetBSD: 26 ans d'experience feront toujours la difference
--

--MGYHOYXEY6WxJCY8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.wdc"

Index: ata/atavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
retrieving revision 1.40.2.2
diff -u -r1.40.2.2 atavar.h
--- ata/atavar.h	11 Aug 2004 19:44:05 -0000	1.40.2.2
+++ ata/atavar.h	17 Jan 2005 13:58:45 -0000
@@ -66,6 +66,9 @@
 #define	C_TIMEOU	0x0002		/* xfer processing timed out */
 #define	C_POLL		0x0004		/* command is polled */
 #define	C_DMA		0x0008		/* command uses DMA */
+#define	C_WAIT		0x0010		/* can use tsleep */
+#define	C_WAITACT	0x0020		/* wakeup when active */
+#define	C_FREE		0x0040		/* call wdc_free_xfer() asap */
 
 /* reasons for c_kill_xfer() */
 #define KILL_GONE 1 /* device is gone */
Index: ic/wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
retrieving revision 1.172.2.7
diff -u -r1.172.2.7 wdc.c
--- ic/wdc.c	17 Sep 2004 04:04:57 -0000	1.172.2.7
+++ ic/wdc.c	17 Jan 2005 13:58:45 -0000
@@ -873,6 +873,17 @@
 	if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
 		return; /* queue froozen */
 	}
+	/*
+	 * if someone is waiting for the command to be active, wake it up
+	 * and let it process the command
+	 */
+	if (xfer->c_flags & C_WAITACT) {
+		WDCDEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
+		    "wait active\n", xfer, chp->ch_channel, xfer->c_drive),
+		    DEBUG_XFERS);
+		wakeup(xfer);
+		return;
+	}
 #ifdef DIAGNOSTIC
 	if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0)
 		panic("wdcstart: channel waiting for irq");
@@ -1635,6 +1646,8 @@
 		wdc_c->flags |= AT_POLL;
 	if (wdc_c->flags & AT_POLL)
 		xfer->c_flags |= C_POLL;
+	if (wdc_c->flags & AT_WAIT)
+		xfer->c_flags |= C_WAIT;
 	xfer->c_drive = drvp->drive;
 	xfer->c_databuf = wdc_c->data;
 	xfer->c_bcount = wdc_c->bcount;
@@ -2016,6 +2029,20 @@
 	TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
 	WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n",
 	    chp->ch_flags), DEBUG_XFERS);
+	/*
+	 * if polling and can sleep, wait for the xfer to be at head of queue
+	 */
+	if ((xfer->c_flags & (C_POLL | C_WAIT)) ==  (C_POLL | C_WAIT)) {
+		while (TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {
+			xfer->c_flags |= C_WAITACT;
+			tsleep(xfer, PRIBIO, "ataact", 0);
+			xfer->c_flags &= ~C_WAITACT;
+			if (xfer->c_flags & C_FREE) {
+				wdc_free_xfer(chp, xfer);
+				return;
+			}
+		}
+	}
 	wdcstart(chp);
 }
 
@@ -2041,6 +2068,13 @@
 	struct wdc_softc *wdc = chp->ch_wdc;
 	int s;
 
+	if (xfer->c_flags & C_WAITACT) {
+		/* Someone is waiting for this xfer, so we can't free now */
+		xfer->c_flags |= C_FREE;
+		wakeup(xfer);
+		return;
+	}
+
 	if (wdc->cap & WDC_CAPABILITY_HWLOCK)
 		(*wdc->free_hw)(chp);
 	s = splbio();

--MGYHOYXEY6WxJCY8--