Module Name:    src
Committed By:   jakllsch
Date:           Sat Jun 27 21:04:47 UTC 2009

Modified Files:
        src/sys/dev/ic: siisata.c

Log Message:
Correct various siisata bugs, some old, some new.

 - Move clearing of interrupts to before atastart() is called in the
   xfer interrupt handler.  Should fix kern/41579.
 - Using cv_timedwait(9) is not possible in code that can be called from
   interrupt context, fall back to DELAY(9).
 - Correctly poll Port Slot Status register for soft reset PRBs.
 - Only use the Recive Transfer Count register on reads, when it is valid.
 - Activate PRBs in a way that takes the whole physical address into account,
   even when the PRB is beyond 4GiB.
 - consistently use DELAY(9)
 - Use DELAY() constants in completion polling loops that are consistent with
   the loop count limit. (i.e. timeout in 10 rather than 100 seconds)


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/ic/siisata.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.5 src/sys/dev/ic/siisata.c:1.6
--- src/sys/dev/ic/siisata.c:1.5	Sun Jun 21 14:15:38 2009
+++ src/sys/dev/ic/siisata.c	Sat Jun 27 21:04:47 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.5 2009/06/21 14:15:38 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.6 2009/06/27 21:04:47 jakllsch Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -494,13 +494,13 @@
 		}
 	}
 
+	/* clear some (ok, all) ints */
+	PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff);
+
 	KASSERT(xfer != NULL);
 	KASSERT(xfer->c_intr != NULL);
 	xfer->c_intr(chp, xfer, slot);
 
-	/* clear some (ok, all) ints */
-	PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff);
-
 	return;
 }
 
@@ -511,17 +511,8 @@
 	struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
 	struct siisata_channel *schp = (struct siisata_channel *)chp;
 	struct siisata_prb *prb;
-	kmutex_t mtx;
-	kcondvar_t cv;
 	int slot = SIISATA_NON_NCQ_SLOT;
 	int i;
-	int wait;
-
-	mutex_init(&mtx, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&cv, "siipd");
-
-	wait = mstohz(10);
-	wait = wait ? wait : 1;
 
 	/* wait for ready */
 	while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
@@ -534,18 +525,18 @@
 
 	siisata_activate_prb(schp, slot);
 
-	for(i = 0; i < (31000/(1000/(wait*hz))); i++) {
+	for(i = 0; i < 31000; i++) {
 		if (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
 		    PR_PXSS(slot))
-			break;
+			DELAY(1000);
 		else
-			cv_timedwait(&cv, &mtx, wait);
+			break;
 	}
 
 	siisata_deactivate_prb(schp, slot);
 
-	log(LOG_DEBUG, "%s: ch_status %x ch_error %x\n",
-	    __func__, chp->ch_status, chp->ch_error);
+	log(LOG_DEBUG, "%s: port %d: ch_status %x ch_error %x\n",
+	    __func__, chp->ch_channel, chp->ch_status, chp->ch_error);
 
 #if 1
 	/* attempt to downgrade signaling in event of CRC error */
@@ -571,9 +562,6 @@
 	chp->ch_error = 0;
 #endif
 
-	cv_destroy(&cv);
-	mutex_destroy(&mtx);
-
 	return;
 }
 
@@ -633,9 +621,6 @@
 	uint32_t sig;
 	int slot = SIISATA_NON_NCQ_SLOT;
 	struct siisata_prb *prb;
-	kmutex_t mtx;
-	kcondvar_t cv;
-	int wait;
 
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc),
 	    __func__, chp->ch_channel), DEBUG_FUNCS);
@@ -646,12 +631,6 @@
 		chp->ch_drive[i].drive = i;
 	}
 
