Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Nov 2006 06:48:42 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 109776 for review
Message-ID:  <200611120648.kAC6mgUp004045@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=109776

Change 109776 by sam@sam_ebb on 2006/11/12 06:48:01

	Mostly working; channel attachs, interrupts work, and we fetch
	params but no drive yet:
	o add a private reset method that's a copy of ata_generic_reset
	  but interprets reset complete w/o an error as being ok
	o remap registers per the linux driver
	o add missing bus space methods for the stream versions of
	  read-multiple and write-multiple
	o mark channels 16-bit only and no slave (probably doesn't
	  matter w/ private reset method but there'll never be slaves)
	o remove debug printfs we don't need any more

Affected files ...

.. //depot/projects/arm/src/sys/arm/xscale/ixp425/avila_ata.c#7 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/xscale/ixp425/avila_ata.c#7 (text+ko) ====

@@ -122,7 +122,9 @@
 	sc->sc_expbus_tag.bs_r_2	= ata_bs_r_2,
 	/* read multiple */
 	sc->sc_expbus_tag.bs_rm_1	= ata_bs_rm_1,
+	sc->sc_expbus_tag.bs_rm_1_s	= ata_bs_rm_1,
 	sc->sc_expbus_tag.bs_rm_2	= ata_bs_rm_2,
+	sc->sc_expbus_tag.bs_rm_2_s	= ata_bs_rm_2,
 	/* write (single) */
 	sc->sc_expbus_tag.bs_w_1_s	= ata_bs_w_1,
 	sc->sc_expbus_tag.bs_w_2_s	= ata_bs_w_2,
@@ -130,7 +132,9 @@
 	sc->sc_expbus_tag.bs_w_2	= ata_bs_w_2,
 	/* write multiple */
 	sc->sc_expbus_tag.bs_wm_1	= ata_bs_wm_1,
+	sc->sc_expbus_tag.bs_wm_1_s	= ata_bs_wm_1,
 	sc->sc_expbus_tag.bs_wm_2	= ata_bs_wm_2,
+	sc->sc_expbus_tag.bs_wm_2_s	= ata_bs_wm_2,
 
 	rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
 	rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
@@ -274,13 +278,7 @@
 {
 	struct ata_avila_softc *sc = t;
 
-#if 0
 	return bus_space_read_1(sc->sc_iot, h, o);
-#else
-uint8_t v = bus_space_read_1(sc->sc_iot, h, o);
-printf("%s(%lx, %ld) => 0x%x\n", __func__, h, o, v);
-return v;
-#endif
 }
 
 void
@@ -288,7 +286,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %ld, 0x%x)\n", __func__, h, o, v);
 	bus_space_write_1(sc->sc_iot, h, o, v);
 }
 
@@ -298,7 +295,6 @@
 	struct ata_avila_softc *sc = t;
 	uint16_t v;
 
-printf("%s(%lx, %lu)\n", __func__, h, o);
 	enable_16(sc);
 	v = bus_space_read_2(sc->sc_iot, h, o);
 	disable_16(sc);
@@ -310,7 +306,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %lu, 0x%x)\n", __func__, h, o, v);
 	enable_16(sc);
 	bus_space_write_2(sc->sc_iot, h, o, v);
 	disable_16(sc);
@@ -322,7 +317,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %lu, %p, %lu)\n", __func__, h, o, d, c);
 	bus_space_read_multi_1(sc->sc_iot, h, o, d, c);
 }
 
@@ -332,7 +326,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %lu, %p, %lu)\n", __func__, h, o, d, c);
 	bus_space_write_multi_1(sc->sc_iot, h, o, d, c);
 }
 
@@ -342,7 +335,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %lu, %p, %lu)\n", __func__, h, o, d, c);
 	enable_16(sc);
 	bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
 	disable_16(sc);
@@ -354,7 +346,6 @@
 {
 	struct ata_avila_softc *sc = t;
 
-printf("%s(%lx, %lu, %p, %lu)\n", __func__, h, o, d, c);
 	enable_16(sc);
 	bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
 	disable_16(sc);
@@ -398,6 +389,7 @@
 	struct ata_channel *ch = device_get_softc(dev);
 
 	ch->unit = 0;
+	ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
 	device_set_desc_copy(dev, "ATA channel 0");
 
 	return ata_probe(dev);
@@ -410,27 +402,116 @@
 	struct ata_channel *ch = device_get_softc(dev);
 	int i;
 
-	/* registers up to ATA_STATUS map directly */
-	for (i = ATA_DATA; i <= ATA_STATUS; i++) {
+	for (i = 0; i < ATA_MAX_RES; i++)
 		ch->r_io[i].res = &sc->sc_ata;
-		ch->r_io[i].offset = i;
-	}
-	/* the control register is special */
-	ch->r_io[ATA_CONTROL].res = &sc->sc_ata;
+
+	ch->r_io[ATA_DATA].offset = ATA_DATA;
+	ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
+	ch->r_io[ATA_COUNT].offset = ATA_COUNT;
+	ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
+	ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
+	ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
+	ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
+	ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
+	ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
+	/* NB: should be used only for ATAPI devices */
+	ch->r_io[ATA_IREASON].offset = ATA_COUNT;
+	ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
+	/* alias this; required by ata_generic_status */
+	ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_STATUS].offset;
+
+	/* NB: the control register is special */
 	ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
