Subject: IDE-doubler support (patch, testers wanted)
To: None <port-amiga@netbsd.org>
From: Ilpo Ruotsalainen <lonewolf@iki.fi>
List: port-amiga
Date: 01/13/2003 22:50:02
--cQXOx3fnlpmgJsTP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Attached is a patch to add support for 'standard' IDE-doublers to
NetBSD-current. Testers (both with IDE-doubler hardware and without) are
very much wanted, especially people with A4000s.

Please note that I don't know of a way to determine if IDE-doubler is
present or not on runtime - DO NOT TRY TO BOOT MISCONFIGURED KERNEL as
it will most probably hang, crash, burn and eat your breakfast.

Should probably add a boot flag to enable/disable this, as it would be
good if we could ship INSTALL/GENERIC kernels with the code in but
disabled by default. Of course if anyone can come up with a way to
determine if an IDE-doubler is present, that is even better.

There are some issues with this (because IDE-doubling on amiga is such
an *ugly* hack), I've seen my CD-ROM not get detected after a soft
reboot (probably left in somekinda interesting state and since we can't
reset the bus...).

I haven't really stresstested this more than checking that I can mount
CDs and md5sums match on the data read from CD, but I believe it should
work pretty reliably as long as you don't get a bus hang (we still can't
reset the bus).

Here's a dmesg for showoff purposes:

NetBSD 1.6L (FOOBAR) #0: Mon Jan 13 22:26:21 EET 2003
    lonewolf@omoikane.cs-intra.net:/scratch/nb/idedoubler/src/sys/arch/amiga/compile/FOOBAR
Amiga 1200 (68060 rev.1 CPU/MMU/FPU)
total memory = 65536 KB
avail memory = 59496 KB
using 422 buffers containing 3376 KB of memory
memory segment 0 at 78000000 size 04000000
memory segment 1 at 00000000 size 00200000
mainbus0 (root)
clock0 at mainbus0: CIA B system hz 100 hardware hz 709379
Calibrating delay loop... 21/1024 us
a2kbbc0 at mainbus0
ser0 at mainbus0: input fifo 512 output fifo 32
par0 at mainbus0
kbd0 at mainbus0: CIA A type Amiga
ms0 at mainbus0
grfcc0 at mainbus0
grf0 at grfcc0: width 640 height 400 colors 4
ite0 at grf0: rows 50 cols 80 repeat at (30/100)s next at (10/100)s has keyboard
fdc0 at mainbus0: dmabuf pa 0x1de874: dmabuf ka 0x8d98874
fd0 at fdc0 unit 0: 3.5dd 80 cyl, 2 head, 11 sec [9 sec], 512 bytes/sec
wdc0 at mainbus0: Gayle IDE (A1200 style) with IDE-doubler
wd0 at wdc0 channel 0 drive 0: <Maxtor 2B020H1>
wd0: drive supports 16-sector PIO transfers, LBA addressing
wd0: 19541 MB, 16383 cyl, 16 head, 63 sec, 512 bytes/sect x 40020624 sectors
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 5 (Ultra/100)
wdc0: unable to reset (no aux registers)
atapibus0 at wdc0 channel 1: 2 targets
cd0 at atapibus0 drive 1: <MEMOREX  CD-MAXX52, MT1198 B Firmware, MB1.0> cdrom removable
cd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 2 (Ultra/33)
wdc0: unable to reset (no aux registers)
zbus0 at mainbus0
bzivsc at zbus0: pa 0xea0000 man/pro 8512/17 not configured
4 views configured
root on wd0a dumps on wd0b
root file system type: ffs

-- 
Ilpo Ruotsalainen - <lonewolf@iki.fi> - http://www.iki.fi/lonewolf/

--cQXOx3fnlpmgJsTP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="idedoubler.patch"

Index: sys/dev/ic/wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
retrieving revision 1.120
diff --unified -r1.120 wdc.c
--- sys/dev/ic/wdc.c	2003/01/01 00:10:19	1.120
+++ sys/dev/ic/wdc.c	2003/01/13 20:36:05
@@ -228,29 +228,35 @@
 
 	if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
 		chp->wdc->select(chp,0);
-	/* assert SRST, wait for reset to complete */
-	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-	    WDSD_IBM);
-	delay(10);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-	    WDCTL_RST | WDCTL_IDS); 
-	DELAY(1000);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-	    WDCTL_IDS);
-	delay(1000);
-	(void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
-	delay(10);
-
-	ret_value = __wdcwait_reset(chp, ret_value);
-	WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
-	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
-	    ret_value), DEBUG_PROBE);
-
-	/* if reset failed, there's nothing here */
-	if (ret_value == 0)
-		return 0;
 
+	if (chp->wdc && ((chp->wdc->cap & WDC_CAPABILITY_NO_AUX) == 0))
+	{
+		/* assert SRST, wait for reset to complete */
+		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+				WDSD_IBM);
+		delay(10);
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+				WDCTL_RST | WDCTL_IDS); 
+		DELAY(1000);
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+				WDCTL_IDS);
+		delay(1000);
+		(void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+				WDCTL_4BIT);
+		delay(10);
+
+		ret_value = __wdcwait_reset(chp, ret_value);
+		WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
+				chp->wdc ? chp->wdc->sc_dev.dv_xname :
+				"wdcprobe",
+				chp->channel, ret_value), DEBUG_PROBE);
+
+		/* if reset failed, there's nothing here */
+		if (ret_value == 0)
+			return 0;
+	}
+
 	/*
 	 * Test presence of drives. First test register signatures looking for
 	 * ATAPI devices. If it's not an ATAPI and reset said there may be
@@ -759,6 +765,13 @@
 	int verb;
 {
 	int drv_mask1, drv_mask2;
+
+	if (chp->wdc->cap & WDC_CAPABILITY_NO_AUX)
+	{
+		printf("%s: unable to reset (no aux registers)\n",
+				chp->wdc->sc_dev.dv_xname);
+		return 1;
+	}
 
 	if (chp->wdc->cap & WDC_CAPABILITY_SELECT)
 		chp->wdc->select(chp,0);
Index: sys/dev/ic/wdcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdcvar.h,v
retrieving revision 1.34
diff --unified -r1.34 wdcvar.h
--- sys/dev/ic/wdcvar.h	2002/01/13 17:24:29	1.34
+++ sys/dev/ic/wdcvar.h	2003/01/13 20:36:05
@@ -103,6 +103,7 @@
 #define WDC_CAPABILITY_SINGLE_DRIVE 0x0800 /* Don't probe second drive */
 #define WDC_CAPABILITY_NOIRQ  0x1000	/* Controller never interrupts */
 #define WDC_CAPABILITY_SELECT  0x2000	/* Controller selects target */
+#define WDC_CAPABILITY_NO_AUX 0x4000	/* Controller doesn't have aux ports */
 	u_int8_t      PIO_cap; /* highest PIO mode supported */
 	u_int8_t      DMA_cap; /* highest DMA mode supported */
 	u_int8_t      UDMA_cap; /* highest UDMA mode supported */
Index: sys/arch/amiga/dev/wdc_amiga.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/dev/wdc_amiga.c,v
retrieving revision 1.10
diff --unified -r1.10 wdc_amiga.c
--- sys/arch/amiga/dev/wdc_amiga.c	2002/10/02 04:55:53	1.10
+++ sys/arch/amiga/dev/wdc_amiga.c	2003/01/13 20:36:05
@@ -59,14 +59,21 @@
 #include <dev/ata/atavar.h>
 #include <dev/ic/wdcvar.h>
 
+#include "opt_idedoubler.h"
+
+#ifdef IDEDOUBLER
+#define NUM_CHANNELS 2
+#else
+#define NUM_CHANNELS 1
+#endif
+
 struct wdc_amiga_softc {
-	struct wdc_softc sc_wdcdev;
-	struct	channel_softc *wdc_chanptr;
-	struct  channel_softc wdc_channel;
-	struct isr sc_isr;
+	struct	wdc_softc sc_wdcdev;
+	struct	channel_softc *wdc_chanptrs[NUM_CHANNELS];
+	struct  channel_softc wdc_channels[NUM_CHANNELS];
+	struct	isr sc_isr;
 	volatile u_char *sc_intreg;
-	struct bus_space_tag cmd_iot;
-	struct bus_space_tag ctl_iot;
+	struct	bus_space_tag sc_iot;
 	char	sc_a1200;
 };
 
@@ -89,51 +96,83 @@
 wdc_amiga_attach(struct device *parent, struct device *self, void *aux)
 {
 	struct wdc_amiga_softc *sc = (void *)self;
+	int i;
 
-	printf("\n");
+	printf(": Gayle IDE");
 
 	if (is_a4000()) {
-		sc->cmd_iot.base = (u_long)ztwomap(0xdd2020 + 2);
+		printf(" (A4000 style)");
+		sc->sc_iot.base = (u_long)ztwomap(0xdd2020 + 2);
 		sc->sc_intreg = (u_char *)ztwomap(0xdd2020 + 0x1000);
 		sc->sc_a1200 = 0;
 	} else {
-		sc->cmd_iot.base = (u_long) ztwomap(0xda0000 + 2);
-		sc->ctl_iot.base = (u_long) ztwomap(0xda4000);
+		printf(" (A1200 style)");
+		sc->sc_iot.base = (u_long) ztwomap(0xda0000 + 2);
 		gayle_init();
 		sc->sc_intreg = &gayle.intreq;
 		sc->sc_a1200 = 1;
 	}
-	sc->cmd_iot.absm = sc->ctl_iot.absm = &amiga_bus_stride_4swap;
-	sc->wdc_channel.cmd_iot = &sc->cmd_iot;
-	sc->wdc_channel.ctl_iot = &sc->ctl_iot;
-
-	if (bus_space_map(sc->wdc_channel.cmd_iot, 0, 0x40, 0,
-			  &sc->wdc_channel.cmd_ioh)) {
-		printf("%s: couldn't map registers\n",
-		    sc->sc_wdcdev.sc_dev.dv_xname);
+	sc->sc_iot.absm = &amiga_bus_stride_4swap;
+
+	if (bus_space_map(&sc->sc_iot,
+	      0, 0x40, 0, &sc->wdc_channels[0].cmd_ioh))
+	{
+		printf("%s: could not map registers\n",
+				sc->sc_wdcdev.sc_dev.dv_xname);
 		return;
 	}
 
-	if (sc->sc_a1200)
-		sc->wdc_channel.ctl_ioh = sc->ctl_iot.base;
-	else if (bus_space_subregion(sc->wdc_channel.cmd_iot,
-	    sc->wdc_channel.cmd_ioh, 0x406, 1, &sc->wdc_channel.ctl_ioh))
+#ifndef IDEDOUBLER
+	printf("\n");
+	
+	sc->wdc_channels[0].cmd_iot = sc->wdc_channels[0].ctl_iot = &sc->sc_iot;
+
+	if (bus_space_subregion(sc->wdc_channels[0].cmd_iot,
+				sc->wdc_channels[0].cmd_ioh,
+				0x406, 1, &sc->wdc_channels[0].ctl_ioh))
+	{
+		printf("%s: could not map registers\n",
+				sc->sc_wdcdev.sc_dev.dv_xname);
 		return;
+	}
 
 	sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16;
+#else
+	printf(" with IDE-doubler\n");
+
+	sc->wdc_channels[0].cmd_iot = sc->wdc_channels[1].cmd_iot = &sc->sc_iot;
+
+	if (bus_space_subregion(sc->wdc_channels[0].cmd_iot,
+				sc->wdc_channels[0].cmd_ioh,
+				0x400, 0x40, &sc->wdc_channels[1].cmd_ioh))
+	{
+		printf("%s: could not map registers\n",
+				sc->sc_wdcdev.sc_dev.dv_xname);
+		return;
+	}
+
+	sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_NO_AUX;
+#endif
+
 	sc->sc_wdcdev.PIO_cap = 0;
-	sc->wdc_chanptr = &sc->wdc_channel;
-	sc->sc_wdcdev.channels = &sc->wdc_chanptr;
-	sc->sc_wdcdev.nchannels = 1;
-	sc->wdc_channel.channel = 0;
-	sc->wdc_channel.wdc = &sc->sc_wdcdev;
-	sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
-	    M_DEVBUF, M_NOWAIT);
-	if (sc->wdc_channel.ch_queue == NULL) {
-	    printf("%s: can't allocate memory for command queue",
-		sc->sc_wdcdev.sc_dev.dv_xname);
-	    return;
+	sc->sc_wdcdev.channels = sc->wdc_chanptrs;
+	sc->sc_wdcdev.nchannels = NUM_CHANNELS;
+
+	for (i=0; i<NUM_CHANNELS; i++)
+	{
+		sc->wdc_channels[i].channel = i;
+		sc->wdc_channels[i].wdc = &sc->sc_wdcdev;
+		sc->wdc_channels[i].ch_queue = malloc(
+		    sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT);
+		if (sc->wdc_channels[i].ch_queue == NULL) {
+			printf("%s: can't allocate memory for command queue",
+					sc->sc_wdcdev.sc_dev.dv_xname);
+			return;
+		}
+
+		sc->wdc_chanptrs[i] = &sc->wdc_channels[i];
 	}
+
 	sc->sc_isr.isr_intr = wdc_amiga_intr;
 	sc->sc_isr.isr_arg = sc;
 	sc->sc_isr.isr_ipl = 2;
@@ -142,7 +181,8 @@
 	if (sc->sc_a1200)
 		gayle.intena |= GAYLE_INT_IDE;
 
-	wdcattach(&sc->wdc_channel);
+	for (i=0; i<NUM_CHANNELS; i++)
+		wdcattach(&sc->wdc_channels[i]);
 }
 
 int
@@ -150,12 +190,24 @@
 {
 	struct wdc_amiga_softc *sc = (struct wdc_amiga_softc *)arg;
 	u_char intreq = *sc->sc_intreg;
-	int ret = 0;
+	int i;
+	int ret = 0, chanret;
 
 	if (intreq & GAYLE_INT_IDE) {
 		if (sc->sc_a1200)
 			gayle.intreq = 0x7c | (intreq & 0x03);
-		ret = wdcintr(&sc->wdc_channel);
+
+		for (i=0; i<NUM_CHANNELS; i++)
+		{
+			chanret = wdcintr(&sc->wdc_channels[i]);
+
+			if (chanret == 0)
+				;
+			else if (chanret == 1)
+				ret = 1;
+			else if (ret == 0)
+				ret = chanret;
+		}
 	}
 
 	return ret;
Index: sys/arch/amiga/conf/files.amiga
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/conf/files.amiga,v
retrieving revision 1.127
diff --unified -r1.127 files.amiga
--- sys/arch/amiga/conf/files.amiga	2002/11/03 02:29:38	1.127
+++ sys/arch/amiga/conf/files.amiga	2003/01/13 20:36:06
@@ -29,6 +29,8 @@
 defflag				P5PPC68KBOARD
 defflag				LEV6_DEFER
 
+defflag				IDEDOUBLER
+
 defparam			IOBZCLOCK
 
 device	mainbus {}

--cQXOx3fnlpmgJsTP--