Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 05 Sep 2002 11:40:39 +0900 (JST)
From:      Mitsuru IWASAKI <iwasaki@jp.FreeBSD.org>
To:        sos@freebsd.dk
Cc:        current@FreeBSD.org
Subject:   [PATCH] 'ata_dmasetup: transfer active on this device!' problem on resume
Message-ID:  <20020905.114039.10290552.iwasaki@jp.FreeBSD.org>

next in thread | raw e-mail | index | archive | help
Hi, Soren.  I got panics with 'ata_dmasetup: transfer active on this
device!' on resume, and have made patches for this.
Problem was that certain process is accessing ATA disk via DMA
transfer on suspend, however the transfer was not completed in most cases,
then ata_dmastart() (called by ata_reinit()) got panic on resume.

My patches will do those things during suspend time;
 - wait for DMA transfer completion if it is on the way.
 - cancel new requests (yes, it's possible even during suspend
   time) for ATA disks and remain them in ATA queue.

Could you review the patches and commit them if OK?

Thanks

Index: ata-all.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-all.c,v
retrieving revision 1.153
diff -u -r1.153 ata-all.c
--- ata-all.c	9 Aug 2002 20:51:53 -0000	1.153
+++ ata-all.c	4 Sep 2002 10:21:22 -0000
@@ -279,8 +279,46 @@
 }
 
 int
+ata_suspend(device_t dev)
+{
+    struct ata_channel *ch;
+
+    ch = device_get_softc(dev);
+
+#ifdef DEV_ATADISK
+    if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) {
+	ch->device[MASTER].suspended = 1;
+	if (ch->device[MASTER].mode >= ATA_DMA) {
+	    ata_waitdmadone(&ch->device[MASTER]);
+	}
+    }
+    if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver) {
+	ch->device[SLAVE].suspended = 1;
+	if (ch->device[SLAVE].mode >= ATA_DMA) {
+	    ata_waitdmadone(&ch->device[SLAVE]);
+	}
+    }
+#endif
+
+    return 0;
+}
+
+int
 ata_resume(device_t dev)
 {
+    struct ata_channel *ch;
+
+    ch = device_get_softc(dev);
+
+#ifdef DEV_ATADISK
+    if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) {
+	ch->device[MASTER].suspended = 0;
+    }
+    if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver) {
+	ch->device[SLAVE].suspended = 0;
+    }
+#endif
+
     return ata_reinit(device_get_softc(dev));
 }
 
@@ -674,6 +712,20 @@
 	    ad_start(&ch->device[MASTER]);
 	if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver)
 	    ad_start(&ch->device[SLAVE]);
+    }
+    if (ch->devices & (ATA_ATA_MASTER) && ch->device[MASTER].driver) {
+ 	if (ch->device[MASTER].suspended && ch->device[MASTER].mode >= ATA_DMA) {
+	    printf("%s: going to suspend, ignoring.\n", __func__);
+	    splx(s);
+	    return;
+	 }
+    }
+    if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) {
+ 	if (ch->device[SLAVE].suspended && ch->device[MASTER].mode >= ATA_DMA) {
+	    printf("%s: going to suspend, ignoring.\n", __func__);
+	    splx(s);
+	    return;
+	 }
     }
     if ((ad_request = TAILQ_FIRST(&ch->ata_queue))) {
 	TAILQ_REMOVE(&ch->ata_queue, ad_request, chain);
Index: ata-all.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-all.h,v
retrieving revision 1.53
diff -u -r1.53 ata-all.h
--- ata-all.h	18 Apr 2002 19:11:43 -0000	1.53
+++ ata-all.h	4 Sep 2002 06:25:24 -0000
@@ -189,6 +189,7 @@
     int				cmd;		/* last cmd executed */
     void			*result;	/* misc data */
     struct ata_dmastate		dmastate;	/* dma state */
+    int				suspended;	/* 0 = normal  1 = suspended */
 };
 
 /* structure describing an ATA channel */
@@ -252,6 +253,7 @@
 int ata_probe(device_t);
 int ata_attach(device_t);
 int ata_detach(device_t);
+int ata_suspend(device_t);
 int ata_resume(device_t);
 
 void ata_start(struct ata_channel *);
@@ -280,6 +282,7 @@
 int ata_dmasetup(struct ata_device *, caddr_t, int32_t);
 int ata_dmastart(struct ata_device *, caddr_t, int32_t, int);
 int ata_dmastatus(struct ata_channel *);
+void ata_waitdmadone(struct ata_device *);
 int ata_dmadone(struct ata_device *);
 
 /* macros for locking a channel */
Index: ata-dma.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-dma.c,v
retrieving revision 1.100
diff -u -r1.100 ata-dma.c
--- ata-dma.c	19 Jul 2002 22:14:54 -0000	1.100
+++ ata-dma.c	4 Sep 2002 11:15:50 -0000
@@ -31,6 +31,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/ata.h>
+#include <sys/kernel.h>
 #include <sys/bio.h>
 #include <sys/endian.h>
 #include <sys/malloc.h> 
@@ -1284,8 +1285,11 @@
     struct ata_dmastate *ds = &atadev->dmastate;
     struct ata_dmasetup_data_cb_args cba;
 
-    if (ds->flags & ATA_DS_ACTIVE)
-	    panic("ata_dmasetup: transfer active on this device!");
+    if (ds->flags & ATA_DS_ACTIVE) {
+	printf("ata_dmastart: transfer active on this device!\n");
+	Debugger("ata_dmastart");
+	return -1;
+    }
 
     cba.dmatab = ds->dmatab;
     bus_dmamap_sync(ds->cdmatag, ds->cdmamap, BUS_DMASYNC_PREWRITE);
@@ -1312,6 +1316,16 @@
     return 0;
 }
 
+void
+ata_waitdmadone(struct ata_device *atadev)
+{
+    if (atadev->dmastate.flags & ATA_DS_ACTIVE) {
+	printf("%s: waiting for ata_dmadone()\n", __func__);
+	tsleep(ata_dmadone, PRIBIO, "atawdma", 10 * hz);
+	printf("%s: done\n", __func__);
+    }
+}
+
 int
 ata_dmadone(struct ata_device *atadev)
 {
@@ -1332,6 +1346,7 @@
 	     error | ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
     ch->flags &= ~ATA_DMA_ACTIVE;
     ds->flags = 0;
+    wakeup((caddr_t)ata_dmadone);
     return (error & ATA_BMSTAT_MASK);
 }
 
Index: ata-pci.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-pci.c,v
retrieving revision 1.43
diff -u -r1.43 ata-pci.c
--- ata-pci.c	19 Jul 2002 22:14:54 -0000	1.43
+++ ata-pci.c	4 Sep 2002 04:01:35 -0000
@@ -856,6 +856,7 @@
     DEVMETHOD(device_probe,	ata_pcisub_probe),
     DEVMETHOD(device_attach,	ata_attach),
     DEVMETHOD(device_detach,	ata_detach),
+    DEVMETHOD(device_suspend,	ata_suspend),
     DEVMETHOD(device_resume,	ata_resume),
     { 0, 0 }
 };

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020905.114039.10290552.iwasaki>