+
 	/* NB: by convention this points at the base of registers */
-	ch->r_io[ATA_IDX_ADDR].res = &sc->sc_ata;
 	ch->r_io[ATA_IDX_ADDR].offset = 0;
 
-	/* NB: should be used only for ATAPI devices */
-	ch->r_io[ATA_IREASON] = ch->r_io[ATA_COUNT];
-	/* alias this; required by ata_generic_status */
-	ch->r_io[ATA_ALTSTAT] = ch->r_io[ATA_CONTROL];
-
 	ata_generic_hw(dev);
 	return ata_attach(dev);
 }
 
+/* XXX override ata_generic_reset to handle non-standard status */
+static void
+avila_channel_reset(device_t dev)
+{
+	struct ata_channel *ch = device_get_softc(dev);
+	u_int8_t ostat0 = 0, stat0 = 0;
+	u_int8_t err = 0, lsb = 0, msb = 0;
+	int mask = 0, timeout;
+
+	/* do we have any signs of ATA/ATAPI HW being present ? */
+	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
+	DELAY(10);
+	ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
+	if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
+		stat0 = ATA_S_BUSY;
+		mask |= 0x01;
+	}
+
+	if (bootverbose)
+		device_printf(dev, "%s: reset tp1 mask=%02x ostat0=%02x\n",
+		    __func__, mask, ostat0);
+
+	/* if nothing showed up there is no need to get any further */
+	/* XXX SOS is that too strong?, we just might loose devices here */
+	ch->devices = 0;
+	if (!mask)
+		return;
+
+	/* reset (both) devices on this channel */
+	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
+	DELAY(10);
+	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
+	ata_udelay(10000); 
+	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
+	ata_udelay(100000);
+	ATA_IDX_INB(ch, ATA_ERROR);
+
+	/* wait for BUSY to go inactive */
+	for (timeout = 0; timeout < 310; timeout++) {
+		if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
+			ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+			DELAY(10);
+			err = ATA_IDX_INB(ch, ATA_ERROR);
+			lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+			msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
+			stat0 = ATA_IDX_INB(ch, ATA_STATUS);
+			if (bootverbose)
+				device_printf(dev,
+				    "%s: stat0=0x%02x err=0x%02x lsb=0x%02x "
+				    "msb=0x%02x\n", __func__,
+				    stat0, err, lsb, msb);
+			if (stat0 == err && lsb == err && msb == err &&
+			    timeout > (stat0 & ATA_S_BUSY ? 100 : 10))
+				mask &= ~0x01;
+			if (!(stat0 & ATA_S_BUSY)) {
+				if ((err & 0x7f) == ATA_E_ILI || err == 0) {
+					if (lsb == ATAPI_MAGIC_LSB &&
+					    msb == ATAPI_MAGIC_MSB) {
+						ch->devices |= ATA_ATAPI_MASTER;
+					} else if (stat0 & ATA_S_READY) {
+						ch->devices |= ATA_ATA_MASTER;
+					}
+				} else if ((stat0 & 0x0f) &&
+				    err == lsb && err == msb) {
+					stat0 |= ATA_S_BUSY;
+				}
+			}
+		}
+		if (mask == 0x00)       /* nothing to wait for */
+			break;
+		/* wait for master */
+		if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10))
+			break;
+		ata_udelay(100000);
+	}
+
+	if (bootverbose)
+		device_printf(dev, "%s: reset tp2 stat0=%02x devices=0x%b\n",
+		    __func__, stat0, ch->devices,
+		    "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
+}
+
 static device_method_t avila_channel_methods[] = {
 	/* device interface */
 	DEVMETHOD(device_probe,     avila_channel_probe),
@@ -440,6 +521,8 @@
 	DEVMETHOD(device_suspend,   ata_suspend),
 	DEVMETHOD(device_resume,    ata_resume),
 
+	DEVMETHOD(ata_reset,	    avila_channel_reset),
+
 	{ 0, 0 }
 };
 



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