Subject: Re: sync negotiation with drives
To: <>
From: Michael <macallan18@earthlink.net>
List: port-macppc
Date: 10/29/2004 22:32:15
Hello,
> So I had a look at the Linux driver which apparently works in synchronous mode, this comment looks interesting:
Yeah, but it wasn't the cause. This however was:
/*
* We can get a phase mismatch here if the target
* changes to the status phase, even though we have
* had a command complete interrupt. Then, if we
* issue the SEQ_STATUS command, we'll get a sequence
* error interrupt. Which isn't so bad except that
* occasionally the mesh actually executes the
* SEQ_STATUS *as well as* giving us the sequence
* error and phase mismatch exception.
*/
We get these interrupts after nearly every transfer, and after a while the whole thing locks up. So we write a 0 into the command register whenever a command completes and clear all interrupts again, so we still get more interrupts than necessary but the controller won't lock up - my Barracuda works now in synchronous mode, performance according to bonnie++ increased from ~6MB/s to ~8MB/s - both, reading and writing. Still a far cry from the maximum ( it's certainly not the drives fault - it does >15MB/s ) but at least something.
It works well with the disk and my CDROM ( a Pioneer 24x, at 10MB/s ) but not the ZIP - it hangs when trying to negotiate sync, so we should probably leave sync disabled by default, or at least disable it for target 5 and 6 where ZIPs are likely to be found - most Macs don't have room for more than 5 internal SCSI devices anyway. In async mode it sort of works - reading is ok, writing is flaky, but that's exactly what it did before.
Another way would be to add a quirk table to mesh and never try to negotiate sync with a ZIP drive. On the other hand this table would better be global, I doubt that the ZIP has only problems with mesh.
Here's the patch:
diff -u -b -B -r1.19 mesh.c
--- mesh.c 15 Jul 2003 02:43:29 -0000 1.19
+++ mesh.c 30 Oct 2004 02:23:48 -0000
@@ -68,6 +68,7 @@
#define T_SYNCMODE 0x01 /* target uses sync mode */
#define T_SYNCNEGO 0x02 /* sync negotiation done */
+#define T_SYNCRJCT 0x04 /* reject sync negotiation */
struct mesh_tinfo {
int flags;
@@ -357,7 +358,8 @@
DPRINTF("%s: NULL nexus\n", sc->sc_dev.dv_xname);
return 1;
}
-
+ if(intr & MESH_INTR_CMDDONE)
+ {
if (sc->sc_flags & MESH_DMA_ACTIVE) {
dbdma_stop(sc->sc_dmareg);
@@ -365,7 +367,9 @@
scb->resid = MESH_GET_XFER(sc);
fifocnt = mesh_read_reg(sc, MESH_FIFO_COUNT);
- if (fifocnt != 0 && (scb->flags & MESH_READ)) {
+ if (fifocnt != 0)
+ {
+ if (scb->flags & MESH_READ) {
char *cp = (char *)scb->daddr + scb->dlen - fifocnt;
DPRINTF("fifocnt = %d, resid = %d\n", fifocnt,
@@ -376,9 +380,16 @@
}
} else
mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
+ } else
+ {
+ mesh_set_reg(sc, MESH_SEQUENCE, 0);
+ mesh_set_reg(sc, MESH_INTERRUPT, 7);
+ }
+ }
}
if (intr & MESH_INTR_ERROR) {
+ printf("error %02x %02x\n",error,exception);
mesh_error(sc, scb, error, 0);
return 1;
}
@@ -392,6 +403,7 @@
/* phase mismatch */
if (exception & MESH_EXC_PHASEMM) {
+ //printf("!");
DPRINTF("%s: PHASE MISMATCH; nextstate = %d -> ",
sc->sc_dev.dv_xname, sc->sc_nextstate);
sc->sc_nextstate = status0 & MESH_PHASE_MASK;
@@ -477,7 +488,7 @@
{
struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target];
int timeout;
-
+ int cnt;
DPRINTF("mesh_select\n");
mesh_setsync(sc, ti);
@@ -491,10 +502,18 @@
* initiator ID to DestID register temporarily.
*/
mesh_set_reg(sc, MESH_DEST_ID, sc->sc_id);
+
mesh_set_reg(sc, MESH_INTR_MASK, 0); /* disable intr. */
+
mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_ARBITRATE);
- while (mesh_read_reg(sc, MESH_INTERRUPT) == 0);
+ cnt=0;
+ while ((mesh_read_reg(sc, MESH_INTERRUPT) == 0)&&(cnt<250))
+ {
+ cnt++;
+ delay(1);
+ }
+
mesh_set_reg(sc, MESH_INTERRUPT, 1);
mesh_set_reg(sc, MESH_INTR_MASK, 7);
@@ -521,8 +539,8 @@
DPRINTF("mesh_identify\n");
mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
-
- if ((ti->flags & T_SYNCNEGO) == 0) {
+ if ((ti->flags & T_SYNCNEGO) == 0)
+ {
ti->period = sc->sc_minsync;
ti->offset = 15;
mesh_msgout(sc, SEND_IDENTIFY | SEND_SDTR);
@@ -672,6 +688,9 @@
struct mesh_softc *sc;
struct mesh_scb *scb;
{
+#ifdef MESH_DEBUG
+ int i;
+#endif
DPRINTF("mesh_msgin\n");
if (mesh_read_reg(sc, MESH_FIFO_COUNT) == 0) { /* XXX cheat */
@@ -760,10 +779,20 @@
scsipi_printaddr(scb->xs->xs_periph);
/* XXX if (offset != 0) ... */
printf("max sync rate %d.%02dMb/s\n", r, s);
+ if(ti->flags & T_SYNCRJCT)
+ {
+ printf("sync requested - I'll ignore it and use asynchronous transfers.\n");
+ ti->period = 0;
+ ti->offset = 0;
+ ti->flags |= T_SYNCNEGO;
+ /*ti->flags |= T_SYNCMODE;*/
+ } else
+ {
ti->period = period;
ti->offset = offset;
ti->flags |= T_SYNCNEGO;
ti->flags |= T_SYNCMODE;
+ }
mesh_setsync(sc, ti);
goto done;
}
@@ -894,7 +923,9 @@
ti->flags = 0;
ti->period = ti->offset = 0;
if (sc->sc_cfflags & (0x100 << i))
- ti->flags |= T_SYNCNEGO;
+ {
+ ti->flags |= (T_SYNCNEGO|T_SYNCRJCT);
+ }
}
sc->sc_nexus = NULL;
}
@@ -1141,17 +1172,18 @@
struct mesh_softc *sc =
(void *)scb->xs->xs_periph->periph_channel->chan_adapter->adapt_dev; int s;
- int status0, status1;
+ int status0, status1, imsk;
int intr, error, exception;
printf("%s: timeout state %d\n", sc->sc_dev.dv_xname, sc->sc_nextstate);
intr = mesh_read_reg(sc, MESH_INTERRUPT);
+ imsk = mesh_read_reg(sc, MESH_INTR_MASK);
exception = mesh_read_reg(sc, MESH_EXCEPTION);
error = mesh_read_reg(sc, MESH_ERROR);
status0 = mesh_read_reg(sc, MESH_BUS_STATUS0);
status1 = mesh_read_reg(sc, MESH_BUS_STATUS1);
-
+ printf("%02x %02x %02x %02x %02x %02x\n",intr, imsk, exception,error,status0,status1);
s = splbio();
if (sc->sc_flags & MESH_DMA_ACTIVE) {
printf("mesh: resetting DMA\n");
not really cleaned up yet and I have no idea what it might break - for me it seems to work.
have fun
Michael