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;