-	mutex_init(&mtx, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&cv, "siipd");
-
-	wait = mstohz(10);
-	wait = wait ? wait : 1;
-
 	switch (sata_reset_interface(chp, sc->sc_prt, schp->sch_scontrol,
 		schp->sch_sstatus)) {
 	case SStatus_DET_DEV:
@@ -667,12 +646,12 @@
 
 		siisata_activate_prb(schp, slot);
 
-		for(i = 0; i < (31000/(1000/(wait*hz))); i++) {
+		for(i = 0; i < 31000; i++) {
 			if (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
 			    PR_PXSS(slot))
-				break;
+				DELAY(1000);
 			else
-				cv_timedwait(&cv, &mtx, wait);
+				break;
 		}
 
 		siisata_deactivate_prb(schp, slot);
@@ -714,9 +693,6 @@
 		break;
 	}
 
-	cv_destroy(&cv);
-	mutex_destroy(&mtx);
-
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc),
 	    __func__, chp->ch_channel), DEBUG_PROBE);
 	return;
@@ -836,7 +812,7 @@
 		if (ata_c->flags & AT_DONE)
 			break;
 		siisata_intr_port(schp);
-		DELAY(10000);
+		DELAY(1000);
 	}
 
 	if ((ata_c->flags & AT_DONE) == 0) {
@@ -1038,7 +1014,7 @@
 		if (ata_bio->flags & ATA_ITSDONE)
 			break;
 		siisata_intr_port(schp);
-		DELAY(10000);
+		DELAY(1000);
 	}
 
 	GRWRITE(sc, GR_GC, GRREAD(sc, GR_GC) | GR_GC_PXIE(chp->ch_channel));
@@ -1123,9 +1099,13 @@
 
 	SIISATA_DEBUG_PRINT(("%s: %s bcount: %ld", SIISATANAME(sc),
 	    __func__, ata_bio->bcount), DEBUG_XFERS); 
-	if ((ata_bio->flags & ATA_READ) || (ata_bio->error == NOERROR))
-		ata_bio->bcount -= PRREAD(sc,
-		    PRSX(chp->ch_channel, slot, PRSO_RTC));
+	if (ata_bio->error == NOERROR) {
+		if (ata_bio->flags & ATA_READ)
+			ata_bio->bcount -=
+			    PRREAD(sc, PRSX(chp->ch_channel, slot, PRSO_RTC));
+		else
+			ata_bio->bcount = 0;
+	}
 	SIISATA_DEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS); 
 	if (ata_bio->flags & ATA_POLL)
 		return 1;
@@ -1203,34 +1183,23 @@
 {
 	struct siisata_softc *sc;
 	bus_size_t offset;
-	bus_addr_t pprb;
-	int port;
+	uint64_t pprb;
 
 	sc = (struct siisata_softc *)schp->ata_channel.ch_atac;
 
 	KASSERTMSG(((schp->sch_active_slots & __BIT(slot)) == __BIT(slot)),
 	    ("%s: trying to activate active slot %d", SIISATANAME(sc), slot));
 
-	port = schp->ata_channel.ch_channel;
-
-	offset = PRO_CARX(port, slot);
-
-	pprb = schp->sch_bus_prb[slot];
-
-
 	SIISATA_PRB_SYNC(sc, schp, slot, BUS_DMASYNC_PREWRITE);
 	/* keep track of what's going on */
 	schp->sch_active_slots |= __BIT(slot);
 
+	offset = PRO_CARX(schp->ata_channel.ch_channel, slot);
 
-	PRWRITE(sc, offset, pprb);
-	offset += 4;
-#if 0
-	if (sizeof(bus_addr_t) == 8)
-		PRWRITE(sc, offset, (pprb >> 32));
-	else
-#endif
-		PRWRITE(sc, offset, 0);
+	pprb = schp->sch_bus_prb[slot];
+
+	PRWRITE(sc, offset + 0, pprb >>  0);
+	PRWRITE(sc, offset + 4, pprb >> 32);
 }
 
 static void
@@ -1379,7 +1348,7 @@
 	}
 
 	/* Some ATAPI devices need a bit more time after software reset. */
-	delay(5000);
+	DELAY(5000);
 	if (ata_get_params(drvp, AT_WAIT, id) == 0) {
 #ifdef ATAPI_DEBUG_PROBE
 		log(LOG_DEBUG, "%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
@@ -1591,7 +1560,7 @@
 		if (sc_xfer->xs_status & XS_STS_DONE)
 			break;
 		siisata_intr_port(schp);
-		DELAY(10000);
+		DELAY(1000);
 	}
 	if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
 		sc_xfer->error = XS_TIMEOUT;

Reply via email to