Subject: port-macppc/27680: fix synchronous transfers for the mesh SCSI controller
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <macallan18@netbsd.org>
List: netbsd-bugs
Date: 10/30/2004 02:56:45
>Number:         27680
>Category:       port-macppc
>Synopsis:       fix synchronous transfers for the mesh SCSI controller
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    port-macppc-maintainer
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Oct 30 02:57:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Michael Lorenz
>Release:        NetBSD 2.99.10
>Organization:
>Environment:
NetBSD Macallan 2.99.10 NetBSD 2.99.10 (MACALLAN) #192: Fri Oct 29 22:25:34 EDT 2004  ml@Macallan:/data/src/sys/arch/macppc/compile/MACALLAN macppc
>Description:
This patch allows synchronous transfers for mesh. 
Problem: when a SCSI target initiates a sync negotiation ( some IBM harddisks do that ) this is honoured by the driver even if sync negotiation is disabled in kernel config, this leads to the symptoms described in PR 19736 and PR 14460, eg.
mesh0: timeout state 3
and the SCSI bus hangs.
The patch does two things - it makes sure that sync negotiations initiated by targets are rejected, so the flags in the kernel config effectively prevent sync negotiation instead of only keeping the driver from initiating them. And it allows synchronous transfers. I couldn't really test it but at least it allows a Seagate Barracuda 9GB disk and a Pioneer CDROM to operate at 10MB/s in synchronous mode.
Caveat: when it tries to negotiate sync with a ZIP drive it hangs, forcing the ZIP into asynchronous mode using the flag field works as before.


>How-To-Repeat:
allow syncronous transfers for mesh and connect a target that supports synchronous mode or use a harddisk with target-initiated sync negotiation enabled ( the DCAS series for instance has a jumper labeled 'TI sync negotiation' ) with mesh
>Fix:

RCS file: /cvsroot/src/sys/arch/macppc/dev/mesh.c,v
retrieving revision 1.19
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");

>Release-Note:
>Audit-Trail:
>Unformatted: